blob: 273f630799afebe006e4675f9a46c71abe8cfa6d [file] [log] [blame]
Björn Stenberg1ac46002002-05-24 12:22:14 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include <stdbool.h>
Linus Nielsen Feltzing72d25352004-10-11 07:55:45 +000020#include <stdlib.h>
Linus Nielsen Feltzingc633ceb2002-06-07 14:41:26 +000021#include "config.h"
Jens Arnold1d38aa12005-08-19 06:43:50 +000022
Jens Arnoldd6c05452005-08-29 21:15:27 +000023#if CONFIG_CODEC != SWCODEC
Jens Arnold1d38aa12005-08-19 06:43:50 +000024
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +000025#include "debug.h"
26#include "panic.h"
27#include "id3.h"
28#include "mpeg.h"
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +000029#include "audio.h"
Björn Stenbergaba3d782002-07-16 12:22:31 +000030#include "ata.h"
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +000031#include "string.h"
Daniel Stenbergf9b44902003-02-07 09:41:57 +000032#include <kernel.h>
Kjell Ericsonddefd1e2003-01-10 09:19:10 +000033#include "thread.h"
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +000034#include "errno.h"
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000035#include "mp3data.h"
Linus Nielsen Feltzing20d031f2003-05-09 16:01:21 +000036#include "buffer.h"
Jörg Hohensohnf9933652004-01-05 20:42:51 +000037#include "mp3_playback.h"
Linus Nielsen Feltzing674eaca2005-04-01 13:41:03 +000038#include "sound.h"
Jens Arnold1d38aa12005-08-19 06:43:50 +000039#include "bitswap.h"
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +000040#ifndef SIMULATOR
Björn Stenberg1ac46002002-05-24 12:22:14 +000041#include "i2c.h"
42#include "mas.h"
43#include "dac.h"
Björn Stenberg1ac46002002-05-24 12:22:14 +000044#include "system.h"
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +000045#include "usb.h"
Björn Stenberg1ac46002002-05-24 12:22:14 +000046#include "file.h"
Linus Nielsen Feltzing8e4a0e02002-11-10 18:24:40 +000047#include "hwcompat.h"
Jens Arnold1d38aa12005-08-19 06:43:50 +000048#endif /* !SIMULATOR */
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +000049#ifdef HAVE_LCD_BITMAP
50#include "lcd.h"
51#endif
Linus Nielsen Feltzingbfc8d0a2002-08-20 14:22:11 +000052
Jens Arnold329caa82005-08-19 22:39:01 +000053#ifndef SIMULATOR
54extern unsigned long mas_version_code;
55#endif
56
Jens Arnoldd6c05452005-08-29 21:15:27 +000057#if CONFIG_CODEC == MAS3587F
Jens Arnold329caa82005-08-19 22:39:01 +000058extern enum /* from mp3_playback.c */
59{
60 MPEG_DECODER,
61 MPEG_ENCODER
62} mpeg_mode;
Jens Arnoldd6c05452005-08-29 21:15:27 +000063#endif /* CONFIG_CODEC == MAS3587F */
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +000064
Jens Arnold329caa82005-08-19 22:39:01 +000065extern char* playlist_peek(int steps);
66extern bool playlist_check(int steps);
67extern int playlist_next(int steps);
68extern int playlist_amount(void);
69extern int playlist_update_resume_info(const struct mp3entry* id3);
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +000070
Jens Arnold9352ac82005-09-04 21:55:15 +000071#define MPEG_PLAY 1
72#define MPEG_STOP 2
73#define MPEG_PAUSE 3
74#define MPEG_RESUME 4
75#define MPEG_NEXT 5
76#define MPEG_PREV 6
77#define MPEG_FF_REWIND 7
78#define MPEG_FLUSH_RELOAD 8
79#define MPEG_RECORD 9
80#define MPEG_INIT_RECORDING 10
81#define MPEG_INIT_PLAYBACK 11
82#define MPEG_NEW_FILE 12
83#define MPEG_PAUSE_RECORDING 13
84#define MPEG_RESUME_RECORDING 14
85#define MPEG_NEED_DATA 100
86#define MPEG_TRACK_CHANGE 101
87#define MPEG_SAVE_DATA 102
88#define MPEG_STOP_DONE 103
89#define MPEG_PRERECORDING_TICK 104
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +000090
Jens Arnolddece4142005-08-21 21:15:32 +000091/* indicator for MPEG_NEED_DATA */
Michael Sevakis4b902672006-12-19 16:50:07 +000092#define GENERATE_UNBUFFER_EVENTS 1
Jens Arnolddece4142005-08-21 21:15:32 +000093
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +000094/* list of tracks in memory */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +000095#define MAX_TRACK_ENTRIES (1<<4) /* Must be power of 2 */
96#define MAX_TRACK_ENTRIES_MASK (MAX_TRACK_ENTRIES - 1)
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +000097
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +000098struct trackdata
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +000099{
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +0000100 struct mp3entry id3;
101 int mempos;
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000102 int load_ahead_index;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000103};
104
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000105static struct trackdata trackdata[MAX_TRACK_ENTRIES];
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000106
Linus Nielsen Feltzinge5792d62002-07-25 23:12:41 +0000107static unsigned int current_track_counter = 0;
108static unsigned int last_track_counter = 0;
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +0000109
Linus Nielsen Feltzingda153da2006-10-19 09:42:58 +0000110/* Play time of the previous track */
111unsigned long prev_track_elapsed;
112
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +0000113#ifndef SIMULATOR
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000114static int track_read_idx = 0;
115static int track_write_idx = 0;
Jens Arnold329caa82005-08-19 22:39:01 +0000116#endif /* !SIMULATOR */
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000117
Jens Arnold509a96d2007-03-01 00:26:24 +0000118/* Cuesheet callback */
119static bool (*cuesheet_callback)(const char *filename) = NULL;
120
Jens Arnold329caa82005-08-19 22:39:01 +0000121static const char mpeg_thread_name[] = "mpeg";
122static unsigned int mpeg_errno;
123
Jens Arnold329caa82005-08-19 22:39:01 +0000124static bool playing = false; /* We are playing an MP3 stream */
125static bool is_playing = false; /* We are (attempting to) playing MP3 files */
126static bool paused; /* playback is paused */
127
128#ifdef SIMULATOR
129static char mpeg_stack[DEFAULT_STACK_SIZE];
130static struct mp3entry taginfo;
131
132#else /* !SIMULATOR */
133static struct event_queue mpeg_queue;
134static long mpeg_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
135
136static int audiobuflen;
137static int audiobuf_write;
138static int audiobuf_swapwrite;
139static int audiobuf_read;
140
141static int mpeg_file;
142
143static bool play_pending; /* We are about to start playing */
Robert Keevilb8bb5212007-08-23 18:53:17 +0000144static bool play_pending_track_change; /* When starting play we're starting a new file */
Jens Arnold329caa82005-08-19 22:39:01 +0000145static bool filling; /* We are filling the buffer with data from disk */
146static bool dma_underrun; /* True when the DMA has stopped because of
147 slow disk reading (read error, shaking) */
148static bool mpeg_stop_done;
149
150static int last_dma_tick = 0;
151static int last_dma_chunk_size;
152
153static long low_watermark; /* Dynamic low watermark level */
Nils Wallménius0bfa3e72007-08-01 08:50:44 +0000154static long low_watermark_margin = 0; /* Extra time in seconds for watermark */
Jens Arnold329caa82005-08-19 22:39:01 +0000155static long lowest_watermark_level; /* Debug value to observe the buffer
156 usage */
Jens Arnoldd6c05452005-08-29 21:15:27 +0000157#if CONFIG_CODEC == MAS3587F
Jens Arnold329caa82005-08-19 22:39:01 +0000158static char recording_filename[MAX_PATH]; /* argument to thread */
159static char delayed_filename[MAX_PATH]; /* internal copy of above */
160
Jens Arnold9352ac82005-09-04 21:55:15 +0000161static char xing_buffer[MAX_XING_HEADER_SIZE];
162
Jens Arnold329caa82005-08-19 22:39:01 +0000163static bool init_recording_done;
164static bool init_playback_done;
165static bool prerecording; /* True if prerecording is enabled */
166static bool is_prerecording; /* True if we are prerecording */
167static bool is_recording; /* We are recording */
Jens Arnold329caa82005-08-19 22:39:01 +0000168
169static enum {
170 NOT_SAVING = 0, /* reasons to save data, sorted by importance */
171 BUFFER_FULL,
172 NEW_FILE,
173 STOP_RECORDING
174} saving_status;
175
176static int rec_frequency_index; /* For create_xing_header() calls */
177static int rec_version_index; /* For create_xing_header() calls */
178
Jens Arnold9352ac82005-09-04 21:55:15 +0000179struct prerecord_info {
180 int mempos;
181 unsigned long framecount;
182};
183
184static struct prerecord_info prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS];
Jens Arnold329caa82005-08-19 22:39:01 +0000185static int prerecord_index; /* Current index in the prerecord buffer */
186static int prerecording_max_seconds; /* Max number of seconds to store */
187static int prerecord_count; /* Number of seconds in the prerecord buffer */
188static int prerecord_timeout; /* The tick count of the next prerecord data
189 store */
190
191unsigned long record_start_time; /* Value of current_tick when recording
192 was started */
193unsigned long pause_start_time; /* Value of current_tick when pause was
194 started */
Jens Arnoldba966c12005-09-15 05:29:26 +0000195static unsigned long last_rec_time;
Jens Arnold329caa82005-08-19 22:39:01 +0000196static unsigned long num_rec_bytes;
Jens Arnold9352ac82005-09-04 21:55:15 +0000197static unsigned long last_rec_bytes;
198static unsigned long frame_count_start;
199static unsigned long frame_count_end;
200static unsigned long saved_header = 0;
Jens Arnold329caa82005-08-19 22:39:01 +0000201
202/* Shadow MAS registers */
203unsigned long shadow_encoder_control = 0;
Jens Arnoldd6c05452005-08-29 21:15:27 +0000204#endif /* CONFIG_CODEC == MAS3587F */
Jens Arnold329caa82005-08-19 22:39:01 +0000205
Jens Arnoldd6c05452005-08-29 21:15:27 +0000206#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
Jens Arnold329caa82005-08-19 22:39:01 +0000207unsigned long shadow_io_control_main = 0;
208unsigned long shadow_soft_mute = 0;
209unsigned shadow_codec_reg0;
Jens Arnoldd6c05452005-08-29 21:15:27 +0000210#endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
Jens Arnold329caa82005-08-19 22:39:01 +0000211
212#ifdef HAVE_RECORDING
213const unsigned char empty_id3_header[] =
214{
215 'I', 'D', '3', 0x03, 0x00, 0x00,
216 0x00, 0x00, 0x1f, 0x76 /* Size is 4096 minus 10 bytes for the header */
217};
218#endif /* HAVE_RECORDING */
219
220
221static int get_unplayed_space(void);
222static int get_playable_space(void);
223static int get_unswapped_space(void);
224#endif /* !SIMULATOR */
225
Jens Arnold8051a0b2005-11-06 23:12:11 +0000226#if (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR)
Jens Arnold329caa82005-08-19 22:39:01 +0000227static void init_recording(void);
Jens Arnold9352ac82005-09-04 21:55:15 +0000228static void prepend_header(void);
229static void update_header(void);
Jens Arnold329caa82005-08-19 22:39:01 +0000230static void start_prerecording(void);
231static void start_recording(void);
232static void stop_recording(void);
233static int get_unsaved_space(void);
234static void pause_recording(void);
235static void resume_recording(void);
Jens Arnold8051a0b2005-11-06 23:12:11 +0000236#endif /* (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR) */
Jens Arnold329caa82005-08-19 22:39:01 +0000237
238
239#ifndef SIMULATOR
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000240static int num_tracks_in_memory(void)
241{
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000242 return (track_write_idx - track_read_idx) & MAX_TRACK_ENTRIES_MASK;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000243}
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000244
Jens Arnold329caa82005-08-19 22:39:01 +0000245#ifdef DEBUG_TAGS
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000246static void debug_tags(void)
247{
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000248 int i;
249
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000250 for(i = 0;i < MAX_TRACK_ENTRIES;i++)
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000251 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000252 DEBUGF("%d - %s\n", i, trackdata[i].id3.path);
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000253 }
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000254 DEBUGF("read: %d, write :%d\n", track_read_idx, track_write_idx);
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000255 DEBUGF("num_tracks_in_memory: %d\n", num_tracks_in_memory());
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000256}
Jens Arnold329caa82005-08-19 22:39:01 +0000257#else /* !DEBUG_TAGS */
258#define debug_tags()
259#endif /* !DEBUG_TAGS */
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000260
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000261static void remove_current_tag(void)
262{
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000263 if(num_tracks_in_memory() > 0)
264 {
265 /* First move the index, so nobody tries to access the tag */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000266 track_read_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000267 debug_tags();
268 }
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000269 else
270 {
271 DEBUGF("remove_current_tag: no tracks to remove\n");
272 }
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000273}
274
Björn Stenberg05704972002-08-14 19:23:34 +0000275static void remove_all_non_current_tags(void)
276{
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000277 track_write_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK;
Björn Stenberg05704972002-08-14 19:23:34 +0000278 debug_tags();
279}
280
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000281static void remove_all_tags(void)
282{
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000283 track_write_idx = track_read_idx;
Hardeep Sidhud3d1b982002-12-19 00:58:11 +0000284
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000285 debug_tags();
286}
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000287
288static struct trackdata *get_trackdata(int offset)
289{
Henrik Backea670e342005-07-08 09:55:22 +0000290 if(offset >= num_tracks_in_memory())
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000291 return NULL;
292 else
293 return &trackdata[(track_read_idx + offset) & MAX_TRACK_ENTRIES_MASK];
294}
Jens Arnold1d38aa12005-08-19 06:43:50 +0000295#endif /* !SIMULATOR */
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000296
Linus Nielsen Feltzing0ad617c2005-08-21 23:01:12 +0000297/***********************************************************************/
298/* audio event handling */
299
300#define MAX_EVENT_HANDLERS 10
301struct event_handlers_table
302{
303 AUDIO_EVENT_HANDLER handler;
304 unsigned short mask;
305};
306static struct event_handlers_table event_handlers[MAX_EVENT_HANDLERS];
307static int event_handlers_count = 0;
308
309void audio_register_event_handler(AUDIO_EVENT_HANDLER handler, unsigned short mask)
310{
311 if (event_handlers_count < MAX_EVENT_HANDLERS)
312 {
313 event_handlers[event_handlers_count].handler = handler;
314 event_handlers[event_handlers_count].mask = mask;
315 event_handlers_count++;
316 }
317}
318
319/* dispatch calls each handler in the order registered and returns after some
320 handler actually handles the event (the event is assumed to no longer be valid
321 after this, due to the handler changing some condition); returns true if someone
322 handled the event, which is expected to cause the caller to skip its own handling
323 of the event */
324#ifndef SIMULATOR
325static bool audio_dispatch_event(unsigned short event, unsigned long data)
326{
327 int i = 0;
328 for(i=0; i < event_handlers_count; i++)
329 {
330 if ( event_handlers[i].mask & event )
331 {
332 int rc = event_handlers[i].handler(event, data);
333 if ( rc == AUDIO_EVENT_RC_HANDLED )
334 return true;
335 }
336 }
337 return false;
338}
339#endif
340
341/***********************************************************************/
342
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000343static void set_elapsed(struct mp3entry* id3)
344{
345 if ( id3->vbr ) {
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000346 if ( id3->has_toc ) {
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000347 /* calculate elapsed time using TOC */
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000348 int i;
349 unsigned int remainder, plen, relpos, nextpos;
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000350
351 /* find wich percent we're at */
352 for (i=0; i<100; i++ )
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000353 {
Jens Arnoldec9b2022005-09-10 12:28:16 +0000354 if ( id3->offset < id3->toc[i] * (id3->filesize / 256) )
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000355 {
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000356 break;
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000357 }
358 }
359
360 i--;
361 if (i < 0)
362 i = 0;
363
364 relpos = id3->toc[i];
365
366 if (i < 99)
367 {
368 nextpos = id3->toc[i+1];
369 }
370 else
371 {
372 nextpos = 256;
373 }
374
375 remainder = id3->offset - (relpos * (id3->filesize / 256));
376
Björn Stenberg972f4312003-10-17 15:11:09 +0000377 /* set time for this percent (divide before multiply to prevent
378 overflow on long files. loss of precision is negligible on
379 short files) */
380 id3->elapsed = i * (id3->length / 100);
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000381
382 /* calculate remainder time */
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000383 plen = (nextpos - relpos) * (id3->filesize / 256);
Björn Stenberg972f4312003-10-17 15:11:09 +0000384 id3->elapsed += (((remainder * 100) / plen) *
385 (id3->length / 10000));
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000386 }
387 else {
388 /* no TOC exists. set a rough estimate using average bitrate */
Björn Stenberg989a3ec2003-01-09 01:02:40 +0000389 int tpk = id3->length / (id3->filesize / 1024);
Björn Stenberg972f4312003-10-17 15:11:09 +0000390 id3->elapsed = id3->offset / 1024 * tpk;
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000391 }
392 }
393 else
Jens Arnoldec9b2022005-09-10 12:28:16 +0000394 /* constant bitrate, use exact calculation */
395 id3->elapsed = id3->offset / (id3->bitrate / 8);
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000396}
397
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +0000398int audio_get_file_pos(void)
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000399{
400 int pos = -1;
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +0000401 struct mp3entry *id3 = audio_current_track();
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000402
403 if (id3->vbr)
404 {
405 if (id3->has_toc)
406 {
407 /* Use the TOC to find the new position */
408 unsigned int percent, remainder;
409 int curtoc, nexttoc, plen;
410
Jens Arnoldec9b2022005-09-10 12:28:16 +0000411 percent = (id3->elapsed*100)/id3->length;
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000412 if (percent > 99)
413 percent = 99;
414
415 curtoc = id3->toc[percent];
416
417 if (percent < 99)
418 nexttoc = id3->toc[percent+1];
419 else
420 nexttoc = 256;
421
422 pos = (id3->filesize/256)*curtoc;
423
424 /* Use the remainder to get a more accurate position */
425 remainder = (id3->elapsed*100)%id3->length;
426 remainder = (remainder*100)/id3->length;
427 plen = (nexttoc - curtoc)*(id3->filesize/256);
428 pos += (plen/100)*remainder;
429 }
430 else
431 {
432 /* No TOC exists, estimate the new position */
433 pos = (id3->filesize / (id3->length / 1000)) *
434 (id3->elapsed / 1000);
435 }
436 }
Jens Arnoldec9b2022005-09-10 12:28:16 +0000437 else if (id3->bitrate)
438 pos = id3->elapsed * (id3->bitrate / 8);
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000439 else
440 {
441 return -1;
442 }
443
444 if (pos >= (int)(id3->filesize - id3->id3v1len))
445 {
446 /* Don't seek right to the end of the file so that we can
447 transition properly to the next song */
448 pos = id3->filesize - id3->id3v1len - 1;
449 }
450 else if (pos < (int)id3->first_frame_offset)
451 {
452 /* skip past id3v2 tag and other leading garbage */
453 pos = id3->first_frame_offset;
454 }
455 return pos;
456}
457
458unsigned long mpeg_get_last_header(void)
459{
460#ifdef SIMULATOR
461 return 0;
Jens Arnold1d38aa12005-08-19 06:43:50 +0000462#else /* !SIMULATOR */
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000463 unsigned long tmp[2];
464
465 /* Read the frame data from the MAS and reconstruct it with the
466 frame sync and all */
Jens Arnoldeaa1f732004-09-29 19:51:41 +0000467 mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_STATUS_1, tmp, 2);
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000468 return 0xffe00000 | ((tmp[0] & 0x7c00) << 6) | (tmp[1] & 0xffff);
Jens Arnold1d38aa12005-08-19 06:43:50 +0000469#endif /* !SIMULATOR */
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000470}
471
Jens Arnold509a96d2007-03-01 00:26:24 +0000472void audio_set_cuesheet_callback(bool (*handler)(const char *filename))
473{
474 cuesheet_callback = handler;
475}
476
Jens Arnold329caa82005-08-19 22:39:01 +0000477#ifndef SIMULATOR
Jens Arnolddece4142005-08-21 21:15:32 +0000478/* Send callback events to notify about removing old tracks. */
479static void generate_unbuffer_events(void)
480{
481 int i;
Jens Arnolddece4142005-08-21 21:15:32 +0000482 int numentries = MAX_TRACK_ENTRIES - num_tracks_in_memory();
483 int cur_idx = track_write_idx;
Jens Arnolddece4142005-08-21 21:15:32 +0000484
485 for (i = 0; i < numentries; i++)
486 {
487 /* Send an event to notify that track has finished. */
Jonathan Gordona67e5d82008-03-17 05:22:53 +0000488 send_event(PLAYBACK_EVENT_TRACK_FINISH, &trackdata[cur_idx].id3);
Jens Arnolddece4142005-08-21 21:15:32 +0000489 cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK;
490 }
491}
492
493/* Send callback events to notify about new tracks. */
494static void generate_postbuffer_events(void)
495{
496 int i;
Jens Arnolddece4142005-08-21 21:15:32 +0000497 int numentries = num_tracks_in_memory();
498 int cur_idx = track_read_idx;
499
500 for (i = 0; i < numentries; i++)
501 {
Jonathan Gordona67e5d82008-03-17 05:22:53 +0000502 send_event(PLAYBACK_EVENT_TRACK_BUFFER, &trackdata[cur_idx].id3);
Jens Arnolddece4142005-08-21 21:15:32 +0000503 cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK;
504 }
505}
506
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +0000507static void recalculate_watermark(int bitrate)
508{
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000509 int bytes_per_sec;
Linus Nielsen Feltzing672479c2002-12-05 21:56:53 +0000510 int time = ata_spinup_time;
511
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000512 /* A bitrate of 0 probably means empty VBR header. We play safe
513 and set a high threshold */
514 if(bitrate == 0)
Linus Nielsen Feltzing27539aa2003-03-24 11:40:59 +0000515 bitrate = 320;
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000516
517 bytes_per_sec = bitrate * 1000 / 8;
518
Linus Nielsen Feltzing672479c2002-12-05 21:56:53 +0000519 if(time)
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +0000520 {
Linus Nielsen Feltzingc9feaaf2002-12-05 23:02:36 +0000521 /* No drive spins up faster than 3.5s */
522 if(time < 350)
523 time = 350;
Linus Nielsen Feltzing672479c2002-12-05 21:56:53 +0000524
525 time = time * 3;
526 low_watermark = ((low_watermark_margin * HZ + time) *
527 bytes_per_sec) / HZ;
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +0000528 }
529 else
530 {
531 low_watermark = MPEG_LOW_WATER;
532 }
533}
534
Nils Wallménius0bfa3e72007-08-01 08:50:44 +0000535#ifndef HAVE_FLASH_STORAGE
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +0000536void audio_set_buffer_margin(int seconds)
Linus Nielsen Feltzingb8ff5f82002-12-05 13:09:51 +0000537{
538 low_watermark_margin = seconds;
539}
Nils Wallménius0bfa3e72007-08-01 08:50:44 +0000540#endif
Linus Nielsen Feltzingb8ff5f82002-12-05 13:09:51 +0000541
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +0000542void audio_get_debugdata(struct audio_debug *dbgdata)
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000543{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000544 dbgdata->audiobuflen = audiobuflen;
545 dbgdata->audiobuf_write = audiobuf_write;
546 dbgdata->audiobuf_swapwrite = audiobuf_swapwrite;
547 dbgdata->audiobuf_read = audiobuf_read;
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000548
549 dbgdata->last_dma_chunk_size = last_dma_chunk_size;
550
Daniel Stenberg301f53f2005-02-02 22:04:15 +0000551#if CONFIG_CPU == SH7034
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000552 dbgdata->dma_on = (SCR0 & 0x80) != 0;
Daniel Stenberg301f53f2005-02-02 22:04:15 +0000553#endif
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000554 dbgdata->playing = playing;
555 dbgdata->play_pending = play_pending;
556 dbgdata->is_playing = is_playing;
557 dbgdata->filling = filling;
558 dbgdata->dma_underrun = dma_underrun;
559
560 dbgdata->unplayed_space = get_unplayed_space();
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000561 dbgdata->playable_space = get_playable_space();
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000562 dbgdata->unswapped_space = get_unswapped_space();
Linus Nielsen Feltzingbf303de2002-10-15 07:23:18 +0000563
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +0000564 dbgdata->low_watermark_level = low_watermark;
Linus Nielsen Feltzingbf303de2002-10-15 07:23:18 +0000565 dbgdata->lowest_watermark_level = lowest_watermark_level;
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000566}
567
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +0000568#ifdef DEBUG
569static void dbg_timer_start(void)
570{
571 /* We are using timer 2 */
572
573 TSTR &= ~0x04; /* Stop the timer */
574 TSNC &= ~0x04; /* No synchronization */
575 TMDR &= ~0x44; /* Operate normally */
576
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000577 TCNT2 = 0; /* Start counting at 0 */
578 TCR2 = 0x03; /* Sysclock/8 */
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +0000579
580 TSTR |= 0x04; /* Start timer 2 */
581}
582
583static int dbg_cnt2us(unsigned int cnt)
584{
585 return (cnt * 10000) / (FREQ/800);
586}
Jens Arnold1d38aa12005-08-19 06:43:50 +0000587#endif /* DEBUG */
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +0000588
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000589static int get_unplayed_space(void)
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000590{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000591 int space = audiobuf_write - audiobuf_read;
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000592 if (space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000593 space += audiobuflen;
Björn Stenberg749d87b2002-08-15 16:48:34 +0000594 return space;
595}
596
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000597static int get_playable_space(void)
598{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000599 int space = audiobuf_swapwrite - audiobuf_read;
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000600 if (space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000601 space += audiobuflen;
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000602 return space;
603}
604
Björn Stenberg749d87b2002-08-15 16:48:34 +0000605static int get_unplayed_space_current_song(void)
606{
607 int space;
608
609 if (num_tracks_in_memory() > 1)
610 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000611 space = get_trackdata(1)->mempos - audiobuf_read;
Björn Stenberg749d87b2002-08-15 16:48:34 +0000612 }
613 else
614 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000615 space = audiobuf_write - audiobuf_read;
Björn Stenberg749d87b2002-08-15 16:48:34 +0000616 }
617
618 if (space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000619 space += audiobuflen;
Björn Stenberg749d87b2002-08-15 16:48:34 +0000620
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000621 return space;
622}
623
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +0000624static int get_unswapped_space(void)
625{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000626 int space = audiobuf_write - audiobuf_swapwrite;
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +0000627 if (space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000628 space += audiobuflen;
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +0000629 return space;
630}
631
Jens Arnoldd6c05452005-08-29 21:15:27 +0000632#if CONFIG_CODEC == MAS3587F
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000633static int get_unsaved_space(void)
634{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000635 int space = audiobuf_write - audiobuf_read;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000636 if (space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000637 space += audiobuflen;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000638 return space;
639}
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +0000640
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000641static void drain_dma_buffer(void)
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +0000642{
Jens Arnoldff3add92005-05-23 18:56:15 +0000643 while (PBDRH & 0x40)
644 {
645 xor_b(0x08, &PADRH);
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +0000646
Jens Arnoldff3add92005-05-23 18:56:15 +0000647 while (PBDRH & 0x80);
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +0000648
Jens Arnoldff3add92005-05-23 18:56:15 +0000649 xor_b(0x08, &PADRH);
Jens Arnold536dff12004-08-05 17:06:31 +0000650
Jens Arnoldff3add92005-05-23 18:56:15 +0000651 while (!(PBDRH & 0x80));
652 }
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +0000653}
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000654
Jens Arnold329caa82005-08-19 22:39:01 +0000655#ifdef DEBUG
656static long timing_info_index = 0;
657static long timing_info[1024];
658#endif /* DEBUG */
659
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000660void rec_tick (void) __attribute__ ((section (".icode")));
661void rec_tick(void)
Björn Stenberg1ac46002002-05-24 12:22:14 +0000662{
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000663 int i;
Jens Arnoldff3add92005-05-23 18:56:15 +0000664 int delay;
665 char data;
666
667 if(is_recording && (PBDRH & 0x40))
Björn Stenberg1ac46002002-05-24 12:22:14 +0000668 {
Linus Nielsen Feltzing0dcd47e2002-11-19 09:50:19 +0000669#ifdef DEBUG
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000670 timing_info[timing_info_index++] = current_tick;
671 TCNT2 = 0;
Jens Arnold1d38aa12005-08-19 06:43:50 +0000672#endif /* DEBUG */
Jens Arnolde03f4022005-06-04 11:29:39 +0000673 /* Note: Although this loop is run in interrupt context, further
674 * optimisation will do no good. The MAS would then deliver bad
675 * frames occasionally, as observed in extended experiments. */
Jens Arnoldff3add92005-05-23 18:56:15 +0000676 i = 0;
677 while (PBDRH & 0x40) /* We try to read as long as EOD is high */
678 {
679 xor_b(0x08, &PADRH); /* Set PR active, independent of polarity */
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +0000680
Jens Arnolde03f4022005-06-04 11:29:39 +0000681 delay = 100;
Jens Arnoldff3add92005-05-23 18:56:15 +0000682 while (PBDRH & 0x80) /* Wait until /RTW becomes active */
683 {
Jens Arnolde03f4022005-06-04 11:29:39 +0000684 if (--delay <= 0) /* Bail out if we have to wait too long */
Jens Arnoldff3add92005-05-23 18:56:15 +0000685 { /* i.e. the MAS doesn't want to talk to us */
686 xor_b(0x08, &PADRH); /* Set PR inactive */
687 goto transfer_end; /* and get out of here */
688 }
689 }
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000690
Jens Arnoldff3add92005-05-23 18:56:15 +0000691 data = *(unsigned char *)0x04000000; /* read data byte */
692
693 xor_b(0x08, &PADRH); /* Set PR inactive */
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000694
Jens Arnoldff3add92005-05-23 18:56:15 +0000695 audiobuf[audiobuf_write++] = data;
696
697 if (audiobuf_write >= audiobuflen)
698 audiobuf_write = 0;
699
700 i++;
701 }
702 transfer_end:
703
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000704#ifdef DEBUG
705 timing_info[timing_info_index++] = TCNT2 + (i << 16);
706 timing_info_index &= 0x3ff;
Jens Arnold1d38aa12005-08-19 06:43:50 +0000707#endif /* DEBUG */
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000708
709 num_rec_bytes += i;
Jens Arnolde03f4022005-06-04 11:29:39 +0000710
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000711 if(is_prerecording)
712 {
713 if(TIME_AFTER(current_tick, prerecord_timeout))
714 {
715 prerecord_timeout = current_tick + HZ;
Jens Arnold9352ac82005-09-04 21:55:15 +0000716 queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0);
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000717 }
718 }
719 else
720 {
721 /* Signal to save the data if we are running out of buffer
722 space */
Jens Arnold363bc492005-08-18 04:38:57 +0000723 if (audiobuflen - get_unsaved_space() < MPEG_RECORDING_LOW_WATER
Jens Arnolde03f4022005-06-04 11:29:39 +0000724 && saving_status == NOT_SAVING)
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000725 {
Jens Arnolde03f4022005-06-04 11:29:39 +0000726 saving_status = BUFFER_FULL;
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000727 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
Linus Nielsen Feltzing00b2aad2002-12-12 02:22:01 +0000728 }
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +0000729 }
730 }
Björn Stenberg1ac46002002-05-24 12:22:14 +0000731}
Jens Arnoldd6c05452005-08-29 21:15:27 +0000732#endif /* CONFIG_CODEC == MAS3587F */
Björn Stenberg1ac46002002-05-24 12:22:14 +0000733
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000734void playback_tick(void)
735{
Linus Nielsen Feltzing0ad617c2005-08-21 23:01:12 +0000736 struct trackdata *ptd = get_trackdata(0);
Linus Nielsen Feltzinge54aa2a2005-08-30 22:50:56 +0000737 if(ptd)
738 {
739 ptd->id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ;
740 last_dma_tick = current_tick;
741 audio_dispatch_event(AUDIO_EVENT_POS_REPORT,
742 (unsigned long)ptd->id3.elapsed);
743 }
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000744}
745
Björn Stenberg1ac46002002-05-24 12:22:14 +0000746static void reset_mp3_buffer(void)
747{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000748 audiobuf_read = 0;
749 audiobuf_write = 0;
750 audiobuf_swapwrite = 0;
751 lowest_watermark_level = audiobuflen;
Björn Stenberg1ac46002002-05-24 12:22:14 +0000752}
753
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000754 /* DMA transfer end interrupt callback */
Nils Wallméniusc7f9ca42007-06-13 15:35:07 +0000755static void transfer_end(unsigned char** ppbuf, size_t* psize)
Björn Stenberg3c260772002-05-24 15:27:55 +0000756{
Björn Stenberg34486b72002-08-19 11:00:29 +0000757 if(playing && !paused)
Björn Stenberg3c260772002-05-24 15:27:55 +0000758 {
Linus Nielsen Feltzinga46a5d32002-08-08 13:29:31 +0000759 int unplayed_space_left;
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000760 int space_until_end_of_buffer;
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000761 int track_offset = 1;
762 struct trackdata *track;
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000763
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000764 audiobuf_read += last_dma_chunk_size;
765 if(audiobuf_read >= audiobuflen)
766 audiobuf_read = 0;
Björn Stenberg3c260772002-05-24 15:27:55 +0000767
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000768 /* First, check if we are on a track boundary */
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000769 if (num_tracks_in_memory() > 1)
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000770 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000771 if (audiobuf_read == get_trackdata(track_offset)->mempos)
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000772 {
Linus Nielsen Feltzing0ad617c2005-08-21 23:01:12 +0000773 if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) )
774 {
775 queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0);
776 track_offset++;
777 }
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000778 }
779 }
780
Linus Nielsen Feltzinga46a5d32002-08-08 13:29:31 +0000781 unplayed_space_left = get_unplayed_space();
782
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000783 space_until_end_of_buffer = audiobuflen - audiobuf_read;
Björn Stenberg3c260772002-05-24 15:27:55 +0000784
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +0000785 if(!filling && unplayed_space_left < low_watermark)
Björn Stenberg3c260772002-05-24 15:27:55 +0000786 {
Linus Nielsen Feltzing3a25aa42002-05-29 12:25:21 +0000787 filling = true;
Jens Arnolddece4142005-08-21 21:15:32 +0000788 queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS);
Björn Stenberg3c260772002-05-24 15:27:55 +0000789 }
790
791 if(unplayed_space_left)
792 {
Linus Nielsen Feltzing9a9d9d02003-01-21 00:11:10 +0000793 last_dma_chunk_size = MIN(0x2000, unplayed_space_left);
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000794 last_dma_chunk_size = MIN(last_dma_chunk_size,
795 space_until_end_of_buffer);
Björn Stenbergbb9aaf52002-06-25 13:26:04 +0000796
Björn Stenberg200d2262002-06-26 12:05:06 +0000797 /* several tracks loaded? */
Linus Nielsen Feltzing80bb2812005-08-30 20:52:24 +0000798 track = get_trackdata(track_offset);
799 if(track)
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000800 {
Björn Stenberg200d2262002-06-26 12:05:06 +0000801 /* will we move across the track boundary? */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000802 if (( audiobuf_read < track->mempos ) &&
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000803 ((audiobuf_read+last_dma_chunk_size) >
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000804 track->mempos ))
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000805 {
806 /* Make sure that we end exactly on the boundary */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000807 last_dma_chunk_size = track->mempos - audiobuf_read;
Björn Stenberg200d2262002-06-26 12:05:06 +0000808 }
Björn Stenbergbb9aaf52002-06-25 13:26:04 +0000809 }
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000810
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000811 *psize = last_dma_chunk_size & 0xffff;
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000812 *ppbuf = audiobuf + audiobuf_read;
Linus Nielsen Feltzinge54aa2a2005-08-30 22:50:56 +0000813 track = get_trackdata(0);
814 if(track)
815 track->id3.offset += last_dma_chunk_size;
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000816
817 /* Update the watermark debug level */
818 if(unplayed_space_left < lowest_watermark_level)
819 lowest_watermark_level = unplayed_space_left;
Björn Stenberg3c260772002-05-24 15:27:55 +0000820 }
821 else
822 {
Linus Nielsen Feltzing33060d02002-10-09 13:25:03 +0000823 /* Check if the end of data is because of a hard disk error.
824 If there is an open file handle, we are still playing music.
825 If not, the last file has been loaded, and the file handle is
826 closed. */
827 if(mpeg_file >= 0)
828 {
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000829 /* Update the watermark debug level */
830 if(unplayed_space_left < lowest_watermark_level)
831 lowest_watermark_level = unplayed_space_left;
832
Linus Nielsen Feltzing33060d02002-10-09 13:25:03 +0000833 DEBUGF("DMA underrun.\n");
834 dma_underrun = true;
835 }
Linus Nielsen Feltzing26e7ec42002-10-09 09:15:28 +0000836 else
837 {
Linus Nielsen Feltzing0ad617c2005-08-21 23:01:12 +0000838 if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) )
839 {
840 DEBUGF("No more MP3 data. Stopping.\n");
841 queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0);
842 playing = false;
843 }
Linus Nielsen Feltzing26e7ec42002-10-09 09:15:28 +0000844 }
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000845 *psize = 0; /* no more transfer */
Björn Stenberg3c260772002-05-24 15:27:55 +0000846 }
847 }
Björn Stenberg3c260772002-05-24 15:27:55 +0000848}
849
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000850static struct trackdata *add_track_to_tag_list(const char *filename)
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000851{
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000852 struct trackdata *track;
853
854 if(num_tracks_in_memory() >= MAX_TRACK_ENTRIES)
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000855 {
856 DEBUGF("Tag memory is full\n");
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000857 return NULL;
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000858 }
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000859
860 track = &trackdata[track_write_idx];
861
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000862 /* grab id3 tag of new file and
863 remember where in memory it starts */
Thom Johansen294ec1d2007-09-19 10:40:55 +0000864 if(mp3info(&track->id3, filename))
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000865 {
866 DEBUGF("Bad mp3\n");
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000867 return NULL;
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000868 }
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000869 track->mempos = audiobuf_write;
870 track->id3.elapsed = 0;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000871#ifdef HAVE_LCD_BITMAP
Magnus Holmgren917f2c12005-12-22 21:42:00 +0000872 if (track->id3.title)
873 lcd_getstringsize(track->id3.title, NULL, NULL);
874 if (track->id3.artist)
875 lcd_getstringsize(track->id3.artist, NULL, NULL);
876 if (track->id3.album)
877 lcd_getstringsize(track->id3.album, NULL, NULL);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000878#endif
Jens Arnold509a96d2007-03-01 00:26:24 +0000879 if (cuesheet_callback)
880 if (cuesheet_callback(filename))
881 track->id3.cuesheet_type = 1;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000882
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000883 track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK;
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000884 debug_tags();
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000885 return track;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000886}
887
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000888static int new_file(int steps)
Björn Stenbergfa8cd2c2002-05-31 12:12:23 +0000889{
Linus Nielsen Feltzing56e5d1a2002-10-09 13:47:38 +0000890 int max_steps = playlist_amount();
Linus Nielsen Feltzing685aeb52004-11-15 00:34:19 +0000891 int start = 0;
892 int i;
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000893 struct trackdata *track;
Linus Nielsen Feltzing685aeb52004-11-15 00:34:19 +0000894
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000895 /* Find out how many steps to advance. The load_ahead_index field tells
896 us how many playlist entries it had to skip to get to a valid one.
897 We add those together to find out where to start. */
898 if(steps > 0 && num_tracks_in_memory() > 1)
Linus Nielsen Feltzing685aeb52004-11-15 00:34:19 +0000899 {
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000900 /* Begin with the song after the currently playing one */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000901 i = 1;
902 while((track = get_trackdata(i++)))
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000903 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000904 start += track->load_ahead_index;
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000905 }
Linus Nielsen Feltzing685aeb52004-11-15 00:34:19 +0000906 }
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000907
Björn Stenbergf952ba72002-07-18 15:37:41 +0000908 do {
Björn Stenberg6224cdb2002-08-16 14:41:47 +0000909 char *trackname;
Björn Stenberg6224cdb2002-08-16 14:41:47 +0000910
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +0000911 trackname = playlist_peek( start + steps );
Björn Stenbergf952ba72002-07-18 15:37:41 +0000912 if ( !trackname )
913 return -1;
914
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000915 DEBUGF("Loading %s\n", trackname);
Björn Stenbergf952ba72002-07-18 15:37:41 +0000916
917 mpeg_file = open(trackname, O_RDONLY);
918 if(mpeg_file < 0) {
919 DEBUGF("Couldn't open file: %s\n",trackname);
Linus Nielsen Feltzing72d25352004-10-11 07:55:45 +0000920 if(steps < 0)
921 steps--;
922 else
923 steps++;
Björn Stenbergf952ba72002-07-18 15:37:41 +0000924 }
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000925 else
926 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000927 struct trackdata *track = add_track_to_tag_list(trackname);
Linus Nielsen Feltzingccfef042002-08-28 10:21:32 +0000928
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000929 if(!track)
Linus Nielsen Feltzing606b0f52002-08-28 11:43:49 +0000930 {
931 /* Bad mp3 file */
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000932 if(steps < 0)
933 steps--;
934 else
935 steps++;
Linus Nielsen Feltzing606b0f52002-08-28 11:43:49 +0000936 close(mpeg_file);
937 mpeg_file = -1;
938 }
939 else
940 {
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +0000941 /* skip past id3v2 tag */
Linus Nielsen Feltzing606b0f52002-08-28 11:43:49 +0000942 lseek(mpeg_file,
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000943 track->id3.first_frame_offset,
Linus Nielsen Feltzing606b0f52002-08-28 11:43:49 +0000944 SEEK_SET);
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000945 track->id3.index = steps;
946 track->load_ahead_index = steps;
947 track->id3.offset = 0;
Linus Nielsen Feltzingce882bb2002-12-05 15:23:46 +0000948
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000949 if(track->id3.vbr)
Linus Nielsen Feltzing672479c2002-12-05 21:56:53 +0000950 /* Average bitrate * 1.5 */
Linus Nielsen Feltzingce882bb2002-12-05 15:23:46 +0000951 recalculate_watermark(
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000952 (track->id3.bitrate * 3) / 2);
Linus Nielsen Feltzingce882bb2002-12-05 15:23:46 +0000953 else
954 recalculate_watermark(
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000955 track->id3.bitrate);
Linus Nielsen Feltzingce882bb2002-12-05 15:23:46 +0000956
Linus Nielsen Feltzing606b0f52002-08-28 11:43:49 +0000957 }
Björn Stenbergf952ba72002-07-18 15:37:41 +0000958 }
Linus Nielsen Feltzing319d5f72004-11-05 07:43:39 +0000959
960 /* Bail out if no file could be opened */
961 if(abs(steps) > max_steps)
962 return -1;
Björn Stenbergf952ba72002-07-18 15:37:41 +0000963 } while ( mpeg_file < 0 );
Björn Stenbergfa8cd2c2002-05-31 12:12:23 +0000964
Björn Stenbergfa8cd2c2002-05-31 12:12:23 +0000965 return 0;
966}
967
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +0000968static void stop_playing(void)
969{
Robert Keevilb8bb5212007-08-23 18:53:17 +0000970 struct trackdata *track;
971
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +0000972 /* Stop the current stream */
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000973 mp3_play_stop();
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +0000974 playing = false;
975 filling = false;
Robert Keevilb8bb5212007-08-23 18:53:17 +0000976
977 track = get_trackdata(0);
978 if (track != NULL)
979 prev_track_elapsed = track->id3.elapsed;
980
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +0000981 if(mpeg_file >= 0)
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +0000982 close(mpeg_file);
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +0000983 mpeg_file = -1;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000984 remove_all_tags();
Jens Arnolddece4142005-08-21 21:15:32 +0000985 generate_unbuffer_events();
Jörg Hohensohn30c338a2004-05-09 09:36:58 +0000986 reset_mp3_buffer();
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +0000987}
988
Robert Keevilb8bb5212007-08-23 18:53:17 +0000989static void end_current_track(void) {
990 struct trackdata *track;
991
992 play_pending = false;
993 playing = false;
994 mp3_play_pause(false);
995
996 track = get_trackdata(0);
997 if (track != NULL)
998 prev_track_elapsed = track->id3.elapsed;
999
1000 reset_mp3_buffer();
1001 remove_all_tags();
1002 generate_unbuffer_events();
1003
1004 if(mpeg_file >= 0)
1005 close(mpeg_file);
1006}
1007
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001008/* Is this a really the end of playback or is a new playlist starting */
1009static void check_playlist_end(int direction)
1010{
Hardeep Sidhu1df2edb2005-11-08 06:33:36 +00001011 /* Use the largest possible step size to account for skipped tracks */
1012 int steps = playlist_amount();
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001013
Hardeep Sidhu1df2edb2005-11-08 06:33:36 +00001014 if (direction < 0)
1015 steps = -steps;
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001016
Hardeep Sidhu1df2edb2005-11-08 06:33:36 +00001017 if (playlist_next(steps) < 0)
1018 is_playing = false;
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001019}
1020
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001021static void update_playlist(void)
1022{
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001023 if (num_tracks_in_memory() > 0)
1024 {
Hardeep Sidhu74d082c2005-06-25 04:46:25 +00001025 struct trackdata *track = get_trackdata(0);
1026 track->id3.index = playlist_next(track->id3.index);
1027 }
1028 else
1029 {
Hardeep Sidhu71d22812005-07-01 11:25:16 +00001030 /* End of playlist? */
Hardeep Sidhu1df2edb2005-11-08 06:33:36 +00001031 check_playlist_end(1);
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001032 }
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001033
1034 playlist_update_resume_info(audio_current_track());
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001035}
1036
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001037static void track_change(void)
1038{
1039 DEBUGF("Track change\n");
1040
Linus Nielsen Feltzingda153da2006-10-19 09:42:58 +00001041 struct trackdata *track = get_trackdata(0);
1042 prev_track_elapsed = track->id3.elapsed;
1043
Jens Arnoldd6c05452005-08-29 21:15:27 +00001044#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001045 /* Reset the AVC */
Jens Arnold65c17462005-11-07 20:35:24 +00001046 sound_set_avc(-1);
Jens Arnoldd6c05452005-08-29 21:15:27 +00001047#endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001048
Hardeep Sidhuc8ce78a2005-07-01 12:06:30 +00001049 if (num_tracks_in_memory() > 0)
1050 {
1051 remove_current_tag();
Jonathan Gordona67e5d82008-03-17 05:22:53 +00001052 send_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_current_track());
Hardeep Sidhuc8ce78a2005-07-01 12:06:30 +00001053 update_playlist();
1054 }
1055
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00001056 current_track_counter++;
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001057}
1058
Linus Nielsen Feltzingda153da2006-10-19 09:42:58 +00001059unsigned long audio_prev_elapsed(void)
1060{
1061 return prev_track_elapsed;
1062}
1063
Linus Nielsen Feltzingb3bb0762002-09-18 13:51:08 +00001064#ifdef DEBUG
Jens Arnoldc76c5682004-08-16 23:37:23 +00001065void hexdump(const unsigned char *buf, int len)
Linus Nielsen Feltzingb3bb0762002-09-18 13:51:08 +00001066{
1067 int i;
1068
1069 for(i = 0;i < len;i++)
1070 {
1071 if(i && (i & 15) == 0)
1072 {
1073 DEBUGF("\n");
1074 }
1075 DEBUGF("%02x ", buf[i]);
1076 }
1077 DEBUGF("\n");
1078}
Jens Arnold1d38aa12005-08-19 06:43:50 +00001079#endif /* DEBUG */
Linus Nielsen Feltzingb3bb0762002-09-18 13:51:08 +00001080
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001081static void start_playback_if_ready(void)
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001082{
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001083 int playable_space;
1084
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001085 playable_space = audiobuf_swapwrite - audiobuf_read;
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001086 if(playable_space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001087 playable_space += audiobuflen;
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001088
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001089 /* See if we have started playing yet. If not, do it. */
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001090 if(play_pending || dma_underrun)
1091 {
1092 /* If the filling has stopped, and we still haven't reached
1093 the watermark, the file must be smaller than the
1094 watermark. We must still play it. */
Linus Nielsen Feltzing7fed4a02002-12-05 17:14:35 +00001095 if((playable_space >= MPEG_PLAY_PENDING_THRESHOLD) ||
Linus Nielsen Feltzing83444372002-12-05 11:09:52 +00001096 !filling || dma_underrun)
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001097 {
1098 DEBUGF("P\n");
Jens Arnolddece4142005-08-21 21:15:32 +00001099 if (play_pending) /* don't do this when recovering from DMA underrun */
1100 {
1101 generate_postbuffer_events(); /* signal first track as buffered */
Robert Keevilb8bb5212007-08-23 18:53:17 +00001102 if (play_pending_track_change)
1103 {
1104 play_pending_track_change = false;
Jonathan Gordona67e5d82008-03-17 05:22:53 +00001105 send_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_current_track());
Robert Keevilb8bb5212007-08-23 18:53:17 +00001106 }
Jens Arnolddece4142005-08-21 21:15:32 +00001107 play_pending = false;
1108 }
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001109 playing = true;
Jens Arnolddece4142005-08-21 21:15:32 +00001110
Linus Nielsen Feltzing66cda8c2004-04-09 21:03:09 +00001111 last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song());
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001112 mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end);
Linus Nielsen Feltzing66cda8c2004-04-09 21:03:09 +00001113 dma_underrun = false;
1114
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001115 if (!paused)
1116 {
1117 last_dma_tick = current_tick;
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001118 mp3_play_pause(true);
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001119 }
1120
1121 /* Tell ourselves that we need more data */
1122 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
1123 }
1124 }
1125}
1126
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001127static bool swap_one_chunk(void)
1128{
1129 int free_space_left;
1130 int amount_to_swap;
1131
1132 free_space_left = get_unswapped_space();
1133
1134 if(free_space_left == 0 && !play_pending)
1135 return false;
1136
1137 /* Swap in larger chunks when the user is waiting for the playback
Linus Nielsen Feltzingd199e692002-12-05 13:36:08 +00001138 to start, or when there is dangerously little playable data left */
Linus Nielsen Feltzing7fed4a02002-12-05 17:14:35 +00001139 if(play_pending)
1140 amount_to_swap = MIN(MPEG_PLAY_PENDING_SWAPSIZE, free_space_left);
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001141 else
Linus Nielsen Feltzing7fed4a02002-12-05 17:14:35 +00001142 {
1143 if(get_playable_space() < low_watermark)
1144 amount_to_swap = MIN(MPEG_LOW_WATER_SWAP_CHUNKSIZE,
1145 free_space_left);
1146 else
1147 amount_to_swap = MIN(MPEG_SWAP_CHUNKSIZE, free_space_left);
1148 }
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001149
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001150 if(audiobuf_write < audiobuf_swapwrite)
1151 amount_to_swap = MIN(audiobuflen - audiobuf_swapwrite,
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001152 amount_to_swap);
1153 else
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001154 amount_to_swap = MIN(audiobuf_write - audiobuf_swapwrite,
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001155 amount_to_swap);
Linus Nielsen Feltzing35c417f2003-04-12 09:38:33 +00001156
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001157 bitswap(audiobuf + audiobuf_swapwrite, amount_to_swap);
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001158
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001159 audiobuf_swapwrite += amount_to_swap;
1160 if(audiobuf_swapwrite >= audiobuflen)
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001161 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001162 audiobuf_swapwrite = 0;
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001163 }
1164
1165 return true;
1166}
Linus Nielsen Feltzinga5fbdbb2005-02-28 09:04:59 +00001167
Björn Stenberg1ac46002002-05-24 12:22:14 +00001168static void mpeg_thread(void)
1169{
Björn Stenberg0c2e9f22002-08-21 17:38:56 +00001170 static int pause_tick = 0;
1171 static unsigned int pause_track = 0;
Michael Sevakisa9b2fb52007-10-16 01:25:17 +00001172 struct queue_event ev;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001173 int len;
1174 int free_space_left;
Linus Nielsen Feltzing54a65f72002-07-21 07:12:39 +00001175 int unplayed_space_left;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001176 int amount_to_read;
Linus Nielsen Feltzing1d21ca92002-08-01 08:16:44 +00001177 int t1, t2;
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001178 int start_offset;
Jens Arnoldd6c05452005-08-29 21:15:27 +00001179#if CONFIG_CODEC == MAS3587F
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001180 int amount_to_save;
Jens Arnolde03f4022005-06-04 11:29:39 +00001181 int save_endpos = 0;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00001182 int rc;
Jens Arnold9352ac82005-09-04 21:55:15 +00001183 int level;
Jean-Philippe Bernardy3f65c3f2005-01-30 14:33:33 +00001184 long offset;
Jens Arnoldd6c05452005-08-29 21:15:27 +00001185#endif /* CONFIG_CODEC == MAS3587F */
Jens Arnolde03f4022005-06-04 11:29:39 +00001186
Linus Nielsen Feltzingccfef042002-08-28 10:21:32 +00001187 is_playing = false;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001188 play_pending = false;
1189 playing = false;
Linus Nielsen Feltzing60ed5ee2002-06-19 06:19:00 +00001190 mpeg_file = -1;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001191
1192 while(1)
1193 {
Jens Arnoldd6c05452005-08-29 21:15:27 +00001194#if CONFIG_CODEC == MAS3587F
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001195 if(mpeg_mode == MPEG_DECODER)
1196 {
Jens Arnoldd6c05452005-08-29 21:15:27 +00001197#endif /* CONFIG_CODEC == MAS3587F */
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001198 yield();
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001199
1200 /* Swap if necessary, and don't block on the queue_wait() */
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001201 if(swap_one_chunk())
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001202 {
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001203 queue_wait_w_tmo(&mpeg_queue, &ev, 0);
1204 }
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001205 else if (playing)
1206 {
1207 /* periodically update resume info */
1208 queue_wait_w_tmo(&mpeg_queue, &ev, HZ/2);
1209 }
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001210 else
1211 {
Linus Nielsen Feltzing647db262002-10-16 09:26:03 +00001212 DEBUGF("S R:%x W:%x SW:%x\n",
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001213 audiobuf_read, audiobuf_write, audiobuf_swapwrite);
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001214 queue_wait(&mpeg_queue, &ev);
1215 }
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001216
1217 start_playback_if_ready();
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001218
Björn Stenberg1ac46002002-05-24 12:22:14 +00001219 switch(ev.id)
1220 {
1221 case MPEG_PLAY:
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001222 DEBUGF("MPEG_PLAY\n");
Linus Nielsen Feltzing0a12f4e2003-05-03 10:03:30 +00001223
Jonathan Gordon00d249a2007-02-18 03:25:40 +00001224#if CONFIG_TUNER
Linus Nielsen Feltzing0a12f4e2003-05-03 10:03:30 +00001225 /* Silence the A/D input, it may be on because the radio
1226 may be playing */
1227 mas_codec_writereg(6, 0x0000);
Jens Arnold1d38aa12005-08-19 06:43:50 +00001228#endif /* CONFIG_TUNER */
Linus Nielsen Feltzing0a12f4e2003-05-03 10:03:30 +00001229
Björn Stenberg1ac46002002-05-24 12:22:14 +00001230 /* Stop the current stream */
Linus Nielsen Feltzing001226c2003-03-15 12:09:09 +00001231 paused = false;
Robert Keevilb8bb5212007-08-23 18:53:17 +00001232 end_current_track();
Linus Nielsen Feltzing60ed5ee2002-06-19 06:19:00 +00001233
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001234 if ( new_file(0) == -1 )
Linus Nielsen Feltzingccfef042002-08-28 10:21:32 +00001235 {
1236 is_playing = false;
Hardeep Sidhu96a68742003-01-04 07:16:36 +00001237 track_change();
Linus Nielsen Feltzingccfef042002-08-28 10:21:32 +00001238 break;
1239 }
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001240
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001241 start_offset = (int)ev.data;
Björn Stenberg3a9e7b52002-08-20 20:38:50 +00001242
1243 /* mid-song resume? */
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001244 if (start_offset) {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001245 struct mp3entry* id3 = &get_trackdata(0)->id3;
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001246 lseek(mpeg_file, start_offset, SEEK_SET);
Björn Stenberg3a9e7b52002-08-20 20:38:50 +00001247 id3->offset = start_offset;
1248 set_elapsed(id3);
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001249 }
1250 else {
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +00001251 /* skip past id3v2 tag */
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001252 lseek(mpeg_file,
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001253 get_trackdata(0)->id3.first_frame_offset,
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001254 SEEK_SET);
1255
1256 }
Björn Stenbergbb9aaf52002-06-25 13:26:04 +00001257
Björn Stenberg1ac46002002-05-24 12:22:14 +00001258 /* Make it read more data */
1259 filling = true;
1260 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
1261
1262 /* Tell the file loading code that we want to start playing
1263 as soon as we have some data */
1264 play_pending = true;
Robert Keevilb8bb5212007-08-23 18:53:17 +00001265 play_pending_track_change = true;
Linus Nielsen Feltzinge5792d62002-07-25 23:12:41 +00001266
Hardeep Sidhuaa287bb2002-09-17 07:04:43 +00001267 update_playlist();
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00001268 current_track_counter++;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001269 break;
1270
1271 case MPEG_STOP:
Björn Stenberg3c260772002-05-24 15:27:55 +00001272 DEBUGF("MPEG_STOP\n");
Linus Nielsen Feltzingccfef042002-08-28 10:21:32 +00001273 is_playing = false;
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +00001274 paused = false;
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001275
1276 if (playing)
1277 playlist_update_resume_info(audio_current_track());
1278
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001279 stop_playing();
Linus Nielsen Feltzingbf0ac612003-02-13 16:25:36 +00001280 mpeg_stop_done = true;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001281 break;
1282
1283 case MPEG_PAUSE:
Björn Stenberg3c260772002-05-24 15:27:55 +00001284 DEBUGF("MPEG_PAUSE\n");
Björn Stenberg1ac46002002-05-24 12:22:14 +00001285 /* Stop the current stream */
Hardeep Sidhu81b32e02005-07-07 16:57:10 +00001286 if (playing)
1287 playlist_update_resume_info(audio_current_track());
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001288 paused = true;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001289 playing = false;
Linus Nielsen Feltzingd2018eb2002-07-25 22:09:12 +00001290 pause_tick = current_tick;
Björn Stenberg0c2e9f22002-08-21 17:38:56 +00001291 pause_track = current_track_counter;
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001292 mp3_play_pause(false);
Björn Stenberg1ac46002002-05-24 12:22:14 +00001293 break;
1294
1295 case MPEG_RESUME:
Björn Stenberg3c260772002-05-24 15:27:55 +00001296 DEBUGF("MPEG_RESUME\n");
Linus Nielsen Feltzingd2018eb2002-07-25 22:09:12 +00001297 /* Continue the current stream */
Björn Stenberg34486b72002-08-19 11:00:29 +00001298 paused = false;
1299 if (!play_pending)
1300 {
Björn Stenberg0c2e9f22002-08-21 17:38:56 +00001301 playing = true;
1302 if ( current_track_counter == pause_track )
1303 last_dma_tick += current_tick - pause_tick;
1304 else
1305 last_dma_tick = current_tick;
1306 pause_tick = 0;
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001307 mp3_play_pause(true);
Björn Stenberg34486b72002-08-19 11:00:29 +00001308 }
Björn Stenberg1ac46002002-05-24 12:22:14 +00001309 break;
1310
Björn Stenberga61617f2002-06-26 21:27:17 +00001311 case MPEG_NEXT:
1312 DEBUGF("MPEG_NEXT\n");
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001313 /* is next track in ram? */
1314 if ( num_tracks_in_memory() > 1 ) {
1315 int unplayed_space_left, unswapped_space_left;
1316
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00001317 /* stop the current stream */
1318 play_pending = false;
1319 playing = false;
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001320 mp3_play_pause(false);
Björn Stenberga61617f2002-06-26 21:27:17 +00001321
Hardeep Sidhu754651e2002-08-22 23:01:25 +00001322 track_change();
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001323 audiobuf_read = get_trackdata(0)->mempos;
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001324 last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song());
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001325 mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end);
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001326 dma_underrun = false;
Linus Nielsen Feltzingfe8a7e72002-08-08 14:51:58 +00001327 last_dma_tick = current_tick;
Björn Stenberg235d9d22002-08-08 14:01:40 +00001328
Hardeep Sidhu754651e2002-08-22 23:01:25 +00001329 unplayed_space_left = get_unplayed_space();
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +00001330 unswapped_space_left = get_unswapped_space();
Hardeep Sidhu754651e2002-08-22 23:01:25 +00001331
Björn Stenberg235d9d22002-08-08 14:01:40 +00001332 /* should we start reading more data? */
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001333 if(!filling && (unplayed_space_left < low_watermark)) {
Björn Stenberg235d9d22002-08-08 14:01:40 +00001334 filling = true;
Jens Arnolddece4142005-08-21 21:15:32 +00001335 queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS);
Linus Nielsen Feltzingfe8a7e72002-08-08 14:51:58 +00001336 play_pending = true;
Hardeep Sidhu754651e2002-08-22 23:01:25 +00001337 } else if(unswapped_space_left &&
1338 unswapped_space_left > unplayed_space_left) {
1339 /* Stop swapping the data from the previous file */
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001340 audiobuf_swapwrite = audiobuf_read;
Hardeep Sidhu754651e2002-08-22 23:01:25 +00001341 play_pending = true;
Linus Nielsen Feltzingfe8a7e72002-08-08 14:51:58 +00001342 } else {
1343 playing = true;
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001344 if (!paused)
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001345 mp3_play_pause(true);
Björn Stenberg235d9d22002-08-08 14:01:40 +00001346 }
Björn Stenberg445f17e2002-08-07 22:44:43 +00001347 }
1348 else {
Linus Nielsen Feltzing9d860e12003-04-11 00:29:15 +00001349 if (!playlist_check(1))
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001350 break;
1351
1352 /* stop the current stream */
Robert Keevilb8bb5212007-08-23 18:53:17 +00001353 end_current_track();
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001354
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001355 if (new_file(1) < 0) {
Björn Stenberg445f17e2002-08-07 22:44:43 +00001356 DEBUGF("No more files to play\n");
1357 filling = false;
Hardeep Sidhu74d082c2005-06-25 04:46:25 +00001358
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001359 check_playlist_end(1);
Hardeep Sidhu74d082c2005-06-25 04:46:25 +00001360 current_track_counter++;
Björn Stenberg445f17e2002-08-07 22:44:43 +00001361 } else {
1362 /* Make it read more data */
1363 filling = true;
1364 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
1365
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +00001366 /* Tell the file loading code that we want
1367 to start playing as soon as we have some data */
Björn Stenberg445f17e2002-08-07 22:44:43 +00001368 play_pending = true;
Robert Keevilb8bb5212007-08-23 18:53:17 +00001369 play_pending_track_change = true;
Linus Nielsen Feltzingab042e62002-07-27 00:31:38 +00001370
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001371 update_playlist();
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00001372 current_track_counter++;
Björn Stenberg445f17e2002-08-07 22:44:43 +00001373 }
Björn Stenberga61617f2002-06-26 21:27:17 +00001374 }
1375 break;
1376
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001377 case MPEG_PREV: {
Björn Stenberga61617f2002-06-26 21:27:17 +00001378 DEBUGF("MPEG_PREV\n");
Linus Nielsen Feltzing9d860e12003-04-11 00:29:15 +00001379
1380 if (!playlist_check(-1))
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001381 break;
Linus Nielsen Feltzing9d860e12003-04-11 00:29:15 +00001382
Björn Stenberga61617f2002-06-26 21:27:17 +00001383 /* stop the current stream */
Robert Keevilb8bb5212007-08-23 18:53:17 +00001384 end_current_track();
Linus Nielsen Feltzingab042e62002-07-27 00:31:38 +00001385
Björn Stenberga61617f2002-06-26 21:27:17 +00001386 /* Open the next file */
Hardeep Sidhu8fd18e92003-01-03 22:54:02 +00001387 if (new_file(-1) < 0) {
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001388 DEBUGF("No more files to play\n");
Linus Nielsen Feltzing80b285c2002-07-23 15:10:31 +00001389 filling = false;
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001390
Hardeep Sidhu1df2edb2005-11-08 06:33:36 +00001391 check_playlist_end(-1);
1392 current_track_counter++;
Björn Stenberga61617f2002-06-26 21:27:17 +00001393 } else {
Linus Nielsen Feltzing80b285c2002-07-23 15:10:31 +00001394 /* Make it read more data */
1395 filling = true;
1396 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
Björn Stenberga61617f2002-06-26 21:27:17 +00001397
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +00001398 /* Tell the file loading code that we want to
1399 start playing as soon as we have some data */
Linus Nielsen Feltzing80b285c2002-07-23 15:10:31 +00001400 play_pending = true;
Robert Keevilb8bb5212007-08-23 18:53:17 +00001401 play_pending_track_change = true;
Linus Nielsen Feltzinge5792d62002-07-25 23:12:41 +00001402
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001403 update_playlist();
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00001404 current_track_counter++;
Björn Stenberga61617f2002-06-26 21:27:17 +00001405 }
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001406 break;
1407 }
Björn Stenberga61617f2002-06-26 21:27:17 +00001408
Björn Stenberg05704972002-08-14 19:23:34 +00001409 case MPEG_FF_REWIND: {
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00001410 struct mp3entry *id3 = audio_current_track();
Hardeep Sidhu98cb6362002-08-30 07:07:57 +00001411 unsigned int oldtime = id3->elapsed;
Hardeep Sidhu4160b752003-08-29 04:36:35 +00001412 unsigned int newtime = (unsigned int)ev.data;
Björn Stenberg05704972002-08-14 19:23:34 +00001413 int curpos, newpos, diffpos;
1414 DEBUGF("MPEG_FF_REWIND\n");
1415
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001416 id3->elapsed = newtime;
1417
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00001418 newpos = audio_get_file_pos();
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +00001419 if(newpos < 0)
Björn Stenberg05704972002-08-14 19:23:34 +00001420 {
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001421 id3->elapsed = oldtime;
Björn Stenberg05704972002-08-14 19:23:34 +00001422 break;
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001423 }
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +00001424
Hardeep Sidhuc5385932002-10-04 16:39:02 +00001425 if (mpeg_file >= 0)
1426 curpos = lseek(mpeg_file, 0, SEEK_CUR);
1427 else
1428 curpos = id3->filesize;
Björn Stenberg05704972002-08-14 19:23:34 +00001429
1430 if (num_tracks_in_memory() > 1)
1431 {
1432 /* We have started loading other tracks that need to be
1433 accounted for */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001434 struct trackdata *track;
1435 int i = 0;
Björn Stenberg05704972002-08-14 19:23:34 +00001436
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001437 while((track = get_trackdata(i++)))
Björn Stenberg05704972002-08-14 19:23:34 +00001438 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001439 curpos += track->id3.filesize;
Björn Stenberg05704972002-08-14 19:23:34 +00001440 }
1441 }
1442
1443 diffpos = curpos - newpos;
1444
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001445 if(!filling && diffpos >= 0 && diffpos < audiobuflen)
Björn Stenberg05704972002-08-14 19:23:34 +00001446 {
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +00001447 int unplayed_space_left, unswapped_space_left;
1448
Björn Stenberg05704972002-08-14 19:23:34 +00001449 /* We are changing to a position that's already in
Linus Nielsen Feltzing35c417f2003-04-12 09:38:33 +00001450 memory, so we just move the DMA read pointer. */
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001451 audiobuf_read = audiobuf_write - diffpos;
1452 if (audiobuf_read < 0)
Björn Stenberg05704972002-08-14 19:23:34 +00001453 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001454 audiobuf_read += audiobuflen;
Björn Stenberg05704972002-08-14 19:23:34 +00001455 }
1456
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +00001457 unplayed_space_left = get_unplayed_space();
1458 unswapped_space_left = get_unswapped_space();
1459
Linus Nielsen Feltzing35c417f2003-04-12 09:38:33 +00001460 /* If unswapped_space_left is larger than
1461 unplayed_space_left, it means that the swapwrite pointer
1462 hasn't yet advanced up to the new location of the read
1463 pointer. We just move it, there is no need to swap
1464 data that won't be played anyway. */
1465
1466 if (unswapped_space_left > unplayed_space_left)
1467 {
1468 DEBUGF("Moved swapwrite\n");
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001469 audiobuf_swapwrite = audiobuf_read;
Linus Nielsen Feltzing35c417f2003-04-12 09:38:33 +00001470 play_pending = true;
1471 }
1472
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001473 if (mpeg_file>=0 && unplayed_space_left < low_watermark)
Hardeep Sidhuc6744152002-08-25 05:11:25 +00001474 {
1475 /* We need to load more data before starting */
1476 filling = true;
Jens Arnolddece4142005-08-21 21:15:32 +00001477 queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS);
Hardeep Sidhuc6744152002-08-25 05:11:25 +00001478 play_pending = true;
1479 }
1480 else
1481 {
1482 /* resume will start at new position */
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001483 last_dma_chunk_size =
1484 MIN(0x2000, get_unplayed_space_current_song());
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001485 mp3_play_data(audiobuf + audiobuf_read,
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001486 last_dma_chunk_size, transfer_end);
1487 dma_underrun = false;
Hardeep Sidhuc6744152002-08-25 05:11:25 +00001488 }
Björn Stenberg05704972002-08-14 19:23:34 +00001489 }
1490 else
1491 {
1492 /* Move to the new position in the file and start
1493 loading data */
1494 reset_mp3_buffer();
1495
1496 if (num_tracks_in_memory() > 1)
1497 {
1498 /* We have to reload the current track */
1499 close(mpeg_file);
1500 remove_all_non_current_tags();
Jens Arnolddece4142005-08-21 21:15:32 +00001501 generate_unbuffer_events();
Hardeep Sidhuc5385932002-10-04 16:39:02 +00001502 mpeg_file = -1;
1503 }
Björn Stenberg05704972002-08-14 19:23:34 +00001504
Hardeep Sidhuc5385932002-10-04 16:39:02 +00001505 if (mpeg_file < 0)
1506 {
Björn Stenberg05704972002-08-14 19:23:34 +00001507 mpeg_file = open(id3->path, O_RDONLY);
1508 if (mpeg_file < 0)
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001509 {
1510 id3->elapsed = oldtime;
Björn Stenberg05704972002-08-14 19:23:34 +00001511 break;
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001512 }
Björn Stenberg05704972002-08-14 19:23:34 +00001513 }
1514
1515 if(-1 == lseek(mpeg_file, newpos, SEEK_SET))
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001516 {
1517 id3->elapsed = oldtime;
Björn Stenberg05704972002-08-14 19:23:34 +00001518 break;
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001519 }
Björn Stenberg05704972002-08-14 19:23:34 +00001520
1521 filling = true;
1522 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
1523
1524 /* Tell the file loading code that we want to start playing
1525 as soon as we have some data */
1526 play_pending = true;
1527 }
1528
Björn Stenberg34486b72002-08-19 11:00:29 +00001529 id3->offset = newpos;
Björn Stenberg05704972002-08-14 19:23:34 +00001530
1531 break;
1532 }
1533
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001534 case MPEG_FLUSH_RELOAD: {
1535 int numtracks = num_tracks_in_memory();
1536 bool reload_track = false;
1537
1538 if (numtracks > 1)
1539 {
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001540 /* Reset the buffer */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001541 audiobuf_write = get_trackdata(1)->mempos;
Hardeep Sidhudf34e6b2003-06-25 15:17:04 +00001542
1543 /* Reset swapwrite unless we're still swapping current
1544 track */
1545 if (get_unplayed_space() <= get_playable_space())
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001546 audiobuf_swapwrite = audiobuf_write;
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001547
1548 close(mpeg_file);
1549 remove_all_non_current_tags();
Jens Arnolddece4142005-08-21 21:15:32 +00001550 generate_unbuffer_events();
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001551 mpeg_file = -1;
1552 reload_track = true;
1553 }
1554 else if (numtracks == 1 && mpeg_file < 0)
1555 {
1556 reload_track = true;
1557 }
1558
1559 if(reload_track && new_file(1) >= 0)
1560 {
1561 /* Tell ourselves that we want more data */
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001562 filling = true;
Jens Arnolddece4142005-08-21 21:15:32 +00001563 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001564 }
1565
1566 break;
1567 }
1568
Björn Stenberg1ac46002002-05-24 12:22:14 +00001569 case MPEG_NEED_DATA:
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001570 free_space_left = audiobuf_read - audiobuf_write;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001571
1572 /* We interpret 0 as "empty buffer" */
1573 if(free_space_left <= 0)
Jens Arnoldef328812005-05-27 21:46:44 +00001574 free_space_left += audiobuflen;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001575
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001576 unplayed_space_left = audiobuflen - free_space_left;
Linus Nielsen Feltzing54a65f72002-07-21 07:12:39 +00001577
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001578 /* Make sure that we don't fill the entire buffer */
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001579 free_space_left -= MPEG_HIGH_WATER;
Jens Arnolddece4142005-08-21 21:15:32 +00001580
1581 if (ev.data == GENERATE_UNBUFFER_EVENTS)
1582 generate_unbuffer_events();
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001583
Björn Stenbergc4b28502002-07-16 12:18:17 +00001584 /* do we have any more buffer space to fill? */
Jens Arnoldef328812005-05-27 21:46:44 +00001585 if(free_space_left <= 0)
Björn Stenberg1ac46002002-05-24 12:22:14 +00001586 {
1587 DEBUGF("0\n");
1588 filling = false;
Jens Arnolddece4142005-08-21 21:15:32 +00001589 generate_postbuffer_events();
Björn Stenbergc4b28502002-07-16 12:18:17 +00001590 ata_sleep();
1591 break;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001592 }
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001593
Linus Nielsen Feltzingb605b2e2002-07-31 06:33:48 +00001594 /* Read small chunks while we are below the low water mark */
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001595 if(unplayed_space_left < low_watermark)
Linus Nielsen Feltzingb605b2e2002-07-31 06:33:48 +00001596 amount_to_read = MIN(MPEG_LOW_WATER_CHUNKSIZE,
1597 free_space_left);
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001598 else
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001599 amount_to_read = free_space_left;
Linus Nielsen Feltzingb605b2e2002-07-31 06:33:48 +00001600
1601 /* Don't read more than until the end of the buffer */
Jens Arnoldef328812005-05-27 21:46:44 +00001602 amount_to_read = MIN(audiobuflen - audiobuf_write,
1603 amount_to_read);
Jens Arnold5ae37f02004-10-09 12:42:56 +00001604#ifdef HAVE_MMC /* MMC is slow, so don't read too large chunks */
1605 amount_to_read = MIN(0x40000, amount_to_read);
Jens Arnoldba966c12005-09-15 05:29:26 +00001606#elif MEM == 8
1607 amount_to_read = MIN(0x100000, amount_to_read);
1608#endif
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001609
1610 /* Read as much mpeg data as we can fit in the buffer */
Linus Nielsen Feltzing3a25aa42002-05-29 12:25:21 +00001611 if(mpeg_file >= 0)
Björn Stenberg1ac46002002-05-24 12:22:14 +00001612 {
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001613 DEBUGF("R\n");
Linus Nielsen Feltzing1d21ca92002-08-01 08:16:44 +00001614 t1 = current_tick;
Jens Arnoldef328812005-05-27 21:46:44 +00001615 len = read(mpeg_file, audiobuf + audiobuf_write,
1616 amount_to_read);
Linus Nielsen Feltzingc7e36752002-06-05 14:34:05 +00001617 if(len > 0)
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001618 {
Linus Nielsen Feltzing1d21ca92002-08-01 08:16:44 +00001619 t2 = current_tick;
1620 DEBUGF("time: %d\n", t2 - t1);
Linus Nielsen Feltzing80b285c2002-07-23 15:10:31 +00001621 DEBUGF("R: %x\n", len);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001622
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001623 /* Now make sure that we don't feed the MAS with ID3V1
1624 data */
1625 if (len < amount_to_read)
1626 {
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001627 int i;
Jens Arnoldef328812005-05-27 21:46:44 +00001628 static const unsigned char tag[] = "TAG";
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001629 int taglen = 128;
Jens Arnoldef328812005-05-27 21:46:44 +00001630 int tagptr = audiobuf_write + len - 128;
1631
1632 /* Really rare case: entire potential tag wasn't
1633 read in this call AND audiobuf_write < 128 */
1634 if (tagptr < 0)
1635 tagptr += audiobuflen;
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001636
1637 for(i = 0;i < 3;i++)
1638 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001639 if(tagptr >= audiobuflen)
1640 tagptr -= audiobuflen;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001641
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001642 if(audiobuf[tagptr] != tag[i])
Jens Arnoldef328812005-05-27 21:46:44 +00001643 {
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001644 taglen = 0;
Jens Arnoldef328812005-05-27 21:46:44 +00001645 break;
1646 }
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001647
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001648 tagptr++;
1649 }
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001650
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001651 if(taglen)
1652 {
1653 /* Skip id3v1 tag */
1654 DEBUGF("Skipping ID3v1 tag\n");
1655 len -= taglen;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001656
Jens Arnoldef328812005-05-27 21:46:44 +00001657 /* In the very rare case when the entire tag
1658 wasn't read in this read() len will be < 0.
1659 Take care of this when changing the write
1660 pointer. */
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001661 }
1662 }
Linus Nielsen Feltzingb3bb0762002-09-18 13:51:08 +00001663
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001664 audiobuf_write += len;
Jens Arnoldef328812005-05-27 21:46:44 +00001665
1666 if (audiobuf_write < 0)
1667 audiobuf_write += audiobuflen;
1668
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001669 if(audiobuf_write >= audiobuflen)
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001670 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001671 audiobuf_write = 0;
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001672 DEBUGF("W\n");
1673 }
Björn Stenberg1ac46002002-05-24 12:22:14 +00001674
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001675 /* Tell ourselves that we want more data */
1676 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
Björn Stenberg1ac46002002-05-24 12:22:14 +00001677 }
1678 else
1679 {
Linus Nielsen Feltzingc7e36752002-06-05 14:34:05 +00001680 if(len < 0)
1681 {
1682 DEBUGF("MPEG read error\n");
1683 }
1684
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001685 close(mpeg_file);
Linus Nielsen Feltzing3a25aa42002-05-29 12:25:21 +00001686 mpeg_file = -1;
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001687
Björn Stenberga61617f2002-06-26 21:27:17 +00001688 if(new_file(1) < 0)
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001689 {
1690 /* No more data to play */
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001691 DEBUGF("No more files to play\n");
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001692 filling = false;
1693 }
1694 else
1695 {
1696 /* Tell ourselves that we want more data */
1697 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
1698 }
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001699 }
Björn Stenberg1ac46002002-05-24 12:22:14 +00001700 }
1701 break;
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001702
Linus Nielsen Feltzinge4b9dbb2002-07-25 11:51:11 +00001703 case MPEG_TRACK_CHANGE:
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001704 track_change();
Linus Nielsen Feltzinge4b9dbb2002-07-25 11:51:11 +00001705 break;
Daniel Stenberg40093342003-12-12 13:30:15 +00001706
1707#ifndef USB_NONE
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001708 case SYS_USB_CONNECTED:
Hardeep Sidhu18261c92003-08-20 02:11:00 +00001709 is_playing = false;
1710 paused = false;
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001711 stop_playing();
Jens Arnold329caa82005-08-19 22:39:01 +00001712
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001713 /* Tell the USB thread that we are safe */
1714 DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n");
1715 usb_acknowledge(SYS_USB_CONNECTED_ACK);
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +00001716
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001717 /* Wait until the USB cable is extracted again */
1718 usb_wait_for_disconnect(&mpeg_queue);
1719 break;
Jens Arnold1d38aa12005-08-19 06:43:50 +00001720#endif /* !USB_NONE */
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001721
Jens Arnoldd6c05452005-08-29 21:15:27 +00001722#if CONFIG_CODEC == MAS3587F
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001723 case MPEG_INIT_RECORDING:
1724 init_recording();
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +00001725 init_recording_done = true;
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001726 break;
Jens Arnoldd6c05452005-08-29 21:15:27 +00001727#endif /* CONFIG_CODEC == MAS3587F */
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001728
1729 case SYS_TIMEOUT:
1730 if (playing)
1731 playlist_update_resume_info(audio_current_track());
1732 break;
Jens Arnolddece4142005-08-21 21:15:32 +00001733 }
Jens Arnoldd6c05452005-08-29 21:15:27 +00001734#if CONFIG_CODEC == MAS3587F
Björn Stenberg1ac46002002-05-24 12:22:14 +00001735 }
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001736 else
1737 {
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001738 queue_wait(&mpeg_queue, &ev);
1739 switch(ev.id)
1740 {
1741 case MPEG_RECORD:
Jens Arnold9352ac82005-09-04 21:55:15 +00001742 if (is_prerecording)
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001743 {
Jens Arnold9352ac82005-09-04 21:55:15 +00001744 int startpos;
1745
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001746 /* Go back prerecord_count seconds in the buffer */
1747 startpos = prerecord_index - prerecord_count;
1748 if(startpos < 0)
1749 startpos += prerecording_max_seconds;
Linus Nielsen Feltzing94dea1e2003-02-22 01:40:57 +00001750
Jens Arnold9352ac82005-09-04 21:55:15 +00001751 /* Read the position data from the prerecord buffer */
1752 frame_count_start = prerecord_buffer[startpos].framecount;
1753 startpos = prerecord_buffer[startpos].mempos;
Linus Nielsen Feltzing94dea1e2003-02-22 01:40:57 +00001754
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001755 DEBUGF("Start looking at address %x (%x)\n",
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001756 audiobuf+startpos, startpos);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001757
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +00001758 saved_header = mpeg_get_last_header();
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001759
Jens Arnold9352ac82005-09-04 21:55:15 +00001760 mem_find_next_frame(startpos, &offset, 1800,
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001761 saved_header);
1762
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001763 audiobuf_read = startpos + offset;
Linus Nielsen Feltzing051f2cf2005-09-02 07:01:08 +00001764 if(audiobuf_read >= audiobuflen)
1765 audiobuf_read -= audiobuflen;
1766
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001767 DEBUGF("New audiobuf_read address: %x (%x)\n",
1768 audiobuf+audiobuf_read, audiobuf_read);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001769
Linus Nielsen Feltzing051f2cf2005-09-02 07:01:08 +00001770 level = set_irq_level(HIGHEST_IRQ_LEVEL);
1771 num_rec_bytes = get_unsaved_space();
1772 set_irq_level(level);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001773 }
1774 else
1775 {
Jens Arnold9352ac82005-09-04 21:55:15 +00001776 frame_count_start = 0;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001777 num_rec_bytes = 0;
Jens Arnold9352ac82005-09-04 21:55:15 +0000