diff options
Diffstat (limited to 'apps/mpeg.c')
-rw-r--r-- | apps/mpeg.c | 1979 |
1 files changed, 0 insertions, 1979 deletions
diff --git a/apps/mpeg.c b/apps/mpeg.c deleted file mode 100644 index e04c227cb1..0000000000 --- a/apps/mpeg.c +++ /dev/null | |||
@@ -1,1979 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Linus Nielsen Feltzing | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <stdbool.h> | ||
22 | #include <stdlib.h> | ||
23 | #include "config.h" | ||
24 | |||
25 | #if CONFIG_CODEC != SWCODEC | ||
26 | |||
27 | #include "debug.h" | ||
28 | #include "panic.h" | ||
29 | #include "metadata.h" | ||
30 | #include "mpeg.h" | ||
31 | #include "audio.h" | ||
32 | #include "storage.h" | ||
33 | #include "string.h" | ||
34 | #include <kernel.h> | ||
35 | #include "thread.h" | ||
36 | #include "errno.h" | ||
37 | #include "mp3data.h" | ||
38 | #include "core_alloc.h" | ||
39 | #include "mp3_playback.h" | ||
40 | #include "talk.h" | ||
41 | #include "sound.h" | ||
42 | #include "system.h" | ||
43 | #include "appevents.h" | ||
44 | #include "playlist.h" | ||
45 | #include "cuesheet.h" | ||
46 | #include "settings.h" | ||
47 | #ifndef SIMULATOR | ||
48 | #include "i2c.h" | ||
49 | #include "system.h" | ||
50 | #include "usb.h" | ||
51 | #include "file.h" | ||
52 | #include "hwcompat.h" | ||
53 | #endif /* !SIMULATOR */ | ||
54 | #ifdef HAVE_LCD_BITMAP | ||
55 | #include "lcd.h" | ||
56 | #endif /* CONFIG_CODEC != SWCODEC */ | ||
57 | |||
58 | #define MPEG_SWAP_CHUNKSIZE 0x2000 | ||
59 | #define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we | ||
60 | wouldn't be able to see the difference between | ||
61 | an empty buffer and a full one. */ | ||
62 | #define MPEG_LOW_WATER 0x60000 | ||
63 | #define MPEG_RECORDING_LOW_WATER 0x80000 | ||
64 | #define MPEG_LOW_WATER_CHUNKSIZE 0x40000 | ||
65 | #define MPEG_LOW_WATER_SWAP_CHUNKSIZE 0x10000 | ||
66 | #if (CONFIG_STORAGE & STORAGE_MMC) | ||
67 | #define MPEG_PLAY_PENDING_THRESHOLD 0x20000 | ||
68 | #define MPEG_PLAY_PENDING_SWAPSIZE 0x20000 | ||
69 | #else | ||
70 | #define MPEG_PLAY_PENDING_THRESHOLD 0x10000 | ||
71 | #define MPEG_PLAY_PENDING_SWAPSIZE 0x10000 | ||
72 | #endif | ||
73 | |||
74 | #define MPEG_MAX_PRERECORD_SECONDS 30 | ||
75 | |||
76 | /* For ID3 info and VBR header */ | ||
77 | #define MPEG_RESERVED_HEADER_SPACE (4096 + 576) | ||
78 | |||
79 | #ifndef SIMULATOR | ||
80 | extern unsigned long mas_version_code; | ||
81 | #endif | ||
82 | |||
83 | #define MPEG_PLAY 1 | ||
84 | #define MPEG_STOP 2 | ||
85 | #define MPEG_PAUSE 3 | ||
86 | #define MPEG_RESUME 4 | ||
87 | #define MPEG_NEXT 5 | ||
88 | #define MPEG_PREV 6 | ||
89 | #define MPEG_FF_REWIND 7 | ||
90 | #define MPEG_FLUSH_RELOAD 8 | ||
91 | #define MPEG_RECORD 9 | ||
92 | #define MPEG_INIT_RECORDING 10 | ||
93 | #define MPEG_INIT_PLAYBACK 11 | ||
94 | #define MPEG_NEW_FILE 12 | ||
95 | #define MPEG_PAUSE_RECORDING 13 | ||
96 | #define MPEG_RESUME_RECORDING 14 | ||
97 | #define MPEG_NEED_DATA 100 | ||
98 | #define MPEG_TRACK_CHANGE 101 | ||
99 | #define MPEG_SAVE_DATA 102 | ||
100 | #define MPEG_STOP_DONE 103 | ||
101 | #define MPEG_PRERECORDING_TICK 104 | ||
102 | |||
103 | /* indicator for MPEG_NEED_DATA */ | ||
104 | #define GENERATE_UNBUFFER_EVENTS 1 | ||
105 | |||
106 | /* list of tracks in memory */ | ||
107 | #define MAX_TRACK_ENTRIES (1<<4) /* Must be power of 2 */ | ||
108 | #define MAX_TRACK_ENTRIES_MASK (MAX_TRACK_ENTRIES - 1) | ||
109 | |||
110 | struct trackdata | ||
111 | { | ||
112 | struct mp3entry id3; | ||
113 | int mempos; | ||
114 | int load_ahead_index; | ||
115 | }; | ||
116 | |||
117 | static struct trackdata trackdata[MAX_TRACK_ENTRIES]; | ||
118 | |||
119 | static unsigned int current_track_counter = 0; | ||
120 | |||
121 | #ifndef SIMULATOR | ||
122 | static void stop_playing(void); | ||
123 | |||
124 | static int track_read_idx = 0; | ||
125 | static int track_write_idx = 0; | ||
126 | #endif /* !SIMULATOR */ | ||
127 | |||
128 | /* Cuesheet support */ | ||
129 | static struct cuesheet *curr_cuesheet = NULL; | ||
130 | static bool checked_for_cuesheet = false; | ||
131 | |||
132 | static const char mpeg_thread_name[] = "mpeg"; | ||
133 | static unsigned int audio_thread_id; | ||
134 | static bool audio_is_initialized; | ||
135 | static unsigned int mpeg_errno; | ||
136 | |||
137 | static bool playing = false; /* We are playing an MP3 stream */ | ||
138 | static bool is_playing = false; /* We are (attempting to) playing MP3 files */ | ||
139 | static bool paused; /* playback is paused */ | ||
140 | static int audiobuf_handle; /* handle to the audio buffer */ | ||
141 | static char* mpeg_audiobuf; /* poiunter to the audio buffer */ | ||
142 | static long audiobuflen; /* length of the audio buffer */ | ||
143 | #define AUDIO_BUFFER_RESERVE (256*1024) | ||
144 | #ifdef SIMULATOR | ||
145 | static char mpeg_stack[DEFAULT_STACK_SIZE]; | ||
146 | static struct mp3entry taginfo; | ||
147 | #else /* !SIMULATOR */ | ||
148 | static struct event_queue mpeg_queue SHAREDBSS_ATTR; | ||
149 | static long mpeg_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; | ||
150 | |||
151 | static int audiobuf_write; | ||
152 | static int audiobuf_swapwrite; | ||
153 | static long audiobuf_read; | ||
154 | |||
155 | static int mpeg_file; | ||
156 | |||
157 | static bool play_pending; /* We are about to start playing */ | ||
158 | static bool play_pending_track_change; /* When starting play we're starting a new file */ | ||
159 | static bool filling; /* We are filling the buffer with data from disk */ | ||
160 | static bool dma_underrun; /* True when the DMA has stopped because of | ||
161 | slow disk reading (read error, shaking) */ | ||
162 | static bool mpeg_stop_done; | ||
163 | |||
164 | static int last_dma_tick = 0; | ||
165 | static int last_dma_chunk_size; | ||
166 | |||
167 | static long low_watermark; /* Dynamic low watermark level */ | ||
168 | static long low_watermark_margin = 0; /* Extra time in seconds for watermark */ | ||
169 | static long lowest_watermark_level; /* Debug value to observe the buffer | ||
170 | usage */ | ||
171 | |||
172 | struct audio_resume_info | ||
173 | { | ||
174 | unsigned long elapsed; | ||
175 | unsigned long offset; | ||
176 | }; | ||
177 | |||
178 | #ifdef HAVE_RECORDING | ||
179 | static const unsigned char empty_id3_header[] = | ||
180 | { | ||
181 | 'I', 'D', '3', 0x03, 0x00, 0x00, | ||
182 | 0x00, 0x00, 0x1f, 0x76 /* Size is 4096 minus 10 bytes for the header */ | ||
183 | }; | ||
184 | #endif /* HAVE_RECORDING */ | ||
185 | |||
186 | |||
187 | static int get_unplayed_space(void); | ||
188 | static int get_playable_space(void); | ||
189 | static int get_unswapped_space(void); | ||
190 | #endif /* !SIMULATOR */ | ||
191 | |||
192 | static void audio_reset_buffer_noalloc(void* buf, size_t bufsize); | ||
193 | static void audio_reset_buffer(void); | ||
194 | |||
195 | |||
196 | #ifndef SIMULATOR | ||
197 | static int num_tracks_in_memory(void) | ||
198 | { | ||
199 | return (track_write_idx - track_read_idx) & MAX_TRACK_ENTRIES_MASK; | ||
200 | } | ||
201 | |||
202 | #ifdef DEBUG_TAGS | ||
203 | static void debug_tags(void) | ||
204 | { | ||
205 | int i; | ||
206 | |||
207 | for(i = 0;i < MAX_TRACK_ENTRIES;i++) | ||
208 | { | ||
209 | DEBUGF("%d - %s\n", i, trackdata[i].id3.path); | ||
210 | } | ||
211 | DEBUGF("read: %d, write :%d\n", track_read_idx, track_write_idx); | ||
212 | DEBUGF("num_tracks_in_memory: %d\n", num_tracks_in_memory()); | ||
213 | } | ||
214 | #else /* !DEBUG_TAGS */ | ||
215 | #define debug_tags() | ||
216 | #endif /* !DEBUG_TAGS */ | ||
217 | |||
218 | static void remove_current_tag(void) | ||
219 | { | ||
220 | if(num_tracks_in_memory() > 0) | ||
221 | { | ||
222 | /* First move the index, so nobody tries to access the tag */ | ||
223 | track_read_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK; | ||
224 | checked_for_cuesheet = false; | ||
225 | debug_tags(); | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | DEBUGF("remove_current_tag: no tracks to remove\n"); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | static void remove_all_non_current_tags(void) | ||
234 | { | ||
235 | track_write_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK; | ||
236 | debug_tags(); | ||
237 | } | ||
238 | |||
239 | static void remove_all_tags(void) | ||
240 | { | ||
241 | track_write_idx = track_read_idx; | ||
242 | |||
243 | debug_tags(); | ||
244 | } | ||
245 | |||
246 | static struct trackdata *get_trackdata(int offset) | ||
247 | { | ||
248 | if(offset >= num_tracks_in_memory()) | ||
249 | return NULL; | ||
250 | else | ||
251 | return &trackdata[(track_read_idx + offset) & MAX_TRACK_ENTRIES_MASK]; | ||
252 | } | ||
253 | #endif /* !SIMULATOR */ | ||
254 | |||
255 | /***********************************************************************/ | ||
256 | /* audio event handling */ | ||
257 | |||
258 | #define MAX_EVENT_HANDLERS 10 | ||
259 | struct event_handlers_table | ||
260 | { | ||
261 | AUDIO_EVENT_HANDLER handler; | ||
262 | unsigned short mask; | ||
263 | }; | ||
264 | static struct event_handlers_table event_handlers[MAX_EVENT_HANDLERS]; | ||
265 | static int event_handlers_count = 0; | ||
266 | |||
267 | void audio_register_event_handler(AUDIO_EVENT_HANDLER handler, unsigned short mask) | ||
268 | { | ||
269 | if (event_handlers_count < MAX_EVENT_HANDLERS) | ||
270 | { | ||
271 | event_handlers[event_handlers_count].handler = handler; | ||
272 | event_handlers[event_handlers_count].mask = mask; | ||
273 | event_handlers_count++; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | /* dispatch calls each handler in the order registered and returns after some | ||
278 | handler actually handles the event (the event is assumed to no longer be valid | ||
279 | after this, due to the handler changing some condition); returns true if someone | ||
280 | handled the event, which is expected to cause the caller to skip its own handling | ||
281 | of the event */ | ||
282 | #ifndef SIMULATOR | ||
283 | static bool audio_dispatch_event(unsigned short event, unsigned long data) | ||
284 | { | ||
285 | int i = 0; | ||
286 | for(i=0; i < event_handlers_count; i++) | ||
287 | { | ||
288 | if ( event_handlers[i].mask & event ) | ||
289 | { | ||
290 | int rc = event_handlers[i].handler(event, data); | ||
291 | if ( rc == AUDIO_EVENT_RC_HANDLED ) | ||
292 | return true; | ||
293 | } | ||
294 | } | ||
295 | return false; | ||
296 | } | ||
297 | |||
298 | static void send_track_event(unsigned int id, struct mp3entry *id3) | ||
299 | { | ||
300 | struct mp3entry *cur_id3 = | ||
301 | &trackdata[track_read_idx & MAX_TRACK_ENTRIES_MASK].id3; | ||
302 | unsigned int flags = id3 == cur_id3 ? TEF_CURRENT : 0; | ||
303 | send_event(id, &(struct track_event){ .flags = flags, .id3 = id3 }); | ||
304 | } | ||
305 | #endif /* SIMULATOR */ | ||
306 | |||
307 | /***********************************************************************/ | ||
308 | |||
309 | static void set_elapsed(struct mp3entry* id3) | ||
310 | { | ||
311 | if ( id3->vbr ) { | ||
312 | if ( id3->has_toc ) { | ||
313 | /* calculate elapsed time using TOC */ | ||
314 | int i; | ||
315 | unsigned int remainder, plen, relpos, nextpos; | ||
316 | |||
317 | /* find wich percent we're at */ | ||
318 | for (i=0; i<100; i++ ) | ||
319 | { | ||
320 | if ( id3->offset < id3->toc[i] * (id3->filesize / 256) ) | ||
321 | { | ||
322 | break; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | i--; | ||
327 | if (i < 0) | ||
328 | i = 0; | ||
329 | |||
330 | relpos = id3->toc[i]; | ||
331 | |||
332 | if (i < 99) | ||
333 | { | ||
334 | nextpos = id3->toc[i+1]; | ||
335 | } | ||
336 | else | ||
337 | { | ||
338 | nextpos = 256; | ||
339 | } | ||
340 | |||
341 | remainder = id3->offset - (relpos * (id3->filesize / 256)); | ||
342 | |||
343 | /* set time for this percent (divide before multiply to prevent | ||
344 | overflow on long files. loss of precision is negligible on | ||
345 | short files) */ | ||
346 | id3->elapsed = i * (id3->length / 100); | ||
347 | |||
348 | /* calculate remainder time */ | ||
349 | plen = (nextpos - relpos) * (id3->filesize / 256); | ||
350 | id3->elapsed += (((remainder * 100) / plen) * | ||
351 | (id3->length / 10000)); | ||
352 | } | ||
353 | else { | ||
354 | /* no TOC exists. set a rough estimate using average bitrate */ | ||
355 | int tpk = id3->length / (id3->filesize / 1024); | ||
356 | id3->elapsed = id3->offset / 1024 * tpk; | ||
357 | } | ||
358 | } | ||
359 | else | ||
360 | /* constant bitrate, use exact calculation */ | ||
361 | id3->elapsed = id3->offset / (id3->bitrate / 8); | ||
362 | } | ||
363 | |||
364 | static int audio_get_file_pos_int(struct mp3entry *id3) | ||
365 | { | ||
366 | int pos = -1; | ||
367 | |||
368 | if (id3->vbr) | ||
369 | { | ||
370 | if (id3->has_toc) | ||
371 | { | ||
372 | /* Use the TOC to find the new position */ | ||
373 | unsigned int percent, remainder; | ||
374 | int curtoc, nexttoc, plen; | ||
375 | |||
376 | percent = (id3->elapsed*100)/id3->length; | ||
377 | if (percent > 99) | ||
378 | percent = 99; | ||
379 | |||
380 | curtoc = id3->toc[percent]; | ||
381 | |||
382 | if (percent < 99) | ||
383 | nexttoc = id3->toc[percent+1]; | ||
384 | else | ||
385 | nexttoc = 256; | ||
386 | |||
387 | pos = (id3->filesize/256)*curtoc; | ||
388 | |||
389 | /* Use the remainder to get a more accurate position */ | ||
390 | remainder = (id3->elapsed*100)%id3->length; | ||
391 | remainder = (remainder*100)/id3->length; | ||
392 | plen = (nexttoc - curtoc)*(id3->filesize/256); | ||
393 | pos += (plen/100)*remainder; | ||
394 | } | ||
395 | else | ||
396 | { | ||
397 | /* No TOC exists, estimate the new position */ | ||
398 | pos = (id3->filesize / (id3->length / 1000)) * | ||
399 | (id3->elapsed / 1000); | ||
400 | } | ||
401 | } | ||
402 | else if (id3->bitrate) | ||
403 | pos = id3->elapsed * (id3->bitrate / 8); | ||
404 | else | ||
405 | { | ||
406 | return -1; | ||
407 | } | ||
408 | |||
409 | if (pos >= (int)(id3->filesize - id3->id3v1len)) | ||
410 | { | ||
411 | /* Don't seek right to the end of the file so that we can | ||
412 | transition properly to the next song */ | ||
413 | pos = id3->filesize - id3->id3v1len - 1; | ||
414 | } | ||
415 | else if (pos < (int)id3->first_frame_offset) | ||
416 | { | ||
417 | /* skip past id3v2 tag and other leading garbage */ | ||
418 | pos = id3->first_frame_offset; | ||
419 | } | ||
420 | return pos; | ||
421 | } | ||
422 | |||
423 | int audio_get_file_pos(void) | ||
424 | { | ||
425 | struct mp3entry *id3 = audio_current_track(); | ||
426 | return id3 ? audio_get_file_pos_int(id3) : 0; | ||
427 | } | ||
428 | |||
429 | unsigned long mpeg_get_last_header(void) | ||
430 | { | ||
431 | #ifdef SIMULATOR | ||
432 | return 0; | ||
433 | #else /* !SIMULATOR */ | ||
434 | unsigned long tmp[2]; | ||
435 | |||
436 | /* Read the frame data from the MAS and reconstruct it with the | ||
437 | frame sync and all */ | ||
438 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_STATUS_1, tmp, 2); | ||
439 | return 0xffe00000 | ((tmp[0] & 0x7c00) << 6) | (tmp[1] & 0xffff); | ||
440 | #endif /* !SIMULATOR */ | ||
441 | } | ||
442 | |||
443 | static void do_stop(void) | ||
444 | { | ||
445 | is_playing = false; | ||
446 | paused = false; | ||
447 | |||
448 | #ifndef SIMULATOR | ||
449 | if (playing) | ||
450 | playlist_update_resume_info(audio_current_track()); | ||
451 | |||
452 | stop_playing(); | ||
453 | mpeg_stop_done = true; | ||
454 | #else | ||
455 | playing = false; | ||
456 | #endif | ||
457 | } | ||
458 | |||
459 | /* Buffer must not move. */ | ||
460 | static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size) | ||
461 | { | ||
462 | ssize_t extradata_size = old_size - audiobuflen; | ||
463 | /* check what buflib requests */ | ||
464 | size_t wanted_size = (hints & BUFLIB_SHRINK_SIZE_MASK); | ||
465 | ssize_t size = (ssize_t)old_size - wanted_size; | ||
466 | |||
467 | /* keep at least 256K for the buffering */ | ||
468 | if ((size - extradata_size) < AUDIO_BUFFER_RESERVE) | ||
469 | { | ||
470 | /* check if buflib needs the memory really hard. if yes we give | ||
471 | * up playback for now, otherwise refuse to shrink to keep at least | ||
472 | * 256K for the buffering */ | ||
473 | if ((hints & BUFLIB_SHRINK_POS_MASK) != BUFLIB_SHRINK_POS_MASK) | ||
474 | return BUFLIB_CB_CANNOT_SHRINK; | ||
475 | } | ||
476 | /* TODO: Do it without stopping playback, if possible */ | ||
477 | bool playing = (audio_status() & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY; | ||
478 | struct mp3entry *id3 = audio_current_track(); | ||
479 | unsigned long elapsed = 0, offset = 0; | ||
480 | if (id3) | ||
481 | { | ||
482 | elapsed = id3->elapsed; | ||
483 | offset = id3->offset; | ||
484 | } | ||
485 | /* don't call audio_hard_stop() as it frees this handle */ | ||
486 | if (thread_self() == audio_thread_id) | ||
487 | { /* inline case MPEG_STOP (audio_stop()) response | ||
488 | * if we're in the audio thread since audio_stop() otherwise deadlocks */ | ||
489 | do_stop(); | ||
490 | } | ||
491 | else | ||
492 | audio_stop(); | ||
493 | |||
494 | switch (hints & BUFLIB_SHRINK_POS_MASK) | ||
495 | { | ||
496 | case BUFLIB_SHRINK_POS_BACK: | ||
497 | core_shrink(handle, start, size); | ||
498 | audio_reset_buffer_noalloc(start, size); | ||
499 | break; | ||
500 | case BUFLIB_SHRINK_POS_FRONT: | ||
501 | core_shrink(handle, start + wanted_size, size); | ||
502 | audio_reset_buffer_noalloc(start + wanted_size, size); | ||
503 | break; | ||
504 | case BUFLIB_SHRINK_POS_MASK: | ||
505 | audiobuf_handle = core_free(audiobuf_handle); | ||
506 | mpeg_audiobuf = NULL; | ||
507 | talk_buffer_set_policy(TALK_BUFFER_DEFAULT); | ||
508 | playing = false; | ||
509 | break; | ||
510 | } | ||
511 | if (playing) | ||
512 | { /* safe to call even from the audio thread (due to queue_post()) */ | ||
513 | audio_play(elapsed, offset); | ||
514 | } | ||
515 | |||
516 | return BUFLIB_CB_OK; | ||
517 | } | ||
518 | |||
519 | static struct buflib_callbacks ops = { | ||
520 | .move_callback = NULL, | ||
521 | .shrink_callback = shrink_callback, | ||
522 | }; | ||
523 | |||
524 | #ifndef SIMULATOR | ||
525 | /* Send callback events to notify about removing old tracks. */ | ||
526 | static void generate_unbuffer_events(void) | ||
527 | { | ||
528 | int i; | ||
529 | int numentries = MAX_TRACK_ENTRIES - num_tracks_in_memory(); | ||
530 | int cur_idx = track_write_idx; | ||
531 | |||
532 | for (i = 0; i < numentries; i++) | ||
533 | { | ||
534 | /* Send an event to notify that track has finished. */ | ||
535 | send_track_event(PLAYBACK_EVENT_TRACK_FINISH, &trackdata[cur_idx].id3); | ||
536 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | /* Send callback events to notify about new tracks. */ | ||
541 | static void generate_postbuffer_events(void) | ||
542 | { | ||
543 | int i; | ||
544 | int numentries = num_tracks_in_memory(); | ||
545 | int cur_idx = track_read_idx; | ||
546 | |||
547 | for (i = 0; i < numentries; i++) | ||
548 | { | ||
549 | send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, &trackdata[cur_idx].id3); | ||
550 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | ||
551 | } | ||
552 | } | ||
553 | |||
554 | static void recalculate_watermark(int bitrate) | ||
555 | { | ||
556 | int bytes_per_sec; | ||
557 | int time = storage_spinup_time(); | ||
558 | |||
559 | /* A bitrate of 0 probably means empty VBR header. We play safe | ||
560 | and set a high threshold */ | ||
561 | if(bitrate == 0) | ||
562 | bitrate = 320; | ||
563 | |||
564 | bytes_per_sec = bitrate * 1000 / 8; | ||
565 | |||
566 | if(time) | ||
567 | { | ||
568 | /* No drive spins up faster than 3.5s */ | ||
569 | if(time < 350) | ||
570 | time = 350; | ||
571 | |||
572 | time = time * 3; | ||
573 | low_watermark = ((low_watermark_margin * HZ + time) * | ||
574 | bytes_per_sec) / HZ; | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | low_watermark = MPEG_LOW_WATER; | ||
579 | } | ||
580 | } | ||
581 | |||
582 | #ifdef HAVE_DISK_STORAGE | ||
583 | void audio_set_buffer_margin(int setting) | ||
584 | { | ||
585 | low_watermark_margin = setting; /* in seconds */ | ||
586 | } | ||
587 | #endif | ||
588 | |||
589 | void audio_get_debugdata(struct audio_debug *dbgdata) | ||
590 | { | ||
591 | dbgdata->audiobuflen = audiobuflen; | ||
592 | dbgdata->audiobuf_write = audiobuf_write; | ||
593 | dbgdata->audiobuf_swapwrite = audiobuf_swapwrite; | ||
594 | dbgdata->audiobuf_read = audiobuf_read; | ||
595 | |||
596 | dbgdata->last_dma_chunk_size = last_dma_chunk_size; | ||
597 | |||
598 | dbgdata->playing = playing; | ||
599 | dbgdata->play_pending = play_pending; | ||
600 | dbgdata->is_playing = is_playing; | ||
601 | dbgdata->filling = filling; | ||
602 | dbgdata->dma_underrun = dma_underrun; | ||
603 | |||
604 | dbgdata->unplayed_space = get_unplayed_space(); | ||
605 | dbgdata->playable_space = get_playable_space(); | ||
606 | dbgdata->unswapped_space = get_unswapped_space(); | ||
607 | |||
608 | dbgdata->low_watermark_level = low_watermark; | ||
609 | dbgdata->lowest_watermark_level = lowest_watermark_level; | ||
610 | } | ||
611 | |||
612 | #ifdef DEBUG | ||
613 | static void dbg_timer_start(void) | ||
614 | { | ||
615 | /* We are using timer 2 */ | ||
616 | |||
617 | TSTR &= ~0x04; /* Stop the timer */ | ||
618 | TSNC &= ~0x04; /* No synchronization */ | ||
619 | TMDR &= ~0x44; /* Operate normally */ | ||
620 | |||
621 | TCNT2 = 0; /* Start counting at 0 */ | ||
622 | TCR2 = 0x03; /* Sysclock/8 */ | ||
623 | |||
624 | TSTR |= 0x04; /* Start timer 2 */ | ||
625 | } | ||
626 | |||
627 | static int dbg_cnt2us(unsigned int cnt) | ||
628 | { | ||
629 | return (cnt * 10000) / (FREQ/800); | ||
630 | } | ||
631 | #endif /* DEBUG */ | ||
632 | |||
633 | static int get_unplayed_space(void) | ||
634 | { | ||
635 | int space = audiobuf_write - audiobuf_read; | ||
636 | if (space < 0) | ||
637 | space += audiobuflen; | ||
638 | return space; | ||
639 | } | ||
640 | |||
641 | static int get_playable_space(void) | ||
642 | { | ||
643 | int space = audiobuf_swapwrite - audiobuf_read; | ||
644 | if (space < 0) | ||
645 | space += audiobuflen; | ||
646 | return space; | ||
647 | } | ||
648 | |||
649 | static int get_unplayed_space_current_song(void) | ||
650 | { | ||
651 | int space; | ||
652 | |||
653 | if (num_tracks_in_memory() > 1) | ||
654 | { | ||
655 | space = get_trackdata(1)->mempos - audiobuf_read; | ||
656 | } | ||
657 | else | ||
658 | { | ||
659 | space = audiobuf_write - audiobuf_read; | ||
660 | } | ||
661 | |||
662 | if (space < 0) | ||
663 | space += audiobuflen; | ||
664 | |||
665 | return space; | ||
666 | } | ||
667 | |||
668 | static int get_unswapped_space(void) | ||
669 | { | ||
670 | int space = audiobuf_write - audiobuf_swapwrite; | ||
671 | if (space < 0) | ||
672 | space += audiobuflen; | ||
673 | return space; | ||
674 | } | ||
675 | |||
676 | void playback_tick(void) | ||
677 | { | ||
678 | struct trackdata *ptd = get_trackdata(0); | ||
679 | if(ptd) | ||
680 | { | ||
681 | ptd->id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ; | ||
682 | last_dma_tick = current_tick; | ||
683 | audio_dispatch_event(AUDIO_EVENT_POS_REPORT, | ||
684 | (unsigned long)ptd->id3.elapsed); | ||
685 | } | ||
686 | } | ||
687 | |||
688 | static void reset_mp3_buffer(void) | ||
689 | { | ||
690 | audiobuf_read = 0; | ||
691 | audiobuf_write = 0; | ||
692 | audiobuf_swapwrite = 0; | ||
693 | lowest_watermark_level = audiobuflen; | ||
694 | } | ||
695 | |||
696 | /* DMA transfer end interrupt callback */ | ||
697 | static void transfer_end(const void** ppbuf, size_t* psize) | ||
698 | { | ||
699 | if(playing && !paused) | ||
700 | { | ||
701 | int unplayed_space_left; | ||
702 | int space_until_end_of_buffer; | ||
703 | int track_offset = 1; | ||
704 | struct trackdata *track; | ||
705 | |||
706 | audiobuf_read += last_dma_chunk_size; | ||
707 | if(audiobuf_read >= audiobuflen) | ||
708 | audiobuf_read = 0; | ||
709 | |||
710 | /* First, check if we are on a track boundary */ | ||
711 | if (num_tracks_in_memory() > 1) | ||
712 | { | ||
713 | if (audiobuf_read == get_trackdata(track_offset)->mempos) | ||
714 | { | ||
715 | if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) ) | ||
716 | { | ||
717 | queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); | ||
718 | track_offset++; | ||
719 | } | ||
720 | } | ||
721 | } | ||
722 | |||
723 | unplayed_space_left = get_unplayed_space(); | ||
724 | |||
725 | space_until_end_of_buffer = audiobuflen - audiobuf_read; | ||
726 | |||
727 | if(!filling && unplayed_space_left < low_watermark) | ||
728 | { | ||
729 | filling = true; | ||
730 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); | ||
731 | } | ||
732 | |||
733 | if(unplayed_space_left) | ||
734 | { | ||
735 | last_dma_chunk_size = MIN(0x2000, unplayed_space_left); | ||
736 | last_dma_chunk_size = MIN(last_dma_chunk_size, | ||
737 | space_until_end_of_buffer); | ||
738 | |||
739 | /* several tracks loaded? */ | ||
740 | track = get_trackdata(track_offset); | ||
741 | if(track) | ||
742 | { | ||
743 | /* will we move across the track boundary? */ | ||
744 | if (( audiobuf_read < track->mempos ) && | ||
745 | ((audiobuf_read+last_dma_chunk_size) > | ||
746 | track->mempos )) | ||
747 | { | ||
748 | /* Make sure that we end exactly on the boundary */ | ||
749 | last_dma_chunk_size = track->mempos - audiobuf_read; | ||
750 | } | ||
751 | } | ||
752 | |||
753 | *psize = last_dma_chunk_size & 0xffff; | ||
754 | *ppbuf = mpeg_audiobuf + audiobuf_read; | ||
755 | track = get_trackdata(0); | ||
756 | if(track) | ||
757 | track->id3.offset += last_dma_chunk_size; | ||
758 | |||
759 | /* Update the watermark debug level */ | ||
760 | if(unplayed_space_left < lowest_watermark_level) | ||
761 | lowest_watermark_level = unplayed_space_left; | ||
762 | } | ||
763 | else | ||
764 | { | ||
765 | /* Check if the end of data is because of a hard disk error. | ||
766 | If there is an open file handle, we are still playing music. | ||
767 | If not, the last file has been loaded, and the file handle is | ||
768 | closed. */ | ||
769 | if(mpeg_file >= 0) | ||
770 | { | ||
771 | /* Update the watermark debug level */ | ||
772 | if(unplayed_space_left < lowest_watermark_level) | ||
773 | lowest_watermark_level = unplayed_space_left; | ||
774 | |||
775 | DEBUGF("DMA underrun.\n"); | ||
776 | dma_underrun = true; | ||
777 | } | ||
778 | else | ||
779 | { | ||
780 | if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) ) | ||
781 | { | ||
782 | DEBUGF("No more MP3 data. Stopping.\n"); | ||
783 | queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); | ||
784 | playing = false; | ||
785 | } | ||
786 | } | ||
787 | *psize = 0; /* no more transfer */ | ||
788 | } | ||
789 | } | ||
790 | } | ||
791 | |||
792 | static struct trackdata *add_track_to_tag_list(const char *filename) | ||
793 | { | ||
794 | struct trackdata *track; | ||
795 | bool send_nid3_event; | ||
796 | |||
797 | if(num_tracks_in_memory() >= MAX_TRACK_ENTRIES) | ||
798 | { | ||
799 | DEBUGF("Tag memory is full\n"); | ||
800 | return NULL; | ||
801 | } | ||
802 | |||
803 | track = &trackdata[track_write_idx]; | ||
804 | |||
805 | /* grab id3 tag of new file and | ||
806 | remember where in memory it starts */ | ||
807 | if(mp3info(&track->id3, filename)) | ||
808 | { | ||
809 | DEBUGF("Bad mp3\n"); | ||
810 | return NULL; | ||
811 | } | ||
812 | track->mempos = audiobuf_write; | ||
813 | track->id3.elapsed = 0; | ||
814 | #ifdef HAVE_LCD_BITMAP | ||
815 | if (track->id3.title) | ||
816 | lcd_getstringsize(track->id3.title, NULL, NULL); | ||
817 | if (track->id3.artist) | ||
818 | lcd_getstringsize(track->id3.artist, NULL, NULL); | ||
819 | if (track->id3.album) | ||
820 | lcd_getstringsize(track->id3.album, NULL, NULL); | ||
821 | #endif | ||
822 | |||
823 | /* if this track is the next track then let the UI know it can get it */ | ||
824 | send_nid3_event = (track_write_idx == track_read_idx + 1); | ||
825 | track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK; | ||
826 | if (send_nid3_event) | ||
827 | send_track_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, &track->id3); | ||
828 | debug_tags(); | ||
829 | return track; | ||
830 | } | ||
831 | |||
832 | static int new_file(int steps) | ||
833 | { | ||
834 | int max_steps = playlist_amount(); | ||
835 | int start = 0; | ||
836 | int i; | ||
837 | struct trackdata *track; | ||
838 | char name_buf[MAX_PATH+1]; | ||
839 | const char *trackname; | ||
840 | |||
841 | /* Find out how many steps to advance. The load_ahead_index field tells | ||
842 | us how many playlist entries it had to skip to get to a valid one. | ||
843 | We add those together to find out where to start. */ | ||
844 | if(steps > 0 && num_tracks_in_memory() > 1) | ||
845 | { | ||
846 | /* Begin with the song after the currently playing one */ | ||
847 | i = 1; | ||
848 | while((track = get_trackdata(i++))) | ||
849 | { | ||
850 | start += track->load_ahead_index; | ||
851 | } | ||
852 | } | ||
853 | |||
854 | do { | ||
855 | trackname = playlist_peek(start + steps, name_buf, sizeof(name_buf)); | ||
856 | if ( !trackname ) | ||
857 | return -1; | ||
858 | |||
859 | DEBUGF("Loading %s\n", trackname); | ||
860 | |||
861 | mpeg_file = open(trackname, O_RDONLY); | ||
862 | if(mpeg_file < 0) { | ||
863 | DEBUGF("Couldn't open file: %s\n",trackname); | ||
864 | if(steps < 0) | ||
865 | steps--; | ||
866 | else | ||
867 | steps++; | ||
868 | } | ||
869 | else | ||
870 | { | ||
871 | struct trackdata *track = add_track_to_tag_list(trackname); | ||
872 | |||
873 | if(!track) | ||
874 | { | ||
875 | /* Bad mp3 file */ | ||
876 | if(steps < 0) | ||
877 | steps--; | ||
878 | else | ||
879 | steps++; | ||
880 | close(mpeg_file); | ||
881 | mpeg_file = -1; | ||
882 | } | ||
883 | else | ||
884 | { | ||
885 | /* skip past id3v2 tag */ | ||
886 | lseek(mpeg_file, | ||
887 | track->id3.first_frame_offset, | ||
888 | SEEK_SET); | ||
889 | track->id3.index = steps; | ||
890 | track->load_ahead_index = steps; | ||
891 | track->id3.offset = 0; | ||
892 | |||
893 | if(track->id3.vbr) | ||
894 | /* Average bitrate * 1.5 */ | ||
895 | recalculate_watermark( | ||
896 | (track->id3.bitrate * 3) / 2); | ||
897 | else | ||
898 | recalculate_watermark( | ||
899 | track->id3.bitrate); | ||
900 | |||
901 | } | ||
902 | } | ||
903 | |||
904 | /* Bail out if no file could be opened */ | ||
905 | if(abs(steps) > max_steps) | ||
906 | return -1; | ||
907 | } while ( mpeg_file < 0 ); | ||
908 | |||
909 | return 0; | ||
910 | } | ||
911 | |||
912 | static void stop_playing(void) | ||
913 | { | ||
914 | /* Stop the current stream */ | ||
915 | mp3_play_stop(); | ||
916 | playing = false; | ||
917 | filling = false; | ||
918 | |||
919 | if(mpeg_file >= 0) | ||
920 | close(mpeg_file); | ||
921 | mpeg_file = -1; | ||
922 | remove_all_tags(); | ||
923 | generate_unbuffer_events(); | ||
924 | reset_mp3_buffer(); | ||
925 | } | ||
926 | |||
927 | static void end_current_track(void) | ||
928 | { | ||
929 | play_pending = false; | ||
930 | playing = false; | ||
931 | mp3_play_pause(false); | ||
932 | |||
933 | reset_mp3_buffer(); | ||
934 | remove_all_tags(); | ||
935 | generate_unbuffer_events(); | ||
936 | |||
937 | if(mpeg_file >= 0) | ||
938 | close(mpeg_file); | ||
939 | } | ||
940 | |||
941 | /* Is this a really the end of playback or is a new playlist starting */ | ||
942 | static void check_playlist_end(int direction) | ||
943 | { | ||
944 | /* Use the largest possible step size to account for skipped tracks */ | ||
945 | int steps = playlist_amount(); | ||
946 | |||
947 | if (direction < 0) | ||
948 | steps = -steps; | ||
949 | |||
950 | if (playlist_next(steps) < 0) | ||
951 | is_playing = false; | ||
952 | } | ||
953 | |||
954 | static void update_playlist(void) | ||
955 | { | ||
956 | if (num_tracks_in_memory() > 0) | ||
957 | { | ||
958 | struct trackdata *track = get_trackdata(0); | ||
959 | track->id3.index = playlist_next(track->id3.index); | ||
960 | } | ||
961 | else | ||
962 | { | ||
963 | /* End of playlist? */ | ||
964 | check_playlist_end(1); | ||
965 | } | ||
966 | |||
967 | playlist_update_resume_info(audio_current_track()); | ||
968 | } | ||
969 | |||
970 | static void track_change(void) | ||
971 | { | ||
972 | DEBUGF("Track change\n"); | ||
973 | |||
974 | if (num_tracks_in_memory() > 0) | ||
975 | { | ||
976 | remove_current_tag(); | ||
977 | update_playlist(); | ||
978 | if (is_playing) | ||
979 | { | ||
980 | send_track_event(PLAYBACK_EVENT_TRACK_CHANGE, | ||
981 | audio_current_track()); | ||
982 | } | ||
983 | } | ||
984 | |||
985 | current_track_counter++; | ||
986 | } | ||
987 | |||
988 | #ifdef DEBUG | ||
989 | void hexdump(const unsigned char *buf, int len) | ||
990 | { | ||
991 | int i; | ||
992 | |||
993 | for(i = 0;i < len;i++) | ||
994 | { | ||
995 | if(i && (i & 15) == 0) | ||
996 | { | ||
997 | DEBUGF("\n"); | ||
998 | } | ||
999 | DEBUGF("%02x ", buf[i]); | ||
1000 | } | ||
1001 | DEBUGF("\n"); | ||
1002 | } | ||
1003 | #endif /* DEBUG */ | ||
1004 | |||
1005 | static void start_playback_if_ready(void) | ||
1006 | { | ||
1007 | int playable_space; | ||
1008 | |||
1009 | playable_space = audiobuf_swapwrite - audiobuf_read; | ||
1010 | if(playable_space < 0) | ||
1011 | playable_space += audiobuflen; | ||
1012 | |||
1013 | /* See if we have started playing yet. If not, do it. */ | ||
1014 | if(play_pending || dma_underrun) | ||
1015 | { | ||
1016 | /* If the filling has stopped, and we still haven't reached | ||
1017 | the watermark, the file must be smaller than the | ||
1018 | watermark. We must still play it. */ | ||
1019 | if((playable_space >= MPEG_PLAY_PENDING_THRESHOLD) || | ||
1020 | !filling || dma_underrun) | ||
1021 | { | ||
1022 | DEBUGF("P\n"); | ||
1023 | if (play_pending) /* don't do this when recovering from DMA underrun */ | ||
1024 | { | ||
1025 | generate_postbuffer_events(); /* signal first track as buffered */ | ||
1026 | if (play_pending_track_change) | ||
1027 | { | ||
1028 | play_pending_track_change = false; | ||
1029 | send_track_event(PLAYBACK_EVENT_TRACK_CHANGE, | ||
1030 | audio_current_track()); | ||
1031 | } | ||
1032 | play_pending = false; | ||
1033 | } | ||
1034 | playing = true; | ||
1035 | |||
1036 | last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); | ||
1037 | mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); | ||
1038 | dma_underrun = false; | ||
1039 | |||
1040 | if (!paused) | ||
1041 | { | ||
1042 | last_dma_tick = current_tick; | ||
1043 | mp3_play_pause(true); | ||
1044 | } | ||
1045 | |||
1046 | /* Tell ourselves that we need more data */ | ||
1047 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1048 | } | ||
1049 | } | ||
1050 | } | ||
1051 | |||
1052 | static bool swap_one_chunk(void) | ||
1053 | { | ||
1054 | int free_space_left; | ||
1055 | int amount_to_swap; | ||
1056 | |||
1057 | free_space_left = get_unswapped_space(); | ||
1058 | |||
1059 | if(free_space_left == 0 && !play_pending) | ||
1060 | return false; | ||
1061 | |||
1062 | /* Swap in larger chunks when the user is waiting for the playback | ||
1063 | to start, or when there is dangerously little playable data left */ | ||
1064 | if(play_pending) | ||
1065 | amount_to_swap = MIN(MPEG_PLAY_PENDING_SWAPSIZE, free_space_left); | ||
1066 | else | ||
1067 | { | ||
1068 | if(get_playable_space() < low_watermark) | ||
1069 | amount_to_swap = MIN(MPEG_LOW_WATER_SWAP_CHUNKSIZE, | ||
1070 | free_space_left); | ||
1071 | else | ||
1072 | amount_to_swap = MIN(MPEG_SWAP_CHUNKSIZE, free_space_left); | ||
1073 | } | ||
1074 | |||
1075 | if(audiobuf_write < audiobuf_swapwrite) | ||
1076 | amount_to_swap = MIN(audiobuflen - audiobuf_swapwrite, | ||
1077 | amount_to_swap); | ||
1078 | else | ||
1079 | amount_to_swap = MIN(audiobuf_write - audiobuf_swapwrite, | ||
1080 | amount_to_swap); | ||
1081 | |||
1082 | bitswap(mpeg_audiobuf + audiobuf_swapwrite, amount_to_swap); | ||
1083 | |||
1084 | audiobuf_swapwrite += amount_to_swap; | ||
1085 | if(audiobuf_swapwrite >= audiobuflen) | ||
1086 | { | ||
1087 | audiobuf_swapwrite = 0; | ||
1088 | } | ||
1089 | |||
1090 | return true; | ||
1091 | } | ||
1092 | |||
1093 | static void mpeg_thread(void) | ||
1094 | { | ||
1095 | static int pause_tick = 0; | ||
1096 | static unsigned int pause_track = 0; | ||
1097 | struct queue_event ev; | ||
1098 | int len; | ||
1099 | int free_space_left; | ||
1100 | int unplayed_space_left; | ||
1101 | int amount_to_read; | ||
1102 | int t1, t2; | ||
1103 | unsigned long start_elapsed, start_offset; | ||
1104 | |||
1105 | is_playing = false; | ||
1106 | play_pending = false; | ||
1107 | playing = false; | ||
1108 | mpeg_file = -1; | ||
1109 | |||
1110 | while(1) | ||
1111 | { | ||
1112 | yield(); | ||
1113 | |||
1114 | /* Swap if necessary, and don't block on the queue_wait() */ | ||
1115 | if(swap_one_chunk()) | ||
1116 | { | ||
1117 | queue_wait_w_tmo(&mpeg_queue, &ev, 0); | ||
1118 | } | ||
1119 | else if (playing) | ||
1120 | { | ||
1121 | /* periodically update resume info */ | ||
1122 | queue_wait_w_tmo(&mpeg_queue, &ev, HZ/2); | ||
1123 | } | ||
1124 | else | ||
1125 | { | ||
1126 | DEBUGF("S R:%x W:%x SW:%x\n", | ||
1127 | audiobuf_read, audiobuf_write, audiobuf_swapwrite); | ||
1128 | queue_wait(&mpeg_queue, &ev); | ||
1129 | } | ||
1130 | |||
1131 | start_playback_if_ready(); | ||
1132 | |||
1133 | switch(ev.id) | ||
1134 | { | ||
1135 | case MPEG_PLAY: | ||
1136 | DEBUGF("MPEG_PLAY\n"); | ||
1137 | |||
1138 | #if CONFIG_TUNER | ||
1139 | /* Silence the A/D input, it may be on because the radio | ||
1140 | may be playing */ | ||
1141 | mas_codec_writereg(6, 0x0000); | ||
1142 | #endif /* CONFIG_TUNER */ | ||
1143 | |||
1144 | /* Stop the current stream */ | ||
1145 | paused = false; | ||
1146 | end_current_track(); | ||
1147 | |||
1148 | if ( new_file(0) == -1 ) | ||
1149 | { | ||
1150 | is_playing = false; | ||
1151 | track_change(); | ||
1152 | break; | ||
1153 | } | ||
1154 | |||
1155 | start_elapsed = ((struct audio_resume_info *)ev.data)->elapsed; | ||
1156 | start_offset = ((struct audio_resume_info *)ev.data)->offset; | ||
1157 | |||
1158 | /* mid-song resume? */ | ||
1159 | if (!start_offset && start_elapsed) { | ||
1160 | struct mp3entry *id3 = &get_trackdata(0)->id3; | ||
1161 | id3->elapsed = start_elapsed; | ||
1162 | start_offset = audio_get_file_pos_int(id3); | ||
1163 | } | ||
1164 | |||
1165 | if (start_offset) { | ||
1166 | struct mp3entry* id3 = &get_trackdata(0)->id3; | ||
1167 | lseek(mpeg_file, start_offset, SEEK_SET); | ||
1168 | id3->offset = start_offset; | ||
1169 | set_elapsed(id3); | ||
1170 | } | ||
1171 | else { | ||
1172 | /* skip past id3v2 tag */ | ||
1173 | lseek(mpeg_file, | ||
1174 | get_trackdata(0)->id3.first_frame_offset, | ||
1175 | SEEK_SET); | ||
1176 | |||
1177 | } | ||
1178 | |||
1179 | /* Make it read more data */ | ||
1180 | filling = true; | ||
1181 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1182 | |||
1183 | /* Tell the file loading code that we want to start playing | ||
1184 | as soon as we have some data */ | ||
1185 | play_pending = true; | ||
1186 | play_pending_track_change = true; | ||
1187 | |||
1188 | update_playlist(); | ||
1189 | current_track_counter++; | ||
1190 | break; | ||
1191 | |||
1192 | case MPEG_STOP: | ||
1193 | do_stop(); | ||
1194 | break; | ||
1195 | |||
1196 | case MPEG_PAUSE: | ||
1197 | DEBUGF("MPEG_PAUSE\n"); | ||
1198 | /* Stop the current stream */ | ||
1199 | if (playing) | ||
1200 | playlist_update_resume_info(audio_current_track()); | ||
1201 | paused = true; | ||
1202 | playing = false; | ||
1203 | pause_tick = current_tick; | ||
1204 | pause_track = current_track_counter; | ||
1205 | mp3_play_pause(false); | ||
1206 | break; | ||
1207 | |||
1208 | case MPEG_RESUME: | ||
1209 | DEBUGF("MPEG_RESUME\n"); | ||
1210 | /* Continue the current stream */ | ||
1211 | paused = false; | ||
1212 | if (!play_pending) | ||
1213 | { | ||
1214 | playing = true; | ||
1215 | if ( current_track_counter == pause_track ) | ||
1216 | last_dma_tick += current_tick - pause_tick; | ||
1217 | else | ||
1218 | last_dma_tick = current_tick; | ||
1219 | pause_tick = 0; | ||
1220 | mp3_play_pause(true); | ||
1221 | } | ||
1222 | break; | ||
1223 | |||
1224 | case MPEG_NEXT: | ||
1225 | DEBUGF("MPEG_NEXT\n"); | ||
1226 | /* is next track in ram? */ | ||
1227 | if ( num_tracks_in_memory() > 1 ) { | ||
1228 | int unplayed_space_left, unswapped_space_left; | ||
1229 | |||
1230 | /* stop the current stream */ | ||
1231 | play_pending = false; | ||
1232 | playing = false; | ||
1233 | mp3_play_pause(false); | ||
1234 | |||
1235 | track_change(); | ||
1236 | audiobuf_read = get_trackdata(0)->mempos; | ||
1237 | last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); | ||
1238 | mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); | ||
1239 | dma_underrun = false; | ||
1240 | last_dma_tick = current_tick; | ||
1241 | |||
1242 | unplayed_space_left = get_unplayed_space(); | ||
1243 | unswapped_space_left = get_unswapped_space(); | ||
1244 | |||
1245 | /* should we start reading more data? */ | ||
1246 | if(!filling && (unplayed_space_left < low_watermark)) { | ||
1247 | filling = true; | ||
1248 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); | ||
1249 | play_pending = true; | ||
1250 | } else if(unswapped_space_left && | ||
1251 | unswapped_space_left > unplayed_space_left) { | ||
1252 | /* Stop swapping the data from the previous file */ | ||
1253 | audiobuf_swapwrite = audiobuf_read; | ||
1254 | play_pending = true; | ||
1255 | } else { | ||
1256 | playing = true; | ||
1257 | if (!paused) | ||
1258 | mp3_play_pause(true); | ||
1259 | } | ||
1260 | } | ||
1261 | else { | ||
1262 | if (!playlist_check(1)) | ||
1263 | break; | ||
1264 | |||
1265 | /* stop the current stream */ | ||
1266 | end_current_track(); | ||
1267 | |||
1268 | if (new_file(1) < 0) { | ||
1269 | DEBUGF("No more files to play\n"); | ||
1270 | filling = false; | ||
1271 | |||
1272 | check_playlist_end(1); | ||
1273 | current_track_counter++; | ||
1274 | } else { | ||
1275 | /* Make it read more data */ | ||
1276 | filling = true; | ||
1277 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1278 | |||
1279 | /* Tell the file loading code that we want | ||
1280 | to start playing as soon as we have some data */ | ||
1281 | play_pending = true; | ||
1282 | play_pending_track_change = true; | ||
1283 | |||
1284 | update_playlist(); | ||
1285 | current_track_counter++; | ||
1286 | } | ||
1287 | } | ||
1288 | break; | ||
1289 | |||
1290 | case MPEG_PREV: { | ||
1291 | DEBUGF("MPEG_PREV\n"); | ||
1292 | |||
1293 | if (!playlist_check(-1)) | ||
1294 | break; | ||
1295 | |||
1296 | /* stop the current stream */ | ||
1297 | end_current_track(); | ||
1298 | |||
1299 | /* Open the next file */ | ||
1300 | if (new_file(-1) < 0) { | ||
1301 | DEBUGF("No more files to play\n"); | ||
1302 | filling = false; | ||
1303 | |||
1304 | check_playlist_end(-1); | ||
1305 | current_track_counter++; | ||
1306 | } else { | ||
1307 | /* Make it read more data */ | ||
1308 | filling = true; | ||
1309 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1310 | |||
1311 | /* Tell the file loading code that we want to | ||
1312 | start playing as soon as we have some data */ | ||
1313 | play_pending = true; | ||
1314 | play_pending_track_change = true; | ||
1315 | |||
1316 | update_playlist(); | ||
1317 | current_track_counter++; | ||
1318 | } | ||
1319 | break; | ||
1320 | } | ||
1321 | |||
1322 | case MPEG_FF_REWIND: { | ||
1323 | struct mp3entry *id3 = audio_current_track(); | ||
1324 | unsigned int oldtime = id3->elapsed; | ||
1325 | unsigned int newtime = (unsigned int)ev.data; | ||
1326 | int curpos, newpos, diffpos; | ||
1327 | DEBUGF("MPEG_FF_REWIND\n"); | ||
1328 | |||
1329 | id3->elapsed = newtime; | ||
1330 | |||
1331 | newpos = audio_get_file_pos_int(id3); | ||
1332 | if(newpos < 0) | ||
1333 | { | ||
1334 | id3->elapsed = oldtime; | ||
1335 | break; | ||
1336 | } | ||
1337 | |||
1338 | if (mpeg_file >= 0) | ||
1339 | curpos = lseek(mpeg_file, 0, SEEK_CUR); | ||
1340 | else | ||
1341 | curpos = id3->filesize; | ||
1342 | |||
1343 | if (num_tracks_in_memory() > 1) | ||
1344 | { | ||
1345 | /* We have started loading other tracks that need to be | ||
1346 | accounted for */ | ||
1347 | struct trackdata *track; | ||
1348 | int i = 0; | ||
1349 | |||
1350 | while((track = get_trackdata(i++))) | ||
1351 | { | ||
1352 | curpos += track->id3.filesize; | ||
1353 | } | ||
1354 | } | ||
1355 | |||
1356 | diffpos = curpos - newpos; | ||
1357 | |||
1358 | if(!filling && diffpos >= 0 && diffpos < audiobuflen) | ||
1359 | { | ||
1360 | int unplayed_space_left, unswapped_space_left; | ||
1361 | |||
1362 | /* We are changing to a position that's already in | ||
1363 | memory, so we just move the DMA read pointer. */ | ||
1364 | audiobuf_read = audiobuf_write - diffpos; | ||
1365 | if (audiobuf_read < 0) | ||
1366 | { | ||
1367 | audiobuf_read += audiobuflen; | ||
1368 | } | ||
1369 | |||
1370 | unplayed_space_left = get_unplayed_space(); | ||
1371 | unswapped_space_left = get_unswapped_space(); | ||
1372 | |||
1373 | /* If unswapped_space_left is larger than | ||
1374 | unplayed_space_left, it means that the swapwrite pointer | ||
1375 | hasn't yet advanced up to the new location of the read | ||
1376 | pointer. We just move it, there is no need to swap | ||
1377 | data that won't be played anyway. */ | ||
1378 | |||
1379 | if (unswapped_space_left > unplayed_space_left) | ||
1380 | { | ||
1381 | DEBUGF("Moved swapwrite\n"); | ||
1382 | audiobuf_swapwrite = audiobuf_read; | ||
1383 | play_pending = true; | ||
1384 | } | ||
1385 | |||
1386 | if (mpeg_file>=0 && unplayed_space_left < low_watermark) | ||
1387 | { | ||
1388 | /* We need to load more data before starting */ | ||
1389 | filling = true; | ||
1390 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); | ||
1391 | play_pending = true; | ||
1392 | } | ||
1393 | else | ||
1394 | { | ||
1395 | /* resume will start at new position */ | ||
1396 | last_dma_chunk_size = | ||
1397 | MIN(0x2000, get_unplayed_space_current_song()); | ||
1398 | mp3_play_data(mpeg_audiobuf + audiobuf_read, | ||
1399 | last_dma_chunk_size, transfer_end); | ||
1400 | dma_underrun = false; | ||
1401 | } | ||
1402 | } | ||
1403 | else | ||
1404 | { | ||
1405 | /* Move to the new position in the file and start | ||
1406 | loading data */ | ||
1407 | reset_mp3_buffer(); | ||
1408 | |||
1409 | if (num_tracks_in_memory() > 1) | ||
1410 | { | ||
1411 | /* We have to reload the current track */ | ||
1412 | close(mpeg_file); | ||
1413 | remove_all_non_current_tags(); | ||
1414 | generate_unbuffer_events(); | ||
1415 | mpeg_file = -1; | ||
1416 | } | ||
1417 | |||
1418 | if (mpeg_file < 0) | ||
1419 | { | ||
1420 | mpeg_file = open(id3->path, O_RDONLY); | ||
1421 | if (mpeg_file < 0) | ||
1422 | { | ||
1423 | id3->elapsed = oldtime; | ||
1424 | break; | ||
1425 | } | ||
1426 | } | ||
1427 | |||
1428 | if(-1 == lseek(mpeg_file, newpos, SEEK_SET)) | ||
1429 | { | ||
1430 | id3->elapsed = oldtime; | ||
1431 | break; | ||
1432 | } | ||
1433 | |||
1434 | filling = true; | ||
1435 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1436 | |||
1437 | /* Tell the file loading code that we want to start playing | ||
1438 | as soon as we have some data */ | ||
1439 | play_pending = true; | ||
1440 | } | ||
1441 | |||
1442 | id3->offset = newpos; | ||
1443 | |||
1444 | break; | ||
1445 | } | ||
1446 | |||
1447 | case MPEG_FLUSH_RELOAD: { | ||
1448 | int numtracks = num_tracks_in_memory(); | ||
1449 | bool reload_track = false; | ||
1450 | |||
1451 | if (numtracks > 1) | ||
1452 | { | ||
1453 | /* Reset the buffer */ | ||
1454 | audiobuf_write = get_trackdata(1)->mempos; | ||
1455 | |||
1456 | /* Reset swapwrite unless we're still swapping current | ||
1457 | track */ | ||
1458 | if (get_unplayed_space() <= get_playable_space()) | ||
1459 | audiobuf_swapwrite = audiobuf_write; | ||
1460 | |||
1461 | close(mpeg_file); | ||
1462 | remove_all_non_current_tags(); | ||
1463 | generate_unbuffer_events(); | ||
1464 | mpeg_file = -1; | ||
1465 | reload_track = true; | ||
1466 | } | ||
1467 | else if (numtracks == 1 && mpeg_file < 0) | ||
1468 | { | ||
1469 | reload_track = true; | ||
1470 | } | ||
1471 | |||
1472 | if(reload_track && new_file(1) >= 0) | ||
1473 | { | ||
1474 | /* Tell ourselves that we want more data */ | ||
1475 | filling = true; | ||
1476 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1477 | } | ||
1478 | |||
1479 | break; | ||
1480 | } | ||
1481 | |||
1482 | case MPEG_NEED_DATA: | ||
1483 | free_space_left = audiobuf_read - audiobuf_write; | ||
1484 | |||
1485 | /* We interpret 0 as "empty buffer" */ | ||
1486 | if(free_space_left <= 0) | ||
1487 | free_space_left += audiobuflen; | ||
1488 | |||
1489 | unplayed_space_left = audiobuflen - free_space_left; | ||
1490 | |||
1491 | /* Make sure that we don't fill the entire buffer */ | ||
1492 | free_space_left -= MPEG_HIGH_WATER; | ||
1493 | |||
1494 | if (ev.data == GENERATE_UNBUFFER_EVENTS) | ||
1495 | generate_unbuffer_events(); | ||
1496 | |||
1497 | /* do we have any more buffer space to fill? */ | ||
1498 | if(free_space_left <= 0) | ||
1499 | { | ||
1500 | DEBUGF("0\n"); | ||
1501 | filling = false; | ||
1502 | generate_postbuffer_events(); | ||
1503 | storage_sleep(); | ||
1504 | break; | ||
1505 | } | ||
1506 | |||
1507 | /* Read small chunks while we are below the low water mark */ | ||
1508 | if(unplayed_space_left < low_watermark) | ||
1509 | amount_to_read = MIN(MPEG_LOW_WATER_CHUNKSIZE, | ||
1510 | free_space_left); | ||
1511 | else | ||
1512 | amount_to_read = free_space_left; | ||
1513 | |||
1514 | /* Don't read more than until the end of the buffer */ | ||
1515 | amount_to_read = MIN(audiobuflen - audiobuf_write, | ||
1516 | amount_to_read); | ||
1517 | #if (CONFIG_STORAGE & STORAGE_MMC) | ||
1518 | /* MMC is slow, so don't read too large chunks */ | ||
1519 | amount_to_read = MIN(0x40000, amount_to_read); | ||
1520 | #elif MEMORYSIZE == 8 | ||
1521 | amount_to_read = MIN(0x100000, amount_to_read); | ||
1522 | #endif | ||
1523 | |||
1524 | /* Read as much mpeg data as we can fit in the buffer */ | ||
1525 | if(mpeg_file >= 0) | ||
1526 | { | ||
1527 | DEBUGF("R\n"); | ||
1528 | t1 = current_tick; | ||
1529 | len = read(mpeg_file, mpeg_audiobuf + audiobuf_write, | ||
1530 | amount_to_read); | ||
1531 | if(len > 0) | ||
1532 | { | ||
1533 | t2 = current_tick; | ||
1534 | DEBUGF("time: %d\n", t2 - t1); | ||
1535 | DEBUGF("R: %x\n", len); | ||
1536 | |||
1537 | /* Now make sure that we don't feed the MAS with ID3V1 | ||
1538 | data */ | ||
1539 | if (len < amount_to_read) | ||
1540 | { | ||
1541 | int i; | ||
1542 | static const unsigned char tag[] = "TAG"; | ||
1543 | int taglen = 128; | ||
1544 | int tagptr = audiobuf_write + len - 128; | ||
1545 | |||
1546 | /* Really rare case: entire potential tag wasn't | ||
1547 | read in this call AND audiobuf_write < 128 */ | ||
1548 | if (tagptr < 0) | ||
1549 | tagptr += audiobuflen; | ||
1550 | |||
1551 | for(i = 0;i < 3;i++) | ||
1552 | { | ||
1553 | if(tagptr >= audiobuflen) | ||
1554 | tagptr -= audiobuflen; | ||
1555 | |||
1556 | if(mpeg_audiobuf[tagptr] != tag[i]) | ||
1557 | { | ||
1558 | taglen = 0; | ||
1559 | break; | ||
1560 | } | ||
1561 | |||
1562 | tagptr++; | ||
1563 | } | ||
1564 | |||
1565 | if(taglen) | ||
1566 | { | ||
1567 | /* Skip id3v1 tag */ | ||
1568 | DEBUGF("Skipping ID3v1 tag\n"); | ||
1569 | len -= taglen; | ||
1570 | |||
1571 | /* In the very rare case when the entire tag | ||
1572 | wasn't read in this read() len will be < 0. | ||
1573 | Take care of this when changing the write | ||
1574 | pointer. */ | ||
1575 | } | ||
1576 | } | ||
1577 | |||
1578 | audiobuf_write += len; | ||
1579 | |||
1580 | if (audiobuf_write < 0) | ||
1581 | audiobuf_write += audiobuflen; | ||
1582 | |||
1583 | if(audiobuf_write >= audiobuflen) | ||
1584 | { | ||
1585 | audiobuf_write = 0; | ||
1586 | DEBUGF("W\n"); | ||
1587 | } | ||
1588 | |||
1589 | /* Tell ourselves that we want more data */ | ||
1590 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1591 | } | ||
1592 | else | ||
1593 | { | ||
1594 | if(len < 0) | ||
1595 | { | ||
1596 | DEBUGF("MPEG read error\n"); | ||
1597 | } | ||
1598 | |||
1599 | close(mpeg_file); | ||
1600 | mpeg_file = -1; | ||
1601 | |||
1602 | if(new_file(1) < 0) | ||
1603 | { | ||
1604 | /* No more data to play */ | ||
1605 | DEBUGF("No more files to play\n"); | ||
1606 | filling = false; | ||
1607 | } | ||
1608 | else | ||
1609 | { | ||
1610 | /* Tell ourselves that we want more data */ | ||
1611 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1612 | } | ||
1613 | } | ||
1614 | } | ||
1615 | break; | ||
1616 | |||
1617 | case MPEG_TRACK_CHANGE: | ||
1618 | track_change(); | ||
1619 | break; | ||
1620 | |||
1621 | #ifndef USB_NONE | ||
1622 | case SYS_USB_CONNECTED: | ||
1623 | is_playing = false; | ||
1624 | paused = false; | ||
1625 | stop_playing(); | ||
1626 | |||
1627 | /* Tell the USB thread that we are safe */ | ||
1628 | DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); | ||
1629 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
1630 | |||
1631 | /* Wait until the USB cable is extracted again */ | ||
1632 | usb_wait_for_disconnect(&mpeg_queue); | ||
1633 | break; | ||
1634 | #endif /* !USB_NONE */ | ||
1635 | |||
1636 | case SYS_TIMEOUT: | ||
1637 | if (playing) | ||
1638 | playlist_update_resume_info(audio_current_track()); | ||
1639 | break; | ||
1640 | } | ||
1641 | } | ||
1642 | } | ||
1643 | #endif /* !SIMULATOR */ | ||
1644 | |||
1645 | struct mp3entry* audio_current_track(void) | ||
1646 | { | ||
1647 | #ifdef SIMULATOR | ||
1648 | struct mp3entry *id3 = &taginfo; | ||
1649 | #else /* !SIMULATOR */ | ||
1650 | if(num_tracks_in_memory()) | ||
1651 | { | ||
1652 | struct mp3entry *id3 = &get_trackdata(0)->id3; | ||
1653 | #endif | ||
1654 | if (!checked_for_cuesheet && curr_cuesheet && id3->cuesheet == NULL) | ||
1655 | { | ||
1656 | checked_for_cuesheet = true; /* only check once per track */ | ||
1657 | struct cuesheet_file cue_file; | ||
1658 | |||
1659 | if (look_for_cuesheet_file(id3, &cue_file) && | ||
1660 | parse_cuesheet(&cue_file, curr_cuesheet)) | ||
1661 | { | ||
1662 | id3->cuesheet = curr_cuesheet; | ||
1663 | } | ||
1664 | } | ||
1665 | return id3; | ||
1666 | #ifndef SIMULATOR | ||
1667 | } | ||
1668 | else | ||
1669 | return NULL; | ||
1670 | #endif /* !SIMULATOR */ | ||
1671 | } | ||
1672 | |||
1673 | struct mp3entry* audio_next_track(void) | ||
1674 | { | ||
1675 | #ifdef SIMULATOR | ||
1676 | return &taginfo; | ||
1677 | #else /* !SIMULATOR */ | ||
1678 | if(num_tracks_in_memory() > 1) | ||
1679 | return &get_trackdata(1)->id3; | ||
1680 | else | ||
1681 | return NULL; | ||
1682 | #endif /* !SIMULATOR */ | ||
1683 | } | ||
1684 | |||
1685 | size_t audio_buffer_size(void) | ||
1686 | { | ||
1687 | if (audiobuf_handle > 0) | ||
1688 | return audiobuflen; | ||
1689 | return 0; | ||
1690 | } | ||
1691 | |||
1692 | size_t audio_buffer_available(void) | ||
1693 | { | ||
1694 | size_t size = 0; | ||
1695 | size_t core_size = core_available(); | ||
1696 | if (audiobuf_handle > 0) | ||
1697 | return audiobuflen - AUDIO_BUFFER_RESERVE - 128; | ||
1698 | return MAX(core_size, size); | ||
1699 | } | ||
1700 | |||
1701 | static void audio_reset_buffer_noalloc(void* buf, size_t bufsize) | ||
1702 | { | ||
1703 | mpeg_audiobuf = buf; | ||
1704 | audiobuflen = bufsize; | ||
1705 | if (global_settings.cuesheet) | ||
1706 | { /* enable cuesheet support */ | ||
1707 | curr_cuesheet = (struct cuesheet*)mpeg_audiobuf; | ||
1708 | mpeg_audiobuf = SKIPBYTES(mpeg_audiobuf, sizeof(struct cuesheet)); | ||
1709 | audiobuflen -= sizeof(struct cuesheet); | ||
1710 | } | ||
1711 | } | ||
1712 | |||
1713 | static void audio_reset_buffer(void) | ||
1714 | { | ||
1715 | size_t bufsize = audiobuflen; | ||
1716 | |||
1717 | /* alloc buffer if it's was never allocated or freed by audio_hard_stop() | ||
1718 | * because voice cannot be played during audio playback make | ||
1719 | * talk.c give up all buffers and disable itself */ | ||
1720 | if (!audiobuf_handle) | ||
1721 | { | ||
1722 | talk_buffer_set_policy(TALK_BUFFER_LOOSE); | ||
1723 | audiobuf_handle = core_alloc_maximum("audiobuf", &bufsize, &ops); | ||
1724 | } | ||
1725 | |||
1726 | audio_reset_buffer_noalloc(core_get_data(audiobuf_handle), bufsize); | ||
1727 | } | ||
1728 | |||
1729 | void audio_play(unsigned long elapsed, unsigned long offset) | ||
1730 | { | ||
1731 | audio_reset_buffer(); | ||
1732 | #ifdef SIMULATOR | ||
1733 | char name_buf[MAX_PATH+1]; | ||
1734 | const char* trackname; | ||
1735 | int steps=0; | ||
1736 | |||
1737 | is_playing = true; | ||
1738 | |||
1739 | do { | ||
1740 | trackname = playlist_peek(steps, name_buf, sizeof(name_buf)); | ||
1741 | if (!trackname) | ||
1742 | break; | ||
1743 | if(mp3info(&taginfo, trackname)) { | ||
1744 | /* bad mp3, move on */ | ||
1745 | if(++steps > playlist_amount()) | ||
1746 | break; | ||
1747 | continue; | ||
1748 | } | ||
1749 | #ifdef HAVE_MPEG_PLAY | ||
1750 | real_mpeg_play(trackname); | ||
1751 | #endif | ||
1752 | playlist_next(steps); | ||
1753 | if (!offset && elapsed) | ||
1754 | { | ||
1755 | /* has an elapsed time but no offset; elapsed may take | ||
1756 | precedence in this case */ | ||
1757 | taginfo.elapsed = elapsed; | ||
1758 | taginfo.offset = audio_get_file_pos_int(&taginfo); | ||
1759 | } | ||
1760 | else | ||
1761 | { | ||
1762 | taginfo.offset = offset; | ||
1763 | set_elapsed(&taginfo); | ||
1764 | } | ||
1765 | is_playing = true; | ||
1766 | playing = true; | ||
1767 | break; | ||
1768 | } while(1); | ||
1769 | #else /* !SIMULATOR */ | ||
1770 | static struct audio_resume_info resume; | ||
1771 | is_playing = true; | ||
1772 | resume.elapsed = elapsed; | ||
1773 | resume.offset = offset; | ||
1774 | queue_post(&mpeg_queue, MPEG_PLAY, (intptr_t)&resume); | ||
1775 | #endif /* !SIMULATOR */ | ||
1776 | |||
1777 | mpeg_errno = 0; | ||
1778 | } | ||
1779 | |||
1780 | void audio_stop(void) | ||
1781 | { | ||
1782 | if (audiobuf_handle <= 0) | ||
1783 | return; /* nothing to do, must be hard-stopped already */ | ||
1784 | #ifndef SIMULATOR | ||
1785 | mpeg_stop_done = false; | ||
1786 | queue_post(&mpeg_queue, MPEG_STOP, 0); | ||
1787 | while(!mpeg_stop_done) | ||
1788 | yield(); | ||
1789 | #else /* SIMULATOR */ | ||
1790 | paused = false; | ||
1791 | is_playing = false; | ||
1792 | playing = false; | ||
1793 | #endif /* SIMULATOR */ | ||
1794 | } | ||
1795 | |||
1796 | /* dummy */ | ||
1797 | void audio_stop_recording(void) | ||
1798 | { | ||
1799 | audio_stop(); | ||
1800 | } | ||
1801 | |||
1802 | void audio_hard_stop(void) | ||
1803 | { | ||
1804 | if (audiobuf_handle > 0) | ||
1805 | { | ||
1806 | audio_stop(); | ||
1807 | audiobuf_handle = core_free(audiobuf_handle); | ||
1808 | mpeg_audiobuf = NULL; | ||
1809 | talk_buffer_set_policy(TALK_BUFFER_DEFAULT); | ||
1810 | } | ||
1811 | } | ||
1812 | |||
1813 | void audio_pause(void) | ||
1814 | { | ||
1815 | #ifndef SIMULATOR | ||
1816 | queue_post(&mpeg_queue, MPEG_PAUSE, 0); | ||
1817 | #else /* SIMULATOR */ | ||
1818 | is_playing = true; | ||
1819 | playing = false; | ||
1820 | paused = true; | ||
1821 | #endif /* SIMULATOR */ | ||
1822 | } | ||
1823 | |||
1824 | void audio_resume(void) | ||
1825 | { | ||
1826 | #ifndef SIMULATOR | ||
1827 | queue_post(&mpeg_queue, MPEG_RESUME, 0); | ||
1828 | #else /* SIMULATOR */ | ||
1829 | is_playing = true; | ||
1830 | playing = true; | ||
1831 | paused = false; | ||
1832 | #endif /* SIMULATOR */ | ||
1833 | } | ||
1834 | |||
1835 | void audio_next(void) | ||
1836 | { | ||
1837 | #ifndef SIMULATOR | ||
1838 | queue_remove_from_head(&mpeg_queue, MPEG_NEED_DATA); | ||
1839 | queue_post(&mpeg_queue, MPEG_NEXT, 0); | ||
1840 | #else /* SIMULATOR */ | ||
1841 | char name_buf[MAX_PATH+1]; | ||
1842 | const char* file; | ||
1843 | int steps = 1; | ||
1844 | |||
1845 | do { | ||
1846 | file = playlist_peek(steps, name_buf, sizeof(name_buf)); | ||
1847 | if(!file) | ||
1848 | break; | ||
1849 | if(mp3info(&taginfo, file)) { | ||
1850 | if(++steps > playlist_amount()) | ||
1851 | break; | ||
1852 | continue; | ||
1853 | } | ||
1854 | playlist_next(steps); | ||
1855 | current_track_counter++; | ||
1856 | is_playing = true; | ||
1857 | playing = true; | ||
1858 | break; | ||
1859 | } while(1); | ||
1860 | #endif /* SIMULATOR */ | ||
1861 | } | ||
1862 | |||
1863 | void audio_prev(void) | ||
1864 | { | ||
1865 | #ifndef SIMULATOR | ||
1866 | queue_remove_from_head(&mpeg_queue, MPEG_NEED_DATA); | ||
1867 | queue_post(&mpeg_queue, MPEG_PREV, 0); | ||
1868 | #else /* SIMULATOR */ | ||
1869 | char name_buf[MAX_PATH+1]; | ||
1870 | const char* file; | ||
1871 | int steps = -1; | ||
1872 | |||
1873 | do { | ||
1874 | file = playlist_peek(steps, name_buf, sizeof(name_buf)); | ||
1875 | if(!file) | ||
1876 | break; | ||
1877 | if(mp3info(&taginfo, file)) { | ||
1878 | steps--; | ||
1879 | continue; | ||
1880 | } | ||
1881 | playlist_next(steps); | ||
1882 | current_track_counter++; | ||
1883 | is_playing = true; | ||
1884 | playing = true; | ||
1885 | break; | ||
1886 | } while(1); | ||
1887 | #endif /* SIMULATOR */ | ||
1888 | } | ||
1889 | |||
1890 | void audio_ff_rewind(long newpos) | ||
1891 | { | ||
1892 | #ifndef SIMULATOR | ||
1893 | queue_post(&mpeg_queue, MPEG_FF_REWIND, newpos); | ||
1894 | #else /* SIMULATOR */ | ||
1895 | (void)newpos; | ||
1896 | #endif /* SIMULATOR */ | ||
1897 | } | ||
1898 | |||
1899 | void audio_flush_and_reload_tracks(void) | ||
1900 | { | ||
1901 | #ifndef SIMULATOR | ||
1902 | queue_post(&mpeg_queue, MPEG_FLUSH_RELOAD, 0); | ||
1903 | #endif /* !SIMULATOR*/ | ||
1904 | } | ||
1905 | |||
1906 | int audio_status(void) | ||
1907 | { | ||
1908 | int ret = 0; | ||
1909 | |||
1910 | if(is_playing) | ||
1911 | ret |= AUDIO_STATUS_PLAY; | ||
1912 | |||
1913 | if(paused) | ||
1914 | ret |= AUDIO_STATUS_PAUSE; | ||
1915 | |||
1916 | if(mpeg_errno) | ||
1917 | ret |= AUDIO_STATUS_ERROR; | ||
1918 | |||
1919 | return ret; | ||
1920 | } | ||
1921 | |||
1922 | /* Unused function | ||
1923 | unsigned int audio_error(void) | ||
1924 | { | ||
1925 | return mpeg_errno; | ||
1926 | } | ||
1927 | */ | ||
1928 | |||
1929 | void audio_error_clear(void) | ||
1930 | { | ||
1931 | mpeg_errno = 0; | ||
1932 | } | ||
1933 | |||
1934 | #ifdef SIMULATOR | ||
1935 | static void mpeg_thread(void) | ||
1936 | { | ||
1937 | struct mp3entry* id3; | ||
1938 | while ( 1 ) { | ||
1939 | if (is_playing) { | ||
1940 | id3 = audio_current_track(); | ||
1941 | if (!paused) | ||
1942 | { | ||
1943 | id3->elapsed+=1000; | ||
1944 | id3->offset+=1000; | ||
1945 | } | ||
1946 | if (id3->elapsed>=id3->length) | ||
1947 | audio_next(); | ||
1948 | } | ||
1949 | sleep(HZ); | ||
1950 | } | ||
1951 | } | ||
1952 | #endif /* SIMULATOR */ | ||
1953 | |||
1954 | void audio_init(void) | ||
1955 | { | ||
1956 | mpeg_errno = 0; | ||
1957 | |||
1958 | audio_reset_buffer(); | ||
1959 | |||
1960 | #ifndef SIMULATOR | ||
1961 | queue_init(&mpeg_queue, true); | ||
1962 | #endif /* !SIMULATOR */ | ||
1963 | audio_thread_id = create_thread(mpeg_thread, mpeg_stack, | ||
1964 | sizeof(mpeg_stack), 0, mpeg_thread_name | ||
1965 | IF_PRIO(, PRIORITY_SYSTEM) | ||
1966 | IF_COP(, CPU)); | ||
1967 | |||
1968 | memset(trackdata, 0, sizeof(trackdata)); | ||
1969 | |||
1970 | #ifdef DEBUG | ||
1971 | #ifndef SIMULATOR | ||
1972 | dbg_timer_start(); | ||
1973 | dbg_cnt2us(0); | ||
1974 | #endif /* !SIMULATOR */ | ||
1975 | #endif /* DEBUG */ | ||
1976 | audio_is_initialized = true; | ||
1977 | } | ||
1978 | |||
1979 | #endif /* CONFIG_CODEC != SWCODEC */ | ||