diff options
Diffstat (limited to 'firmware/mpeg.c')
-rw-r--r-- | firmware/mpeg.c | 2872 |
1 files changed, 0 insertions, 2872 deletions
diff --git a/firmware/mpeg.c b/firmware/mpeg.c deleted file mode 100644 index 2503ba11e0..0000000000 --- a/firmware/mpeg.c +++ /dev/null | |||
@@ -1,2872 +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 "id3.h" | ||
30 | #include "mpeg.h" | ||
31 | #include "audio.h" | ||
32 | #include "ata.h" | ||
33 | #include "string.h" | ||
34 | #include <kernel.h> | ||
35 | #include "thread.h" | ||
36 | #include "errno.h" | ||
37 | #include "mp3data.h" | ||
38 | #include "buffer.h" | ||
39 | #include "mp3_playback.h" | ||
40 | #include "sound.h" | ||
41 | #include "bitswap.h" | ||
42 | #include "events.h" | ||
43 | #ifndef SIMULATOR | ||
44 | #include "i2c.h" | ||
45 | #include "mas.h" | ||
46 | #include "dac.h" | ||
47 | #include "system.h" | ||
48 | #include "usb.h" | ||
49 | #include "file.h" | ||
50 | #include "hwcompat.h" | ||
51 | #endif /* !SIMULATOR */ | ||
52 | #ifdef HAVE_LCD_BITMAP | ||
53 | #include "lcd.h" | ||
54 | #endif | ||
55 | |||
56 | #ifndef SIMULATOR | ||
57 | extern unsigned long mas_version_code; | ||
58 | #endif | ||
59 | |||
60 | #if CONFIG_CODEC == MAS3587F | ||
61 | extern enum /* from mp3_playback.c */ | ||
62 | { | ||
63 | MPEG_DECODER, | ||
64 | MPEG_ENCODER | ||
65 | } mpeg_mode; | ||
66 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
67 | |||
68 | extern char* playlist_peek(int steps); | ||
69 | extern bool playlist_check(int steps); | ||
70 | extern int playlist_next(int steps); | ||
71 | extern int playlist_amount(void); | ||
72 | extern int playlist_update_resume_info(const struct mp3entry* id3); | ||
73 | |||
74 | #define MPEG_PLAY 1 | ||
75 | #define MPEG_STOP 2 | ||
76 | #define MPEG_PAUSE 3 | ||
77 | #define MPEG_RESUME 4 | ||
78 | #define MPEG_NEXT 5 | ||
79 | #define MPEG_PREV 6 | ||
80 | #define MPEG_FF_REWIND 7 | ||
81 | #define MPEG_FLUSH_RELOAD 8 | ||
82 | #define MPEG_RECORD 9 | ||
83 | #define MPEG_INIT_RECORDING 10 | ||
84 | #define MPEG_INIT_PLAYBACK 11 | ||
85 | #define MPEG_NEW_FILE 12 | ||
86 | #define MPEG_PAUSE_RECORDING 13 | ||
87 | #define MPEG_RESUME_RECORDING 14 | ||
88 | #define MPEG_NEED_DATA 100 | ||
89 | #define MPEG_TRACK_CHANGE 101 | ||
90 | #define MPEG_SAVE_DATA 102 | ||
91 | #define MPEG_STOP_DONE 103 | ||
92 | #define MPEG_PRERECORDING_TICK 104 | ||
93 | |||
94 | /* indicator for MPEG_NEED_DATA */ | ||
95 | #define GENERATE_UNBUFFER_EVENTS 1 | ||
96 | |||
97 | /* list of tracks in memory */ | ||
98 | #define MAX_TRACK_ENTRIES (1<<4) /* Must be power of 2 */ | ||
99 | #define MAX_TRACK_ENTRIES_MASK (MAX_TRACK_ENTRIES - 1) | ||
100 | |||
101 | struct trackdata | ||
102 | { | ||
103 | struct mp3entry id3; | ||
104 | int mempos; | ||
105 | int load_ahead_index; | ||
106 | }; | ||
107 | |||
108 | static struct trackdata trackdata[MAX_TRACK_ENTRIES]; | ||
109 | |||
110 | static unsigned int current_track_counter = 0; | ||
111 | static unsigned int last_track_counter = 0; | ||
112 | |||
113 | /* Play time of the previous track */ | ||
114 | unsigned long prev_track_elapsed; | ||
115 | |||
116 | #ifndef SIMULATOR | ||
117 | static int track_read_idx = 0; | ||
118 | static int track_write_idx = 0; | ||
119 | #endif /* !SIMULATOR */ | ||
120 | |||
121 | /* Cuesheet callback */ | ||
122 | static bool (*cuesheet_callback)(const char *filename) = NULL; | ||
123 | |||
124 | static const char mpeg_thread_name[] = "mpeg"; | ||
125 | static unsigned int mpeg_errno; | ||
126 | |||
127 | static bool playing = false; /* We are playing an MP3 stream */ | ||
128 | static bool is_playing = false; /* We are (attempting to) playing MP3 files */ | ||
129 | static bool paused; /* playback is paused */ | ||
130 | |||
131 | #ifdef SIMULATOR | ||
132 | static char mpeg_stack[DEFAULT_STACK_SIZE]; | ||
133 | static struct mp3entry taginfo; | ||
134 | |||
135 | #else /* !SIMULATOR */ | ||
136 | static struct event_queue mpeg_queue; | ||
137 | static long mpeg_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; | ||
138 | |||
139 | static int audiobuflen; | ||
140 | static int audiobuf_write; | ||
141 | static int audiobuf_swapwrite; | ||
142 | static int audiobuf_read; | ||
143 | |||
144 | static int mpeg_file; | ||
145 | |||
146 | static bool play_pending; /* We are about to start playing */ | ||
147 | static bool play_pending_track_change; /* When starting play we're starting a new file */ | ||
148 | static bool filling; /* We are filling the buffer with data from disk */ | ||
149 | static bool dma_underrun; /* True when the DMA has stopped because of | ||
150 | slow disk reading (read error, shaking) */ | ||
151 | static bool mpeg_stop_done; | ||
152 | |||
153 | static int last_dma_tick = 0; | ||
154 | static int last_dma_chunk_size; | ||
155 | |||
156 | static long low_watermark; /* Dynamic low watermark level */ | ||
157 | static long low_watermark_margin = 0; /* Extra time in seconds for watermark */ | ||
158 | static long lowest_watermark_level; /* Debug value to observe the buffer | ||
159 | usage */ | ||
160 | #if CONFIG_CODEC == MAS3587F | ||
161 | static char recording_filename[MAX_PATH]; /* argument to thread */ | ||
162 | static char delayed_filename[MAX_PATH]; /* internal copy of above */ | ||
163 | |||
164 | static char xing_buffer[MAX_XING_HEADER_SIZE]; | ||
165 | |||
166 | static bool init_recording_done; | ||
167 | static bool init_playback_done; | ||
168 | static bool prerecording; /* True if prerecording is enabled */ | ||
169 | static bool is_prerecording; /* True if we are prerecording */ | ||
170 | static bool is_recording; /* We are recording */ | ||
171 | |||
172 | static enum { | ||
173 | NOT_SAVING = 0, /* reasons to save data, sorted by importance */ | ||
174 | BUFFER_FULL, | ||
175 | NEW_FILE, | ||
176 | STOP_RECORDING | ||
177 | } saving_status; | ||
178 | |||
179 | static int rec_frequency_index; /* For create_xing_header() calls */ | ||
180 | static int rec_version_index; /* For create_xing_header() calls */ | ||
181 | |||
182 | struct prerecord_info { | ||
183 | int mempos; | ||
184 | unsigned long framecount; | ||
185 | }; | ||
186 | |||
187 | static struct prerecord_info prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS]; | ||
188 | static int prerecord_index; /* Current index in the prerecord buffer */ | ||
189 | static int prerecording_max_seconds; /* Max number of seconds to store */ | ||
190 | static int prerecord_count; /* Number of seconds in the prerecord buffer */ | ||
191 | static int prerecord_timeout; /* The tick count of the next prerecord data | ||
192 | store */ | ||
193 | |||
194 | unsigned long record_start_time; /* Value of current_tick when recording | ||
195 | was started */ | ||
196 | unsigned long pause_start_time; /* Value of current_tick when pause was | ||
197 | started */ | ||
198 | static unsigned long last_rec_time; | ||
199 | static unsigned long num_rec_bytes; | ||
200 | static unsigned long last_rec_bytes; | ||
201 | static unsigned long frame_count_start; | ||
202 | static unsigned long frame_count_end; | ||
203 | static unsigned long saved_header = 0; | ||
204 | |||
205 | /* Shadow MAS registers */ | ||
206 | unsigned long shadow_encoder_control = 0; | ||
207 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
208 | |||
209 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
210 | unsigned long shadow_io_control_main = 0; | ||
211 | unsigned long shadow_soft_mute = 0; | ||
212 | unsigned shadow_codec_reg0; | ||
213 | #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ | ||
214 | |||
215 | #ifdef HAVE_RECORDING | ||
216 | static const unsigned char empty_id3_header[] = | ||
217 | { | ||
218 | 'I', 'D', '3', 0x03, 0x00, 0x00, | ||
219 | 0x00, 0x00, 0x1f, 0x76 /* Size is 4096 minus 10 bytes for the header */ | ||
220 | }; | ||
221 | #endif /* HAVE_RECORDING */ | ||
222 | |||
223 | |||
224 | static int get_unplayed_space(void); | ||
225 | static int get_playable_space(void); | ||
226 | static int get_unswapped_space(void); | ||
227 | #endif /* !SIMULATOR */ | ||
228 | |||
229 | #if (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR) | ||
230 | static void init_recording(void); | ||
231 | static void prepend_header(void); | ||
232 | static void update_header(void); | ||
233 | static void start_prerecording(void); | ||
234 | static void start_recording(void); | ||
235 | static void stop_recording(void); | ||
236 | static int get_unsaved_space(void); | ||
237 | static void pause_recording(void); | ||
238 | static void resume_recording(void); | ||
239 | #endif /* (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR) */ | ||
240 | |||
241 | |||
242 | #ifndef SIMULATOR | ||
243 | static int num_tracks_in_memory(void) | ||
244 | { | ||
245 | return (track_write_idx - track_read_idx) & MAX_TRACK_ENTRIES_MASK; | ||
246 | } | ||
247 | |||
248 | #ifdef DEBUG_TAGS | ||
249 | static void debug_tags(void) | ||
250 | { | ||
251 | int i; | ||
252 | |||
253 | for(i = 0;i < MAX_TRACK_ENTRIES;i++) | ||
254 | { | ||
255 | DEBUGF("%d - %s\n", i, trackdata[i].id3.path); | ||
256 | } | ||
257 | DEBUGF("read: %d, write :%d\n", track_read_idx, track_write_idx); | ||
258 | DEBUGF("num_tracks_in_memory: %d\n", num_tracks_in_memory()); | ||
259 | } | ||
260 | #else /* !DEBUG_TAGS */ | ||
261 | #define debug_tags() | ||
262 | #endif /* !DEBUG_TAGS */ | ||
263 | |||
264 | static void remove_current_tag(void) | ||
265 | { | ||
266 | if(num_tracks_in_memory() > 0) | ||
267 | { | ||
268 | /* First move the index, so nobody tries to access the tag */ | ||
269 | track_read_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK; | ||
270 | debug_tags(); | ||
271 | } | ||
272 | else | ||
273 | { | ||
274 | DEBUGF("remove_current_tag: no tracks to remove\n"); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | static void remove_all_non_current_tags(void) | ||
279 | { | ||
280 | track_write_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK; | ||
281 | debug_tags(); | ||
282 | } | ||
283 | |||
284 | static void remove_all_tags(void) | ||
285 | { | ||
286 | track_write_idx = track_read_idx; | ||
287 | |||
288 | debug_tags(); | ||
289 | } | ||
290 | |||
291 | static struct trackdata *get_trackdata(int offset) | ||
292 | { | ||
293 | if(offset >= num_tracks_in_memory()) | ||
294 | return NULL; | ||
295 | else | ||
296 | return &trackdata[(track_read_idx + offset) & MAX_TRACK_ENTRIES_MASK]; | ||
297 | } | ||
298 | #endif /* !SIMULATOR */ | ||
299 | |||
300 | /***********************************************************************/ | ||
301 | /* audio event handling */ | ||
302 | |||
303 | #define MAX_EVENT_HANDLERS 10 | ||
304 | struct event_handlers_table | ||
305 | { | ||
306 | AUDIO_EVENT_HANDLER handler; | ||
307 | unsigned short mask; | ||
308 | }; | ||
309 | static struct event_handlers_table event_handlers[MAX_EVENT_HANDLERS]; | ||
310 | static int event_handlers_count = 0; | ||
311 | |||
312 | void audio_register_event_handler(AUDIO_EVENT_HANDLER handler, unsigned short mask) | ||
313 | { | ||
314 | if (event_handlers_count < MAX_EVENT_HANDLERS) | ||
315 | { | ||
316 | event_handlers[event_handlers_count].handler = handler; | ||
317 | event_handlers[event_handlers_count].mask = mask; | ||
318 | event_handlers_count++; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | /* dispatch calls each handler in the order registered and returns after some | ||
323 | handler actually handles the event (the event is assumed to no longer be valid | ||
324 | after this, due to the handler changing some condition); returns true if someone | ||
325 | handled the event, which is expected to cause the caller to skip its own handling | ||
326 | of the event */ | ||
327 | #ifndef SIMULATOR | ||
328 | static bool audio_dispatch_event(unsigned short event, unsigned long data) | ||
329 | { | ||
330 | int i = 0; | ||
331 | for(i=0; i < event_handlers_count; i++) | ||
332 | { | ||
333 | if ( event_handlers[i].mask & event ) | ||
334 | { | ||
335 | int rc = event_handlers[i].handler(event, data); | ||
336 | if ( rc == AUDIO_EVENT_RC_HANDLED ) | ||
337 | return true; | ||
338 | } | ||
339 | } | ||
340 | return false; | ||
341 | } | ||
342 | #endif | ||
343 | |||
344 | /***********************************************************************/ | ||
345 | |||
346 | static void set_elapsed(struct mp3entry* id3) | ||
347 | { | ||
348 | if ( id3->vbr ) { | ||
349 | if ( id3->has_toc ) { | ||
350 | /* calculate elapsed time using TOC */ | ||
351 | int i; | ||
352 | unsigned int remainder, plen, relpos, nextpos; | ||
353 | |||
354 | /* find wich percent we're at */ | ||
355 | for (i=0; i<100; i++ ) | ||
356 | { | ||
357 | if ( id3->offset < id3->toc[i] * (id3->filesize / 256) ) | ||
358 | { | ||
359 | break; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | i--; | ||
364 | if (i < 0) | ||
365 | i = 0; | ||
366 | |||
367 | relpos = id3->toc[i]; | ||
368 | |||
369 | if (i < 99) | ||
370 | { | ||
371 | nextpos = id3->toc[i+1]; | ||
372 | } | ||
373 | else | ||
374 | { | ||
375 | nextpos = 256; | ||
376 | } | ||
377 | |||
378 | remainder = id3->offset - (relpos * (id3->filesize / 256)); | ||
379 | |||
380 | /* set time for this percent (divide before multiply to prevent | ||
381 | overflow on long files. loss of precision is negligible on | ||
382 | short files) */ | ||
383 | id3->elapsed = i * (id3->length / 100); | ||
384 | |||
385 | /* calculate remainder time */ | ||
386 | plen = (nextpos - relpos) * (id3->filesize / 256); | ||
387 | id3->elapsed += (((remainder * 100) / plen) * | ||
388 | (id3->length / 10000)); | ||
389 | } | ||
390 | else { | ||
391 | /* no TOC exists. set a rough estimate using average bitrate */ | ||
392 | int tpk = id3->length / (id3->filesize / 1024); | ||
393 | id3->elapsed = id3->offset / 1024 * tpk; | ||
394 | } | ||
395 | } | ||
396 | else | ||
397 | /* constant bitrate, use exact calculation */ | ||
398 | id3->elapsed = id3->offset / (id3->bitrate / 8); | ||
399 | } | ||
400 | |||
401 | int audio_get_file_pos(void) | ||
402 | { | ||
403 | int pos = -1; | ||
404 | struct mp3entry *id3 = audio_current_track(); | ||
405 | |||
406 | if (id3->vbr) | ||
407 | { | ||
408 | if (id3->has_toc) | ||
409 | { | ||
410 | /* Use the TOC to find the new position */ | ||
411 | unsigned int percent, remainder; | ||
412 | int curtoc, nexttoc, plen; | ||
413 | |||
414 | percent = (id3->elapsed*100)/id3->length; | ||
415 | if (percent > 99) | ||
416 | percent = 99; | ||
417 | |||
418 | curtoc = id3->toc[percent]; | ||
419 | |||
420 | if (percent < 99) | ||
421 | nexttoc = id3->toc[percent+1]; | ||
422 | else | ||
423 | nexttoc = 256; | ||
424 | |||
425 | pos = (id3->filesize/256)*curtoc; | ||
426 | |||
427 | /* Use the remainder to get a more accurate position */ | ||
428 | remainder = (id3->elapsed*100)%id3->length; | ||
429 | remainder = (remainder*100)/id3->length; | ||
430 | plen = (nexttoc - curtoc)*(id3->filesize/256); | ||
431 | pos += (plen/100)*remainder; | ||
432 | } | ||
433 | else | ||
434 | { | ||
435 | /* No TOC exists, estimate the new position */ | ||
436 | pos = (id3->filesize / (id3->length / 1000)) * | ||
437 | (id3->elapsed / 1000); | ||
438 | } | ||
439 | } | ||
440 | else if (id3->bitrate) | ||
441 | pos = id3->elapsed * (id3->bitrate / 8); | ||
442 | else | ||
443 | { | ||
444 | return -1; | ||
445 | } | ||
446 | |||
447 | if (pos >= (int)(id3->filesize - id3->id3v1len)) | ||
448 | { | ||
449 | /* Don't seek right to the end of the file so that we can | ||
450 | transition properly to the next song */ | ||
451 | pos = id3->filesize - id3->id3v1len - 1; | ||
452 | } | ||
453 | else if (pos < (int)id3->first_frame_offset) | ||
454 | { | ||
455 | /* skip past id3v2 tag and other leading garbage */ | ||
456 | pos = id3->first_frame_offset; | ||
457 | } | ||
458 | return pos; | ||
459 | } | ||
460 | |||
461 | unsigned long mpeg_get_last_header(void) | ||
462 | { | ||
463 | #ifdef SIMULATOR | ||
464 | return 0; | ||
465 | #else /* !SIMULATOR */ | ||
466 | unsigned long tmp[2]; | ||
467 | |||
468 | /* Read the frame data from the MAS and reconstruct it with the | ||
469 | frame sync and all */ | ||
470 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_STATUS_1, tmp, 2); | ||
471 | return 0xffe00000 | ((tmp[0] & 0x7c00) << 6) | (tmp[1] & 0xffff); | ||
472 | #endif /* !SIMULATOR */ | ||
473 | } | ||
474 | |||
475 | void audio_set_cuesheet_callback(bool (*handler)(const char *filename)) | ||
476 | { | ||
477 | cuesheet_callback = handler; | ||
478 | } | ||
479 | |||
480 | #ifndef SIMULATOR | ||
481 | /* Send callback events to notify about removing old tracks. */ | ||
482 | static void generate_unbuffer_events(void) | ||
483 | { | ||
484 | int i; | ||
485 | int numentries = MAX_TRACK_ENTRIES - num_tracks_in_memory(); | ||
486 | int cur_idx = track_write_idx; | ||
487 | |||
488 | for (i = 0; i < numentries; i++) | ||
489 | { | ||
490 | /* Send an event to notify that track has finished. */ | ||
491 | send_event(PLAYBACK_EVENT_TRACK_FINISH, &trackdata[cur_idx].id3); | ||
492 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | /* Send callback events to notify about new tracks. */ | ||
497 | static void generate_postbuffer_events(void) | ||
498 | { | ||
499 | int i; | ||
500 | int numentries = num_tracks_in_memory(); | ||
501 | int cur_idx = track_read_idx; | ||
502 | |||
503 | for (i = 0; i < numentries; i++) | ||
504 | { | ||
505 | send_event(PLAYBACK_EVENT_TRACK_BUFFER, &trackdata[cur_idx].id3); | ||
506 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | ||
507 | } | ||
508 | } | ||
509 | |||
510 | static void recalculate_watermark(int bitrate) | ||
511 | { | ||
512 | int bytes_per_sec; | ||
513 | int time = ata_spinup_time; | ||
514 | |||
515 | /* A bitrate of 0 probably means empty VBR header. We play safe | ||
516 | and set a high threshold */ | ||
517 | if(bitrate == 0) | ||
518 | bitrate = 320; | ||
519 | |||
520 | bytes_per_sec = bitrate * 1000 / 8; | ||
521 | |||
522 | if(time) | ||
523 | { | ||
524 | /* No drive spins up faster than 3.5s */ | ||
525 | if(time < 350) | ||
526 | time = 350; | ||
527 | |||
528 | time = time * 3; | ||
529 | low_watermark = ((low_watermark_margin * HZ + time) * | ||
530 | bytes_per_sec) / HZ; | ||
531 | } | ||
532 | else | ||
533 | { | ||
534 | low_watermark = MPEG_LOW_WATER; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | #ifdef HAVE_DISK_STORAGE | ||
539 | void audio_set_buffer_margin(int seconds) | ||
540 | { | ||
541 | low_watermark_margin = seconds; | ||
542 | } | ||
543 | #endif | ||
544 | |||
545 | void audio_get_debugdata(struct audio_debug *dbgdata) | ||
546 | { | ||
547 | dbgdata->audiobuflen = audiobuflen; | ||
548 | dbgdata->audiobuf_write = audiobuf_write; | ||
549 | dbgdata->audiobuf_swapwrite = audiobuf_swapwrite; | ||
550 | dbgdata->audiobuf_read = audiobuf_read; | ||
551 | |||
552 | dbgdata->last_dma_chunk_size = last_dma_chunk_size; | ||
553 | |||
554 | #if CONFIG_CPU == SH7034 | ||
555 | dbgdata->dma_on = (SCR0 & 0x80) != 0; | ||
556 | #endif | ||
557 | dbgdata->playing = playing; | ||
558 | dbgdata->play_pending = play_pending; | ||
559 | dbgdata->is_playing = is_playing; | ||
560 | dbgdata->filling = filling; | ||
561 | dbgdata->dma_underrun = dma_underrun; | ||
562 | |||
563 | dbgdata->unplayed_space = get_unplayed_space(); | ||
564 | dbgdata->playable_space = get_playable_space(); | ||
565 | dbgdata->unswapped_space = get_unswapped_space(); | ||
566 | |||
567 | dbgdata->low_watermark_level = low_watermark; | ||
568 | dbgdata->lowest_watermark_level = lowest_watermark_level; | ||
569 | } | ||
570 | |||
571 | #ifdef DEBUG | ||
572 | static void dbg_timer_start(void) | ||
573 | { | ||
574 | /* We are using timer 2 */ | ||
575 | |||
576 | TSTR &= ~0x04; /* Stop the timer */ | ||
577 | TSNC &= ~0x04; /* No synchronization */ | ||
578 | TMDR &= ~0x44; /* Operate normally */ | ||
579 | |||
580 | TCNT2 = 0; /* Start counting at 0 */ | ||
581 | TCR2 = 0x03; /* Sysclock/8 */ | ||
582 | |||
583 | TSTR |= 0x04; /* Start timer 2 */ | ||
584 | } | ||
585 | |||
586 | static int dbg_cnt2us(unsigned int cnt) | ||
587 | { | ||
588 | return (cnt * 10000) / (FREQ/800); | ||
589 | } | ||
590 | #endif /* DEBUG */ | ||
591 | |||
592 | static int get_unplayed_space(void) | ||
593 | { | ||
594 | int space = audiobuf_write - audiobuf_read; | ||
595 | if (space < 0) | ||
596 | space += audiobuflen; | ||
597 | return space; | ||
598 | } | ||
599 | |||
600 | static int get_playable_space(void) | ||
601 | { | ||
602 | int space = audiobuf_swapwrite - audiobuf_read; | ||
603 | if (space < 0) | ||
604 | space += audiobuflen; | ||
605 | return space; | ||
606 | } | ||
607 | |||
608 | static int get_unplayed_space_current_song(void) | ||
609 | { | ||
610 | int space; | ||
611 | |||
612 | if (num_tracks_in_memory() > 1) | ||
613 | { | ||
614 | space = get_trackdata(1)->mempos - audiobuf_read; | ||
615 | } | ||
616 | else | ||
617 | { | ||
618 | space = audiobuf_write - audiobuf_read; | ||
619 | } | ||
620 | |||
621 | if (space < 0) | ||
622 | space += audiobuflen; | ||
623 | |||
624 | return space; | ||
625 | } | ||
626 | |||
627 | static int get_unswapped_space(void) | ||
628 | { | ||
629 | int space = audiobuf_write - audiobuf_swapwrite; | ||
630 | if (space < 0) | ||
631 | space += audiobuflen; | ||
632 | return space; | ||
633 | } | ||
634 | |||
635 | #if CONFIG_CODEC == MAS3587F | ||
636 | static int get_unsaved_space(void) | ||
637 | { | ||
638 | int space = audiobuf_write - audiobuf_read; | ||
639 | if (space < 0) | ||
640 | space += audiobuflen; | ||
641 | return space; | ||
642 | } | ||
643 | |||
644 | static void drain_dma_buffer(void) | ||
645 | { | ||
646 | while (PBDRH & 0x40) | ||
647 | { | ||
648 | xor_b(0x08, &PADRH); | ||
649 | |||
650 | while (PBDRH & 0x80); | ||
651 | |||
652 | xor_b(0x08, &PADRH); | ||
653 | |||
654 | while (!(PBDRH & 0x80)); | ||
655 | } | ||
656 | } | ||
657 | |||
658 | #ifdef DEBUG | ||
659 | static long timing_info_index = 0; | ||
660 | static long timing_info[1024]; | ||
661 | #endif /* DEBUG */ | ||
662 | |||
663 | void rec_tick (void) __attribute__ ((section (".icode"))); | ||
664 | void rec_tick(void) | ||
665 | { | ||
666 | int i; | ||
667 | int delay; | ||
668 | char data; | ||
669 | |||
670 | if(is_recording && (PBDRH & 0x40)) | ||
671 | { | ||
672 | #ifdef DEBUG | ||
673 | timing_info[timing_info_index++] = current_tick; | ||
674 | TCNT2 = 0; | ||
675 | #endif /* DEBUG */ | ||
676 | /* Note: Although this loop is run in interrupt context, further | ||
677 | * optimisation will do no good. The MAS would then deliver bad | ||
678 | * frames occasionally, as observed in extended experiments. */ | ||
679 | i = 0; | ||
680 | while (PBDRH & 0x40) /* We try to read as long as EOD is high */ | ||
681 | { | ||
682 | xor_b(0x08, &PADRH); /* Set PR active, independent of polarity */ | ||
683 | |||
684 | delay = 100; | ||
685 | while (PBDRH & 0x80) /* Wait until /RTW becomes active */ | ||
686 | { | ||
687 | if (--delay <= 0) /* Bail out if we have to wait too long */ | ||
688 | { /* i.e. the MAS doesn't want to talk to us */ | ||
689 | xor_b(0x08, &PADRH); /* Set PR inactive */ | ||
690 | goto transfer_end; /* and get out of here */ | ||
691 | } | ||
692 | } | ||
693 | |||
694 | data = *(unsigned char *)0x04000000; /* read data byte */ | ||
695 | |||
696 | xor_b(0x08, &PADRH); /* Set PR inactive */ | ||
697 | |||
698 | audiobuf[audiobuf_write++] = data; | ||
699 | |||
700 | if (audiobuf_write >= audiobuflen) | ||
701 | audiobuf_write = 0; | ||
702 | |||
703 | i++; | ||
704 | } | ||
705 | transfer_end: | ||
706 | |||
707 | #ifdef DEBUG | ||
708 | timing_info[timing_info_index++] = TCNT2 + (i << 16); | ||
709 | timing_info_index &= 0x3ff; | ||
710 | #endif /* DEBUG */ | ||
711 | |||
712 | num_rec_bytes += i; | ||
713 | |||
714 | if(is_prerecording) | ||
715 | { | ||
716 | if(TIME_AFTER(current_tick, prerecord_timeout)) | ||
717 | { | ||
718 | prerecord_timeout = current_tick + HZ; | ||
719 | queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0); | ||
720 | } | ||
721 | } | ||
722 | else | ||
723 | { | ||
724 | /* Signal to save the data if we are running out of buffer | ||
725 | space */ | ||
726 | if (audiobuflen - get_unsaved_space() < MPEG_RECORDING_LOW_WATER | ||
727 | && saving_status == NOT_SAVING) | ||
728 | { | ||
729 | saving_status = BUFFER_FULL; | ||
730 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
731 | } | ||
732 | } | ||
733 | } | ||
734 | } | ||
735 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
736 | |||
737 | void playback_tick(void) | ||
738 | { | ||
739 | struct trackdata *ptd = get_trackdata(0); | ||
740 | if(ptd) | ||
741 | { | ||
742 | ptd->id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ; | ||
743 | last_dma_tick = current_tick; | ||
744 | audio_dispatch_event(AUDIO_EVENT_POS_REPORT, | ||
745 | (unsigned long)ptd->id3.elapsed); | ||
746 | } | ||
747 | } | ||
748 | |||
749 | static void reset_mp3_buffer(void) | ||
750 | { | ||
751 | audiobuf_read = 0; | ||
752 | audiobuf_write = 0; | ||
753 | audiobuf_swapwrite = 0; | ||
754 | lowest_watermark_level = audiobuflen; | ||
755 | } | ||
756 | |||
757 | /* DMA transfer end interrupt callback */ | ||
758 | static void transfer_end(unsigned char** ppbuf, size_t* psize) | ||
759 | { | ||
760 | if(playing && !paused) | ||
761 | { | ||
762 | int unplayed_space_left; | ||
763 | int space_until_end_of_buffer; | ||
764 | int track_offset = 1; | ||
765 | struct trackdata *track; | ||
766 | |||
767 | audiobuf_read += last_dma_chunk_size; | ||
768 | if(audiobuf_read >= audiobuflen) | ||
769 | audiobuf_read = 0; | ||
770 | |||
771 | /* First, check if we are on a track boundary */ | ||
772 | if (num_tracks_in_memory() > 1) | ||
773 | { | ||
774 | if (audiobuf_read == get_trackdata(track_offset)->mempos) | ||
775 | { | ||
776 | if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) ) | ||
777 | { | ||
778 | queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); | ||
779 | track_offset++; | ||
780 | } | ||
781 | } | ||
782 | } | ||
783 | |||
784 | unplayed_space_left = get_unplayed_space(); | ||
785 | |||
786 | space_until_end_of_buffer = audiobuflen - audiobuf_read; | ||
787 | |||
788 | if(!filling && unplayed_space_left < low_watermark) | ||
789 | { | ||
790 | filling = true; | ||
791 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); | ||
792 | } | ||
793 | |||
794 | if(unplayed_space_left) | ||
795 | { | ||
796 | last_dma_chunk_size = MIN(0x2000, unplayed_space_left); | ||
797 | last_dma_chunk_size = MIN(last_dma_chunk_size, | ||
798 | space_until_end_of_buffer); | ||
799 | |||
800 | /* several tracks loaded? */ | ||
801 | track = get_trackdata(track_offset); | ||
802 | if(track) | ||
803 | { | ||
804 | /* will we move across the track boundary? */ | ||
805 | if (( audiobuf_read < track->mempos ) && | ||
806 | ((audiobuf_read+last_dma_chunk_size) > | ||
807 | track->mempos )) | ||
808 | { | ||
809 | /* Make sure that we end exactly on the boundary */ | ||
810 | last_dma_chunk_size = track->mempos - audiobuf_read; | ||
811 | } | ||
812 | } | ||
813 | |||
814 | *psize = last_dma_chunk_size & 0xffff; | ||
815 | *ppbuf = audiobuf + audiobuf_read; | ||
816 | track = get_trackdata(0); | ||
817 | if(track) | ||
818 | track->id3.offset += last_dma_chunk_size; | ||
819 | |||
820 | /* Update the watermark debug level */ | ||
821 | if(unplayed_space_left < lowest_watermark_level) | ||
822 | lowest_watermark_level = unplayed_space_left; | ||
823 | } | ||
824 | else | ||
825 | { | ||
826 | /* Check if the end of data is because of a hard disk error. | ||
827 | If there is an open file handle, we are still playing music. | ||
828 | If not, the last file has been loaded, and the file handle is | ||
829 | closed. */ | ||
830 | if(mpeg_file >= 0) | ||
831 | { | ||
832 | /* Update the watermark debug level */ | ||
833 | if(unplayed_space_left < lowest_watermark_level) | ||
834 | lowest_watermark_level = unplayed_space_left; | ||
835 | |||
836 | DEBUGF("DMA underrun.\n"); | ||
837 | dma_underrun = true; | ||
838 | } | ||
839 | else | ||
840 | { | ||
841 | if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) ) | ||
842 | { | ||
843 | DEBUGF("No more MP3 data. Stopping.\n"); | ||
844 | queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); | ||
845 | playing = false; | ||
846 | } | ||
847 | } | ||
848 | *psize = 0; /* no more transfer */ | ||
849 | } | ||
850 | } | ||
851 | } | ||
852 | |||
853 | static struct trackdata *add_track_to_tag_list(const char *filename) | ||
854 | { | ||
855 | struct trackdata *track; | ||
856 | |||
857 | if(num_tracks_in_memory() >= MAX_TRACK_ENTRIES) | ||
858 | { | ||
859 | DEBUGF("Tag memory is full\n"); | ||
860 | return NULL; | ||
861 | } | ||
862 | |||
863 | track = &trackdata[track_write_idx]; | ||
864 | |||
865 | /* grab id3 tag of new file and | ||
866 | remember where in memory it starts */ | ||
867 | if(mp3info(&track->id3, filename)) | ||
868 | { | ||
869 | DEBUGF("Bad mp3\n"); | ||
870 | return NULL; | ||
871 | } | ||
872 | track->mempos = audiobuf_write; | ||
873 | track->id3.elapsed = 0; | ||
874 | #ifdef HAVE_LCD_BITMAP | ||
875 | if (track->id3.title) | ||
876 | lcd_getstringsize(track->id3.title, NULL, NULL); | ||
877 | if (track->id3.artist) | ||
878 | lcd_getstringsize(track->id3.artist, NULL, NULL); | ||
879 | if (track->id3.album) | ||
880 | lcd_getstringsize(track->id3.album, NULL, NULL); | ||
881 | #endif | ||
882 | if (cuesheet_callback) | ||
883 | if (cuesheet_callback(filename)) | ||
884 | track->id3.cuesheet_type = 1; | ||
885 | |||
886 | track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK; | ||
887 | debug_tags(); | ||
888 | return track; | ||
889 | } | ||
890 | |||
891 | static int new_file(int steps) | ||
892 | { | ||
893 | int max_steps = playlist_amount(); | ||
894 | int start = 0; | ||
895 | int i; | ||
896 | struct trackdata *track; | ||
897 | |||
898 | /* Find out how many steps to advance. The load_ahead_index field tells | ||
899 | us how many playlist entries it had to skip to get to a valid one. | ||
900 | We add those together to find out where to start. */ | ||
901 | if(steps > 0 && num_tracks_in_memory() > 1) | ||
902 | { | ||
903 | /* Begin with the song after the currently playing one */ | ||
904 | i = 1; | ||
905 | while((track = get_trackdata(i++))) | ||
906 | { | ||
907 | start += track->load_ahead_index; | ||
908 | } | ||
909 | } | ||
910 | |||
911 | do { | ||
912 | char *trackname; | ||
913 | |||
914 | trackname = playlist_peek( start + steps ); | ||
915 | if ( !trackname ) | ||
916 | return -1; | ||
917 | |||
918 | DEBUGF("Loading %s\n", trackname); | ||
919 | |||
920 | mpeg_file = open(trackname, O_RDONLY); | ||
921 | if(mpeg_file < 0) { | ||
922 | DEBUGF("Couldn't open file: %s\n",trackname); | ||
923 | if(steps < 0) | ||
924 | steps--; | ||
925 | else | ||
926 | steps++; | ||
927 | } | ||
928 | else | ||
929 | { | ||
930 | struct trackdata *track = add_track_to_tag_list(trackname); | ||
931 | |||
932 | if(!track) | ||
933 | { | ||
934 | /* Bad mp3 file */ | ||
935 | if(steps < 0) | ||
936 | steps--; | ||
937 | else | ||
938 | steps++; | ||
939 | close(mpeg_file); | ||
940 | mpeg_file = -1; | ||
941 | } | ||
942 | else | ||
943 | { | ||
944 | /* skip past id3v2 tag */ | ||
945 | lseek(mpeg_file, | ||
946 | track->id3.first_frame_offset, | ||
947 | SEEK_SET); | ||
948 | track->id3.index = steps; | ||
949 | track->load_ahead_index = steps; | ||
950 | track->id3.offset = 0; | ||
951 | |||
952 | if(track->id3.vbr) | ||
953 | /* Average bitrate * 1.5 */ | ||
954 | recalculate_watermark( | ||
955 | (track->id3.bitrate * 3) / 2); | ||
956 | else | ||
957 | recalculate_watermark( | ||
958 | track->id3.bitrate); | ||
959 | |||
960 | } | ||
961 | } | ||
962 | |||
963 | /* Bail out if no file could be opened */ | ||
964 | if(abs(steps) > max_steps) | ||
965 | return -1; | ||
966 | } while ( mpeg_file < 0 ); | ||
967 | |||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static void stop_playing(void) | ||
972 | { | ||
973 | struct trackdata *track; | ||
974 | |||
975 | /* Stop the current stream */ | ||
976 | mp3_play_stop(); | ||
977 | playing = false; | ||
978 | filling = false; | ||
979 | |||
980 | track = get_trackdata(0); | ||
981 | if (track != NULL) | ||
982 | prev_track_elapsed = track->id3.elapsed; | ||
983 | |||
984 | if(mpeg_file >= 0) | ||
985 | close(mpeg_file); | ||
986 | mpeg_file = -1; | ||
987 | remove_all_tags(); | ||
988 | generate_unbuffer_events(); | ||
989 | reset_mp3_buffer(); | ||
990 | } | ||
991 | |||
992 | static void end_current_track(void) { | ||
993 | struct trackdata *track; | ||
994 | |||
995 | play_pending = false; | ||
996 | playing = false; | ||
997 | mp3_play_pause(false); | ||
998 | |||
999 | track = get_trackdata(0); | ||
1000 | if (track != NULL) | ||
1001 | prev_track_elapsed = track->id3.elapsed; | ||
1002 | |||
1003 | reset_mp3_buffer(); | ||
1004 | remove_all_tags(); | ||
1005 | generate_unbuffer_events(); | ||
1006 | |||
1007 | if(mpeg_file >= 0) | ||
1008 | close(mpeg_file); | ||
1009 | } | ||
1010 | |||
1011 | /* Is this a really the end of playback or is a new playlist starting */ | ||
1012 | static void check_playlist_end(int direction) | ||
1013 | { | ||
1014 | /* Use the largest possible step size to account for skipped tracks */ | ||
1015 | int steps = playlist_amount(); | ||
1016 | |||
1017 | if (direction < 0) | ||
1018 | steps = -steps; | ||
1019 | |||
1020 | if (playlist_next(steps) < 0) | ||
1021 | is_playing = false; | ||
1022 | } | ||
1023 | |||
1024 | static void update_playlist(void) | ||
1025 | { | ||
1026 | if (num_tracks_in_memory() > 0) | ||
1027 | { | ||
1028 | struct trackdata *track = get_trackdata(0); | ||
1029 | track->id3.index = playlist_next(track->id3.index); | ||
1030 | } | ||
1031 | else | ||
1032 | { | ||
1033 | /* End of playlist? */ | ||
1034 | check_playlist_end(1); | ||
1035 | } | ||
1036 | |||
1037 | playlist_update_resume_info(audio_current_track()); | ||
1038 | } | ||
1039 | |||
1040 | static void track_change(void) | ||
1041 | { | ||
1042 | DEBUGF("Track change\n"); | ||
1043 | |||
1044 | struct trackdata *track = get_trackdata(0); | ||
1045 | prev_track_elapsed = track->id3.elapsed; | ||
1046 | |||
1047 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
1048 | /* Reset the AVC */ | ||
1049 | sound_set_avc(-1); | ||
1050 | #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */ | ||
1051 | |||
1052 | if (num_tracks_in_memory() > 0) | ||
1053 | { | ||
1054 | remove_current_tag(); | ||
1055 | send_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_current_track()); | ||
1056 | update_playlist(); | ||
1057 | } | ||
1058 | |||
1059 | current_track_counter++; | ||
1060 | } | ||
1061 | |||
1062 | unsigned long audio_prev_elapsed(void) | ||
1063 | { | ||
1064 | return prev_track_elapsed; | ||
1065 | } | ||
1066 | |||
1067 | #ifdef DEBUG | ||
1068 | void hexdump(const unsigned char *buf, int len) | ||
1069 | { | ||
1070 | int i; | ||
1071 | |||
1072 | for(i = 0;i < len;i++) | ||
1073 | { | ||
1074 | if(i && (i & 15) == 0) | ||
1075 | { | ||
1076 | DEBUGF("\n"); | ||
1077 | } | ||
1078 | DEBUGF("%02x ", buf[i]); | ||
1079 | } | ||
1080 | DEBUGF("\n"); | ||
1081 | } | ||
1082 | #endif /* DEBUG */ | ||
1083 | |||
1084 | static void start_playback_if_ready(void) | ||
1085 | { | ||
1086 | int playable_space; | ||
1087 | |||
1088 | playable_space = audiobuf_swapwrite - audiobuf_read; | ||
1089 | if(playable_space < 0) | ||
1090 | playable_space += audiobuflen; | ||
1091 | |||
1092 | /* See if we have started playing yet. If not, do it. */ | ||
1093 | if(play_pending || dma_underrun) | ||
1094 | { | ||
1095 | /* If the filling has stopped, and we still haven't reached | ||
1096 | the watermark, the file must be smaller than the | ||
1097 | watermark. We must still play it. */ | ||
1098 | if((playable_space >= MPEG_PLAY_PENDING_THRESHOLD) || | ||
1099 | !filling || dma_underrun) | ||
1100 | { | ||
1101 | DEBUGF("P\n"); | ||
1102 | if (play_pending) /* don't do this when recovering from DMA underrun */ | ||
1103 | { | ||
1104 | generate_postbuffer_events(); /* signal first track as buffered */ | ||
1105 | if (play_pending_track_change) | ||
1106 | { | ||
1107 | play_pending_track_change = false; | ||
1108 | send_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_current_track()); | ||
1109 | } | ||
1110 | play_pending = false; | ||
1111 | } | ||
1112 | playing = true; | ||
1113 | |||
1114 | last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); | ||
1115 | mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); | ||
1116 | dma_underrun = false; | ||
1117 | |||
1118 | if (!paused) | ||
1119 | { | ||
1120 | last_dma_tick = current_tick; | ||
1121 | mp3_play_pause(true); | ||
1122 | } | ||
1123 | |||
1124 | /* Tell ourselves that we need more data */ | ||
1125 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1126 | } | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | static bool swap_one_chunk(void) | ||
1131 | { | ||
1132 | int free_space_left; | ||
1133 | int amount_to_swap; | ||
1134 | |||
1135 | free_space_left = get_unswapped_space(); | ||
1136 | |||
1137 | if(free_space_left == 0 && !play_pending) | ||
1138 | return false; | ||
1139 | |||
1140 | /* Swap in larger chunks when the user is waiting for the playback | ||
1141 | to start, or when there is dangerously little playable data left */ | ||
1142 | if(play_pending) | ||
1143 | amount_to_swap = MIN(MPEG_PLAY_PENDING_SWAPSIZE, free_space_left); | ||
1144 | else | ||
1145 | { | ||
1146 | if(get_playable_space() < low_watermark) | ||
1147 | amount_to_swap = MIN(MPEG_LOW_WATER_SWAP_CHUNKSIZE, | ||
1148 | free_space_left); | ||
1149 | else | ||
1150 | amount_to_swap = MIN(MPEG_SWAP_CHUNKSIZE, free_space_left); | ||
1151 | } | ||
1152 | |||
1153 | if(audiobuf_write < audiobuf_swapwrite) | ||
1154 | amount_to_swap = MIN(audiobuflen - audiobuf_swapwrite, | ||
1155 | amount_to_swap); | ||
1156 | else | ||
1157 | amount_to_swap = MIN(audiobuf_write - audiobuf_swapwrite, | ||
1158 | amount_to_swap); | ||
1159 | |||
1160 | bitswap(audiobuf + audiobuf_swapwrite, amount_to_swap); | ||
1161 | |||
1162 | audiobuf_swapwrite += amount_to_swap; | ||
1163 | if(audiobuf_swapwrite >= audiobuflen) | ||
1164 | { | ||
1165 | audiobuf_swapwrite = 0; | ||
1166 | } | ||
1167 | |||
1168 | return true; | ||
1169 | } | ||
1170 | |||
1171 | static void mpeg_thread(void) | ||
1172 | { | ||
1173 | static int pause_tick = 0; | ||
1174 | static unsigned int pause_track = 0; | ||
1175 | struct queue_event ev; | ||
1176 | int len; | ||
1177 | int free_space_left; | ||
1178 | int unplayed_space_left; | ||
1179 | int amount_to_read; | ||
1180 | int t1, t2; | ||
1181 | int start_offset; | ||
1182 | #if CONFIG_CODEC == MAS3587F | ||
1183 | int amount_to_save; | ||
1184 | int save_endpos = 0; | ||
1185 | int rc; | ||
1186 | int level; | ||
1187 | long offset; | ||
1188 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
1189 | |||
1190 | is_playing = false; | ||
1191 | play_pending = false; | ||
1192 | playing = false; | ||
1193 | mpeg_file = -1; | ||
1194 | |||
1195 | while(1) | ||
1196 | { | ||
1197 | #if CONFIG_CODEC == MAS3587F | ||
1198 | if(mpeg_mode == MPEG_DECODER) | ||
1199 | { | ||
1200 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
1201 | yield(); | ||
1202 | |||
1203 | /* Swap if necessary, and don't block on the queue_wait() */ | ||
1204 | if(swap_one_chunk()) | ||
1205 | { | ||
1206 | queue_wait_w_tmo(&mpeg_queue, &ev, 0); | ||
1207 | } | ||
1208 | else if (playing) | ||
1209 | { | ||
1210 | /* periodically update resume info */ | ||
1211 | queue_wait_w_tmo(&mpeg_queue, &ev, HZ/2); | ||
1212 | } | ||
1213 | else | ||
1214 | { | ||
1215 | DEBUGF("S R:%x W:%x SW:%x\n", | ||
1216 | audiobuf_read, audiobuf_write, audiobuf_swapwrite); | ||
1217 | queue_wait(&mpeg_queue, &ev); | ||
1218 | } | ||
1219 | |||
1220 | start_playback_if_ready(); | ||
1221 | |||
1222 | switch(ev.id) | ||
1223 | { | ||
1224 | case MPEG_PLAY: | ||
1225 | DEBUGF("MPEG_PLAY\n"); | ||
1226 | |||
1227 | #if CONFIG_TUNER | ||
1228 | /* Silence the A/D input, it may be on because the radio | ||
1229 | may be playing */ | ||
1230 | mas_codec_writereg(6, 0x0000); | ||
1231 | #endif /* CONFIG_TUNER */ | ||
1232 | |||
1233 | /* Stop the current stream */ | ||
1234 | paused = false; | ||
1235 | end_current_track(); | ||
1236 | |||
1237 | if ( new_file(0) == -1 ) | ||
1238 | { | ||
1239 | is_playing = false; | ||
1240 | track_change(); | ||
1241 | break; | ||
1242 | } | ||
1243 | |||
1244 | start_offset = (int)ev.data; | ||
1245 | |||
1246 | /* mid-song resume? */ | ||
1247 | if (start_offset) { | ||
1248 | struct mp3entry* id3 = &get_trackdata(0)->id3; | ||
1249 | lseek(mpeg_file, start_offset, SEEK_SET); | ||
1250 | id3->offset = start_offset; | ||
1251 | set_elapsed(id3); | ||
1252 | } | ||
1253 | else { | ||
1254 | /* skip past id3v2 tag */ | ||
1255 | lseek(mpeg_file, | ||
1256 | get_trackdata(0)->id3.first_frame_offset, | ||
1257 | SEEK_SET); | ||
1258 | |||
1259 | } | ||
1260 | |||
1261 | /* Make it read more data */ | ||
1262 | filling = true; | ||
1263 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1264 | |||
1265 | /* Tell the file loading code that we want to start playing | ||
1266 | as soon as we have some data */ | ||
1267 | play_pending = true; | ||
1268 | play_pending_track_change = true; | ||
1269 | |||
1270 | update_playlist(); | ||
1271 | current_track_counter++; | ||
1272 | break; | ||
1273 | |||
1274 | case MPEG_STOP: | ||
1275 | DEBUGF("MPEG_STOP\n"); | ||
1276 | is_playing = false; | ||
1277 | paused = false; | ||
1278 | |||
1279 | if (playing) | ||
1280 | playlist_update_resume_info(audio_current_track()); | ||
1281 | |||
1282 | stop_playing(); | ||
1283 | mpeg_stop_done = true; | ||
1284 | break; | ||
1285 | |||
1286 | case MPEG_PAUSE: | ||
1287 | DEBUGF("MPEG_PAUSE\n"); | ||
1288 | /* Stop the current stream */ | ||
1289 | if (playing) | ||
1290 | playlist_update_resume_info(audio_current_track()); | ||
1291 | paused = true; | ||
1292 | playing = false; | ||
1293 | pause_tick = current_tick; | ||
1294 | pause_track = current_track_counter; | ||
1295 | mp3_play_pause(false); | ||
1296 | break; | ||
1297 | |||
1298 | case MPEG_RESUME: | ||
1299 | DEBUGF("MPEG_RESUME\n"); | ||
1300 | /* Continue the current stream */ | ||
1301 | paused = false; | ||
1302 | if (!play_pending) | ||
1303 | { | ||
1304 | playing = true; | ||
1305 | if ( current_track_counter == pause_track ) | ||
1306 | last_dma_tick += current_tick - pause_tick; | ||
1307 | else | ||
1308 | last_dma_tick = current_tick; | ||
1309 | pause_tick = 0; | ||
1310 | mp3_play_pause(true); | ||
1311 | } | ||
1312 | break; | ||
1313 | |||
1314 | case MPEG_NEXT: | ||
1315 | DEBUGF("MPEG_NEXT\n"); | ||
1316 | /* is next track in ram? */ | ||
1317 | if ( num_tracks_in_memory() > 1 ) { | ||
1318 | int unplayed_space_left, unswapped_space_left; | ||
1319 | |||
1320 | /* stop the current stream */ | ||
1321 | play_pending = false; | ||
1322 | playing = false; | ||
1323 | mp3_play_pause(false); | ||
1324 | |||
1325 | track_change(); | ||
1326 | audiobuf_read = get_trackdata(0)->mempos; | ||
1327 | last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); | ||
1328 | mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); | ||
1329 | dma_underrun = false; | ||
1330 | last_dma_tick = current_tick; | ||
1331 | |||
1332 | unplayed_space_left = get_unplayed_space(); | ||
1333 | unswapped_space_left = get_unswapped_space(); | ||
1334 | |||
1335 | /* should we start reading more data? */ | ||
1336 | if(!filling && (unplayed_space_left < low_watermark)) { | ||
1337 | filling = true; | ||
1338 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); | ||
1339 | play_pending = true; | ||
1340 | } else if(unswapped_space_left && | ||
1341 | unswapped_space_left > unplayed_space_left) { | ||
1342 | /* Stop swapping the data from the previous file */ | ||
1343 | audiobuf_swapwrite = audiobuf_read; | ||
1344 | play_pending = true; | ||
1345 | } else { | ||
1346 | playing = true; | ||
1347 | if (!paused) | ||
1348 | mp3_play_pause(true); | ||
1349 | } | ||
1350 | } | ||
1351 | else { | ||
1352 | if (!playlist_check(1)) | ||
1353 | break; | ||
1354 | |||
1355 | /* stop the current stream */ | ||
1356 | end_current_track(); | ||
1357 | |||
1358 | if (new_file(1) < 0) { | ||
1359 | DEBUGF("No more files to play\n"); | ||
1360 | filling = false; | ||
1361 | |||
1362 | check_playlist_end(1); | ||
1363 | current_track_counter++; | ||
1364 | } else { | ||
1365 | /* Make it read more data */ | ||
1366 | filling = true; | ||
1367 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1368 | |||
1369 | /* Tell the file loading code that we want | ||
1370 | to start playing as soon as we have some data */ | ||
1371 | play_pending = true; | ||
1372 | play_pending_track_change = true; | ||
1373 | |||
1374 | update_playlist(); | ||
1375 | current_track_counter++; | ||
1376 | } | ||
1377 | } | ||
1378 | break; | ||
1379 | |||
1380 | case MPEG_PREV: { | ||
1381 | DEBUGF("MPEG_PREV\n"); | ||
1382 | |||
1383 | if (!playlist_check(-1)) | ||
1384 | break; | ||
1385 | |||
1386 | /* stop the current stream */ | ||
1387 | end_current_track(); | ||
1388 | |||
1389 | /* Open the next file */ | ||
1390 | if (new_file(-1) < 0) { | ||
1391 | DEBUGF("No more files to play\n"); | ||
1392 | filling = false; | ||
1393 | |||
1394 | check_playlist_end(-1); | ||
1395 | current_track_counter++; | ||
1396 | } else { | ||
1397 | /* Make it read more data */ | ||
1398 | filling = true; | ||
1399 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1400 | |||
1401 | /* Tell the file loading code that we want to | ||
1402 | start playing as soon as we have some data */ | ||
1403 | play_pending = true; | ||
1404 | play_pending_track_change = true; | ||
1405 | |||
1406 | update_playlist(); | ||
1407 | current_track_counter++; | ||
1408 | } | ||
1409 | break; | ||
1410 | } | ||
1411 | |||
1412 | case MPEG_FF_REWIND: { | ||
1413 | struct mp3entry *id3 = audio_current_track(); | ||
1414 | unsigned int oldtime = id3->elapsed; | ||
1415 | unsigned int newtime = (unsigned int)ev.data; | ||
1416 | int curpos, newpos, diffpos; | ||
1417 | DEBUGF("MPEG_FF_REWIND\n"); | ||
1418 | |||
1419 | id3->elapsed = newtime; | ||
1420 | |||
1421 | newpos = audio_get_file_pos(); | ||
1422 | if(newpos < 0) | ||
1423 | { | ||
1424 | id3->elapsed = oldtime; | ||
1425 | break; | ||
1426 | } | ||
1427 | |||
1428 | if (mpeg_file >= 0) | ||
1429 | curpos = lseek(mpeg_file, 0, SEEK_CUR); | ||
1430 | else | ||
1431 | curpos = id3->filesize; | ||
1432 | |||
1433 | if (num_tracks_in_memory() > 1) | ||
1434 | { | ||
1435 | /* We have started loading other tracks that need to be | ||
1436 | accounted for */ | ||
1437 | struct trackdata *track; | ||
1438 | int i = 0; | ||
1439 | |||
1440 | while((track = get_trackdata(i++))) | ||
1441 | { | ||
1442 | curpos += track->id3.filesize; | ||
1443 | } | ||
1444 | } | ||
1445 | |||
1446 | diffpos = curpos - newpos; | ||
1447 | |||
1448 | if(!filling && diffpos >= 0 && diffpos < audiobuflen) | ||
1449 | { | ||
1450 | int unplayed_space_left, unswapped_space_left; | ||
1451 | |||
1452 | /* We are changing to a position that's already in | ||
1453 | memory, so we just move the DMA read pointer. */ | ||
1454 | audiobuf_read = audiobuf_write - diffpos; | ||
1455 | if (audiobuf_read < 0) | ||
1456 | { | ||
1457 | audiobuf_read += audiobuflen; | ||
1458 | } | ||
1459 | |||
1460 | unplayed_space_left = get_unplayed_space(); | ||
1461 | unswapped_space_left = get_unswapped_space(); | ||
1462 | |||
1463 | /* If unswapped_space_left is larger than | ||
1464 | unplayed_space_left, it means that the swapwrite pointer | ||
1465 | hasn't yet advanced up to the new location of the read | ||
1466 | pointer. We just move it, there is no need to swap | ||
1467 | data that won't be played anyway. */ | ||
1468 | |||
1469 | if (unswapped_space_left > unplayed_space_left) | ||
1470 | { | ||
1471 | DEBUGF("Moved swapwrite\n"); | ||
1472 | audiobuf_swapwrite = audiobuf_read; | ||
1473 | play_pending = true; | ||
1474 | } | ||
1475 | |||
1476 | if (mpeg_file>=0 && unplayed_space_left < low_watermark) | ||
1477 | { | ||
1478 | /* We need to load more data before starting */ | ||
1479 | filling = true; | ||
1480 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); | ||
1481 | play_pending = true; | ||
1482 | } | ||
1483 | else | ||
1484 | { | ||
1485 | /* resume will start at new position */ | ||
1486 | last_dma_chunk_size = | ||
1487 | MIN(0x2000, get_unplayed_space_current_song()); | ||
1488 | mp3_play_data(audiobuf + audiobuf_read, | ||
1489 | last_dma_chunk_size, transfer_end); | ||
1490 | dma_underrun = false; | ||
1491 | } | ||
1492 | } | ||
1493 | else | ||
1494 | { | ||
1495 | /* Move to the new position in the file and start | ||
1496 | loading data */ | ||
1497 | reset_mp3_buffer(); | ||
1498 | |||
1499 | if (num_tracks_in_memory() > 1) | ||
1500 | { | ||
1501 | /* We have to reload the current track */ | ||
1502 | close(mpeg_file); | ||
1503 | remove_all_non_current_tags(); | ||
1504 | generate_unbuffer_events(); | ||
1505 | mpeg_file = -1; | ||
1506 | } | ||
1507 | |||
1508 | if (mpeg_file < 0) | ||
1509 | { | ||
1510 | mpeg_file = open(id3->path, O_RDONLY); | ||
1511 | if (mpeg_file < 0) | ||
1512 | { | ||
1513 | id3->elapsed = oldtime; | ||
1514 | break; | ||
1515 | } | ||
1516 | } | ||
1517 | |||
1518 | if(-1 == lseek(mpeg_file, newpos, SEEK_SET)) | ||
1519 | { | ||
1520 | id3->elapsed = oldtime; | ||
1521 | break; | ||
1522 | } | ||
1523 | |||
1524 | filling = true; | ||
1525 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1526 | |||
1527 | /* Tell the file loading code that we want to start playing | ||
1528 | as soon as we have some data */ | ||
1529 | play_pending = true; | ||
1530 | } | ||
1531 | |||
1532 | id3->offset = newpos; | ||
1533 | |||
1534 | break; | ||
1535 | } | ||
1536 | |||
1537 | case MPEG_FLUSH_RELOAD: { | ||
1538 | int numtracks = num_tracks_in_memory(); | ||
1539 | bool reload_track = false; | ||
1540 | |||
1541 | if (numtracks > 1) | ||
1542 | { | ||
1543 | /* Reset the buffer */ | ||
1544 | audiobuf_write = get_trackdata(1)->mempos; | ||
1545 | |||
1546 | /* Reset swapwrite unless we're still swapping current | ||
1547 | track */ | ||
1548 | if (get_unplayed_space() <= get_playable_space()) | ||
1549 | audiobuf_swapwrite = audiobuf_write; | ||
1550 | |||
1551 | close(mpeg_file); | ||
1552 | remove_all_non_current_tags(); | ||
1553 | generate_unbuffer_events(); | ||
1554 | mpeg_file = -1; | ||
1555 | reload_track = true; | ||
1556 | } | ||
1557 | else if (numtracks == 1 && mpeg_file < 0) | ||
1558 | { | ||
1559 | reload_track = true; | ||
1560 | } | ||
1561 | |||
1562 | if(reload_track && new_file(1) >= 0) | ||
1563 | { | ||
1564 | /* Tell ourselves that we want more data */ | ||
1565 | filling = true; | ||
1566 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1567 | } | ||
1568 | |||
1569 | break; | ||
1570 | } | ||
1571 | |||
1572 | case MPEG_NEED_DATA: | ||
1573 | free_space_left = audiobuf_read - audiobuf_write; | ||
1574 | |||
1575 | /* We interpret 0 as "empty buffer" */ | ||
1576 | if(free_space_left <= 0) | ||
1577 | free_space_left += audiobuflen; | ||
1578 | |||
1579 | unplayed_space_left = audiobuflen - free_space_left; | ||
1580 | |||
1581 | /* Make sure that we don't fill the entire buffer */ | ||
1582 | free_space_left -= MPEG_HIGH_WATER; | ||
1583 | |||
1584 | if (ev.data == GENERATE_UNBUFFER_EVENTS) | ||
1585 | generate_unbuffer_events(); | ||
1586 | |||
1587 | /* do we have any more buffer space to fill? */ | ||
1588 | if(free_space_left <= 0) | ||
1589 | { | ||
1590 | DEBUGF("0\n"); | ||
1591 | filling = false; | ||
1592 | generate_postbuffer_events(); | ||
1593 | ata_sleep(); | ||
1594 | break; | ||
1595 | } | ||
1596 | |||
1597 | /* Read small chunks while we are below the low water mark */ | ||
1598 | if(unplayed_space_left < low_watermark) | ||
1599 | amount_to_read = MIN(MPEG_LOW_WATER_CHUNKSIZE, | ||
1600 | free_space_left); | ||
1601 | else | ||
1602 | amount_to_read = free_space_left; | ||
1603 | |||
1604 | /* Don't read more than until the end of the buffer */ | ||
1605 | amount_to_read = MIN(audiobuflen - audiobuf_write, | ||
1606 | amount_to_read); | ||
1607 | #ifdef HAVE_MMC /* MMC is slow, so don't read too large chunks */ | ||
1608 | amount_to_read = MIN(0x40000, amount_to_read); | ||
1609 | #elif MEM == 8 | ||
1610 | amount_to_read = MIN(0x100000, amount_to_read); | ||
1611 | #endif | ||
1612 | |||
1613 | /* Read as much mpeg data as we can fit in the buffer */ | ||
1614 | if(mpeg_file >= 0) | ||
1615 | { | ||
1616 | DEBUGF("R\n"); | ||
1617 | t1 = current_tick; | ||
1618 | len = read(mpeg_file, audiobuf + audiobuf_write, | ||
1619 | amount_to_read); | ||
1620 | if(len > 0) | ||
1621 | { | ||
1622 | t2 = current_tick; | ||
1623 | DEBUGF("time: %d\n", t2 - t1); | ||
1624 | DEBUGF("R: %x\n", len); | ||
1625 | |||
1626 | /* Now make sure that we don't feed the MAS with ID3V1 | ||
1627 | data */ | ||
1628 | if (len < amount_to_read) | ||
1629 | { | ||
1630 | int i; | ||
1631 | static const unsigned char tag[] = "TAG"; | ||
1632 | int taglen = 128; | ||
1633 | int tagptr = audiobuf_write + len - 128; | ||
1634 | |||
1635 | /* Really rare case: entire potential tag wasn't | ||
1636 | read in this call AND audiobuf_write < 128 */ | ||
1637 | if (tagptr < 0) | ||
1638 | tagptr += audiobuflen; | ||
1639 | |||
1640 | for(i = 0;i < 3;i++) | ||
1641 | { | ||
1642 | if(tagptr >= audiobuflen) | ||
1643 | tagptr -= audiobuflen; | ||
1644 | |||
1645 | if(audiobuf[tagptr] != tag[i]) | ||
1646 | { | ||
1647 | taglen = 0; | ||
1648 | break; | ||
1649 | } | ||
1650 | |||
1651 | tagptr++; | ||
1652 | } | ||
1653 | |||
1654 | if(taglen) | ||
1655 | { | ||
1656 | /* Skip id3v1 tag */ | ||
1657 | DEBUGF("Skipping ID3v1 tag\n"); | ||
1658 | len -= taglen; | ||
1659 | |||
1660 | /* In the very rare case when the entire tag | ||
1661 | wasn't read in this read() len will be < 0. | ||
1662 | Take care of this when changing the write | ||
1663 | pointer. */ | ||
1664 | } | ||
1665 | } | ||
1666 | |||
1667 | audiobuf_write += len; | ||
1668 | |||
1669 | if (audiobuf_write < 0) | ||
1670 | audiobuf_write += audiobuflen; | ||
1671 | |||
1672 | if(audiobuf_write >= audiobuflen) | ||
1673 | { | ||
1674 | audiobuf_write = 0; | ||
1675 | DEBUGF("W\n"); | ||
1676 | } | ||
1677 | |||
1678 | /* Tell ourselves that we want more data */ | ||
1679 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1680 | } | ||
1681 | else | ||
1682 | { | ||
1683 | if(len < 0) | ||
1684 | { | ||
1685 | DEBUGF("MPEG read error\n"); | ||
1686 | } | ||
1687 | |||
1688 | close(mpeg_file); | ||
1689 | mpeg_file = -1; | ||
1690 | |||
1691 | if(new_file(1) < 0) | ||
1692 | { | ||
1693 | /* No more data to play */ | ||
1694 | DEBUGF("No more files to play\n"); | ||
1695 | filling = false; | ||
1696 | } | ||
1697 | else | ||
1698 | { | ||
1699 | /* Tell ourselves that we want more data */ | ||
1700 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1701 | } | ||
1702 | } | ||
1703 | } | ||
1704 | break; | ||
1705 | |||
1706 | case MPEG_TRACK_CHANGE: | ||
1707 | track_change(); | ||
1708 | break; | ||
1709 | |||
1710 | #ifndef USB_NONE | ||
1711 | case SYS_USB_CONNECTED: | ||
1712 | is_playing = false; | ||
1713 | paused = false; | ||
1714 | stop_playing(); | ||
1715 | |||
1716 | /* Tell the USB thread that we are safe */ | ||
1717 | DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); | ||
1718 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
1719 | |||
1720 | /* Wait until the USB cable is extracted again */ | ||
1721 | usb_wait_for_disconnect(&mpeg_queue); | ||
1722 | break; | ||
1723 | #endif /* !USB_NONE */ | ||
1724 | |||
1725 | #if CONFIG_CODEC == MAS3587F | ||
1726 | case MPEG_INIT_RECORDING: | ||
1727 | init_recording(); | ||
1728 | init_recording_done = true; | ||
1729 | break; | ||
1730 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
1731 | |||
1732 | case SYS_TIMEOUT: | ||
1733 | if (playing) | ||
1734 | playlist_update_resume_info(audio_current_track()); | ||
1735 | break; | ||
1736 | } | ||
1737 | #if CONFIG_CODEC == MAS3587F | ||
1738 | } | ||
1739 | else | ||
1740 | { | ||
1741 | queue_wait(&mpeg_queue, &ev); | ||
1742 | switch(ev.id) | ||
1743 | { | ||
1744 | case MPEG_RECORD: | ||
1745 | if (is_prerecording) | ||
1746 | { | ||
1747 | int startpos; | ||
1748 | |||
1749 | /* Go back prerecord_count seconds in the buffer */ | ||
1750 | startpos = prerecord_index - prerecord_count; | ||
1751 | if(startpos < 0) | ||
1752 | startpos += prerecording_max_seconds; | ||
1753 | |||
1754 | /* Read the position data from the prerecord buffer */ | ||
1755 | frame_count_start = prerecord_buffer[startpos].framecount; | ||
1756 | startpos = prerecord_buffer[startpos].mempos; | ||
1757 | |||
1758 | DEBUGF("Start looking at address %x (%x)\n", | ||
1759 | audiobuf+startpos, startpos); | ||
1760 | |||
1761 | saved_header = mpeg_get_last_header(); | ||
1762 | |||
1763 | mem_find_next_frame(startpos, &offset, 1800, | ||
1764 | saved_header); | ||
1765 | |||
1766 | audiobuf_read = startpos + offset; | ||
1767 | if(audiobuf_read >= audiobuflen) | ||
1768 | audiobuf_read -= audiobuflen; | ||
1769 | |||
1770 | DEBUGF("New audiobuf_read address: %x (%x)\n", | ||
1771 | audiobuf+audiobuf_read, audiobuf_read); | ||
1772 | |||
1773 | level = disable_irq_save(); | ||
1774 | num_rec_bytes = get_unsaved_space(); | ||
1775 | restore_irq(level); | ||
1776 | } | ||
1777 | else | ||
1778 | { | ||
1779 | frame_count_start = 0; | ||
1780 | num_rec_bytes = 0; | ||
1781 | audiobuf_read = MPEG_RESERVED_HEADER_SPACE; | ||
1782 | audiobuf_write = MPEG_RESERVED_HEADER_SPACE; | ||
1783 | } | ||
1784 | |||
1785 | prepend_header(); | ||
1786 | DEBUGF("Recording...\n"); | ||
1787 | start_recording(); | ||
1788 | |||
1789 | /* Wait until at least one frame is encoded and get the | ||
1790 | frame header, for later use by the Xing header | ||
1791 | generation */ | ||
1792 | sleep(HZ/5); | ||
1793 | saved_header = mpeg_get_last_header(); | ||
1794 | |||
1795 | /* delayed until buffer is saved, don't open yet */ | ||
1796 | strcpy(delayed_filename, recording_filename); | ||
1797 | mpeg_file = -1; | ||
1798 | |||
1799 | break; | ||
1800 | |||
1801 | case MPEG_STOP: | ||
1802 | DEBUGF("MPEG_STOP\n"); | ||
1803 | |||
1804 | stop_recording(); | ||
1805 | |||
1806 | /* Save the remaining data in the buffer */ | ||
1807 | save_endpos = audiobuf_write; | ||
1808 | saving_status = STOP_RECORDING; | ||
1809 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
1810 | break; | ||
1811 | |||
1812 | case MPEG_STOP_DONE: | ||
1813 | DEBUGF("MPEG_STOP_DONE\n"); | ||
1814 | |||
1815 | if (mpeg_file >= 0) | ||
1816 | close(mpeg_file); | ||
1817 | mpeg_file = -1; | ||
1818 | |||
1819 | update_header(); | ||
1820 | #ifdef DEBUG1 | ||
1821 | { | ||
1822 | int i; | ||
1823 | for(i = 0;i < 512;i++) | ||
1824 | { | ||
1825 | DEBUGF("%d - %d us (%d bytes)\n", | ||
1826 | timing_info[i*2], | ||
1827 | (timing_info[i*2+1] & 0xffff) * | ||
1828 | 10000 / 13824, | ||
1829 | timing_info[i*2+1] >> 16); | ||
1830 | } | ||
1831 | } | ||
1832 | #endif /* DEBUG1 */ | ||
1833 | |||
1834 | if (prerecording) | ||
1835 | { | ||
1836 | start_prerecording(); | ||
1837 | } | ||
1838 | mpeg_stop_done = true; | ||
1839 | break; | ||
1840 | |||
1841 | case MPEG_NEW_FILE: | ||
1842 | /* Bail out when a more important save is happening */ | ||
1843 | if (saving_status > NEW_FILE) | ||
1844 | break; | ||
1845 | |||
1846 | /* Make sure we have at least one complete frame | ||
1847 | in the buffer. If we haven't recorded a single | ||
1848 | frame within 200ms, the MAS is probably not recording | ||
1849 | anything, and we bail out. */ | ||
1850 | amount_to_save = get_unsaved_space(); | ||
1851 | if (amount_to_save < 1800) | ||
1852 | { | ||
1853 | sleep(HZ/5); | ||
1854 | amount_to_save = get_unsaved_space(); | ||
1855 | } | ||
1856 | |||
1857 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, | ||
1858 | &frame_count_end, 1); | ||
1859 | |||
1860 | last_rec_time = current_tick - record_start_time; | ||
1861 | record_start_time = current_tick; | ||
1862 | if (paused) | ||
1863 | pause_start_time = record_start_time; | ||
1864 | |||
1865 | /* capture all values at one point */ | ||
1866 | level = disable_irq_save(); | ||
1867 | save_endpos = audiobuf_write; | ||
1868 | last_rec_bytes = num_rec_bytes; | ||
1869 | num_rec_bytes = 0; | ||
1870 | restore_irq(level); | ||
1871 | |||
1872 | if (amount_to_save >= 1800) | ||
1873 | { | ||
1874 | /* Now find a frame boundary to split at */ | ||
1875 | save_endpos -= 1800; | ||
1876 | if (save_endpos < 0) | ||
1877 | save_endpos += audiobuflen; | ||
1878 | |||
1879 | rc = mem_find_next_frame(save_endpos, &offset, 1800, | ||
1880 | saved_header); | ||
1881 | if (!rc) /* No header found, save whole buffer */ | ||
1882 | offset = 1800; | ||
1883 | |||
1884 | save_endpos += offset; | ||
1885 | if (save_endpos >= audiobuflen) | ||
1886 | save_endpos -= audiobuflen; | ||
1887 | |||
1888 | last_rec_bytes += offset - 1800; | ||
1889 | level = disable_irq_save(); | ||
1890 | num_rec_bytes += 1800 - offset; | ||
1891 | restore_irq(level); | ||
1892 | } | ||
1893 | |||
1894 | saving_status = NEW_FILE; | ||
1895 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
1896 | break; | ||
1897 | |||
1898 | case MPEG_SAVE_DATA: | ||
1899 | if (saving_status == BUFFER_FULL) | ||
1900 | save_endpos = audiobuf_write; | ||
1901 | |||
1902 | if (mpeg_file < 0) /* delayed file open */ | ||
1903 | { | ||
1904 | mpeg_file = open(delayed_filename, O_WRONLY|O_CREAT); | ||
1905 | |||
1906 | if (mpeg_file < 0) | ||
1907 | panicf("recfile: %d", mpeg_file); | ||
1908 | } | ||
1909 | |||
1910 | amount_to_save = save_endpos - audiobuf_read; | ||
1911 | if (amount_to_save < 0) | ||
1912 | amount_to_save += audiobuflen; | ||
1913 | |||
1914 | amount_to_save = MIN(amount_to_save, | ||
1915 | audiobuflen - audiobuf_read); | ||
1916 | #ifdef HAVE_MMC /* MMC is slow, so don't save too large chunks at once */ | ||
1917 | amount_to_save = MIN(0x40000, amount_to_save); | ||
1918 | #elif MEM == 8 | ||
1919 | amount_to_save = MIN(0x100000, amount_to_save); | ||
1920 | #endif | ||
1921 | rc = write(mpeg_file, audiobuf + audiobuf_read, | ||
1922 | amount_to_save); | ||
1923 | if (rc < 0) | ||
1924 | { | ||
1925 | if (errno == ENOSPC) | ||
1926 | { | ||
1927 | mpeg_errno = AUDIOERR_DISK_FULL; | ||
1928 | stop_recording(); | ||
1929 | queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); | ||
1930 | /* will close the file */ | ||
1931 | break; | ||
1932 | } | ||
1933 | else | ||
1934 | panicf("rec wrt: %d", rc); | ||
1935 | } | ||
1936 | |||
1937 | audiobuf_read += amount_to_save; | ||
1938 | if (audiobuf_read >= audiobuflen) | ||
1939 | audiobuf_read = 0; | ||
1940 | |||
1941 | if (audiobuf_read == save_endpos) /* all saved */ | ||
1942 | { | ||
1943 | switch (saving_status) | ||
1944 | { | ||
1945 | case BUFFER_FULL: | ||
1946 | rc = fsync(mpeg_file); | ||
1947 | if (rc < 0) | ||
1948 | panicf("rec fls: %d", rc); | ||
1949 | ata_sleep(); | ||
1950 | break; | ||
1951 | |||
1952 | case NEW_FILE: | ||
1953 | /* Close the current file */ | ||
1954 | rc = close(mpeg_file); | ||
1955 | if (rc < 0) | ||
1956 | panicf("rec cls: %d", rc); | ||
1957 | mpeg_file = -1; | ||
1958 | update_header(); | ||
1959 | ata_sleep(); | ||
1960 | |||
1961 | /* copy new filename */ | ||
1962 | strcpy(delayed_filename, recording_filename); | ||
1963 | prepend_header(); | ||
1964 | frame_count_start = frame_count_end; | ||
1965 | break; | ||
1966 | |||
1967 | case STOP_RECORDING: | ||
1968 | queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); | ||
1969 | /* will close the file */ | ||
1970 | break; | ||
1971 | |||
1972 | default: | ||
1973 | break; | ||
1974 | } | ||
1975 | saving_status = NOT_SAVING; | ||
1976 | } | ||
1977 | else /* tell ourselves to save the next chunk */ | ||
1978 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | ||
1979 | |||
1980 | break; | ||
1981 | |||
1982 | case MPEG_PRERECORDING_TICK: | ||
1983 | if(!is_prerecording) | ||
1984 | break; | ||
1985 | |||
1986 | /* Store the write pointer every second */ | ||
1987 | prerecord_buffer[prerecord_index].mempos = audiobuf_write; | ||
1988 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, | ||
1989 | &prerecord_buffer[prerecord_index].framecount, 1); | ||
1990 | |||
1991 | /* Wrap if necessary */ | ||
1992 | if(++prerecord_index == prerecording_max_seconds) | ||
1993 | prerecord_index = 0; | ||
1994 | |||
1995 | /* Update the number of seconds recorded */ | ||
1996 | if(prerecord_count < prerecording_max_seconds) | ||
1997 | prerecord_count++; | ||
1998 | break; | ||
1999 | |||
2000 | case MPEG_INIT_PLAYBACK: | ||
2001 | /* Stop the prerecording */ | ||
2002 | stop_recording(); | ||
2003 | reset_mp3_buffer(); | ||
2004 | mp3_play_init(); | ||
2005 | init_playback_done = true; | ||
2006 | break; | ||
2007 | |||
2008 | case MPEG_PAUSE_RECORDING: | ||
2009 | pause_recording(); | ||
2010 | break; | ||
2011 | |||
2012 | case MPEG_RESUME_RECORDING: | ||
2013 | resume_recording(); | ||
2014 | break; | ||
2015 | |||
2016 | case SYS_USB_CONNECTED: | ||
2017 | /* We can safely go to USB mode if no recording | ||
2018 | is taking place */ | ||
2019 | if((!is_recording || is_prerecording) && mpeg_stop_done) | ||
2020 | { | ||
2021 | /* Even if we aren't recording, we still call this | ||
2022 | function, to put the MAS in monitoring mode, | ||
2023 | to save power. */ | ||
2024 | stop_recording(); | ||
2025 | |||
2026 | /* Tell the USB thread that we are safe */ | ||
2027 | DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); | ||
2028 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
2029 | |||
2030 | /* Wait until the USB cable is extracted again */ | ||
2031 | usb_wait_for_disconnect(&mpeg_queue); | ||
2032 | } | ||
2033 | break; | ||
2034 | } | ||
2035 | } | ||
2036 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
2037 | } | ||
2038 | } | ||
2039 | #endif /* !SIMULATOR */ | ||
2040 | |||
2041 | struct mp3entry* audio_current_track() | ||
2042 | { | ||
2043 | #ifdef SIMULATOR | ||
2044 | return &taginfo; | ||
2045 | #else /* !SIMULATOR */ | ||
2046 | if(num_tracks_in_memory()) | ||
2047 | return &get_trackdata(0)->id3; | ||
2048 | else | ||
2049 | return NULL; | ||
2050 | #endif /* !SIMULATOR */ | ||
2051 | } | ||
2052 | |||
2053 | struct mp3entry* audio_next_track() | ||
2054 | { | ||
2055 | #ifdef SIMULATOR | ||
2056 | return &taginfo; | ||
2057 | #else /* !SIMULATOR */ | ||
2058 | if(num_tracks_in_memory() > 1) | ||
2059 | return &get_trackdata(1)->id3; | ||
2060 | else | ||
2061 | return NULL; | ||
2062 | #endif /* !SIMULATOR */ | ||
2063 | } | ||
2064 | |||
2065 | bool audio_has_changed_track(void) | ||
2066 | { | ||
2067 | if(last_track_counter != current_track_counter) | ||
2068 | { | ||
2069 | last_track_counter = current_track_counter; | ||
2070 | return true; | ||
2071 | } | ||
2072 | return false; | ||
2073 | } | ||
2074 | |||
2075 | #if CONFIG_CODEC == MAS3587F | ||
2076 | #ifndef SIMULATOR | ||
2077 | void audio_init_playback(void) | ||
2078 | { | ||
2079 | init_playback_done = false; | ||
2080 | queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, 0); | ||
2081 | |||
2082 | while(!init_playback_done) | ||
2083 | sleep(1); | ||
2084 | } | ||
2085 | |||
2086 | |||
2087 | /**************************************************************************** | ||
2088 | * Recording functions | ||
2089 | ***************************************************************************/ | ||
2090 | void audio_init_recording(unsigned int buffer_offset) | ||
2091 | { | ||
2092 | buffer_offset = buffer_offset; | ||
2093 | init_recording_done = false; | ||
2094 | queue_post(&mpeg_queue, MPEG_INIT_RECORDING, 0); | ||
2095 | |||
2096 | while(!init_recording_done) | ||
2097 | sleep(1); | ||
2098 | } | ||
2099 | |||
2100 | static void init_recording(void) | ||
2101 | { | ||
2102 | unsigned long val; | ||
2103 | int rc; | ||
2104 | |||
2105 | /* Disable IRQ6 */ | ||
2106 | IPRB &= 0xff0f; | ||
2107 | |||
2108 | stop_playing(); | ||
2109 | is_playing = false; | ||
2110 | paused = false; | ||
2111 | |||
2112 | /* Init the recording variables */ | ||
2113 | is_recording = false; | ||
2114 | is_prerecording = false; | ||
2115 | |||
2116 | mpeg_stop_done = true; | ||
2117 | |||
2118 | mas_reset(); | ||
2119 | |||
2120 | /* Enable the audio CODEC and the DSP core, max analog voltage range */ | ||
2121 | rc = mas_direct_config_write(MAS_CONTROL, 0x8c00); | ||
2122 | if(rc < 0) | ||
2123 | panicf("mas_ctrl_w: %d", rc); | ||
2124 | |||
2125 | /* Stop the current application */ | ||
2126 | val = 0; | ||
2127 | mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1); | ||
2128 | do | ||
2129 | { | ||
2130 | mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1); | ||
2131 | } while(val); | ||
2132 | |||
2133 | /* Perform black magic as described by the data sheet */ | ||
2134 | if((mas_version_code & 0x0fff) == 0x0102) | ||
2135 | { | ||
2136 | DEBUGF("Performing MAS black magic for B2 version\n"); | ||
2137 | mas_writereg(0xa3, 0x98); | ||
2138 | mas_writereg(0x94, 0xfffff); | ||
2139 | val = 0; | ||
2140 | mas_writemem(MAS_BANK_D1, 0, &val, 1); | ||
2141 | mas_writereg(0xa3, 0x90); | ||
2142 | } | ||
2143 | |||
2144 | /* Enable A/D Converters */ | ||
2145 | shadow_codec_reg0 = 0xcccd; | ||
2146 | mas_codec_writereg(0x0, shadow_codec_reg0); | ||
2147 | |||
2148 | /* Copy left channel to right (mono mode) */ | ||
2149 | mas_codec_writereg(8, 0x8000); | ||
2150 | |||
2151 | /* ADC scale 0%, DSP scale 100% | ||
2152 | We use the DSP output for monitoring, because it works with all | ||
2153 | sources including S/PDIF */ | ||
2154 | mas_codec_writereg(6, 0x0000); | ||
2155 | mas_codec_writereg(7, 0x4000); | ||
2156 | |||
2157 | /* No mute */ | ||
2158 | shadow_soft_mute = 0; | ||
2159 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute, 1); | ||
2160 | |||
2161 | #ifdef HAVE_SPDIF_OUT | ||
2162 | val = 0x09; /* Disable SDO and SDI, low impedance S/PDIF outputs */ | ||
2163 | #else | ||
2164 | val = 0x2d; /* Disable SDO and SDI, disable S/PDIF output */ | ||
2165 | #endif | ||
2166 | mas_writemem(MAS_BANK_D0, MAS_D0_INTERFACE_CONTROL, &val, 1); | ||
2167 | |||
2168 | /* Set Demand mode, monitoring OFF and validate all settings */ | ||
2169 | shadow_io_control_main = 0x125; | ||
2170 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
2171 | |||
2172 | /* Start the encoder application */ | ||
2173 | val = 0x40; | ||
2174 | mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1); | ||
2175 | do | ||
2176 | { | ||
2177 | mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1); | ||
2178 | } while(!(val & 0x40)); | ||
2179 | |||
2180 | /* We have started the recording application with monitoring OFF. | ||
2181 | This is because we want to record at least one frame to fill the DMA | ||
2182 | buffer, because the silly MAS will not negate EOD until at least one | ||
2183 | DMA transfer has taken place. | ||
2184 | Now let's wait for some data to be encoded. */ | ||
2185 | sleep(HZ/5); | ||
2186 | |||
2187 | /* Now set it to Monitoring mode as default, saves power */ | ||
2188 | shadow_io_control_main = 0x525; | ||
2189 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
2190 | |||
2191 | /* Wait until the DSP has accepted the settings */ | ||
2192 | do | ||
2193 | { | ||
2194 | mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1); | ||
2195 | } while(val & 1); | ||
2196 | |||
2197 | drain_dma_buffer(); | ||
2198 | mpeg_mode = MPEG_ENCODER; | ||
2199 | |||
2200 | DEBUGF("MAS Recording application started\n"); | ||
2201 | |||
2202 | /* At this point, all settings are the reset MAS defaults, next thing is to | ||
2203 | call mpeg_set_recording_options(). */ | ||
2204 | } | ||
2205 | |||
2206 | void audio_record(const char *filename) | ||
2207 | { | ||
2208 | mpeg_errno = 0; | ||
2209 | |||
2210 | strncpy(recording_filename, filename, MAX_PATH - 1); | ||
2211 | recording_filename[MAX_PATH - 1] = 0; | ||
2212 | |||
2213 | queue_post(&mpeg_queue, MPEG_RECORD, 0); | ||
2214 | } | ||
2215 | |||
2216 | void audio_pause_recording(void) | ||
2217 | { | ||
2218 | queue_post(&mpeg_queue, MPEG_PAUSE_RECORDING, 0); | ||
2219 | } | ||
2220 | |||
2221 | void audio_resume_recording(void) | ||
2222 | { | ||
2223 | queue_post(&mpeg_queue, MPEG_RESUME_RECORDING, 0); | ||
2224 | } | ||
2225 | |||
2226 | static void prepend_header(void) | ||
2227 | { | ||
2228 | int startpos; | ||
2229 | unsigned i; | ||
2230 | |||
2231 | /* Make room for header */ | ||
2232 | audiobuf_read -= MPEG_RESERVED_HEADER_SPACE; | ||
2233 | if(audiobuf_read < 0) | ||
2234 | { | ||
2235 | /* Clear the bottom half */ | ||
2236 | memset(audiobuf, 0, audiobuf_read + MPEG_RESERVED_HEADER_SPACE); | ||
2237 | |||
2238 | /* And the top half */ | ||
2239 | audiobuf_read += audiobuflen; | ||
2240 | memset(audiobuf + audiobuf_read, 0, audiobuflen - audiobuf_read); | ||
2241 | } | ||
2242 | else | ||
2243 | { | ||
2244 | memset(audiobuf + audiobuf_read, 0, MPEG_RESERVED_HEADER_SPACE); | ||
2245 | } | ||
2246 | /* Copy the empty ID3 header */ | ||
2247 | startpos = audiobuf_read; | ||
2248 | for(i = 0; i < sizeof(empty_id3_header); i++) | ||
2249 | { | ||
2250 | audiobuf[startpos++] = empty_id3_header[i]; | ||
2251 | if(startpos == audiobuflen) | ||
2252 | startpos = 0; | ||
2253 | } | ||
2254 | } | ||
2255 | |||
2256 | static void update_header(void) | ||
2257 | { | ||
2258 | int fd, framelen; | ||
2259 | unsigned long frames; | ||
2260 | |||
2261 | if (last_rec_bytes > 0) | ||
2262 | { | ||
2263 | /* Create the Xing header */ | ||
2264 | fd = open(delayed_filename, O_RDWR); | ||
2265 | if (fd < 0) | ||
2266 | panicf("rec upd: %d (%s)", fd, recording_filename); | ||
2267 | |||
2268 | frames = frame_count_end - frame_count_start; | ||
2269 | /* If the number of recorded frames has reached 0x7ffff, | ||
2270 | we can no longer trust it */ | ||
2271 | if (frame_count_end == 0x7ffff) | ||
2272 | frames = 0; | ||
2273 | |||
2274 | /* saved_header is saved right before stopping the MAS */ | ||
2275 | framelen = create_xing_header(fd, 0, last_rec_bytes, xing_buffer, | ||
2276 | frames, last_rec_time * (1000/HZ), | ||
2277 | saved_header, NULL, false); | ||
2278 | |||
2279 | lseek(fd, MPEG_RESERVED_HEADER_SPACE - framelen, SEEK_SET); | ||
2280 | write(fd, xing_buffer, framelen); | ||
2281 | close(fd); | ||
2282 | } | ||
2283 | } | ||
2284 | |||
2285 | static void start_prerecording(void) | ||
2286 | { | ||
2287 | unsigned long val; | ||
2288 | |||
2289 | DEBUGF("Starting prerecording\n"); | ||
2290 | |||
2291 | prerecord_index = 0; | ||
2292 | prerecord_count = 0; | ||
2293 | prerecord_timeout = current_tick + HZ; | ||
2294 | memset(prerecord_buffer, 0, sizeof(prerecord_buffer)); | ||
2295 | reset_mp3_buffer(); | ||
2296 | |||
2297 | is_prerecording = true; | ||
2298 | |||
2299 | /* Stop monitoring and start the encoder */ | ||
2300 | shadow_io_control_main &= ~(1 << 10); | ||
2301 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
2302 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); | ||
2303 | |||
2304 | /* Wait until the DSP has accepted the settings */ | ||
2305 | do | ||
2306 | { | ||
2307 | mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1); | ||
2308 | } while(val & 1); | ||
2309 | |||
2310 | is_recording = true; | ||
2311 | saving_status = NOT_SAVING; | ||
2312 | |||
2313 | demand_irq_enable(true); | ||
2314 | } | ||
2315 | |||
2316 | static void start_recording(void) | ||
2317 | { | ||
2318 | unsigned long val; | ||
2319 | |||
2320 | if(is_prerecording) | ||
2321 | { | ||
2322 | /* This will make the IRQ handler start recording | ||
2323 | for real, i.e send MPEG_SAVE_DATA messages when | ||
2324 | the buffer is full */ | ||
2325 | is_prerecording = false; | ||
2326 | } | ||
2327 | else | ||
2328 | { | ||
2329 | /* If prerecording is off, we need to stop the monitoring | ||
2330 | and start the encoder */ | ||
2331 | shadow_io_control_main &= ~(1 << 10); | ||
2332 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
2333 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); | ||
2334 | |||
2335 | /* Wait until the DSP has accepted the settings */ | ||
2336 | do | ||
2337 | { | ||
2338 | mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1); | ||
2339 | } while(val & 1); | ||
2340 | } | ||
2341 | |||
2342 | is_recording = true; | ||
2343 | saving_status = NOT_SAVING; | ||
2344 | paused = false; | ||
2345 | |||
2346 | /* Store the current time */ | ||
2347 | if(prerecording) | ||
2348 | record_start_time = current_tick - prerecord_count * HZ; | ||
2349 | else | ||
2350 | record_start_time = current_tick; | ||
2351 | |||
2352 | pause_start_time = 0; | ||
2353 | |||
2354 | demand_irq_enable(true); | ||
2355 | } | ||
2356 | |||
2357 | static void pause_recording(void) | ||
2358 | { | ||
2359 | pause_start_time = current_tick; | ||
2360 | |||
2361 | /* Set the pause bit */ | ||
2362 | shadow_soft_mute |= 2; | ||
2363 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute, 1); | ||
2364 | |||
2365 | paused = true; | ||
2366 | } | ||
2367 | |||
2368 | static void resume_recording(void) | ||
2369 | { | ||
2370 | paused = false; | ||
2371 | |||
2372 | /* Clear the pause bit */ | ||
2373 | shadow_soft_mute &= ~2; | ||
2374 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute, 1); | ||
2375 | |||
2376 | /* Compensate for the time we have been paused */ | ||
2377 | if(pause_start_time) | ||
2378 | { | ||
2379 | record_start_time = | ||
2380 | current_tick - (pause_start_time - record_start_time); | ||
2381 | pause_start_time = 0; | ||
2382 | } | ||
2383 | } | ||
2384 | |||
2385 | static void stop_recording(void) | ||
2386 | { | ||
2387 | unsigned long val; | ||
2388 | |||
2389 | /* Let it finish the last frame */ | ||
2390 | if(!paused) | ||
2391 | pause_recording(); | ||
2392 | sleep(HZ/5); | ||
2393 | |||
2394 | demand_irq_enable(false); | ||
2395 | |||
2396 | is_recording = false; | ||
2397 | is_prerecording = false; | ||
2398 | |||
2399 | last_rec_bytes = num_rec_bytes; | ||
2400 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count_end, 1); | ||
2401 | last_rec_time = current_tick - record_start_time; | ||
2402 | |||
2403 | /* Start monitoring */ | ||
2404 | shadow_io_control_main |= (1 << 10); | ||
2405 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1); | ||
2406 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); | ||
2407 | |||
2408 | /* Wait until the DSP has accepted the settings */ | ||
2409 | do | ||
2410 | { | ||
2411 | mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1); | ||
2412 | } while(val & 1); | ||
2413 | |||
2414 | resume_recording(); | ||
2415 | } | ||
2416 | |||
2417 | void audio_set_recording_options(struct audio_recording_options *options) | ||
2418 | { | ||
2419 | bool is_mpeg1; | ||
2420 | |||
2421 | is_mpeg1 = (options->rec_frequency < 3)?true:false; | ||
2422 | |||
2423 | rec_version_index = is_mpeg1?3:2; | ||
2424 | rec_frequency_index = options->rec_frequency % 3; | ||
2425 | |||
2426 | shadow_encoder_control = (options->rec_quality << 17) | | ||
2427 | (rec_frequency_index << 10) | | ||
2428 | ((is_mpeg1?1:0) << 9) | | ||
2429 | (((options->rec_channels * 2 + 1) & 3) << 6) | | ||
2430 | (1 << 5) /* MS-stereo */ | | ||
2431 | (1 << 2) /* Is an original */; | ||
2432 | mas_writemem(MAS_BANK_D0, MAS_D0_ENCODER_CONTROL, &shadow_encoder_control,1); | ||
2433 | |||
2434 | DEBUGF("mas_writemem(MAS_BANK_D0, ENCODER_CONTROL, %x)\n", shadow_encoder_control); | ||
2435 | |||
2436 | shadow_soft_mute = options->rec_editable?4:0; | ||
2437 | mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute,1); | ||
2438 | |||
2439 | DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute); | ||
2440 | |||
2441 | shadow_io_control_main = ((1 << 10) | /* Monitoring ON */ | ||
2442 | ((options->rec_source < 2)?1:2) << 8) | /* Input select */ | ||
2443 | (1 << 5) | /* SDO strobe invert */ | ||
2444 | ((is_mpeg1?0:1) << 3) | | ||
2445 | (1 << 2) | /* Inverted SIBC clock signal */ | ||
2446 | 1; /* Validate */ | ||
2447 | mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main,1); | ||
2448 | |||
2449 | DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); | ||
2450 | |||
2451 | if(options->rec_source == AUDIO_SRC_MIC) | ||
2452 | { | ||
2453 | /* Copy left channel to right (mono mode) */ | ||
2454 | mas_codec_writereg(8, 0x8000); | ||
2455 | } | ||
2456 | else | ||
2457 | { | ||
2458 | /* Stereo input mode */ | ||
2459 | mas_codec_writereg(8, 0); | ||
2460 | } | ||
2461 | |||
2462 | prerecording_max_seconds = options->rec_prerecord_time; | ||
2463 | if(prerecording_max_seconds) | ||
2464 | { | ||
2465 | prerecording = true; | ||
2466 | start_prerecording(); | ||
2467 | } | ||
2468 | else | ||
2469 | { | ||
2470 | prerecording = false; | ||
2471 | is_prerecording = false; | ||
2472 | is_recording = false; | ||
2473 | } | ||
2474 | } | ||
2475 | |||
2476 | /* If use_mic is true, the left gain is used */ | ||
2477 | void audio_set_recording_gain(int left, int right, int type) | ||
2478 | { | ||
2479 | /* Enable both left and right A/D */ | ||
2480 | shadow_codec_reg0 = (left << 12) | | ||
2481 | (right << 8) | | ||
2482 | (left << 4) | | ||
2483 | (type==AUDIO_GAIN_MIC?0x0008:0) | /* Connect left A/D to mic */ | ||
2484 | 0x0007; | ||
2485 | mas_codec_writereg(0x0, shadow_codec_reg0); | ||
2486 | } | ||
2487 | |||
2488 | #if CONFIG_TUNER & S1A0903X01 | ||
2489 | /* Get the (unpitched) MAS PLL frequency, for avoiding FM interference with the | ||
2490 | * Samsung tuner. Zero means unknown. Currently handles recording from analog | ||
2491 | * input only. */ | ||
2492 | int mpeg_get_mas_pllfreq(void) | ||
2493 | { | ||
2494 | if (mpeg_mode != MPEG_ENCODER) | ||
2495 | return 0; | ||
2496 | |||
2497 | if (rec_frequency_index == 0) /* 44.1 kHz / 22.05 kHz */ | ||
2498 | return 22579000; | ||
2499 | else | ||
2500 | return 24576000; | ||
2501 | } | ||
2502 | #endif /* CONFIG_TUNER & S1A0903X01 */ | ||
2503 | |||
2504 | /* try to make some kind of beep, also in recording mode */ | ||
2505 | void audio_beep(int duration) | ||
2506 | { | ||
2507 | long starttick = current_tick; | ||
2508 | do | ||
2509 | { /* toggle bit 0 of codec register 0, toggling the DAC off & on. | ||
2510 | * While this is still audible even without an external signal, | ||
2511 | * it doesn't affect the (pre-)recording. */ | ||
2512 | mas_codec_writereg(0, shadow_codec_reg0 ^ 1); | ||
2513 | mas_codec_writereg(0, shadow_codec_reg0); | ||
2514 | yield(); | ||
2515 | } | ||
2516 | while (current_tick - starttick < duration); | ||
2517 | } | ||
2518 | |||
2519 | void audio_new_file(const char *filename) | ||
2520 | { | ||
2521 | mpeg_errno = 0; | ||
2522 | |||
2523 | strncpy(recording_filename, filename, MAX_PATH - 1); | ||
2524 | recording_filename[MAX_PATH - 1] = 0; | ||
2525 | |||
2526 | queue_post(&mpeg_queue, MPEG_NEW_FILE, 0); | ||
2527 | } | ||
2528 | |||
2529 | unsigned long audio_recorded_time(void) | ||
2530 | { | ||
2531 | if(is_prerecording) | ||
2532 | return prerecord_count * HZ; | ||
2533 | |||
2534 | if(is_recording) | ||
2535 | { | ||
2536 | if(paused) | ||
2537 | return pause_start_time - record_start_time; | ||
2538 | else | ||
2539 | return current_tick - record_start_time; | ||
2540 | } | ||
2541 | |||
2542 | return 0; | ||
2543 | } | ||
2544 | |||
2545 | unsigned long audio_num_recorded_bytes(void) | ||
2546 | { | ||
2547 | int num_bytes; | ||
2548 | int index; | ||
2549 | |||
2550 | if(is_recording) | ||
2551 | { | ||
2552 | if(is_prerecording) | ||
2553 | { | ||
2554 | index = prerecord_index - prerecord_count; | ||
2555 | if(index < 0) | ||
2556 | index += prerecording_max_seconds; | ||
2557 | |||
2558 | num_bytes = audiobuf_write - prerecord_buffer[index].mempos; | ||
2559 | if(num_bytes < 0) | ||
2560 | num_bytes += audiobuflen; | ||
2561 | |||
2562 | return num_bytes;; | ||
2563 | } | ||
2564 | else | ||
2565 | return num_rec_bytes; | ||
2566 | } | ||
2567 | else | ||
2568 | return 0; | ||
2569 | } | ||
2570 | |||
2571 | #else /* SIMULATOR */ | ||
2572 | |||
2573 | /* dummies coming up */ | ||
2574 | |||
2575 | void audio_init_playback(void) | ||
2576 | { | ||
2577 | /* a dummy */ | ||
2578 | } | ||
2579 | unsigned long audio_recorded_time(void) | ||
2580 | { | ||
2581 | /* a dummy */ | ||
2582 | return 0; | ||
2583 | } | ||
2584 | void audio_beep(int duration) | ||
2585 | { | ||
2586 | /* a dummy */ | ||
2587 | (void)duration; | ||
2588 | } | ||
2589 | void audio_pause_recording(void) | ||
2590 | { | ||
2591 | /* a dummy */ | ||
2592 | } | ||
2593 | void audio_resume_recording(void) | ||
2594 | { | ||
2595 | /* a dummy */ | ||
2596 | } | ||
2597 | unsigned long audio_num_recorded_bytes(void) | ||
2598 | { | ||
2599 | /* a dummy */ | ||
2600 | return 0; | ||
2601 | } | ||
2602 | void audio_record(const char *filename) | ||
2603 | { | ||
2604 | /* a dummy */ | ||
2605 | (void)filename; | ||
2606 | } | ||
2607 | void audio_new_file(const char *filename) | ||
2608 | { | ||
2609 | /* a dummy */ | ||
2610 | (void)filename; | ||
2611 | } | ||
2612 | |||
2613 | void audio_set_recording_gain(int left, int right, int type) | ||
2614 | { | ||
2615 | /* a dummy */ | ||
2616 | (void)left; | ||
2617 | (void)right; | ||
2618 | (void)type; | ||
2619 | } | ||
2620 | void audio_init_recording(unsigned int buffer_offset) | ||
2621 | { | ||
2622 | /* a dummy */ | ||
2623 | (void)buffer_offset; | ||
2624 | } | ||
2625 | void audio_set_recording_options(struct audio_recording_options *options) | ||
2626 | { | ||
2627 | /* a dummy */ | ||
2628 | (void)options; | ||
2629 | } | ||
2630 | #endif /* SIMULATOR */ | ||
2631 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
2632 | |||
2633 | void audio_play(long offset) | ||
2634 | { | ||
2635 | #ifdef SIMULATOR | ||
2636 | char* trackname; | ||
2637 | int steps=0; | ||
2638 | |||
2639 | is_playing = true; | ||
2640 | |||
2641 | do { | ||
2642 | trackname = playlist_peek( steps ); | ||
2643 | if (!trackname) | ||
2644 | break; | ||
2645 | if(mp3info(&taginfo, trackname)) { | ||
2646 | /* bad mp3, move on */ | ||
2647 | if(++steps > playlist_amount()) | ||
2648 | break; | ||
2649 | continue; | ||
2650 | } | ||
2651 | #ifdef HAVE_MPEG_PLAY | ||
2652 | real_mpeg_play(trackname); | ||
2653 | #endif | ||
2654 | playlist_next(steps); | ||
2655 | taginfo.offset = offset; | ||
2656 | set_elapsed(&taginfo); | ||
2657 | is_playing = true; | ||
2658 | playing = true; | ||
2659 | break; | ||
2660 | } while(1); | ||
2661 | #else /* !SIMULATOR */ | ||
2662 | is_playing = true; | ||
2663 | |||
2664 | queue_post(&mpeg_queue, MPEG_PLAY, offset); | ||
2665 | #endif /* !SIMULATOR */ | ||
2666 | |||
2667 | mpeg_errno = 0; | ||
2668 | } | ||
2669 | |||
2670 | void audio_stop(void) | ||
2671 | { | ||
2672 | #ifndef SIMULATOR | ||
2673 | if (playing) | ||
2674 | { | ||
2675 | struct trackdata *track = get_trackdata(0); | ||
2676 | prev_track_elapsed = track->id3.elapsed; | ||
2677 | } | ||
2678 | mpeg_stop_done = false; | ||
2679 | queue_post(&mpeg_queue, MPEG_STOP, 0); | ||
2680 | while(!mpeg_stop_done) | ||
2681 | yield(); | ||
2682 | #else /* SIMULATOR */ | ||
2683 | paused = false; | ||
2684 | is_playing = false; | ||
2685 | playing = false; | ||
2686 | #endif /* SIMULATOR */ | ||
2687 | } | ||
2688 | |||
2689 | /* dummy */ | ||
2690 | void audio_stop_recording(void) | ||
2691 | { | ||
2692 | audio_stop(); | ||
2693 | } | ||
2694 | |||
2695 | void audio_pause(void) | ||
2696 | { | ||
2697 | #ifndef SIMULATOR | ||
2698 | queue_post(&mpeg_queue, MPEG_PAUSE, 0); | ||
2699 | #else /* SIMULATOR */ | ||
2700 | is_playing = true; | ||
2701 | playing = false; | ||
2702 | paused = true; | ||
2703 | #endif /* SIMULATOR */ | ||
2704 | } | ||
2705 | |||
2706 | void audio_resume(void) | ||
2707 | { | ||
2708 | #ifndef SIMULATOR | ||
2709 | queue_post(&mpeg_queue, MPEG_RESUME, 0); | ||
2710 | #else /* SIMULATOR */ | ||
2711 | is_playing = true; | ||
2712 | playing = true; | ||
2713 | paused = false; | ||
2714 | #endif /* SIMULATOR */ | ||
2715 | } | ||
2716 | |||
2717 | void audio_next(void) | ||
2718 | { | ||
2719 | #ifndef SIMULATOR | ||
2720 | queue_remove_from_head(&mpeg_queue, MPEG_NEED_DATA); | ||
2721 | queue_post(&mpeg_queue, MPEG_NEXT, 0); | ||
2722 | #else /* SIMULATOR */ | ||
2723 | char* file; | ||
2724 | int steps = 1; | ||
2725 | int index; | ||
2726 | |||
2727 | do { | ||
2728 | file = playlist_peek(steps); | ||
2729 | if(!file) | ||
2730 | break; | ||
2731 | if(mp3info(&taginfo, file)) { | ||
2732 | if(++steps > playlist_amount()) | ||
2733 | break; | ||
2734 | continue; | ||
2735 | } | ||
2736 | index = playlist_next(steps); | ||
2737 | taginfo.index = index; | ||
2738 | current_track_counter++; | ||
2739 | is_playing = true; | ||
2740 | playing = true; | ||
2741 | break; | ||
2742 | } while(1); | ||
2743 | #endif /* SIMULATOR */ | ||
2744 | } | ||
2745 | |||
2746 | void audio_prev(void) | ||
2747 | { | ||
2748 | #ifndef SIMULATOR | ||
2749 | queue_remove_from_head(&mpeg_queue, MPEG_NEED_DATA); | ||
2750 | queue_post(&mpeg_queue, MPEG_PREV, 0); | ||
2751 | #else /* SIMULATOR */ | ||
2752 | char* file; | ||
2753 | int steps = -1; | ||
2754 | int index; | ||
2755 | |||
2756 | do { | ||
2757 | file = playlist_peek(steps); | ||
2758 | if(!file) | ||
2759 | break; | ||
2760 | if(mp3info(&taginfo, file)) { | ||
2761 | steps--; | ||
2762 | continue; | ||
2763 | } | ||
2764 | index = playlist_next(steps); | ||
2765 | taginfo.index = index; | ||
2766 | current_track_counter++; | ||
2767 | is_playing = true; | ||
2768 | playing = true; | ||
2769 | break; | ||
2770 | } while(1); | ||
2771 | #endif /* SIMULATOR */ | ||
2772 | } | ||
2773 | |||
2774 | void audio_ff_rewind(long newtime) | ||
2775 | { | ||
2776 | #ifndef SIMULATOR | ||
2777 | queue_post(&mpeg_queue, MPEG_FF_REWIND, newtime); | ||
2778 | #else /* SIMULATOR */ | ||
2779 | (void)newtime; | ||
2780 | #endif /* SIMULATOR */ | ||
2781 | } | ||
2782 | |||
2783 | void audio_flush_and_reload_tracks(void) | ||
2784 | { | ||
2785 | #ifndef SIMULATOR | ||
2786 | queue_post(&mpeg_queue, MPEG_FLUSH_RELOAD, 0); | ||
2787 | #endif /* !SIMULATOR*/ | ||
2788 | } | ||
2789 | |||
2790 | int audio_status(void) | ||
2791 | { | ||
2792 | int ret = 0; | ||
2793 | |||
2794 | if(is_playing) | ||
2795 | ret |= AUDIO_STATUS_PLAY; | ||
2796 | |||
2797 | if(paused) | ||
2798 | ret |= AUDIO_STATUS_PAUSE; | ||
2799 | |||
2800 | #if (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR) | ||
2801 | if(is_recording && !is_prerecording) | ||
2802 | ret |= AUDIO_STATUS_RECORD; | ||
2803 | |||
2804 | if(is_prerecording) | ||
2805 | ret |= AUDIO_STATUS_PRERECORD; | ||
2806 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
2807 | |||
2808 | if(mpeg_errno) | ||
2809 | ret |= AUDIO_STATUS_ERROR; | ||
2810 | |||
2811 | return ret; | ||
2812 | } | ||
2813 | |||
2814 | unsigned int audio_error(void) | ||
2815 | { | ||
2816 | return mpeg_errno; | ||
2817 | } | ||
2818 | |||
2819 | void audio_error_clear(void) | ||
2820 | { | ||
2821 | mpeg_errno = 0; | ||
2822 | } | ||
2823 | |||
2824 | #ifdef SIMULATOR | ||
2825 | static void mpeg_thread(void) | ||
2826 | { | ||
2827 | struct mp3entry* id3; | ||
2828 | while ( 1 ) { | ||
2829 | if (is_playing) { | ||
2830 | id3 = audio_current_track(); | ||
2831 | if (!paused) | ||
2832 | { | ||
2833 | id3->elapsed+=1000; | ||
2834 | id3->offset+=1000; | ||
2835 | } | ||
2836 | if (id3->elapsed>=id3->length) | ||
2837 | audio_next(); | ||
2838 | } | ||
2839 | sleep(HZ); | ||
2840 | } | ||
2841 | } | ||
2842 | #endif /* SIMULATOR */ | ||
2843 | |||
2844 | void audio_init(void) | ||
2845 | { | ||
2846 | mpeg_errno = 0; | ||
2847 | |||
2848 | #ifndef SIMULATOR | ||
2849 | audiobuflen = audiobufend - audiobuf; | ||
2850 | queue_init(&mpeg_queue, true); | ||
2851 | #endif /* !SIMULATOR */ | ||
2852 | create_thread(mpeg_thread, mpeg_stack, | ||
2853 | sizeof(mpeg_stack), 0, mpeg_thread_name | ||
2854 | IF_PRIO(, PRIORITY_SYSTEM) | ||
2855 | IF_COP(, CPU)); | ||
2856 | |||
2857 | memset(trackdata, sizeof(trackdata), 0); | ||
2858 | |||
2859 | #if (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR) | ||
2860 | if (HW_MASK & PR_ACTIVE_HIGH) | ||
2861 | and_b(~0x08, &PADRH); | ||
2862 | else | ||
2863 | or_b(0x08, &PADRH); | ||
2864 | #endif /* CONFIG_CODEC == MAS3587F */ | ||
2865 | |||
2866 | #ifdef DEBUG | ||
2867 | dbg_timer_start(); | ||
2868 | dbg_cnt2us(0); | ||
2869 | #endif /* DEBUG */ | ||
2870 | } | ||
2871 | |||
2872 | #endif /* CONFIG_CODEC != SWCODEC */ | ||