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