blob: d3e0e5c13790457ca99a9c2865af63b3afc1152f [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 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * 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.
Björn Stenberg1ac46002002-05-24 12:22:14 +000016 *
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>
Linus Nielsen Feltzing72d25352004-10-11 07:55:45 +000022#include <stdlib.h>
Linus Nielsen Feltzingc633ceb2002-06-07 14:41:26 +000023#include "config.h"
Jens Arnold1d38aa12005-08-19 06:43:50 +000024
Jens Arnoldd6c05452005-08-29 21:15:27 +000025#if CONFIG_CODEC != SWCODEC
Jens Arnold1d38aa12005-08-19 06:43:50 +000026
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +000027#include "debug.h"
28#include "panic.h"
Björn Stenberg51b45d52008-10-15 06:38:51 +000029#include "metadata.h"
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +000030#include "mpeg.h"
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +000031#include "audio.h"
Frank Gevaerts2f8a0082008-11-01 16:14:28 +000032#include "storage.h"
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +000033#include "string.h"
Daniel Stenbergf9b44902003-02-07 09:41:57 +000034#include <kernel.h>
Kjell Ericsonddefd1e2003-01-10 09:19:10 +000035#include "thread.h"
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +000036#include "errno.h"
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000037#include "mp3data.h"
Thomas Martitzd0b72e22011-08-30 14:01:33 +000038#include "core_alloc.h"
Jörg Hohensohnf9933652004-01-05 20:42:51 +000039#include "mp3_playback.h"
Thomas Martitzd1322b72011-08-14 15:13:00 +000040#include "talk.h"
Linus Nielsen Feltzing674eaca2005-04-01 13:41:03 +000041#include "sound.h"
Thomas Martitzbaa070c2011-08-30 14:01:45 +000042#include "system.h"
Jonathan Gordon71898e52008-10-16 10:38:03 +000043#include "appevents.h"
Jens Arnold5bea40f2010-08-22 20:58:32 +000044#include "playlist.h"
Jonathan Gordon24b136f2009-07-20 05:18:18 +000045#include "cuesheet.h"
46#include "settings.h"
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +000047#ifndef SIMULATOR
Björn Stenberg1ac46002002-05-24 12:22:14 +000048#include "i2c.h"
Marcin Bukat56c4e9f2010-10-31 21:09:34 +000049#include "mas35xx.h"
Björn Stenberg1ac46002002-05-24 12:22:14 +000050#include "system.h"
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +000051#include "usb.h"
Björn Stenberg1ac46002002-05-24 12:22:14 +000052#include "file.h"
Linus Nielsen Feltzing8e4a0e02002-11-10 18:24:40 +000053#include "hwcompat.h"
Jens Arnold1d38aa12005-08-19 06:43:50 +000054#endif /* !SIMULATOR */
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +000055#ifdef HAVE_LCD_BITMAP
56#include "lcd.h"
Marcin Bukat56c4e9f2010-10-31 21:09:34 +000057#endif /* CONFIG_CODEC != SWCODEC */
Linus Nielsen Feltzingbfc8d0a2002-08-20 14:22:11 +000058
Jeffrey Goodea0521022009-11-16 22:02:06 +000059#define MPEG_SWAP_CHUNKSIZE 0x2000
60#define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we
61 wouldn't be able to see the difference between
62 an empty buffer and a full one. */
63#define MPEG_LOW_WATER 0x60000
64#define MPEG_RECORDING_LOW_WATER 0x80000
65#define MPEG_LOW_WATER_CHUNKSIZE 0x40000
66#define MPEG_LOW_WATER_SWAP_CHUNKSIZE 0x10000
67#if (CONFIG_STORAGE & STORAGE_MMC)
68#define MPEG_PLAY_PENDING_THRESHOLD 0x20000
69#define MPEG_PLAY_PENDING_SWAPSIZE 0x20000
70#else
71#define MPEG_PLAY_PENDING_THRESHOLD 0x10000
72#define MPEG_PLAY_PENDING_SWAPSIZE 0x10000
73#endif
74
75#define MPEG_MAX_PRERECORD_SECONDS 30
76
77/* For ID3 info and VBR header */
78#define MPEG_RESERVED_HEADER_SPACE (4096 + 576)
79
Jens Arnold329caa82005-08-19 22:39:01 +000080#ifndef SIMULATOR
81extern unsigned long mas_version_code;
82#endif
83
Jens Arnoldd6c05452005-08-29 21:15:27 +000084#if CONFIG_CODEC == MAS3587F
Jens Arnold329caa82005-08-19 22:39:01 +000085extern enum /* from mp3_playback.c */
86{
87 MPEG_DECODER,
88 MPEG_ENCODER
89} mpeg_mode;
Jens Arnoldd6c05452005-08-29 21:15:27 +000090#endif /* CONFIG_CODEC == MAS3587F */
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +000091
Jens Arnold9352ac82005-09-04 21:55:15 +000092#define MPEG_PLAY 1
93#define MPEG_STOP 2
94#define MPEG_PAUSE 3
95#define MPEG_RESUME 4
96#define MPEG_NEXT 5
97#define MPEG_PREV 6
98#define MPEG_FF_REWIND 7
99#define MPEG_FLUSH_RELOAD 8
100#define MPEG_RECORD 9
101#define MPEG_INIT_RECORDING 10
102#define MPEG_INIT_PLAYBACK 11
103#define MPEG_NEW_FILE 12
104#define MPEG_PAUSE_RECORDING 13
105#define MPEG_RESUME_RECORDING 14
106#define MPEG_NEED_DATA 100
107#define MPEG_TRACK_CHANGE 101
108#define MPEG_SAVE_DATA 102
109#define MPEG_STOP_DONE 103
110#define MPEG_PRERECORDING_TICK 104
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +0000111
Jens Arnolddece4142005-08-21 21:15:32 +0000112/* indicator for MPEG_NEED_DATA */
Michael Sevakis4b902672006-12-19 16:50:07 +0000113#define GENERATE_UNBUFFER_EVENTS 1
Jens Arnolddece4142005-08-21 21:15:32 +0000114
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +0000115/* list of tracks in memory */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000116#define MAX_TRACK_ENTRIES (1<<4) /* Must be power of 2 */
117#define MAX_TRACK_ENTRIES_MASK (MAX_TRACK_ENTRIES - 1)
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000118
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000119struct trackdata
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000120{
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +0000121 struct mp3entry id3;
122 int mempos;
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000123 int load_ahead_index;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000124};
125
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000126static struct trackdata trackdata[MAX_TRACK_ENTRIES];
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000127
Linus Nielsen Feltzinge5792d62002-07-25 23:12:41 +0000128static unsigned int current_track_counter = 0;
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +0000129
130#ifndef SIMULATOR
Thomas Martitz0c4c8162011-08-30 14:32:16 +0000131static void stop_playing(void);
Bertrik Sikkenf7361592010-01-09 17:42:54 +0000132
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000133static int track_read_idx = 0;
134static int track_write_idx = 0;
Jens Arnold329caa82005-08-19 22:39:01 +0000135#endif /* !SIMULATOR */
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000136
Jonathan Gordon24b136f2009-07-20 05:18:18 +0000137/* Cuesheet support */
138static struct cuesheet *curr_cuesheet = NULL;
139static bool checked_for_cuesheet = false;
Jens Arnold509a96d2007-03-01 00:26:24 +0000140
Jens Arnold329caa82005-08-19 22:39:01 +0000141static const char mpeg_thread_name[] = "mpeg";
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000142static unsigned int audio_thread_id;
Jens Arnold0aa12a92011-10-09 16:19:51 +0000143static bool audio_is_initialized;
Jens Arnold329caa82005-08-19 22:39:01 +0000144static unsigned int mpeg_errno;
145
Jens Arnold329caa82005-08-19 22:39:01 +0000146static bool playing = false; /* We are playing an MP3 stream */
147static bool is_playing = false; /* We are (attempting to) playing MP3 files */
148static bool paused; /* playback is paused */
Thomas Martitzd0b72e22011-08-30 14:01:33 +0000149static int audiobuf_handle; /* handle to the audio buffer */
150static char* mpeg_audiobuf; /* poiunter to the audio buffer */
Thomas Martitzd1322b72011-08-14 15:13:00 +0000151static long audiobuflen; /* length of the audio buffer */
Thomas Martitz2a8eacd2011-11-17 17:55:02 +0000152#define AUDIO_BUFFER_RESERVE (256*1024)
Jens Arnold329caa82005-08-19 22:39:01 +0000153#ifdef SIMULATOR
154static char mpeg_stack[DEFAULT_STACK_SIZE];
155static struct mp3entry taginfo;
Jens Arnold329caa82005-08-19 22:39:01 +0000156#else /* !SIMULATOR */
Michael Sevakisb15aa472011-02-14 11:27:45 +0000157static struct event_queue mpeg_queue SHAREDBSS_ATTR;
Jens Arnold329caa82005-08-19 22:39:01 +0000158static long mpeg_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
159
Jens Arnold329caa82005-08-19 22:39:01 +0000160static int audiobuf_write;
161static int audiobuf_swapwrite;
Thomas Martitzd1322b72011-08-14 15:13:00 +0000162static long audiobuf_read;
Jens Arnold329caa82005-08-19 22:39:01 +0000163
164static int mpeg_file;
165
166static bool play_pending; /* We are about to start playing */
Robert Keevilb8bb5212007-08-23 18:53:17 +0000167static bool play_pending_track_change; /* When starting play we're starting a new file */
Jens Arnold329caa82005-08-19 22:39:01 +0000168static bool filling; /* We are filling the buffer with data from disk */
169static bool dma_underrun; /* True when the DMA has stopped because of
170 slow disk reading (read error, shaking) */
171static bool mpeg_stop_done;
172
173static int last_dma_tick = 0;
174static int last_dma_chunk_size;
175
176static long low_watermark; /* Dynamic low watermark level */
Nils Wallménius0bfa3e72007-08-01 08:50:44 +0000177static long low_watermark_margin = 0; /* Extra time in seconds for watermark */
Jens Arnold329caa82005-08-19 22:39:01 +0000178static long lowest_watermark_level; /* Debug value to observe the buffer
179 usage */
Michael Sevakis31b71222013-07-14 07:59:39 -0400180
181struct audio_resume_info
182{
183 unsigned long elapsed;
184 unsigned long offset;
185};
186
Jens Arnoldd6c05452005-08-29 21:15:27 +0000187#if CONFIG_CODEC == MAS3587F
Jens Arnold329caa82005-08-19 22:39:01 +0000188static char recording_filename[MAX_PATH]; /* argument to thread */
189static char delayed_filename[MAX_PATH]; /* internal copy of above */
190
Jens Arnold9352ac82005-09-04 21:55:15 +0000191static char xing_buffer[MAX_XING_HEADER_SIZE];
192
Jens Arnold329caa82005-08-19 22:39:01 +0000193static bool init_recording_done;
194static bool init_playback_done;
195static bool prerecording; /* True if prerecording is enabled */
196static bool is_prerecording; /* True if we are prerecording */
197static bool is_recording; /* We are recording */
Jens Arnold329caa82005-08-19 22:39:01 +0000198
199static enum {
200 NOT_SAVING = 0, /* reasons to save data, sorted by importance */
201 BUFFER_FULL,
202 NEW_FILE,
203 STOP_RECORDING
204} saving_status;
205
206static int rec_frequency_index; /* For create_xing_header() calls */
207static int rec_version_index; /* For create_xing_header() calls */
208
Jens Arnold9352ac82005-09-04 21:55:15 +0000209struct prerecord_info {
210 int mempos;
211 unsigned long framecount;
212};
213
214static struct prerecord_info prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS];
Jens Arnold329caa82005-08-19 22:39:01 +0000215static int prerecord_index; /* Current index in the prerecord buffer */
216static int prerecording_max_seconds; /* Max number of seconds to store */
217static int prerecord_count; /* Number of seconds in the prerecord buffer */
218static int prerecord_timeout; /* The tick count of the next prerecord data
219 store */
220
Bertrik Sikkenf7361592010-01-09 17:42:54 +0000221static unsigned long record_start_time; /* Value of current_tick when recording
222 was started */
223static unsigned long pause_start_time; /* Value of current_tick when pause was
224 started */
Jens Arnoldba966c12005-09-15 05:29:26 +0000225static unsigned long last_rec_time;
Jens Arnold329caa82005-08-19 22:39:01 +0000226static unsigned long num_rec_bytes;
Jens Arnold9352ac82005-09-04 21:55:15 +0000227static unsigned long last_rec_bytes;
228static unsigned long frame_count_start;
229static unsigned long frame_count_end;
230static unsigned long saved_header = 0;
Jens Arnold329caa82005-08-19 22:39:01 +0000231
232/* Shadow MAS registers */
233unsigned long shadow_encoder_control = 0;
Jens Arnoldd6c05452005-08-29 21:15:27 +0000234#endif /* CONFIG_CODEC == MAS3587F */
Jens Arnold329caa82005-08-19 22:39:01 +0000235
Jens Arnoldd6c05452005-08-29 21:15:27 +0000236#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
Jens Arnold329caa82005-08-19 22:39:01 +0000237unsigned long shadow_io_control_main = 0;
238unsigned long shadow_soft_mute = 0;
239unsigned shadow_codec_reg0;
Jens Arnoldd6c05452005-08-29 21:15:27 +0000240#endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
Jens Arnold329caa82005-08-19 22:39:01 +0000241
242#ifdef HAVE_RECORDING
Steve Bavin135cc752008-03-28 12:51:33 +0000243static const unsigned char empty_id3_header[] =
Jens Arnold329caa82005-08-19 22:39:01 +0000244{
245 'I', 'D', '3', 0x03, 0x00, 0x00,
246 0x00, 0x00, 0x1f, 0x76 /* Size is 4096 minus 10 bytes for the header */
247};
248#endif /* HAVE_RECORDING */
249
250
251static int get_unplayed_space(void);
252static int get_playable_space(void);
253static int get_unswapped_space(void);
254#endif /* !SIMULATOR */
255
Jens Arnold8051a0b2005-11-06 23:12:11 +0000256#if (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR)
Jens Arnold329caa82005-08-19 22:39:01 +0000257static void init_recording(void);
Jens Arnold9352ac82005-09-04 21:55:15 +0000258static void prepend_header(void);
259static void update_header(void);
Jens Arnold329caa82005-08-19 22:39:01 +0000260static void start_prerecording(void);
261static void start_recording(void);
262static void stop_recording(void);
263static int get_unsaved_space(void);
264static void pause_recording(void);
265static void resume_recording(void);
Jens Arnold8051a0b2005-11-06 23:12:11 +0000266#endif /* (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR) */
Jens Arnold329caa82005-08-19 22:39:01 +0000267
Thomas Martitzee7c1352013-12-23 12:48:26 +0100268static void audio_reset_buffer_noalloc(void* buf, size_t bufsize);
269static void audio_reset_buffer(void);
270
Jens Arnold329caa82005-08-19 22:39:01 +0000271
272#ifndef SIMULATOR
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000273static int num_tracks_in_memory(void)
274{
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000275 return (track_write_idx - track_read_idx) & MAX_TRACK_ENTRIES_MASK;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000276}
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000277
Jens Arnold329caa82005-08-19 22:39:01 +0000278#ifdef DEBUG_TAGS
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000279static void debug_tags(void)
280{
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000281 int i;
282
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000283 for(i = 0;i < MAX_TRACK_ENTRIES;i++)
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000284 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000285 DEBUGF("%d - %s\n", i, trackdata[i].id3.path);
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000286 }
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000287 DEBUGF("read: %d, write :%d\n", track_read_idx, track_write_idx);
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000288 DEBUGF("num_tracks_in_memory: %d\n", num_tracks_in_memory());
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000289}
Jens Arnold329caa82005-08-19 22:39:01 +0000290#else /* !DEBUG_TAGS */
291#define debug_tags()
292#endif /* !DEBUG_TAGS */
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000293
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000294static void remove_current_tag(void)
295{
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000296 if(num_tracks_in_memory() > 0)
297 {
298 /* First move the index, so nobody tries to access the tag */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000299 track_read_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK;
Jonathan Gordon24b136f2009-07-20 05:18:18 +0000300 checked_for_cuesheet = false;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000301 debug_tags();
302 }
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000303 else
304 {
305 DEBUGF("remove_current_tag: no tracks to remove\n");
306 }
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000307}
308
Björn Stenberg05704972002-08-14 19:23:34 +0000309static void remove_all_non_current_tags(void)
310{
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000311 track_write_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK;
Björn Stenberg05704972002-08-14 19:23:34 +0000312 debug_tags();
313}
314
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000315static void remove_all_tags(void)
316{
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000317 track_write_idx = track_read_idx;
Hardeep Sidhud3d1b982002-12-19 00:58:11 +0000318
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000319 debug_tags();
320}
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000321
322static struct trackdata *get_trackdata(int offset)
323{
Henrik Backea670e342005-07-08 09:55:22 +0000324 if(offset >= num_tracks_in_memory())
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000325 return NULL;
326 else
327 return &trackdata[(track_read_idx + offset) & MAX_TRACK_ENTRIES_MASK];
328}
Jens Arnold1d38aa12005-08-19 06:43:50 +0000329#endif /* !SIMULATOR */
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000330
Linus Nielsen Feltzing0ad617c2005-08-21 23:01:12 +0000331/***********************************************************************/
332/* audio event handling */
333
334#define MAX_EVENT_HANDLERS 10
335struct event_handlers_table
336{
337 AUDIO_EVENT_HANDLER handler;
338 unsigned short mask;
339};
340static struct event_handlers_table event_handlers[MAX_EVENT_HANDLERS];
341static int event_handlers_count = 0;
342
343void audio_register_event_handler(AUDIO_EVENT_HANDLER handler, unsigned short mask)
344{
345 if (event_handlers_count < MAX_EVENT_HANDLERS)
346 {
347 event_handlers[event_handlers_count].handler = handler;
348 event_handlers[event_handlers_count].mask = mask;
349 event_handlers_count++;
350 }
351}
352
353/* dispatch calls each handler in the order registered and returns after some
354 handler actually handles the event (the event is assumed to no longer be valid
355 after this, due to the handler changing some condition); returns true if someone
356 handled the event, which is expected to cause the caller to skip its own handling
357 of the event */
358#ifndef SIMULATOR
359static bool audio_dispatch_event(unsigned short event, unsigned long data)
360{
361 int i = 0;
362 for(i=0; i < event_handlers_count; i++)
363 {
364 if ( event_handlers[i].mask & event )
365 {
366 int rc = event_handlers[i].handler(event, data);
367 if ( rc == AUDIO_EVENT_RC_HANDLED )
368 return true;
369 }
370 }
371 return false;
372}
Michael Sevakis023f6b62013-07-12 12:06:38 -0400373
374static void send_track_event(unsigned int id, struct mp3entry *id3)
375{
376 struct mp3entry *cur_id3 =
377 &trackdata[track_read_idx & MAX_TRACK_ENTRIES_MASK].id3;
378 unsigned int flags = id3 == cur_id3 ? TEF_CURRENT : 0;
379 send_event(id, &(struct track_event){ .flags = flags, .id3 = id3 });
380}
381#endif /* SIMULATOR */
Linus Nielsen Feltzing0ad617c2005-08-21 23:01:12 +0000382
383/***********************************************************************/
384
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000385static void set_elapsed(struct mp3entry* id3)
386{
387 if ( id3->vbr ) {
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000388 if ( id3->has_toc ) {
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000389 /* calculate elapsed time using TOC */
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000390 int i;
391 unsigned int remainder, plen, relpos, nextpos;
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000392
393 /* find wich percent we're at */
394 for (i=0; i<100; i++ )
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000395 {
Jens Arnoldec9b2022005-09-10 12:28:16 +0000396 if ( id3->offset < id3->toc[i] * (id3->filesize / 256) )
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000397 {
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000398 break;
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000399 }
400 }
Michael Sevakisffa86262013-07-12 12:03:20 -0400401
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000402 i--;
403 if (i < 0)
404 i = 0;
405
406 relpos = id3->toc[i];
407
408 if (i < 99)
409 {
410 nextpos = id3->toc[i+1];
411 }
412 else
413 {
Michael Sevakisffa86262013-07-12 12:03:20 -0400414 nextpos = 256;
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000415 }
416
417 remainder = id3->offset - (relpos * (id3->filesize / 256));
418
Björn Stenberg972f4312003-10-17 15:11:09 +0000419 /* set time for this percent (divide before multiply to prevent
420 overflow on long files. loss of precision is negligible on
421 short files) */
422 id3->elapsed = i * (id3->length / 100);
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000423
424 /* calculate remainder time */
Hardeep Sidhu441f48f2002-08-27 07:19:25 +0000425 plen = (nextpos - relpos) * (id3->filesize / 256);
Björn Stenberg972f4312003-10-17 15:11:09 +0000426 id3->elapsed += (((remainder * 100) / plen) *
427 (id3->length / 10000));
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000428 }
429 else {
430 /* no TOC exists. set a rough estimate using average bitrate */
Björn Stenberg989a3ec2003-01-09 01:02:40 +0000431 int tpk = id3->length / (id3->filesize / 1024);
Björn Stenberg972f4312003-10-17 15:11:09 +0000432 id3->elapsed = id3->offset / 1024 * tpk;
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000433 }
434 }
435 else
Jens Arnoldec9b2022005-09-10 12:28:16 +0000436 /* constant bitrate, use exact calculation */
437 id3->elapsed = id3->offset / (id3->bitrate / 8);
Björn Stenberg3a9e7b52002-08-20 20:38:50 +0000438}
439
Michael Sevakis31b71222013-07-14 07:59:39 -0400440static int audio_get_file_pos_int(struct mp3entry *id3)
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000441{
442 int pos = -1;
Michael Sevakisffa86262013-07-12 12:03:20 -0400443
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000444 if (id3->vbr)
445 {
446 if (id3->has_toc)
447 {
448 /* Use the TOC to find the new position */
449 unsigned int percent, remainder;
450 int curtoc, nexttoc, plen;
Michael Sevakisffa86262013-07-12 12:03:20 -0400451
Jens Arnoldec9b2022005-09-10 12:28:16 +0000452 percent = (id3->elapsed*100)/id3->length;
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000453 if (percent > 99)
454 percent = 99;
Michael Sevakisffa86262013-07-12 12:03:20 -0400455
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000456 curtoc = id3->toc[percent];
Michael Sevakisffa86262013-07-12 12:03:20 -0400457
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000458 if (percent < 99)
459 nexttoc = id3->toc[percent+1];
460 else
461 nexttoc = 256;
Michael Sevakisffa86262013-07-12 12:03:20 -0400462
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000463 pos = (id3->filesize/256)*curtoc;
Michael Sevakisffa86262013-07-12 12:03:20 -0400464
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000465 /* Use the remainder to get a more accurate position */
466 remainder = (id3->elapsed*100)%id3->length;
467 remainder = (remainder*100)/id3->length;
468 plen = (nexttoc - curtoc)*(id3->filesize/256);
469 pos += (plen/100)*remainder;
470 }
471 else
472 {
473 /* No TOC exists, estimate the new position */
474 pos = (id3->filesize / (id3->length / 1000)) *
475 (id3->elapsed / 1000);
476 }
477 }
Jens Arnoldec9b2022005-09-10 12:28:16 +0000478 else if (id3->bitrate)
479 pos = id3->elapsed * (id3->bitrate / 8);
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000480 else
481 {
482 return -1;
483 }
484
485 if (pos >= (int)(id3->filesize - id3->id3v1len))
486 {
487 /* Don't seek right to the end of the file so that we can
488 transition properly to the next song */
489 pos = id3->filesize - id3->id3v1len - 1;
490 }
491 else if (pos < (int)id3->first_frame_offset)
492 {
493 /* skip past id3v2 tag and other leading garbage */
494 pos = id3->first_frame_offset;
495 }
Michael Sevakisffa86262013-07-12 12:03:20 -0400496 return pos;
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000497}
498
Michael Sevakis31b71222013-07-14 07:59:39 -0400499int audio_get_file_pos(void)
500{
501 struct mp3entry *id3 = audio_current_track();
502 return id3 ? audio_get_file_pos_int(id3) : 0;
503}
504
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000505unsigned long mpeg_get_last_header(void)
506{
507#ifdef SIMULATOR
508 return 0;
Jens Arnold1d38aa12005-08-19 06:43:50 +0000509#else /* !SIMULATOR */
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000510 unsigned long tmp[2];
511
512 /* Read the frame data from the MAS and reconstruct it with the
513 frame sync and all */
Jens Arnoldeaa1f732004-09-29 19:51:41 +0000514 mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_STATUS_1, tmp, 2);
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000515 return 0xffe00000 | ((tmp[0] & 0x7c00) << 6) | (tmp[1] & 0xffff);
Jens Arnold1d38aa12005-08-19 06:43:50 +0000516#endif /* !SIMULATOR */
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +0000517}
518
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000519static void do_stop(void)
520{
521 is_playing = false;
522 paused = false;
523
524#ifndef SIMULATOR
525 if (playing)
526 playlist_update_resume_info(audio_current_track());
527
528 stop_playing();
529 mpeg_stop_done = true;
530#else
531 playing = false;
532#endif
533}
534
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000535/* Buffer must not move. */
536static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size)
537{
Thomas Martitz2a8eacd2011-11-17 17:55:02 +0000538 ssize_t extradata_size = old_size - audiobuflen;
539 /* check what buflib requests */
540 size_t wanted_size = (hints & BUFLIB_SHRINK_SIZE_MASK);
541 ssize_t size = (ssize_t)old_size - wanted_size;
Thomas Martitzee7c1352013-12-23 12:48:26 +0100542
Thomas Martitz10d71bb2013-12-23 13:02:59 +0100543#if !defined(SIMULATOR) && (CONFIG_CODEC == MAS3587F)
Thomas Martitzee7c1352013-12-23 12:48:26 +0100544 /* FIXME: Cannot give the buffer during recording yet */
545 if (is_recording)
546 return BUFLIB_CB_CANNOT_SHRINK;
547#endif
548
Thomas Martitz2a8eacd2011-11-17 17:55:02 +0000549 /* keep at least 256K for the buffering */
550 if ((size - extradata_size) < AUDIO_BUFFER_RESERVE)
Thomas Martitz22e802e2013-05-30 11:24:16 +0200551 {
552 /* check if buflib needs the memory really hard. if yes we give
553 * up playback for now, otherwise refuse to shrink to keep at least
554 * 256K for the buffering */
555 if ((hints & BUFLIB_SHRINK_POS_MASK) != BUFLIB_SHRINK_POS_MASK)
556 return BUFLIB_CB_CANNOT_SHRINK;
557 }
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000558 /* TODO: Do it without stopping playback, if possible */
Thomas Martitz2a8eacd2011-11-17 17:55:02 +0000559 bool playing = (audio_status() & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY;
Michael Sevakis31b71222013-07-14 07:59:39 -0400560 struct mp3entry *id3 = audio_current_track();
561 unsigned long elapsed = 0, offset = 0;
562 if (id3)
563 {
564 elapsed = id3->elapsed;
565 offset = id3->offset;
566 }
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000567 /* don't call audio_hard_stop() as it frees this handle */
568 if (thread_self() == audio_thread_id)
569 { /* inline case MPEG_STOP (audio_stop()) response
570 * if we're in the audio thread since audio_stop() otherwise deadlocks */
571 do_stop();
572 }
573 else
574 audio_stop();
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000575
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000576 switch (hints & BUFLIB_SHRINK_POS_MASK)
577 {
578 case BUFLIB_SHRINK_POS_BACK:
579 core_shrink(handle, start, size);
580 audio_reset_buffer_noalloc(start, size);
581 break;
582 case BUFLIB_SHRINK_POS_FRONT:
583 core_shrink(handle, start + wanted_size, size);
584 audio_reset_buffer_noalloc(start + wanted_size, size);
585 break;
Thomas Martitz22e802e2013-05-30 11:24:16 +0200586 case BUFLIB_SHRINK_POS_MASK:
587 audiobuf_handle = core_free(audiobuf_handle);
588 mpeg_audiobuf = NULL;
589 talk_buffer_set_policy(TALK_BUFFER_DEFAULT);
590 playing = false;
591 break;
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000592 }
Thomas Martitzca2b82b2011-11-06 12:01:43 +0000593 if (playing)
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000594 { /* safe to call even from the audio thread (due to queue_post()) */
Michael Sevakis31b71222013-07-14 07:59:39 -0400595 audio_play(elapsed, offset);
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000596 }
597
598 return BUFLIB_CB_OK;
599}
600
601static struct buflib_callbacks ops = {
602 .move_callback = NULL,
603 .shrink_callback = shrink_callback,
604};
605
Jens Arnold329caa82005-08-19 22:39:01 +0000606#ifndef SIMULATOR
Jens Arnolddece4142005-08-21 21:15:32 +0000607/* Send callback events to notify about removing old tracks. */
608static void generate_unbuffer_events(void)
609{
610 int i;
Jens Arnolddece4142005-08-21 21:15:32 +0000611 int numentries = MAX_TRACK_ENTRIES - num_tracks_in_memory();
612 int cur_idx = track_write_idx;
Jens Arnolddece4142005-08-21 21:15:32 +0000613
614 for (i = 0; i < numentries; i++)
615 {
616 /* Send an event to notify that track has finished. */
Michael Sevakis023f6b62013-07-12 12:06:38 -0400617 send_track_event(PLAYBACK_EVENT_TRACK_FINISH, &trackdata[cur_idx].id3);
Jens Arnolddece4142005-08-21 21:15:32 +0000618 cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK;
619 }
620}
621
622/* Send callback events to notify about new tracks. */
623static void generate_postbuffer_events(void)
624{
625 int i;
Jens Arnolddece4142005-08-21 21:15:32 +0000626 int numentries = num_tracks_in_memory();
627 int cur_idx = track_read_idx;
628
629 for (i = 0; i < numentries; i++)
630 {
Michael Sevakis023f6b62013-07-12 12:06:38 -0400631 send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, &trackdata[cur_idx].id3);
Jens Arnolddece4142005-08-21 21:15:32 +0000632 cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK;
633 }
634}
635
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +0000636static void recalculate_watermark(int bitrate)
637{
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000638 int bytes_per_sec;
Frank Gevaerts2f8a0082008-11-01 16:14:28 +0000639 int time = storage_spinup_time();
Linus Nielsen Feltzing672479c2002-12-05 21:56:53 +0000640
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000641 /* A bitrate of 0 probably means empty VBR header. We play safe
642 and set a high threshold */
643 if(bitrate == 0)
Linus Nielsen Feltzing27539aa2003-03-24 11:40:59 +0000644 bitrate = 320;
Michael Sevakisffa86262013-07-12 12:03:20 -0400645
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000646 bytes_per_sec = bitrate * 1000 / 8;
Michael Sevakisffa86262013-07-12 12:03:20 -0400647
Linus Nielsen Feltzing672479c2002-12-05 21:56:53 +0000648 if(time)
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +0000649 {
Linus Nielsen Feltzingc9feaaf2002-12-05 23:02:36 +0000650 /* No drive spins up faster than 3.5s */
651 if(time < 350)
652 time = 350;
Linus Nielsen Feltzing672479c2002-12-05 21:56:53 +0000653
654 time = time * 3;
655 low_watermark = ((low_watermark_margin * HZ + time) *
656 bytes_per_sec) / HZ;
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +0000657 }
658 else
659 {
660 low_watermark = MPEG_LOW_WATER;
661 }
662}
663
Frank Gevaerts46573012008-10-07 19:37:33 +0000664#ifdef HAVE_DISK_STORAGE
Jeffrey Goodedb82be42009-11-16 20:09:46 +0000665void audio_set_buffer_margin(int setting)
Linus Nielsen Feltzingb8ff5f82002-12-05 13:09:51 +0000666{
Jeffrey Goodedb82be42009-11-16 20:09:46 +0000667 low_watermark_margin = setting; /* in seconds */
Linus Nielsen Feltzingb8ff5f82002-12-05 13:09:51 +0000668}
Nils Wallménius0bfa3e72007-08-01 08:50:44 +0000669#endif
Linus Nielsen Feltzingb8ff5f82002-12-05 13:09:51 +0000670
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +0000671void audio_get_debugdata(struct audio_debug *dbgdata)
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000672{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000673 dbgdata->audiobuflen = audiobuflen;
674 dbgdata->audiobuf_write = audiobuf_write;
675 dbgdata->audiobuf_swapwrite = audiobuf_swapwrite;
676 dbgdata->audiobuf_read = audiobuf_read;
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000677
678 dbgdata->last_dma_chunk_size = last_dma_chunk_size;
679
Daniel Stenberg301f53f2005-02-02 22:04:15 +0000680#if CONFIG_CPU == SH7034
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000681 dbgdata->dma_on = (SCR0 & 0x80) != 0;
Daniel Stenberg301f53f2005-02-02 22:04:15 +0000682#endif
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000683 dbgdata->playing = playing;
684 dbgdata->play_pending = play_pending;
685 dbgdata->is_playing = is_playing;
686 dbgdata->filling = filling;
687 dbgdata->dma_underrun = dma_underrun;
688
689 dbgdata->unplayed_space = get_unplayed_space();
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000690 dbgdata->playable_space = get_playable_space();
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000691 dbgdata->unswapped_space = get_unswapped_space();
Linus Nielsen Feltzingbf303de2002-10-15 07:23:18 +0000692
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +0000693 dbgdata->low_watermark_level = low_watermark;
Linus Nielsen Feltzingbf303de2002-10-15 07:23:18 +0000694 dbgdata->lowest_watermark_level = lowest_watermark_level;
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000695}
696
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +0000697#ifdef DEBUG
698static void dbg_timer_start(void)
699{
700 /* We are using timer 2 */
Michael Sevakisffa86262013-07-12 12:03:20 -0400701
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +0000702 TSTR &= ~0x04; /* Stop the timer */
703 TSNC &= ~0x04; /* No synchronization */
704 TMDR &= ~0x44; /* Operate normally */
705
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000706 TCNT2 = 0; /* Start counting at 0 */
707 TCR2 = 0x03; /* Sysclock/8 */
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +0000708
709 TSTR |= 0x04; /* Start timer 2 */
710}
711
712static int dbg_cnt2us(unsigned int cnt)
713{
714 return (cnt * 10000) / (FREQ/800);
715}
Jens Arnold1d38aa12005-08-19 06:43:50 +0000716#endif /* DEBUG */
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +0000717
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +0000718static int get_unplayed_space(void)
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000719{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000720 int space = audiobuf_write - audiobuf_read;
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000721 if (space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000722 space += audiobuflen;
Björn Stenberg749d87b2002-08-15 16:48:34 +0000723 return space;
724}
725
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000726static int get_playable_space(void)
727{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000728 int space = audiobuf_swapwrite - audiobuf_read;
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000729 if (space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000730 space += audiobuflen;
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000731 return space;
732}
733
Björn Stenberg749d87b2002-08-15 16:48:34 +0000734static int get_unplayed_space_current_song(void)
735{
736 int space;
737
738 if (num_tracks_in_memory() > 1)
739 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000740 space = get_trackdata(1)->mempos - audiobuf_read;
Björn Stenberg749d87b2002-08-15 16:48:34 +0000741 }
742 else
743 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000744 space = audiobuf_write - audiobuf_read;
Björn Stenberg749d87b2002-08-15 16:48:34 +0000745 }
746
747 if (space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000748 space += audiobuflen;
Björn Stenberg749d87b2002-08-15 16:48:34 +0000749
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000750 return space;
751}
752
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +0000753static int get_unswapped_space(void)
754{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000755 int space = audiobuf_write - audiobuf_swapwrite;
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +0000756 if (space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000757 space += audiobuflen;
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +0000758 return space;
759}
760
Jens Arnoldd6c05452005-08-29 21:15:27 +0000761#if CONFIG_CODEC == MAS3587F
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000762static int get_unsaved_space(void)
763{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000764 int space = audiobuf_write - audiobuf_read;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000765 if (space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000766 space += audiobuflen;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000767 return space;
768}
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +0000769
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000770static void drain_dma_buffer(void)
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +0000771{
Jens Arnoldff3add92005-05-23 18:56:15 +0000772 while (PBDRH & 0x40)
773 {
774 xor_b(0x08, &PADRH);
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +0000775
Jens Arnoldff3add92005-05-23 18:56:15 +0000776 while (PBDRH & 0x80);
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +0000777
Jens Arnoldff3add92005-05-23 18:56:15 +0000778 xor_b(0x08, &PADRH);
Jens Arnold536dff12004-08-05 17:06:31 +0000779
Jens Arnoldff3add92005-05-23 18:56:15 +0000780 while (!(PBDRH & 0x80));
781 }
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +0000782}
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000783
Jens Arnold329caa82005-08-19 22:39:01 +0000784#ifdef DEBUG
785static long timing_info_index = 0;
786static long timing_info[1024];
787#endif /* DEBUG */
788
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000789void rec_tick (void) __attribute__ ((section (".icode")));
790void rec_tick(void)
Björn Stenberg1ac46002002-05-24 12:22:14 +0000791{
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000792 int i;
Jens Arnoldff3add92005-05-23 18:56:15 +0000793 int delay;
794 char data;
795
796 if(is_recording && (PBDRH & 0x40))
Björn Stenberg1ac46002002-05-24 12:22:14 +0000797 {
Linus Nielsen Feltzing0dcd47e2002-11-19 09:50:19 +0000798#ifdef DEBUG
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000799 timing_info[timing_info_index++] = current_tick;
800 TCNT2 = 0;
Jens Arnold1d38aa12005-08-19 06:43:50 +0000801#endif /* DEBUG */
Jens Arnolde03f4022005-06-04 11:29:39 +0000802 /* Note: Although this loop is run in interrupt context, further
803 * optimisation will do no good. The MAS would then deliver bad
804 * frames occasionally, as observed in extended experiments. */
Jens Arnoldff3add92005-05-23 18:56:15 +0000805 i = 0;
806 while (PBDRH & 0x40) /* We try to read as long as EOD is high */
807 {
808 xor_b(0x08, &PADRH); /* Set PR active, independent of polarity */
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +0000809
Jens Arnolde03f4022005-06-04 11:29:39 +0000810 delay = 100;
Jens Arnoldff3add92005-05-23 18:56:15 +0000811 while (PBDRH & 0x80) /* Wait until /RTW becomes active */
812 {
Jens Arnolde03f4022005-06-04 11:29:39 +0000813 if (--delay <= 0) /* Bail out if we have to wait too long */
Jens Arnoldff3add92005-05-23 18:56:15 +0000814 { /* i.e. the MAS doesn't want to talk to us */
815 xor_b(0x08, &PADRH); /* Set PR inactive */
816 goto transfer_end; /* and get out of here */
817 }
818 }
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000819
Jens Arnoldff3add92005-05-23 18:56:15 +0000820 data = *(unsigned char *)0x04000000; /* read data byte */
Michael Sevakisffa86262013-07-12 12:03:20 -0400821
Jens Arnoldff3add92005-05-23 18:56:15 +0000822 xor_b(0x08, &PADRH); /* Set PR inactive */
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000823
Thomas Martitzd1322b72011-08-14 15:13:00 +0000824 mpeg_audiobuf[audiobuf_write++] = data;
Jens Arnoldff3add92005-05-23 18:56:15 +0000825
826 if (audiobuf_write >= audiobuflen)
827 audiobuf_write = 0;
828
829 i++;
830 }
831 transfer_end:
832
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000833#ifdef DEBUG
834 timing_info[timing_info_index++] = TCNT2 + (i << 16);
835 timing_info_index &= 0x3ff;
Jens Arnold1d38aa12005-08-19 06:43:50 +0000836#endif /* DEBUG */
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000837
838 num_rec_bytes += i;
Jens Arnolde03f4022005-06-04 11:29:39 +0000839
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000840 if(is_prerecording)
841 {
842 if(TIME_AFTER(current_tick, prerecord_timeout))
843 {
844 prerecord_timeout = current_tick + HZ;
Jens Arnold9352ac82005-09-04 21:55:15 +0000845 queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0);
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000846 }
847 }
848 else
849 {
850 /* Signal to save the data if we are running out of buffer
851 space */
Jens Arnold363bc492005-08-18 04:38:57 +0000852 if (audiobuflen - get_unsaved_space() < MPEG_RECORDING_LOW_WATER
Jens Arnolde03f4022005-06-04 11:29:39 +0000853 && saving_status == NOT_SAVING)
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000854 {
Jens Arnolde03f4022005-06-04 11:29:39 +0000855 saving_status = BUFFER_FULL;
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000856 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
Linus Nielsen Feltzing00b2aad2002-12-12 02:22:01 +0000857 }
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +0000858 }
859 }
Björn Stenberg1ac46002002-05-24 12:22:14 +0000860}
Jens Arnoldd6c05452005-08-29 21:15:27 +0000861#endif /* CONFIG_CODEC == MAS3587F */
Björn Stenberg1ac46002002-05-24 12:22:14 +0000862
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000863void playback_tick(void)
864{
Linus Nielsen Feltzing0ad617c2005-08-21 23:01:12 +0000865 struct trackdata *ptd = get_trackdata(0);
Linus Nielsen Feltzinge54aa2a2005-08-30 22:50:56 +0000866 if(ptd)
867 {
868 ptd->id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ;
869 last_dma_tick = current_tick;
870 audio_dispatch_event(AUDIO_EVENT_POS_REPORT,
871 (unsigned long)ptd->id3.elapsed);
872 }
Jörg Hohensohnec5d4462004-01-10 15:39:56 +0000873}
874
Björn Stenberg1ac46002002-05-24 12:22:14 +0000875static void reset_mp3_buffer(void)
876{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000877 audiobuf_read = 0;
878 audiobuf_write = 0;
879 audiobuf_swapwrite = 0;
880 lowest_watermark_level = audiobuflen;
Björn Stenberg1ac46002002-05-24 12:22:14 +0000881}
882
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000883 /* DMA transfer end interrupt callback */
Michael Sevakisd18a5ca2012-03-04 14:44:43 -0500884static void transfer_end(const void** ppbuf, size_t* psize)
Björn Stenberg3c260772002-05-24 15:27:55 +0000885{
Björn Stenberg34486b72002-08-19 11:00:29 +0000886 if(playing && !paused)
Björn Stenberg3c260772002-05-24 15:27:55 +0000887 {
Linus Nielsen Feltzinga46a5d32002-08-08 13:29:31 +0000888 int unplayed_space_left;
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000889 int space_until_end_of_buffer;
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000890 int track_offset = 1;
891 struct trackdata *track;
Björn Stenbergbcbc7822002-08-08 12:02:17 +0000892
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000893 audiobuf_read += last_dma_chunk_size;
894 if(audiobuf_read >= audiobuflen)
895 audiobuf_read = 0;
Michael Sevakisffa86262013-07-12 12:03:20 -0400896
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000897 /* First, check if we are on a track boundary */
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000898 if (num_tracks_in_memory() > 1)
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000899 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000900 if (audiobuf_read == get_trackdata(track_offset)->mempos)
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000901 {
Linus Nielsen Feltzing0ad617c2005-08-21 23:01:12 +0000902 if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) )
903 {
904 queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0);
905 track_offset++;
906 }
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000907 }
908 }
Michael Sevakisffa86262013-07-12 12:03:20 -0400909
Linus Nielsen Feltzinga46a5d32002-08-08 13:29:31 +0000910 unplayed_space_left = get_unplayed_space();
Michael Sevakisffa86262013-07-12 12:03:20 -0400911
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000912 space_until_end_of_buffer = audiobuflen - audiobuf_read;
Michael Sevakisffa86262013-07-12 12:03:20 -0400913
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +0000914 if(!filling && unplayed_space_left < low_watermark)
Björn Stenberg3c260772002-05-24 15:27:55 +0000915 {
Linus Nielsen Feltzing3a25aa42002-05-29 12:25:21 +0000916 filling = true;
Jens Arnolddece4142005-08-21 21:15:32 +0000917 queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS);
Björn Stenberg3c260772002-05-24 15:27:55 +0000918 }
Michael Sevakisffa86262013-07-12 12:03:20 -0400919
Björn Stenberg3c260772002-05-24 15:27:55 +0000920 if(unplayed_space_left)
921 {
Linus Nielsen Feltzing9a9d9d02003-01-21 00:11:10 +0000922 last_dma_chunk_size = MIN(0x2000, unplayed_space_left);
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000923 last_dma_chunk_size = MIN(last_dma_chunk_size,
924 space_until_end_of_buffer);
Björn Stenbergbb9aaf52002-06-25 13:26:04 +0000925
Björn Stenberg200d2262002-06-26 12:05:06 +0000926 /* several tracks loaded? */
Linus Nielsen Feltzing80bb2812005-08-30 20:52:24 +0000927 track = get_trackdata(track_offset);
928 if(track)
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000929 {
Björn Stenberg200d2262002-06-26 12:05:06 +0000930 /* will we move across the track boundary? */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000931 if (( audiobuf_read < track->mempos ) &&
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000932 ((audiobuf_read+last_dma_chunk_size) >
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000933 track->mempos ))
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000934 {
935 /* Make sure that we end exactly on the boundary */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000936 last_dma_chunk_size = track->mempos - audiobuf_read;
Björn Stenberg200d2262002-06-26 12:05:06 +0000937 }
Björn Stenbergbb9aaf52002-06-25 13:26:04 +0000938 }
Linus Nielsen Feltzing4e2384e2002-07-25 11:12:54 +0000939
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000940 *psize = last_dma_chunk_size & 0xffff;
Thomas Martitzd1322b72011-08-14 15:13:00 +0000941 *ppbuf = mpeg_audiobuf + audiobuf_read;
Linus Nielsen Feltzinge54aa2a2005-08-30 22:50:56 +0000942 track = get_trackdata(0);
943 if(track)
944 track->id3.offset += last_dma_chunk_size;
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000945
946 /* Update the watermark debug level */
947 if(unplayed_space_left < lowest_watermark_level)
948 lowest_watermark_level = unplayed_space_left;
Björn Stenberg3c260772002-05-24 15:27:55 +0000949 }
950 else
951 {
Linus Nielsen Feltzing33060d02002-10-09 13:25:03 +0000952 /* Check if the end of data is because of a hard disk error.
953 If there is an open file handle, we are still playing music.
954 If not, the last file has been loaded, and the file handle is
955 closed. */
956 if(mpeg_file >= 0)
957 {
Linus Nielsen Feltzingd29248d2002-12-05 14:11:48 +0000958 /* Update the watermark debug level */
959 if(unplayed_space_left < lowest_watermark_level)
960 lowest_watermark_level = unplayed_space_left;
Michael Sevakisffa86262013-07-12 12:03:20 -0400961
Linus Nielsen Feltzing33060d02002-10-09 13:25:03 +0000962 DEBUGF("DMA underrun.\n");
963 dma_underrun = true;
964 }
Linus Nielsen Feltzing26e7ec42002-10-09 09:15:28 +0000965 else
966 {
Linus Nielsen Feltzing0ad617c2005-08-21 23:01:12 +0000967 if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) )
968 {
969 DEBUGF("No more MP3 data. Stopping.\n");
970 queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0);
971 playing = false;
972 }
Linus Nielsen Feltzing26e7ec42002-10-09 09:15:28 +0000973 }
Jörg Hohensohnf9933652004-01-05 20:42:51 +0000974 *psize = 0; /* no more transfer */
Björn Stenberg3c260772002-05-24 15:27:55 +0000975 }
976 }
Björn Stenberg3c260772002-05-24 15:27:55 +0000977}
978
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000979static struct trackdata *add_track_to_tag_list(const char *filename)
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +0000980{
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000981 struct trackdata *track;
Jonathan Gordon843c7ef2009-04-06 00:39:43 +0000982 bool send_nid3_event;
Michael Sevakisffa86262013-07-12 12:03:20 -0400983
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000984 if(num_tracks_in_memory() >= MAX_TRACK_ENTRIES)
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000985 {
986 DEBUGF("Tag memory is full\n");
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000987 return NULL;
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000988 }
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000989
990 track = &trackdata[track_write_idx];
Michael Sevakisffa86262013-07-12 12:03:20 -0400991
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000992 /* grab id3 tag of new file and
993 remember where in memory it starts */
Thom Johansen294ec1d2007-09-19 10:40:55 +0000994 if(mp3info(&track->id3, filename))
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000995 {
996 DEBUGF("Bad mp3\n");
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000997 return NULL;
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +0000998 }
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +0000999 track->mempos = audiobuf_write;
1000 track->id3.elapsed = 0;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +00001001#ifdef HAVE_LCD_BITMAP
Magnus Holmgren917f2c12005-12-22 21:42:00 +00001002 if (track->id3.title)
1003 lcd_getstringsize(track->id3.title, NULL, NULL);
1004 if (track->id3.artist)
1005 lcd_getstringsize(track->id3.artist, NULL, NULL);
1006 if (track->id3.album)
1007 lcd_getstringsize(track->id3.album, NULL, NULL);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +00001008#endif
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001009
Jonathan Gordon843c7ef2009-04-06 00:39:43 +00001010 /* if this track is the next track then let the UI know it can get it */
1011 send_nid3_event = (track_write_idx == track_read_idx + 1);
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001012 track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK;
Jonathan Gordon843c7ef2009-04-06 00:39:43 +00001013 if (send_nid3_event)
Michael Sevakis023f6b62013-07-12 12:06:38 -04001014 send_track_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, &track->id3);
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +00001015 debug_tags();
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001016 return track;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001017}
1018
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001019static int new_file(int steps)
Björn Stenbergfa8cd2c2002-05-31 12:12:23 +00001020{
Linus Nielsen Feltzing56e5d1a2002-10-09 13:47:38 +00001021 int max_steps = playlist_amount();
Linus Nielsen Feltzing685aeb52004-11-15 00:34:19 +00001022 int start = 0;
1023 int i;
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001024 struct trackdata *track;
Jens Arnold5bea40f2010-08-22 20:58:32 +00001025 char name_buf[MAX_PATH+1];
1026 const char *trackname;
Linus Nielsen Feltzing685aeb52004-11-15 00:34:19 +00001027
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +00001028 /* Find out how many steps to advance. The load_ahead_index field tells
1029 us how many playlist entries it had to skip to get to a valid one.
1030 We add those together to find out where to start. */
1031 if(steps > 0 && num_tracks_in_memory() > 1)
Linus Nielsen Feltzing685aeb52004-11-15 00:34:19 +00001032 {
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +00001033 /* Begin with the song after the currently playing one */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001034 i = 1;
1035 while((track = get_trackdata(i++)))
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +00001036 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001037 start += track->load_ahead_index;
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +00001038 }
Linus Nielsen Feltzing685aeb52004-11-15 00:34:19 +00001039 }
Michael Sevakisffa86262013-07-12 12:03:20 -04001040
Björn Stenbergf952ba72002-07-18 15:37:41 +00001041 do {
Jens Arnold5bea40f2010-08-22 20:58:32 +00001042 trackname = playlist_peek(start + steps, name_buf, sizeof(name_buf));
Björn Stenbergf952ba72002-07-18 15:37:41 +00001043 if ( !trackname )
1044 return -1;
Michael Sevakisffa86262013-07-12 12:03:20 -04001045
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +00001046 DEBUGF("Loading %s\n", trackname);
Michael Sevakisffa86262013-07-12 12:03:20 -04001047
Björn Stenbergf952ba72002-07-18 15:37:41 +00001048 mpeg_file = open(trackname, O_RDONLY);
1049 if(mpeg_file < 0) {
1050 DEBUGF("Couldn't open file: %s\n",trackname);
Linus Nielsen Feltzing72d25352004-10-11 07:55:45 +00001051 if(steps < 0)
1052 steps--;
1053 else
1054 steps++;
Björn Stenbergf952ba72002-07-18 15:37:41 +00001055 }
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001056 else
1057 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001058 struct trackdata *track = add_track_to_tag_list(trackname);
Linus Nielsen Feltzingccfef042002-08-28 10:21:32 +00001059
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001060 if(!track)
Linus Nielsen Feltzing606b0f52002-08-28 11:43:49 +00001061 {
1062 /* Bad mp3 file */
Linus Nielsen Feltzing34145af2004-11-17 12:42:43 +00001063 if(steps < 0)
1064 steps--;
1065 else
1066 steps++;
Linus Nielsen Feltzing606b0f52002-08-28 11:43:49 +00001067 close(mpeg_file);
1068 mpeg_file = -1;
1069 }
1070 else
1071 {
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +00001072 /* skip past id3v2 tag */
Michael Sevakisffa86262013-07-12 12:03:20 -04001073 lseek(mpeg_file,
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001074 track->id3.first_frame_offset,
Linus Nielsen Feltzing606b0f52002-08-28 11:43:49 +00001075 SEEK_SET);
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001076 track->id3.index = steps;
1077 track->load_ahead_index = steps;
1078 track->id3.offset = 0;
Linus Nielsen Feltzingce882bb2002-12-05 15:23:46 +00001079
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001080 if(track->id3.vbr)
Linus Nielsen Feltzing672479c2002-12-05 21:56:53 +00001081 /* Average bitrate * 1.5 */
Linus Nielsen Feltzingce882bb2002-12-05 15:23:46 +00001082 recalculate_watermark(
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001083 (track->id3.bitrate * 3) / 2);
Linus Nielsen Feltzingce882bb2002-12-05 15:23:46 +00001084 else
1085 recalculate_watermark(
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001086 track->id3.bitrate);
Michael Sevakisffa86262013-07-12 12:03:20 -04001087
Linus Nielsen Feltzing606b0f52002-08-28 11:43:49 +00001088 }
Björn Stenbergf952ba72002-07-18 15:37:41 +00001089 }
Linus Nielsen Feltzing319d5f72004-11-05 07:43:39 +00001090
1091 /* Bail out if no file could be opened */
1092 if(abs(steps) > max_steps)
1093 return -1;
Björn Stenbergf952ba72002-07-18 15:37:41 +00001094 } while ( mpeg_file < 0 );
Björn Stenbergfa8cd2c2002-05-31 12:12:23 +00001095
Björn Stenbergfa8cd2c2002-05-31 12:12:23 +00001096 return 0;
1097}
1098
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +00001099static void stop_playing(void)
1100{
1101 /* Stop the current stream */
Jörg Hohensohnec5d4462004-01-10 15:39:56 +00001102 mp3_play_stop();
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +00001103 playing = false;
1104 filling = false;
Robert Keevilb8bb5212007-08-23 18:53:17 +00001105
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +00001106 if(mpeg_file >= 0)
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001107 close(mpeg_file);
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +00001108 mpeg_file = -1;
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001109 remove_all_tags();
Jens Arnolddece4142005-08-21 21:15:32 +00001110 generate_unbuffer_events();
Jörg Hohensohn30c338a2004-05-09 09:36:58 +00001111 reset_mp3_buffer();
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +00001112}
1113
Michael Sevakis023f6b62013-07-12 12:06:38 -04001114static void end_current_track(void)
1115{
Robert Keevilb8bb5212007-08-23 18:53:17 +00001116 play_pending = false;
1117 playing = false;
1118 mp3_play_pause(false);
1119
Robert Keevilb8bb5212007-08-23 18:53:17 +00001120 reset_mp3_buffer();
1121 remove_all_tags();
1122 generate_unbuffer_events();
1123
1124 if(mpeg_file >= 0)
1125 close(mpeg_file);
1126}
1127
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001128/* Is this a really the end of playback or is a new playlist starting */
1129static void check_playlist_end(int direction)
1130{
Hardeep Sidhu1df2edb2005-11-08 06:33:36 +00001131 /* Use the largest possible step size to account for skipped tracks */
1132 int steps = playlist_amount();
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001133
Hardeep Sidhu1df2edb2005-11-08 06:33:36 +00001134 if (direction < 0)
1135 steps = -steps;
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001136
Hardeep Sidhu1df2edb2005-11-08 06:33:36 +00001137 if (playlist_next(steps) < 0)
1138 is_playing = false;
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001139}
1140
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001141static void update_playlist(void)
1142{
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001143 if (num_tracks_in_memory() > 0)
1144 {
Hardeep Sidhu74d082c2005-06-25 04:46:25 +00001145 struct trackdata *track = get_trackdata(0);
1146 track->id3.index = playlist_next(track->id3.index);
1147 }
1148 else
1149 {
Hardeep Sidhu71d22812005-07-01 11:25:16 +00001150 /* End of playlist? */
Hardeep Sidhu1df2edb2005-11-08 06:33:36 +00001151 check_playlist_end(1);
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001152 }
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001153
1154 playlist_update_resume_info(audio_current_track());
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001155}
1156
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001157static void track_change(void)
1158{
1159 DEBUGF("Track change\n");
1160
Jens Arnoldd6c05452005-08-29 21:15:27 +00001161#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001162 /* Reset the AVC */
Jens Arnold65c17462005-11-07 20:35:24 +00001163 sound_set_avc(-1);
Jens Arnoldd6c05452005-08-29 21:15:27 +00001164#endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001165
Hardeep Sidhuc8ce78a2005-07-01 12:06:30 +00001166 if (num_tracks_in_memory() > 0)
1167 {
1168 remove_current_tag();
1169 update_playlist();
Jens Arnolda2f92c92009-02-16 00:29:07 +00001170 if (is_playing)
Michael Sevakis023f6b62013-07-12 12:06:38 -04001171 {
1172 send_track_event(PLAYBACK_EVENT_TRACK_CHANGE,
1173 audio_current_track());
1174 }
Hardeep Sidhuc8ce78a2005-07-01 12:06:30 +00001175 }
1176
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00001177 current_track_counter++;
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001178}
1179
Linus Nielsen Feltzingb3bb0762002-09-18 13:51:08 +00001180#ifdef DEBUG
Jens Arnoldc76c5682004-08-16 23:37:23 +00001181void hexdump(const unsigned char *buf, int len)
Linus Nielsen Feltzingb3bb0762002-09-18 13:51:08 +00001182{
1183 int i;
1184
1185 for(i = 0;i < len;i++)
1186 {
1187 if(i && (i & 15) == 0)
1188 {
1189 DEBUGF("\n");
1190 }
1191 DEBUGF("%02x ", buf[i]);
1192 }
1193 DEBUGF("\n");
1194}
Jens Arnold1d38aa12005-08-19 06:43:50 +00001195#endif /* DEBUG */
Linus Nielsen Feltzingb3bb0762002-09-18 13:51:08 +00001196
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001197static void start_playback_if_ready(void)
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001198{
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001199 int playable_space;
1200
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001201 playable_space = audiobuf_swapwrite - audiobuf_read;
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001202 if(playable_space < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001203 playable_space += audiobuflen;
Michael Sevakisffa86262013-07-12 12:03:20 -04001204
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001205 /* See if we have started playing yet. If not, do it. */
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001206 if(play_pending || dma_underrun)
1207 {
1208 /* If the filling has stopped, and we still haven't reached
1209 the watermark, the file must be smaller than the
1210 watermark. We must still play it. */
Linus Nielsen Feltzing7fed4a02002-12-05 17:14:35 +00001211 if((playable_space >= MPEG_PLAY_PENDING_THRESHOLD) ||
Linus Nielsen Feltzing83444372002-12-05 11:09:52 +00001212 !filling || dma_underrun)
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001213 {
1214 DEBUGF("P\n");
Jens Arnolddece4142005-08-21 21:15:32 +00001215 if (play_pending) /* don't do this when recovering from DMA underrun */
1216 {
1217 generate_postbuffer_events(); /* signal first track as buffered */
Robert Keevilb8bb5212007-08-23 18:53:17 +00001218 if (play_pending_track_change)
1219 {
1220 play_pending_track_change = false;
Michael Sevakis023f6b62013-07-12 12:06:38 -04001221 send_track_event(PLAYBACK_EVENT_TRACK_CHANGE,
1222 audio_current_track());
Robert Keevilb8bb5212007-08-23 18:53:17 +00001223 }
Jens Arnolddece4142005-08-21 21:15:32 +00001224 play_pending = false;
1225 }
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001226 playing = true;
Jens Arnolddece4142005-08-21 21:15:32 +00001227
Linus Nielsen Feltzing66cda8c2004-04-09 21:03:09 +00001228 last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song());
Thomas Martitzd1322b72011-08-14 15:13:00 +00001229 mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end);
Linus Nielsen Feltzing66cda8c2004-04-09 21:03:09 +00001230 dma_underrun = false;
1231
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001232 if (!paused)
1233 {
1234 last_dma_tick = current_tick;
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001235 mp3_play_pause(true);
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001236 }
1237
1238 /* Tell ourselves that we need more data */
1239 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
1240 }
1241 }
1242}
1243
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001244static bool swap_one_chunk(void)
1245{
1246 int free_space_left;
1247 int amount_to_swap;
1248
1249 free_space_left = get_unswapped_space();
1250
1251 if(free_space_left == 0 && !play_pending)
1252 return false;
1253
1254 /* Swap in larger chunks when the user is waiting for the playback
Linus Nielsen Feltzingd199e692002-12-05 13:36:08 +00001255 to start, or when there is dangerously little playable data left */
Linus Nielsen Feltzing7fed4a02002-12-05 17:14:35 +00001256 if(play_pending)
1257 amount_to_swap = MIN(MPEG_PLAY_PENDING_SWAPSIZE, free_space_left);
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001258 else
Linus Nielsen Feltzing7fed4a02002-12-05 17:14:35 +00001259 {
1260 if(get_playable_space() < low_watermark)
1261 amount_to_swap = MIN(MPEG_LOW_WATER_SWAP_CHUNKSIZE,
1262 free_space_left);
1263 else
1264 amount_to_swap = MIN(MPEG_SWAP_CHUNKSIZE, free_space_left);
1265 }
Michael Sevakisffa86262013-07-12 12:03:20 -04001266
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001267 if(audiobuf_write < audiobuf_swapwrite)
1268 amount_to_swap = MIN(audiobuflen - audiobuf_swapwrite,
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001269 amount_to_swap);
1270 else
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001271 amount_to_swap = MIN(audiobuf_write - audiobuf_swapwrite,
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001272 amount_to_swap);
Linus Nielsen Feltzing35c417f2003-04-12 09:38:33 +00001273
Thomas Martitzd1322b72011-08-14 15:13:00 +00001274 bitswap(mpeg_audiobuf + audiobuf_swapwrite, amount_to_swap);
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001275
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001276 audiobuf_swapwrite += amount_to_swap;
1277 if(audiobuf_swapwrite >= audiobuflen)
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001278 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001279 audiobuf_swapwrite = 0;
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001280 }
1281
1282 return true;
1283}
Linus Nielsen Feltzinga5fbdbb2005-02-28 09:04:59 +00001284
Björn Stenberg1ac46002002-05-24 12:22:14 +00001285static void mpeg_thread(void)
1286{
Björn Stenberg0c2e9f22002-08-21 17:38:56 +00001287 static int pause_tick = 0;
1288 static unsigned int pause_track = 0;
Michael Sevakisa9b2fb52007-10-16 01:25:17 +00001289 struct queue_event ev;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001290 int len;
1291 int free_space_left;
Linus Nielsen Feltzing54a65f72002-07-21 07:12:39 +00001292 int unplayed_space_left;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001293 int amount_to_read;
Linus Nielsen Feltzing1d21ca92002-08-01 08:16:44 +00001294 int t1, t2;
Michael Sevakis31b71222013-07-14 07:59:39 -04001295 unsigned long start_elapsed, start_offset;
Jens Arnoldd6c05452005-08-29 21:15:27 +00001296#if CONFIG_CODEC == MAS3587F
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001297 int amount_to_save;
Jens Arnolde03f4022005-06-04 11:29:39 +00001298 int save_endpos = 0;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00001299 int rc;
Jens Arnold9352ac82005-09-04 21:55:15 +00001300 int level;
Jean-Philippe Bernardy3f65c3f2005-01-30 14:33:33 +00001301 long offset;
Jens Arnoldd6c05452005-08-29 21:15:27 +00001302#endif /* CONFIG_CODEC == MAS3587F */
Jens Arnolde03f4022005-06-04 11:29:39 +00001303
Linus Nielsen Feltzingccfef042002-08-28 10:21:32 +00001304 is_playing = false;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001305 play_pending = false;
1306 playing = false;
Linus Nielsen Feltzing60ed5ee2002-06-19 06:19:00 +00001307 mpeg_file = -1;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001308
1309 while(1)
1310 {
Jens Arnoldd6c05452005-08-29 21:15:27 +00001311#if CONFIG_CODEC == MAS3587F
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001312 if(mpeg_mode == MPEG_DECODER)
1313 {
Jens Arnoldd6c05452005-08-29 21:15:27 +00001314#endif /* CONFIG_CODEC == MAS3587F */
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001315 yield();
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001316
1317 /* Swap if necessary, and don't block on the queue_wait() */
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001318 if(swap_one_chunk())
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001319 {
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001320 queue_wait_w_tmo(&mpeg_queue, &ev, 0);
1321 }
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001322 else if (playing)
1323 {
1324 /* periodically update resume info */
1325 queue_wait_w_tmo(&mpeg_queue, &ev, HZ/2);
1326 }
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001327 else
1328 {
Linus Nielsen Feltzing647db262002-10-16 09:26:03 +00001329 DEBUGF("S R:%x W:%x SW:%x\n",
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001330 audiobuf_read, audiobuf_write, audiobuf_swapwrite);
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001331 queue_wait(&mpeg_queue, &ev);
1332 }
Linus Nielsen Feltzingc5e29932002-10-28 00:00:07 +00001333
1334 start_playback_if_ready();
Michael Sevakisffa86262013-07-12 12:03:20 -04001335
Björn Stenberg1ac46002002-05-24 12:22:14 +00001336 switch(ev.id)
1337 {
1338 case MPEG_PLAY:
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001339 DEBUGF("MPEG_PLAY\n");
Linus Nielsen Feltzing0a12f4e2003-05-03 10:03:30 +00001340
Jonathan Gordon00d249a2007-02-18 03:25:40 +00001341#if CONFIG_TUNER
Linus Nielsen Feltzing0a12f4e2003-05-03 10:03:30 +00001342 /* Silence the A/D input, it may be on because the radio
1343 may be playing */
1344 mas_codec_writereg(6, 0x0000);
Jens Arnold1d38aa12005-08-19 06:43:50 +00001345#endif /* CONFIG_TUNER */
Linus Nielsen Feltzing0a12f4e2003-05-03 10:03:30 +00001346
Björn Stenberg1ac46002002-05-24 12:22:14 +00001347 /* Stop the current stream */
Linus Nielsen Feltzing001226c2003-03-15 12:09:09 +00001348 paused = false;
Robert Keevilb8bb5212007-08-23 18:53:17 +00001349 end_current_track();
Linus Nielsen Feltzing60ed5ee2002-06-19 06:19:00 +00001350
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001351 if ( new_file(0) == -1 )
Linus Nielsen Feltzingccfef042002-08-28 10:21:32 +00001352 {
1353 is_playing = false;
Hardeep Sidhu96a68742003-01-04 07:16:36 +00001354 track_change();
Linus Nielsen Feltzingccfef042002-08-28 10:21:32 +00001355 break;
1356 }
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001357
Michael Sevakis31b71222013-07-14 07:59:39 -04001358 start_elapsed = ((struct audio_resume_info *)ev.data)->elapsed;
1359 start_offset = ((struct audio_resume_info *)ev.data)->offset;
Björn Stenberg3a9e7b52002-08-20 20:38:50 +00001360
1361 /* mid-song resume? */
Michael Sevakis31b71222013-07-14 07:59:39 -04001362 if (!start_offset && start_elapsed) {
1363 struct mp3entry *id3 = &get_trackdata(0)->id3;
1364 id3->elapsed = start_elapsed;
1365 start_offset = audio_get_file_pos_int(id3);
1366 }
1367
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001368 if (start_offset) {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001369 struct mp3entry* id3 = &get_trackdata(0)->id3;
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001370 lseek(mpeg_file, start_offset, SEEK_SET);
Björn Stenberg3a9e7b52002-08-20 20:38:50 +00001371 id3->offset = start_offset;
1372 set_elapsed(id3);
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001373 }
1374 else {
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +00001375 /* skip past id3v2 tag */
Michael Sevakisffa86262013-07-12 12:03:20 -04001376 lseek(mpeg_file,
1377 get_trackdata(0)->id3.first_frame_offset,
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001378 SEEK_SET);
1379
1380 }
Björn Stenbergbb9aaf52002-06-25 13:26:04 +00001381
Björn Stenberg1ac46002002-05-24 12:22:14 +00001382 /* Make it read more data */
1383 filling = true;
1384 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
1385
1386 /* Tell the file loading code that we want to start playing
1387 as soon as we have some data */
1388 play_pending = true;
Robert Keevilb8bb5212007-08-23 18:53:17 +00001389 play_pending_track_change = true;
Linus Nielsen Feltzinge5792d62002-07-25 23:12:41 +00001390
Hardeep Sidhuaa287bb2002-09-17 07:04:43 +00001391 update_playlist();
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00001392 current_track_counter++;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001393 break;
1394
1395 case MPEG_STOP:
Thomas Martitzbaa070c2011-08-30 14:01:45 +00001396 do_stop();
Björn Stenberg1ac46002002-05-24 12:22:14 +00001397 break;
1398
1399 case MPEG_PAUSE:
Björn Stenberg3c260772002-05-24 15:27:55 +00001400 DEBUGF("MPEG_PAUSE\n");
Björn Stenberg1ac46002002-05-24 12:22:14 +00001401 /* Stop the current stream */
Hardeep Sidhu81b32e02005-07-07 16:57:10 +00001402 if (playing)
1403 playlist_update_resume_info(audio_current_track());
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001404 paused = true;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001405 playing = false;
Linus Nielsen Feltzingd2018eb2002-07-25 22:09:12 +00001406 pause_tick = current_tick;
Björn Stenberg0c2e9f22002-08-21 17:38:56 +00001407 pause_track = current_track_counter;
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001408 mp3_play_pause(false);
Björn Stenberg1ac46002002-05-24 12:22:14 +00001409 break;
1410
1411 case MPEG_RESUME:
Björn Stenberg3c260772002-05-24 15:27:55 +00001412 DEBUGF("MPEG_RESUME\n");
Linus Nielsen Feltzingd2018eb2002-07-25 22:09:12 +00001413 /* Continue the current stream */
Björn Stenberg34486b72002-08-19 11:00:29 +00001414 paused = false;
1415 if (!play_pending)
1416 {
Björn Stenberg0c2e9f22002-08-21 17:38:56 +00001417 playing = true;
1418 if ( current_track_counter == pause_track )
1419 last_dma_tick += current_tick - pause_tick;
1420 else
Michael Sevakisffa86262013-07-12 12:03:20 -04001421 last_dma_tick = current_tick;
Björn Stenberg0c2e9f22002-08-21 17:38:56 +00001422 pause_tick = 0;
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001423 mp3_play_pause(true);
Björn Stenberg34486b72002-08-19 11:00:29 +00001424 }
Björn Stenberg1ac46002002-05-24 12:22:14 +00001425 break;
1426
Björn Stenberga61617f2002-06-26 21:27:17 +00001427 case MPEG_NEXT:
1428 DEBUGF("MPEG_NEXT\n");
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001429 /* is next track in ram? */
1430 if ( num_tracks_in_memory() > 1 ) {
1431 int unplayed_space_left, unswapped_space_left;
1432
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00001433 /* stop the current stream */
1434 play_pending = false;
1435 playing = false;
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001436 mp3_play_pause(false);
Björn Stenberga61617f2002-06-26 21:27:17 +00001437
Hardeep Sidhu754651e2002-08-22 23:01:25 +00001438 track_change();
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001439 audiobuf_read = get_trackdata(0)->mempos;
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001440 last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song());
Thomas Martitzd1322b72011-08-14 15:13:00 +00001441 mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end);
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001442 dma_underrun = false;
Linus Nielsen Feltzingfe8a7e72002-08-08 14:51:58 +00001443 last_dma_tick = current_tick;
Björn Stenberg235d9d22002-08-08 14:01:40 +00001444
Hardeep Sidhu754651e2002-08-22 23:01:25 +00001445 unplayed_space_left = get_unplayed_space();
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +00001446 unswapped_space_left = get_unswapped_space();
Hardeep Sidhu754651e2002-08-22 23:01:25 +00001447
Björn Stenberg235d9d22002-08-08 14:01:40 +00001448 /* should we start reading more data? */
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001449 if(!filling && (unplayed_space_left < low_watermark)) {
Björn Stenberg235d9d22002-08-08 14:01:40 +00001450 filling = true;
Jens Arnolddece4142005-08-21 21:15:32 +00001451 queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS);
Linus Nielsen Feltzingfe8a7e72002-08-08 14:51:58 +00001452 play_pending = true;
Hardeep Sidhu754651e2002-08-22 23:01:25 +00001453 } else if(unswapped_space_left &&
1454 unswapped_space_left > unplayed_space_left) {
1455 /* Stop swapping the data from the previous file */
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001456 audiobuf_swapwrite = audiobuf_read;
Hardeep Sidhu754651e2002-08-22 23:01:25 +00001457 play_pending = true;
Linus Nielsen Feltzingfe8a7e72002-08-08 14:51:58 +00001458 } else {
1459 playing = true;
Björn Stenberg6224cdb2002-08-16 14:41:47 +00001460 if (!paused)
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001461 mp3_play_pause(true);
Björn Stenberg235d9d22002-08-08 14:01:40 +00001462 }
Björn Stenberg445f17e2002-08-07 22:44:43 +00001463 }
1464 else {
Linus Nielsen Feltzing9d860e12003-04-11 00:29:15 +00001465 if (!playlist_check(1))
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001466 break;
1467
1468 /* stop the current stream */
Robert Keevilb8bb5212007-08-23 18:53:17 +00001469 end_current_track();
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001470
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001471 if (new_file(1) < 0) {
Björn Stenberg445f17e2002-08-07 22:44:43 +00001472 DEBUGF("No more files to play\n");
1473 filling = false;
Hardeep Sidhu74d082c2005-06-25 04:46:25 +00001474
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001475 check_playlist_end(1);
Hardeep Sidhu74d082c2005-06-25 04:46:25 +00001476 current_track_counter++;
Björn Stenberg445f17e2002-08-07 22:44:43 +00001477 } else {
1478 /* Make it read more data */
1479 filling = true;
1480 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
Michael Sevakisffa86262013-07-12 12:03:20 -04001481
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +00001482 /* Tell the file loading code that we want
1483 to start playing as soon as we have some data */
Björn Stenberg445f17e2002-08-07 22:44:43 +00001484 play_pending = true;
Robert Keevilb8bb5212007-08-23 18:53:17 +00001485 play_pending_track_change = true;
Linus Nielsen Feltzingab042e62002-07-27 00:31:38 +00001486
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001487 update_playlist();
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00001488 current_track_counter++;
Björn Stenberg445f17e2002-08-07 22:44:43 +00001489 }
Björn Stenberga61617f2002-06-26 21:27:17 +00001490 }
1491 break;
1492
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001493 case MPEG_PREV: {
Björn Stenberga61617f2002-06-26 21:27:17 +00001494 DEBUGF("MPEG_PREV\n");
Linus Nielsen Feltzing9d860e12003-04-11 00:29:15 +00001495
1496 if (!playlist_check(-1))
Björn Stenberga6d0abb2002-10-04 08:48:20 +00001497 break;
Michael Sevakisffa86262013-07-12 12:03:20 -04001498
Björn Stenberga61617f2002-06-26 21:27:17 +00001499 /* stop the current stream */
Robert Keevilb8bb5212007-08-23 18:53:17 +00001500 end_current_track();
Linus Nielsen Feltzingab042e62002-07-27 00:31:38 +00001501
Björn Stenberga61617f2002-06-26 21:27:17 +00001502 /* Open the next file */
Hardeep Sidhu8fd18e92003-01-03 22:54:02 +00001503 if (new_file(-1) < 0) {
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001504 DEBUGF("No more files to play\n");
Linus Nielsen Feltzing80b285c2002-07-23 15:10:31 +00001505 filling = false;
Hardeep Sidhu8fef62b2005-11-08 06:28:05 +00001506
Hardeep Sidhu1df2edb2005-11-08 06:33:36 +00001507 check_playlist_end(-1);
1508 current_track_counter++;
Björn Stenberga61617f2002-06-26 21:27:17 +00001509 } else {
Linus Nielsen Feltzing80b285c2002-07-23 15:10:31 +00001510 /* Make it read more data */
1511 filling = true;
1512 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
Björn Stenberga61617f2002-06-26 21:27:17 +00001513
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +00001514 /* Tell the file loading code that we want to
1515 start playing as soon as we have some data */
Linus Nielsen Feltzing80b285c2002-07-23 15:10:31 +00001516 play_pending = true;
Robert Keevilb8bb5212007-08-23 18:53:17 +00001517 play_pending_track_change = true;
Linus Nielsen Feltzinge5792d62002-07-25 23:12:41 +00001518
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001519 update_playlist();
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00001520 current_track_counter++;
Björn Stenberga61617f2002-06-26 21:27:17 +00001521 }
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001522 break;
1523 }
Björn Stenberga61617f2002-06-26 21:27:17 +00001524
Björn Stenberg05704972002-08-14 19:23:34 +00001525 case MPEG_FF_REWIND: {
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00001526 struct mp3entry *id3 = audio_current_track();
Hardeep Sidhu98cb6362002-08-30 07:07:57 +00001527 unsigned int oldtime = id3->elapsed;
Hardeep Sidhu4160b752003-08-29 04:36:35 +00001528 unsigned int newtime = (unsigned int)ev.data;
Björn Stenberg05704972002-08-14 19:23:34 +00001529 int curpos, newpos, diffpos;
1530 DEBUGF("MPEG_FF_REWIND\n");
1531
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001532 id3->elapsed = newtime;
1533
Michael Sevakis31b71222013-07-14 07:59:39 -04001534 newpos = audio_get_file_pos_int(id3);
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +00001535 if(newpos < 0)
Björn Stenberg05704972002-08-14 19:23:34 +00001536 {
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001537 id3->elapsed = oldtime;
Björn Stenberg05704972002-08-14 19:23:34 +00001538 break;
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001539 }
Michael Sevakisffa86262013-07-12 12:03:20 -04001540
Hardeep Sidhuc5385932002-10-04 16:39:02 +00001541 if (mpeg_file >= 0)
1542 curpos = lseek(mpeg_file, 0, SEEK_CUR);
1543 else
1544 curpos = id3->filesize;
Björn Stenberg05704972002-08-14 19:23:34 +00001545
1546 if (num_tracks_in_memory() > 1)
1547 {
1548 /* We have started loading other tracks that need to be
1549 accounted for */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001550 struct trackdata *track;
1551 int i = 0;
Björn Stenberg05704972002-08-14 19:23:34 +00001552
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001553 while((track = get_trackdata(i++)))
Björn Stenberg05704972002-08-14 19:23:34 +00001554 {
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001555 curpos += track->id3.filesize;
Björn Stenberg05704972002-08-14 19:23:34 +00001556 }
1557 }
1558
1559 diffpos = curpos - newpos;
1560
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001561 if(!filling && diffpos >= 0 && diffpos < audiobuflen)
Björn Stenberg05704972002-08-14 19:23:34 +00001562 {
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +00001563 int unplayed_space_left, unswapped_space_left;
1564
Björn Stenberg05704972002-08-14 19:23:34 +00001565 /* We are changing to a position that's already in
Linus Nielsen Feltzing35c417f2003-04-12 09:38:33 +00001566 memory, so we just move the DMA read pointer. */
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001567 audiobuf_read = audiobuf_write - diffpos;
1568 if (audiobuf_read < 0)
Björn Stenberg05704972002-08-14 19:23:34 +00001569 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001570 audiobuf_read += audiobuflen;
Björn Stenberg05704972002-08-14 19:23:34 +00001571 }
1572
Hardeep Sidhu67f95ec2002-10-03 07:28:28 +00001573 unplayed_space_left = get_unplayed_space();
1574 unswapped_space_left = get_unswapped_space();
1575
Linus Nielsen Feltzing35c417f2003-04-12 09:38:33 +00001576 /* If unswapped_space_left is larger than
1577 unplayed_space_left, it means that the swapwrite pointer
1578 hasn't yet advanced up to the new location of the read
1579 pointer. We just move it, there is no need to swap
1580 data that won't be played anyway. */
Michael Sevakisffa86262013-07-12 12:03:20 -04001581
Linus Nielsen Feltzing35c417f2003-04-12 09:38:33 +00001582 if (unswapped_space_left > unplayed_space_left)
1583 {
1584 DEBUGF("Moved swapwrite\n");
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001585 audiobuf_swapwrite = audiobuf_read;
Linus Nielsen Feltzing35c417f2003-04-12 09:38:33 +00001586 play_pending = true;
1587 }
1588
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001589 if (mpeg_file>=0 && unplayed_space_left < low_watermark)
Hardeep Sidhuc6744152002-08-25 05:11:25 +00001590 {
1591 /* We need to load more data before starting */
1592 filling = true;
Jens Arnolddece4142005-08-21 21:15:32 +00001593 queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS);
Hardeep Sidhuc6744152002-08-25 05:11:25 +00001594 play_pending = true;
1595 }
1596 else
1597 {
1598 /* resume will start at new position */
Michael Sevakisffa86262013-07-12 12:03:20 -04001599 last_dma_chunk_size =
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001600 MIN(0x2000, get_unplayed_space_current_song());
Michael Sevakisffa86262013-07-12 12:03:20 -04001601 mp3_play_data(mpeg_audiobuf + audiobuf_read,
Jörg Hohensohnf9933652004-01-05 20:42:51 +00001602 last_dma_chunk_size, transfer_end);
1603 dma_underrun = false;
Hardeep Sidhuc6744152002-08-25 05:11:25 +00001604 }
Björn Stenberg05704972002-08-14 19:23:34 +00001605 }
1606 else
1607 {
1608 /* Move to the new position in the file and start
1609 loading data */
1610 reset_mp3_buffer();
1611
1612 if (num_tracks_in_memory() > 1)
1613 {
1614 /* We have to reload the current track */
1615 close(mpeg_file);
1616 remove_all_non_current_tags();
Jens Arnolddece4142005-08-21 21:15:32 +00001617 generate_unbuffer_events();
Hardeep Sidhuc5385932002-10-04 16:39:02 +00001618 mpeg_file = -1;
1619 }
Björn Stenberg05704972002-08-14 19:23:34 +00001620
Hardeep Sidhuc5385932002-10-04 16:39:02 +00001621 if (mpeg_file < 0)
1622 {
Björn Stenberg05704972002-08-14 19:23:34 +00001623 mpeg_file = open(id3->path, O_RDONLY);
1624 if (mpeg_file < 0)
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001625 {
1626 id3->elapsed = oldtime;
Björn Stenberg05704972002-08-14 19:23:34 +00001627 break;
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001628 }
Björn Stenberg05704972002-08-14 19:23:34 +00001629 }
1630
1631 if(-1 == lseek(mpeg_file, newpos, SEEK_SET))
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001632 {
1633 id3->elapsed = oldtime;
Björn Stenberg05704972002-08-14 19:23:34 +00001634 break;
Hardeep Sidhu441f48f2002-08-27 07:19:25 +00001635 }
Björn Stenberg05704972002-08-14 19:23:34 +00001636
1637 filling = true;
1638 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
1639
1640 /* Tell the file loading code that we want to start playing
1641 as soon as we have some data */
1642 play_pending = true;
1643 }
1644
Björn Stenberg34486b72002-08-19 11:00:29 +00001645 id3->offset = newpos;
Björn Stenberg05704972002-08-14 19:23:34 +00001646
1647 break;
1648 }
1649
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001650 case MPEG_FLUSH_RELOAD: {
1651 int numtracks = num_tracks_in_memory();
1652 bool reload_track = false;
1653
1654 if (numtracks > 1)
1655 {
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001656 /* Reset the buffer */
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00001657 audiobuf_write = get_trackdata(1)->mempos;
Hardeep Sidhudf34e6b2003-06-25 15:17:04 +00001658
1659 /* Reset swapwrite unless we're still swapping current
1660 track */
1661 if (get_unplayed_space() <= get_playable_space())
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001662 audiobuf_swapwrite = audiobuf_write;
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001663
1664 close(mpeg_file);
1665 remove_all_non_current_tags();
Jens Arnolddece4142005-08-21 21:15:32 +00001666 generate_unbuffer_events();
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001667 mpeg_file = -1;
1668 reload_track = true;
1669 }
1670 else if (numtracks == 1 && mpeg_file < 0)
1671 {
1672 reload_track = true;
1673 }
1674
1675 if(reload_track && new_file(1) >= 0)
1676 {
1677 /* Tell ourselves that we want more data */
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001678 filling = true;
Jens Arnolddece4142005-08-21 21:15:32 +00001679 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00001680 }
1681
1682 break;
1683 }
1684
Björn Stenberg1ac46002002-05-24 12:22:14 +00001685 case MPEG_NEED_DATA:
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001686 free_space_left = audiobuf_read - audiobuf_write;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001687
1688 /* We interpret 0 as "empty buffer" */
1689 if(free_space_left <= 0)
Jens Arnoldef328812005-05-27 21:46:44 +00001690 free_space_left += audiobuflen;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001691
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001692 unplayed_space_left = audiobuflen - free_space_left;
Linus Nielsen Feltzing54a65f72002-07-21 07:12:39 +00001693
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001694 /* Make sure that we don't fill the entire buffer */
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001695 free_space_left -= MPEG_HIGH_WATER;
Michael Sevakisffa86262013-07-12 12:03:20 -04001696
Jens Arnolddece4142005-08-21 21:15:32 +00001697 if (ev.data == GENERATE_UNBUFFER_EVENTS)
1698 generate_unbuffer_events();
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001699
Björn Stenbergc4b28502002-07-16 12:18:17 +00001700 /* do we have any more buffer space to fill? */
Jens Arnoldef328812005-05-27 21:46:44 +00001701 if(free_space_left <= 0)
Björn Stenberg1ac46002002-05-24 12:22:14 +00001702 {
1703 DEBUGF("0\n");
1704 filling = false;
Jens Arnolddece4142005-08-21 21:15:32 +00001705 generate_postbuffer_events();
Frank Gevaerts2f8a0082008-11-01 16:14:28 +00001706 storage_sleep();
Björn Stenbergc4b28502002-07-16 12:18:17 +00001707 break;
Björn Stenberg1ac46002002-05-24 12:22:14 +00001708 }
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001709
Linus Nielsen Feltzingb605b2e2002-07-31 06:33:48 +00001710 /* Read small chunks while we are below the low water mark */
Linus Nielsen Feltzing2df262c2002-12-05 12:18:22 +00001711 if(unplayed_space_left < low_watermark)
Linus Nielsen Feltzingb605b2e2002-07-31 06:33:48 +00001712 amount_to_read = MIN(MPEG_LOW_WATER_CHUNKSIZE,
1713 free_space_left);
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001714 else
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001715 amount_to_read = free_space_left;
Linus Nielsen Feltzingb605b2e2002-07-31 06:33:48 +00001716
1717 /* Don't read more than until the end of the buffer */
Jens Arnoldef328812005-05-27 21:46:44 +00001718 amount_to_read = MIN(audiobuflen - audiobuf_write,
1719 amount_to_read);
Frank Gevaerts19d1cac2008-10-31 21:25:04 +00001720#if (CONFIG_STORAGE & STORAGE_MMC)
1721 /* MMC is slow, so don't read too large chunks */
Jens Arnold5ae37f02004-10-09 12:42:56 +00001722 amount_to_read = MIN(0x40000, amount_to_read);
Andree Buschmann5d849a92011-02-02 17:43:32 +00001723#elif MEMORYSIZE == 8
Jens Arnoldba966c12005-09-15 05:29:26 +00001724 amount_to_read = MIN(0x100000, amount_to_read);
1725#endif
Linus Nielsen Feltzing402502f2002-10-14 14:13:13 +00001726
1727 /* Read as much mpeg data as we can fit in the buffer */
Linus Nielsen Feltzing3a25aa42002-05-29 12:25:21 +00001728 if(mpeg_file >= 0)
Björn Stenberg1ac46002002-05-24 12:22:14 +00001729 {
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001730 DEBUGF("R\n");
Linus Nielsen Feltzing1d21ca92002-08-01 08:16:44 +00001731 t1 = current_tick;
Thomas Martitzd1322b72011-08-14 15:13:00 +00001732 len = read(mpeg_file, mpeg_audiobuf + audiobuf_write,
Jens Arnoldef328812005-05-27 21:46:44 +00001733 amount_to_read);
Linus Nielsen Feltzingc7e36752002-06-05 14:34:05 +00001734 if(len > 0)
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001735 {
Linus Nielsen Feltzing1d21ca92002-08-01 08:16:44 +00001736 t2 = current_tick;
1737 DEBUGF("time: %d\n", t2 - t1);
Linus Nielsen Feltzing80b285c2002-07-23 15:10:31 +00001738 DEBUGF("R: %x\n", len);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001739
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001740 /* Now make sure that we don't feed the MAS with ID3V1
1741 data */
1742 if (len < amount_to_read)
1743 {
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001744 int i;
Jens Arnoldef328812005-05-27 21:46:44 +00001745 static const unsigned char tag[] = "TAG";
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001746 int taglen = 128;
Jens Arnoldef328812005-05-27 21:46:44 +00001747 int tagptr = audiobuf_write + len - 128;
Michael Sevakisffa86262013-07-12 12:03:20 -04001748
Jens Arnoldef328812005-05-27 21:46:44 +00001749 /* Really rare case: entire potential tag wasn't
1750 read in this call AND audiobuf_write < 128 */
1751 if (tagptr < 0)
1752 tagptr += audiobuflen;
Michael Sevakisffa86262013-07-12 12:03:20 -0400