1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 Miika Pekkarinen
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
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 */
49 #include "buffering.h"
50 #include "mp3_playback.h"
65 #ifdef HAVE_LCD_BITMAP
67 #include "peakmeter.h"
77 #include "ata_idle_notify.h"
80 #include "recording.h"
85 #include "menus/eq_menu.h"
88 #define PLAYBACK_VOICE
91 /* default point to start buffer refill */
92 #define AUDIO_DEFAULT_WATERMARK (1024*512)
93 /* amount of data to read in one read() call */
94 #define AUDIO_DEFAULT_FILECHUNK (1024*32)
95 /* amount of guess-space to allow for codecs that must hunt and peck
96 * for their correct seeek target, 32k seems a good size */
97 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
99 /* Define LOGF_ENABLE to enable logf output in this file */
100 /*#define LOGF_ENABLE*/
103 /* macros to enable logf for queues
104 logging on SYS_TIMEOUT can be disabled */
106 /* Define this for logf output of all queuing except SYS_TIMEOUT */
107 #define PLAYBACK_LOGQUEUES
108 /* Define this to logf SYS_TIMEOUT messages */
109 /*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
112 #ifdef PLAYBACK_LOGQUEUES
113 #define LOGFQUEUE logf
115 #define LOGFQUEUE(...)
118 #ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
119 #define LOGFQUEUE_SYS_TIMEOUT logf
121 #define LOGFQUEUE_SYS_TIMEOUT(...)
125 /* Define one constant that includes recording related functionality */
126 #if defined(HAVE_RECORDING) && !defined(SIMULATOR)
127 #define AUDIO_HAVE_RECORDING
135 Q_AUDIO_PRE_FF_REWIND
,
137 Q_AUDIO_CHECK_NEW_TRACK
,
139 Q_AUDIO_TRACK_CHANGED
,
143 Q_CODEC_REQUEST_COMPLETE
,
144 Q_CODEC_REQUEST_FAILED
,
152 #ifdef AUDIO_HAVE_RECORDING
158 /* As defined in plugins/lib/xxx2wav.h */
160 #define MALLOC_BUFSIZE (512*1024)
161 #define GUARD_BUFSIZE (32*1024)
163 #define MALLOC_BUFSIZE (100*1024)
164 #define GUARD_BUFSIZE (8*1024)
167 /* As defined in plugin.lds */
169 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x4000c000)
170 #define CODEC_IRAM_SIZE ((size_t)0xc000)
171 #elif defined(IAUDIO_X5) || defined(IAUDIO_M5)
172 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x10010000)
173 #define CODEC_IRAM_SIZE ((size_t)0x10000)
175 #define CODEC_IRAM_ORIGIN ((unsigned char *)0x1000c000)
176 #define CODEC_IRAM_SIZE ((size_t)0xc000)
179 #ifndef IBSS_ATTR_VOICE_STACK
180 #define IBSS_ATTR_VOICE_STACK IBSS_ATTR
183 bool audio_is_initialized
= false;
185 /* Variables are commented with the threads that use them: *
186 * A=audio, C=codec, V=voice. A suffix of - indicates that *
187 * the variable is read but not updated on that thread. */
188 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
190 /* Main state control */
191 static volatile bool audio_codec_loaded NOCACHEBSS_ATTR
= false; /* Codec loaded? (C/A-) */
192 static volatile bool playing NOCACHEBSS_ATTR
= false; /* Is audio playing? (A) */
193 static volatile bool paused NOCACHEBSS_ATTR
= false; /* Is audio paused? (A/C-) */
195 /* Ring buffer where compressed audio and codecs are loaded */
196 static unsigned char *filebuf
= NULL
; /* Start of buffer (A/C-) */
197 static unsigned char *malloc_buf
= NULL
; /* Start of malloc buffer (A/C-) */
198 /* FIXME: make filebuflen static */
199 size_t filebuflen
= 0; /* Size of buffer (A/C-) */
200 /* FIXME: make buf_ridx (C/A-) */
202 /* Possible arrangements of the buffer */
203 #define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
204 #define BUFFER_STATE_INITIALIZED 0 /* voice+audio OR audio-only */
205 #define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
206 static int buffer_state
= BUFFER_STATE_TRASHED
; /* Buffer state */
208 static struct mp3entry prevtrack_id3
;
209 static struct mp3entry curtrack_id3
;
210 static struct mp3entry nexttrack_id3
;
212 /* Track info structure about songs in the file buffer (A/C-) */
214 int audio_hid
; /* The ID for the track's buffer handle */
215 int id3_hid
; /* The ID for the track's metadata handle */
216 int codec_hid
; /* The ID for the track's codec handle */
218 size_t codecsize
; /* Codec length in bytes */
219 size_t filesize
; /* File total length */
221 bool taginfo_ready
; /* Is metadata read */
223 bool event_sent
; /* Was this track's buffered event sent */
226 static struct track_info tracks
[MAX_TRACK
];
227 static volatile int track_ridx
= 0; /* Track being decoded (A/C-) */
228 static int track_widx
= 0; /* Track being buffered (A) */
230 #define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
232 /* Set by the audio thread when the current track information has updated
233 * and the WPS may need to update its cached information */
234 static bool track_changed
= false;
236 /* Information used only for filling the buffer */
237 /* Playlist steps from playing track to next track to be buffered (A) */
238 static int last_peek_offset
= 0;
240 /* Scrobbler support */
241 static unsigned long prev_track_elapsed
= 0; /* Previous track elapsed time (C/A-)*/
243 /* Track change controls */
244 static bool automatic_skip
= false; /* Who initiated in-progress skip? (C/A-) */
245 static bool playlist_end
= false; /* Has the current playlist ended? (A) */
246 static bool dir_skip
= false; /* Is a directory skip pending? (A) */
247 static bool new_playlist
= false; /* Are we starting a new playlist? (A) */
248 static int wps_offset
= 0; /* Pending track change offset, to keep WPS responsive (A) */
249 static bool skipped_during_pause
= false; /* Do we need to clear the PCM buffer when playback resumes (A) */
251 /* Callbacks which applications or plugins may set */
252 /* When the playing track has changed from the user's perspective */
253 void (*track_changed_callback
)(struct mp3entry
*id3
) = NULL
;
254 /* When a track has been buffered */
255 void (*track_buffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
256 /* When a track's buffer has been overwritten or cleared */
257 void (*track_unbuffer_callback
)(struct mp3entry
*id3
, bool last_track
) = NULL
;
259 static size_t buffer_margin
= 0; /* Buffer margin aka anti-skip buffer (A/C-) */
261 /* Multiple threads */
262 static void set_current_codec(int codec_idx
);
263 /* Set the watermark to trigger buffer fill (A/C) FIXME */
264 static void set_filebuf_watermark(int seconds
, size_t max
);
267 static struct event_queue audio_queue NOCACHEBSS_ATTR
;
268 static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR
;
269 static long audio_stack
[(DEFAULT_STACK_SIZE
+ 0x1000)/sizeof(long)];
270 static const char audio_thread_name
[] = "audio";
272 static void audio_thread(void);
273 static void audio_initiate_track_change(long direction
);
274 static bool audio_have_tracks(void);
275 static void audio_reset_buffer(void);
278 extern struct codec_api ci
;
279 static struct event_queue codec_queue NOCACHEBSS_ATTR
;
280 static struct queue_sender_list codec_queue_sender_list
;
281 static long codec_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
283 static const char codec_thread_name
[] = "codec";
284 struct thread_entry
*codec_thread_p
; /* For modifying thread priority later. */
286 static volatile int current_codec IDATA_ATTR
; /* Current codec (normal/voice) */
289 #ifdef PLAYBACK_VOICE
291 extern struct codec_api ci_voice
;
293 static struct thread_entry
*voice_thread_p
= NULL
;
294 static struct event_queue voice_queue NOCACHEBSS_ATTR
;
295 static long voice_stack
[(DEFAULT_STACK_SIZE
+ 0x2000)/sizeof(long)]
296 IBSS_ATTR_VOICE_STACK
;
297 static const char voice_thread_name
[] = "voice codec";
299 /* Voice codec swapping control */
300 extern unsigned char codecbuf
[]; /* DRAM codec swap buffer */
303 /* IRAM codec swap buffer for sim*/
304 static unsigned char sim_iram
[CODEC_IRAM_SIZE
];
305 #undef CODEC_IRAM_ORIGIN
306 #define CODEC_IRAM_ORIGIN sim_iram
309 /* iram_buf and dram_buf are either both NULL or both non-NULL */
310 /* Pointer to IRAM buffer for codec swapping */
311 static unsigned char *iram_buf
= NULL
;
312 /* Pointer to DRAM buffer for codec swapping */
313 static unsigned char *dram_buf
= NULL
;
314 /* Parity of swap_codec calls - needed because one codec swapping itself in
315 automatically swaps in the other and the swap when unlocking should not
316 happen if the parity is even.
318 static bool swap_codec_parity NOCACHEBSS_ATTR
= false; /* true=odd, false=even */
319 /* Locking to control which codec (normal/voice) is running */
320 static struct semaphore sem_codecthread NOCACHEBSS_ATTR
;
321 static struct event event_codecthread NOCACHEBSS_ATTR
;
324 static volatile bool voice_thread_start
= false; /* Triggers voice playback (A/V) */
325 static volatile bool voice_is_playing NOCACHEBSS_ATTR
= false; /* Is voice currently playing? (V) */
326 static volatile bool voice_codec_loaded NOCACHEBSS_ATTR
= false; /* Is voice codec loaded (V/A-) */
327 static unsigned char *voicebuf
= NULL
;
328 static size_t voice_remaining
= 0;
331 /* Voice IRAM has been stolen for other use */
332 static bool voice_iram_stolen
= false;
335 static void (*voice_getmore
)(unsigned char** start
, size_t* size
) = NULL
;
338 void (*callback
)(unsigned char **start
, size_t* size
);
342 static void voice_thread(void);
343 static void voice_stop(void);
345 #endif /* PLAYBACK_VOICE */
348 /* --- Helper functions --- */
350 struct mp3entry
*bufgetid3(int handle_id
)
355 struct mp3entry
*id3
;
356 ssize_t ret
= bufgetdata(handle_id
, 0, (void *)&id3
);
358 if (ret
< 0 || ret
!= sizeof(struct mp3entry
))
364 void *bufgetcodec(struct track_info
*track
)
367 ssize_t ret
= bufgetdata(track
->codec_hid
, track
->codecsize
, &ptr
);
370 buf_request_buffer_handle(CUR_TI
->audio_hid
);
375 ret
= bufgetdata(track
->codec_hid
, track
->codecsize
, &ptr
);
384 bool clear_track_info(struct track_info
*track
)
389 if (track
->codec_hid
> 0) {
390 if (bufclose(track
->codec_hid
))
391 track
->codec_hid
= 0;
396 if (track
->id3_hid
> 0) {
397 if (bufclose(track
->id3_hid
))
403 if (track
->audio_hid
> 0) {
404 if (bufclose(track
->audio_hid
))
405 track
->audio_hid
= 0;
410 memset(track
, 0, sizeof(struct track_info
));
414 /* --- External interfaces --- */
416 void mp3_play_data(const unsigned char* start
, int size
,
417 void (*get_more
)(unsigned char** start
, size_t* size
))
419 #ifdef PLAYBACK_VOICE
420 static struct voice_info voice_clip
;
421 voice_clip
.callback
= get_more
;
422 voice_clip
.buf
= (unsigned char*)start
;
423 voice_clip
.size
= size
;
424 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
425 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
426 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
427 queue_post(&voice_queue
, Q_VOICE_PLAY
, (intptr_t)&voice_clip
);
428 voice_thread_start
= true;
437 void mp3_play_stop(void)
439 #ifdef PLAYBACK_VOICE
440 queue_remove_from_head(&voice_queue
, Q_VOICE_STOP
);
441 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
442 queue_post(&voice_queue
, Q_VOICE_STOP
, 1);
446 void mp3_play_pause(bool play
)
452 bool mp3_is_playing(void)
454 #ifdef PLAYBACK_VOICE
455 return voice_is_playing
;
461 /* If voice could be swapped out - wait for it to return
462 * Used by buffer claming functions.
464 static void wait_for_voice_swap_in(void)
466 #ifdef PLAYBACK_VOICE
467 if (NULL
== iram_buf
)
470 event_wait(&event_codecthread
, STATE_NONSIGNALED
);
471 #endif /* PLAYBACK_VOICE */
474 /* This sends a stop message and the audio thread will dump all it's
475 subsequenct messages */
476 static void audio_hard_stop(void)
479 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
480 queue_send(&audio_queue
, Q_AUDIO_STOP
, 1);
483 unsigned char *audio_get_buffer(bool talk_buf
, size_t *buffer_size
)
485 unsigned char *buf
, *end
;
487 if (audio_is_initialized
)
490 wait_for_voice_swap_in();
491 #ifdef PLAYBACK_VOICE
495 /* else buffer_state will be BUFFER_STATE_TRASHED at this point */
497 if (buffer_size
== NULL
)
499 /* Special case for talk_init to use since it already knows it's
501 buffer_state
= BUFFER_STATE_TRASHED
;
505 if (talk_buf
|| buffer_state
== BUFFER_STATE_TRASHED
506 || !talk_voice_required())
508 logf("get buffer: talk, audio");
509 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
510 the talk buffer is not needed because voice isn't being used, or
511 could be BUFFER_STATE_TRASHED already. If state is
512 BUFFER_STATE_VOICED_ONLY, no problem as long as memory isn't written
513 without the caller knowing what's going on. Changing certain settings
514 may move it to a worse condition but the memory in use by something
515 else will remain undisturbed.
517 if (buffer_state
!= BUFFER_STATE_TRASHED
)
520 buffer_state
= BUFFER_STATE_TRASHED
;
528 /* Safe to just return this if already BUFFER_STATE_VOICED_ONLY or
529 still BUFFER_STATE_INITIALIZED */
530 /* Skip talk buffer and move pcm buffer to end to maximize available
531 contiguous memory - no audio running means voice will not need the
533 logf("get buffer: audio");
534 buf
= audiobuf
+ talk_get_bufsize();
535 end
= audiobufend
- pcmbuf_init(audiobufend
);
536 buffer_state
= BUFFER_STATE_VOICED_ONLY
;
539 *buffer_size
= end
- buf
;
545 void audio_iram_steal(void)
547 /* We need to stop audio playback in order to use codec IRAM */
550 #ifdef PLAYBACK_VOICE
551 if (NULL
!= iram_buf
)
553 /* Can't already be stolen */
554 if (voice_iram_stolen
)
557 /* Must wait for voice to be current again if it is swapped which
558 would cause the caller's buffer to get clobbered when voice locks
559 and runs - we'll wait for it to lock and yield again then make sure
560 the ride has come to a complete stop */
561 wait_for_voice_swap_in();
564 /* Save voice IRAM but just memcpy - safe to do here since voice
565 is current and no audio codec is loaded */
566 memcpy(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
567 voice_iram_stolen
= true;
571 /* Nothing much to do if no voice */
572 voice_iram_stolen
= false;
576 #endif /* IRAM_STEAL */
578 #ifdef HAVE_RECORDING
579 unsigned char *audio_get_recording_buffer(size_t *buffer_size
)
581 /* Don't allow overwrite of voice swap area or we'll trash the
582 swapped-out voice codec but can use whole thing if none */
585 /* Stop audio and voice. Wait for voice to swap in and be clear
586 of pending events to ensure trouble-free operation of encoders */
588 wait_for_voice_swap_in();
589 #ifdef PLAYBACK_VOICE
594 #ifdef PLAYBACK_VOICE
595 /* If no dram_buf, swap space not used and recording gets more
596 memory. Codec swap areas will remain unaffected by the next init
597 since they're allocated at the end of the buffer and their sizes
598 don't change between calls */
601 #endif /* PLAYBACK_VOICE */
604 buffer_state
= BUFFER_STATE_TRASHED
;
606 *buffer_size
= end
- audiobuf
;
608 return (unsigned char *)audiobuf
;
611 bool audio_load_encoder(int afmt
)
614 const char *enc_fn
= get_codec_filename(afmt
| CODEC_TYPE_ENCODER
);
618 audio_remove_encoder();
619 ci
.enc_codec_loaded
= 0; /* clear any previous error condition */
621 LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK");
622 queue_post(&codec_queue
, Q_ENCODER_LOAD_DISK
, (intptr_t)enc_fn
);
624 while (ci
.enc_codec_loaded
== 0)
627 logf("codec loaded: %d", ci
.enc_codec_loaded
);
629 return ci
.enc_codec_loaded
> 0;
634 } /* audio_load_encoder */
636 void audio_remove_encoder(void)
639 /* force encoder codec unload (if currently loaded) */
640 if (ci
.enc_codec_loaded
<= 0)
643 ci
.stop_encoder
= true;
644 while (ci
.enc_codec_loaded
> 0)
647 } /* audio_remove_encoder */
649 #endif /* HAVE_RECORDING */
651 struct mp3entry
* audio_current_track(void)
653 const char *filename
;
655 static struct mp3entry temp_id3
;
657 int offset
= ci
.new_track
+ wps_offset
;
659 cur_idx
= track_ridx
+ offset
;
660 cur_idx
&= MAX_TRACK_MASK
;
662 if (cur_idx
== track_ridx
&& *curtrack_id3
.path
)
663 return &curtrack_id3
;
664 else if (offset
== -1 && *prevtrack_id3
.path
)
665 return &prevtrack_id3
;
666 else if (tracks
[cur_idx
].id3_hid
> 0)
667 return bufgetid3(tracks
[cur_idx
].id3_hid
);
669 memset(&temp_id3
, 0, sizeof(struct mp3entry
));
671 filename
= playlist_peek(0);
673 filename
= "No file!";
675 #ifdef HAVE_TC_RAMCACHE
676 if (tagcache_fill_tags(&temp_id3
, filename
))
680 p
= strrchr(filename
, '/');
686 strncpy(temp_id3
.path
, p
, sizeof(temp_id3
.path
)-1);
687 temp_id3
.title
= &temp_id3
.path
[0];
692 struct mp3entry
* audio_next_track(void)
694 int next_idx
= track_ridx
;
696 if (!audio_have_tracks())
699 if (wps_offset
== -1 && *prevtrack_id3
.path
)
700 return &curtrack_id3
;
703 next_idx
&= MAX_TRACK_MASK
;
705 if (tracks
[next_idx
].id3_hid
<= 0)
708 return &nexttrack_id3
;
711 bool audio_has_changed_track(void)
715 track_changed
= false;
722 void audio_play(long offset
)
726 #ifdef PLAYBACK_VOICE
727 /* Truncate any existing voice output so we don't have spelling
728 * etc. over the first part of the played track */
733 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset
);
734 /* Don't return until playback has actually started */
735 queue_send(&audio_queue
, Q_AUDIO_PLAY
, offset
);
738 void audio_stop(void)
741 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
742 /* Don't return until playback has actually stopped */
743 queue_send(&audio_queue
, Q_AUDIO_STOP
, 0);
746 void audio_pause(void)
748 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
749 /* Don't return until playback has actually paused */
750 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, true);
753 void audio_resume(void)
755 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
756 /* Don't return until playback has actually resumed */
757 queue_send(&audio_queue
, Q_AUDIO_PAUSE
, false);
760 void audio_next(void)
762 if (playlist_check(ci
.new_track
+ wps_offset
+ 1))
764 if (global_settings
.beep
)
765 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
767 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
768 queue_post(&audio_queue
, Q_AUDIO_SKIP
, 1);
769 /* Update wps while our message travels inside deep playback queues. */
771 track_changed
= true;
775 /* No more tracks. */
776 if (global_settings
.beep
)
777 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
781 void audio_prev(void)
783 if (playlist_check(ci
.new_track
+ wps_offset
- 1))
785 if (global_settings
.beep
)
786 pcmbuf_beep(5000, 100, 2500*global_settings
.beep
);
788 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
789 queue_post(&audio_queue
, Q_AUDIO_SKIP
, -1);
790 /* Update wps while our message travels inside deep playback queues. */
792 track_changed
= true;
796 /* No more tracks. */
797 if (global_settings
.beep
)
798 pcmbuf_beep(1000, 100, 1000*global_settings
.beep
);
802 void audio_next_dir(void)
804 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
805 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, 1);
808 void audio_prev_dir(void)
810 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
811 queue_post(&audio_queue
, Q_AUDIO_DIR_SKIP
, -1);
814 void audio_pre_ff_rewind(void)
816 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
817 queue_post(&audio_queue
, Q_AUDIO_PRE_FF_REWIND
, 0);
820 void audio_ff_rewind(long newpos
)
822 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
823 queue_post(&audio_queue
, Q_AUDIO_FF_REWIND
, newpos
);
826 void audio_flush_and_reload_tracks(void)
828 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
829 queue_post(&audio_queue
, Q_AUDIO_FLUSH
, 0);
832 void audio_error_clear(void)
834 #ifdef AUDIO_HAVE_RECORDING
835 pcm_rec_error_clear();
839 int audio_status(void)
844 ret
|= AUDIO_STATUS_PLAY
;
847 ret
|= AUDIO_STATUS_PAUSE
;
849 #ifdef HAVE_RECORDING
850 /* Do this here for constitency with mpeg.c version */
851 ret
|= pcm_rec_status();
857 int audio_get_file_pos(void)
862 #ifndef HAVE_FLASH_STORAGE
863 void audio_set_buffer_margin(int setting
)
865 static const int lookup
[] = {5, 15, 30, 60, 120, 180, 300, 600};
866 buffer_margin
= lookup
[setting
];
867 logf("buffer margin: %d", buffer_margin
);
868 set_filebuf_watermark(buffer_margin
, 0);
872 /* Take nescessary steps to enable or disable the crossfade setting */
873 void audio_set_crossfade(int enable
)
879 /* Tell it the next setting to use */
880 pcmbuf_crossfade_enable(enable
);
882 /* Return if size hasn't changed or this is too early to determine
883 which in the second case there's no way we could be playing
885 if (pcmbuf_is_same_size())
887 /* This function is a copout and just syncs some variables -
888 to be removed at a later date */
889 pcmbuf_crossfade_enable_finished();
894 was_playing
= playing
;
896 /* Playback has to be stopped before changing the buffer size */
899 /* Store the track resume position */
900 offset
= curtrack_id3
.offset
;
901 gui_syncsplash(0, str(LANG_RESTARTING_PLAYBACK
));
904 /* Blast it - audio buffer will have to be setup again next time
906 audio_get_buffer(true, &size
);
908 /* Restart playback if audio was running previously */
913 /* --- Routines called from multiple threads --- */
914 static void set_current_codec(int codec_idx
)
916 current_codec
= codec_idx
;
917 dsp_configure(DSP_SWITCH_CODEC
, codec_idx
);
920 #ifdef PLAYBACK_VOICE
921 static void swap_codec(void)
925 /* Swap nothing if no swap buffers exist */
926 if (dram_buf
== NULL
)
928 logf("swap: no swap buffers");
932 my_codec
= current_codec
;
934 logf("swapping out codec: %d", my_codec
);
936 /* Invert this when a codec thread enters and leaves */
937 swap_codec_parity
= !swap_codec_parity
;
939 /* If this is true, an odd number of calls has occurred and there's
940 no codec thread waiting to swap us out when it locks and runs. This
941 occurs when playback is stopped or when just starting playback and
942 the audio thread is loading a codec; parities should always be even
943 on entry when a thread calls this during playback */
944 if (swap_codec_parity
)
946 /* Save our current IRAM and DRAM */
948 if (voice_iram_stolen
)
950 logf("swap: iram restore");
951 voice_iram_stolen
= false;
952 /* Don't swap trashed data into buffer as the voice IRAM will
953 already be swapped out - should _always_ be the case if
954 voice_iram_stolen is true since the voice has been swapped
956 if (my_codec
== CODEC_IDX_VOICE
)
958 logf("voice iram already swapped");
964 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
970 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
971 /* No cache invalidation needed; it will be done in codec_load_ram
972 or we won't be here otherwise */
975 /* Release my semaphore */
976 semaphore_release(&sem_codecthread
);
977 logf("unlocked: %d", my_codec
);
979 /* Wait for other codec */
980 event_wait(&event_codecthread
,
981 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_NONSIGNALED
: STATE_SIGNALED
);
983 /* Wait for other codec to unlock */
984 logf("waiting for lock: %d", my_codec
);
985 semaphore_wait(&sem_codecthread
);
988 set_current_codec(my_codec
);
989 event_set_state(&event_codecthread
,
990 (my_codec
== CODEC_IDX_AUDIO
) ? STATE_SIGNALED
: STATE_NONSIGNALED
);
992 /* Reload our IRAM and DRAM */
993 memswap128(iram_buf
, CODEC_IRAM_ORIGIN
, CODEC_IRAM_SIZE
);
994 memswap128(dram_buf
, codecbuf
, CODEC_SIZE
);
997 /* Flip parity again */
998 swap_codec_parity
= !swap_codec_parity
;
1000 logf("resuming codec: %d", my_codec
);
1003 /* This function is meant to be used by the buffer stealing functions to
1004 ensure the codec is no longer active and so voice will be swapped-in
1005 before it is called */
1006 static void voice_stop(void)
1008 /* Must have a voice codec loaded or we'll hang forever here */
1009 if (!voice_codec_loaded
)
1012 talk_force_shutup();
1014 /* Loop until voice empties it's queue, stops and picks up on the new
1015 track; the voice thread must be stopped and waiting for messages
1016 outside the codec */
1017 while (voice_is_playing
|| !queue_empty(&voice_queue
) ||
1025 /* Is voice still speaking */
1026 /* Unfortunately only reliable when music is not also playing. */
1027 static bool is_voice_speaking(void)
1029 return is_voice_queued()
1031 || (!playing
&& pcm_is_playing());
1034 #endif /* PLAYBACK_VOICE */
1036 /* Wait for voice to finish speaking. */
1037 /* Also only reliable when music is not also playing. */
1038 void voice_wait(void)
1040 #ifdef PLAYBACK_VOICE
1041 while (is_voice_speaking())
1046 static void set_filebuf_watermark(int seconds
, size_t max
)
1051 return; /* Audio buffers not yet set up */
1053 bytes
= MAX(curtrack_id3
.bitrate
* seconds
* (1000/8), max
);
1054 bytes
= MIN(bytes
, filebuflen
/ 2);
1055 buf_set_conf(BUFFERING_SET_WATERMARK
, bytes
);
1058 const char * get_codec_filename(int cod_spec
)
1062 #ifdef HAVE_RECORDING
1063 /* Can choose decoder or encoder if one available */
1064 int type
= cod_spec
& CODEC_TYPE_MASK
;
1065 int afmt
= cod_spec
& CODEC_AFMT_MASK
;
1067 if ((unsigned)afmt
>= AFMT_NUM_CODECS
)
1068 type
= AFMT_UNKNOWN
| (type
& CODEC_TYPE_MASK
);
1070 fname
= (type
== CODEC_TYPE_ENCODER
) ?
1071 audio_formats
[afmt
].codec_enc_root_fn
:
1072 audio_formats
[afmt
].codec_root_fn
;
1075 (type
== CODEC_TYPE_ENCODER
) ? "Encoder" : "Decoder",
1076 afmt
, fname
? fname
: "<unknown>");
1077 #else /* !HAVE_RECORDING */
1078 /* Always decoder */
1079 if ((unsigned)cod_spec
>= AFMT_NUM_CODECS
)
1080 cod_spec
= AFMT_UNKNOWN
;
1081 fname
= audio_formats
[cod_spec
].codec_root_fn
;
1082 logf("Codec: %d - %s", cod_spec
, fname
? fname
: "<unknown>");
1083 #endif /* HAVE_RECORDING */
1086 } /* get_codec_filename */
1089 /* --- Voice thread --- */
1091 #ifdef PLAYBACK_VOICE
1093 static bool voice_pcmbuf_insert_callback(
1094 const void *ch1
, const void *ch2
, int count
)
1096 const char *src
[2] = { ch1
, ch2
};
1100 int out_count
= dsp_output_count(count
);
1104 while ((dest
= pcmbuf_request_voice_buffer(
1105 &out_count
, playing
)) == NULL
)
1107 if (playing
&& audio_codec_loaded
)
1113 /* Get the real input_size for output_size bytes, guarding
1114 * against resampling buffer overflows. */
1115 inp_count
= dsp_input_count(out_count
);
1120 /* Input size has grown, no error, just don't write more than length */
1121 if (inp_count
> count
)
1124 out_count
= dsp_process(dest
, src
, inp_count
);
1131 pcmbuf_mix_voice(out_count
);
1132 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1137 pcmbuf_write_complete(out_count
);
1143 } /* voice_pcmbuf_insert_callback */
1145 static void* voice_get_memory_callback(size_t *size
)
1147 /* Voice should have no use for this. If it did, we'd have to
1148 swap the malloc buffer as well. */
1153 static void voice_set_elapsed_callback(unsigned int value
)
1158 static void voice_set_offset_callback(size_t value
)
1163 static void voice_configure_callback(int setting
, intptr_t value
)
1165 if (!dsp_configure(setting
, value
))
1167 logf("Illegal key:%d", setting
);
1171 static size_t voice_filebuf_callback(void *ptr
, size_t size
)
1179 /* Handle Q_VOICE_STOP and part of SYS_USB_CONNECTED */
1180 static bool voice_on_voice_stop(bool aborting
, size_t *realsize
)
1182 if (aborting
&& !playing
)
1184 /* Aborting: Slight hack - flush PCM buffer if
1185 only being used for voice */
1189 if (voice_is_playing
)
1191 /* Clear the current buffer */
1192 voice_is_playing
= false;
1193 voice_getmore
= NULL
;
1194 voice_remaining
= 0;
1197 /* Cancel any automatic boost if no more clips requested. */
1198 if (!playing
|| !voice_thread_start
)
1201 /* Force the codec to think it's changing tracks */
1202 ci_voice
.new_track
= 1;
1205 return true; /* Yes, change tracks */
1211 static void* voice_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1213 struct queue_event ev
;
1215 if (ci_voice
.new_track
)
1223 if (voice_is_playing
|| playing
)
1225 queue_wait_w_tmo(&voice_queue
, &ev
, 0);
1226 if (!voice_is_playing
&& ev
.id
== SYS_TIMEOUT
)
1227 ev
.id
= Q_AUDIO_PLAY
;
1231 queue_wait(&voice_queue
, &ev
);
1236 LOGFQUEUE("voice < Q_AUDIO_PLAY");
1239 if (audio_codec_loaded
)
1245 #ifdef AUDIO_HAVE_RECORDING
1246 case Q_ENCODER_RECORD
:
1247 LOGFQUEUE("voice < Q_ENCODER_RECORD");
1253 LOGFQUEUE("voice < Q_VOICE_STOP");
1254 if (voice_on_voice_stop(ev
.data
, realsize
))
1258 case SYS_USB_CONNECTED
:
1260 LOGFQUEUE("voice < SYS_USB_CONNECTED");
1261 bool change_tracks
= voice_on_voice_stop(ev
.data
, realsize
);
1262 /* Voice is obviously current so let us swap ourselves away if
1263 playing so audio may stop itself - audio_codec_loaded can
1264 only be true in this case if we're here even if the codec
1265 is only about to load */
1266 if (audio_codec_loaded
)
1268 /* Playback should be finished by now - ack and wait */
1269 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1270 usb_wait_for_disconnect(&voice_queue
);
1277 LOGFQUEUE("voice < Q_VOICE_PLAY");
1278 if (!voice_is_playing
)
1280 /* Set up new voice data */
1281 struct voice_info
*voice_data
;
1283 if (voice_iram_stolen
)
1285 /* Voice is the first to run again and is currently
1287 logf("voice: iram restore");
1288 memcpy(CODEC_IRAM_ORIGIN
, iram_buf
, CODEC_IRAM_SIZE
);
1289 voice_iram_stolen
= false;
1292 /* Must reset the buffer before any playback begins if
1294 if (buffer_state
== BUFFER_STATE_TRASHED
)
1295 audio_reset_buffer();
1297 voice_is_playing
= true;
1298 trigger_cpu_boost();
1299 voice_data
= (struct voice_info
*)ev
.data
;
1300 voice_remaining
= voice_data
->size
;
1301 voicebuf
= voice_data
->buf
;
1302 voice_getmore
= voice_data
->callback
;
1304 goto voice_play_clip
; /* To exit both switch and while */
1307 LOGFQUEUE_SYS_TIMEOUT("voice < SYS_TIMEOUT");
1308 goto voice_play_clip
;
1311 LOGFQUEUE("voice < default");
1317 if (voice_remaining
== 0 || voicebuf
== NULL
)
1320 voice_getmore((unsigned char **)&voicebuf
, &voice_remaining
);
1322 /* If this clip is done */
1323 if (voice_remaining
== 0)
1325 LOGFQUEUE("voice > voice Q_VOICE_STOP");
1326 queue_post(&voice_queue
, Q_VOICE_STOP
, 0);
1327 /* Force pcm playback. */
1328 if (!pcm_is_playing())
1329 pcmbuf_play_start();
1333 *realsize
= MIN(voice_remaining
, reqsize
);
1339 } /* voice_request_buffer_callback */
1341 static void voice_advance_buffer_callback(size_t amount
)
1343 amount
= MIN(amount
, voice_remaining
);
1345 voice_remaining
-= amount
;
1348 static void voice_advance_buffer_loc_callback(void *ptr
)
1350 size_t amount
= (size_t)ptr
- (size_t)voicebuf
;
1352 voice_advance_buffer_callback(amount
);
1355 static off_t
voice_mp3_get_filepos_callback(int newtime
)
1362 static void voice_do_nothing(void)
1367 static bool voice_seek_buffer_callback(size_t newpos
)
1374 static bool voice_request_next_track_callback(void)
1376 ci_voice
.new_track
= 0;
1380 static void voice_thread(void)
1382 logf("Loading voice codec");
1383 voice_codec_loaded
= true;
1384 semaphore_wait(&sem_codecthread
);
1385 event_set_state(&event_codecthread
, false);
1386 set_current_codec(CODEC_IDX_VOICE
);
1387 dsp_configure(DSP_RESET
, 0);
1388 voice_remaining
= 0;
1389 voice_getmore
= NULL
;
1391 /* FIXME: If we being starting the voice thread without reboot, the
1392 voice_queue could be full of old stuff and we must flush it. */
1393 codec_load_file(get_codec_filename(AFMT_MPA_L3
), &ci_voice
);
1395 logf("Voice codec finished");
1396 voice_codec_loaded
= false;
1397 voice_thread_p
= NULL
;
1398 semaphore_release(&sem_codecthread
);
1399 } /* voice_thread */
1401 #endif /* PLAYBACK_VOICE */
1403 /* --- Codec thread --- */
1404 static bool codec_pcmbuf_insert_callback(
1405 const void *ch1
, const void *ch2
, int count
)
1407 const char *src
[2] = { ch1
, ch2
};
1411 int out_count
= dsp_output_count(count
);
1415 /* Prevent audio from a previous track from playing */
1416 if (ci
.new_track
|| ci
.stop_codec
)
1419 while ((dest
= pcmbuf_request_buffer(&out_count
)) == NULL
)
1422 if (ci
.seek_time
|| ci
.new_track
|| ci
.stop_codec
)
1426 /* Get the real input_size for output_size bytes, guarding
1427 * against resampling buffer overflows. */
1428 inp_count
= dsp_input_count(out_count
);
1433 /* Input size has grown, no error, just don't write more than length */
1434 if (inp_count
> count
)
1437 out_count
= dsp_process(dest
, src
, inp_count
);
1442 pcmbuf_write_complete(out_count
);
1444 #ifdef PLAYBACK_VOICE
1445 if ((voice_is_playing
|| voice_thread_start
)
1446 && pcm_is_playing() && voice_codec_loaded
&&
1447 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1449 voice_thread_start
= false;
1458 } /* codec_pcmbuf_insert_callback */
1460 static void* codec_get_memory_callback(size_t *size
)
1462 *size
= MALLOC_BUFSIZE
;
1466 static void codec_pcmbuf_position_callback(size_t size
) ICODE_ATTR
;
1467 static void codec_pcmbuf_position_callback(size_t size
)
1469 /* This is called from an ISR, so be quick */
1470 unsigned int time
= size
* 1000 / 4 / NATIVE_FREQUENCY
+
1471 prevtrack_id3
.elapsed
;
1473 if (time
>= prevtrack_id3
.length
)
1475 pcmbuf_set_position_callback(NULL
);
1476 prevtrack_id3
.elapsed
= prevtrack_id3
.length
;
1479 prevtrack_id3
.elapsed
= time
;
1482 static void codec_set_elapsed_callback(unsigned int value
)
1484 unsigned int latency
;
1488 #ifdef AB_REPEAT_ENABLE
1489 ab_position_report(value
);
1492 latency
= pcmbuf_get_latency();
1493 if (value
< latency
)
1494 curtrack_id3
.elapsed
= 0;
1495 else if (value
- latency
> curtrack_id3
.elapsed
||
1496 value
- latency
< curtrack_id3
.elapsed
- 2)
1498 curtrack_id3
.elapsed
= value
- latency
;
1502 static void codec_set_offset_callback(size_t value
)
1504 unsigned int latency
;
1509 latency
= pcmbuf_get_latency() * curtrack_id3
.bitrate
/ 8;
1510 if (value
< latency
)
1511 curtrack_id3
.offset
= 0;
1513 curtrack_id3
.offset
= value
- latency
;
1516 static void codec_advance_buffer_counters(size_t amount
)
1518 bufadvance(CUR_TI
->audio_hid
, amount
);
1519 ci
.curpos
+= amount
;
1522 /* copy up-to size bytes into ptr and return the actual size copied */
1523 static size_t codec_filebuf_callback(void *ptr
, size_t size
)
1527 if (ci
.stop_codec
|| !playing
)
1530 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
1532 /* Nothing requested OR nothing left */
1539 buf_request_buffer_handle(CUR_TI
->audio_hid
);
1542 /* Let the disk buffer catch fill until enough data is available */
1543 while (copy_n
== -2)
1547 if (ci
.stop_codec
|| ci
.new_track
)
1550 copy_n
= bufread(CUR_TI
->audio_hid
, size
, ptr
);
1553 /* Update read and other position pointers */
1554 codec_advance_buffer_counters(copy_n
);
1556 /* Return the actual amount of data copied to the buffer */
1558 } /* codec_filebuf_callback */
1560 static void* codec_request_buffer_callback(size_t *realsize
, size_t reqsize
)
1562 size_t copy_n
= reqsize
;
1572 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, &ptr
);
1574 copy_n
= MIN((size_t)ret
, reqsize
);
1584 buf_request_buffer_handle(CUR_TI
->audio_hid
);
1587 /* Let the disk buffer catch fill until enough data is available */
1592 if (ci
.stop_codec
|| ci
.new_track
)
1597 ret
= bufgetdata(CUR_TI
->audio_hid
, reqsize
, &ptr
);
1599 copy_n
= MIN((size_t)ret
, reqsize
);
1604 } /* codec_request_buffer_callback */
1606 static int get_codec_base_type(int type
)
1618 static void codec_advance_buffer_callback(size_t amount
)
1620 codec_advance_buffer_counters(amount
);
1621 codec_set_offset_callback(ci
.curpos
);
1624 static void codec_advance_buffer_loc_callback(void *ptr
)
1626 size_t amount
= buf_get_offset(CUR_TI
->audio_hid
, ptr
);
1627 codec_advance_buffer_callback(amount
);
1630 /* Copied from mpeg.c. Should be moved somewhere else. */
1631 static int codec_get_file_pos(void)
1634 struct mp3entry
*id3
= audio_current_track();
1640 /* Use the TOC to find the new position */
1641 unsigned int percent
, remainder
;
1642 int curtoc
, nexttoc
, plen
;
1644 percent
= (id3
->elapsed
*100)/id3
->length
;
1648 curtoc
= id3
->toc
[percent
];
1651 nexttoc
= id3
->toc
[percent
+1];
1655 pos
= (id3
->filesize
/256)*curtoc
;
1657 /* Use the remainder to get a more accurate position */
1658 remainder
= (id3
->elapsed
*100)%id3
->length
;
1659 remainder
= (remainder
*100)/id3
->length
;
1660 plen
= (nexttoc
- curtoc
)*(id3
->filesize
/256);
1661 pos
+= (plen
/100)*remainder
;
1665 /* No TOC exists, estimate the new position */
1666 pos
= (id3
->filesize
/ (id3
->length
/ 1000)) *
1667 (id3
->elapsed
/ 1000);
1670 else if (id3
->bitrate
)
1671 pos
= id3
->elapsed
* (id3
->bitrate
/ 8);
1675 pos
+= id3
->first_frame_offset
;
1677 /* Don't seek right to the end of the file so that we can
1678 transition properly to the next song */
1679 if (pos
>= (int)(id3
->filesize
- id3
->id3v1len
))
1680 pos
= id3
->filesize
- id3
->id3v1len
- 1;
1685 static off_t
codec_mp3_get_filepos_callback(int newtime
)
1689 curtrack_id3
.elapsed
= newtime
;
1690 newpos
= codec_get_file_pos();
1695 static void codec_seek_complete_callback(void)
1697 logf("seek_complete");
1698 if (pcm_is_paused())
1700 /* If this is not a seamless seek, clear the buffer */
1702 dsp_configure(DSP_FLUSH
, 0);
1704 /* If playback was not 'deliberately' paused, unpause now */
1706 pcmbuf_pause(false);
1711 static bool codec_seek_buffer_callback(size_t newpos
)
1713 logf("codec_seek_buffer_callback");
1715 int ret
= bufseek(CUR_TI
->audio_hid
, newpos
);
1725 static void codec_configure_callback(int setting
, intptr_t value
)
1728 case CODEC_SET_FILEBUF_WATERMARK
:
1729 set_filebuf_watermark(buffer_margin
, value
);
1732 case CODEC_SET_FILEBUF_CHUNKSIZE
:
1733 buf_set_conf(BUFFERING_SET_CHUNKSIZE
, value
);
1736 case CODEC_SET_FILEBUF_PRESEEK
:
1737 buf_set_conf(BUFFERING_SET_PRESEEK
, value
);
1741 if (!dsp_configure(setting
, value
)) { logf("Illegal key:%d", setting
); }
1745 static void codec_track_changed(void)
1747 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1748 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1751 static void codec_pcmbuf_track_changed_callback(void)
1753 pcmbuf_set_position_callback(NULL
);
1754 codec_track_changed();
1757 static void codec_discard_codec_callback(void)
1759 if (CUR_TI
->codec_hid
> 0)
1761 bufclose(CUR_TI
->codec_hid
);
1762 CUR_TI
->codec_hid
= 0;
1763 CUR_TI
->codecsize
= 0;
1767 static inline void codec_gapless_track_change(void) {
1768 /* callback keeps the progress bar moving while the pcmbuf empties */
1769 pcmbuf_set_position_callback(codec_pcmbuf_position_callback
);
1770 /* set the pcmbuf callback for when the track really changes */
1771 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback
);
1774 static inline void codec_crossfade_track_change(void) {
1775 /* Initiate automatic crossfade mode */
1776 pcmbuf_crossfade_init(false);
1777 /* Notify the wps that the track change starts now */
1778 codec_track_changed();
1781 static void codec_track_skip_done(bool was_manual
)
1783 int crossfade_mode
= global_settings
.crossfade
;
1785 /* Manual track change (always crossfade or flush audio). */
1788 pcmbuf_crossfade_init(true);
1789 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
1790 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
1792 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1793 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1794 && crossfade_mode
!= CROSSFADE_ENABLE_TRACKSKIP
)
1796 if (crossfade_mode
== CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP
)
1798 if (global_settings
.playlist_shuffle
)
1799 /* shuffle mode is on, so crossfade: */
1800 codec_crossfade_track_change();
1802 /* shuffle mode is off, so do a gapless track change */
1803 codec_gapless_track_change();
1806 /* normal crossfade: */
1807 codec_crossfade_track_change();
1810 /* normal gapless playback. */
1811 codec_gapless_track_change();
1814 static bool codec_load_next_track(void)
1816 intptr_t result
= Q_CODEC_REQUEST_FAILED
;
1818 prev_track_elapsed
= curtrack_id3
.elapsed
;
1821 codec_seek_complete_callback();
1823 #ifdef AB_REPEAT_ENABLE
1824 ab_end_of_track_report();
1827 logf("Request new track");
1829 if (ci
.new_track
== 0)
1832 automatic_skip
= true;
1837 trigger_cpu_boost();
1838 LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK");
1839 result
= queue_send(&audio_queue
, Q_AUDIO_CHECK_NEW_TRACK
, 0);
1844 case Q_CODEC_REQUEST_COMPLETE
:
1845 LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE");
1846 codec_track_skip_done(!automatic_skip
);
1849 case Q_CODEC_REQUEST_FAILED
:
1850 LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED");
1852 ci
.stop_codec
= true;
1856 LOGFQUEUE("codec |< default");
1857 ci
.stop_codec
= true;
1862 static bool codec_request_next_track_callback(void)
1866 if (ci
.stop_codec
|| !playing
)
1869 prev_codectype
= get_codec_base_type(curtrack_id3
.codectype
);
1871 if (!codec_load_next_track())
1874 /* Seek to the beginning of the new track because if the struct mp3entry was
1875 buffered, "elapsed" might not be zero (if the track has been played
1876 already but not unbuffered) */
1877 codec_seek_buffer_callback(0);
1879 /* Check if the next codec is the same file. */
1880 if (prev_codectype
== get_codec_base_type(curtrack_id3
.codectype
))
1882 logf("New track loaded");
1883 codec_discard_codec_callback();
1888 logf("New codec:%d/%d", curtrack_id3
.codectype
, prev_codectype
);
1893 static void codec_thread(void)
1895 struct queue_event ev
;
1901 queue_wait(&codec_queue
, &ev
);
1904 case Q_CODEC_LOAD_DISK
:
1905 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1906 queue_reply(&codec_queue
, 1);
1907 audio_codec_loaded
= true;
1908 #ifdef PLAYBACK_VOICE
1909 /* Don't sent messages to voice codec if it's already swapped
1910 out or it will never get this */
1911 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1913 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1914 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1916 semaphore_wait(&sem_codecthread
);
1917 event_set_state(&event_codecthread
, true);
1919 set_current_codec(CODEC_IDX_AUDIO
);
1920 ci
.stop_codec
= false;
1921 status
= codec_load_file((const char *)ev
.data
, &ci
);
1922 #ifdef PLAYBACK_VOICE
1923 semaphore_release(&sem_codecthread
);
1928 LOGFQUEUE("codec < Q_CODEC_LOAD");
1929 if (CUR_TI
->codec_hid
<= 0) {
1930 logf("Codec slot is empty!");
1931 /* Wait for the pcm buffer to go empty */
1932 while (pcm_is_playing())
1934 /* This must be set to prevent an infinite loop */
1935 ci
.stop_codec
= true;
1936 LOGFQUEUE("codec > codec Q_AUDIO_PLAY");
1937 queue_post(&codec_queue
, Q_AUDIO_PLAY
, 0);
1941 audio_codec_loaded
= true;
1942 #ifdef PLAYBACK_VOICE
1943 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1945 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1946 queue_post(&voice_queue
, Q_AUDIO_PLAY
, 0);
1948 semaphore_wait(&sem_codecthread
);
1949 event_set_state(&event_codecthread
, true);
1951 set_current_codec(CODEC_IDX_AUDIO
);
1952 ci
.stop_codec
= false;
1953 wrap
= (size_t)&filebuf
[filebuflen
] - (size_t)bufgetcodec(CUR_TI
);
1954 status
= codec_load_ram(bufgetcodec(CUR_TI
), CUR_TI
->codecsize
,
1955 &filebuf
[0], wrap
, &ci
);
1956 #ifdef PLAYBACK_VOICE
1957 semaphore_release(&sem_codecthread
);
1961 #ifdef AUDIO_HAVE_RECORDING
1962 case Q_ENCODER_LOAD_DISK
:
1963 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1964 audio_codec_loaded
= false; /* Not audio codec! */
1965 #ifdef PLAYBACK_VOICE
1966 if (voice_codec_loaded
&& current_codec
== CODEC_IDX_VOICE
)
1968 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
1969 queue_post(&voice_queue
, Q_ENCODER_RECORD
, 0);
1971 semaphore_wait(&sem_codecthread
);
1972 event_set_state(&event_codecthread
, true);
1974 logf("loading encoder");
1975 set_current_codec(CODEC_IDX_AUDIO
);
1976 ci
.stop_encoder
= false;
1977 status
= codec_load_file((const char *)ev
.data
, &ci
);
1978 #ifdef PLAYBACK_VOICE
1979 semaphore_release(&sem_codecthread
);
1981 logf("encoder stopped");
1983 #endif /* AUDIO_HAVE_RECORDING */
1986 case SYS_USB_CONNECTED
:
1987 LOGFQUEUE("codec < SYS_USB_CONNECTED");
1988 queue_clear(&codec_queue
);
1989 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
1990 usb_wait_for_disconnect(&codec_queue
);
1995 LOGFQUEUE("codec < default");
1998 if (audio_codec_loaded
)
2007 audio_codec_loaded
= false;
2011 case Q_CODEC_LOAD_DISK
:
2013 LOGFQUEUE("codec < Q_CODEC_LOAD");
2016 if (ci
.new_track
|| status
!= CODEC_OK
)
2020 logf("Codec failure");
2021 gui_syncsplash(HZ
*2, "Codec failure");
2024 if (!codec_load_next_track())
2026 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2027 /* End of playlist */
2028 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2034 logf("Codec finished");
2037 /* Wait for the audio to stop playing before
2038 * triggering the WPS exit */
2039 while(pcm_is_playing())
2041 curtrack_id3
.elapsed
=
2042 curtrack_id3
.length
- pcmbuf_get_latency();
2045 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
2046 /* End of playlist */
2047 queue_post(&audio_queue
, Q_AUDIO_STOP
, 0);
2052 if (CUR_TI
->codec_hid
> 0)
2054 LOGFQUEUE("codec > codec Q_CODEC_LOAD");
2055 queue_post(&codec_queue
, Q_CODEC_LOAD
, 0);
2059 const char *codec_fn
=
2060 get_codec_filename(curtrack_id3
.codectype
);
2061 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2062 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
,
2063 (intptr_t)codec_fn
);
2068 #ifdef AUDIO_HAVE_RECORDING
2069 case Q_ENCODER_LOAD_DISK
:
2070 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
2072 if (status
== CODEC_OK
)
2075 logf("Encoder failure");
2076 gui_syncsplash(HZ
*2, "Encoder failure");
2078 if (ci
.enc_codec_loaded
< 0)
2081 logf("Encoder failed to load");
2082 ci
.enc_codec_loaded
= -1;
2084 #endif /* AUDIO_HAVE_RECORDING */
2087 LOGFQUEUE("codec < default");
2094 /* --- Audio thread --- */
2096 static bool audio_have_tracks(void)
2098 return track_ridx
!= track_widx
|| CUR_TI
->filesize
;
2101 static bool audio_have_free_tracks(void)
2103 if (track_widx
< track_ridx
)
2104 return track_widx
+ 1 < track_ridx
;
2105 else if (track_ridx
== 0)
2106 return track_widx
< MAX_TRACK
- 1;
2111 int audio_track_count(void)
2113 if (audio_have_tracks())
2115 int relative_track_widx
= track_widx
;
2117 if (track_ridx
> track_widx
)
2118 relative_track_widx
+= MAX_TRACK
;
2120 return relative_track_widx
- track_ridx
+ 1;
2126 long audio_filebufused(void)
2128 return (long) buf_used();
2131 static void audio_update_trackinfo(void)
2133 if (CUR_TI
->id3_hid
> 0)
2134 copy_mp3entry(&curtrack_id3
, bufgetid3(CUR_TI
->id3_hid
));
2136 CUR_TI
->taginfo_ready
= (CUR_TI
->id3_hid
> 0);
2138 int next_idx
= track_ridx
+ 1;
2139 next_idx
&= MAX_TRACK_MASK
;
2141 if (tracks
[next_idx
].id3_hid
> 0)
2142 copy_mp3entry(&nexttrack_id3
, bufgetid3(tracks
[next_idx
].id3_hid
));
2144 tracks
[next_idx
].taginfo_ready
= (tracks
[next_idx
].id3_hid
> 0);
2146 ci
.filesize
= CUR_TI
->filesize
;
2147 curtrack_id3
.elapsed
= 0;
2148 curtrack_id3
.offset
= 0;
2149 ci
.id3
= &curtrack_id3
;
2151 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2154 static void audio_clear_track_entries(bool clear_unbuffered
)
2156 int cur_idx
= track_widx
;
2159 logf("Clearing tracks:%d/%d, %d", track_ridx
, track_widx
, clear_unbuffered
);
2161 /* Loop over all tracks from write-to-read */
2165 cur_idx
&= MAX_TRACK_MASK
;
2167 if (cur_idx
== track_ridx
)
2170 /* If the track is buffered, conditionally clear/notify,
2171 * otherwise clear the track if that option is selected */
2172 if (tracks
[cur_idx
].event_sent
)
2176 /* If there is an unbuffer callback, call it, otherwise,
2177 * just clear the track */
2178 if (track_unbuffer_callback
&& tracks
[last_idx
].id3_hid
> 0)
2179 track_unbuffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), false);
2181 clear_track_info(&tracks
[last_idx
]);
2185 else if (clear_unbuffered
)
2186 clear_track_info(&tracks
[cur_idx
]);
2189 /* We clear the previous instance of a buffered track throughout
2190 * the above loop to facilitate 'last' detection. Clear/notify
2191 * the last track here */
2194 if (track_unbuffer_callback
&& tracks
[last_idx
].id3_hid
> 0)
2195 track_unbuffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), true);
2196 clear_track_info(&tracks
[last_idx
]);
2200 static bool audio_release_tracks(void)
2204 logf("releasing all tracks");
2206 for(i
= 0; i
< MAX_TRACKS
; i
++)
2208 cur_idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
2209 if (!clear_track_info(&tracks
[cur_idx
]))
2216 static bool audio_loadcodec(bool start_play
)
2220 char codec_path
[MAX_PATH
]; /* Full path to codec */
2222 if (tracks
[track_widx
].id3_hid
<= 0) {
2226 const char * codec_fn
=
2227 get_codec_filename(bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
);
2228 if (codec_fn
== NULL
)
2231 tracks
[track_widx
].codec_hid
= 0;
2235 /* Load the codec directly from disk and save some memory. */
2236 track_ridx
= track_widx
;
2237 ci
.filesize
= CUR_TI
->filesize
;
2238 ci
.id3
= &curtrack_id3
;
2239 ci
.taginfo_ready
= &CUR_TI
->taginfo_ready
;
2241 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2242 queue_post(&codec_queue
, Q_CODEC_LOAD_DISK
, (intptr_t)codec_fn
);
2247 /* If we already have another track than this one buffered */
2248 if (track_widx
!= track_ridx
)
2250 prev_track
= (track_widx
- 1) & MAX_TRACK_MASK
;
2252 /* If the previous codec is the same as this one, there is no need
2253 * to put another copy of it on the file buffer */
2254 if (get_codec_base_type(
2255 bufgetid3(tracks
[track_widx
].id3_hid
)->codectype
) ==
2256 get_codec_base_type(
2257 bufgetid3(tracks
[prev_track
].id3_hid
)->codectype
)
2258 && audio_codec_loaded
)
2260 logf("Reusing prev. codec");
2266 codec_get_full_path(codec_path
, codec_fn
);
2268 fd
= open(codec_path
, O_RDONLY
);
2271 logf("Codec doesn't exist!");
2275 tracks
[track_widx
].codecsize
= filesize(fd
);
2277 tracks
[track_widx
].codec_hid
= bufopen(codec_path
, 0, TYPE_CODEC
);
2278 if (tracks
[track_widx
].codec_hid
< 0)
2280 logf("Not enough space");
2286 logf("Loaded codec");
2291 /* TODO: Copied from mpeg.c. Should be moved somewhere else. */
2292 static void audio_set_elapsed(struct mp3entry
* id3
)
2294 unsigned long offset
= id3
->offset
> id3
->first_frame_offset
?
2295 id3
->offset
- id3
->first_frame_offset
: 0;
2298 if ( id3
->has_toc
) {
2299 /* calculate elapsed time using TOC */
2301 unsigned int remainder
, plen
, relpos
, nextpos
;
2303 /* find wich percent we're at */
2304 for (i
=0; i
<100; i
++ )
2305 if ( offset
< id3
->toc
[i
] * (id3
->filesize
/ 256) )
2312 relpos
= id3
->toc
[i
];
2315 nextpos
= id3
->toc
[i
+1];
2319 remainder
= offset
- (relpos
* (id3
->filesize
/ 256));
2321 /* set time for this percent (divide before multiply to prevent
2322 overflow on long files. loss of precision is negligible on
2324 id3
->elapsed
= i
* (id3
->length
/ 100);
2326 /* calculate remainder time */
2327 plen
= (nextpos
- relpos
) * (id3
->filesize
/ 256);
2328 id3
->elapsed
+= (((remainder
* 100) / plen
) *
2329 (id3
->length
/ 10000));
2332 /* no TOC exists. set a rough estimate using average bitrate */
2333 int tpk
= id3
->length
/
2334 ((id3
->filesize
- id3
->first_frame_offset
- id3
->id3v1len
) /
2336 id3
->elapsed
= offset
/ 1024 * tpk
;
2341 /* constant bitrate, use exact calculation */
2342 if (id3
->bitrate
!= 0)
2343 id3
->elapsed
= offset
/ (id3
->bitrate
/ 8);
2347 /* Load one track by making the appropriate bufopen calls. Return true if
2348 everything required was loaded correctly, false if not. */
2349 static bool audio_load_track(int offset
, bool start_play
)
2354 int file_offset
= 0;
2355 struct mp3entry id3
;
2357 /* Stop buffer filling if there is no free track entries.
2358 Don't fill up the last track entry (we wan't to store next track
2360 if (!audio_have_free_tracks())
2362 logf("No free tracks");
2368 logf("Buffering track:%d/%d", track_widx
, track_ridx
);
2369 /* Get track name from current playlist read position. */
2370 while ((trackname
= playlist_peek(last_peek_offset
)) != NULL
)
2372 /* Handle broken playlists. */
2373 fd
= open(trackname
, O_RDONLY
);
2376 logf("Open failed");
2377 /* Skip invalid entry from playlist. */
2378 playlist_skip_entry(NULL
, last_peek_offset
);
2386 logf("End-of-playlist");
2387 playlist_end
= true;
2391 tracks
[track_widx
].filesize
= filesize(fd
);
2393 /* Set default values */
2396 int last_codec
= current_codec
;
2398 set_current_codec(CODEC_IDX_AUDIO
);
2399 buf_set_conf(BUFFERING_SET_WATERMARK
, AUDIO_DEFAULT_WATERMARK
);
2400 buf_set_conf(BUFFERING_SET_CHUNKSIZE
, AUDIO_DEFAULT_FILECHUNK
);
2401 buf_set_conf(BUFFERING_SET_PRESEEK
, AUDIO_REBUFFER_GUESS_SIZE
);
2402 dsp_configure(DSP_RESET
, 0);
2403 set_current_codec(last_codec
);
2405 track_changed
= true;
2406 playlist_update_resume_info(audio_current_track());
2409 /* Get track metadata if we don't already have it. */
2410 if (tracks
[track_widx
].id3_hid
<= 0)
2412 if (get_metadata(&id3
, fd
, trackname
))
2414 tracks
[track_widx
].id3_hid
= bufalloc(&id3
, sizeof(struct mp3entry
),
2416 tracks
[track_widx
].taginfo_ready
= (tracks
[track_widx
].id3_hid
> 0);
2418 if (tracks
[track_widx
].id3_hid
<= 0)
2425 if (track_widx
== track_ridx
)
2426 copy_mp3entry(&curtrack_id3
, &id3
);
2427 else if (track_widx
== ((track_ridx
+ 1) & MAX_TRACK_MASK
))
2428 copy_mp3entry(&nexttrack_id3
, &id3
);
2432 track_changed
= true;
2433 playlist_update_resume_info(audio_current_track());
2438 logf("mde:%s!",trackname
);
2440 /* Skip invalid entry from playlist. */
2441 playlist_skip_entry(NULL
, last_peek_offset
);
2442 tracks
[track_widx
].taginfo_ready
= false;
2451 if (cuesheet_is_enabled() && tracks
[track_widx
].id3
.cuesheet_type
== 1)
2453 char cuepath
[MAX_PATH
];
2455 struct cuesheet
*cue
= start_play
? curr_cue
: temp_cue
;
2457 if (look_for_cuesheet_file(trackname
, cuepath
) &&
2458 parse_cuesheet(cuepath
, cue
))
2460 strcpy((cue
)->audio_filename
, trackname
);
2462 cue_spoof_id3(curr_cue
, &tracks
[track_widx
].id3
);
2467 /* Load the codec. */
2468 if (!audio_loadcodec(start_play
))
2470 if (tracks
[track_widx
].codecsize
)
2472 /* No space for codec on buffer, not an error */
2473 tracks
[track_widx
].codecsize
= 0;
2477 /* This is an error condition, either no codec was found, or reading
2478 * the codec file failed part way through, either way, skip the track */
2479 snprintf(msgbuf
, sizeof(msgbuf
)-1, "No codec for: %s", trackname
);
2480 /* We should not use gui_syncplash from audio thread! */
2481 gui_syncsplash(HZ
*2, msgbuf
);
2482 /* Skip invalid entry from playlist. */
2483 playlist_skip_entry(NULL
, last_peek_offset
);
2484 tracks
[track_widx
].taginfo_ready
= false;
2488 struct mp3entry
*track_id3
;
2490 if (track_widx
== track_ridx
)
2491 track_id3
= &curtrack_id3
;
2492 else if (track_widx
== ((track_ridx
+ 1) & MAX_TRACK_MASK
))
2493 track_id3
= &nexttrack_id3
;
2495 track_id3
= bufgetid3(tracks
[track_widx
].id3_hid
);
2497 set_filebuf_watermark(buffer_margin
, 0);
2498 track_id3
->elapsed
= 0;
2502 switch (track_id3
->codectype
) {
2506 file_offset
= offset
;
2507 track_id3
->offset
= offset
;
2508 audio_set_elapsed(track_id3
);
2513 file_offset
= offset
;
2514 track_id3
->offset
= offset
;
2515 track_id3
->elapsed
= track_id3
->length
/ 2;
2519 case AFMT_OGG_VORBIS
:
2527 track_id3
->offset
= offset
;
2532 logf("alt:%s", trackname
);
2534 tracks
[track_widx
].audio_hid
= bufopen(trackname
, file_offset
, TYPE_AUDIO
);
2536 if (tracks
[track_widx
].audio_hid
<= 0)
2541 buf_request_buffer_handle(tracks
[track_widx
].audio_hid
);
2545 track_widx
&= MAX_TRACK_MASK
;
2550 /* Send callback events to notify about new tracks. */
2551 static void audio_generate_postbuffer_events(void)
2556 logf("Postbuffer:%d/%d",track_ridx
,track_widx
);
2558 if (audio_have_tracks())
2560 cur_idx
= track_ridx
;
2563 if (!tracks
[cur_idx
].event_sent
)
2565 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2567 /* Mark the event 'sent' even if we don't really send one */
2568 tracks
[last_idx
].event_sent
= true;
2569 if (track_buffer_callback
&& tracks
[last_idx
].id3_hid
> 0)
2570 track_buffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), false);
2574 if (cur_idx
== track_widx
)
2577 cur_idx
&= MAX_TRACK_MASK
;
2580 if (last_idx
>= 0 && !tracks
[last_idx
].event_sent
)
2582 tracks
[last_idx
].event_sent
= true;
2583 if (track_buffer_callback
&& tracks
[last_idx
].id3_hid
> 0)
2584 track_buffer_callback(bufgetid3(tracks
[last_idx
].id3_hid
), true);
2589 static void low_buffer_callback(void)
2591 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER");
2592 queue_post(&audio_queue
, Q_AUDIO_FILL_BUFFER
, 0);
2595 static void audio_fill_file_buffer(bool start_play
, size_t offset
)
2597 bool had_next_track
= audio_next_track() != NULL
;
2598 bool continue_buffering
;
2600 /* Must reset the buffer before use if trashed or voice only - voice
2601 file size shouldn't have changed so we can go straight from
2602 BUFFER_STATE_VOICED_ONLY to BUFFER_STATE_INITIALIZED */
2603 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
2604 audio_reset_buffer();
2606 logf("Starting buffer fill");
2609 audio_clear_track_entries(false);
2611 /* Save the current resume position once. */
2612 playlist_update_resume_info(audio_current_track());
2615 continue_buffering
= audio_load_track(offset
, start_play
);
2619 } while (continue_buffering
);
2621 if (!had_next_track
&& audio_next_track())
2622 track_changed
= true;
2624 audio_generate_postbuffer_events();
2625 register_buffer_low_callback(low_buffer_callback
);
2628 static void audio_rebuffer(void)
2630 logf("Forcing rebuffer");
2632 clear_track_info(CUR_TI
);
2634 /* Reset track pointers */
2635 track_widx
= track_ridx
;
2636 audio_clear_track_entries(true);
2638 /* Just to make sure none were forgotten */
2639 audio_release_tracks();
2641 /* Fill the buffer */
2642 last_peek_offset
= -1;
2645 if (!CUR_TI
->taginfo_ready
)
2646 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
2648 audio_fill_file_buffer(false, 0);
2651 static int audio_check_new_track(void)
2653 int track_count
= audio_track_count();
2654 int old_track_ridx
= track_ridx
;
2660 if (playlist_next_dir(ci
.new_track
))
2668 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2669 return Q_CODEC_REQUEST_FAILED
;
2676 /* If the playlist isn't that big */
2677 if (!playlist_check(ci
.new_track
))
2679 if (ci
.new_track
>= 0)
2681 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2682 return Q_CODEC_REQUEST_FAILED
;
2684 /* Find the beginning backward if the user over-skips it */
2685 while (!playlist_check(++ci
.new_track
))
2686 if (ci
.new_track
>= 0)
2688 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2689 return Q_CODEC_REQUEST_FAILED
;
2692 /* Update the playlist */
2693 last_peek_offset
-= ci
.new_track
;
2695 if (playlist_next(ci
.new_track
) < 0)
2697 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED");
2698 return Q_CODEC_REQUEST_FAILED
;
2704 new_playlist
= false;
2707 /* Save the old track */
2708 copy_mp3entry(&prevtrack_id3
, &curtrack_id3
);
2711 for (i
= 0; i
< ci
.new_track
; i
++)
2713 idx
= (track_ridx
+ i
) & MAX_TRACK_MASK
;
2714 if (buf_handle_offset(tracks
[idx
].audio_hid
) > 0)
2715 clear_track_info(&tracks
[idx
]);
2718 /* Move to the new track */
2719 track_ridx
+= ci
.new_track
;
2720 track_ridx
&= MAX_TRACK_MASK
;
2722 buf_set_base_handle(CUR_TI
->audio_hid
);
2726 playlist_end
= false;
2727 wps_offset
= -ci
.new_track
;
2730 track_changed
= true;
2732 /* If it is not safe to even skip this many track entries */
2733 if (ci
.new_track
>= track_count
|| ci
.new_track
<= track_count
- MAX_TRACK
)
2740 forward
= ci
.new_track
> 0;
2743 /* If the target track is clearly not in memory */
2744 if (CUR_TI
->filesize
== 0 || !CUR_TI
->taginfo_ready
)
2750 /* The track may be in memory, see if it really is */
2753 int cur_idx
= track_ridx
;
2754 bool taginfo_ready
= true;
2755 bool wrap
= track_ridx
> old_track_ridx
;
2760 cur_idx
&= MAX_TRACK_MASK
;
2761 if (!(wrap
|| cur_idx
< old_track_ridx
))
2764 /* If we hit a track in between without valid tag info, bail */
2765 if (!tracks
[cur_idx
].taginfo_ready
)
2767 taginfo_ready
= false;
2778 audio_update_trackinfo();
2779 LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE");
2780 return Q_CODEC_REQUEST_COMPLETE
;
2783 void audio_set_track_buffer_event(void (*handler
)(struct mp3entry
*id3
,
2786 track_buffer_callback
= handler
;
2789 void audio_set_track_unbuffer_event(void (*handler
)(struct mp3entry
*id3
,
2792 track_unbuffer_callback
= handler
;
2795 void audio_set_track_changed_event(void (*handler
)(struct mp3entry
*id3
))
2797 track_changed_callback
= handler
;
2800 unsigned long audio_prev_elapsed(void)
2802 return prev_track_elapsed
;
2805 static void audio_stop_codec_flush(void)
2807 ci
.stop_codec
= true;
2810 while (audio_codec_loaded
)
2813 /* If the audio codec is not loaded any more, and the audio is still
2814 * playing, it is now and _only_ now safe to call this function from the
2816 if (pcm_is_playing())
2818 pcmbuf_pause(paused
);
2821 static void audio_stop_playback(void)
2823 /* If we were playing, save resume information */
2826 struct mp3entry
*id3
= NULL
;
2828 if (!playlist_end
|| !ci
.stop_codec
)
2830 /* Set this early, the outside code yields and may allow the codec
2831 to try to wait for a reply on a buffer wait */
2832 ci
.stop_codec
= true;
2833 id3
= audio_current_track();
2836 /* Save the current playing spot, or NULL if the playlist has ended */
2837 playlist_update_resume_info(id3
);
2839 prev_track_elapsed
= curtrack_id3
.elapsed
;
2841 /* Increment index so runtime info is saved in audio_clear_track_entries().
2842 * Done here, as audio_stop_playback() may be called more than once.
2843 * Don't update runtime unless playback is stopped because of end of playlist.
2844 * Updating runtime when manually stopping a tracks, can destroy autoscores
2850 track_ridx
&= MAX_TRACK_MASK
;
2855 audio_stop_codec_flush();
2858 /* Close all tracks */
2859 audio_release_tracks();
2861 /* Mark all entries null. */
2862 audio_clear_track_entries(false);
2864 memset(&curtrack_id3
, 0, sizeof(struct mp3entry
));
2865 memset(&nexttrack_id3
, 0, sizeof(struct mp3entry
));
2868 static void audio_play_start(size_t offset
)
2870 #if INPUT_SRC_CAPS != 0
2871 audio_set_input_source(AUDIO_SRC_PLAYBACK
, SRCF_PLAYBACK
);
2872 audio_set_output_source(AUDIO_SRC_PLAYBACK
);
2875 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2877 audio_stop_codec_flush();
2879 track_changed
= true;
2880 playlist_end
= false;
2888 sound_set_volume(global_settings
.volume
);
2889 track_widx
= track_ridx
= 0;
2891 /* Mark all entries null. */
2892 memset(tracks
, 0, sizeof(struct track_info
) * MAX_TRACK
);
2894 last_peek_offset
= -1;
2896 /* Officially playing */
2897 queue_reply(&audio_queue
, 1);
2899 audio_fill_file_buffer(true, offset
);
2901 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED");
2902 queue_post(&audio_queue
, Q_AUDIO_TRACK_CHANGED
, 0);
2906 /* Invalidates all but currently playing track. */
2907 static void audio_invalidate_tracks(void)
2909 if (audio_have_tracks())
2911 last_peek_offset
= 0;
2912 playlist_end
= false;
2913 track_widx
= track_ridx
;
2915 /* Mark all other entries null (also buffered wrong metadata). */
2916 audio_clear_track_entries(true);
2918 track_widx
= (track_widx
+ 1) & MAX_TRACK_MASK
;
2920 audio_fill_file_buffer(false, 0);
2924 static void audio_new_playlist(void)
2926 /* Prepare to start a new fill from the beginning of the playlist */
2927 last_peek_offset
= -1;
2928 if (audio_have_tracks())
2931 skipped_during_pause
= true;
2932 playlist_end
= false;
2933 track_widx
= track_ridx
;
2934 audio_clear_track_entries(true);
2937 track_widx
&= MAX_TRACK_MASK
;
2939 /* Mark the current track as invalid to prevent skipping back to it */
2940 CUR_TI
->taginfo_ready
= false;
2943 /* Signal the codec to initiate a track change forward */
2944 new_playlist
= true;
2947 /* Officially playing */
2948 queue_reply(&audio_queue
, 1);
2950 audio_fill_file_buffer(false, 0);
2953 static void audio_initiate_track_change(long direction
)
2955 playlist_end
= false;
2956 ci
.new_track
+= direction
;
2957 wps_offset
-= direction
;
2959 skipped_during_pause
= true;
2962 static void audio_initiate_dir_change(long direction
)
2964 playlist_end
= false;
2966 ci
.new_track
= direction
;
2968 skipped_during_pause
= true;
2972 * Layout audio buffer as follows - iram buffer depends on target:
2973 * [|SWAP:iram][|TALK]|MALLOC|FILE|GUARD|PCM|[SWAP:dram[|iram]|]
2975 static void audio_reset_buffer(void)
2977 /* see audio_get_recording_buffer if this is modified */
2978 logf("audio_reset_buffer");
2980 /* If the setup of anything allocated before the file buffer is
2981 changed, do check the adjustments after the buffer_alloc call
2982 as it will likely be affected and need sliding over */
2984 /* Initially set up file buffer as all space available */
2985 malloc_buf
= audiobuf
+ talk_get_bufsize();
2986 /* Align the malloc buf to line size. Especially important to cf
2987 targets that do line reads/writes. */
2988 malloc_buf
= (unsigned char *)(((uintptr_t)malloc_buf
+ 15) & ~15);
2989 filebuf
= malloc_buf
+ MALLOC_BUFSIZE
; /* filebuf line align implied */
2990 filebuflen
= audiobufend
- filebuf
;
2992 /* Allow for codec swap space at end of audio buffer */
2993 if (talk_voice_required())
2995 /* Layout of swap buffer:
2996 * #ifdef IRAM_STEAL (dedicated iram_buf):
2997 * |iram_buf|...audiobuf...|dram_buf|audiobufend
2999 * audiobuf...|dram_buf|iram_buf|audiobufend
3001 #ifdef PLAYBACK_VOICE
3002 /* Check for an absolutely nasty situation which should never,
3003 ever happen - frankly should just panic */
3004 if (voice_codec_loaded
&& current_codec
!= CODEC_IDX_VOICE
)
3006 logf("buffer reset with voice swapped");
3008 /* line align length which line aligns the calculations below since
3009 all sizes are also at least line aligned - needed for memswap128 */
3012 filebuflen
-= CODEC_SIZE
;
3014 filebuflen
-= CODEC_SIZE
+ CODEC_IRAM_SIZE
;
3016 /* Allocate buffers for swapping voice <=> audio */
3017 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3018 and out of the way of buffer usage or else a call to audio_get_buffer
3019 and subsequent buffer use might trash the swap space. A plugin
3020 initializing IRAM after getting the full buffer would present similar
3021 problem. Options include: failing the request if the other buffer
3022 has been obtained already or never allowing use of the voice IRAM
3023 buffer within the audio buffer. Using buffer_alloc basically
3024 implements the second in a more convenient way. */
3025 dram_buf
= filebuf
+ filebuflen
;
3028 /* Allocate voice IRAM swap buffer once */
3029 if (iram_buf
== NULL
)
3031 iram_buf
= buffer_alloc(CODEC_IRAM_SIZE
);
3032 /* buffer_alloc moves audiobuf; this is safe because only the end
3033 * has been touched so far in this function and the address of
3034 * filebuf + filebuflen is not changed */
3035 malloc_buf
+= CODEC_IRAM_SIZE
;
3036 filebuf
+= CODEC_IRAM_SIZE
;
3037 filebuflen
-= CODEC_IRAM_SIZE
;
3040 /* Allocate iram_buf after dram_buf */
3041 iram_buf
= dram_buf
+ CODEC_SIZE
;
3042 #endif /* IRAM_STEAL */
3043 #endif /* PLAYBACK_VOICE */
3047 #ifdef PLAYBACK_VOICE
3048 /* No swap buffers needed */
3054 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
3055 filebuflen
-= pcmbuf_init(filebuf
+ filebuflen
) + GUARD_BUFSIZE
;
3057 /* Make sure filebuflen is a longword multiple after adjustment - filebuf
3058 will already be line aligned */
3061 buffering_init(filebuf
, filebuflen
);
3063 /* Clear any references to the file buffer */
3064 buffer_state
= BUFFER_STATE_INITIALIZED
;
3066 #if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
3067 /* Make sure everything adds up - yes, some info is a bit redundant but
3068 aids viewing and the sumation of certain variables should add up to
3069 the location of others. */
3072 unsigned char * pcmbuf
= pcmbuf_get_meminfo(&pcmbufsize
);
3073 logf("mabuf: %08X", (unsigned)malloc_buf
);
3074 logf("mabufe: %08X", (unsigned)(malloc_buf
+ MALLOC_BUFSIZE
));
3075 logf("fbuf: %08X", (unsigned)filebuf
);
3076 logf("fbufe: %08X", (unsigned)(filebuf
+ filebuflen
));
3077 logf("gbuf: %08X", (unsigned)(filebuf
+ filebuflen
));
3078 logf("gbufe: %08X", (unsigned)(filebuf
+ filebuflen
+ GUARD_BUFSIZE
));
3079 logf("pcmb: %08X", (unsigned)pcmbuf
);
3080 logf("pcmbe: %08X", (unsigned)(pcmbuf
+ pcmbufsize
));
3083 logf("dramb: %08X", (unsigned)dram_buf
);
3084 logf("drambe: %08X", (unsigned)(dram_buf
+ CODEC_SIZE
));
3088 logf("iramb: %08X", (unsigned)iram_buf
);
3089 logf("irambe: %08X", (unsigned)(iram_buf
+ CODEC_IRAM_SIZE
));
3095 static void audio_thread(void)
3097 struct queue_event ev
;
3101 #ifdef PLAYBACK_VOICE
3102 /* Unlock semaphore that init stage locks before creating this thread */
3103 semaphore_release(&sem_codecthread
);
3105 /* Buffers must be set up by now - should panic - really */
3106 if (buffer_state
!= BUFFER_STATE_INITIALIZED
)
3108 logf("audio_thread start: no buffer");
3111 /* Have to wait for voice to load up or else the codec swap will be
3112 invalid when an audio codec is loaded */
3113 wait_for_voice_swap_in();
3118 queue_wait_w_tmo(&audio_queue
, &ev
, HZ
/2);
3121 case Q_AUDIO_FILL_BUFFER
:
3122 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
3123 if (!playing
|| playlist_end
|| ci
.stop_codec
)
3125 audio_fill_file_buffer(false, 0);
3129 LOGFQUEUE("audio < Q_AUDIO_PLAY");
3130 if (playing
&& ev
.data
<= 0)
3131 audio_new_playlist();
3134 audio_stop_playback();
3135 audio_play_start((size_t)ev
.data
);
3140 LOGFQUEUE("audio < Q_AUDIO_STOP");
3142 audio_stop_playback();
3144 queue_clear(&audio_queue
);
3148 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
3149 if (!(bool) ev
.data
&& skipped_during_pause
&& !pcmbuf_is_crossfade_active())
3150 pcmbuf_play_stop(); /* Flush old track on resume after skip */
3151 skipped_during_pause
= false;
3154 pcmbuf_pause((bool)ev
.data
);
3155 paused
= (bool)ev
.data
;
3159 LOGFQUEUE("audio < Q_AUDIO_SKIP");
3160 audio_initiate_track_change((long)ev
.data
);
3163 case Q_AUDIO_PRE_FF_REWIND
:
3164 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
3170 case Q_AUDIO_FF_REWIND
:
3171 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
3174 ci
.seek_time
= (long)ev
.data
+1;
3177 case Q_AUDIO_CHECK_NEW_TRACK
:
3178 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK");
3179 queue_reply(&audio_queue
, audio_check_new_track());
3182 case Q_AUDIO_DIR_SKIP
:
3183 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3184 playlist_end
= false;
3185 audio_initiate_dir_change(ev
.data
);
3189 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
3190 audio_invalidate_tracks();
3193 case Q_AUDIO_TRACK_CHANGED
:
3194 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
3198 automatic_skip
= false;
3199 prevtrack_id3
.path
[0] = 0;
3201 if (track_changed_callback
)
3202 track_changed_callback(&curtrack_id3
);
3203 track_changed
= true;
3204 playlist_update_resume_info(audio_current_track());
3208 case SYS_USB_CONNECTED
:
3209 LOGFQUEUE("audio < SYS_USB_CONNECTED");
3211 audio_stop_playback();
3212 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
3213 usb_wait_for_disconnect(&audio_queue
);
3214 /* release tracks to make sure all handles are closed */
3215 audio_release_tracks();
3220 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3224 LOGFQUEUE("audio < default");
3230 #ifdef ROCKBOX_HAS_LOGF
3231 static void audio_test_track_changed_event(struct mp3entry
*id3
)
3235 logf("tce:%s", id3
->path
);
3239 /* Initialize the audio system - called from init() in main.c.
3240 * Last function because of all the references to internal symbols
3242 void audio_init(void)
3244 #ifdef PLAYBACK_VOICE
3245 static bool voicetagtrue
= true;
3246 static struct mp3entry id3_voice
;
3247 struct thread_entry
*voice_thread_p
= NULL
;
3249 struct thread_entry
*audio_thread_p
;
3251 /* Can never do this twice */
3252 if (audio_is_initialized
)
3254 logf("audio: already initialized");
3258 logf("audio: initializing");
3260 /* Initialize queues before giving control elsewhere in case it likes
3261 to send messages. Thread creation will be delayed however so nothing
3262 starts running until ready if something yields such as talk_init. */
3263 #ifdef PLAYBACK_VOICE
3264 /* Take ownership of lock to prevent playback of anything before audio
3265 hardware is initialized - audio thread unlocks it after final init
3267 semaphore_init(&sem_codecthread
, 1, 0);
3268 event_init(&event_codecthread
, EVENT_MANUAL
| STATE_SIGNALED
);
3270 queue_init(&audio_queue
, true);
3271 queue_enable_queue_send(&audio_queue
, &audio_queue_sender_list
);
3272 queue_init(&codec_queue
, true);
3273 queue_enable_queue_send(&codec_queue
, &codec_queue_sender_list
);
3277 #ifdef ROCKBOX_HAS_LOGF
3278 audio_set_track_changed_event(audio_test_track_changed_event
);
3281 /* Initialize codec api. */
3282 ci
.read_filebuf
= codec_filebuf_callback
;
3283 ci
.pcmbuf_insert
= codec_pcmbuf_insert_callback
;
3284 ci
.get_codec_memory
= codec_get_memory_callback
;
3285 ci
.request_buffer
= codec_request_buffer_callback
;
3286 ci
.advance_buffer
= codec_advance_buffer_callback
;
3287 ci
.advance_buffer_loc
= codec_advance_buffer_loc_callback
;
3288 ci
.request_next_track
= codec_request_next_track_callback
;
3289 ci
.mp3_get_filepos
= codec_mp3_get_filepos_callback
;
3290 ci
.seek_buffer
= codec_seek_buffer_callback
;
3291 ci
.seek_complete
= codec_seek_complete_callback
;
3292 ci
.set_elapsed
= codec_set_elapsed_callback
;
3293 ci
.set_offset
= codec_set_offset_callback
;
3294 ci
.configure
= codec_configure_callback
;
3295 ci
.discard_codec
= codec_discard_codec_callback
;
3297 /* Initialize voice codec api. */
3298 #ifdef PLAYBACK_VOICE
3299 memcpy(&ci_voice
, &ci
, sizeof(ci_voice
));
3300 memset(&id3_voice
, 0, sizeof(id3_voice
));
3301 ci_voice
.read_filebuf
= voice_filebuf_callback
;
3302 ci_voice
.pcmbuf_insert
= voice_pcmbuf_insert_callback
;
3303 ci_voice
.get_codec_memory
= voice_get_memory_callback
;
3304 ci_voice
.request_buffer
= voice_request_buffer_callback
;
3305 ci_voice
.advance_buffer
= voice_advance_buffer_callback
;
3306 ci_voice
.advance_buffer_loc
= voice_advance_buffer_loc_callback
;
3307 ci_voice
.request_next_track
= voice_request_next_track_callback
;
3308 ci_voice
.mp3_get_filepos
= voice_mp3_get_filepos_callback
;
3309 ci_voice
.seek_buffer
= voice_seek_buffer_callback
;
3310 ci_voice
.seek_complete
= voice_do_nothing
;
3311 ci_voice
.set_elapsed
= voice_set_elapsed_callback
;
3312 ci_voice
.set_offset
= voice_set_offset_callback
;
3313 ci_voice
.configure
= voice_configure_callback
;
3314 ci_voice
.discard_codec
= voice_do_nothing
;
3315 ci_voice
.taginfo_ready
= &voicetagtrue
;
3316 ci_voice
.id3
= &id3_voice
;
3317 id3_voice
.frequency
= 11200;
3318 id3_voice
.length
= 1000000L;
3321 /* initialize the buffer */
3324 /* audio_reset_buffer must to know the size of voice buffer so init
3328 codec_thread_p
= create_thread(
3329 codec_thread
, codec_stack
, sizeof(codec_stack
),
3330 CREATE_THREAD_FROZEN
,
3331 codec_thread_name
IF_PRIO(, PRIORITY_PLAYBACK
)
3334 audio_thread_p
= create_thread(audio_thread
, audio_stack
,
3335 sizeof(audio_stack
), CREATE_THREAD_FROZEN
,
3336 audio_thread_name
IF_PRIO(, PRIORITY_BACKGROUND
)
3339 #ifdef PLAYBACK_VOICE
3340 /* TODO: Change this around when various speech codecs can be used */
3341 if (talk_voice_required())
3343 logf("Starting voice codec");
3344 queue_init(&voice_queue
, true);
3345 voice_thread_p
= create_thread(voice_thread
, voice_stack
,
3346 sizeof(voice_stack
), CREATE_THREAD_FROZEN
,
3348 IF_PRIO(, PRIORITY_PLAYBACK
) IF_COP(, CPU
));
3352 /* Set crossfade setting for next buffer init which should be about... */
3353 pcmbuf_crossfade_enable(global_settings
.crossfade
);
3355 /* ...now! Set up the buffers */
3356 audio_reset_buffer();
3358 /* Probably safe to say */
3359 audio_is_initialized
= true;
3361 sound_settings_apply();
3363 eq_hw_enable(global_settings
.eq_hw_enabled
);
3365 #ifndef HAVE_FLASH_STORAGE
3366 audio_set_buffer_margin(global_settings
.buffer_margin
);
3369 /* it's safe to let the threads run now */
3370 thread_thaw(codec_thread_p
);
3371 #ifdef PLAYBACK_VOICE
3373 thread_thaw(voice_thread_p
);
3375 thread_thaw(audio_thread_p
);