Part of Slepp's ProjectsPastebinTURLImagebinFilebin
Feedback -- English French German Japanese
Create Upload Newest Tools Donate
Sign In | Create Account

Unnamed
Wednesday, January 31st, 2007 at 11:15:14am UTC 

  1. /***************************************************************************
  2.  *             __________               __   ___.
  3.  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
  4.  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
  5.  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  6.  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  7.  *                     \/            \/     \/    \/            \/
  8.  * $Id: playback.c 12125 2007-01-27 16:33:44Z lostlogic $
  9.  *
  10.  * Copyright (C) 2005 Miika Pekkarinen
  11.  *
  12.  * All files in this archive are subject to the GNU General Public License.
  13.  * See the file COPYING in the source tree root for full license agreement.
  14.  *
  15.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  16.  * KIND, either express or implied.
  17.  *
  18.  ****************************************************************************/
  19.  
  20. /* TODO: Can use the track changed callback to detect end of track and seek
  21.  * in the previous track until this happens */
  22. /* Design: we have prev_ti already, have a conditional for what type of seek
  23.  * to do on a seek request, if it is a previous track seek, skip previous,
  24.  * and in the request_next_track callback set the offset up the same way that
  25.  * starting from an offset works. */
  26. /* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
  27.  * play whilst audio is paused */
  28.  
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <stdlib.h>
  32. #include <ctype.h>
  33.  
  34. #include "system.h"
  35. #include "thread.h"
  36. #include "file.h"
  37. #include "lcd.h"
  38. #include "font.h"
  39. #include "button.h"
  40. #include "kernel.h"
  41. #include "tree.h"
  42. #include "debug.h"
  43. #include "sprintf.h"
  44. #include "settings.h"
  45. #include "codecs.h"
  46. #include "audio.h"
  47. #include "logf.h"
  48. #include "mp3_playback.h"
  49. #include "usb.h"
  50. #include "status.h"
  51. #include "main_menu.h"
  52. #include "ata.h"
  53. #include "screens.h"
  54. #include "playlist.h"
  55. #include "playback.h"
  56. #include "pcmbuf.h"
  57. #include "buffer.h"
  58. #include "dsp.h"
  59. #include "abrepeat.h"
  60. #ifdef HAVE_TAGCACHE
  61. #include "tagcache.h"
  62. #endif
  63. #ifdef HAVE_LCD_BITMAP
  64. #include "icons.h"
  65. #include "peakmeter.h"
  66. #include "action.h"
  67. #endif
  68. #include "lang.h"
  69. #include "bookmark.h"
  70. #include "misc.h"
  71. #include "sound.h"
  72. #include "metadata.h"
  73. #include "splash.h"
  74. #include "talk.h"
  75. #include "ata_idle_notify.h"
  76.  
  77. #ifdef HAVE_RECORDING
  78. #include "recording.h"
  79. #include "talk.h"
  80. #endif
  81.  
  82. #define PLAYBACK_VOICE
  83.  
  84.  
  85. /* default point to start buffer refill */
  86. #define AUDIO_DEFAULT_WATERMARK      (1024*512)
  87. /* amount of data to read in one read() call */
  88. #define AUDIO_DEFAULT_FILECHUNK      (1024*32)
  89. /* point at which the file buffer will fight for CPU time */
  90. #define AUDIO_FILEBUF_CRITICAL       (1024*128)
  91. /* amount of guess-space to allow for codecs that must hunt and peck
  92.  * for their correct seeek target, 32k seems a good size */
  93. #define AUDIO_REBUFFER_GUESS_SIZE    (1024*32)
  94.  
  95. /* macros to enable logf for queues
  96.    logging on SYS_TIMEOUT can be disabled */
  97. #ifdef SIMULATOR
  98. /* Define this for logf output of all queuing except SYS_TIMEOUT */
  99. #define PLAYBACK_LOGQUEUES
  100. /* Define this to logf SYS_TIMEOUT messages */
  101. #define PLAYBACK_LOGQUEUES_SYS_TIMEOUT
  102. #endif
  103.  
  104. #ifdef PLAYBACK_LOGQUEUES
  105. #define LOGFQUEUE(s) logf("%s", s)
  106. #else
  107. #define LOGFQUEUE(s)
  108. #endif
  109.  
  110. #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
  111. #define LOGFQUEUE_SYS_TIMEOUT(s) logf("%s", s)
  112. #else
  113. #define LOGFQUEUE_SYS_TIMEOUT(s)
  114. #endif
  115.  
  116.  
  117. /* Define one constant that includes recording related functionality */
  118. #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
  119. #define AUDIO_HAVE_RECORDING
  120. #endif
  121.  
  122. enum {
  123.     Q_AUDIO_PLAY = 1,
  124.     Q_AUDIO_STOP,
  125.     Q_AUDIO_PAUSE,
  126.     Q_AUDIO_SKIP,
  127.     Q_AUDIO_PRE_FF_REWIND,
  128.     Q_AUDIO_FF_REWIND,
  129.     Q_AUDIO_REBUFFER_SEEK,
  130.     Q_AUDIO_CHECK_NEW_TRACK,
  131.     Q_AUDIO_FLUSH,
  132.     Q_AUDIO_TRACK_CHANGED,
  133.     Q_AUDIO_DIR_SKIP,
  134.     Q_AUDIO_NEW_PLAYLIST,
  135.     Q_AUDIO_POSTINIT,
  136.     Q_AUDIO_FILL_BUFFER,
  137. #if MEM > 8
  138.     Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA,
  139. #endif
  140. #ifdef AUDIO_HAVE_RECORDING
  141.     Q_AUDIO_LOAD_ENCODER,
  142. #endif
  143.  
  144. #if 0
  145.     Q_CODEC_REQUEST_PENDING,
  146. #endif
  147.     Q_CODEC_REQUEST_COMPLETE,
  148.     Q_CODEC_REQUEST_FAILED,
  149.  
  150.     Q_VOICE_PLAY,
  151.     Q_VOICE_STOP,
  152.  
  153.     Q_CODEC_LOAD,
  154.     Q_CODEC_LOAD_DISK,
  155.  
  156. #ifdef AUDIO_HAVE_RECORDING
  157.     Q_ENCODER_LOAD_DISK,
  158.     Q_ENCODER_RECORD,
  159. #endif
  160. };
  161.  
  162. /* As defined in plugins/lib/xxx2wav.h */
  163. #if MEM > 1
  164. #define MALLOC_BUFSIZE (512*1024)
  165. #define GUARD_BUFSIZE  (32*1024)
  166. #else
  167. #define MALLOC_BUFSIZE (100*1024)
  168. #define GUARD_BUFSIZE  (8*1024)
  169. #endif
  170.  
  171. /* As defined in plugin.lds */
  172. #if defined(CPU_PP)
  173. #define CODEC_IRAM_ORIGIN   0x4000c000
  174. #define CODEC_IRAM_SIZE     0xc000
  175. #elif defined(IAUDIO_X5)
  176. #define CODEC_IRAM_ORIGIN   0x10010000
  177. #define CODEC_IRAM_SIZE     0x10000
  178. #else
  179. #define CODEC_IRAM_ORIGIN   0x1000c000
  180. #define CODEC_IRAM_SIZE     0xc000
  181. #endif
  182.  
  183. #ifndef IBSS_ATTR_VOICE_STACK
  184. #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
  185. #endif
  186.  
  187. #ifndef SIMULATOR
  188. extern bool audio_is_initialized;
  189. #else
  190. static bool audio_is_initialized = false;
  191. #endif
  192.  
  193.  
  194. /* Variables are commented with the threads that use them: *
  195.  * A=audio, C=codec, V=voice. A suffix of - indicates that *
  196.  * the variable is read but not updated on that thread.    */
  197. /* TBD: Split out "audio" and "playback" (ie. calling) threads */
  198.  
  199. /* Main state control */
  200. static volatile bool audio_codec_loaded; /* Is codec loaded? (C/A-) */
  201. static volatile bool playing;            /* Is audio playing? (A) */
  202. static volatile bool paused;             /* Is audio paused? (A/C-) */
  203. static volatile bool filling IDATA_ATTR; /* Is file buffer refilling? (A/C-) */
  204.  
  205. /* Ring buffer where compressed audio and codecs are loaded */
  206. static unsigned char *filebuf;              /* Start of buffer (A/C-) */
  207. /* FIXME: make filebuflen static */
  208. size_t filebuflen;                          /* Size of buffer (A/C-) */
  209. /* FIXME: make buf_ridx (C/A-) */
  210. static volatile size_t buf_ridx IDATA_ATTR; /* Buffer read position (A/C)*/
  211. static volatile size_t buf_widx IDATA_ATTR; /* Buffer write position (A/C-) */
  212.  
  213. /* Possible arrangements of the buffer */
  214. #define BUFFER_STATE_TRASHED        -1          /* trashed; must be reset */
  215. #define BUFFER_STATE_NORMAL          0          /* voice+audio OR audio-only */
  216. #define BUFFER_STATE_VOICED_ONLY     1          /* voice-only */
  217. static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */
  218.  
  219. /* Compressed ring buffer helper macros */
  220. /* Buffer pointer (p) plus value (v), wrapped if necessary */
  221. #define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen)
  222. /* Buffer pointer (p) minus value (v), wrapped if necessary */
  223. #define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v)
  224. /* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
  225. #define RINGBUF_ADD_CROSS(p1,v,p2) \
  226.     ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen)
  227. /* Bytes available in the buffer */
  228. #define FILEBUFUSED RINGBUF_SUB(buf_widx, buf_ridx)
  229.  
  230. /* Track info structure about songs in the file buffer (A/C-) */
  231. static struct track_info tracks[MAX_TRACK];
  232. static volatile int track_ridx;      /* Track being decoded (A/C-) */
  233. static int track_widx;               /* Track being buffered (A) */
  234.  
  235. static struct track_info *prev_ti;   /* Previous track info pointer (A/C-) */
  236. #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
  237.  
  238. /* Set by the audio thread when the current track information has updated
  239.  * and the WPS may need to update its cached information */
  240. static bool track_changed;
  241.  
  242. /* Information used only for filling the buffer */
  243. /* Playlist steps from playing track to next track to be buffered (A) */
  244. static int last_peek_offset;
  245. /* Partially loaded track file handle to continue buffering (A) */
  246. static int current_fd;
  247.  
  248. /* Scrobbler support */
  249. static unsigned long prev_track_elapsed; /* Previous track elapsed time (C/A-)*/
  250.  
  251. /* Track change controls */
  252. static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
  253. static bool playlist_end = false;   /* Has the current playlist ended? (A) */
  254. static bool dir_skip = false;       /* Is a directory skip pending? (A) */
  255. static bool new_playlist = false;   /* Are we starting a new playlist? (A) */
  256. /* Pending track change offset, to keep WPS responsive (A) */
  257. static int wps_offset = 0;
  258.  
  259. /* Callbacks which applications or plugins may set */
  260. /* When the playing track has changed from the user's perspective */
  261. void (*track_changed_callback)(struct mp3entry *id3);
  262. /* When a track has been buffered */
  263. void (*track_buffer_callback)(struct mp3entry *id3, bool last_track);
  264. /* When a track's buffer has been overwritten or cleared */
  265. void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track);
  266.  
  267. /* Configuration */
  268. static size_t conf_watermark; /* Level to trigger filebuf fill (A/C) FIXME */
  269. static size_t conf_filechunk; /* Largest chunk the codec accepts (A/C) FIXME */
  270. static size_t conf_preseek;   /* Codec pre-seek margin (A/C) FIXME */
  271. static size_t buffer_margin;  /* Buffer margin aka anti-skip buffer (A/C-) */
  272. static bool v1first = false;  /* ID3 data control, true if V1 then V2 (A) */
  273. #if MEM > 8
  274. static size_t high_watermark; /* High watermark for rebuffer (A/V/other) */
  275. #endif
  276.  
  277. /* Multiple threads */
  278. static const char *get_codec_filename(int enc_spec); /* (A-/C-/V-) */
  279. /* Set the watermark to trigger buffer fill (A/C) FIXME */
  280. static void set_filebuf_watermark(int seconds);
  281.  
  282. /* Audio thread */
  283. static struct event_queue       audio_queue;
  284. static struct queue_sender_list audio_queue_sender_list;
  285. static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
  286. static const char audio_thread_name[] = "audio";
  287.  
  288. static void audio_thread(void);
  289. static void audio_initiate_track_change(long direction);
  290. static bool audio_have_tracks(void);
  291. static void audio_reset_buffer(size_t pcmbufsize);
  292.  
  293. /* Codec thread */
  294. extern struct codec_api ci;
  295. static struct event_queue codec_queue;
  296. static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
  297. IBSS_ATTR;
  298. static const char codec_thread_name[] = "codec";
  299. struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
  300.  
  301. volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */
  302.  
  303. /* Voice thread */
  304. #ifdef PLAYBACK_VOICE
  305.  
  306. extern struct codec_api ci_voice;
  307.  
  308. static struct thread_entry *voice_thread_p = NULL;
  309. static struct event_queue voice_queue;
  310. static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
  311. IBSS_ATTR_VOICE_STACK;
  312. static const char voice_thread_name[] = "voice codec";
  313.  
  314. /* Voice codec swapping control */
  315. extern unsigned char codecbuf[];                /* DRAM codec swap buffer */
  316.  
  317. #ifdef SIMULATOR
  318. /* IRAM codec swap buffer for sim*/
  319. static unsigned char sim_iram[CODEC_IRAM_SIZE];
  320. #undef CODEC_IRAM_ORIGIN
  321. #define CODEC_IRAM_ORIGIN sim_iram
  322. #endif
  323.  
  324. /* Pointer to IRAM buffers for normal/voice codecs */
  325. static unsigned char *iram_buf[2] = { NULL, NULL };
  326. /* Pointer to DRAM buffers for normal/voice codecs */
  327. static unsigned char *dram_buf[2] = { NULL, NULL };
  328. /* Mutex to control which codec (normal/voice) is running */
  329. static struct mutex mutex_codecthread;
  330.  
  331. /* Voice state */
  332. static volatile bool voice_thread_start; /* Triggers voice playback (A/V) */
  333. static volatile bool voice_is_playing;   /* Is voice currently playing? (V) */
  334. static volatile bool voice_codec_loaded; /* Is voice codec loaded (V/A-) */
  335. static char *voicebuf;
  336. static size_t voice_remaining;
  337.  
  338. #ifdef IRAM_STEAL
  339. /* Voice IRAM has been stolen for other use */
  340. static bool voice_iram_stolen = false;
  341. #endif
  342.  
  343. static void (*voice_getmore)(unsigned char** start, int* size);
  344.  
  345. struct voice_info {
  346.     void (*callback)(unsigned char **start, int *size);
  347.     int size;
  348.     char *buf;
  349. };
  350. static void voice_thread(void);
  351.  
  352. #endif /* PLAYBACK_VOICE */
  353.  
  354. /* --- External interfaces --- */
  355.  
  356. void mp3_play_data(const unsigned char* start, int size,
  357.                    void (*get_more)(unsigned char** start, int* size))
  358. {
  359. #ifdef PLAYBACK_VOICE
  360.     static struct voice_info voice_clip;
  361.     voice_clip.callback = get_more;
  362.     voice_clip.buf = (char *)start;
  363.     voice_clip.size = size;
  364.     LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
  365.     queue_post(&voice_queue, Q_VOICE_STOP, 0);
  366.     LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
  367.     queue_post(&voice_queue, Q_VOICE_PLAY, (intptr_t)&voice_clip);
  368.     voice_thread_start = true;
  369.     trigger_cpu_boost();
  370. #else
  371.     (void) start;
  372.     (void) size;
  373.     (void) get_more;
  374. #endif
  375. }
  376.  
  377. void mp3_play_stop(void)
  378. {
  379. #ifdef PLAYBACK_VOICE
  380.     queue_remove_from_head(&voice_queue, Q_VOICE_STOP);
  381.     LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
  382.     queue_post(&voice_queue, Q_VOICE_STOP, 1);
  383. #endif
  384. }
  385.  
  386. bool mp3_pause_done(void)
  387. {
  388.     return pcm_is_paused();
  389. }
  390.  
  391. void mpeg_id3_options(bool _v1first)
  392. {
  393.     v1first = _v1first;
  394. }
  395.  
  396. /* If voice could be swapped out - wait for it to return
  397.  * Used by buffer claming functions.
  398.  */
  399. static void wait_for_voice_swap_in(void)
  400. {
  401. #ifdef PLAYBACK_VOICE
  402.     if (NULL == iram_buf[CODEC_IDX_VOICE])
  403.         return;
  404.  
  405.     while (current_codec != CODEC_IDX_VOICE)
  406.         yield();
  407. #endif /* PLAYBACK_VOICE */
  408. }
  409.  
  410. unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
  411. {
  412.     unsigned char *buf, *end;
  413.  
  414.     if (audio_is_initialized)
  415.     {
  416.         audio_stop();
  417.         wait_for_voice_swap_in();
  418.         voice_stop();
  419.     }
  420.     /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
  421.  
  422.     if (buffer_size == NULL)
  423.     {
  424.         /* Special case for talk_init to use */
  425.         buffer_state = BUFFER_STATE_TRASHED;
  426.         return NULL;
  427.     }
  428.  
  429.     if (talk_buf || buffer_state == BUFFER_STATE_TRASHED
  430.            || !talk_voice_required())
  431.     {
  432.         logf("get buffer: talk_buf");
  433.         /* ok to use everything from audiobuf to audiobufend */
  434.         if (buffer_state != BUFFER_STATE_TRASHED)
  435.         {
  436.             talk_buffer_steal();
  437.             buffer_state = BUFFER_STATE_TRASHED;
  438.         }
  439.  
  440.         buf = audiobuf;
  441.         end = audiobufend;
  442.     }
  443.     else
  444.     {
  445.         /* skip talk buffer and move pcm buffer to end */
  446.         logf("get buffer: voice");
  447.         buf = audiobuf + talk_get_bufsize();
  448.         end = audiobufend - pcmbuf_init(pcmbuf_get_bufsize(), audiobufend);
  449.         buffer_state = BUFFER_STATE_VOICED_ONLY;
  450.     }
  451.  
  452.     *buffer_size = end - buf;
  453.  
  454.     return buf;
  455. }
  456.  
  457. #ifdef IRAM_STEAL
  458. void audio_iram_steal(void)
  459. {
  460.     /* We need to stop audio playback in order to use codec IRAM */
  461.     audio_stop();
  462.  
  463. #ifdef PLAYBACK_VOICE
  464.     if (NULL != iram_buf[CODEC_IDX_VOICE])
  465.     {
  466.         /* Can't already be stolen */
  467.         if (voice_iram_stolen)
  468.             return;
  469.  
  470.         wait_for_voice_swap_in();
  471.         voice_stop();
  472.  
  473.         /* Save voice IRAM - safe to do here since state is known */
  474.         memcpy(iram_buf[CODEC_IDX_VOICE], (void *)CODEC_IRAM_ORIGIN,
  475.                CODEC_IRAM_SIZE);
  476.         voice_iram_stolen = true;
  477.     }
  478.     else
  479.     {
  480.         /* Nothing much to do if no voice */
  481.         voice_iram_stolen = false;
  482.     }
  483. #endif
  484. }
  485. #endif /* IRAM_STEAL */
  486.  
  487. #ifdef HAVE_RECORDING
  488. unsigned char *audio_get_recording_buffer(size_t *buffer_size)
  489. {
  490.     /* don't allow overwrite of voice swap area or we'll trash the
  491.        swapped-out voice codec but can use whole thing if none */
  492.     unsigned char *end;
  493.  
  494.     audio_stop();
  495.     wait_for_voice_swap_in();
  496.     voice_stop();
  497.     talk_buffer_steal();
  498.  
  499. #ifdef PLAYBACK_VOICE
  500. #ifdef IRAM_STEAL
  501.     end = dram_buf[CODEC_IDX_VOICE];
  502. #else
  503.     end = iram_buf[CODEC_IDX_VOICE];
  504. #endif /* IRAM_STEAL */
  505.     if (NULL == end)
  506. #endif /* PLAYBACK_VOICE */
  507.         end = audiobufend;
  508.  
  509.     buffer_state = BUFFER_STATE_TRASHED;
  510.  
  511.     *buffer_size = end - audiobuf;
  512.  
  513.     return (unsigned char *)audiobuf;
  514. }
  515.  
  516. bool audio_load_encoder(int afmt)
  517. {
  518. #ifndef SIMULATOR
  519.     const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER);
  520.     if (!enc_fn)
  521.         return false;
  522.  
  523.     audio_remove_encoder();
  524.     ci.enc_codec_loaded = 0; /* clear any previous error condition */
  525.  
  526.     LOGFQUEUE("audio > Q_AUDIO_LOAD_ENCODER");
  527.     queue_post(&audio_queue, Q_AUDIO_LOAD_ENCODER, (intptr_t)enc_fn);
  528.  
  529.     while (ci.enc_codec_loaded == 0)
  530.         yield();
  531.  
  532.     logf("codec loaded: %d", ci.enc_codec_loaded);
  533.  
  534.     return ci.enc_codec_loaded > 0;
  535. #else
  536.     (void)afmt;
  537.     return true;
  538. #endif
  539. } /* audio_load_encoder */
  540.  
  541. void audio_remove_encoder(void)
  542. {
  543. #ifndef SIMULATOR
  544.     /* force encoder codec unload (if currently loaded) */
  545.     if (ci.enc_codec_loaded <= 0)
  546.         return;
  547.  
  548.     ci.stop_codec = true;
  549.     while (ci.enc_codec_loaded > 0)
  550.         yield();
  551. #endif
  552. } /* audio_remove_encoder */
  553.  
  554. #endif /* HAVE_RECORDING */
  555.  
  556. struct mp3entry* audio_current_track(void)
  557. {
  558.     const char *filename;
  559.     const char *p;
  560.     static struct mp3entry temp_id3;
  561.     int cur_idx;
  562.     int offset = ci.new_track + wps_offset;
  563.    
  564.     cur_idx = track_ridx + offset;
  565.     cur_idx &= MAX_TRACK_MASK;
  566.  
  567.     if (tracks[cur_idx].taginfo_ready)
  568.         return &tracks[cur_idx].id3;
  569.  
  570.     memset(&temp_id3, 0, sizeof(struct mp3entry));
  571.    
  572.     filename = playlist_peek(offset);
  573.     if (!filename)
  574.         filename = "No file!";
  575.  
  576. #ifdef HAVE_TC_RAMCACHE
  577.     if (tagcache_fill_tags(&temp_id3, filename))
  578.         return &temp_id3;
  579. #endif
  580.  
  581.     p = strrchr(filename, '/');
  582.     if (!p)
  583.         p = filename;
  584.     else
  585.         p++;
  586.  
  587.     strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
  588.     temp_id3.title = &temp_id3.path[0];
  589.  
  590.     return &temp_id3;
  591. }
  592.  
  593. struct mp3entry* audio_next_track(void)
  594. {
  595.     int next_idx = track_ridx;
  596.  
  597.     if (!audio_have_tracks())
  598.         return NULL;
  599.  
  600.     next_idx++;
  601.     next_idx &= MAX_TRACK_MASK;
  602.  
  603.     if (!tracks[next_idx].taginfo_ready)
  604.         return NULL;
  605.  
  606.     return &tracks[next_idx].id3;
  607. }
  608.  
  609. bool audio_has_changed_track(void)
  610. {
  611.     if (track_changed)
  612.     {
  613.         track_changed = false;
  614.         return true;
  615.     }
  616.  
  617.     return false;
  618. }
  619.  
  620. void audio_play(long offset)
  621. {
  622.     logf("audio_play");
  623.  
  624. #ifdef PLAYBACK_VOICE
  625.     /* Truncate any existing voice output so we don't have spelling
  626.      * etc. over the first part of the played track */
  627.     LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
  628.     queue_post(&voice_queue, Q_VOICE_STOP, 1);
  629. #endif
  630.  
  631.     /* Start playback */
  632.     if (playing && offset <= 0)
  633.     {
  634.         LOGFQUEUE("audio > audio Q_AUDIO_NEW_PLAYLIST");
  635.         queue_post(&audio_queue, Q_AUDIO_NEW_PLAYLIST, 0);
  636.     }
  637.     else
  638.     {
  639.         LOGFQUEUE("audio > audio Q_AUDIO_STOP");
  640.         queue_post(&audio_queue, Q_AUDIO_STOP, 0);
  641.         LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
  642.         queue_post(&audio_queue, Q_AUDIO_PLAY, offset);
  643.     }
  644.  
  645.     /* Don't return until playback has actually started */
  646.     while (!playing)
  647.         yield();
  648. }
  649.  
  650. void audio_stop(void)
  651. {
  652.     /* Stop playback */
  653.     LOGFQUEUE("audio > audio Q_AUDIO_STOP");
  654.     queue_post(&audio_queue, Q_AUDIO_STOP, 0);
  655.  
  656.     /* Don't return until playback has actually stopped */
  657.     while(playing || !queue_empty(&audio_queue))
  658.         yield();
  659. }
  660.  
  661. void audio_pause(void)
  662. {
  663.     LOGFQUEUE("audio > audio Q_AUDIO_PAUSE");
  664.     queue_post(&audio_queue, Q_AUDIO_PAUSE, true);
  665. }
  666.  
  667. void audio_resume(void)
  668. {
  669.     LOGFQUEUE("audio > audio Q_AUDIO_PAUSE resume");
  670.     queue_post(&audio_queue, Q_AUDIO_PAUSE, false);
  671. }
  672.  
  673. void audio_next(void)
  674. {
  675.     if (playlist_check(ci.new_track + wps_offset + 1))
  676.     {
  677.         if (global_settings.beep)
  678.             pcmbuf_beep(5000, 100, 2500*global_settings.beep);
  679.  
  680.         LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
  681.         queue_post(&audio_queue, Q_AUDIO_SKIP, 1);
  682.         /* Update wps while our message travels inside deep playback queues. */
  683.         wps_offset++;
  684.         track_changed = true;
  685.     }
  686.     else
  687.     {
  688.         /* No more tracks. */
  689.         if (global_settings.beep)
  690.             pcmbuf_beep(1000, 100, 1000*global_settings.beep);
  691.     }
  692. }
  693.  
  694. void audio_prev(void)
  695. {
  696.     if (playlist_check(ci.new_track + wps_offset - 1))
  697.     {
  698.         if (global_settings.beep)
  699.             pcmbuf_beep(5000, 100, 2500*global_settings.beep);
  700.  
  701.         LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
  702.         queue_post(&audio_queue, Q_AUDIO_SKIP, -1);
  703.         /* Update wps while our message travels inside deep playback queues. */
  704.         wps_offset--;
  705.         track_changed = true;
  706.     }
  707.     else
  708.     {
  709.         /* No more tracks. */
  710.         if (global_settings.beep)
  711.             pcmbuf_beep(1000, 100, 1000*global_settings.beep);
  712.     }
  713. }
  714.  
  715. void audio_next_dir(void)
  716. {
  717.     LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
  718.     queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
  719. }
  720.  
  721. void audio_prev_dir(void)
  722. {
  723.     LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
  724.     queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
  725. }
  726.  
  727. void audio_pre_ff_rewind(void)
  728. {
  729.     LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
  730.     queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
  731. }
  732.  
  733. void audio_ff_rewind(long newpos)
  734. {
  735.     LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
  736.     queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
  737. }
  738.  
  739. void audio_flush_and_reload_tracks(void)
  740. {
  741.     LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
  742.     queue_post(&audio_queue, Q_AUDIO_FLUSH, 0);
  743. }
  744.  
  745. void audio_error_clear(void)
  746. {
  747. #ifdef AUDIO_HAVE_RECORDING
  748.     pcm_rec_error_clear();
  749. #endif
  750. }
  751.  
  752. int audio_status(void)
  753. {
  754.     int ret = 0;
  755.  
  756.     if (playing)
  757.         ret |= AUDIO_STATUS_PLAY;
  758.  
  759.     if (paused)
  760.         ret |= AUDIO_STATUS_PAUSE;
  761.  
  762. #ifdef HAVE_RECORDING
  763.     /* Do this here for constitency with mpeg.c version */
  764.     ret |= pcm_rec_status();
  765. #endif
  766.  
  767.     return ret;
  768. }
  769.  
  770. int audio_get_file_pos(void)
  771. {
  772.     return 0;
  773. }
  774.  
  775. void audio_set_buffer_margin(int setting)
  776. {
  777.     static const int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
  778.     buffer_margin = lookup[setting];
  779.     logf("buffer margin: %ds", buffer_margin);
  780.     set_filebuf_watermark(buffer_margin);
  781. }
  782.  
  783. /* Set crossfade & PCM buffer length. */
  784. void audio_set_crossfade(int enable)
  785. {
  786.     size_t size;
  787.     bool was_playing = (playing && audio_is_initialized);
  788.     size_t offset = 0;
  789. #if MEM > 1
  790.     int seconds = 1;
  791. #endif
  792.  
  793.     if (!filebuf)
  794.         return;     /* Audio buffers not yet set up */
  795.  
  796. #if MEM > 1
  797.     if (enable)
  798.         seconds = global_settings.crossfade_fade_out_delay
  799.                 + global_settings.crossfade_fade_out_duration;
  800.  
  801.     /* Buffer has to be at least 2s long. */
  802.     seconds += 2;
  803.     logf("buf len: %d", seconds);
  804.     size = seconds * (NATIVE_FREQUENCY*4);
  805. #else
  806.     enable = 0;
  807.     size = NATIVE_FREQUENCY*2;
  808. #endif
  809.     if (buffer_state == BUFFER_STATE_NORMAL && pcmbuf_is_same_size(size))
  810.         return ;
  811.  
  812.     if (was_playing)
  813.     {
  814.         /* Store the track resume position */
  815.         offset = CUR_TI->id3.offset;
  816.  
  817.         /* Playback has to be stopped before changing the buffer size. */
  818.         gui_syncsplash(0, true, (char *)str(LANG_RESTARTING_PLAYBACK));
  819.         audio_stop();
  820.     }
  821.  
  822.     voice_stop();
  823.  
  824.     /* Re-initialize audio system. */
  825.     audio_reset_buffer(size);
  826.     pcmbuf_crossfade_enable(enable);
  827.     logf("abuf:%dB", pcmbuf_get_bufsize());
  828.     logf("fbuf:%dB", filebuflen);
  829.  
  830.     voice_init();
  831.  
  832.     /* Restart playback. */
  833.     if (was_playing)
  834.         audio_play(offset);
  835. }
  836.  
  837. void audio_preinit(void)
  838. {
  839.     logf("playback system pre-init");
  840.  
  841.     filling = false;
  842.     current_codec = CODEC_IDX_AUDIO;
  843.     playing = false;
  844.     paused = false;
  845.     audio_codec_loaded = false;
  846. #ifdef PLAYBACK_VOICE
  847.     voice_is_playing = false;
  848.     voice_thread_start = false;
  849.     voice_codec_loaded = false;
  850. #endif
  851.     track_changed = false;
  852.     current_fd = -1;
  853.     track_buffer_callback = NULL;
  854.     track_unbuffer_callback = NULL;
  855.     track_changed_callback = NULL;
  856.     track_ridx = 0; /* Just to prevent CUR_TI from being anything random. */
  857.     prev_ti = &tracks[MAX_TRACK-1]; /* And prevent prev_ti being random too */
  858.  
  859. #ifdef PLAYBACK_VOICE
  860.     mutex_init(&mutex_codecthread);
  861. #endif
  862.  
  863.     queue_init(&audio_queue, true);
  864.     queue_enable_queue_send(&audio_queue, &audio_queue_sender_list);
  865.     queue_init(&codec_queue, true);
  866.  
  867.     create_thread(audio_thread, audio_stack, sizeof(audio_stack),
  868.                   audio_thread_name IF_PRIO(, PRIORITY_BUFFERING));
  869. }
  870.  
  871. void audio_init(void)
  872. {
  873.     LOGFQUEUE("audio > audio Q_AUDIO_POSTINIT");
  874.     queue_post(&audio_queue, Q_AUDIO_POSTINIT, 0);
  875. }
  876.  
  877. void voice_init(void)
  878. {
  879. #ifdef PLAYBACK_VOICE
  880.     if (!filebuf)
  881.         return;     /* Audio buffers not yet set up */
  882.  
  883.     if (voice_thread_p)
  884.         return;
  885.  
  886.     if (!talk_voice_required())
  887.         return;
  888.  
  889.     logf("Starting voice codec");
  890.     queue_init(&voice_queue, true);
  891.     voice_thread_p = create_thread(voice_thread, voice_stack,
  892.             sizeof(voice_stack), voice_thread_name
  893.             IF_PRIO(, PRIORITY_PLAYBACK));
  894.    
  895.     while (!voice_codec_loaded)
  896.         yield();
  897. #endif
  898. } /* voice_init */
  899.  
  900. void voice_stop(void)
  901. {
  902. #ifdef PLAYBACK_VOICE
  903.     /* Messages should not be posted to voice codec queue unless it is the
  904.        current codec or deadlocks happen. */
  905.     if (current_codec != CODEC_IDX_VOICE)
  906.         return;
  907.  
  908.     LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
  909.     queue_post(&voice_queue, Q_VOICE_STOP, 0);
  910.     while (voice_is_playing || !queue_empty(&voice_queue))
  911.         yield();
  912.     if (!playing)   
  913.         pcmbuf_play_stop();
  914. #endif
  915. } /* voice_stop */
  916.  
  917.  
  918.  
  919. /* --- Routines called from multiple threads --- */
  920. #ifdef PLAYBACK_VOICE
  921. static void swap_codec(void)
  922. {
  923.     int my_codec = current_codec;
  924.  
  925.     logf("swapping out codec:%d", my_codec);
  926.  
  927.     /* Save our current IRAM and DRAM */
  928. #ifdef IRAM_STEAL
  929.     if (voice_iram_stolen)
  930.     {
  931.         logf("swap: iram restore");
  932.         voice_iram_stolen = false;
  933.         /* Don't swap trashed data into buffer - _should_ always be the case
  934.            if voice_iram_stolen is true since the voice has been swapped in
  935.            before hand */
  936.         if (my_codec == CODEC_IDX_VOICE)
  937.             goto skip_iram_swap;
  938.     }
  939. #endif
  940.  
  941.     memcpy(iram_buf[my_codec], (unsigned char *)CODEC_IRAM_ORIGIN,
  942.             CODEC_IRAM_SIZE);
  943.  
  944. #ifdef IRAM_STEAL
  945. skip_iram_swap:
  946. #endif
  947.  
  948.     memcpy(dram_buf[my_codec], codecbuf, CODEC_SIZE);
  949.  
  950.     /* Release my semaphore */
  951.     mutex_unlock(&mutex_codecthread);
  952.  
  953.     /* Loop until the other codec has locked and run */
  954.     do {
  955.         /* Release my semaphore and force a task switch. */
  956.         yield();
  957.     } while (my_codec == current_codec);
  958.  
  959.     /* Wait for other codec to unlock */
  960.     mutex_lock(&mutex_codecthread);
  961.  
  962.     /* Take control */
  963.     current_codec = my_codec;
  964.  
  965.     /* Reload our IRAM and DRAM */
  966.     memcpy((unsigned char *)CODEC_IRAM_ORIGIN, iram_buf[my_codec],
  967.             CODEC_IRAM_SIZE);
  968.     invalidate_icache();
  969.     memcpy(codecbuf, dram_buf[my_codec], CODEC_SIZE);
  970.  
  971.     logf("resuming codec:%d", my_codec);
  972. }
  973. #endif
  974.  
  975. static void set_filebuf_watermark(int seconds)
  976. {
  977.     size_t bytes;
  978.  
  979.     if (current_codec == CODEC_IDX_VOICE)
  980.         return;
  981.  
  982.     if (!filebuf)
  983.         return;     /* Audio buffers not yet set up */
  984.  
  985.     bytes = MAX(CUR_TI->id3.bitrate * seconds * (1000/8), conf_watermark);
  986.     bytes = MIN(bytes, filebuflen / 2);
  987.     conf_watermark = bytes;
  988. }
  989.  
  990. static const char * get_codec_filename(int cod_spec)
  991. {
  992.     const char *fname;
  993.  
  994. #ifdef HAVE_RECORDING
  995.     /* Can choose decoder or encoder if one available */
  996.     int type = cod_spec & CODEC_TYPE_MASK;
  997.     int afmt = cod_spec & CODEC_AFMT_MASK;
  998.  
  999.     if ((unsigned)afmt >= AFMT_NUM_CODECS)
  1000.         type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
  1001.  
  1002.     fname = (type == CODEC_TYPE_ENCODER) ?
  1003.                 audio_formats[afmt].codec_enc_root_fn :
  1004.                 audio_formats[afmt].codec_root_fn;
  1005.  
  1006.     logf("%s: %d - %s",
  1007.         (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
  1008.         afmt, fname ? fname : "<unknown>");
  1009. #else /* !HAVE_RECORDING */
  1010.     /* Always decoder */
  1011.     if ((unsigned)cod_spec >= AFMT_NUM_CODECS)
  1012.         cod_spec = AFMT_UNKNOWN;
  1013.     fname = audio_formats[cod_spec].codec_root_fn;
  1014.     logf("Codec: %d - %s",  cod_spec, fname ? fname : "<unknown>");
  1015. #endif /* HAVE_RECORDING */
  1016.  
  1017.     return fname;
  1018. } /* get_codec_filename */
  1019.  
  1020.  
  1021. /* --- Voice thread --- */
  1022.  
  1023. #ifdef PLAYBACK_VOICE
  1024.  
  1025. static bool voice_pcmbuf_insert_split_callback(
  1026.         const void *ch1, const void *ch2, size_t length)
  1027. {
  1028.     const char* src[2];
  1029.     char *dest;
  1030.     long input_size;
  1031.     size_t output_size;
  1032.  
  1033.     src[0] = ch1;
  1034.     src[1] = ch2;
  1035.  
  1036.     if (dsp_stereo_mode() == STEREO_NONINTERLEAVED)
  1037.         length *= 2;    /* Length is per channel */
  1038.  
  1039.     while (length)
  1040.     {
  1041.         long est_output_size = dsp_output_size(length);
  1042.        
  1043.         while ((dest = pcmbuf_request_voice_buffer(est_output_size,
  1044.                         &output_size, playing)) == NULL)
  1045.         {
  1046.             if (playing && audio_codec_loaded)
  1047.                 swap_codec();
  1048.             else
  1049.                 yield();
  1050.         }
  1051.        
  1052.         /* Get the real input_size for output_size bytes, guarding
  1053.          * against resampling buffer overflows. */
  1054.         input_size = dsp_input_size(output_size);
  1055.  
  1056.         if (input_size <= 0)
  1057.         {
  1058.             DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld<=0\n",
  1059.                     output_size, length, input_size);
  1060.             /* If this happens, there are samples of codec data that don't
  1061.              * become a number of pcm samples, and something is broken */
  1062.             return false;
  1063.         }
  1064.  
  1065.         /* Input size has grown, no error, just don't write more than length */
  1066.         if ((size_t)input_size > length)
  1067.             input_size = length;
  1068.  
  1069.         output_size = dsp_process(dest, src, input_size);
  1070.  
  1071.         if (playing)
  1072.         {
  1073.             pcmbuf_mix_voice(output_size);
  1074.             if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
  1075.                     audio_codec_loaded)
  1076.                 swap_codec();
  1077.         }
  1078.         else
  1079.             pcmbuf_write_complete(output_size);
  1080.  
  1081.         length -= input_size;
  1082.     }
  1083.  
  1084.     return true;
  1085. } /* voice_pcmbuf_insert_split_callback */
  1086.  
  1087. static bool voice_pcmbuf_insert_callback(const char *buf, size_t length)
  1088. {
  1089.     /* TODO: The audiobuffer API should probably be updated, and be based on
  1090.      *       pcmbuf_insert_split().  */
  1091.     long real_length = length;
  1092.  
  1093.     if (dsp_stereo_mode() == STEREO_NONINTERLEAVED)
  1094.         length /= 2;    /* Length is per channel */
  1095.  
  1096.     /* Second channel is only used for non-interleaved stereo. */
  1097.     return voice_pcmbuf_insert_split_callback(buf, buf + (real_length / 2),
  1098.         length);
  1099. }
  1100.  
  1101. static void* voice_get_memory_callback(size_t *size)
  1102. {
  1103.     *size = 0;
  1104.     return NULL;
  1105. }
  1106.  
  1107. static void voice_set_elapsed_callback(unsigned int value)
  1108. {
  1109.     (void)value;
  1110. }
  1111.  
  1112. static void voice_set_offset_callback(size_t value)
  1113. {
  1114.     (void)value;
  1115. }
  1116.  
  1117. static size_t voice_filebuf_callback(void *ptr, size_t size)
  1118. {
  1119.     (void)ptr;
  1120.     (void)size;
  1121.  
  1122.     return 0;
  1123. }
  1124.  
  1125. static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
  1126. {
  1127.     struct event ev;
  1128.  
  1129.     if (ci_voice.new_track)
  1130.     {
  1131.         *realsize = 0;
  1132.         return NULL;
  1133.     }
  1134.  
  1135.     while (1)
  1136.     {
  1137.         if (voice_is_playing || playing)
  1138.             queue_wait_w_tmo(&voice_queue, &ev, 0);
  1139.         else
  1140.             queue_wait(&voice_queue, &ev);
  1141.         if (!voice_is_playing)
  1142.         {
  1143.             if (ev.id == SYS_TIMEOUT)
  1144.                 ev.id = Q_AUDIO_PLAY;
  1145.         }
  1146.  
  1147.         switch (ev.id) {
  1148.             case Q_AUDIO_PLAY:
  1149.                 LOGFQUEUE("voice < Q_AUDIO_PLAY");
  1150.                 if (playing)
  1151.                 {
  1152.                     if (audio_codec_loaded)
  1153.                         swap_codec();
  1154.                     yield();
  1155.                 }
  1156.                 break;
  1157.  
  1158. #ifdef AUDIO_HAVE_RECORDING
  1159.             case Q_ENCODER_RECORD:
  1160.                 LOGFQUEUE("voice < Q_ENCODER_RECORD");
  1161.                 swap_codec();
  1162.                 break;
  1163. #endif
  1164.  
  1165.             case Q_VOICE_STOP:
  1166.                 LOGFQUEUE("voice < Q_VOICE_STOP");
  1167.                 if (ev.data == 1 && !playing && pcm_is_playing())
  1168.                 {
  1169.                     /* Aborting: Slight hack - flush PCM buffer if
  1170.                        only being used for voice */
  1171.                     pcmbuf_play_stop();
  1172.                 }
  1173.                 if (voice_is_playing)
  1174.                 {
  1175.                     /* Clear the current buffer */
  1176.                     voice_is_playing = false;
  1177.                     voice_getmore = NULL;
  1178.                     voice_remaining = 0;
  1179.                     voicebuf = NULL;
  1180.  
  1181.                     /* Force the codec to think it's changing tracks */
  1182.                     ci_voice.new_track = 1;
  1183.                     *realsize = 0;
  1184.                     return NULL;
  1185.                 }
  1186.                 else
  1187.                     break;
  1188.  
  1189.             case SYS_USB_CONNECTED:
  1190.                 LOGFQUEUE("voice < SYS_USB_CONNECTED");
  1191.                 usb_acknowledge(SYS_USB_CONNECTED_ACK);
  1192.                 if (audio_codec_loaded)
  1193.                     swap_codec();
  1194.                 usb_wait_for_disconnect(&voice_queue);
  1195.                 break;
  1196.  
  1197.             case Q_VOICE_PLAY:
  1198.                 LOGFQUEUE("voice < Q_VOICE_PLAY");
  1199.                 if (!voice_is_playing)
  1200.                 {
  1201.                     /* Set up new voice data */
  1202.                     struct voice_info *voice_data;
  1203. #ifdef IRAM_STEAL
  1204.                     if (voice_iram_stolen)
  1205.                     {
  1206.                         logf("voice: iram restore");
  1207.                         memcpy((void*)CODEC_IRAM_ORIGIN,
  1208.                                iram_buf[CODEC_IDX_VOICE],
  1209.                                CODEC_IRAM_SIZE);
  1210.                         voice_iram_stolen = false;
  1211.                     }
  1212. #endif
  1213.                     /* must reset the buffer before any playback
  1214.                        begins if needed */
  1215.                     if (buffer_state == BUFFER_STATE_TRASHED)
  1216.                         audio_reset_buffer(pcmbuf_get_bufsize());
  1217.  
  1218.                     voice_is_playing = true;
  1219.                     trigger_cpu_boost();
  1220.                     voice_data = (struct voice_info *)ev.data;
  1221.                     voice_remaining = voice_data->size;
  1222.                     voicebuf = voice_data->buf;
  1223.                     voice_getmore = voice_data->callback;
  1224.                 }
  1225.                 goto voice_play_clip;
  1226.  
  1227.             case SYS_TIMEOUT:
  1228.                 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
  1229.                 goto voice_play_clip;
  1230.  
  1231.             default:
  1232.                 LOGFQUEUE("voice < default");
  1233.         }
  1234.     }
  1235.  
  1236. voice_play_clip:
  1237.  
  1238.     if (voice_remaining == 0 || voicebuf == NULL)
  1239.     {
  1240.         if (voice_getmore)
  1241.             voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining);
  1242.  
  1243.         /* If this clip is done */
  1244.         if (voice_remaining == 0)
  1245.         {
  1246.             LOGFQUEUE("voice > voice Q_VOICE_STOP");
  1247.             queue_post(&voice_queue, Q_VOICE_STOP, 0);
  1248.             /* Force pcm playback. */
  1249.             if (!pcm_is_playing())
  1250.                 pcmbuf_play_start();
  1251.         }
  1252.     }
  1253.    
  1254.     *realsize = MIN(voice_remaining, reqsize);
  1255.  
  1256.     if (*realsize == 0)
  1257.         return NULL;
  1258.  
  1259.     return voicebuf;
  1260. } /* voice_request_buffer_callback */
  1261.  
  1262. static void voice_advance_buffer_callback(size_t amount)
  1263. {
  1264.     amount = MIN(amount, voice_remaining);
  1265.     voicebuf += amount;
  1266.     voice_remaining -= amount;
  1267. }
  1268.  
  1269. static void voice_advance_buffer_loc_callback(void *ptr)
  1270. {
  1271.     size_t amount = (size_t)ptr - (size_t)voicebuf;
  1272.    
  1273.     voice_advance_buffer_callback(amount);
  1274. }
  1275.  
  1276. static off_t voice_mp3_get_filepos_callback(int newtime)
  1277. {
  1278.     (void)newtime;
  1279.    
  1280.     return 0;
  1281. }
  1282.  
  1283. static void voice_do_nothing(void)
  1284. {
  1285.     return;
  1286. }
  1287.  
  1288. static bool voice_seek_buffer_callback(size_t newpos)
  1289. {
  1290.     (void)newpos;
  1291.    
  1292.     return false;
  1293. }
  1294.  
  1295. static bool voice_request_next_track_callback(void)
  1296. {
  1297.     ci_voice.new_track = 0;
  1298.     return true;
  1299. }
  1300.  
  1301. static void voice_thread(void)
  1302. {
  1303.     while (1)
  1304.     {
  1305.         logf("Loading voice codec");
  1306.         voice_codec_loaded = true;
  1307.         mutex_lock(&mutex_codecthread);
  1308.         current_codec = CODEC_IDX_VOICE;
  1309.         dsp_configure(DSP_RESET, 0);
  1310.         voice_remaining = 0;
  1311.         voice_getmore = NULL;
  1312.  
  1313.         codec_load_file(get_codec_filename(AFMT_MPA_L3), &ci_voice);
  1314.  
  1315.         logf("Voice codec finished");
  1316.         voice_codec_loaded = false;
  1317.         mutex_unlock(&mutex_codecthread);
  1318.     }
  1319. } /* voice_thread */
  1320.  
  1321. #endif /* PLAYBACK_VOICE */
  1322.  
  1323. /* --- Codec thread --- */
  1324.  
  1325. static bool codec_pcmbuf_insert_split_callback(
  1326.         const void *ch1, const void *ch2, size_t length)
  1327. {
  1328.     const char* src[2];
  1329.     char *dest;
  1330.     long input_size;
  1331.     size_t output_size;
  1332.  
  1333.     src[0] = ch1;
  1334.     src[1] = ch2;
  1335.  
  1336.     if (dsp_stereo_mode() == STEREO_NONINTERLEAVED)
  1337.         length *= 2;    /* Length is per channel */
  1338.  
  1339.     while (length)
  1340.     {
  1341.         long est_output_size = dsp_output_size(length);
  1342.         /* Prevent audio from a previous track from playing */
  1343.         if (ci.new_track || ci.stop_codec)
  1344.             return true;
  1345.  
  1346.         while ((dest = pcmbuf_request_buffer(est_output_size,
  1347.                         &output_size)) == NULL)
  1348.         {
  1349.             sleep(1);
  1350.             if (ci.seek_time || ci.new_track || ci.stop_codec)
  1351.                 return true;
  1352.         }
  1353.  
  1354.         /* Get the real input_size for output_size bytes, guarding
  1355.          * against resampling buffer overflows. */
  1356.         input_size = dsp_input_size(output_size);
  1357.  
  1358.         if (input_size <= 0)
  1359.         {
  1360.             DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld<=0\n",
  1361.                     output_size, length, input_size);
  1362.             /* If this happens, there are samples of codec data that don't
  1363.              * become a number of pcm samples, and something is broken */
  1364.             return false;
  1365.         }
  1366.  
  1367.         /* Input size has grown, no error, just don't write more than length */
  1368.         if ((size_t)input_size > length)
  1369.             input_size = length;
  1370.  
  1371.         output_size = dsp_process(dest, src, input_size);
  1372.  
  1373.         pcmbuf_write_complete(output_size);
  1374.  
  1375. #ifdef PLAYBACK_VOICE
  1376.         if ((voice_is_playing || voice_thread_start)
  1377.             && pcm_is_playing() && voice_codec_loaded &&
  1378.             pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
  1379.         {
  1380.             voice_thread_start = false;
  1381.             swap_codec();
  1382.         }
  1383. #endif
  1384.        
  1385.         length -= input_size;
  1386.     }
  1387.  
  1388.     return true;
  1389. } /* codec_pcmbuf_insert_split_callback */
  1390.  
  1391. static bool codec_pcmbuf_insert_callback(const char *buf, size_t length)
  1392. {
  1393.     /* TODO: The audiobuffer API should probably be updated, and be based on
  1394.      *       pcmbuf_insert_split().  */
  1395.     long real_length = length;
  1396.  
  1397.     if (dsp_stereo_mode() == STEREO_NONINTERLEAVED)
  1398.         length /= 2;    /* Length is per channel */
  1399.  
  1400.     /* Second channel is only used for non-interleaved stereo. */
  1401.     return codec_pcmbuf_insert_split_callback(buf, buf + (real_length / 2),
  1402.         length);
  1403. }
  1404.  
  1405. static void* codec_get_memory_callback(size_t *size)
  1406. {
  1407.     *size = MALLOC_BUFSIZE;
  1408.     return &audiobuf[talk_get_bufsize()];
  1409. }
  1410.  
  1411. static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
  1412. static void codec_pcmbuf_position_callback(size_t size)
  1413. {
  1414.     /* This is called from an ISR, so be quick */
  1415.     unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
  1416.         prev_ti->id3.elapsed;
  1417.    
  1418.     if (time >= prev_ti->id3.length)
  1419.     {
  1420.         pcmbuf_set_position_callback(NULL);
  1421.         prev_ti->id3.elapsed = prev_ti->id3.length;
  1422.     }
  1423.     else
  1424.         prev_ti->id3.elapsed = time;
  1425. }
  1426.  
  1427. static void codec_set_elapsed_callback(unsigned int value)
  1428. {
  1429.     unsigned int latency;
  1430.     if (ci.seek_time)
  1431.         return;
  1432.  
  1433. #ifdef AB_REPEAT_ENABLE
  1434.     ab_position_report(value);
  1435. #endif
  1436.  
  1437.     latency = pcmbuf_get_latency();
  1438.     if (value < latency)
  1439.         CUR_TI->id3.elapsed = 0;
  1440.     else if (value - latency > CUR_TI->id3.elapsed ||
  1441.             value - latency < CUR_TI->id3.elapsed - 2)
  1442.     {
  1443.         CUR_TI->id3.elapsed = value - latency;
  1444.     }
  1445. }
  1446.  
  1447. static void codec_set_offset_callback(size_t value)
  1448. {
  1449.     unsigned int latency;
  1450.    
  1451.     if (ci.seek_time)
  1452.         return;
  1453.  
  1454.     latency = pcmbuf_get_latency() * CUR_TI->id3.bitrate / 8;
  1455.     if (value < latency)
  1456.         CUR_TI->id3.offset = 0;
  1457.     else
  1458.         CUR_TI->id3.offset = value - latency;
  1459. }
  1460.  
  1461. static void codec_advance_buffer_counters(size_t amount)
  1462. {
  1463.     buf_ridx = RINGBUF_ADD(buf_ridx, amount);
  1464.     ci.curpos += amount;
  1465.     CUR_TI->available -= amount;
  1466.  
  1467.     /* Start buffer filling as necessary. */
  1468.     if (!pcmbuf_is_lowdata() && !filling)
  1469.     {
  1470.         if (FILEBUFUSED < conf_watermark && playing && !playlist_end)
  1471.         {
  1472.             LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
  1473.             queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
  1474.         }
  1475.     }
  1476. }
  1477.  
  1478. /* copy up-to size bytes into ptr and return the actual size copied */
  1479. static size_t codec_filebuf_callback(void *ptr, size_t size)
  1480. {
  1481.     char *buf = (char *)ptr;
  1482.     size_t copy_n;
  1483.     size_t part_n;
  1484.  
  1485.     if (ci.stop_codec || !playing)
  1486.         return 0;
  1487.  
  1488.     /* The ammount to copy is the lesser of the requested amount and the
  1489.      * amount left of the current track (both on disk and already loaded) */
  1490.     copy_n = MIN(size, CUR_TI->available + CUR_TI->filerem);
  1491.  
  1492.     /* Nothing requested OR nothing left */
  1493.     if (copy_n == 0)
  1494.         return 0;
  1495.  
  1496.     /* Let the disk buffer catch fill until enough data is available */
  1497.     while (copy_n > CUR_TI->available)
  1498.     {
  1499.         if (!filling)
  1500.         {
  1501.             LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
  1502.             queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
  1503.         }
  1504.        
  1505.         sleep(1);
  1506.         if (ci.stop_codec || ci.new_track)
  1507.             return 0;
  1508.     }
  1509.  
  1510.     /* Copy as much as possible without wrapping */
  1511.     part_n = MIN(copy_n, filebuflen - buf_ridx);
  1512.     memcpy(buf, &filebuf[buf_ridx], part_n);
  1513.     /* Copy the rest in the case of a wrap */
  1514.     if (part_n < copy_n) {
  1515.         memcpy(&buf[part_n], &filebuf[0], copy_n - part_n);
  1516.     }
  1517.  
  1518.     /* Update read and other position pointers */
  1519.     codec_advance_buffer_counters(copy_n);
  1520.  
  1521.     /* Return the actual amount of data copied to the buffer */
  1522.     return copy_n;
  1523. } /* codec_filebuf_callback */
  1524.  
  1525. static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
  1526. {
  1527.     size_t short_n, copy_n, buf_rem;
  1528.  
  1529.     if (!playing)
  1530.     {
  1531.         *realsize = 0;
  1532.         return NULL;
  1533.     }
  1534.  
  1535.     copy_n = MIN(reqsize, CUR_TI->available + CUR_TI->filerem);
  1536.     if (copy_n == 0)
  1537.     {
  1538.         *realsize = 0;
  1539.         return NULL;
  1540.     }
  1541.  
  1542.     while (copy_n > CUR_TI->available)
  1543.     {
  1544.         if (!filling)
  1545.         {
  1546.             LOGFQUEUE("codec > audio Q_AUDIO_FILL_BUFFER");
  1547.             queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0);
  1548.         }
  1549.        
  1550.         sleep(1);
  1551.         if (ci.stop_codec || ci.new_track)
  1552.         {
  1553.             *realsize = 0;
  1554.             return NULL;
  1555.         }
  1556.     }
  1557.  
  1558.     /* How much is left at the end of the file buffer before wrap? */
  1559.     buf_rem = filebuflen - buf_ridx;
  1560.    
  1561.     /* If we can't satisfy the request without wrapping */
  1562.     if (buf_rem < copy_n)
  1563.     {
  1564.         /* How short are we? */
  1565.         short_n = copy_n - buf_rem;
  1566.        
  1567.         /* If we can fudge it with the guardbuf */
  1568.         if (short_n < GUARD_BUFSIZE)
  1569.             memcpy(&filebuf[filebuflen], &filebuf[0], short_n);
  1570.         else
  1571.             copy_n = buf_rem;
  1572.     }
  1573.  
  1574.     *realsize = copy_n;
  1575.    
  1576.     return (char *)&filebuf[buf_ridx];
  1577. } /* codec_request_buffer_callback */
  1578.  
  1579. static int get_codec_base_type(int type)
  1580. {
  1581.     switch (type) {
  1582.         case AFMT_MPA_L1:
  1583.         case AFMT_MPA_L2:
  1584.         case AFMT_MPA_L3:
  1585.             return AFMT_MPA_L3;
  1586.     }
  1587.  
  1588.     return type;
  1589. }
  1590.  
  1591. static void codec_advance_buffer_callback(size_t amount)
  1592. {
  1593.     if (amount > CUR_TI->available + CUR_TI->filerem)
  1594.         amount = CUR_TI->available + CUR_TI->filerem;
  1595.  
  1596.     while (amount > CUR_TI->available && filling)
  1597.         sleep(1);
  1598.  
  1599.     if (amount > CUR_TI->available)
  1600.     {
  1601.         intptr_t result;
  1602.         LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
  1603.        
  1604.         result = queue_send(&audio_queue, Q_AUDIO_REBUFFER_SEEK,
  1605.                             ci.curpos + amount);
  1606.  
  1607.         switch (result)
  1608.         {
  1609.             case Q_CODEC_REQUEST_FAILED:
  1610.                 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
  1611.                 ci.stop_codec = true;
  1612.                 return;
  1613.  
  1614.             case Q_CODEC_REQUEST_COMPLETE:
  1615.                 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
  1616.                 return;           
  1617.  
  1618.             default:
  1619.                 LOGFQUEUE("codec |< default");
  1620.                 ci.stop_codec = true;
  1621.                 return;
  1622.         }
  1623.     }
  1624.  
  1625.     codec_advance_buffer_counters(amount);
  1626.  
  1627.     codec_set_offset_callback(ci.curpos);
  1628. }
  1629.  
  1630. static void codec_advance_buffer_loc_callback(void *ptr)
  1631. {
  1632.     size_t amount = (size_t)ptr - (size_t)&filebuf[buf_ridx];
  1633.    
  1634.     codec_advance_buffer_callback(amount);
  1635. }
  1636.  
  1637. /* Copied from mpeg.c. Should be moved somewhere else. */
  1638. static int codec_get_file_pos(void)
  1639. {
  1640.     int pos = -1;
  1641.     struct mp3entry *id3 = audio_current_track();
  1642.  
  1643.     if (id3->vbr)
  1644.     {
  1645.         if (id3->has_toc)
  1646.         {
  1647.             /* Use the TOC to find the new position */
  1648.             unsigned int percent, remainder;
  1649.             int curtoc, nexttoc, plen;
  1650.  
  1651.             percent = (id3->elapsed*100)/id3->length;
  1652.             if (percent > 99)
  1653.                 percent = 99;
  1654.  
  1655.             curtoc = id3->toc[percent];
  1656.  
  1657.             if (percent < 99)
  1658.                 nexttoc = id3->toc[percent+1];
  1659.             else
  1660.                 nexttoc = 256;
  1661.  
  1662.             pos = (id3->filesize/256)*curtoc;
  1663.  
  1664.             /* Use the remainder to get a more accurate position */
  1665.             remainder   = (id3->elapsed*100)%id3->length;
  1666.             remainder   = (remainder*100)/id3->length;
  1667.             plen        = (nexttoc - curtoc)*(id3->filesize/256);
  1668.             pos        += (plen/100)*remainder;
  1669.         }
  1670.         else
  1671.         {
  1672.             /* No TOC exists, estimate the new position */
  1673.             pos = (id3->filesize / (id3->length / 1000)) *
  1674.                 (id3->elapsed / 1000);
  1675.         }
  1676.     }
  1677.     else if (id3->bitrate)
  1678.         pos = id3->elapsed * (id3->bitrate / 8);
  1679.     else
  1680.         return -1;
  1681.  
  1682.     pos += id3->first_frame_offset;
  1683.  
  1684.     /* Don't seek right to the end of the file so that we can
  1685.        transition properly to the next song */
  1686.     if (pos >= (int)(id3->filesize - id3->id3v1len))
  1687.         pos = id3->filesize - id3->id3v1len - 1;
  1688.  
  1689.     return pos;
  1690. }
  1691.  
  1692. static off_t codec_mp3_get_filepos_callback(int newtime)
  1693. {
  1694.     off_t newpos;
  1695.  
  1696.     CUR_TI->id3.elapsed = newtime;
  1697.     newpos = codec_get_file_pos();
  1698.  
  1699.     return newpos;
  1700. }
  1701.  
  1702. static void codec_seek_complete_callback(void)
  1703. {
  1704.     logf("seek_complete");
  1705.     if (pcm_is_paused())
  1706.     {
  1707.         /* If this is not a seamless seek, clear the buffer */
  1708.         pcmbuf_play_stop();
  1709.         dsp_configure(DSP_FLUSH, NULL);
  1710.  
  1711.         /* If playback was not 'deliberately' paused, unpause now */
  1712.         if (!paused)
  1713.             pcmbuf_pause(false);
  1714.     }
  1715.     ci.seek_time = 0;
  1716. }
  1717.  
  1718. static bool codec_seek_buffer_callback(size_t newpos)
  1719. {
  1720.     int difference;
  1721.  
  1722.     logf("codec_seek_buffer_callback");
  1723.  
  1724.     if (newpos >= CUR_TI->filesize)
  1725.         newpos = CUR_TI->filesize - 1;
  1726.  
  1727.     difference = newpos - ci.curpos;
  1728.     if (difference >= 0)
  1729.     {
  1730.         /* Seeking forward */
  1731.         logf("seek: +%d", difference);
  1732.         codec_advance_buffer_callback(difference);
  1733.         return true;
  1734.     }
  1735.  
  1736.     /* Seeking backward */
  1737.     difference = -difference;
  1738.     if (ci.curpos - difference < 0)
  1739.         difference = ci.curpos;
  1740.  
  1741.     /* We need to reload the song. */
  1742.     if (newpos < CUR_TI->start_pos)
  1743.     {
  1744.         intptr_t result;
  1745.        
  1746.         LOGFQUEUE("codec >| audio Q_AUDIO_REBUFFER_SEEK");
  1747.         result = queue_send(&audio_queue, Q_AUDIO_REBUFFER_SEEK, newpos);
  1748.        
  1749.         switch (result)
  1750.         {
  1751.             case Q_CODEC_REQUEST_COMPLETE:
  1752.                 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
  1753.                 return true;
  1754.            
  1755.             case Q_CODEC_REQUEST_FAILED:
  1756.                 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
  1757.                 ci.stop_codec = true;
  1758.                 return false;
  1759.            
  1760.             default:
  1761.                 LOGFQUEUE("codec |< default");
  1762.                 return false;
  1763.         }
  1764.     }
  1765.  
  1766.     /* Seeking inside buffer space. */
  1767.     logf("seek: -%d", difference);
  1768.     CUR_TI->available += difference;
  1769.     buf_ridx = RINGBUF_SUB(buf_ridx, (unsigned)difference);
  1770.     ci.curpos -= difference;
  1771.  
  1772.     return true;
  1773. }
  1774.  
  1775. static void codec_configure_callback(int setting, void *value)
  1776. {
  1777.     switch (setting) {
  1778.     case CODEC_SET_FILEBUF_WATERMARK:
  1779.         conf_watermark = (unsigned long)value;
  1780.         set_filebuf_watermark(buffer_margin);
  1781.         break;
  1782.  
  1783.     case CODEC_SET_FILEBUF_CHUNKSIZE:
  1784.         conf_filechunk = (unsigned long)value;
  1785.         break;
  1786.  
  1787.     case CODEC_SET_FILEBUF_PRESEEK:
  1788.         conf_preseek = (unsigned long)value;
  1789.         break;
  1790.  
  1791.     default:
  1792.         if (!dsp_configure(setting, value)) { logf("Illegal key:%d", setting); }
  1793.     }
  1794. }
  1795.  
  1796. static void codec_track_changed(void)
  1797. {
  1798.     automatic_skip = false;
  1799.     LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
  1800.     queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
  1801. }
  1802.  
  1803. static void codec_pcmbuf_track_changed_callback(void)
  1804. {
  1805.     pcmbuf_set_position_callback(NULL);
  1806.     codec_track_changed();
  1807. }
  1808.  
  1809. static void codec_discard_codec_callback(void)
  1810. {
  1811.     if (CUR_TI->has_codec)
  1812.     {
  1813.         CUR_TI->has_codec = false;
  1814.         buf_ridx = RINGBUF_ADD(buf_ridx, CUR_TI->codecsize);
  1815.     }
  1816.  
  1817. #if 0
  1818.     /* Check if a buffer desync has happened, log it and stop playback. */
  1819.     if (buf_ridx != CUR_TI->buf_idx)
  1820.     {
  1821.         int offset = CUR_TI->buf_idx - buf_ridx;
  1822.         size_t new_used = FILEBUFUSED - offset;
  1823.        
  1824.         logf("Buf off :%d=%d-%d", offset, CUR_TI->buf_idx, buf_ridx);
  1825.         logf("Used off:%d",FILEBUFUSED - new_used);
  1826.        
  1827.         /* This is a fatal internal error and it's not safe to
  1828.          * continue playback. */
  1829.         ci.stop_codec = true;
  1830.         queue_post(&audio_queue, Q_AUDIO_STOP, 0);
  1831.     }
  1832. #endif
  1833. }
  1834.  
  1835. static void codec_track_skip_done(bool was_manual)
  1836. {
  1837.     int crossfade_mode = global_settings.crossfade;
  1838.  
  1839.     /* Manual track change (always crossfade or flush audio). */
  1840.     if (was_manual)
  1841.     {
  1842.         pcmbuf_crossfade_init(true);
  1843.         LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
  1844.         queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
  1845.     }
  1846.     /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
  1847.     else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
  1848.              && crossfade_mode != CROSSFADE_ENABLE_TRACKSKIP)
  1849.     {
  1850.         if (crossfade_mode == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
  1851.         {
  1852.             if (global_settings.playlist_shuffle)
  1853.             {
  1854.                 /* shuffle mode is on, so crossfade: */
  1855.                 pcmbuf_crossfade_init(false);
  1856.                 codec_track_changed();
  1857.             }
  1858.             else
  1859.             {
  1860.                 /* shuffle mode is off, so do a gapless track change */
  1861.                pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
  1862.                pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
  1863.             }
  1864.         }
  1865.         else
  1866.         {
  1867.             /* normal crossfade:  */
  1868.             pcmbuf_crossfade_init(false);
  1869.                 codec_track_changed();
  1870.         }
  1871.     }
  1872.     else
  1873.     {
  1874.         /* normal gapless playback. */
  1875.         pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
  1876.                pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
  1877.     }
  1878. }
  1879.  
  1880. static bool codec_load_next_track(void)
  1881. {
  1882.     intptr_t result;
  1883.  
  1884.     prev_track_elapsed = CUR_TI->id3.elapsed;
  1885.  
  1886.     if (ci.seek_time)
  1887.         codec_seek_complete_callback();
  1888.  
  1889. #ifdef AB_REPEAT_ENABLE
  1890.     ab_end_of_track_report();
  1891. #endif
  1892.  
  1893.     logf("Request new track");
  1894.  
  1895.     if (ci.new_track == 0)
  1896.     {
  1897.         ci.new_track++;
  1898.         automatic_skip = true;
  1899.     }
  1900.    
  1901.     trigger_cpu_boost();
  1902.     LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
  1903.     result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
  1904.  
  1905. #if 0 /* Q_CODEC_REQUEST_PENDING never posted anyway */
  1906.     while (1)
  1907.     {
  1908.         queue_wait(&codec_callback_queue, &ev);
  1909.         if (ev.id == Q_CODEC_REQUEST_PENDING)
  1910.         {
  1911.             if (!automatic_skip)
  1912.                 pcmbuf_play_stop();
  1913.         }
  1914.         else
  1915.             break;
  1916.     }
  1917. #endif
  1918.  
  1919.     switch (result)
  1920.     {
  1921.         case Q_CODEC_REQUEST_COMPLETE:
  1922.             LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
  1923.             codec_track_skip_done(!automatic_skip);
  1924.             return true;
  1925.  
  1926.         case Q_CODEC_REQUEST_FAILED:
  1927.             LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
  1928.             ci.new_track = 0;
  1929.             ci.stop_codec = true;
  1930.             return false;
  1931.  
  1932.         default:
  1933.             LOGFQUEUE("codec |< default");
  1934.             ci.stop_codec = true;
  1935.             return false;
  1936.     }
  1937. }
  1938.  
  1939. static bool codec_request_next_track_callback(void)
  1940. {
  1941.     int prev_codectype;
  1942.  
  1943.     if (ci.stop_codec || !playing)
  1944.         return false;
  1945.  
  1946.     prev_codectype = get_codec_base_type(CUR_TI->id3.codectype);
  1947.  
  1948.     if (!codec_load_next_track())
  1949.         return false;
  1950.  
  1951.     /* Check if the next codec is the same file. */
  1952.     if (prev_codectype == get_codec_base_type(CUR_TI->id3.codectype))
  1953.     {
  1954.         logf("New track loaded");
  1955.         codec_discard_codec_callback();
  1956.         return true;
  1957.     }
  1958.     else
  1959.     {
  1960.         logf("New codec:%d/%d", CUR_TI->id3.codectype, prev_codectype);
  1961.         return false;
  1962.     }
  1963. }
  1964.  
  1965. static void codec_thread(void)
  1966. {
  1967.     struct event ev;
  1968.     int status;
  1969.     size_t wrap;
  1970.  
  1971.     while (1) {
  1972.         status = 0;
  1973.         queue_wait(&codec_queue, &ev);
  1974.  
  1975.         switch (ev.id) {
  1976.             case Q_CODEC_LOAD_DISK:
  1977.                 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
  1978.                 audio_codec_loaded = true;
  1979. #ifdef PLAYBACK_VOICE
  1980.                 /* Don't sent messages to voice codec if it's not current */
  1981.                 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
  1982.                 {
  1983.                     LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
  1984.                     queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
  1985.                 }
  1986.                 mutex_lock(&mutex_codecthread);
  1987. #endif
  1988.                 current_codec = CODEC_IDX_AUDIO;
  1989.                 ci.stop_codec = false;
  1990.                 status = codec_load_file((const char *)ev.data, &ci);
  1991. #ifdef PLAYBACK_VOICE
  1992.                 mutex_unlock(&mutex_codecthread);
  1993. #endif
  1994.                 break ;
  1995.  
  1996.             case Q_CODEC_LOAD:
  1997.                 LOGFQUEUE("codec < Q_CODEC_LOAD");
  1998.                 if (!CUR_TI->has_codec) {
  1999.                     logf("Codec slot is empty!");
  2000.                     /* Wait for the pcm buffer to go empty */
  2001.                     while (pcm_is_playing())
  2002.                         yield();
  2003.                     /* This must be set to prevent an infinite loop */
  2004.                     ci.stop_codec = true;
  2005.                     LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
  2006.                     queue_post(&codec_queue, Q_AUDIO_PLAY, 0);
  2007.                     break ;
  2008.                 }
  2009.  
  2010.                 audio_codec_loaded = true;
  2011. #ifdef PLAYBACK_VOICE
  2012.                 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
  2013.                 {
  2014.                     LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
  2015.                     queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
  2016.                 }
  2017.                 mutex_lock(&mutex_codecthread);
  2018. #endif
  2019.                 current_codec = CODEC_IDX_AUDIO;
  2020.                 ci.stop_codec = false;
  2021.                 wrap = (size_t)&filebuf[filebuflen] - (size_t)CUR_TI->codecbuf;
  2022.                 status = codec_load_ram(CUR_TI->codecbuf, CUR_TI->codecsize,
  2023.                         &filebuf[0], wrap, &ci);
  2024. #ifdef PLAYBACK_VOICE
  2025.                 mutex_unlock(&mutex_codecthread);
  2026. #endif
  2027.                 break ;
  2028.  
  2029. #ifdef AUDIO_HAVE_RECORDING
  2030.             case Q_ENCODER_LOAD_DISK:
  2031.                 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
  2032.                 audio_codec_loaded = false; /* Not audio codec! */
  2033. #ifdef PLAYBACK_VOICE
  2034.                 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
  2035.                 {
  2036.                     LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
  2037.                     queue_post(&voice_queue, Q_ENCODER_RECORD, 0);
  2038.                 }
  2039.                 mutex_lock(&mutex_codecthread);
  2040. #endif
  2041.                 logf("loading encoder");
  2042.                 current_codec = CODEC_IDX_AUDIO;
  2043.                 ci.stop_codec = false;
  2044.                 status = codec_load_file((const char *)ev.data, &ci);
  2045. #ifdef PLAYBACK_VOICE
  2046.                 mutex_unlock(&mutex_codecthread);
  2047. #endif
  2048.                 logf("encoder stopped");
  2049.                 break;
  2050. #endif /* AUDIO_HAVE_RECORDING */
  2051.  
  2052. #ifndef SIMULATOR
  2053.             case SYS_USB_CONNECTED: 
  2054.                 LOGFQUEUE("codec < SYS_USB_CONNECTED");
  2055.                 queue_clear(&codec_queue);
  2056.                 usb_acknowledge(SYS_USB_CONNECTED_ACK);
  2057.                 usb_wait_for_disconnect(&codec_queue);
  2058.                 break;
  2059. #endif
  2060.                
  2061.             default:
  2062.                 LOGFQUEUE("codec < default");
  2063.         }
  2064.  
  2065.         if (audio_codec_loaded)
  2066.         {
  2067.             if (ci.stop_codec)
  2068.             {
  2069.                 status = CODEC_OK;
  2070.                 if (!playing)
  2071.                     pcmbuf_play_stop();
  2072.  
  2073.             }
  2074.             audio_codec_loaded = false;
  2075.         }
  2076.  
  2077.         switch (ev.id) {
  2078.             case Q_CODEC_LOAD_DISK:
  2079.             case Q_CODEC_LOAD:
  2080.                 LOGFQUEUE("codec < Q_CODEC_LOAD");
  2081.                 if (playing)
  2082.                 {
  2083.                     if (ci.new_track || status != CODEC_OK)
  2084.                     {
  2085.                         if (!ci.new_track)
  2086.                         {
  2087.                             logf("Codec failure");
  2088.                             gui_syncsplash(HZ*2, true, "Codec failure");
  2089.                         }
  2090.                        
  2091.                         if (!codec_load_next_track())
  2092.                         {
  2093.                             // queue_post(&codec_queue, Q_AUDIO_STOP, 0);
  2094.                             LOGFQUEUE("codec > audio Q_AUDIO_STOP");
  2095.                             queue_post(&audio_queue, Q_AUDIO_STOP, 0);
  2096.                             break;
  2097.                         }
  2098.                     }
  2099.                     else
  2100.                     {
  2101.                         logf("Codec finished");
  2102.                         if (ci.stop_codec)
  2103.                         {
  2104.                             /* Wait for the audio to stop playing before
  2105.                              * triggering the WPS exit */
  2106.                             while(pcm_is_playing())
  2107.                             {
  2108.                                 CUR_TI->id3.elapsed =
  2109.                                     CUR_TI->id3.length - pcmbuf_get_latency();
  2110.                                 sleep(1);
  2111.                             }
  2112.                             LOGFQUEUE("codec > audio Q_AUDIO_STOP");
  2113.                             queue_post(&audio_queue, Q_AUDIO_STOP, 0);
  2114.                             break;
  2115.                         }
  2116.                     }
  2117.                    
  2118.                     if (CUR_TI->has_codec)
  2119.                     {
  2120.                         LOGFQUEUE("codec > codec Q_CODEC_LOAD");
  2121.                         queue_post(&codec_queue, Q_CODEC_LOAD, 0);
  2122.                     }
  2123.                     else
  2124.                     {
  2125.                         const char *codec_fn =
  2126.                             get_codec_filename(CUR_TI->id3.codectype);
  2127.                         LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
  2128.                         queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
  2129.                             (intptr_t)codec_fn);
  2130.                     }
  2131.                 }
  2132.                 break;
  2133.  
  2134. #ifdef AUDIO_HAVE_RECORDING
  2135.             case Q_ENCODER_LOAD_DISK:
  2136.                 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
  2137.  
  2138.                 if (status == CODEC_OK)
  2139.                     break;
  2140.  
  2141.                 logf("Encoder failure");
  2142.                 gui_syncsplash(HZ*2, true, "Encoder failure");
  2143.  
  2144.                 if (ci.enc_codec_loaded < 0)
  2145.                     break;
  2146.  
  2147.                 logf("Encoder failed to load");
  2148.                 ci.enc_codec_loaded = -1;
  2149.                 break;
  2150. #endif /* AUDIO_HAVE_RECORDING */
  2151.  
  2152.             default:
  2153.                 LOGFQUEUE("codec < default");
  2154.  
  2155.         } /* end switch */
  2156.     }
  2157. }
  2158.  
  2159.  
  2160. /* --- Audio thread --- */
  2161.  
  2162. static bool audio_filebuf_is_lowdata(void)
  2163. {
  2164.     return FILEBUFUSED < AUDIO_FILEBUF_CRITICAL;
  2165. }
  2166.  
  2167. static bool audio_have_tracks(void)
  2168. {
  2169.     return track_ridx != track_widx || CUR_TI->filesize;
  2170. }
  2171.  
  2172. static bool audio_have_free_tracks(void)
  2173. {
  2174.     if (track_widx < track_ridx)
  2175.         return track_widx + 1 < track_ridx;
  2176.     else if (track_ridx == 0)
  2177.         return track_widx < MAX_TRACK - 1;
  2178.    
  2179.     return true;
  2180. }
  2181.        
  2182. int audio_track_count(void)
  2183. {
  2184.     if (audio_have_tracks())
  2185.     {
  2186.         int relative_track_widx = track_widx;
  2187.        
  2188.         if (track_ridx > track_widx)
  2189.             relative_track_widx += MAX_TRACK;
  2190.        
  2191.         return relative_track_widx - track_ridx + 1;
  2192.     }
  2193.    
  2194.     return 0;
  2195. }
  2196.  
  2197. long audio_filebufused(void)
  2198. {
  2199.     return (long) FILEBUFUSED;
  2200. }
  2201.  
  2202. /* Count the data BETWEEN the selected tracks */
  2203. static size_t audio_buffer_count_tracks(int from_track, int to_track)
  2204. {
  2205.     size_t amount = 0;
  2206.     bool need_wrap = to_track < from_track;
  2207.  
  2208.     while (1)
  2209.     {
  2210.         if (++from_track >= MAX_TRACK)
  2211.         {
  2212.             from_track -= MAX_TRACK;
  2213.             need_wrap = false;
  2214.         }
  2215.        
  2216.         if (from_track >= to_track && !need_wrap)
  2217.             break;
  2218.        
  2219.         amount += tracks[from_track].codecsize + tracks[from_track].filesize;
  2220.     }
  2221.     return amount;
  2222. }
  2223.  
  2224. static bool audio_buffer_wind_forward(int new_track_ridx, int old_track_ridx)
  2225. {
  2226.     size_t amount;
  2227.  
  2228.     /* Start with the remainder of the previously playing track */
  2229.     amount = tracks[old_track_ridx].filesize - ci.curpos;
  2230.     /* Then collect all data from tracks in between them */
  2231.     amount += audio_buffer_count_tracks(old_track_ridx, new_track_ridx);
  2232.     logf("bwf:%ldB", (long) amount);
  2233.    
  2234.     if (amount > FILEBUFUSED)
  2235.         return false;
  2236.  
  2237.     /* Wind the buffer to the beginning of the target track or its codec */
  2238.     buf_ridx = RINGBUF_ADD(buf_ridx, amount);
  2239.    
  2240.     return true;
  2241. }
  2242.  
  2243. static bool audio_buffer_wind_backward(int new_track_ridx, int old_track_ridx)
  2244. {
  2245.     /* Available buffer data */
  2246.     size_t buf_back;
  2247.     /* Start with the previously playing track's data and our data */
  2248.     size_t amount;
  2249.    
  2250.     amount = ci.curpos;
  2251.     buf_back = RINGBUF_SUB(buf_ridx, buf_widx);
  2252.    
  2253.     /* If we're not just resetting the current track */
  2254.     if (new_track_ridx != old_track_ridx)
  2255.     {
  2256.         /* Need to wind to before the old track's codec and our filesize */
  2257.         amount += tracks[old_track_ridx].codecsize;
  2258.         amount += tracks[new_track_ridx].filesize;
  2259.  
  2260.         /* Rewind the old track to its beginning */
  2261.         tracks[old_track_ridx].available =
  2262.             tracks[old_track_ridx].filesize - tracks[old_track_ridx].filerem;
  2263.     }
  2264.  
  2265.     /* If the codec was ever buffered */
  2266.     if (tracks[new_track_ridx].codecsize)
  2267.     {
  2268.         /* Add the codec to the needed size */
  2269.         amount += tracks[new_track_ridx].codecsize;
  2270.         tracks[new_track_ridx].has_codec = true;
  2271.     }
  2272.  
  2273.     /* Then collect all data from tracks between new and old */
  2274.     amount += audio_buffer_count_tracks(new_track_ridx, old_track_ridx);
  2275.  
  2276.     /* Do we have space to make this skip? */
  2277.     if (amount > buf_back)
  2278.         return false;
  2279.  
  2280.     logf("bwb:%ldB",amount);
  2281.  
  2282.     /* Rewind the buffer to the beginning of the target track or its codec */
  2283.     buf_ridx = RINGBUF_SUB(buf_ridx, amount);
  2284.  
  2285.     /* Reset to the beginning of the new track */
  2286.     tracks[new_track_ridx].available = tracks[new_track_ridx].filesize;
  2287.  
  2288.     return true;
  2289. }
  2290.  
  2291. static void audio_update_trackinfo(void)
  2292. {
  2293.     ci.filesize = CUR_TI->filesize;
  2294.     CUR_TI->id3.elapsed = 0;
  2295.     CUR_TI->id3.offset = 0;
  2296.     ci.id3 = &CUR_TI->id3;
  2297.     ci.curpos = 0;
  2298.     ci.taginfo_ready = &CUR_TI->taginfo_ready;
  2299. }
  2300.  
  2301. /* Yield to codecs for as long as possible if they are in need of data
  2302.  * return true if the caller should break to let the audio thread process
  2303.  * new events */
  2304. static bool audio_yield_codecs(void)
  2305. {
  2306.     yield();
  2307.    
  2308.     if (!queue_empty(&audio_queue))
  2309.         return true;
  2310.  
  2311.     while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
  2312.             && !ci.stop_codec && playing && !audio_filebuf_is_lowdata())
  2313.     {
  2314.         if (filling)
  2315.             yield();
  2316.         else
  2317.             sleep(2);
  2318.  
  2319.         if (!queue_empty(&audio_queue))
  2320.             return true;
  2321.     }
  2322.    
  2323.     return false;
  2324. }
  2325.  
  2326. static void audio_clear_track_entries(bool clear_unbuffered)
  2327. {
  2328.     int cur_idx = track_widx;
  2329.     int last_idx = -1;
  2330.    
  2331.     logf("Clearing tracks:%d/%d, %d", track_ridx, track_widx, clear_unbuffered);
  2332.    
  2333.     /* Loop over all tracks from write-to-read */
  2334.     while (1)
  2335.     {
  2336.         cur_idx++;
  2337.         cur_idx &= MAX_TRACK_MASK;
  2338.  
  2339.         if (cur_idx == track_ridx)
  2340.             break;
  2341.  
  2342.         /* If the track is buffered, conditionally clear/notify,
  2343.          * otherwise clear the track if that option is selected */
  2344.         if (tracks[cur_idx].event_sent)
  2345.         {
  2346.             if (last_idx >= 0)
  2347.             {
  2348.                 /* If there is an unbuffer callback, call it, otherwise,
  2349.                  * just clear the track */
  2350.                 if (track_unbuffer_callback)
  2351.                     track_unbuffer_callback(&tracks[last_idx].id3, false);
  2352.                
  2353.                 memset(&tracks[last_idx], 0, sizeof(struct track_info));
  2354.             }
  2355.             last_idx = cur_idx;
  2356.         }
  2357.         else if (clear_unbuffered)
  2358.             memset(&tracks[cur_idx], 0, sizeof(struct track_info));
  2359.     }
  2360.  
  2361.     /* We clear the previous instance of a buffered track throughout
  2362.      * the above loop to facilitate 'last' detection.  Clear/notify
  2363.      * the last track here */
  2364.     if (last_idx >= 0)
  2365.     {
  2366.         if (track_unbuffer_callback)
  2367.             track_unbuffer_callback(&tracks[last_idx].id3, true);
  2368.         memset(&tracks[last_idx], 0, sizeof(struct track_info));
  2369.     }
  2370. }
  2371.  
  2372. /* FIXME: This code should be made more generic and move to metadata.c */
  2373. static void audio_strip_tags(void)
  2374. {
  2375.     int i;
  2376.     static const unsigned char tag[] = "TAG";
  2377.     static const unsigned char apetag[] = "APETAGEX";   
  2378.     size_t tag_idx;
  2379.     size_t cur_idx;
  2380.     size_t len, version;
  2381.  
  2382.     tag_idx = RINGBUF_SUB(buf_widx, 128);
  2383.  
  2384.     if (FILEBUFUSED > 128 && tag_idx > buf_ridx)
  2385.     {
  2386.         cur_idx = tag_idx;
  2387.         for(i = 0;i < 3;i++)
  2388.         {
  2389.             if(filebuf[cur_idx] != tag[i])
  2390.                 goto strip_ape_tag;
  2391.  
  2392.             cur_idx = RINGBUF_ADD(cur_idx, 1);
  2393.         }
  2394.  
  2395.         /* Skip id3v1 tag */
  2396.         logf("Skipping ID3v1 tag");
  2397.         buf_widx = tag_idx;
  2398.         tracks[track_widx].available -= 128;
  2399.         tracks[track_widx].filesize -= 128;
  2400.     }
  2401.  
  2402. strip_ape_tag:
  2403.     /* Check for APE tag (look for the APE tag footer) */
  2404.     tag_idx = RINGBUF_SUB(buf_widx, 32);
  2405.  
  2406.     if (FILEBUFUSED > 32 && tag_idx > buf_ridx)
  2407.     {
  2408.         cur_idx = tag_idx;
  2409.         for(i = 0;i < 8;i++)
  2410.         {
  2411.             if(filebuf[cur_idx] != apetag[i])
  2412.                 return;
  2413.  
  2414.             cur_idx = RINGBUF_ADD(cur_idx, 1);
  2415.         }
  2416.  
  2417.         /* Read the version and length from the footer */
  2418.         version = filebuf[tag_idx+8] | (filebuf[tag_idx+9] << 8) |
  2419.                   (filebuf[tag_idx+10] << 16) | (filebuf[tag_idx+11] << 24);
  2420.         len = filebuf[tag_idx+12] | (filebuf[tag_idx+13] << 8) |
  2421.               (filebuf[tag_idx+14] << 16) | (filebuf[tag_idx+15] << 24);
  2422.         if (version == 2000)
  2423.             len += 32; /* APEv2 has a 32 byte header */
  2424.  
  2425.         /* Skip APE tag */
  2426.         if (FILEBUFUSED > len)
  2427.         {
  2428.             logf("Skipping APE tag (%dB)", len);
  2429.             buf_widx = RINGBUF_SUB(buf_widx, len);
  2430.             tracks[track_widx].available -= len;
  2431.             tracks[track_widx].filesize -= len;
  2432.         }
  2433.     }
  2434. }
  2435.  
  2436. /* Returns true if a whole file is read, false otherwise */
  2437. static bool audio_read_file(size_t minimum)
  2438. {
  2439.     bool ret_val = false;
  2440.  
  2441.     /* If we're called and no file is open, this is an error */
  2442.     if (current_fd < 0)
  2443.     {
  2444.         logf("Bad fd in arf");
  2445.         /* Give some hope of miraculous recovery by forcing a track reload */
  2446.         tracks[track_widx].filesize = 0;
  2447.         /* Stop this buffering run */
  2448.         return ret_val;
  2449.     }
  2450.  
  2451.     trigger_cpu_boost();
  2452.     while (tracks[track_widx].filerem > 0)
  2453.     {
  2454.         size_t copy_n;
  2455.         int overlap;
  2456.         int rc;
  2457.  
  2458.         /* copy_n is the largest chunk that is safe to read */
  2459.         copy_n = MIN(conf_filechunk, filebuflen - buf_widx);
  2460.  
  2461.         /* buf_widx == buf_ridx is defined as buffer empty, not buffer full */
  2462.         if (RINGBUF_ADD_CROSS(buf_widx,copy_n,buf_ridx) >= 0)
  2463.             break;
  2464.  
  2465.         /* rc is the actual amount read */
  2466.         rc = read(current_fd, &filebuf[buf_widx], copy_n);
  2467.  
  2468.         if (rc < 0)
  2469.         {
  2470.             logf("File ended %dB early", tracks[track_widx].filerem);
  2471.             tracks[track_widx].filesize -= tracks[track_widx].filerem;
  2472.             tracks[track_widx].filerem = 0;
  2473.             break;
  2474.         }
  2475.  
  2476.         /* How much of the playing track did we overwrite */
  2477.         if (buf_widx == CUR_TI->buf_idx)
  2478.         {
  2479.             /* Special handling; zero or full overlap? */
  2480.             if (track_widx == track_ridx && CUR_TI->available == 0)
  2481.                 overlap = 0;
  2482.             else
  2483.                 overlap = rc;
  2484.         }
  2485.         else
  2486.             overlap = RINGBUF_ADD_CROSS(buf_widx,rc,CUR_TI->buf_idx);
  2487.  
  2488.         if ((unsigned)rc > tracks[track_widx].filerem)
  2489.         {
  2490.             logf("Bad: rc-filerem=%d, fixing", rc-tracks[track_widx].filerem);
  2491.             tracks[track_widx].filesize += rc - tracks[track_widx].filerem;
  2492.             tracks[track_widx].filerem = rc;
  2493.         }
  2494.  
  2495.         /* Advance buffer */
  2496.         buf_widx = RINGBUF_ADD(buf_widx, rc);
  2497.         tracks[track_widx].available += rc;
  2498.         tracks[track_widx].filerem -= rc;
  2499.  
  2500.         /* If we write into the playing track, adjust it's buffer info */
  2501.         if (overlap > 0)
  2502.         {
  2503.             CUR_TI->buf_idx += overlap;
  2504.             CUR_TI->start_pos += overlap;
  2505.         }
  2506.  
  2507.         /* For a rebuffer, fill at least this minimum */
  2508.         if (minimum > (unsigned)rc)
  2509.             minimum -= rc;
  2510.         /* Let the codec process up to the watermark */
  2511.         /* Break immediately if this is a quick buffer, or there is an event */
  2512.         else if (minimum || audio_yield_codecs())
  2513.         {
  2514.             /* Exit quickly, but don't stop the overall buffering process */
  2515.             ret_val = true;
  2516.             break;
  2517.         }
  2518.     }
  2519.  
  2520.     if (tracks[track_widx].filerem == 0)
  2521.     {
  2522.         logf("Finished buf:%dB", tracks[track_widx].filesize);
  2523.         close(current_fd);
  2524.         current_fd = -1;
  2525.         audio_strip_tags();
  2526.  
  2527.         track_widx++;
  2528.         track_widx &= MAX_TRACK_MASK;
  2529.  
  2530.         tracks[track_widx].filesize = 0;
  2531.         return true;
  2532.     }
  2533.     else
  2534.     {
  2535.         logf("%s buf:%dB", ret_val?"Quick":"Partially",
  2536.                 tracks[track_widx].filesize - tracks[track_widx].filerem);
  2537.         return ret_val;
  2538.     }
  2539. }
  2540.  
  2541. static bool audio_loadcodec(bool start_play)
  2542. {
  2543.     size_t size = 0;
  2544.     int fd;
  2545.     int rc;
  2546.     size_t copy_n;
  2547.     int prev_track;
  2548.     char codec_path[MAX_PATH]; /* Full path to codec */
  2549.  
  2550.     const char * codec_fn =
  2551.         get_codec_filename(tracks[track_widx].id3.codectype);
  2552.     if (codec_fn == NULL)
  2553.         return false;
  2554.  
  2555.     tracks[track_widx].has_codec = false;
  2556.  
  2557.     if (start_play)
  2558.     {
  2559.         /* Load the codec directly from disk and save some memory. */
  2560.         track_ridx = track_widx;
  2561.         ci.filesize = CUR_TI->filesize;
  2562.         ci.id3 = &CUR_TI->id3;
  2563.         ci.taginfo_ready = &CUR_TI->taginfo_ready;
  2564.         ci.curpos = 0;
  2565.         LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
  2566.         queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn);
  2567.         return true;
  2568.     }
  2569.     else
  2570.     {
  2571.         /* If we already have another track than this one buffered */
  2572.         if (track_widx != track_ridx)
  2573.         {
  2574.             prev_track = (track_widx - 1) & MAX_TRACK_MASK;
  2575.            
  2576.             /* If the previous codec is the same as this one, there is no need
  2577.              * to put another copy of it on the file buffer */
  2578.             if (get_codec_base_type(tracks[track_widx].id3.codectype) ==
  2579.                     get_codec_base_type(tracks[prev_track].id3.codectype)
  2580.                 && audio_codec_loaded)
  2581.             {
  2582.                 logf("Reusing prev. codec");
  2583.                 return true;
  2584.             }
  2585.         }
  2586.     }
  2587.  
  2588.     codec_get_full_path(codec_path, codec_fn);
  2589.  
  2590.     fd = open(codec_path, O_RDONLY);
  2591.     if (fd < 0)
  2592.     {
  2593.         logf("Codec doesn't exist!");
  2594.         return false;
  2595.     }
  2596.  
  2597.     tracks[track_widx].codecsize = filesize(fd);
  2598.    
  2599.     /* Never load a partial codec */
  2600.     if (RINGBUF_ADD_CROSS(buf_widx,tracks[track_widx].codecsize,buf_ridx) >= 0)
  2601.     {
  2602.         logf("Not enough space");
  2603.         close(fd);
  2604.         return false;
  2605.     }
  2606.  
  2607.     while (size < tracks[track_widx].codecsize)
  2608.     {
  2609.         copy_n = MIN(conf_filechunk, filebuflen - buf_widx);
  2610.         rc = read(fd, &filebuf[buf_widx], copy_n);
  2611.         if (rc < 0)
  2612.         {
  2613.             close(fd);
  2614.             /* This is an error condition, likely the codec file is corrupt */
  2615.             logf("Partial codec loaded");
  2616.             /* Must undo the buffer write of the partial codec */
  2617.             buf_widx = RINGBUF_SUB(buf_widx, size);
  2618.             tracks[track_widx].codecsize = 0;
  2619.             return false;
  2620.         }
  2621.        
  2622.         buf_widx = RINGBUF_ADD(buf_widx, rc);
  2623.  
  2624.         size += rc;       
  2625.     }
  2626.  
  2627.     tracks[track_widx].has_codec = true;
  2628.  
  2629.     close(fd);
  2630.     logf("Done: %dB", size);
  2631.  
  2632.     return true;
  2633. }
  2634.  
  2635. /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
  2636. static void audio_set_elapsed(struct mp3entry* id3)
  2637. {
  2638.     unsigned long offset = id3->offset > id3->first_frame_offset ?
  2639.         id3->offset - id3->first_frame_offset : 0;
  2640.  
  2641.     if ( id3->vbr ) {
  2642.         if ( id3->has_toc ) {
  2643.             /* calculate elapsed time using TOC */
  2644.             int i;
  2645.             unsigned int remainder, plen, relpos, nextpos;
  2646.  
  2647.             /* find wich percent we're at */
  2648.             for (i=0; i<100; i++ )
  2649.                 if ( offset < id3->toc[i] * (id3->filesize / 256) )
  2650.                     break;
  2651.  
  2652.             i--;
  2653.             if (i < 0)
  2654.                 i = 0;
  2655.  
  2656.             relpos = id3->toc[i];
  2657.  
  2658.             if (i < 99)
  2659.                 nextpos = id3->toc[i+1];
  2660.             else
  2661.                 nextpos = 256;
  2662.  
  2663.             remainder = offset - (relpos * (id3->filesize / 256));
  2664.  
  2665.             /* set time for this percent (divide before multiply to prevent
  2666.                overflow on long files. loss of precision is negligible on
  2667.                short files) */
  2668.             id3->elapsed = i * (id3->length / 100);
  2669.  
  2670.             /* calculate remainder time */
  2671.             plen = (nextpos - relpos) * (id3->filesize / 256);
  2672.             id3->elapsed += (((remainder * 100) / plen) *
  2673.                              (id3->length / 10000));
  2674.         }
  2675.         else {
  2676.             /* no TOC exists. set a rough estimate using average bitrate */
  2677.             int tpk = id3->length /
  2678.                 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
  2679.                 1024);
  2680.             id3->elapsed = offset / 1024 * tpk;
  2681.         }
  2682.     }
  2683.     else
  2684.     {
  2685.         /* constant bitrate, use exact calculation */
  2686.         if (id3->bitrate != 0)
  2687.             id3->elapsed = offset / (id3->bitrate / 8);
  2688.     }
  2689. }
  2690.  
  2691. static bool audio_load_track(int offset, bool start_play, bool rebuffer)
  2692. {
  2693.     char *trackname;
  2694.     off_t size;
  2695.     char msgbuf[80];
  2696.  
  2697.     /* Stop buffer filling if there is no free track entries.
  2698.        Don't fill up the last track entry (we wan't to store next track
  2699.        metadata there). */
  2700.     if (!audio_have_free_tracks())
  2701.     {
  2702.         logf("No free tracks");
  2703.         return false;
  2704.     }
  2705.  
  2706.     if (current_fd >= 0)
  2707.     {
  2708.         logf("Nonzero fd in alt");
  2709.         close(current_fd);
  2710.         current_fd = -1;
  2711.     }
  2712.  
  2713.     last_peek_offset++;
  2714.     peek_again:
  2715.     logf("Buffering track:%d/%d", track_widx, track_ridx);
  2716.     /* Get track name from current playlist read position. */
  2717.     while ((trackname = playlist_peek(last_peek_offset)) != NULL)
  2718.     {
  2719.         /* Handle broken playlists. */
  2720.         current_fd = open(trackname, O_RDONLY);
  2721.         if (current_fd < 0)
  2722.         {
  2723.             logf("Open failed");
  2724.             /* Skip invalid entry from playlist. */
  2725.             playlist_skip_entry(NULL, last_peek_offset);
  2726.         }
  2727.         else
  2728.             break;
  2729.     }
  2730.  
  2731.     if (!trackname)
  2732.     {
  2733.         logf("End-of-playlist");
  2734.         playlist_end = true;
  2735.         return false;
  2736.     }
  2737.  
  2738.     /* Initialize track entry. */
  2739.     size = filesize(current_fd);
  2740.     tracks[track_widx].filerem = size;
  2741.     tracks[track_widx].filesize = size;
  2742.     tracks[track_widx].available = 0;
  2743.  
  2744.     /* Set default values */
  2745.     if (start_play)
  2746.     {
  2747.         int last_codec = current_codec;
  2748.        
  2749.         current_codec = CODEC_IDX_AUDIO;
  2750.         conf_watermark = AUDIO_DEFAULT_WATERMARK;
  2751.         conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
  2752.         conf_preseek = AUDIO_REBUFFER_GUESS_SIZE;
  2753.         dsp_configure(DSP_RESET, 0);
  2754.         current_codec = last_codec;
  2755.     }
  2756.  
  2757.     /* Get track metadata if we don't already have it. */
  2758.     if (!tracks[track_widx].taginfo_ready)
  2759.     {
  2760.         if (get_metadata(&tracks[track_widx],current_fd,trackname,v1first))
  2761.         {
  2762.             if (start_play)
  2763.             {
  2764.                 track_changed = true;
  2765.                 playlist_update_resume_info(audio_current_track());
  2766.             }
  2767.         }
  2768.         else
  2769.         {
  2770.             logf("mde:%s!",trackname);
  2771.            
  2772.             /* Set filesize to zero to indicate no file was loaded. */
  2773.             tracks[track_widx].filesize = 0;
  2774.             tracks[track_widx].filerem = 0;
  2775.             close(current_fd);
  2776.             current_fd = -1;
  2777.            
  2778.             /* Skip invalid entry from playlist. */
  2779.             playlist_skip_entry(NULL, last_peek_offset);
  2780.             tracks[track_widx].taginfo_ready = false;
  2781.             goto peek_again;
  2782.         }
  2783.  
  2784.     }
  2785.  
  2786.     /* Load the codec. */
  2787.     tracks[track_widx].codecbuf = &filebuf[buf_widx];
  2788.     if (!audio_loadcodec(start_play))
  2789.     {
  2790.         /* Set filesize to zero to indicate no file was loaded. */
  2791.         tracks[track_widx].filesize = 0;
  2792.         tracks[track_widx].filerem = 0;
  2793.         close(current_fd);
  2794.         current_fd = -1;
  2795.  
  2796.         if (tracks[track_widx].codecsize)
  2797.         {
  2798.             /* No space for codec on buffer, not an error */
  2799.             tracks[track_widx].codecsize = 0;
  2800.             return false;
  2801.         }
  2802.  
  2803.         /* This is an error condition, either no codec was found, or reading
  2804.          * the codec file failed part way through, either way, skip the track */
  2805.         snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname);
  2806.         /* We should not use gui_syncplash from audio thread! */
  2807.         gui_syncsplash(HZ*2, true, msgbuf);
  2808.         /* Skip invalid entry from playlist. */
  2809.         playlist_skip_entry(NULL, last_peek_offset);
  2810.         tracks[track_widx].taginfo_ready = false;
  2811.         goto peek_again;
  2812.     }
  2813.  
  2814.     tracks[track_widx].start_pos = 0;
  2815.     set_filebuf_watermark(buffer_margin);
  2816.     tracks[track_widx].id3.elapsed = 0;
  2817.  
  2818.     if (offset > 0)
  2819.     {
  2820.         switch (tracks[track_widx].id3.codectype) {
  2821.         case AFMT_MPA_L1:
  2822.         case AFMT_MPA_L2:
  2823.         case AFMT_MPA_L3:
  2824.             lseek(current_fd, offset, SEEK_SET);
  2825.             tracks[track_widx].id3.offset = offset;
  2826.             audio_set_elapsed(&tracks[track_widx].id3);
  2827.             tracks[track_widx].filerem = size - offset;
  2828.             ci.curpos = offset;
  2829.             tracks[track_widx].start_pos = offset;
  2830.             break;
  2831.  
  2832.         case AFMT_WAVPACK:
  2833.             lseek(current_fd, offset, SEEK_SET);
  2834.             tracks[track_widx].id3.offset = offset;
  2835.             tracks[track_widx].id3.elapsed =
  2836.                 tracks[track_widx].id3.length / 2;
  2837.             tracks[track_widx].filerem = size - offset;
  2838.             ci.curpos = offset;
  2839.             tracks[track_widx].start_pos = offset;
  2840.             break;
  2841.  
  2842.         case AFMT_OGG_VORBIS:
  2843.         case AFMT_FLAC:
  2844.         case AFMT_PCM_WAV:
  2845.         case AFMT_A52:
  2846.         case AFMT_AAC:
  2847.             tracks[track_widx].id3.offset = offset;
  2848.             break;
  2849.         }
  2850.     }
  2851.    
  2852.     logf("alt:%s", trackname);
  2853.     tracks[track_widx].buf_idx = buf_widx;
  2854.  
  2855.     return audio_read_file(rebuffer);
  2856. }
  2857.  
  2858. static bool audio_read_next_metadata(void)
  2859. {
  2860.     int fd;
  2861.     char *trackname;
  2862.     int next_idx;
  2863.     int status;
  2864.  
  2865.     next_idx = track_widx;
  2866.     if (tracks[next_idx].taginfo_ready)
  2867.     {
  2868.         next_idx++;
  2869.         next_idx &= MAX_TRACK_MASK;
  2870.  
  2871.         if (tracks[next_idx].taginfo_ready)
  2872.             return true;
  2873.     }
  2874.  
  2875.     trackname = playlist_peek(last_peek_offset + 1);
  2876.     if (!trackname)
  2877.         return false;
  2878.  
  2879.     fd = open(trackname, O_RDONLY);
  2880.     if (fd < 0)
  2881.         return false;
  2882.  
  2883.     status = get_metadata(&tracks[next_idx],fd,trackname,v1first);
  2884.     /* Preload the glyphs in the tags */
  2885.     if (status)
  2886.     {
  2887.         if (tracks[next_idx].id3.title)
  2888.             lcd_getstringsize(tracks[next_idx].id3.title, NULL, NULL);
  2889.         if (tracks[next_idx].id3.artist)
  2890.             lcd_getstringsize(tracks[next_idx].id3.artist, NULL, NULL);
  2891.         if (tracks[next_idx].id3.album)
  2892.             lcd_getstringsize(tracks[next_idx].id3.album, NULL, NULL);
  2893.     }
  2894.     close(fd);
  2895.  
  2896.     return status;
  2897. }
  2898.  
  2899. /* Send callback events to notify about new tracks. */
  2900. static void audio_generate_postbuffer_events(void)
  2901. {
  2902.     int cur_idx;
  2903.     int last_idx = -1;
  2904.  
  2905.     logf("Postbuffer:%d/%d",track_ridx,track_widx);
  2906.  
  2907.     if (audio_have_tracks())
  2908.     {
  2909.         cur_idx = track_ridx;
  2910.        
  2911.         while (1) {
  2912.             if (!tracks[cur_idx].event_sent)
  2913.             {
  2914.                 if (last_idx >= 0 && !tracks[last_idx].event_sent)
  2915.                 {
  2916.                     /* Mark the event 'sent' even if we don't really send one */
  2917.                     tracks[last_idx].event_sent = true;
  2918.                     if (track_buffer_callback)
  2919.                         track_buffer_callback(&tracks[last_idx].id3, false);
  2920.                 }
  2921.                 last_idx = cur_idx;
  2922.             }
  2923.             if (cur_idx == track_widx)
  2924.                 break;
  2925.             cur_idx++;
  2926.             cur_idx &= MAX_TRACK_MASK;
  2927.         }
  2928.  
  2929.         if (last_idx >= 0 && !tracks[last_idx].event_sent)
  2930.         {
  2931.             tracks[last_idx].event_sent = true;
  2932.             if (track_buffer_callback)
  2933.                 track_buffer_callback(&tracks[last_idx].id3, true);
  2934.         }
  2935.        
  2936.         /* Force WPS reload. */
  2937.         track_changed = true;
  2938.     }
  2939. }
  2940.  
  2941. static bool audio_initialize_buffer_fill(bool clear_tracks)
  2942. {
  2943.     /* Don't initialize if we're already initialized */
  2944.     if (filling)
  2945.         return true;
  2946.  
  2947.     logf("Starting buffer fill");
  2948.  
  2949.     /* Set the filling flag true before calling audio_clear_tracks as that
  2950.      * function can yield and we start looping. */
  2951.     filling = true;
  2952.    
  2953.     if (clear_tracks)
  2954.         audio_clear_track_entries(false);
  2955.  
  2956.     /* Save the current resume position once. */
  2957.     playlist_update_resume_info(audio_current_track());
  2958.    
  2959.     return true;
  2960. }
  2961.  
  2962. static void audio_fill_file_buffer(
  2963.         bool start_play, bool rebuffer, size_t offset)
  2964. {
  2965.     bool had_next_track = audio_next_track() != NULL;
  2966.     bool continue_buffering;
  2967.  
  2968.     /* must reset the buffer before use if trashed */
  2969.     if (buffer_state != BUFFER_STATE_NORMAL)
  2970.         audio_reset_buffer(pcmbuf_get_bufsize());
  2971.  
  2972.     if (!audio_initialize_buffer_fill(!start_play))
  2973.         return ;
  2974.  
  2975.     /* If we have a partially buffered track, continue loading,
  2976.      * otherwise load a new track */
  2977.     if (tracks[track_widx].filesize > 0)
  2978.         continue_buffering = audio_read_file(rebuffer);
  2979.     else
  2980.         continue_buffering = audio_load_track(offset, start_play, rebuffer);
  2981.  
  2982.     if (!had_next_track && audio_next_track())
  2983.         track_changed = true;
  2984.  
  2985.     /* If we're done buffering */
  2986.     if (!continue_buffering)
  2987.     {
  2988.         audio_read_next_metadata();
  2989.  
  2990.         audio_generate_postbuffer_events();
  2991.         filling = false;
  2992.     }
  2993. #ifndef SIMULATOR
  2994.     ata_sleep();
  2995. #endif
  2996.  
  2997. }
  2998.  
  2999. static void audio_rebuffer(void)
  3000. {
  3001.     logf("Forcing rebuffer");
  3002.  
  3003. #if 0
  3004.     /* Notify the codec that this will take a while */
  3005.     /* Currently this can cause some problems (logf in reverse order):
  3006.      * Codec load error:-1
  3007.      * Codec load disk
  3008.      * Codec: Unsupported
  3009.      * Codec finished
  3010.      * New codec:0/3
  3011.      * Clearing tracks:7/7, 1
  3012.      * Forcing rebuffer
  3013.      * Check new track buffer
  3014.      * Request new track
  3015.      * Clearing tracks:5/5, 0
  3016.      * Starting buffer fill
  3017.      * Clearing tracks:5/5, 1
  3018.      * Re-buffering song w/seek
  3019.      */
  3020.     if (!filling)
  3021.         queue_post(&codec_callback_queue, Q_CODEC_REQUEST_PENDING, 0);
  3022. #endif
  3023.    
  3024.     /* Stop in progress fill, and clear open file descriptor */
  3025.     if (current_fd >= 0)
  3026.     {
  3027.         close(current_fd);
  3028.         current_fd = -1;
  3029.     }
  3030.     filling = false;
  3031.  
  3032.     /* Reset buffer and track pointers */
  3033.     CUR_TI->buf_idx = buf_ridx = buf_widx = 0;
  3034.     track_widx = track_ridx;
  3035.     audio_clear_track_entries(true);
  3036.     CUR_TI->available = 0;
  3037.  
  3038.     /* Fill the buffer */
  3039.     last_peek_offset = -1;
  3040.     CUR_TI->filesize = 0;
  3041.     CUR_TI->start_pos = 0;
  3042.     ci.curpos = 0;
  3043.  
  3044.     if (!CUR_TI->taginfo_ready)
  3045.         memset(&CUR_TI->id3, 0, sizeof(struct mp3entry));
  3046.  
  3047.     audio_fill_file_buffer(false, true, 0);
  3048. }
  3049.  
  3050. static int audio_check_new_track(void)
  3051. {
  3052.     int track_count = audio_track_count();
  3053.     int old_track_ridx = track_ridx;
  3054.     bool forward;
  3055.  
  3056.     if (dir_skip)
  3057.     {
  3058.         dir_skip = false;
  3059.         if (playlist_next_dir(ci.new_track))
  3060.         {
  3061.             ci.new_track = 0;
  3062.             CUR_TI->taginfo_ready = false;
  3063.             audio_rebuffer();
  3064.             goto skip_done;
  3065.         }
  3066.         else
  3067.         {
  3068.             LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
  3069.             return Q_CODEC_REQUEST_FAILED;
  3070.         }
  3071.     }
  3072.  
  3073.     if (new_playlist)
  3074.         ci.new_track = 0;
  3075.  
  3076.     /* If the playlist isn't that big */
  3077.     if (!playlist_check(ci.new_track))
  3078.     {
  3079.         if (ci.new_track >= 0)
  3080.         {
  3081.             LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
  3082.             return Q_CODEC_REQUEST_FAILED;
  3083.         }
  3084.         /* Find the beginning backward if the user over-skips it */
  3085.         while (!playlist_check(++ci.new_track))
  3086.             if (ci.new_track >= 0)
  3087.             {
  3088.                 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
  3089.                 return Q_CODEC_REQUEST_FAILED;
  3090.             }
  3091.     }
  3092.     /* Update the playlist */
  3093.     last_peek_offset -= ci.new_track;
  3094.  
  3095.     if (playlist_next(ci.new_track) < 0)
  3096.     {
  3097.         LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
  3098.         return Q_CODEC_REQUEST_FAILED;
  3099.     }
  3100.  
  3101.     if (new_playlist)
  3102.     {
  3103.         ci.new_track = 1;
  3104.         new_playlist = false;
  3105.     }
  3106.  
  3107.     /* Save the old track */
  3108.     prev_ti = CUR_TI;
  3109.  
  3110.     /* Move to the new track */
  3111.     track_ridx += ci.new_track;
  3112.     track_ridx &= MAX_TRACK_MASK;
  3113.  
  3114.     if (automatic_skip)
  3115.         playlist_end = false;
  3116.  
  3117.     track_changed = !automatic_skip;
  3118.  
  3119.     /* If it is not safe to even skip this many track entries */
  3120.     if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
  3121.     {
  3122.         ci.new_track = 0;
  3123.         CUR_TI->taginfo_ready = false;
  3124.         audio_rebuffer();
  3125.         goto skip_done;
  3126.     }
  3127.  
  3128.     forward = ci.new_track > 0;
  3129.     ci.new_track = 0;
  3130.  
  3131.     /* If the target track is clearly not in memory */
  3132.     if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready)
  3133.     {
  3134.         audio_rebuffer();
  3135.         goto skip_done;
  3136.     }
  3137.  
  3138.     /* The track may be in memory, see if it really is */
  3139.     if (forward)
  3140.     {
  3141.         if (!audio_buffer_wind_forward(track_ridx, old_track_ridx))
  3142.             audio_rebuffer();
  3143.     }
  3144.     else
  3145.     {
  3146.         int cur_idx = track_ridx;
  3147.         bool taginfo_ready = true;
  3148.         bool wrap = track_ridx > old_track_ridx;
  3149.        
  3150.         while (1)
  3151.         {
  3152.             cur_idx++;
  3153.             cur_idx &= MAX_TRACK_MASK;
  3154.             if (!(wrap || cur_idx < old_track_ridx))
  3155.                 break;
  3156.  
  3157.             /* If we hit a track in between without valid tag info, bail */
  3158.             if (!tracks[cur_idx].taginfo_ready)
  3159.             {
  3160.                 taginfo_ready = false;
  3161.                 break;
  3162.             }
  3163.  
  3164.             tracks[cur_idx].available = tracks[cur_idx].filesize;
  3165.             if (tracks[cur_idx].codecsize)
  3166.                 tracks[cur_idx].has_codec = true;
  3167.         }
  3168.         if (taginfo_ready)
  3169.         {
  3170.             if (!audio_buffer_wind_backward(track_ridx, old_track_ridx))
  3171.                 audio_rebuffer();
  3172.         }
  3173.         else
  3174.         {
  3175.             CUR_TI->taginfo_ready = false;
  3176.             audio_rebuffer();
  3177.         }
  3178.     }
  3179.  
  3180. skip_done:
  3181.     audio_update_trackinfo();
  3182.     LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
  3183.     return Q_CODEC_REQUEST_COMPLETE;
  3184. }
  3185.  
  3186. static int audio_rebuffer_and_seek(size_t newpos)
  3187. {
  3188.     size_t real_preseek;
  3189.     int fd;
  3190.     char *trackname;
  3191.  
  3192.     /* (Re-)open current track's file handle. */
  3193.     trackname = playlist_peek(0);
  3194.     fd = open(trackname, O_RDONLY);
  3195.     if (fd < 0)
  3196.     {
  3197.         LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
  3198.         return Q_CODEC_REQUEST_FAILED;
  3199.     }
  3200.    
  3201.     if (current_fd >= 0)
  3202.         close(current_fd);
  3203.     current_fd = fd;
  3204.  
  3205.     playlist_end = false;
  3206.  
  3207.     ci.curpos = newpos;
  3208.  
  3209.     /* Clear codec buffer. */
  3210.     track_widx = track_ridx;
  3211.     tracks[track_widx].buf_idx = buf_widx = buf_ridx = 0;
  3212.  
  3213.     last_peek_offset = 0;
  3214.     filling = false;
  3215.     audio_initialize_buffer_fill(true);
  3216.  
  3217.     /* This may have been tweaked by the id3v1 code */
  3218.     CUR_TI->filesize=filesize(fd);
  3219.     if (newpos > conf_preseek)
  3220.     {
  3221.         CUR_TI->start_pos = newpos - conf_preseek;
  3222.         lseek(current_fd, CUR_TI->start_pos, SEEK_SET);
  3223.         CUR_TI->filerem = CUR_TI->filesize - CUR_TI->start_pos;
  3224.         real_preseek = conf_preseek;
  3225.     }
  3226.     else
  3227.     {
  3228.         CUR_TI->start_pos = 0;
  3229.         CUR_TI->filerem = CUR_TI->filesize;
  3230.         real_preseek = newpos;
  3231.     }
  3232.  
  3233.     CUR_TI->available = 0;
  3234.  
  3235.     audio_read_file(real_preseek);
  3236.  
  3237.     /* Account for the data we just read that is 'behind' us now */
  3238.     CUR_TI->available -= real_preseek;
  3239.  
  3240.     buf_ridx = RINGBUF_ADD(buf_ridx, real_preseek);
  3241.  
  3242.     LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
  3243.     return Q_CODEC_REQUEST_COMPLETE;
  3244. }
  3245.  
  3246. void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3,
  3247.                                                   bool last_track))
  3248. {
  3249.     track_buffer_callback = handler;
  3250. }
  3251.  
  3252. void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3,
  3253.                                                     bool last_track))
  3254. {
  3255.     track_unbuffer_callback = handler;
  3256. }
  3257.  
  3258. void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3))
  3259. {
  3260.     track_changed_callback = handler;
  3261. }
  3262.  
  3263. unsigned long audio_prev_elapsed(void)
  3264. {
  3265.     return prev_track_elapsed;
  3266. }
  3267.  
  3268. static void audio_stop_codec_flush(void)
  3269. {
  3270.     ci.stop_codec = true;
  3271.     pcmbuf_pause(true);
  3272.     while (audio_codec_loaded)
  3273.         yield();
  3274.     /* If the audio codec is not loaded any more, and the audio is still
  3275.      * playing, it is now and _only_ now safe to call this function from the
  3276.      * audio thread */
  3277.     if (pcm_is_playing())
  3278.         pcmbuf_play_stop();
  3279.     pcmbuf_pause(paused);
  3280. }
  3281.  
  3282. static void audio_stop_playback(void)
  3283. {
  3284.     /* If we were playing, save resume information */
  3285.     if (playing)
  3286.     {
  3287.         /* Save the current playing spot, or NULL if the playlist has ended */
  3288.         playlist_update_resume_info(
  3289.             (playlist_end && ci.stop_codec)?NULL:audio_current_track());
  3290.     }
  3291.  
  3292.     filling = false;
  3293.     paused = false;
  3294.     audio_stop_codec_flush();
  3295.     playing = false;
  3296.    
  3297.     if (current_fd >= 0)
  3298.     {
  3299.         close(current_fd);
  3300.         current_fd = -1;
  3301.     }
  3302.  
  3303.     /* Mark all entries null. */
  3304.     audio_clear_track_entries(false);
  3305. }
  3306.  
  3307. static void audio_play_start(size_t offset)
  3308. {
  3309. #if defined(HAVE_RECORDING) || defined(CONFIG_TUNER)
  3310.     rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
  3311. #endif
  3312.  
  3313.     /* Wait for any previously playing audio to flush - TODO: Not necessary? */
  3314.     audio_stop_codec_flush();
  3315.  
  3316.     track_changed = true;
  3317.     playlist_end = false;
  3318.  
  3319.     playing = true;
  3320.     ci.new_track = 0;
  3321.     ci.seek_time = 0;
  3322.     wps_offset = 0;
  3323.    
  3324.     if (current_fd >= 0)
  3325.     {
  3326.         close(current_fd);
  3327.         current_fd = -1;
  3328.     }
  3329.  
  3330.     sound_set_volume(global_settings.volume);
  3331.     track_widx = track_ridx = 0;
  3332.     buf_ridx = buf_widx = 0;
  3333.  
  3334.     /* Mark all entries null. */
  3335.     memset(tracks, 0, sizeof(struct track_info) * MAX_TRACK);
  3336.    
  3337.     last_peek_offset = -1;
  3338.  
  3339.     audio_fill_file_buffer(true, false, offset);
  3340. }
  3341.  
  3342.  
  3343. /* Invalidates all but currently playing track. */
  3344. static void audio_invalidate_tracks(void)
  3345. {
  3346.     if (audio_have_tracks()) {
  3347.         last_peek_offset = 0;
  3348.  
  3349.         playlist_end = false;
  3350.         track_widx = track_ridx;
  3351.         /* Mark all other entries null (also buffered wrong metadata). */
  3352.         audio_clear_track_entries(true);
  3353.  
  3354.         /* If the current track is fully buffered, advance the write pointer */
  3355.         if (tracks[track_widx].filerem == 0)
  3356.             track_widx = (track_widx + 1) & MAX_TRACK_MASK;
  3357.  
  3358.         buf_widx = RINGBUF_ADD(buf_ridx, CUR_TI->available);
  3359.  
  3360.         audio_read_next_metadata();
  3361.     }
  3362. }
  3363.  
  3364. static void audio_new_playlist(void)
  3365. {
  3366.     /* Prepare to start a new fill from the beginning of the playlist */
  3367.     last_peek_offset = -1;
  3368.     if (audio_have_tracks()) {
  3369.         playlist_end = false;
  3370.         track_widx = track_ridx;
  3371.         audio_clear_track_entries(true);
  3372.  
  3373.         track_widx++;
  3374.         track_widx &= MAX_TRACK_MASK;
  3375.  
  3376.         /* Stop reading the current track */
  3377.         CUR_TI->filerem = 0;
  3378.         close(current_fd);
  3379.         current_fd = -1;
  3380.  
  3381.         /* Mark the current track as invalid to prevent skipping back to it */
  3382.         CUR_TI->taginfo_ready = false;
  3383.  
  3384.         /* Invalidate the buffer other than the playing track */
  3385.         buf_widx = RINGBUF_ADD(buf_ridx, CUR_TI->available);
  3386.     }
  3387.    
  3388.     /* Signal the codec to initiate a track change forward */
  3389.     new_playlist = true;
  3390.     ci.new_track = 1;
  3391.     audio_fill_file_buffer(false, true, 0);
  3392. }
  3393.  
  3394. static void audio_initiate_track_change(long direction)
  3395. {
  3396.     playlist_end = false;
  3397.     ci.new_track += direction;
  3398.     wps_offset -= direction;
  3399. }
  3400.  
  3401. static void audio_initiate_dir_change(long direction)
  3402. {
  3403.     playlist_end = false;
  3404.     dir_skip = true;
  3405.     ci.new_track = direction;
  3406. }
  3407.  
  3408. /*
  3409.  * Layout audio buffer as follows:
  3410.  * [|TALK]|MALLOC|FILE|GUARD|PCM|AUDIOCODEC|[VOICECODEC|]
  3411.  */
  3412. static void audio_reset_buffer(size_t pcmbufsize)
  3413. {
  3414.     /* see audio_get_recording_buffer if this is modified */
  3415.     size_t offset;
  3416.  
  3417.     logf("audio_reset_buffer");
  3418.     logf("  size:%08X", pcmbufsize);
  3419.  
  3420.     /* Initially set up file buffer as all space available */
  3421.     filebuf    = audiobuf + MALLOC_BUFSIZE + talk_get_bufsize();
  3422.     filebuflen = audiobufend - filebuf;
  3423.  
  3424.     /* Allow for codec(s) at end of audio buffer */
  3425.     if (talk_voice_required())
  3426.     {
  3427. #ifdef PLAYBACK_VOICE
  3428. #ifdef IRAM_STEAL
  3429.         filebuflen -= CODEC_IRAM_SIZE + 2*CODEC_SIZE;
  3430. #else
  3431.         filebuflen -= 2*(CODEC_IRAM_SIZE + CODEC_SIZE);
  3432. #endif
  3433.         /* Allow 2 codecs at end of audio buffer */
  3434.         /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
  3435.            and out of the way of buffer usage or else a call to audio_get_buffer
  3436.            and subsequent buffer use might trash the swap space. A plugin
  3437.            initializing IRAM after getting the full buffer would present similar
  3438.            problem. Options include: failing the request if the other buffer
  3439.            has been obtained already or never allowing use of the voice IRAM
  3440.            buffer within the audio buffer. Using buffer_alloc basically
  3441.            implements the second in a more convenient way. */
  3442.         iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen;
  3443.         dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE;
  3444.  
  3445. #ifdef IRAM_STEAL
  3446.         /* Allocate voice IRAM swap buffer once */
  3447.         if (iram_buf[CODEC_IDX_VOICE] == NULL)
  3448.         {
  3449.             iram_buf[CODEC_IDX_VOICE] = buffer_alloc(CODEC_IRAM_SIZE);
  3450.             /* buffer_alloc moves audiobuf; this is safe because only the end
  3451.              * has been touched so far in this function and the address of
  3452.              * filebuf + filebuflen is not changed */
  3453.             filebuf += CODEC_IRAM_SIZE;
  3454.             filebuflen -= CODEC_IRAM_SIZE;
  3455.         }
  3456.         dram_buf[CODEC_IDX_VOICE] = dram_buf[CODEC_IDX_AUDIO] + CODEC_SIZE;
  3457. #else
  3458.         iram_buf[CODEC_IDX_VOICE] = dram_buf[CODEC_IDX_AUDIO] + CODEC_SIZE;
  3459.         dram_buf[CODEC_IDX_VOICE] = iram_buf[CODEC_IDX_VOICE] + CODEC_IRAM_SIZE;
  3460. #endif /* IRAM_STEAL */
  3461.  
  3462. #endif /* PLAYBACK_VOICE */
  3463.     }
  3464.     else
  3465.     {
  3466. #ifdef PLAYBACK_VOICE
  3467.         /* Allow for 1 codec at end of audio buffer */
  3468.         filebuflen -= CODEC_IRAM_SIZE + CODEC_SIZE;
  3469.  
  3470.         iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen;
  3471.         dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE;
  3472.         iram_buf[CODEC_IDX_VOICE] = NULL;
  3473.         dram_buf[CODEC_IDX_VOICE] = NULL;
  3474. #endif
  3475.     }
  3476.  
  3477.     filebuflen -= pcmbuf_init(pcmbufsize, filebuf + filebuflen) + GUARD_BUFSIZE;
  3478.  
  3479.     /* Ensure that file buffer is aligned */
  3480.     offset      = -(size_t)filebuf & 3;
  3481.     filebuf += offset;
  3482.     filebuflen -= offset;
  3483.     filebuflen &= ~3;
  3484.  
  3485. #if MEM > 8
  3486.     high_watermark = (3*filebuflen)/4;
  3487. #endif
  3488.  
  3489.     /* Clear any references to the file buffer */
  3490.     buffer_state = BUFFER_STATE_NORMAL;
  3491. }
  3492.  
  3493. #ifdef ROCKBOX_HAS_LOGF
  3494. static void audio_test_track_changed_event(struct mp3entry *id3)
  3495. {
  3496.     (void)id3;
  3497.  
  3498.     logf("tce:%s", id3->path);
  3499. }
  3500. #endif
  3501.  
  3502. static void audio_playback_init(void)
  3503. {
  3504. #ifdef PLAYBACK_VOICE
  3505.     static bool voicetagtrue = true;
  3506.     static struct mp3entry id3_voice;
  3507. #endif
  3508.     struct event ev;
  3509.  
  3510.     logf("playback api init");
  3511.     pcm_init();
  3512.  
  3513. #ifdef AUDIO_HAVE_RECORDING
  3514.     rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
  3515. #endif
  3516.  
  3517. #ifdef ROCKBOX_HAS_LOGF
  3518.     audio_set_track_changed_event(audio_test_track_changed_event);
  3519. #endif
  3520.  
  3521.     /* Initialize codec api. */
  3522.     ci.read_filebuf = codec_filebuf_callback;
  3523.     ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
  3524.     ci.pcmbuf_insert_split = codec_pcmbuf_insert_split_callback;
  3525.     ci.get_codec_memory = codec_get_memory_callback;
  3526.     ci.request_buffer = codec_request_buffer_callback;
  3527.     ci.advance_buffer = codec_advance_buffer_callback;
  3528.     ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
  3529.     ci.request_next_track = codec_request_next_track_callback;
  3530.     ci.mp3_get_filepos = codec_mp3_get_filepos_callback;
  3531.     ci.seek_buffer = codec_seek_buffer_callback;
  3532.     ci.seek_complete = codec_seek_complete_callback;
  3533.     ci.set_elapsed = codec_set_elapsed_callback;
  3534.     ci.set_offset = codec_set_offset_callback;
  3535.     ci.configure = codec_configure_callback;
  3536.     ci.discard_codec = codec_discard_codec_callback;
  3537.  
  3538.     /* Initialize voice codec api. */
  3539. #ifdef PLAYBACK_VOICE
  3540.     memcpy(&ci_voice, &ci, sizeof(struct codec_api));
  3541.     memset(&id3_voice, 0, sizeof(struct mp3entry));
  3542.     ci_voice.read_filebuf = voice_filebuf_callback;
  3543.     ci_voice.pcmbuf_insert = voice_pcmbuf_insert_callback;
  3544.     ci_voice.pcmbuf_insert_split = voice_pcmbuf_insert_split_callback;
  3545.     ci_voice.get_codec_memory = voice_get_memory_callback;
  3546.     ci_voice.request_buffer = voice_request_buffer_callback;
  3547.     ci_voice.advance_buffer = voice_advance_buffer_callback;
  3548.     ci_voice.advance_buffer_loc = voice_advance_buffer_loc_callback;
  3549.     ci_voice.request_next_track = voice_request_next_track_callback;
  3550.     ci_voice.mp3_get_filepos = voice_mp3_get_filepos_callback;
  3551.     ci_voice.seek_buffer = voice_seek_buffer_callback;
  3552.     ci_voice.seek_complete = voice_do_nothing;
  3553.     ci_voice.set_elapsed = voice_set_elapsed_callback;
  3554.     ci_voice.set_offset = voice_set_offset_callback;
  3555.     ci_voice.discard_codec = voice_do_nothing;
  3556.     ci_voice.taginfo_ready = &voicetagtrue;
  3557.     ci_voice.id3 = &id3_voice;
  3558.     id3_voice.frequency = 11200;
  3559.     id3_voice.length = 1000000L;
  3560. #endif
  3561.  
  3562.     codec_thread_p = create_thread(
  3563.             codec_thread, codec_stack, sizeof(codec_stack),
  3564.             codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK));
  3565.  
  3566.     while (1)
  3567.     {
  3568.         queue_wait(&audio_queue, &ev);
  3569.         if (ev.id == Q_AUDIO_POSTINIT)
  3570.             break ;
  3571.  
  3572. #ifndef SIMULATOR
  3573.         if (ev.id == SYS_USB_CONNECTED)
  3574.         {
  3575.             logf("USB: Audio preinit");
  3576.             usb_acknowledge(SYS_USB_CONNECTED_ACK);
  3577.             usb_wait_for_disconnect(&audio_queue);
  3578.         }
  3579. #endif
  3580.     }
  3581.  
  3582.     /* initialize the buffer */
  3583.     filebuf = audiobuf; /* must be non-NULL for audio_set_crossfade */
  3584.     buffer_state = BUFFER_STATE_TRASHED; /* force it */
  3585.     audio_set_crossfade(global_settings.crossfade);
  3586.  
  3587.     audio_is_initialized = true;
  3588.  
  3589.     sound_settings_apply();
  3590. }
  3591. #if MEM > 8
  3592. /* we dont want this rebuffering on targets with little ram
  3593.    because the disk may never spin down */
  3594. static bool ata_fillbuffer_callback(void)
  3595. {
  3596.     queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA, 0);
  3597.     return true;
  3598. }
  3599. #endif
  3600.  
  3601. static void audio_thread(void)
  3602. {
  3603.     struct event ev;
  3604.     /* At first initialize audio system in background. */
  3605.     audio_playback_init();
  3606.    
  3607.     while (1)
  3608.     {
  3609.         intptr_t result = 0;
  3610.  
  3611.         if (filling)
  3612.         {
  3613.             queue_wait_w_tmo(&audio_queue, &ev, 0);
  3614.             if (ev.id == SYS_TIMEOUT)
  3615.                 ev.id = Q_AUDIO_FILL_BUFFER;
  3616.         }
  3617.         else
  3618.         {
  3619.             queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
  3620. #if MEM > 8
  3621.             if (playing && (ev.id == SYS_TIMEOUT) &&
  3622.                 (FILEBUFUSED < high_watermark))
  3623.                 register_ata_idle_func(ata_fillbuffer_callback);
  3624. #endif
  3625.         }
  3626.  
  3627.         switch (ev.id) {
  3628. #if MEM > 8
  3629.             case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA:
  3630.                  /* only fill if the disk is still spining */
  3631. #ifndef SIMULATOR
  3632.                  if (!ata_disk_is_active())
  3633.                     break;
  3634. #endif
  3635. #endif /* MEM > 8 */
  3636.                   /* else fall through to Q_AUDIO_FILL_BUFFER */
  3637.             case Q_AUDIO_FILL_BUFFER:
  3638.                 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
  3639.                 if (!filling)
  3640.                     if (!playing || playlist_end || ci.stop_codec)
  3641.                         break;
  3642.                 audio_fill_file_buffer(false, false, 0);
  3643.                 break;
  3644.  
  3645.             case Q_AUDIO_PLAY:
  3646.                 LOGFQUEUE("audio < Q_AUDIO_PLAY");
  3647.                 audio_clear_track_entries(false);
  3648.                 audio_play_start((size_t)ev.data);
  3649.                 break ;
  3650.  
  3651.             case Q_AUDIO_STOP:
  3652.                 LOGFQUEUE("audio < Q_AUDIO_STOP");
  3653.                 audio_stop_playback();
  3654.                 break ;
  3655.  
  3656.             case Q_AUDIO_PAUSE:
  3657.                 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
  3658.                 pcmbuf_pause((bool)ev.data);
  3659.                 paused = (bool)ev.data;
  3660.                 break ;
  3661.  
  3662.             case Q_AUDIO_SKIP:
  3663.                 LOGFQUEUE("audio < Q_AUDIO_SKIP");
  3664.                 audio_initiate_track_change((long)ev.data);
  3665.                 break;
  3666.  
  3667.             case Q_AUDIO_PRE_FF_REWIND:
  3668.                 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
  3669.                 if (!playing)
  3670.                     break;
  3671.                 pcmbuf_pause(true);
  3672.                 break;
  3673.  
  3674.             case Q_AUDIO_FF_REWIND:
  3675.                 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
  3676.                 if (!playing)
  3677.                     break ;
  3678.                 ci.seek_time = (long)ev.data+1;
  3679.                 break ;
  3680.  
  3681.             case Q_AUDIO_REBUFFER_SEEK:
  3682.                 LOGFQUEUE("audio < Q_AUDIO_REBUFFER_SEEK");
  3683.                 result = audio_rebuffer_and_seek(ev.data);
  3684.                 break;
  3685.  
  3686.             case Q_AUDIO_CHECK_NEW_TRACK:
  3687.                 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
  3688.                 result = audio_check_new_track();
  3689.                 break;
  3690.  
  3691.             case Q_AUDIO_DIR_SKIP:
  3692.                 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
  3693.                 playlist_end = false;
  3694.                 audio_initiate_dir_change(ev.data);
  3695.                 break;
  3696.  
  3697.             case Q_AUDIO_NEW_PLAYLIST:
  3698.                 LOGFQUEUE("audio < Q_AUDIO_NEW_PLAYLIST");
  3699.                 audio_new_playlist();
  3700.                 break;
  3701.  
  3702.             case Q_AUDIO_FLUSH:
  3703.                 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
  3704.                 audio_invalidate_tracks();
  3705.                 break ;
  3706.  
  3707.             case Q_AUDIO_TRACK_CHANGED:
  3708.                 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
  3709.                 if (track_changed_callback)
  3710.                     track_changed_callback(&CUR_TI->id3);
  3711.                 track_changed = true;
  3712.                 playlist_update_resume_info(audio_current_track());
  3713.                 break ;
  3714.  
  3715. #ifdef AUDIO_HAVE_RECORDING
  3716.             case Q_AUDIO_LOAD_ENCODER:
  3717.                 LOGFQUEUE("audio < Q_AUDIO_LOAD_ENCODER");
  3718.                 LOGFQUEUE("audio > codec Q_ENCODER_LOAD_DISK");
  3719.                 queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, ev.data);
  3720.                 break;
  3721. #endif
  3722.  
  3723. #ifndef SIMULATOR
  3724.             case SYS_USB_CONNECTED:
  3725.                 LOGFQUEUE("audio < SYS_USB_CONNECTED");
  3726.                 audio_stop_playback();
  3727.                 usb_acknowledge(SYS_USB_CONNECTED_ACK);
  3728.                 usb_wait_for_disconnect(&audio_queue);
  3729.                 break ;
  3730. #endif
  3731.  
  3732.             case SYS_TIMEOUT:
  3733.                 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
  3734.                 break;
  3735.  
  3736.             default:
  3737.                 LOGFQUEUE("audio < default");
  3738.         } /* end switch */
  3739.  
  3740.         queue_reply(&audio_queue, result);
  3741.     } /* end while */
  3742. }

Update the Post

Either update this post and resubmit it with changes, or make a new post.

You may also comment on this post.

update paste below
details of the post (optional)

Note: Only the paste content is required, though the following information can be useful to others.

Save name / title?

(space separated, optional)



Please note that information posted here will expire by default in one month. If you do not want it to expire, please set the expiry time above. If it is set to expire, web search engines will not be allowed to index it prior to it expiring. Items that are not marked to expire will be indexable by search engines. Be careful with your passwords. All illegal activities will be reported and any information will be handed over to the authorities, so be good.

comments powered by Disqus
worth-right
worth-right