Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 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 | ****************************************************************************/ |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 19 | |
| 20 | /* TODO: Check for a possibly broken codepath on a rapid skip, stop event */ |
Brandon Low | 83ce568 | 2006-04-22 21:31:07 +0000 | [diff] [blame] | 21 | /* TODO: same in reverse ^^ */ |
Brandon Low | d461a3e | 2006-04-23 23:27:11 +0000 | [diff] [blame] | 22 | /* TODO: Also play, stop ^^ */ |
Brandon Low | 1d41f77 | 2006-04-13 21:47:00 +0000 | [diff] [blame] | 23 | /* TODO: Can use the track changed callback to detect end of track and seek |
| 24 | * in the previous track until this happens */ |
| 25 | /* Design: we have prev_ti already, have a conditional for what type of seek |
| 26 | * to do on a seek request, if it is a previous track seek, skip previous, |
| 27 | * and in the request_next_track callback set the offset up the same way that |
| 28 | * starting from an offset works. */ |
Brandon Low | 363dbc4 | 2006-04-14 22:15:38 +0000 | [diff] [blame] | 29 | /* This is also necesary to prevent the problem with buffer overwriting on |
| 30 | * automatic track changes */ |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 31 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 32 | #include <stdio.h> |
| 33 | #include <string.h> |
| 34 | #include <stdlib.h> |
| 35 | #include <ctype.h> |
| 36 | |
| 37 | #include "system.h" |
| 38 | #include "thread.h" |
| 39 | #include "file.h" |
| 40 | #include "lcd.h" |
| 41 | #include "font.h" |
| 42 | #include "backlight.h" |
| 43 | #include "button.h" |
| 44 | #include "kernel.h" |
| 45 | #include "tree.h" |
| 46 | #include "debug.h" |
| 47 | #include "sprintf.h" |
| 48 | #include "settings.h" |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 49 | #include "codecs.h" |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 50 | #include "audio.h" |
| 51 | #include "logf.h" |
| 52 | #include "mp3_playback.h" |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 53 | #include "usb.h" |
| 54 | #include "status.h" |
| 55 | #include "main_menu.h" |
| 56 | #include "ata.h" |
| 57 | #include "screens.h" |
| 58 | #include "playlist.h" |
| 59 | #include "playback.h" |
Miika Pekkarinen | 20b3897 | 2005-07-13 12:48:22 +0000 | [diff] [blame] | 60 | #include "pcmbuf.h" |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 61 | #include "pcm_playback.h" |
Linus Nielsen Feltzing | 735f827 | 2005-12-20 21:49:47 +0000 | [diff] [blame] | 62 | #include "pcm_record.h" |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 63 | #include "buffer.h" |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 64 | #include "dsp.h" |
Brandon Low | 8d5a660 | 2006-01-21 23:43:57 +0000 | [diff] [blame] | 65 | #include "abrepeat.h" |
Miika Pekkarinen | b725126 | 2006-03-26 16:37:18 +0000 | [diff] [blame] | 66 | #include "tagcache.h" |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 67 | #ifdef HAVE_LCD_BITMAP |
| 68 | #include "icons.h" |
| 69 | #include "peakmeter.h" |
| 70 | #include "action.h" |
| 71 | #endif |
| 72 | #include "lang.h" |
| 73 | #include "bookmark.h" |
| 74 | #include "misc.h" |
| 75 | #include "sound.h" |
Dave Chapman | 3ad485b | 2005-06-14 22:27:57 +0000 | [diff] [blame] | 76 | #include "metadata.h" |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 77 | #include "talk.h" |
Anton Oleynikov | 3dbb3a2 | 2005-11-13 10:57:35 +0000 | [diff] [blame] | 78 | #ifdef CONFIG_TUNER |
| 79 | #include "radio.h" |
Anton Oleynikov | 3dbb3a2 | 2005-11-13 10:57:35 +0000 | [diff] [blame] | 80 | #endif |
Kevin Ferrare | e991bee | 2005-11-16 15:12:15 +0000 | [diff] [blame] | 81 | #include "splash.h" |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 82 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 83 | static volatile bool audio_codec_loaded; |
| 84 | static volatile bool voice_codec_loaded; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 85 | static volatile bool playing; |
Brandon Low | 857db45 | 2006-04-06 04:07:06 +0000 | [diff] [blame] | 86 | static volatile bool paused; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 87 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 88 | #define CODEC_VORBIS "/.rockbox/codecs/vorbis.codec" |
| 89 | #define CODEC_MPA_L3 "/.rockbox/codecs/mpa.codec" |
| 90 | #define CODEC_FLAC "/.rockbox/codecs/flac.codec" |
| 91 | #define CODEC_WAV "/.rockbox/codecs/wav.codec" |
| 92 | #define CODEC_A52 "/.rockbox/codecs/a52.codec" |
| 93 | #define CODEC_MPC "/.rockbox/codecs/mpc.codec" |
| 94 | #define CODEC_WAVPACK "/.rockbox/codecs/wavpack.codec" |
Dave Chapman | 139c1cb | 2005-09-22 21:55:37 +0000 | [diff] [blame] | 95 | #define CODEC_ALAC "/.rockbox/codecs/alac.codec" |
Dave Chapman | cea6d0c | 2005-10-31 20:56:29 +0000 | [diff] [blame] | 96 | #define CODEC_AAC "/.rockbox/codecs/aac.codec" |
Dave Chapman | 2bf9be1 | 2005-11-11 19:45:36 +0000 | [diff] [blame] | 97 | #define CODEC_SHN "/.rockbox/codecs/shorten.codec" |
Dave Chapman | fbd8e5d | 2006-02-01 16:42:02 +0000 | [diff] [blame] | 98 | #define CODEC_AIFF "/.rockbox/codecs/aiff.codec" |
Dave Chapman | 752faa4 | 2006-07-18 18:33:12 +0000 | [diff] [blame] | 99 | #define CODEC_SID "/.rockbox/codecs/sid.codec" |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 100 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 101 | /* default point to start buffer refill */ |
Miika Pekkarinen | de3b04e | 2005-06-29 14:46:27 +0000 | [diff] [blame] | 102 | #define AUDIO_DEFAULT_WATERMARK (1024*512) |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 103 | /* amount of data to read in one read() call */ |
Miika Pekkarinen | 68b9acd | 2005-06-10 15:02:10 +0000 | [diff] [blame] | 104 | #define AUDIO_DEFAULT_FILECHUNK (1024*32) |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 105 | /* point at which the file buffer will fight for CPU time */ |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 106 | #define AUDIO_FILEBUF_CRITICAL (1024*128) |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 107 | /* amount of guess-space to allow for codecs that must hunt and peck |
| 108 | * for their correct seeek target, 32k seems a good size */ |
| 109 | #define AUDIO_REBUFFER_GUESS_SIZE (1024*32) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 110 | |
Miika Pekkarinen | d319116 | 2006-01-27 11:39:46 +0000 | [diff] [blame] | 111 | enum { |
| 112 | Q_AUDIO_PLAY = 1, |
| 113 | Q_AUDIO_STOP, |
| 114 | Q_AUDIO_PAUSE, |
Brandon Low | 2736363 | 2006-04-06 21:06:37 +0000 | [diff] [blame] | 115 | Q_AUDIO_SKIP, |
Brandon Low | ab57025 | 2006-04-07 18:18:36 +0000 | [diff] [blame] | 116 | Q_AUDIO_PRE_FF_REWIND, |
Miika Pekkarinen | d319116 | 2006-01-27 11:39:46 +0000 | [diff] [blame] | 117 | Q_AUDIO_FF_REWIND, |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 118 | Q_AUDIO_REBUFFER_SEEK, |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 119 | Q_AUDIO_CHECK_NEW_TRACK, |
Miika Pekkarinen | d319116 | 2006-01-27 11:39:46 +0000 | [diff] [blame] | 120 | Q_AUDIO_FLUSH, |
| 121 | Q_AUDIO_TRACK_CHANGED, |
Brandon Low | 2736363 | 2006-04-06 21:06:37 +0000 | [diff] [blame] | 122 | Q_AUDIO_DIR_SKIP, |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 123 | Q_AUDIO_NEW_PLAYLIST, |
Miika Pekkarinen | d319116 | 2006-01-27 11:39:46 +0000 | [diff] [blame] | 124 | Q_AUDIO_POSTINIT, |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 125 | Q_AUDIO_FILL_BUFFER, |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 126 | |
Brandon Low | 4b36096 | 2006-04-19 00:23:08 +0000 | [diff] [blame] | 127 | Q_CODEC_REQUEST_PENDING, |
Brandon Low | fd08424 | 2006-04-14 13:05:08 +0000 | [diff] [blame] | 128 | Q_CODEC_REQUEST_COMPLETE, |
Brandon Low | 0291a6e | 2006-04-14 14:03:43 +0000 | [diff] [blame] | 129 | Q_CODEC_REQUEST_FAILED, |
Brandon Low | fd08424 | 2006-04-14 13:05:08 +0000 | [diff] [blame] | 130 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 131 | Q_VOICE_PLAY, |
| 132 | Q_VOICE_STOP, |
| 133 | |
Miika Pekkarinen | d319116 | 2006-01-27 11:39:46 +0000 | [diff] [blame] | 134 | Q_CODEC_LOAD, |
| 135 | Q_CODEC_LOAD_DISK, |
| 136 | }; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 137 | |
| 138 | /* As defined in plugins/lib/xxx2wav.h */ |
| 139 | #define MALLOC_BUFSIZE (512*1024) |
Miika Pekkarinen | a4c190f | 2005-10-30 09:30:14 +0000 | [diff] [blame] | 140 | #define GUARD_BUFSIZE (32*1024) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 141 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 142 | /* As defined in plugin.lds */ |
Thom Johansen | a7b5a2c | 2006-03-22 15:19:59 +0000 | [diff] [blame] | 143 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 |
| 144 | #define CODEC_IRAM_ORIGIN 0x4000c000 |
| 145 | #else |
Jens Arnold | a317d74 | 2005-09-01 20:57:33 +0000 | [diff] [blame] | 146 | #define CODEC_IRAM_ORIGIN 0x1000c000 |
Thom Johansen | a7b5a2c | 2006-03-22 15:19:59 +0000 | [diff] [blame] | 147 | #endif |
Jens Arnold | a317d74 | 2005-09-01 20:57:33 +0000 | [diff] [blame] | 148 | #define CODEC_IRAM_SIZE 0xc000 |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 149 | |
Hardeep Sidhu | b8d1a55 | 2006-05-01 18:18:54 +0000 | [diff] [blame] | 150 | #ifndef SIMULATOR |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 151 | extern bool audio_is_initialized; |
Hardeep Sidhu | b8d1a55 | 2006-05-01 18:18:54 +0000 | [diff] [blame] | 152 | #else |
| 153 | static bool audio_is_initialized = false; |
| 154 | #endif |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 155 | |
| 156 | /* Buffer control thread. */ |
| 157 | static struct event_queue audio_queue; |
| 158 | static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; |
| 159 | static const char audio_thread_name[] = "audio"; |
| 160 | |
| 161 | /* Codec thread. */ |
| 162 | static struct event_queue codec_queue; |
Brandon Low | 87484fc | 2006-04-11 20:41:04 +0000 | [diff] [blame] | 163 | static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] |
| 164 | IBSS_ATTR; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 165 | static const char codec_thread_name[] = "codec"; |
| 166 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 167 | /* Voice codec thread. */ |
| 168 | static struct event_queue voice_codec_queue; |
Brandon Low | 87484fc | 2006-04-11 20:41:04 +0000 | [diff] [blame] | 169 | static long voice_codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] |
| 170 | IBSS_ATTR; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 171 | static const char voice_codec_thread_name[] = "voice codec"; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 172 | struct voice_info { |
| 173 | void (*callback)(unsigned char **start, int *size); |
| 174 | int size; |
| 175 | char *buf; |
| 176 | }; |
| 177 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 178 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 179 | static struct mutex mutex_codecthread; |
Brandon Low | fd08424 | 2006-04-14 13:05:08 +0000 | [diff] [blame] | 180 | static struct event_queue codec_callback_queue; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 181 | |
| 182 | static struct mp3entry id3_voice; |
| 183 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 184 | static char *voicebuf; |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 185 | static size_t voice_remaining; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 186 | static bool voice_is_playing; |
| 187 | static void (*voice_getmore)(unsigned char** start, int* size); |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 188 | static int voice_thread_num = -1; |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 189 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 190 | /* Is file buffer currently being refilled? */ |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 191 | static volatile bool filling IDATA_ATTR; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 192 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 193 | volatile int current_codec IDATA_ATTR; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 194 | extern unsigned char codecbuf[]; |
| 195 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 196 | /* Ring buffer where tracks and codecs are loaded. */ |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 197 | static char *filebuf; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 198 | |
| 199 | /* Total size of the ring buffer. */ |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 200 | size_t filebuflen; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 201 | |
| 202 | /* Bytes available in the buffer. */ |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 203 | size_t filebufused; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 204 | |
| 205 | /* Ring buffer read and write indexes. */ |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 206 | static volatile size_t buf_ridx IDATA_ATTR; |
| 207 | static volatile size_t buf_widx IDATA_ATTR; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 208 | |
Brandon Low | a553d5f | 2006-03-23 16:18:17 +0000 | [diff] [blame] | 209 | #ifndef SIMULATOR |
| 210 | static unsigned char *iram_buf[2]; |
| 211 | #endif |
| 212 | static unsigned char *dram_buf[2]; |
| 213 | |
Miika Pekkarinen | 34a25a6 | 2005-07-15 16:42:01 +0000 | [diff] [blame] | 214 | /* Step count to the next unbuffered track. */ |
Miika Pekkarinen | 431e813 | 2005-06-19 18:41:53 +0000 | [diff] [blame] | 215 | static int last_peek_offset; |
| 216 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 217 | /* Track information (count in file buffer, read/write indexes for |
| 218 | track ring structure. */ |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 219 | static int track_ridx; |
| 220 | static int track_widx; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 221 | static bool track_changed; |
| 222 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 223 | /* Partially loaded song's file handle to continue buffering later. */ |
| 224 | static int current_fd; |
| 225 | |
| 226 | /* Information about how many bytes left on the buffer re-fill run. */ |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 227 | static size_t fill_bytesleft; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 228 | |
| 229 | /* Track info structure about songs in the file buffer. */ |
| 230 | static struct track_info tracks[MAX_TRACK]; |
| 231 | |
| 232 | /* Pointer to track info structure about current song playing. */ |
Miika Pekkarinen | 7d6d122 | 2005-06-29 21:36:30 +0000 | [diff] [blame] | 233 | static struct track_info *cur_ti; |
Brandon Low | a3868d3 | 2006-01-21 22:42:44 +0000 | [diff] [blame] | 234 | static struct track_info *prev_ti; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 235 | |
Miika Pekkarinen | 999f89c | 2005-12-03 12:14:26 +0000 | [diff] [blame] | 236 | /* Have we reached end of the current playlist. */ |
| 237 | static bool playlist_end = false; |
| 238 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 239 | /* Codec API including function callbacks. */ |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 240 | extern struct codec_api ci; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 241 | extern struct codec_api ci_voice; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 242 | |
Brandon Low | ebadcc6 | 2006-04-15 02:03:11 +0000 | [diff] [blame] | 243 | /* Was the skip being executed manual or automatic? */ |
Brandon Low | 5cdee94 | 2006-04-23 22:30:52 +0000 | [diff] [blame] | 244 | static bool automatic_skip; |
Brandon Low | 2b18727 | 2006-04-18 18:33:09 +0000 | [diff] [blame] | 245 | static bool dir_skip = false; |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 246 | static bool new_playlist = false; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 247 | |
Miika Pekkarinen | 7d6d122 | 2005-06-29 21:36:30 +0000 | [diff] [blame] | 248 | /* Callback function to call when current track has really changed. */ |
Jens Arnold | a88d076 | 2005-08-18 06:05:15 +0000 | [diff] [blame] | 249 | void (*track_changed_callback)(struct mp3entry *id3); |
Miika Pekkarinen | d54811f | 2005-07-02 16:52:30 +0000 | [diff] [blame] | 250 | void (*track_buffer_callback)(struct mp3entry *id3, bool last_track); |
Miika Pekkarinen | 9bde038 | 2005-07-03 18:36:24 +0000 | [diff] [blame] | 251 | void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track); |
Miika Pekkarinen | 7d6d122 | 2005-06-29 21:36:30 +0000 | [diff] [blame] | 252 | |
Miika Pekkarinen | d319116 | 2006-01-27 11:39:46 +0000 | [diff] [blame] | 253 | static void playback_init(void); |
| 254 | |
Miika Pekkarinen | 68b9acd | 2005-06-10 15:02:10 +0000 | [diff] [blame] | 255 | /* Configuration */ |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 256 | static size_t conf_watermark; |
| 257 | static size_t conf_filechunk; |
| 258 | static size_t buffer_margin; |
Miika Pekkarinen | 2326bea | 2005-06-10 13:43:12 +0000 | [diff] [blame] | 259 | |
Linus Nielsen Feltzing | 4aaa321 | 2005-06-06 00:35:21 +0000 | [diff] [blame] | 260 | static bool v1first = false; |
| 261 | |
Miika Pekkarinen | 5899ed5 | 2005-06-08 10:33:01 +0000 | [diff] [blame] | 262 | static void mp3_set_elapsed(struct mp3entry* id3); |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 263 | static int mp3_get_file_pos(void); |
Miika Pekkarinen | 5899ed5 | 2005-06-08 10:33:01 +0000 | [diff] [blame] | 264 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 265 | static void audio_clear_track_entries( |
Miika Pekkarinen | bb5330c | 2006-08-03 07:45:53 +0000 | [diff] [blame] | 266 | bool clear_buffered, bool clear_unbuffered, bool may_yield); |
Miika Pekkarinen | 8e0b02a | 2006-08-04 10:29:04 +0000 | [diff] [blame] | 267 | static bool initialize_buffer_fill(bool clear_tracks); |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 268 | static void audio_fill_file_buffer( |
| 269 | bool start_play, bool rebuffer, size_t offset); |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 270 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 271 | static void swap_codec(void) |
| 272 | { |
Brandon Low | a553d5f | 2006-03-23 16:18:17 +0000 | [diff] [blame] | 273 | int my_codec = current_codec; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 274 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 275 | logf("swapping out codec:%d", my_codec); |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 276 | |
Brandon Low | a553d5f | 2006-03-23 16:18:17 +0000 | [diff] [blame] | 277 | /* Save our current IRAM and DRAM */ |
| 278 | #ifndef SIMULATOR |
| 279 | memcpy(iram_buf[my_codec], (unsigned char *)CODEC_IRAM_ORIGIN, |
| 280 | CODEC_IRAM_SIZE); |
| 281 | #endif |
| 282 | memcpy(dram_buf[my_codec], codecbuf, CODEC_SIZE); |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 283 | |
Brandon Low | a553d5f | 2006-03-23 16:18:17 +0000 | [diff] [blame] | 284 | do { |
| 285 | /* Release my semaphore and force a task switch. */ |
| 286 | mutex_unlock(&mutex_codecthread); |
| 287 | yield(); |
| 288 | mutex_lock(&mutex_codecthread); |
| 289 | /* Loop until the other codec has locked and run */ |
| 290 | } while (my_codec == current_codec); |
| 291 | current_codec = my_codec; |
| 292 | |
| 293 | /* Reload our IRAM and DRAM */ |
| 294 | #ifndef SIMULATOR |
| 295 | memcpy((unsigned char *)CODEC_IRAM_ORIGIN, iram_buf[my_codec], |
| 296 | CODEC_IRAM_SIZE); |
| 297 | #endif |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 298 | invalidate_icache(); |
Brandon Low | a553d5f | 2006-03-23 16:18:17 +0000 | [diff] [blame] | 299 | memcpy(codecbuf, dram_buf[my_codec], CODEC_SIZE); |
| 300 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 301 | logf("resuming codec:%d", my_codec); |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 302 | } |
| 303 | |
Miika Pekkarinen | 65d43a2 | 2005-08-28 19:55:30 +0000 | [diff] [blame] | 304 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
Miika Pekkarinen | 29aad55 | 2005-08-28 14:16:03 +0000 | [diff] [blame] | 305 | static void voice_boost_cpu(bool state) |
| 306 | { |
Miika Pekkarinen | 65d43a2 | 2005-08-28 19:55:30 +0000 | [diff] [blame] | 307 | static bool voice_cpu_boosted = false; |
Miika Pekkarinen | 731b22e | 2005-11-19 14:04:07 +0000 | [diff] [blame] | 308 | |
Miika Pekkarinen | 29aad55 | 2005-08-28 14:16:03 +0000 | [diff] [blame] | 309 | if (state != voice_cpu_boosted) |
| 310 | { |
Miika Pekkarinen | 29aad55 | 2005-08-28 14:16:03 +0000 | [diff] [blame] | 311 | cpu_boost(state); |
Miika Pekkarinen | 29aad55 | 2005-08-28 14:16:03 +0000 | [diff] [blame] | 312 | voice_cpu_boosted = state; |
| 313 | } |
| 314 | } |
Miika Pekkarinen | 65d43a2 | 2005-08-28 19:55:30 +0000 | [diff] [blame] | 315 | #else |
| 316 | #define voice_boost_cpu(state) do { } while(0) |
| 317 | #endif |
Miika Pekkarinen | 29aad55 | 2005-08-28 14:16:03 +0000 | [diff] [blame] | 318 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 319 | static bool voice_pcmbuf_insert_split_callback( |
| 320 | const void *ch1, const void *ch2, size_t length) |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 321 | { |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 322 | const char* src[2]; |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 323 | char *dest; |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 324 | long input_size; |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 325 | size_t output_size; |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 326 | |
| 327 | src[0] = ch1; |
| 328 | src[1] = ch2; |
| 329 | |
| 330 | if (dsp_stereo_mode() == STEREO_NONINTERLEAVED) |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 331 | length *= 2; /* Length is per channel */ |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 332 | |
Brandon Low | 522ec27 | 2006-04-25 18:21:05 +0000 | [diff] [blame] | 333 | while (length) |
| 334 | { |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 335 | long est_output_size = dsp_output_size(length); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 336 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 337 | while ((dest = pcmbuf_request_voice_buffer(est_output_size, |
| 338 | &output_size, playing)) == NULL) |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 339 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 340 | if (playing) |
| 341 | swap_codec(); |
| 342 | else |
| 343 | yield(); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 344 | } |
| 345 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 346 | /* Get the real input_size for output_size bytes, guarding |
| 347 | * against resampling buffer overflows. */ |
| 348 | input_size = dsp_input_size(output_size); |
| 349 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 350 | if (input_size <= 0) |
| 351 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 352 | DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld<=0\n", |
| 353 | output_size, length, input_size); |
| 354 | /* If this happens, there are samples of codec data that don't |
| 355 | * become a number of pcm samples, and something is broken */ |
| 356 | return false; |
| 357 | } |
| 358 | |
| 359 | /* Input size has grown, no error, just don't write more than length */ |
| 360 | if ((size_t)input_size > length) |
| 361 | input_size = length; |
| 362 | |
| 363 | output_size = dsp_process(dest, src, input_size); |
| 364 | |
| 365 | if (playing) |
| 366 | { |
| 367 | pcmbuf_mix_voice(output_size); |
| 368 | if (pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) |
| 369 | swap_codec(); |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 370 | } |
| 371 | else |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 372 | pcmbuf_write_complete(output_size); |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 373 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 374 | length -= input_size; |
Brandon Low | 522ec27 | 2006-04-25 18:21:05 +0000 | [diff] [blame] | 375 | } |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 376 | |
| 377 | return true; |
| 378 | } |
| 379 | |
| 380 | static bool codec_pcmbuf_insert_split_callback( |
| 381 | const void *ch1, const void *ch2, size_t length) |
| 382 | { |
| 383 | const char* src[2]; |
| 384 | char *dest; |
| 385 | long input_size; |
| 386 | size_t output_size; |
| 387 | |
| 388 | src[0] = ch1; |
| 389 | src[1] = ch2; |
| 390 | |
| 391 | if (dsp_stereo_mode() == STEREO_NONINTERLEAVED) |
| 392 | length *= 2; /* Length is per channel */ |
| 393 | |
Brandon Low | 522ec27 | 2006-04-25 18:21:05 +0000 | [diff] [blame] | 394 | while (length) |
| 395 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 396 | long est_output_size = dsp_output_size(length); |
| 397 | /* Prevent audio from a previous track from playing */ |
| 398 | if (ci.new_track || ci.stop_codec) |
| 399 | return true; |
| 400 | |
| 401 | while ((dest = pcmbuf_request_buffer(est_output_size, |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 402 | &output_size)) == NULL) |
| 403 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 404 | sleep(1); |
| 405 | if (ci.seek_time || ci.new_track || ci.stop_codec) |
| 406 | return true; |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 407 | } |
| 408 | |
Linus Nielsen Feltzing | 591d289 | 2005-08-10 23:17:55 +0000 | [diff] [blame] | 409 | /* Get the real input_size for output_size bytes, guarding |
| 410 | * against resampling buffer overflows. */ |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 411 | input_size = dsp_input_size(output_size); |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 412 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 413 | if (input_size <= 0) |
| 414 | { |
Brandon Low | 87484fc | 2006-04-11 20:41:04 +0000 | [diff] [blame] | 415 | DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld<=0\n", |
| 416 | output_size, length, input_size); |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 417 | /* If this happens, there are samples of codec data that don't |
| 418 | * become a number of pcm samples, and something is broken */ |
| 419 | return false; |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 420 | } |
| 421 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 422 | /* Input size has grown, no error, just don't write more than length */ |
| 423 | if ((size_t)input_size > length) |
Linus Nielsen Feltzing | 591d289 | 2005-08-10 23:17:55 +0000 | [diff] [blame] | 424 | input_size = length; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 425 | |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 426 | output_size = dsp_process(dest, src, input_size); |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 427 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 428 | pcmbuf_write_complete(output_size); |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 429 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 430 | if (voice_is_playing && pcm_is_playing() && |
| 431 | pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80) |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 432 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 433 | swap_codec(); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 434 | } |
| 435 | |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 436 | length -= input_size; |
Brandon Low | 522ec27 | 2006-04-25 18:21:05 +0000 | [diff] [blame] | 437 | } |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 438 | |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 439 | return true; |
| 440 | } |
| 441 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 442 | static bool voice_pcmbuf_insert_callback(const char *buf, size_t length) |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 443 | { |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 444 | /* TODO: The audiobuffer API should probably be updated, and be based on |
Brandon Low | 87484fc | 2006-04-11 20:41:04 +0000 | [diff] [blame] | 445 | * pcmbuf_insert_split(). */ |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 446 | long real_length = length; |
| 447 | |
| 448 | if (dsp_stereo_mode() == STEREO_NONINTERLEAVED) |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 449 | length /= 2; /* Length is per channel */ |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 450 | |
| 451 | /* Second channel is only used for non-interleaved stereo. */ |
| 452 | return voice_pcmbuf_insert_split_callback(buf, buf + (real_length / 2), |
| 453 | length); |
| 454 | } |
| 455 | |
| 456 | static bool codec_pcmbuf_insert_callback(const char *buf, size_t length) |
| 457 | { |
| 458 | /* TODO: The audiobuffer API should probably be updated, and be based on |
| 459 | * pcmbuf_insert_split(). */ |
| 460 | long real_length = length; |
| 461 | |
| 462 | if (dsp_stereo_mode() == STEREO_NONINTERLEAVED) |
| 463 | length /= 2; /* Length is per channel */ |
Magnus Holmgren | 08761aa | 2005-07-16 12:25:28 +0000 | [diff] [blame] | 464 | |
| 465 | /* Second channel is only used for non-interleaved stereo. */ |
| 466 | return codec_pcmbuf_insert_split_callback(buf, buf + (real_length / 2), |
| 467 | length); |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 468 | } |
| 469 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 470 | static void* get_voice_memory_callback(size_t *size) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 471 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 472 | *size = 0; |
| 473 | return NULL; |
| 474 | } |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 475 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 476 | static void* get_codec_memory_callback(size_t *size) |
| 477 | { |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 478 | *size = MALLOC_BUFSIZE; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 479 | if (voice_codec_loaded) |
| 480 | return &audiobuf[talk_get_bufsize()]; |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 481 | else |
| 482 | return audiobuf; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 483 | } |
| 484 | |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 485 | static void pcmbuf_position_callback(size_t size) ICODE_ATTR; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 486 | static void pcmbuf_position_callback(size_t size) |
| 487 | { |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 488 | unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY + |
| 489 | prev_ti->id3.elapsed; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 490 | |
| 491 | if (time >= prev_ti->id3.length) |
| 492 | { |
Brandon Low | a3868d3 | 2006-01-21 22:42:44 +0000 | [diff] [blame] | 493 | pcmbuf_set_position_callback(NULL); |
Brandon Low | 998610c | 2006-01-22 04:35:28 +0000 | [diff] [blame] | 494 | prev_ti->id3.elapsed = prev_ti->id3.length; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 495 | } |
| 496 | else |
Brandon Low | a3868d3 | 2006-01-21 22:42:44 +0000 | [diff] [blame] | 497 | prev_ti->id3.elapsed = time; |
Brandon Low | a3868d3 | 2006-01-21 22:42:44 +0000 | [diff] [blame] | 498 | } |
| 499 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 500 | static void voice_set_elapsed_callback(unsigned int value) |
| 501 | { |
| 502 | (void)value; |
| 503 | } |
| 504 | |
| 505 | static void codec_set_elapsed_callback(unsigned int value) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 506 | { |
| 507 | unsigned int latency; |
Brandon Low | d461a3e | 2006-04-23 23:27:11 +0000 | [diff] [blame] | 508 | if (ci.seek_time) |
| 509 | return; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 510 | |
Brandon Low | 8d5a660 | 2006-01-21 23:43:57 +0000 | [diff] [blame] | 511 | #ifdef AB_REPEAT_ENABLE |
| 512 | ab_position_report(value); |
| 513 | #endif |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 514 | |
Brandon Low | d461a3e | 2006-04-23 23:27:11 +0000 | [diff] [blame] | 515 | latency = pcmbuf_get_latency(); |
Brandon Low | 87484fc | 2006-04-11 20:41:04 +0000 | [diff] [blame] | 516 | if (value < latency) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 517 | cur_ti->id3.elapsed = 0; |
Brandon Low | 87484fc | 2006-04-11 20:41:04 +0000 | [diff] [blame] | 518 | else if (value - latency > cur_ti->id3.elapsed || |
| 519 | value - latency < cur_ti->id3.elapsed - 2) |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 520 | { |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 521 | cur_ti->id3.elapsed = value - latency; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 522 | } |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 523 | } |
| 524 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 525 | static void voice_set_offset_callback(size_t value) |
Ryan Jackson | d191756 | 2005-07-12 16:45:38 +0000 | [diff] [blame] | 526 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 527 | (void)value; |
| 528 | } |
Ryan Jackson | d191756 | 2005-07-12 16:45:38 +0000 | [diff] [blame] | 529 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 530 | static void codec_set_offset_callback(size_t value) |
| 531 | { |
Brandon Low | d461a3e | 2006-04-23 23:27:11 +0000 | [diff] [blame] | 532 | unsigned int latency; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 533 | |
Brandon Low | d461a3e | 2006-04-23 23:27:11 +0000 | [diff] [blame] | 534 | if (ci.seek_time) |
| 535 | return; |
| 536 | |
| 537 | latency = pcmbuf_get_latency() * cur_ti->id3.bitrate / 8; |
Brandon Low | 87484fc | 2006-04-11 20:41:04 +0000 | [diff] [blame] | 538 | if (value < latency) |
Ryan Jackson | d191756 | 2005-07-12 16:45:38 +0000 | [diff] [blame] | 539 | cur_ti->id3.offset = 0; |
Brandon Low | 87484fc | 2006-04-11 20:41:04 +0000 | [diff] [blame] | 540 | else |
Ryan Jackson | d191756 | 2005-07-12 16:45:38 +0000 | [diff] [blame] | 541 | cur_ti->id3.offset = value - latency; |
Ryan Jackson | d191756 | 2005-07-12 16:45:38 +0000 | [diff] [blame] | 542 | } |
| 543 | |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 544 | static bool filebuf_is_lowdata(void) |
| 545 | { |
| 546 | return filebufused < AUDIO_FILEBUF_CRITICAL; |
| 547 | } |
| 548 | |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 549 | static bool have_tracks(void) |
| 550 | { |
Brandon Low | 54af304 | 2006-04-12 02:01:26 +0000 | [diff] [blame] | 551 | return track_ridx != track_widx || cur_ti->filesize; |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 552 | } |
| 553 | |
| 554 | static bool have_free_tracks(void) |
| 555 | { |
| 556 | if (track_widx < track_ridx) |
| 557 | return track_widx + 1 < track_ridx; |
| 558 | else if (track_ridx == 0) |
| 559 | return track_widx < MAX_TRACK - 1; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 560 | |
| 561 | return true; |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 562 | } |
| 563 | |
| 564 | int audio_track_count(void) |
| 565 | { |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 566 | if (have_tracks()) |
| 567 | { |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 568 | int relative_track_widx = track_widx; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 569 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 570 | if (track_ridx > track_widx) |
| 571 | relative_track_widx += MAX_TRACK; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 572 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 573 | return relative_track_widx - track_ridx + 1; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 574 | } |
| 575 | |
| 576 | return 0; |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 577 | } |
| 578 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 579 | static void advance_buffer_counters(size_t amount) |
| 580 | { |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 581 | buf_ridx += amount; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 582 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 583 | if (buf_ridx >= filebuflen) |
| 584 | buf_ridx -= filebuflen; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 585 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 586 | ci.curpos += amount; |
| 587 | cur_ti->available -= amount; |
| 588 | filebufused -= amount; |
Brandon Low | 857db45 | 2006-04-06 04:07:06 +0000 | [diff] [blame] | 589 | |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 590 | /* Start buffer filling as necessary. */ |
| 591 | if (!pcmbuf_is_lowdata() && !filling) |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 592 | { |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 593 | if (conf_watermark && filebufused <= conf_watermark && playing) |
| 594 | queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 595 | } |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 596 | } |
| 597 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 598 | static size_t voice_filebuf_callback(void *ptr, size_t size) |
| 599 | { |
| 600 | (void)ptr; |
| 601 | (void)size; |
| 602 | |
| 603 | return 0; |
| 604 | } |
| 605 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 606 | /* copy up-to size bytes into ptr and return the actual size copied */ |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 607 | static size_t codec_filebuf_callback(void *ptr, size_t size) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 608 | { |
| 609 | char *buf = (char *)ptr; |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 610 | size_t copy_n; |
| 611 | size_t part_n; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 612 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 613 | if (ci.stop_codec || !playing) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 614 | return 0; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 615 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 616 | /* The ammount to copy is the lesser of the requested amount and the |
| 617 | * amount left of the current track (both on disk and already loaded) */ |
| 618 | copy_n = MIN(size, cur_ti->available + cur_ti->filerem); |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 619 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 620 | /* Nothing requested OR nothing left */ |
| 621 | if (copy_n == 0) |
| 622 | return 0; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 623 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 624 | /* Let the disk buffer catch fill until enough data is available */ |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 625 | while (copy_n > cur_ti->available) |
| 626 | { |
Brandon Low | bf397b5 | 2006-04-15 09:19:49 +0000 | [diff] [blame] | 627 | if (!filling) |
| 628 | queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 629 | |
Brandon Low | bf397b5 | 2006-04-15 09:19:49 +0000 | [diff] [blame] | 630 | sleep(1); |
Brandon Low | ebadcc6 | 2006-04-15 02:03:11 +0000 | [diff] [blame] | 631 | if (ci.stop_codec || ci.new_track) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 632 | return 0; |
| 633 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 634 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 635 | /* Copy as much as possible without wrapping */ |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 636 | part_n = MIN(copy_n, filebuflen - buf_ridx); |
| 637 | memcpy(buf, &filebuf[buf_ridx], part_n); |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 638 | /* Copy the rest in the case of a wrap */ |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 639 | if (part_n < copy_n) { |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 640 | memcpy(&buf[part_n], &filebuf[0], copy_n - part_n); |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 641 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 642 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 643 | /* Update read and other position pointers */ |
| 644 | advance_buffer_counters(copy_n); |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 645 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 646 | /* Return the actual amount of data copied to the buffer */ |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 647 | return copy_n; |
| 648 | } |
| 649 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 650 | static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 651 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 652 | struct event ev; |
| 653 | |
| 654 | if (ci_voice.new_track) |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 655 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 656 | *realsize = 0; |
| 657 | return NULL; |
| 658 | } |
| 659 | |
| 660 | while (1) |
| 661 | { |
| 662 | if (voice_is_playing) |
| 663 | queue_wait_w_tmo(&voice_codec_queue, &ev, 0); |
| 664 | else if (playing) |
Miika Pekkarinen | 29aad55 | 2005-08-28 14:16:03 +0000 | [diff] [blame] | 665 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 666 | queue_wait_w_tmo(&voice_codec_queue, &ev, 0); |
| 667 | if (ev.id == SYS_TIMEOUT) |
| 668 | ev.id = Q_AUDIO_PLAY; |
Miika Pekkarinen | 29aad55 | 2005-08-28 14:16:03 +0000 | [diff] [blame] | 669 | } |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 670 | else |
| 671 | queue_wait(&voice_codec_queue, &ev); |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 672 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 673 | switch (ev.id) { |
| 674 | case Q_AUDIO_PLAY: |
Hardeep Sidhu | a02fd1a | 2006-06-17 11:21:22 +0000 | [diff] [blame] | 675 | if (playing) |
| 676 | swap_codec(); |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 677 | break; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 678 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 679 | case Q_VOICE_STOP: |
| 680 | if (voice_is_playing) |
| 681 | { |
| 682 | /* Clear the current buffer */ |
| 683 | voice_is_playing = false; |
| 684 | voice_getmore = NULL; |
| 685 | voice_remaining = 0; |
| 686 | voicebuf = NULL; |
| 687 | voice_boost_cpu(false); |
| 688 | ci_voice.new_track = 1; |
| 689 | /* Force the codec to think it's changing tracks */ |
| 690 | *realsize = 0; |
| 691 | return NULL; |
| 692 | } |
| 693 | else |
| 694 | break; |
| 695 | |
| 696 | case SYS_USB_CONNECTED: |
Miika Pekkarinen | b591bb3 | 2006-08-05 07:29:53 +0000 | [diff] [blame] | 697 | logf("USB: Voice codec"); |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 698 | usb_acknowledge(SYS_USB_CONNECTED_ACK); |
| 699 | if (audio_codec_loaded) |
| 700 | swap_codec(); |
| 701 | usb_wait_for_disconnect(&voice_codec_queue); |
| 702 | break; |
| 703 | |
| 704 | case Q_VOICE_PLAY: |
| 705 | { |
| 706 | struct voice_info *voice_data; |
| 707 | voice_is_playing = true; |
| 708 | voice_boost_cpu(true); |
| 709 | voice_data = ev.data; |
| 710 | voice_remaining = voice_data->size; |
| 711 | voicebuf = voice_data->buf; |
| 712 | voice_getmore = voice_data->callback; |
| 713 | } |
| 714 | case SYS_TIMEOUT: |
| 715 | goto voice_play_clip; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 716 | } |
| 717 | } |
| 718 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 719 | voice_play_clip: |
| 720 | |
| 721 | if (voice_remaining == 0 || voicebuf == NULL) |
| 722 | { |
| 723 | if (voice_getmore) |
| 724 | voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining); |
| 725 | |
| 726 | /* If this clip is done */ |
| 727 | if (!voice_remaining) |
| 728 | { |
| 729 | queue_post(&voice_codec_queue, Q_VOICE_STOP, 0); |
| 730 | /* Force pcm playback. */ |
| 731 | if (!pcm_is_playing()) |
| 732 | pcmbuf_play_start(); |
| 733 | } |
| 734 | } |
| 735 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 736 | *realsize = MIN(voice_remaining, reqsize); |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 737 | |
| 738 | if (*realsize == 0) |
| 739 | return NULL; |
| 740 | |
| 741 | return voicebuf; |
| 742 | } |
| 743 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 744 | static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 745 | { |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 746 | size_t short_n, copy_n, buf_rem; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 747 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 748 | if (!playing) |
| 749 | { |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 750 | *realsize = 0; |
| 751 | return NULL; |
| 752 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 753 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 754 | copy_n = MIN(reqsize, cur_ti->available + cur_ti->filerem); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 755 | if (copy_n == 0) |
| 756 | { |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 757 | *realsize = 0; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 758 | return NULL; |
| 759 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 760 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 761 | while (copy_n > cur_ti->available) |
| 762 | { |
Brandon Low | bf397b5 | 2006-04-15 09:19:49 +0000 | [diff] [blame] | 763 | if (!filling) |
| 764 | queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 765 | |
Brandon Low | bf397b5 | 2006-04-15 09:19:49 +0000 | [diff] [blame] | 766 | sleep(1); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 767 | if (ci.stop_codec || ci.new_track) |
| 768 | { |
Miika Pekkarinen | 9ff373c | 2005-06-10 20:29:35 +0000 | [diff] [blame] | 769 | *realsize = 0; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 770 | return NULL; |
| 771 | } |
| 772 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 773 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 774 | /* How much is left at the end of the file buffer before wrap? */ |
| 775 | buf_rem = filebuflen - buf_ridx; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 776 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 777 | /* If we can't satisfy the request without wrapping */ |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 778 | if (buf_rem < copy_n) |
| 779 | { |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 780 | /* How short are we? */ |
| 781 | short_n = copy_n - buf_rem; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 782 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 783 | /* If we can fudge it with the guardbuf */ |
| 784 | if (short_n < GUARD_BUFSIZE) |
| 785 | memcpy(&filebuf[filebuflen], &filebuf[0], short_n); |
| 786 | else |
| 787 | copy_n = buf_rem; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 788 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 789 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 790 | *realsize = copy_n; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 791 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 792 | return (char *)&filebuf[buf_ridx]; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 793 | } |
| 794 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 795 | static int get_codec_base_type(int type) |
| 796 | { |
| 797 | switch (type) { |
| 798 | case AFMT_MPA_L1: |
| 799 | case AFMT_MPA_L2: |
| 800 | case AFMT_MPA_L3: |
| 801 | return AFMT_MPA_L3; |
| 802 | } |
| 803 | |
| 804 | return type; |
| 805 | } |
| 806 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 807 | /* Count the data BETWEEN the selected tracks */ |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 808 | static size_t buffer_count_tracks(int from_track, int to_track) |
| 809 | { |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 810 | size_t amount = 0; |
| 811 | bool need_wrap = to_track < from_track; |
| 812 | |
Brandon Low | fbe74d1 | 2006-04-14 12:53:29 +0000 | [diff] [blame] | 813 | while (1) |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 814 | { |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 815 | if (++from_track >= MAX_TRACK) |
| 816 | { |
| 817 | from_track -= MAX_TRACK; |
| 818 | need_wrap = false; |
| 819 | } |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 820 | |
Brandon Low | 530cad3 | 2006-04-14 17:48:01 +0000 | [diff] [blame] | 821 | if (from_track >= to_track && !need_wrap) |
Brandon Low | fbe74d1 | 2006-04-14 12:53:29 +0000 | [diff] [blame] | 822 | break; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 823 | |
Brandon Low | fbe74d1 | 2006-04-14 12:53:29 +0000 | [diff] [blame] | 824 | amount += tracks[from_track].codecsize + tracks[from_track].filesize; |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 825 | } |
| 826 | return amount; |
| 827 | } |
| 828 | |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 829 | static bool buffer_wind_forward(int new_track_ridx, int old_track_ridx) |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 830 | { |
| 831 | size_t amount; |
| 832 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 833 | /* Start with the remainder of the previously playing track */ |
| 834 | amount = tracks[old_track_ridx].filesize - ci.curpos; |
| 835 | /* Then collect all data from tracks in between them */ |
| 836 | amount += buffer_count_tracks(old_track_ridx, new_track_ridx); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 837 | |
Brandon Low | 7c986a9 | 2006-04-14 17:31:19 +0000 | [diff] [blame] | 838 | if (amount > filebufused) |
| 839 | return false; |
| 840 | |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 841 | logf("bwf:%ldB",amount); |
| 842 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 843 | /* Wind the buffer to the beginning of the target track or its codec */ |
| 844 | buf_ridx += amount; |
| 845 | filebufused -= amount; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 846 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 847 | /* Check and handle buffer wrapping */ |
| 848 | if (buf_ridx >= filebuflen) |
| 849 | buf_ridx -= filebuflen; |
| 850 | |
| 851 | return true; |
| 852 | } |
| 853 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 854 | static bool buffer_wind_backward(int new_track_ridx, int old_track_ridx) |
| 855 | { |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 856 | /* Available buffer data */ |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 857 | size_t buf_back; |
| 858 | /* Start with the previously playing track's data and our data */ |
| 859 | size_t amount; |
| 860 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 861 | buf_back = buf_ridx; |
| 862 | amount = ci.curpos; |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 863 | if (buf_ridx < buf_widx) |
| 864 | buf_back += filebuflen; |
| 865 | buf_back -= buf_widx; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 866 | |
Brandon Low | 0744e76 | 2006-04-13 17:30:54 +0000 | [diff] [blame] | 867 | /* If we're not just resetting the current track */ |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 868 | if (new_track_ridx != old_track_ridx) |
| 869 | { |
| 870 | /* Need to wind to before the old track's codec and our filesize */ |
| 871 | amount += tracks[old_track_ridx].codecsize; |
| 872 | amount += tracks[new_track_ridx].filesize; |
| 873 | |
| 874 | /* Rewind the old track to its beginning */ |
| 875 | tracks[old_track_ridx].available = |
| 876 | tracks[old_track_ridx].filesize - tracks[old_track_ridx].filerem; |
| 877 | } |
| 878 | |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 879 | /* If the codec was ever buffered */ |
| 880 | if (tracks[new_track_ridx].codecsize) |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 881 | { |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 882 | /* Add the codec to the needed size */ |
| 883 | amount += tracks[new_track_ridx].codecsize; |
| 884 | tracks[new_track_ridx].has_codec = true; |
| 885 | } |
| 886 | |
| 887 | /* Then collect all data from tracks between new and old */ |
| 888 | amount += buffer_count_tracks(new_track_ridx, old_track_ridx); |
| 889 | |
| 890 | /* Do we have space to make this skip? */ |
| 891 | if (amount > buf_back) |
| 892 | return false; |
| 893 | |
Brandon Low | 0744e76 | 2006-04-13 17:30:54 +0000 | [diff] [blame] | 894 | logf("bwb:%ldB",amount); |
| 895 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 896 | /* Check and handle buffer wrapping */ |
| 897 | if (amount > buf_ridx) |
| 898 | buf_ridx += filebuflen; |
| 899 | /* Rewind the buffer to the beginning of the target track or its codec */ |
| 900 | buf_ridx -= amount; |
| 901 | filebufused += amount; |
| 902 | |
| 903 | /* Reset to the beginning of the new track */ |
| 904 | tracks[new_track_ridx].available = tracks[new_track_ridx].filesize; |
| 905 | |
| 906 | return true; |
| 907 | } |
| 908 | |
Brandon Low | 1d41f77 | 2006-04-13 21:47:00 +0000 | [diff] [blame] | 909 | static void audio_update_trackinfo(void) |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 910 | { |
Brandon Low | 1d41f77 | 2006-04-13 21:47:00 +0000 | [diff] [blame] | 911 | ci.filesize = cur_ti->filesize; |
| 912 | cur_ti->id3.elapsed = 0; |
| 913 | cur_ti->id3.offset = 0; |
| 914 | ci.id3 = &cur_ti->id3; |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 915 | ci.curpos = 0; |
Brandon Low | 1d41f77 | 2006-04-13 21:47:00 +0000 | [diff] [blame] | 916 | ci.taginfo_ready = &cur_ti->taginfo_ready; |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 917 | } |
| 918 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 919 | static void audio_rebuffer(void) |
| 920 | { |
| 921 | logf("Forcing rebuffer"); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 922 | |
Brandon Low | 4b36096 | 2006-04-19 00:23:08 +0000 | [diff] [blame] | 923 | /* Notify the codec that this will take a while */ |
Miika Pekkarinen | 513cafe | 2006-07-31 06:12:53 +0000 | [diff] [blame] | 924 | /* Currently this can cause some problems (logf in reverse order): |
| 925 | * Codec load error:-1 |
| 926 | * Codec load disk |
| 927 | * Codec: Unsupported |
| 928 | * Codec finished |
| 929 | * New codec:0/3 |
| 930 | * Clearing tracks:7/7, 1 |
| 931 | * Forcing rebuffer |
| 932 | * Check new track buffer |
| 933 | * Request new track |
| 934 | * Clearing tracks:5/5, 0 |
| 935 | * Starting buffer fill |
| 936 | * Clearing tracks:5/5, 1 |
| 937 | * Re-buffering song w/seek |
| 938 | */ |
| 939 | //if (!filling) |
| 940 | // queue_post(&codec_callback_queue, Q_CODEC_REQUEST_PENDING, 0); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 941 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 942 | /* Stop in progress fill, and clear open file descriptor */ |
Miika Pekkarinen | 4ccacd4 | 2006-07-29 19:34:12 +0000 | [diff] [blame] | 943 | if (current_fd >= 0) |
| 944 | { |
| 945 | close(current_fd); |
| 946 | current_fd = -1; |
| 947 | } |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 948 | filling = false; |
| 949 | |
| 950 | /* Reset buffer and track pointers */ |
| 951 | buf_ridx = buf_widx = 0; |
Miika Pekkarinen | 4ccacd4 | 2006-07-29 19:34:12 +0000 | [diff] [blame] | 952 | track_widx = track_ridx; |
Miika Pekkarinen | 513cafe | 2006-07-31 06:12:53 +0000 | [diff] [blame] | 953 | cur_ti = &tracks[track_ridx]; |
Miika Pekkarinen | bb5330c | 2006-08-03 07:45:53 +0000 | [diff] [blame] | 954 | audio_clear_track_entries(true, true, false); |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 955 | filebufused = 0; |
| 956 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 957 | /* Fill the buffer */ |
| 958 | last_peek_offset = -1; |
Brandon Low | 54af304 | 2006-04-12 02:01:26 +0000 | [diff] [blame] | 959 | cur_ti->filesize = 0; |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 960 | cur_ti->start_pos = 0; |
Miika Pekkarinen | 4ccacd4 | 2006-07-29 19:34:12 +0000 | [diff] [blame] | 961 | ci.curpos = 0; |
Hardeep Sidhu | c9a11cd | 2006-05-15 01:45:35 +0000 | [diff] [blame] | 962 | |
| 963 | if (!cur_ti->taginfo_ready) |
| 964 | memset(&cur_ti->id3, 0, sizeof(struct mp3entry)); |
| 965 | |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 966 | audio_fill_file_buffer(false, true, 0); |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 967 | } |
| 968 | |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 969 | static void audio_check_new_track(void) |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 970 | { |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 971 | int track_count = audio_track_count(); |
| 972 | int old_track_ridx = track_ridx; |
Brandon Low | 2f11d60 | 2006-04-14 03:47:32 +0000 | [diff] [blame] | 973 | bool forward; |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 974 | |
Brandon Low | 2b18727 | 2006-04-18 18:33:09 +0000 | [diff] [blame] | 975 | if (dir_skip) |
| 976 | { |
| 977 | dir_skip = false; |
| 978 | if (playlist_next_dir(ci.new_track)) |
| 979 | { |
| 980 | ci.new_track = 0; |
| 981 | cur_ti->taginfo_ready = false; |
| 982 | audio_rebuffer(); |
| 983 | goto skip_done; |
| 984 | } |
| 985 | else |
| 986 | { |
| 987 | queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0); |
| 988 | return; |
| 989 | } |
| 990 | } |
| 991 | |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 992 | if (new_playlist) |
| 993 | ci.new_track = 0; |
| 994 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 995 | /* If the playlist isn't that big */ |
Brandon Low | ebadcc6 | 2006-04-15 02:03:11 +0000 | [diff] [blame] | 996 | if (!playlist_check(ci.new_track)) |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 997 | { |
Brandon Low | ebadcc6 | 2006-04-15 02:03:11 +0000 | [diff] [blame] | 998 | if (ci.new_track >= 0) |
Brandon Low | fb966b3 | 2006-04-14 14:19:56 +0000 | [diff] [blame] | 999 | { |
Brandon Low | 0291a6e | 2006-04-14 14:03:43 +0000 | [diff] [blame] | 1000 | queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0); |
Brandon Low | fb966b3 | 2006-04-14 14:19:56 +0000 | [diff] [blame] | 1001 | return; |
| 1002 | } |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1003 | /* Find the beginning backward if the user over-skips it */ |
Brandon Low | ebadcc6 | 2006-04-15 02:03:11 +0000 | [diff] [blame] | 1004 | while (!playlist_check(++ci.new_track)) |
| 1005 | if (ci.new_track >= 0) |
Brandon Low | fb966b3 | 2006-04-14 14:19:56 +0000 | [diff] [blame] | 1006 | { |
Brandon Low | 0291a6e | 2006-04-14 14:03:43 +0000 | [diff] [blame] | 1007 | queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0); |
Brandon Low | fb966b3 | 2006-04-14 14:19:56 +0000 | [diff] [blame] | 1008 | return; |
| 1009 | } |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1010 | } |
| 1011 | /* Update the playlist */ |
Brandon Low | ebadcc6 | 2006-04-15 02:03:11 +0000 | [diff] [blame] | 1012 | last_peek_offset -= ci.new_track; |
Hardeep Sidhu | 1e0b1d5 | 2006-06-07 20:43:34 +0000 | [diff] [blame] | 1013 | |
| 1014 | if (playlist_next(ci.new_track) < 0) |
| 1015 | { |
| 1016 | queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0); |
| 1017 | return; |
| 1018 | } |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1019 | |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 1020 | if (new_playlist) |
Brandon Low | 69cf4f5 | 2006-04-26 04:31:06 +0000 | [diff] [blame] | 1021 | { |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 1022 | ci.new_track = 1; |
Brandon Low | 69cf4f5 | 2006-04-26 04:31:06 +0000 | [diff] [blame] | 1023 | new_playlist = false; |
| 1024 | } |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 1025 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1026 | track_ridx += ci.new_track; |
| 1027 | track_ridx &= MAX_TRACK_MASK; |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1028 | |
Brandon Low | 0744e76 | 2006-04-13 17:30:54 +0000 | [diff] [blame] | 1029 | /* Save the old track */ |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1030 | prev_ti = cur_ti; |
Brandon Low | 0744e76 | 2006-04-13 17:30:54 +0000 | [diff] [blame] | 1031 | /* Move to the new track */ |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1032 | cur_ti = &tracks[track_ridx]; |
| 1033 | |
Hardeep Sidhu | 5483da6 | 2006-06-03 17:23:20 +0000 | [diff] [blame] | 1034 | if (automatic_skip) |
| 1035 | playlist_end = false; |
| 1036 | |
Brandon Low | 5cdee94 | 2006-04-23 22:30:52 +0000 | [diff] [blame] | 1037 | track_changed = !automatic_skip; |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1038 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1039 | /* If it is not safe to even skip this many track entries */ |
Brandon Low | ebadcc6 | 2006-04-15 02:03:11 +0000 | [diff] [blame] | 1040 | if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK) |
Brandon Low | fbe74d1 | 2006-04-14 12:53:29 +0000 | [diff] [blame] | 1041 | { |
Brandon Low | 4564f5c | 2006-04-26 12:19:16 +0000 | [diff] [blame] | 1042 | ci.new_track = 0; |
Brandon Low | fbe74d1 | 2006-04-14 12:53:29 +0000 | [diff] [blame] | 1043 | cur_ti->taginfo_ready = false; |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1044 | audio_rebuffer(); |
Brandon Low | 2b18727 | 2006-04-18 18:33:09 +0000 | [diff] [blame] | 1045 | goto skip_done; |
Brandon Low | fbe74d1 | 2006-04-14 12:53:29 +0000 | [diff] [blame] | 1046 | } |
Brandon Low | 2b18727 | 2006-04-18 18:33:09 +0000 | [diff] [blame] | 1047 | |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 1048 | forward = ci.new_track > 0; |
| 1049 | ci.new_track = 0; |
| 1050 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1051 | /* If the target track is clearly not in memory */ |
Brandon Low | 2b18727 | 2006-04-18 18:33:09 +0000 | [diff] [blame] | 1052 | if (cur_ti->filesize == 0 || !cur_ti->taginfo_ready) |
| 1053 | { |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1054 | audio_rebuffer(); |
Brandon Low | 2b18727 | 2006-04-18 18:33:09 +0000 | [diff] [blame] | 1055 | goto skip_done; |
| 1056 | } |
| 1057 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1058 | /* The track may be in memory, see if it really is */ |
Brandon Low | 2b18727 | 2006-04-18 18:33:09 +0000 | [diff] [blame] | 1059 | if (forward) |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1060 | { |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 1061 | if (!buffer_wind_forward(track_ridx, old_track_ridx)) |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1062 | audio_rebuffer(); |
| 1063 | } |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1064 | else |
| 1065 | { |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1066 | int cur_idx = track_ridx; |
| 1067 | bool taginfo_ready = true; |
| 1068 | bool wrap = track_ridx > old_track_ridx; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1069 | |
| 1070 | while (1) |
| 1071 | { |
| 1072 | cur_idx++; |
| 1073 | cur_idx &= MAX_TRACK_MASK; |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1074 | if (!(wrap || cur_idx < old_track_ridx)) |
| 1075 | break; |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1076 | |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1077 | /* If we hit a track in between without valid tag info, bail */ |
| 1078 | if (!tracks[cur_idx].taginfo_ready) |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1079 | { |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1080 | taginfo_ready = false; |
| 1081 | break; |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1082 | } |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1083 | |
| 1084 | tracks[cur_idx].available = tracks[cur_idx].filesize; |
| 1085 | if (tracks[cur_idx].codecsize) |
| 1086 | tracks[cur_idx].has_codec = true; |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1087 | } |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1088 | if (taginfo_ready) |
| 1089 | { |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 1090 | if (!buffer_wind_backward(track_ridx, old_track_ridx)) |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1091 | audio_rebuffer(); |
| 1092 | } |
| 1093 | else |
| 1094 | { |
Brandon Low | 0744e76 | 2006-04-13 17:30:54 +0000 | [diff] [blame] | 1095 | cur_ti->taginfo_ready = false; |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1096 | audio_rebuffer(); |
| 1097 | } |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1098 | } |
Brandon Low | c95044a | 2006-04-13 14:17:12 +0000 | [diff] [blame] | 1099 | |
Brandon Low | 2b18727 | 2006-04-18 18:33:09 +0000 | [diff] [blame] | 1100 | skip_done: |
Brandon Low | 1d41f77 | 2006-04-13 21:47:00 +0000 | [diff] [blame] | 1101 | audio_update_trackinfo(); |
Brandon Low | fd08424 | 2006-04-14 13:05:08 +0000 | [diff] [blame] | 1102 | queue_post(&codec_callback_queue, Q_CODEC_REQUEST_COMPLETE, 0); |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1103 | } |
| 1104 | |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 1105 | static void rebuffer_and_seek(size_t newpos) |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1106 | { |
| 1107 | int fd; |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1108 | char *trackname; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1109 | |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1110 | trackname = playlist_peek(0); |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1111 | /* (Re-)open current track's file handle. */ |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1112 | |
| 1113 | fd = open(trackname, O_RDONLY); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1114 | if (fd < 0) |
| 1115 | { |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1116 | logf("Open failed!"); |
Brandon Low | 0291a6e | 2006-04-14 14:03:43 +0000 | [diff] [blame] | 1117 | queue_post(&codec_callback_queue, Q_CODEC_REQUEST_FAILED, 0); |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 1118 | return; |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1119 | } |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1120 | |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1121 | if (current_fd >= 0) |
| 1122 | close(current_fd); |
| 1123 | current_fd = fd; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1124 | |
Miika Pekkarinen | 999f89c | 2005-12-03 12:14:26 +0000 | [diff] [blame] | 1125 | playlist_end = false; |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1126 | |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1127 | ci.curpos = newpos; |
| 1128 | |
| 1129 | /* Clear codec buffer. */ |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1130 | track_widx = track_ridx; |
Miika Pekkarinen | 513cafe | 2006-07-31 06:12:53 +0000 | [diff] [blame] | 1131 | filebufused = 0; |
| 1132 | buf_widx = buf_ridx = 0; |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1133 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1134 | last_peek_offset = 0; |
Miika Pekkarinen | 513cafe | 2006-07-31 06:12:53 +0000 | [diff] [blame] | 1135 | filling = false; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1136 | initialize_buffer_fill(true); |
Brandon Low | 01219fa | 2006-04-11 17:08:11 +0000 | [diff] [blame] | 1137 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1138 | if (newpos > AUDIO_REBUFFER_GUESS_SIZE) |
| 1139 | { |
Dave Chapman | b1a272e | 2006-07-03 21:23:14 +0000 | [diff] [blame] | 1140 | buf_ridx += AUDIO_REBUFFER_GUESS_SIZE; |
Brandon Low | 01219fa | 2006-04-11 17:08:11 +0000 | [diff] [blame] | 1141 | cur_ti->start_pos = newpos - AUDIO_REBUFFER_GUESS_SIZE; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1142 | } |
| 1143 | else |
| 1144 | { |
Mark Arigo | 50f7e4e | 2006-07-18 21:10:13 +0000 | [diff] [blame] | 1145 | buf_ridx += newpos; |
Brandon Low | 01219fa | 2006-04-11 17:08:11 +0000 | [diff] [blame] | 1146 | cur_ti->start_pos = 0; |
Dave Chapman | b1a272e | 2006-07-03 21:23:14 +0000 | [diff] [blame] | 1147 | } |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1148 | |
| 1149 | cur_ti->filerem = cur_ti->filesize - cur_ti->start_pos; |
| 1150 | cur_ti->available = 0; |
| 1151 | |
| 1152 | lseek(current_fd, cur_ti->start_pos, SEEK_SET); |
| 1153 | |
Brandon Low | fd08424 | 2006-04-14 13:05:08 +0000 | [diff] [blame] | 1154 | queue_post(&codec_callback_queue, Q_CODEC_REQUEST_COMPLETE, 0); |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1155 | } |
| 1156 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1157 | static void voice_advance_buffer_callback(size_t amount) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1158 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1159 | amount = MIN(amount, voice_remaining); |
| 1160 | voicebuf += amount; |
| 1161 | voice_remaining -= amount; |
| 1162 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1163 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1164 | static void codec_advance_buffer_callback(size_t amount) |
| 1165 | { |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1166 | if (amount > cur_ti->available + cur_ti->filerem) |
Miika Pekkarinen | 5899ed5 | 2005-06-08 10:33:01 +0000 | [diff] [blame] | 1167 | amount = cur_ti->available + cur_ti->filerem; |
Miika Pekkarinen | 59e0ccb | 2005-12-01 19:38:08 +0000 | [diff] [blame] | 1168 | |
| 1169 | while (amount > cur_ti->available && filling) |
| 1170 | sleep(1); |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1171 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1172 | if (amount > cur_ti->available) |
| 1173 | { |
Brandon Low | fd08424 | 2006-04-14 13:05:08 +0000 | [diff] [blame] | 1174 | struct event ev; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1175 | |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 1176 | queue_post(&audio_queue, |
| 1177 | Q_AUDIO_REBUFFER_SEEK, (void *)(ci.curpos + amount)); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1178 | |
Brandon Low | fd08424 | 2006-04-14 13:05:08 +0000 | [diff] [blame] | 1179 | queue_wait(&codec_callback_queue, &ev); |
Brandon Low | 0291a6e | 2006-04-14 14:03:43 +0000 | [diff] [blame] | 1180 | switch (ev.id) |
| 1181 | { |
| 1182 | case Q_CODEC_REQUEST_FAILED: |
| 1183 | ci.stop_codec = true; |
| 1184 | case Q_CODEC_REQUEST_COMPLETE: |
| 1185 | return; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1186 | |
Brandon Low | 0291a6e | 2006-04-14 14:03:43 +0000 | [diff] [blame] | 1187 | default: |
| 1188 | logf("Bad event on ccq"); |
| 1189 | ci.stop_codec = true; |
| 1190 | return; |
| 1191 | } |
Miika Pekkarinen | 5899ed5 | 2005-06-08 10:33:01 +0000 | [diff] [blame] | 1192 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1193 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 1194 | advance_buffer_counters(amount); |
| 1195 | |
Ryan Jackson | d191756 | 2005-07-12 16:45:38 +0000 | [diff] [blame] | 1196 | codec_set_offset_callback(ci.curpos); |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1197 | } |
| 1198 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1199 | static void voice_advance_buffer_loc_callback(void *ptr) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1200 | { |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1201 | size_t amount = (size_t)ptr - (size_t)voicebuf; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1202 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1203 | voice_advance_buffer_callback(amount); |
| 1204 | } |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1205 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1206 | static void codec_advance_buffer_loc_callback(void *ptr) |
| 1207 | { |
| 1208 | size_t amount = (size_t)ptr - (size_t)&filebuf[buf_ridx]; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1209 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1210 | codec_advance_buffer_callback(amount); |
| 1211 | } |
| 1212 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1213 | static off_t voice_mp3_get_filepos_callback(int newtime) |
| 1214 | { |
| 1215 | (void)newtime; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1216 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1217 | return 0; |
| 1218 | } |
| 1219 | |
| 1220 | static off_t codec_mp3_get_filepos_callback(int newtime) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1221 | { |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1222 | off_t newpos; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1223 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1224 | cur_ti->id3.elapsed = newtime; |
Miika Pekkarinen | 82c2927 | 2005-06-07 06:34:54 +0000 | [diff] [blame] | 1225 | newpos = mp3_get_file_pos(); |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1226 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1227 | return newpos; |
| 1228 | } |
| 1229 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1230 | static void voice_do_nothing(void) |
| 1231 | { |
| 1232 | return; |
| 1233 | } |
| 1234 | |
| 1235 | static void codec_seek_complete_callback(void) |
Miika Pekkarinen | 8a7d104 | 2005-08-21 18:12:31 +0000 | [diff] [blame] | 1236 | { |
Brandon Low | 502fbd7 | 2006-04-08 12:58:39 +0000 | [diff] [blame] | 1237 | logf("seek_complete"); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1238 | if (pcm_is_paused()) |
| 1239 | { |
Brandon Low | 502fbd7 | 2006-04-08 12:58:39 +0000 | [diff] [blame] | 1240 | /* If this is not a seamless seek, clear the buffer */ |
| 1241 | pcmbuf_play_stop(); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1242 | |
Brandon Low | 502fbd7 | 2006-04-08 12:58:39 +0000 | [diff] [blame] | 1243 | /* If playback was not 'deliberately' paused, unpause now */ |
| 1244 | if (!paused) |
| 1245 | pcmbuf_pause(false); |
| 1246 | } |
Brandon Low | 1344ccd | 2006-04-18 19:51:37 +0000 | [diff] [blame] | 1247 | ci.seek_time = 0; |
Miika Pekkarinen | 8a7d104 | 2005-08-21 18:12:31 +0000 | [diff] [blame] | 1248 | } |
| 1249 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1250 | static bool voice_seek_buffer_callback(size_t newpos) |
| 1251 | { |
| 1252 | (void)newpos; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1253 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1254 | return false; |
| 1255 | } |
| 1256 | |
| 1257 | static bool codec_seek_buffer_callback(size_t newpos) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1258 | { |
| 1259 | int difference; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1260 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1261 | if (newpos >= cur_ti->filesize) |
| 1262 | newpos = cur_ti->filesize - 1; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1263 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1264 | difference = newpos - ci.curpos; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1265 | if (difference >= 0) |
| 1266 | { |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1267 | /* Seeking forward */ |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1268 | logf("seek: +%d", difference); |
| 1269 | codec_advance_buffer_callback(difference); |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1270 | return true; |
| 1271 | } |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1272 | |
| 1273 | /* Seeking backward */ |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1274 | difference = -difference; |
| 1275 | if (ci.curpos - difference < 0) |
| 1276 | difference = ci.curpos; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1277 | |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1278 | /* We need to reload the song. */ |
| 1279 | if (newpos < cur_ti->start_pos) |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 1280 | { |
Brandon Low | fd08424 | 2006-04-14 13:05:08 +0000 | [diff] [blame] | 1281 | struct event ev; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1282 | |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 1283 | queue_post(&audio_queue, Q_AUDIO_REBUFFER_SEEK, (void *)newpos); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1284 | |
Brandon Low | fd08424 | 2006-04-14 13:05:08 +0000 | [diff] [blame] | 1285 | queue_wait(&codec_callback_queue, &ev); |
Brandon Low | 0291a6e | 2006-04-14 14:03:43 +0000 | [diff] [blame] | 1286 | switch (ev.id) |
| 1287 | { |
| 1288 | case Q_CODEC_REQUEST_COMPLETE: |
| 1289 | return true; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1290 | |
Brandon Low | 0291a6e | 2006-04-14 14:03:43 +0000 | [diff] [blame] | 1291 | case Q_CODEC_REQUEST_FAILED: |
| 1292 | ci.stop_codec = true; |
| 1293 | return false; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1294 | |
Brandon Low | 0291a6e | 2006-04-14 14:03:43 +0000 | [diff] [blame] | 1295 | default: |
| 1296 | logf("Bad event on ccq"); |
| 1297 | return false; |
| 1298 | } |
Brandon Low | 72232bd | 2006-04-09 02:15:35 +0000 | [diff] [blame] | 1299 | } |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1300 | |
| 1301 | /* Seeking inside buffer space. */ |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1302 | logf("seek: -%d", difference); |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1303 | filebufused += difference; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1304 | cur_ti->available += difference; |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 1305 | if (buf_ridx < (unsigned)difference) |
| 1306 | buf_ridx += filebuflen; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1307 | buf_ridx -= difference; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1308 | ci.curpos -= difference; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1309 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1310 | return true; |
| 1311 | } |
| 1312 | |
Miika Pekkarinen | f090dc3 | 2005-07-21 11:44:00 +0000 | [diff] [blame] | 1313 | static void set_filebuf_watermark(int seconds) |
| 1314 | { |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 1315 | size_t bytes; |
Miika Pekkarinen | f090dc3 | 2005-07-21 11:44:00 +0000 | [diff] [blame] | 1316 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1317 | if (current_codec == CODEC_IDX_VOICE) |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1318 | return; |
Magnus Holmgren | 62634a3 | 2005-10-16 08:01:02 +0000 | [diff] [blame] | 1319 | |
| 1320 | if (!filebuf) |
| 1321 | return; /* Audio buffers not yet set up */ |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1322 | |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 1323 | bytes = MAX(cur_ti->id3.bitrate * seconds * (1000/8), conf_watermark); |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1324 | bytes = MIN(bytes, filebuflen / 2); |
Miika Pekkarinen | f090dc3 | 2005-07-21 11:44:00 +0000 | [diff] [blame] | 1325 | conf_watermark = bytes; |
| 1326 | } |
| 1327 | |
Miika Pekkarinen | 6a4bfb5 | 2005-12-01 18:44:11 +0000 | [diff] [blame] | 1328 | static void codec_configure_callback(int setting, void *value) |
Miika Pekkarinen | 68b9acd | 2005-06-10 15:02:10 +0000 | [diff] [blame] | 1329 | { |
| 1330 | switch (setting) { |
| 1331 | case CODEC_SET_FILEBUF_WATERMARK: |
Thom Johansen | e2824c9 | 2006-03-22 16:04:51 +0000 | [diff] [blame] | 1332 | conf_watermark = (unsigned long)value; |
Miika Pekkarinen | f090dc3 | 2005-07-21 11:44:00 +0000 | [diff] [blame] | 1333 | set_filebuf_watermark(buffer_margin); |
Miika Pekkarinen | 68b9acd | 2005-06-10 15:02:10 +0000 | [diff] [blame] | 1334 | break; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1335 | |
Miika Pekkarinen | 68b9acd | 2005-06-10 15:02:10 +0000 | [diff] [blame] | 1336 | case CODEC_SET_FILEBUF_CHUNKSIZE: |
Thom Johansen | e2824c9 | 2006-03-22 16:04:51 +0000 | [diff] [blame] | 1337 | conf_filechunk = (unsigned long)value; |
Miika Pekkarinen | 68b9acd | 2005-06-10 15:02:10 +0000 | [diff] [blame] | 1338 | break; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1339 | |
Miika Pekkarinen | 68b9acd | 2005-06-10 15:02:10 +0000 | [diff] [blame] | 1340 | default: |
Brandon Low | 87484fc | 2006-04-11 20:41:04 +0000 | [diff] [blame] | 1341 | if (!dsp_configure(setting, value)) { logf("Illegal key:%d", setting); } |
Miika Pekkarinen | 68b9acd | 2005-06-10 15:02:10 +0000 | [diff] [blame] | 1342 | } |
| 1343 | } |
| 1344 | |
Miika Pekkarinen | d54811f | 2005-07-02 16:52:30 +0000 | [diff] [blame] | 1345 | void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3, |
| 1346 | bool last_track)) |
| 1347 | { |
| 1348 | track_buffer_callback = handler; |
| 1349 | } |
| 1350 | |
| 1351 | void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3, |
Miika Pekkarinen | 9bde038 | 2005-07-03 18:36:24 +0000 | [diff] [blame] | 1352 | bool last_track)) |
Miika Pekkarinen | d54811f | 2005-07-02 16:52:30 +0000 | [diff] [blame] | 1353 | { |
| 1354 | track_unbuffer_callback = handler; |
| 1355 | } |
| 1356 | |
Jens Arnold | a88d076 | 2005-08-18 06:05:15 +0000 | [diff] [blame] | 1357 | void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)) |
Miika Pekkarinen | 7d6d122 | 2005-06-29 21:36:30 +0000 | [diff] [blame] | 1358 | { |
| 1359 | track_changed_callback = handler; |
| 1360 | } |
| 1361 | |
Miika Pekkarinen | 6a4bfb5 | 2005-12-01 18:44:11 +0000 | [diff] [blame] | 1362 | static void codec_track_changed(void) |
Miika Pekkarinen | c3fed62 | 2005-06-15 18:59:04 +0000 | [diff] [blame] | 1363 | { |
Brandon Low | 5cdee94 | 2006-04-23 22:30:52 +0000 | [diff] [blame] | 1364 | automatic_skip = false; |
Miika Pekkarinen | c3fed62 | 2005-06-15 18:59:04 +0000 | [diff] [blame] | 1365 | track_changed = true; |
Miika Pekkarinen | d319116 | 2006-01-27 11:39:46 +0000 | [diff] [blame] | 1366 | queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0); |
Miika Pekkarinen | c3fed62 | 2005-06-15 18:59:04 +0000 | [diff] [blame] | 1367 | } |
| 1368 | |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 1369 | static void pcmbuf_track_changed_callback(void) |
| 1370 | { |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 1371 | pcmbuf_set_position_callback(NULL); |
Brandon Low | 5cdee94 | 2006-04-23 22:30:52 +0000 | [diff] [blame] | 1372 | codec_track_changed(); |
Brandon Low | 413da2a | 2006-02-07 20:38:55 +0000 | [diff] [blame] | 1373 | } |
| 1374 | |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1375 | /* Yield to codecs for as long as possible if they are in need of data |
| 1376 | * return true if the caller should break to let the audio thread process |
| 1377 | * new events */ |
| 1378 | static bool yield_codecs(void) |
Miika Pekkarinen | 82c2927 | 2005-06-07 06:34:54 +0000 | [diff] [blame] | 1379 | { |
Miika Pekkarinen | 61716dd | 2005-06-07 18:03:33 +0000 | [diff] [blame] | 1380 | yield(); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1381 | |
Brandon Low | 29f7dd3 | 2006-04-07 21:32:30 +0000 | [diff] [blame] | 1382 | if (!queue_empty(&audio_queue)) return true; |
Brandon Low | 2736363 | 2006-04-06 21:06:37 +0000 | [diff] [blame] | 1383 | |
Miika Pekkarinen | 20b3897 | 2005-07-13 12:48:22 +0000 | [diff] [blame] | 1384 | while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata()) |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1385 | && !ci.stop_codec && playing && !filebuf_is_lowdata()) |
| 1386 | { |
Miika Pekkarinen | b142a58 | 2005-10-30 08:51:47 +0000 | [diff] [blame] | 1387 | sleep(1); |
Brandon Low | 29f7dd3 | 2006-04-07 21:32:30 +0000 | [diff] [blame] | 1388 | if (!queue_empty(&audio_queue)) return true; |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1389 | } |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1390 | |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1391 | return false; |
Miika Pekkarinen | 82c2927 | 2005-06-07 06:34:54 +0000 | [diff] [blame] | 1392 | } |
| 1393 | |
Linus Nielsen Feltzing | df80798 | 2005-07-07 09:53:02 +0000 | [diff] [blame] | 1394 | /* FIXME: This code should be made more generic and move to metadata.c */ |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 1395 | static void strip_id3v1_tag(void) |
Linus Nielsen Feltzing | df80798 | 2005-07-07 09:53:02 +0000 | [diff] [blame] | 1396 | { |
| 1397 | int i; |
| 1398 | static const unsigned char tag[] = "TAG"; |
Brandon Low | 2f4edab | 2006-04-14 04:42:11 +0000 | [diff] [blame] | 1399 | size_t tag_idx; |
| 1400 | size_t cur_idx; |
Linus Nielsen Feltzing | df80798 | 2005-07-07 09:53:02 +0000 | [diff] [blame] | 1401 | |
Brandon Low | 2f4edab | 2006-04-14 04:42:11 +0000 | [diff] [blame] | 1402 | tag_idx = buf_widx; |
| 1403 | if (tag_idx < 128) |
| 1404 | tag_idx += filebuflen; |
| 1405 | tag_idx -= 128; |
| 1406 | |
| 1407 | if (filebufused > 128 && tag_idx > buf_ridx) |
Linus Nielsen Feltzing | df80798 | 2005-07-07 09:53:02 +0000 | [diff] [blame] | 1408 | { |
Brandon Low | 2f4edab | 2006-04-14 04:42:11 +0000 | [diff] [blame] | 1409 | cur_idx = tag_idx; |
Linus Nielsen Feltzing | df80798 | 2005-07-07 09:53:02 +0000 | [diff] [blame] | 1410 | for(i = 0;i < 3;i++) |
| 1411 | { |
Brandon Low | 2f4edab | 2006-04-14 04:42:11 +0000 | [diff] [blame] | 1412 | if(filebuf[cur_idx] != tag[i]) |
| 1413 | return; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1414 | |
Brandon Low | 2f4edab | 2006-04-14 04:42:11 +0000 | [diff] [blame] | 1415 | if(++cur_idx >= filebuflen) |
| 1416 | cur_idx -= filebuflen; |
Linus Nielsen Feltzing | df80798 | 2005-07-07 09:53:02 +0000 | [diff] [blame] | 1417 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1418 | |
Brandon Low | 2f4edab | 2006-04-14 04:42:11 +0000 | [diff] [blame] | 1419 | /* Skip id3v1 tag */ |
| 1420 | logf("Skipping ID3v1 tag"); |
| 1421 | buf_widx = tag_idx; |
| 1422 | tracks[track_widx].available -= 128; |
| 1423 | tracks[track_widx].filesize -= 128; |
| 1424 | filebufused -= 128; |
Linus Nielsen Feltzing | df80798 | 2005-07-07 09:53:02 +0000 | [diff] [blame] | 1425 | } |
| 1426 | } |
| 1427 | |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 1428 | static void audio_read_file(bool quick) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1429 | { |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 1430 | size_t copy_n; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1431 | int rc; |
Miika Pekkarinen | bbd42ad | 2005-07-01 18:22:04 +0000 | [diff] [blame] | 1432 | |
Brandon Low | de60231 | 2006-04-07 16:31:20 +0000 | [diff] [blame] | 1433 | /* If we're called and no file is open, this is an error */ |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1434 | if (current_fd < 0) |
| 1435 | { |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 1436 | logf("Bad fd in arf"); |
Brandon Low | de60231 | 2006-04-07 16:31:20 +0000 | [diff] [blame] | 1437 | /* Stop this buffer cycle immediately */ |
| 1438 | fill_bytesleft = 0; |
| 1439 | /* Give some hope of miraculous recovery by forcing a track reload */ |
| 1440 | tracks[track_widx].filesize = 0; |
Miika Pekkarinen | 431e813 | 2005-06-19 18:41:53 +0000 | [diff] [blame] | 1441 | return ; |
Brandon Low | de60231 | 2006-04-07 16:31:20 +0000 | [diff] [blame] | 1442 | } |
| 1443 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1444 | while (tracks[track_widx].filerem > 0) |
| 1445 | { |
Brandon Low | b660745 | 2006-04-11 14:13:41 +0000 | [diff] [blame] | 1446 | if (fill_bytesleft == 0) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1447 | break ; |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1448 | |
| 1449 | /* copy_n is the largest chunk that is safe to read */ |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 1450 | copy_n = MIN(conf_filechunk, filebuflen - buf_widx); |
| 1451 | copy_n = MIN(copy_n, fill_bytesleft); |
Brandon Low | 7c986a9 | 2006-04-14 17:31:19 +0000 | [diff] [blame] | 1452 | |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1453 | /* rc is the actual amount read */ |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 1454 | rc = read(current_fd, &filebuf[buf_widx], copy_n); |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1455 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1456 | if (rc <= 0) |
| 1457 | { |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1458 | /* Reached the end of the file */ |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1459 | tracks[track_widx].filerem = 0; |
| 1460 | break ; |
| 1461 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1462 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1463 | buf_widx += rc; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1464 | if (buf_widx >= filebuflen) |
| 1465 | buf_widx -= filebuflen; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1466 | tracks[track_widx].available += rc; |
Miika Pekkarinen | 3eb962d | 2005-07-07 07:15:05 +0000 | [diff] [blame] | 1467 | tracks[track_widx].filerem -= rc; |
Brandon Low | b660745 | 2006-04-11 14:13:41 +0000 | [diff] [blame] | 1468 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1469 | filebufused += rc; |
Brandon Low | b660745 | 2006-04-11 14:13:41 +0000 | [diff] [blame] | 1470 | if (fill_bytesleft > (unsigned)rc) |
| 1471 | fill_bytesleft -= rc; |
| 1472 | else |
| 1473 | fill_bytesleft = 0; |
Brandon Low | 29f7dd3 | 2006-04-07 21:32:30 +0000 | [diff] [blame] | 1474 | |
| 1475 | /* Let the codec process until it is out of the danger zone, or there |
| 1476 | * is an event to handle. In the latter case, break this fill cycle |
| 1477 | * immediately */ |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 1478 | if (quick || yield_codecs()) |
Brandon Low | 29f7dd3 | 2006-04-07 21:32:30 +0000 | [diff] [blame] | 1479 | break; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1480 | } |
Linus Nielsen Feltzing | 27312b2 | 2006-01-18 14:20:34 +0000 | [diff] [blame] | 1481 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1482 | if (tracks[track_widx].filerem == 0) |
| 1483 | { |
Brandon Low | af09d22 | 2006-04-11 23:08:21 +0000 | [diff] [blame] | 1484 | logf("Finished buf:%dB", tracks[track_widx].filesize); |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1485 | close(current_fd); |
| 1486 | current_fd = -1; |
Brandon Low | 017914a | 2006-04-13 20:42:11 +0000 | [diff] [blame] | 1487 | strip_id3v1_tag(); |
| 1488 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1489 | track_widx++; |
| 1490 | track_widx &= MAX_TRACK_MASK; |
Brandon Low | 87484fc | 2006-04-11 20:41:04 +0000 | [diff] [blame] | 1491 | |
Brandon Low | de60231 | 2006-04-07 16:31:20 +0000 | [diff] [blame] | 1492 | tracks[track_widx].filesize = 0; |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1493 | } |
| 1494 | else |
| 1495 | { |
Brandon Low | af09d22 | 2006-04-11 23:08:21 +0000 | [diff] [blame] | 1496 | logf("Partially buf:%dB", |
| 1497 | tracks[track_widx].filesize - tracks[track_widx].filerem); |
| 1498 | } |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1499 | } |
| 1500 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1501 | static void codec_discard_codec_callback(void) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1502 | { |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1503 | if (cur_ti->has_codec) |
| 1504 | { |
Brandon Low | 54af304 | 2006-04-12 02:01:26 +0000 | [diff] [blame] | 1505 | cur_ti->has_codec = false; |
| 1506 | filebufused -= cur_ti->codecsize; |
| 1507 | buf_ridx += cur_ti->codecsize; |
Brandon Low | 3b76544 | 2006-04-11 12:29:46 +0000 | [diff] [blame] | 1508 | if (buf_ridx >= filebuflen) |
| 1509 | buf_ridx -= filebuflen; |
| 1510 | } |
Miika Pekkarinen | 513cafe | 2006-07-31 06:12:53 +0000 | [diff] [blame] | 1511 | |
| 1512 | #if 0 |
| 1513 | /* Check if a buffer desync has happened, log it and stop playback. */ |
Brandon Low | 0744e76 | 2006-04-13 17:30:54 +0000 | [diff] [blame] | 1514 | if (buf_ridx != cur_ti->buf_idx) |
| 1515 | { |
Brandon Low | 1d41f77 | 2006-04-13 21:47:00 +0000 | [diff] [blame] | 1516 | int offset = cur_ti->buf_idx - buf_ridx; |
| 1517 | size_t new_used = filebufused - offset; |
Miika Pekkarinen | 513cafe | 2006-07-31 06:12:53 +0000 | [diff] [blame] | 1518 | |
Brandon Low | 1d41f77 | 2006-04-13 21:47:00 +0000 | [diff] [blame] | 1519 | logf("Buf off :%d=%d-%d", offset, cur_ti->buf_idx, buf_ridx); |
Miika Pekkarinen | 513cafe | 2006-07-31 06:12:53 +0000 | [diff] [blame] | 1520 | logf("Used off:%d",filebufused - new_used); |
| 1521 | |
| 1522 | /* This is a fatal internal error and it's not safe to |
| 1523 | * continue playback. */ |
| 1524 | ci.stop_codec = true; |
| 1525 | queue_post(&audio_queue, Q_AUDIO_STOP, 0); |
Brandon Low | 0744e76 | 2006-04-13 17:30:54 +0000 | [diff] [blame] | 1526 | } |
Miika Pekkarinen | 513cafe | 2006-07-31 06:12:53 +0000 | [diff] [blame] | 1527 | #endif |
Miika Pekkarinen | 6a4bfb5 | 2005-12-01 18:44:11 +0000 | [diff] [blame] | 1528 | } |
| 1529 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1530 | static const char *get_codec_path(int codectype) |
| 1531 | { |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 1532 | switch (codectype) { |
| 1533 | case AFMT_OGG_VORBIS: |
| 1534 | logf("Codec: Vorbis"); |
| 1535 | return CODEC_VORBIS; |
| 1536 | case AFMT_MPA_L1: |
| 1537 | case AFMT_MPA_L2: |
| 1538 | case AFMT_MPA_L3: |
| 1539 | logf("Codec: MPA L1/L2/L3"); |
| 1540 | return CODEC_MPA_L3; |
| 1541 | case AFMT_PCM_WAV: |
| 1542 | logf("Codec: PCM WAV"); |
| 1543 | return CODEC_WAV; |
| 1544 | case AFMT_FLAC: |
| 1545 | logf("Codec: FLAC"); |
| 1546 | return CODEC_FLAC; |
| 1547 | case AFMT_A52: |
| 1548 | logf("Codec: A52"); |
| 1549 | return CODEC_A52; |
| 1550 | case AFMT_MPC: |
| 1551 | logf("Codec: Musepack"); |
| 1552 | return CODEC_MPC; |
| 1553 | case AFMT_WAVPACK: |
| 1554 | logf("Codec: WAVPACK"); |
| 1555 | return CODEC_WAVPACK; |
| 1556 | case AFMT_ALAC: |
| 1557 | logf("Codec: ALAC"); |
| 1558 | return CODEC_ALAC; |
| 1559 | case AFMT_AAC: |
| 1560 | logf("Codec: AAC"); |
| 1561 | return CODEC_AAC; |
| 1562 | case AFMT_SHN: |
| 1563 | logf("Codec: SHN"); |
| 1564 | return CODEC_SHN; |
| 1565 | case AFMT_AIFF: |
| 1566 | logf("Codec: PCM AIFF"); |
| 1567 | return CODEC_AIFF; |
Dave Chapman | 752faa4 | 2006-07-18 18:33:12 +0000 | [diff] [blame] | 1568 | case AFMT_SID: |
| 1569 | logf("Codec: SID"); |
| 1570 | return CODEC_SID; |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 1571 | default: |
| 1572 | logf("Codec: Unsupported"); |
| 1573 | return NULL; |
| 1574 | } |
| 1575 | } |
| 1576 | |
Miika Pekkarinen | 6a4bfb5 | 2005-12-01 18:44:11 +0000 | [diff] [blame] | 1577 | static bool loadcodec(bool start_play) |
| 1578 | { |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 1579 | size_t size; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1580 | int fd; |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 1581 | int rc; |
Brandon Low | 86f1e2e | 2006-03-24 13:43:15 +0000 | [diff] [blame] | 1582 | size_t copy_n; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1583 | int prev_track; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1584 | |
Brandon Low | 98097d2 | 2006-04-17 17:05:05 +0000 | [diff] [blame] | 1585 | const char *codec_path = get_codec_path(tracks[track_widx].id3.codectype); |
| 1586 | if (codec_path == NULL) |
Miika Pekkarinen | d1704f6 | 2005-11-21 11:14:51 +0000 | [diff] [blame] | 1587 | return false; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1588 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1589 | tracks[track_widx].has_codec = false; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1590 | tracks[track_widx].codecsize = 0; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1591 | |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1592 | if (start_play) |
| 1593 | { |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1594 | /* Load the codec directly from disk and save some memory. */ |
Brandon Low | 0744e76 | 2006-04-13 17:30:54 +0000 | [diff] [blame] | 1595 | track_ridx = track_widx; |
| 1596 | cur_ti = &tracks[track_ridx]; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1597 | ci.filesize = cur_ti->filesize; |
Brandon Low | 0744e76 | 2006-04-13 17:30:54 +0000 | [diff] [blame] | 1598 | ci.id3 = &cur_ti->id3; |
| 1599 | ci.taginfo_ready = &cur_ti->taginfo_ready; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1600 | ci.curpos = 0; |
| 1601 | playing = true; |
Miika Pekkarinen | d319116 | 2006-01-27 11:39:46 +0000 | [diff] [blame] | 1602 | queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (void *)codec_path); |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1603 | return true; |
| 1604 | } |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1605 | else |
| 1606 | { |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1607 | /* If we already have another track than this one buffered */ |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1608 | if (track_widx != track_ridx) |
| 1609 | { |
| 1610 | prev_track = (track_widx - 1) & MAX_TRACK_MASK; |
| 1611 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1612 | /* If the previous codec is the same as this one, there is no need |
| 1613 | * to put another copy of it on the file buffer */ |
| 1614 | if (get_codec_base_type(tracks[track_widx].id3.codectype) == |
Miika Pekkarinen | 513cafe | 2006-07-31 06:12:53 +0000 | [diff] [blame] | 1615 | get_codec_base_type(tracks[prev_track].id3.codectype) |
| 1616 | && audio_codec_loaded) |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1617 | { |
| 1618 | logf("Reusing prev. codec"); |
| 1619 | return true; |
| 1620 | } |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1621 | } |
| 1622 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1623 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1624 | fd = open(codec_path, O_RDONLY); |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1625 | if (fd < 0) |
| 1626 | { |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1627 | logf("Codec doesn't exist!"); |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1628 | return false; |
| 1629 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1630 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1631 | size = filesize(fd); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1632 | |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1633 | /* Never load a partial codec */ |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1634 | if (fill_bytesleft < size) |
| 1635 | { |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1636 | logf("Not enough space"); |
Miika Pekkarinen | 431e813 | 2005-06-19 18:41:53 +0000 | [diff] [blame] | 1637 | fill_bytesleft = 0; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1638 | close(fd); |
| 1639 | return false; |
| 1640 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1641 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1642 | while (tracks[track_widx].codecsize < size) |
| 1643 | { |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1644 | copy_n = MIN(conf_filechunk, filebuflen - buf_widx); |
| 1645 | rc = read(fd, &filebuf[buf_widx], copy_n); |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1646 | if (rc < 0) |
| 1647 | return false; |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1648 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1649 | filebufused += rc; |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1650 | if (fill_bytesleft > (unsigned)rc) |
| 1651 | fill_bytesleft -= rc; |
| 1652 | else |
| 1653 | fill_bytesleft = 0; |
| 1654 | |
| 1655 | buf_widx += rc; |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame] | 1656 | if (buf_widx >= filebuflen) |
| 1657 | buf_widx -= filebuflen; |
Brandon Low | 29f7dd3 | 2006-04-07 21:32:30 +0000 | [diff] [blame] | 1658 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1659 | tracks[track_widx].codecsize += rc; |
| 1660 | |
Brandon Low | 29f7dd3 | 2006-04-07 21:32:30 +0000 | [diff] [blame] | 1661 | yield_codecs(); |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1662 | } |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1663 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1664 | tracks[track_widx].has_codec = true; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1665 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1666 | close(fd); |
| 1667 | logf("Done: %dB", size); |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1668 | |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1669 | return true; |
| 1670 | } |
| 1671 | |
Miika Pekkarinen | 6a4bfb5 | 2005-12-01 18:44:11 +0000 | [diff] [blame] | 1672 | static bool read_next_metadata(void) |
Miika Pekkarinen | f46c9f2 | 2005-07-03 18:03:20 +0000 | [diff] [blame] | 1673 | { |
| 1674 | int fd; |
| 1675 | char *trackname; |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1676 | int next_idx; |
Miika Pekkarinen | f46c9f2 | 2005-07-03 18:03:20 +0000 | [diff] [blame] | 1677 | int status; |
| 1678 | |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1679 | next_idx = track_widx; |
| 1680 | if (tracks[next_idx].taginfo_ready) |
| 1681 | { |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1682 | next_idx++; |
| 1683 | next_idx &= MAX_TRACK_MASK; |
| 1684 | |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1685 | if (tracks[next_idx].taginfo_ready) |
| 1686 | return true; |
| 1687 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1688 | |
Miika Pekkarinen | fd7952e | 2005-07-30 17:00:06 +0000 | [diff] [blame] | 1689 | trackname = playlist_peek(last_peek_offset + 1); |
Miika Pekkarinen | f46c9f2 | 2005-07-03 18:03:20 +0000 | [diff] [blame] | 1690 | if (!trackname) |
| 1691 | return false; |
| 1692 | |
| 1693 | fd = open(trackname, O_RDONLY); |
| 1694 | if (fd < 0) |
| 1695 | return false; |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1696 | |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1697 | status = get_metadata(&tracks[next_idx],fd,trackname,v1first); |
Marcoen Hirschberg | b0fee17 | 2005-12-06 13:27:15 +0000 | [diff] [blame] | 1698 | /* Preload the glyphs in the tags */ |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1699 | if (status) |
| 1700 | { |
Brandon Low | 4f3bb2d | 2006-04-09 15:30:28 +0000 | [diff] [blame] | 1701 | if (tracks[next_idx].id3.title) |
| 1702 | lcd_getstringsize(tracks[next_idx].id3.title, NULL, NULL); |
| 1703 | if (tracks[next_idx].id3.artist) |
| 1704 | lcd_getstringsize(tracks[next_idx].id3.artist, NULL, NULL); |
| 1705 | if (tracks[next_idx].id3.album) |
| 1706 | lcd_getstringsize(tracks[next_idx].id3.album, NULL, NULL); |
Marcoen Hirschberg | b0fee17 | 2005-12-06 13:27:15 +0000 | [diff] [blame] | 1707 | } |
Miika Pekkarinen | f46c9f2 | 2005-07-03 18:03:20 +0000 | [diff] [blame] | 1708 | close(fd); |
| 1709 | |
| 1710 | return status; |
| 1711 | } |
| 1712 | |
Brandon Low | da1cddf | 2006-04-26 04:01:35 +0000 | [diff] [blame] | 1713 | static bool audio_load_track(int offset, bool start_play, bool rebuffer) |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1714 | { |
| 1715 | char *trackname; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1716 | off_t size; |
Miika Pekkarinen | 6a4bfb5 | 2005-12-01 18:44:11 +0000 | [diff] [blame] | 1717 | char msgbuf[80]; |
Miika Pekkarinen | de3b04e | 2005-06-29 14:46:27 +0000 | [diff] [blame] | 1718 | |
Miika Pekkarinen | b288dda | 2005-07-10 08:38:16 +0000 | [diff] [blame] | 1719 | /* Stop buffer filling if there is no free track entries. |
| 1720 | Don't fill up the last track entry (we wan't to store next track |
| 1721 | metadata there). */ |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1722 | if (!have_free_tracks()) |
| 1723 | { |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1724 | logf("No free tracks"); |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1725 | return false; |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1726 | } |
Miika Pekkarinen | 2d79df5 | 2005-07-05 13:34:52 +0000 | [diff] [blame] | 1727 | |
Brandon Low | de60231 | 2006-04-07 16:31:20 +0000 | [diff] [blame] | 1728 | if (current_fd >= 0) |
| 1729 | { |
Brandon Low | 348d9ec | 2006-04-14 17:00:22 +0000 | [diff] [blame] | 1730 | logf("Nonzero fd in alt"); |
Brandon Low | de60231 | 2006-04-07 16:31:20 +0000 | [diff] [blame] | 1731 | close(current_fd); |
| 1732 | current_fd = -1; |
| 1733 | } |
Miika Pekkarinen | 2d79df5 | 2005-07-05 13:34:52 +0000 | [diff] [blame] | 1734 | |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1735 | last_peek_offset++; |
Miika Pekkarinen | fd7952e | 2005-07-30 17:00:06 +0000 | [diff] [blame] | 1736 | peek_again: |
Miika Pekkarinen | de3b04e | 2005-06-29 14:46:27 +0000 | [diff] [blame] | 1737 | logf("Buffering track:%d/%d", track_widx, track_ridx); |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1738 | /* Get track name from current playlist read position. */ |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1739 | while ((trackname = playlist_peek(last_peek_offset)) != NULL) |
| 1740 | { |
Brandon Low | 930785c | 2006-04-06 16:21:31 +0000 | [diff] [blame] | 1741 | /* Handle broken playlists. */ |
Brandon Low | de60231 | 2006-04-07 16:31:20 +0000 | [diff] [blame] | 1742 | current_fd = open(trackname, O_RDONLY); |
Miika Pekkarinen | 513cafe | 2006-07-31 06:12:53 +0000 | [diff] [blame] | 1743 | if (current_fd < 0) |
| 1744 | { |
Miika Pekkarinen | fd7952e | 2005-07-30 17:00:06 +0000 | [diff] [blame] | 1745 | logf("Open failed"); |
Miika Pekkarinen | c52f7f1 | 2005-10-21 06:40:45 +0000 | [diff] [blame] | 1746 | /* Skip invalid entry from playlist. */ |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1747 | playlist_skip_entry(NULL, last_peek_offset); |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1748 | } |
| 1749 | else |
Brandon Low | 62ccbbb | 2006-04-11 03:55:58 +0000 | [diff] [blame] | 1750 | break; |
Miika Pekkarinen | fd7952e | 2005-07-30 17:00:06 +0000 | [diff] [blame] | 1751 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1752 | |
Miika Pekkarinen | d43bff9 | 2006-07-29 17:25:31 +0000 | [diff] [blame] | 1753 | if (!trackname) |
| 1754 | { |
Miika Pekkarinen | c3fed62 | 2005-06-15 18:59:04 +0000 | [diff] [blame] | 1755 | logf("End-of-playlist"); |
Miika Pekkarinen | 999f89c | 2005-12-03 12:14:26 +0000 | [diff] [blame] | 1756 | playlist_end = true; |
Linus Nielsen Feltzing | 1c497e6 | 2005-06-05 23:05:10 +0000 | [diff] [blame] | 1757 | return false; |
| 1758 | } |
Zakk Roberts | 8bdd92b | 2006-03-30 05:56:19 +0000 | [diff] [blame] | 1759 | |
Miika Pekkarinen | 2d79df5 | 2005-07-05 13:34:52 +0000 | [diff] [blame] | 1760 | /* Initialize track entry. */ |
Brandon Low | de60231 | 2006-04-07 16:31:20 +0000 | [diff] [blame] | 1761 | size = filesize(current_fd); |
Linus Nielsen Feltzing | |