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 -04001753
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001754 for(i = 0;i < 3;i++)
1755 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001756 if(tagptr >= audiobuflen)
1757 tagptr -= audiobuflen;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001758
Thomas Martitzd1322b72011-08-14 15:13:00 +00001759 if(mpeg_audiobuf[tagptr] != tag[i])
Jens Arnoldef328812005-05-27 21:46:44 +00001760 {
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001761 taglen = 0;
Jens Arnoldef328812005-05-27 21:46:44 +00001762 break;
1763 }
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001764
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001765 tagptr++;
1766 }
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001767
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001768 if(taglen)
1769 {
1770 /* Skip id3v1 tag */
1771 DEBUGF("Skipping ID3v1 tag\n");
1772 len -= taglen;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001773
Jens Arnoldef328812005-05-27 21:46:44 +00001774 /* In the very rare case when the entire tag
1775 wasn't read in this read() len will be < 0.
1776 Take care of this when changing the write
1777 pointer. */
Linus Nielsen Feltzingcc136c52003-03-02 03:58:54 +00001778 }
1779 }
Linus Nielsen Feltzingb3bb0762002-09-18 13:51:08 +00001780
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001781 audiobuf_write += len;
Jens Arnoldef328812005-05-27 21:46:44 +00001782
1783 if (audiobuf_write < 0)
1784 audiobuf_write += audiobuflen;
1785
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001786 if(audiobuf_write >= audiobuflen)
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001787 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001788 audiobuf_write = 0;
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001789 DEBUGF("W\n");
1790 }
Björn Stenberg1ac46002002-05-24 12:22:14 +00001791
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001792 /* Tell ourselves that we want more data */
1793 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
Björn Stenberg1ac46002002-05-24 12:22:14 +00001794 }
1795 else
1796 {
Linus Nielsen Feltzingc7e36752002-06-05 14:34:05 +00001797 if(len < 0)
1798 {
1799 DEBUGF("MPEG read error\n");
1800 }
Michael Sevakisffa86262013-07-12 12:03:20 -04001801
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001802 close(mpeg_file);
Linus Nielsen Feltzing3a25aa42002-05-29 12:25:21 +00001803 mpeg_file = -1;
Michael Sevakisffa86262013-07-12 12:03:20 -04001804
Björn Stenberga61617f2002-06-26 21:27:17 +00001805 if(new_file(1) < 0)
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001806 {
1807 /* No more data to play */
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00001808 DEBUGF("No more files to play\n");
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001809 filling = false;
1810 }
1811 else
1812 {
1813 /* Tell ourselves that we want more data */
1814 queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
1815 }
Linus Nielsen Feltzingf779e262002-05-29 10:26:06 +00001816 }
Björn Stenberg1ac46002002-05-24 12:22:14 +00001817 }
1818 break;
Michael Sevakisffa86262013-07-12 12:03:20 -04001819
Linus Nielsen Feltzinge4b9dbb2002-07-25 11:51:11 +00001820 case MPEG_TRACK_CHANGE:
Björn Stenbergbcbc7822002-08-08 12:02:17 +00001821 track_change();
Linus Nielsen Feltzinge4b9dbb2002-07-25 11:51:11 +00001822 break;
Daniel Stenberg40093342003-12-12 13:30:15 +00001823
1824#ifndef USB_NONE
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001825 case SYS_USB_CONNECTED:
Hardeep Sidhu18261c92003-08-20 02:11:00 +00001826 is_playing = false;
1827 paused = false;
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001828 stop_playing();
Jens Arnold329caa82005-08-19 22:39:01 +00001829
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001830 /* Tell the USB thread that we are safe */
1831 DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n");
1832 usb_acknowledge(SYS_USB_CONNECTED_ACK);
Linus Nielsen Feltzing392f3852002-06-29 23:01:10 +00001833
Linus Nielsen Feltzing4e46ac72002-07-18 21:02:55 +00001834 /* Wait until the USB cable is extracted again */
1835 usb_wait_for_disconnect(&mpeg_queue);
1836 break;
Jens Arnold1d38aa12005-08-19 06:43:50 +00001837#endif /* !USB_NONE */
Michael Sevakisffa86262013-07-12 12:03:20 -04001838
Jens Arnoldd6c05452005-08-29 21:15:27 +00001839#if CONFIG_CODEC == MAS3587F
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001840 case MPEG_INIT_RECORDING:
1841 init_recording();
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +00001842 init_recording_done = true;
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001843 break;
Jens Arnoldd6c05452005-08-29 21:15:27 +00001844#endif /* CONFIG_CODEC == MAS3587F */
Hardeep Sidhu839dbca2005-07-04 22:50:57 +00001845
1846 case SYS_TIMEOUT:
1847 if (playing)
1848 playlist_update_resume_info(audio_current_track());
1849 break;
Jens Arnolddece4142005-08-21 21:15:32 +00001850 }
Jens Arnoldd6c05452005-08-29 21:15:27 +00001851#if CONFIG_CODEC == MAS3587F
Björn Stenberg1ac46002002-05-24 12:22:14 +00001852 }
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001853 else
1854 {
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001855 queue_wait(&mpeg_queue, &ev);
1856 switch(ev.id)
1857 {
1858 case MPEG_RECORD:
Jens Arnold9352ac82005-09-04 21:55:15 +00001859 if (is_prerecording)
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001860 {
Jens Arnold9352ac82005-09-04 21:55:15 +00001861 int startpos;
1862
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001863 /* Go back prerecord_count seconds in the buffer */
1864 startpos = prerecord_index - prerecord_count;
1865 if(startpos < 0)
1866 startpos += prerecording_max_seconds;
Linus Nielsen Feltzing94dea1e2003-02-22 01:40:57 +00001867
Jens Arnold9352ac82005-09-04 21:55:15 +00001868 /* Read the position data from the prerecord buffer */
1869 frame_count_start = prerecord_buffer[startpos].framecount;
1870 startpos = prerecord_buffer[startpos].mempos;
Linus Nielsen Feltzing94dea1e2003-02-22 01:40:57 +00001871
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001872 DEBUGF("Start looking at address %x (%x)\n",
Thomas Martitzd1322b72011-08-14 15:13:00 +00001873 mpeg_audiobuf+startpos, startpos);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001874
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +00001875 saved_header = mpeg_get_last_header();
Michael Sevakisffa86262013-07-12 12:03:20 -04001876
Jens Arnold9352ac82005-09-04 21:55:15 +00001877 mem_find_next_frame(startpos, &offset, 1800,
Thomas Martitzd1322b72011-08-14 15:13:00 +00001878 saved_header, mpeg_audiobuf,
1879 audiobuflen);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001880
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001881 audiobuf_read = startpos + offset;
Linus Nielsen Feltzing051f2cf2005-09-02 07:01:08 +00001882 if(audiobuf_read >= audiobuflen)
1883 audiobuf_read -= audiobuflen;
1884
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001885 DEBUGF("New audiobuf_read address: %x (%x)\n",
Thomas Martitzd1322b72011-08-14 15:13:00 +00001886 mpeg_audiobuf+audiobuf_read, audiobuf_read);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001887
Michael Sevakisaf395f42008-03-26 01:50:41 +00001888 level = disable_irq_save();
Linus Nielsen Feltzing051f2cf2005-09-02 07:01:08 +00001889 num_rec_bytes = get_unsaved_space();
Michael Sevakisaf395f42008-03-26 01:50:41 +00001890 restore_irq(level);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001891 }
1892 else
1893 {
Jens Arnold9352ac82005-09-04 21:55:15 +00001894 frame_count_start = 0;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001895 num_rec_bytes = 0;
Jens Arnold9352ac82005-09-04 21:55:15 +00001896 audiobuf_read = MPEG_RESERVED_HEADER_SPACE;
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00001897 audiobuf_write = MPEG_RESERVED_HEADER_SPACE;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001898 }
Linus Nielsen Feltzing6fc0df92003-04-11 23:45:38 +00001899
Jens Arnold9352ac82005-09-04 21:55:15 +00001900 prepend_header();
1901 DEBUGF("Recording...\n");
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001902 start_recording();
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00001903
1904 /* Wait until at least one frame is encoded and get the
1905 frame header, for later use by the Xing header
1906 generation */
Jens Arnolde03f4022005-06-04 11:29:39 +00001907 sleep(HZ/5);
Linus Nielsen Feltzing0744c502004-07-29 13:58:16 +00001908 saved_header = mpeg_get_last_header();
Jens Arnold9352ac82005-09-04 21:55:15 +00001909
Jörg Hohensohnfbea7082004-03-11 19:27:26 +00001910 /* delayed until buffer is saved, don't open yet */
1911 strcpy(delayed_filename, recording_filename);
Michael Sevakisffa86262013-07-12 12:03:20 -04001912 mpeg_file = -1;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001913
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001914 break;
Michael Sevakisffa86262013-07-12 12:03:20 -04001915
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001916 case MPEG_STOP:
1917 DEBUGF("MPEG_STOP\n");
Linus Nielsen Feltzinga9875a92003-12-28 03:37:23 +00001918
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001919 stop_recording();
Jens Arnoldba966c12005-09-15 05:29:26 +00001920
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001921 /* Save the remaining data in the buffer */
Jens Arnolde03f4022005-06-04 11:29:39 +00001922 save_endpos = audiobuf_write;
1923 saving_status = STOP_RECORDING;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001924 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
1925 break;
Jens Arnolde03f4022005-06-04 11:29:39 +00001926
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001927 case MPEG_STOP_DONE:
1928 DEBUGF("MPEG_STOP_DONE\n");
Jens Arnolde03f4022005-06-04 11:29:39 +00001929
1930 if (mpeg_file >= 0)
Linus Nielsen Feltzing94dea1e2003-02-22 01:40:57 +00001931 close(mpeg_file);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001932 mpeg_file = -1;
Jens Arnolde03f4022005-06-04 11:29:39 +00001933
Jens Arnold9352ac82005-09-04 21:55:15 +00001934 update_header();
Linus Nielsen Feltzing6a240592002-11-24 11:49:17 +00001935#ifdef DEBUG1
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001936 {
1937 int i;
1938 for(i = 0;i < 512;i++)
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001939 {
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001940 DEBUGF("%d - %d us (%d bytes)\n",
1941 timing_info[i*2],
1942 (timing_info[i*2+1] & 0xffff) *
1943 10000 / 13824,
1944 timing_info[i*2+1] >> 16);
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00001945 }
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001946 }
Jens Arnold1d38aa12005-08-19 06:43:50 +00001947#endif /* DEBUG1 */
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001948
Jens Arnolde03f4022005-06-04 11:29:39 +00001949 if (prerecording)
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00001950 {
1951 start_prerecording();
1952 }
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001953 mpeg_stop_done = true;
1954 break;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00001955
1956 case MPEG_NEW_FILE:
Jens Arnolde03f4022005-06-04 11:29:39 +00001957 /* Bail out when a more important save is happening */
Jens Arnoldba966c12005-09-15 05:29:26 +00001958 if (saving_status > NEW_FILE)
Jens Arnolde03f4022005-06-04 11:29:39 +00001959 break;
1960
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00001961 /* Make sure we have at least one complete frame
Linus Nielsen Feltzing51d962f2003-11-03 21:05:46 +00001962 in the buffer. If we haven't recorded a single
1963 frame within 200ms, the MAS is probably not recording
1964 anything, and we bail out. */
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00001965 amount_to_save = get_unsaved_space();
Jens Arnolde03f4022005-06-04 11:29:39 +00001966 if (amount_to_save < 1800)
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00001967 {
Jens Arnolde03f4022005-06-04 11:29:39 +00001968 sleep(HZ/5);
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00001969 amount_to_save = get_unsaved_space();
1970 }
1971
Jens Arnold9352ac82005-09-04 21:55:15 +00001972 mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT,
1973 &frame_count_end, 1);
Michael Sevakisffa86262013-07-12 12:03:20 -04001974
Jens Arnoldba966c12005-09-15 05:29:26 +00001975 last_rec_time = current_tick - record_start_time;
1976 record_start_time = current_tick;
1977 if (paused)
1978 pause_start_time = record_start_time;
1979
Jens Arnold9352ac82005-09-04 21:55:15 +00001980 /* capture all values at one point */
Michael Sevakisaf395f42008-03-26 01:50:41 +00001981 level = disable_irq_save();
Jens Arnold9352ac82005-09-04 21:55:15 +00001982 save_endpos = audiobuf_write;
1983 last_rec_bytes = num_rec_bytes;
1984 num_rec_bytes = 0;
Michael Sevakisaf395f42008-03-26 01:50:41 +00001985 restore_irq(level);
Jens Arnold9352ac82005-09-04 21:55:15 +00001986
Jens Arnolde03f4022005-06-04 11:29:39 +00001987 if (amount_to_save >= 1800)
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00001988 {
Linus Nielsen Feltzing51d962f2003-11-03 21:05:46 +00001989 /* Now find a frame boundary to split at */
Jens Arnold9352ac82005-09-04 21:55:15 +00001990 save_endpos -= 1800;
Jens Arnolde03f4022005-06-04 11:29:39 +00001991 if (save_endpos < 0)
1992 save_endpos += audiobuflen;
Linus Nielsen Feltzinga9875a92003-12-28 03:37:23 +00001993
Jens Arnolde03f4022005-06-04 11:29:39 +00001994 rc = mem_find_next_frame(save_endpos, &offset, 1800,
Thomas Martitzd1322b72011-08-14 15:13:00 +00001995 saved_header, mpeg_audiobuf,
1996 audiobuflen);
Jens Arnold9352ac82005-09-04 21:55:15 +00001997 if (!rc) /* No header found, save whole buffer */
1998 offset = 1800;
1999
2000 save_endpos += offset;
2001 if (save_endpos >= audiobuflen)
2002 save_endpos -= audiobuflen;
2003
2004 last_rec_bytes += offset - 1800;
Michael Sevakisaf395f42008-03-26 01:50:41 +00002005 level = disable_irq_save();
Jens Arnold9352ac82005-09-04 21:55:15 +00002006 num_rec_bytes += 1800 - offset;
Michael Sevakisaf395f42008-03-26 01:50:41 +00002007 restore_irq(level);
Linus Nielsen Feltzing532eb412003-11-03 20:06:21 +00002008 }
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00002009
Jens Arnolde03f4022005-06-04 11:29:39 +00002010 saving_status = NEW_FILE;
2011 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
Jens Arnold9352ac82005-09-04 21:55:15 +00002012 break;
Jens Arnolde03f4022005-06-04 11:29:39 +00002013
Michael Sevakisffa86262013-07-12 12:03:20 -04002014 case MPEG_SAVE_DATA:
Jens Arnolde03f4022005-06-04 11:29:39 +00002015 if (saving_status == BUFFER_FULL)
2016 save_endpos = audiobuf_write;
2017
2018 if (mpeg_file < 0) /* delayed file open */
Jörg Hohensohnfbea7082004-03-11 19:27:26 +00002019 {
Thomas Martitz0a1d7c22010-05-06 17:35:13 +00002020 mpeg_file = open(delayed_filename, O_WRONLY|O_CREAT, 0666);
Jens Arnolde03f4022005-06-04 11:29:39 +00002021
2022 if (mpeg_file < 0)
Jörg Hohensohnfbea7082004-03-11 19:27:26 +00002023 panicf("recfile: %d", mpeg_file);
2024 }
2025
Jens Arnolde03f4022005-06-04 11:29:39 +00002026 amount_to_save = save_endpos - audiobuf_read;
2027 if (amount_to_save < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00002028 amount_to_save += audiobuflen;
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002029
Jens Arnolde03f4022005-06-04 11:29:39 +00002030 amount_to_save = MIN(amount_to_save,
2031 audiobuflen - audiobuf_read);
Frank Gevaerts19d1cac2008-10-31 21:25:04 +00002032#if (CONFIG_STORAGE & STORAGE_MMC)
2033 /* MMC is slow, so don't save too large chunks at once */
Jens Arnolde03f4022005-06-04 11:29:39 +00002034 amount_to_save = MIN(0x40000, amount_to_save);
Andree Buschmann5d849a92011-02-02 17:43:32 +00002035#elif MEMORYSIZE == 8
Jens Arnoldba966c12005-09-15 05:29:26 +00002036 amount_to_save = MIN(0x100000, amount_to_save);
Jens Arnolde03f4022005-06-04 11:29:39 +00002037#endif
Thomas Martitzd1322b72011-08-14 15:13:00 +00002038 rc = write(mpeg_file, mpeg_audiobuf + audiobuf_read,
Jens Arnolde03f4022005-06-04 11:29:39 +00002039 amount_to_save);
2040 if (rc < 0)
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00002041 {
Jens Arnolde03f4022005-06-04 11:29:39 +00002042 if (errno == ENOSPC)
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002043 {
Jens Arnolde03f4022005-06-04 11:29:39 +00002044 mpeg_errno = AUDIOERR_DISK_FULL;
2045 stop_recording();
2046 queue_post(&mpeg_queue, MPEG_STOP_DONE, 0);
2047 /* will close the file */
2048 break;
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002049 }
2050 else
Jens Arnolde03f4022005-06-04 11:29:39 +00002051 panicf("rec wrt: %d", rc);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00002052 }
Jens Arnolde03f4022005-06-04 11:29:39 +00002053
2054 audiobuf_read += amount_to_save;
2055 if (audiobuf_read >= audiobuflen)
2056 audiobuf_read = 0;
2057
2058 if (audiobuf_read == save_endpos) /* all saved */
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00002059 {
Jens Arnolde03f4022005-06-04 11:29:39 +00002060 switch (saving_status)
2061 {
2062 case BUFFER_FULL:
2063 rc = fsync(mpeg_file);
2064 if (rc < 0)
2065 panicf("rec fls: %d", rc);
Frank Gevaerts2f8a0082008-11-01 16:14:28 +00002066 storage_sleep();
Jens Arnolde03f4022005-06-04 11:29:39 +00002067 break;
2068
2069 case NEW_FILE:
2070 /* Close the current file */
2071 rc = close(mpeg_file);
2072 if (rc < 0)
Jens Arnold9352ac82005-09-04 21:55:15 +00002073 panicf("rec cls: %d", rc);
Jens Arnolde03f4022005-06-04 11:29:39 +00002074 mpeg_file = -1;
Jens Arnold9352ac82005-09-04 21:55:15 +00002075 update_header();
Frank Gevaerts2f8a0082008-11-01 16:14:28 +00002076 storage_sleep();
Jens Arnold9352ac82005-09-04 21:55:15 +00002077
Jens Arnolde03f4022005-06-04 11:29:39 +00002078 /* copy new filename */
2079 strcpy(delayed_filename, recording_filename);
Jens Arnold9352ac82005-09-04 21:55:15 +00002080 prepend_header();
2081 frame_count_start = frame_count_end;
Jens Arnolde03f4022005-06-04 11:29:39 +00002082 break;
2083
2084 case STOP_RECORDING:
Michael Sevakis4b902672006-12-19 16:50:07 +00002085 queue_post(&mpeg_queue, MPEG_STOP_DONE, 0);
Jens Arnolde03f4022005-06-04 11:29:39 +00002086 /* will close the file */
2087 break;
Jens Arnold9352ac82005-09-04 21:55:15 +00002088
Jens Arnolde03f4022005-06-04 11:29:39 +00002089 default:
2090 break;
2091 }
2092 saving_status = NOT_SAVING;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00002093 }
Jens Arnolde03f4022005-06-04 11:29:39 +00002094 else /* tell ourselves to save the next chunk */
2095 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
2096
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00002097 break;
Michael Sevakisffa86262013-07-12 12:03:20 -04002098
Jens Arnold9352ac82005-09-04 21:55:15 +00002099 case MPEG_PRERECORDING_TICK:
2100 if(!is_prerecording)
2101 break;
2102
2103 /* Store the write pointer every second */
2104 prerecord_buffer[prerecord_index].mempos = audiobuf_write;
2105 mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT,
2106 &prerecord_buffer[prerecord_index].framecount, 1);
2107
2108 /* Wrap if necessary */
2109 if(++prerecord_index == prerecording_max_seconds)
2110 prerecord_index = 0;
2111
2112 /* Update the number of seconds recorded */
2113 if(prerecord_count < prerecording_max_seconds)
2114 prerecord_count++;
2115 break;
Jens Arnolde03f4022005-06-04 11:29:39 +00002116
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00002117 case MPEG_INIT_PLAYBACK:
Michael Sevakisffa86262013-07-12 12:03:20 -04002118 /* Stop the prerecording */
Linus Nielsen Feltzingcd8847b2004-01-08 11:18:01 +00002119 stop_recording();
Jens Arnold3f11ff62005-12-04 16:37:38 +00002120 reset_mp3_buffer();
Jörg Hohensohnf9933652004-01-05 20:42:51 +00002121 mp3_play_init();
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00002122 init_playback_done = true;
2123 break;
Michael Sevakisffa86262013-07-12 12:03:20 -04002124
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002125 case MPEG_PAUSE_RECORDING:
Jens Arnolde03f4022005-06-04 11:29:39 +00002126 pause_recording();
2127 break;
Michael Sevakisffa86262013-07-12 12:03:20 -04002128
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002129 case MPEG_RESUME_RECORDING:
Jens Arnolde03f4022005-06-04 11:29:39 +00002130 resume_recording();
2131 break;
Michael Sevakisffa86262013-07-12 12:03:20 -04002132
Linus Nielsen Feltzingaaa99e72003-11-20 00:33:43 +00002133 case SYS_USB_CONNECTED:
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002134 /* We can safely go to USB mode if no recording
2135 is taking place */
2136 if((!is_recording || is_prerecording) && mpeg_stop_done)
2137 {
2138 /* Even if we aren't recording, we still call this
2139 function, to put the MAS in monitoring mode,
2140 to save power. */
2141 stop_recording();
Michael Sevakisffa86262013-07-12 12:03:20 -04002142
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002143 /* Tell the USB thread that we are safe */
2144 DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n");
2145 usb_acknowledge(SYS_USB_CONNECTED_ACK);
Michael Sevakisffa86262013-07-12 12:03:20 -04002146
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002147 /* Wait until the USB cable is extracted again */
2148 usb_wait_for_disconnect(&mpeg_queue);
2149 }
Linus Nielsen Feltzingaaa99e72003-11-20 00:33:43 +00002150 break;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00002151 }
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002152 }
Jens Arnoldd6c05452005-08-29 21:15:27 +00002153#endif /* CONFIG_CODEC == MAS3587F */
Björn Stenberg1ac46002002-05-24 12:22:14 +00002154 }
2155}
Jens Arnold1d38aa12005-08-19 06:43:50 +00002156#endif /* !SIMULATOR */
Björn Stenberg1ac46002002-05-24 12:22:14 +00002157
Jeffrey Goodedb82be42009-11-16 20:09:46 +00002158struct mp3entry* audio_current_track(void)
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +00002159{
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00002160#ifdef SIMULATOR
Jonathan Gordon24b136f2009-07-20 05:18:18 +00002161 struct mp3entry *id3 = &taginfo;
Jens Arnold1d38aa12005-08-19 06:43:50 +00002162#else /* !SIMULATOR */
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00002163 if(num_tracks_in_memory())
Jonathan Gordon24b136f2009-07-20 05:18:18 +00002164 {
2165 struct mp3entry *id3 = &get_trackdata(0)->id3;
Michael Sevakisffa86262013-07-12 12:03:20 -04002166#endif
Jonathan Gordon24b136f2009-07-20 05:18:18 +00002167 if (!checked_for_cuesheet && curr_cuesheet && id3->cuesheet == NULL)
2168 {
2169 checked_for_cuesheet = true; /* only check once per track */
Nick Peskett02fd3142011-12-16 10:09:41 +00002170 struct cuesheet_file cue_file;
Jonathan Gordon24b136f2009-07-20 05:18:18 +00002171
Nick Pesketta47982e2011-12-16 10:24:21 +00002172 if (look_for_cuesheet_file(id3, &cue_file) &&
Nick Peskett02fd3142011-12-16 10:09:41 +00002173 parse_cuesheet(&cue_file, curr_cuesheet))
Jonathan Gordon24b136f2009-07-20 05:18:18 +00002174 {
Jonathan Gordon24b136f2009-07-20 05:18:18 +00002175 id3->cuesheet = curr_cuesheet;
Jonathan Gordon24b136f2009-07-20 05:18:18 +00002176 }
2177 }
2178 return id3;
2179#ifndef SIMULATOR
2180 }
Linus Nielsen Feltzing42faf562002-07-26 14:32:24 +00002181 else
2182 return NULL;
Jens Arnold1d38aa12005-08-19 06:43:50 +00002183#endif /* !SIMULATOR */
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +00002184}
Björn Stenberg3c260772002-05-24 15:27:55 +00002185
Jeffrey Goodedb82be42009-11-16 20:09:46 +00002186struct mp3entry* audio_next_track(void)
Daniel Stenbergd815ad62004-01-15 15:32:49 +00002187{
2188#ifdef SIMULATOR
2189 return &taginfo;
Jens Arnold1d38aa12005-08-19 06:43:50 +00002190#else /* !SIMULATOR */
Daniel Stenbergd815ad62004-01-15 15:32:49 +00002191 if(num_tracks_in_memory() > 1)
Linus Nielsen Feltzing5f8241a2005-04-07 22:28:26 +00002192 return &get_trackdata(1)->id3;
Daniel Stenbergd815ad62004-01-15 15:32:49 +00002193 else
2194 return NULL;
Jens Arnold1d38aa12005-08-19 06:43:50 +00002195#endif /* !SIMULATOR */
Daniel Stenbergd815ad62004-01-15 15:32:49 +00002196}
2197
Jens Arnoldd6c05452005-08-29 21:15:27 +00002198#if CONFIG_CODEC == MAS3587F
Jens Arnold8051a0b2005-11-06 23:12:11 +00002199#ifndef SIMULATOR
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002200void audio_init_playback(void)
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002201{
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +00002202 init_playback_done = false;
Michael Sevakis4b902672006-12-19 16:50:07 +00002203 queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, 0);
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +00002204
2205 while(!init_playback_done)
Michael Sevakised8445f2008-03-20 15:20:06 +00002206 sleep(1);
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002207}
2208
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002209
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002210/****************************************************************************
Jens Arnold329caa82005-08-19 22:39:01 +00002211 * Recording functions
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002212 ***************************************************************************/
Thomas Martitz8a701e52011-08-14 15:37:05 +00002213void audio_init_recording(void)
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002214{
2215 init_recording_done = false;
Michael Sevakis4b902672006-12-19 16:50:07 +00002216 queue_post(&mpeg_queue, MPEG_INIT_RECORDING, 0);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002217
2218 while(!init_recording_done)
Michael Sevakised8445f2008-03-20 15:20:06 +00002219 sleep(1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002220}
2221
2222static void init_recording(void)
2223{
2224 unsigned long val;
2225 int rc;
2226
2227 /* Disable IRQ6 */
2228 IPRB &= 0xff0f;
2229
2230 stop_playing();
2231 is_playing = false;
2232 paused = false;
2233
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002234 /* Init the recording variables */
2235 is_recording = false;
2236 is_prerecording = false;
2237
Thomas Martitzee7c1352013-12-23 12:48:26 +01002238 /* Have to grab the audio buffer in case voice had it */
2239 audio_reset_buffer();
2240
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002241 mpeg_stop_done = true;
Michael Sevakisffa86262013-07-12 12:03:20 -04002242
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002243 mas_reset();
Michael Sevakisffa86262013-07-12 12:03:20 -04002244
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002245 /* Enable the audio CODEC and the DSP core, max analog voltage range */
2246 rc = mas_direct_config_write(MAS_CONTROL, 0x8c00);
2247 if(rc < 0)
2248 panicf("mas_ctrl_w: %d", rc);
2249
2250 /* Stop the current application */
2251 val = 0;
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002252 mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002253 do
2254 {
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002255 mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002256 } while(val);
2257
2258 /* Perform black magic as described by the data sheet */
Jens Arnold536dff12004-08-05 17:06:31 +00002259 if((mas_version_code & 0x0fff) == 0x0102)
Michael Sevakisffa86262013-07-12 12:03:20 -04002260 {
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002261 DEBUGF("Performing MAS black magic for B2 version\n");
2262 mas_writereg(0xa3, 0x98);
2263 mas_writereg(0x94, 0xfffff);
2264 val = 0;
2265 mas_writemem(MAS_BANK_D1, 0, &val, 1);
2266 mas_writereg(0xa3, 0x90);
2267 }
2268
2269 /* Enable A/D Converters */
Jörg Hohensohn3bf321f2004-12-21 23:49:43 +00002270 shadow_codec_reg0 = 0xcccd;
2271 mas_codec_writereg(0x0, shadow_codec_reg0);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002272
2273 /* Copy left channel to right (mono mode) */
2274 mas_codec_writereg(8, 0x8000);
Michael Sevakisffa86262013-07-12 12:03:20 -04002275
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002276 /* ADC scale 0%, DSP scale 100%
2277 We use the DSP output for monitoring, because it works with all
2278 sources including S/PDIF */
2279 mas_codec_writereg(6, 0x0000);
2280 mas_codec_writereg(7, 0x4000);
2281
2282 /* No mute */
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002283 shadow_soft_mute = 0;
2284 mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute, 1);
Michael Sevakisffa86262013-07-12 12:03:20 -04002285
Jens Arnold0f949e92006-11-06 22:40:40 +00002286#ifdef HAVE_SPDIF_OUT
2287 val = 0x09; /* Disable SDO and SDI, low impedance S/PDIF outputs */
2288#else
2289 val = 0x2d; /* Disable SDO and SDI, disable S/PDIF output */
2290#endif
2291 mas_writemem(MAS_BANK_D0, MAS_D0_INTERFACE_CONTROL, &val, 1);
2292
Linus Nielsen Feltzing52486412004-04-01 14:07:56 +00002293 /* Set Demand mode, monitoring OFF and validate all settings */
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002294 shadow_io_control_main = 0x125;
2295 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002296
2297 /* Start the encoder application */
2298 val = 0x40;
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002299 mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002300 do
2301 {
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002302 mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002303 } while(!(val & 0x40));
2304
2305 /* We have started the recording application with monitoring OFF.
2306 This is because we want to record at least one frame to fill the DMA
2307 buffer, because the silly MAS will not negate EOD until at least one
2308 DMA transfer has taken place.
2309 Now let's wait for some data to be encoded. */
Jens Arnoldd6c05452005-08-29 21:15:27 +00002310 sleep(HZ/5);
Michael Sevakisffa86262013-07-12 12:03:20 -04002311
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002312 /* Now set it to Monitoring mode as default, saves power */
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002313 shadow_io_control_main = 0x525;
2314 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002315
Jens Arnold7464fb92004-08-23 23:05:55 +00002316 /* Wait until the DSP has accepted the settings */
2317 do
2318 {
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002319 mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1);
Jens Arnold7464fb92004-08-23 23:05:55 +00002320 } while(val & 1);
2321
Linus Nielsen Feltzing52486412004-04-01 14:07:56 +00002322 drain_dma_buffer();
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002323 mpeg_mode = MPEG_ENCODER;
2324
2325 DEBUGF("MAS Recording application started\n");
2326
2327 /* At this point, all settings are the reset MAS defaults, next thing is to
2328 call mpeg_set_recording_options(). */
2329}
2330
Andye6e54962005-11-12 04:00:56 +00002331void audio_record(const char *filename)
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002332{
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +00002333 mpeg_errno = 0;
Michael Sevakisffa86262013-07-12 12:03:20 -04002334
Nils Wallménius3d4701a2009-07-14 13:57:45 +00002335 strlcpy(recording_filename, filename, MAX_PATH);
Jens Arnoldba966c12005-09-15 05:29:26 +00002336
Michael Sevakis4b902672006-12-19 16:50:07 +00002337 queue_post(&mpeg_queue, MPEG_RECORD, 0);
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002338}
2339
Andye6e54962005-11-12 04:00:56 +00002340void audio_pause_recording(void)
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002341{
Michael Sevakis4b902672006-12-19 16:50:07 +00002342 queue_post(&mpeg_queue, MPEG_PAUSE_RECORDING, 0);
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002343}
2344
Andye6e54962005-11-12 04:00:56 +00002345void audio_resume_recording(void)
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002346{
Michael Sevakis4b902672006-12-19 16:50:07 +00002347 queue_post(&mpeg_queue, MPEG_RESUME_RECORDING, 0);
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002348}
2349
Jens Arnold9352ac82005-09-04 21:55:15 +00002350static void prepend_header(void)
2351{
2352 int startpos;
2353 unsigned i;
2354
2355 /* Make room for header */
2356 audiobuf_read -= MPEG_RESERVED_HEADER_SPACE;
2357 if(audiobuf_read < 0)
2358 {
2359 /* Clear the bottom half */
Thomas Martitzd1322b72011-08-14 15:13:00 +00002360 memset(mpeg_audiobuf, 0, audiobuf_read + MPEG_RESERVED_HEADER_SPACE);
Jens Arnold9352ac82005-09-04 21:55:15 +00002361
2362 /* And the top half */
2363 audiobuf_read += audiobuflen;
Thomas Martitzd1322b72011-08-14 15:13:00 +00002364 memset(mpeg_audiobuf + audiobuf_read, 0, audiobuflen - audiobuf_read);
Jens Arnold9352ac82005-09-04 21:55:15 +00002365 }
2366 else
2367 {
Thomas Martitzd1322b72011-08-14 15:13:00 +00002368 memset(mpeg_audiobuf + audiobuf_read, 0, MPEG_RESERVED_HEADER_SPACE);
Jens Arnold9352ac82005-09-04 21:55:15 +00002369 }
2370 /* Copy the empty ID3 header */
2371 startpos = audiobuf_read;
2372 for(i = 0; i < sizeof(empty_id3_header); i++)
2373 {
Thomas Martitzd1322b72011-08-14 15:13:00 +00002374 mpeg_audiobuf[startpos++] = empty_id3_header[i];
Jens Arnold9352ac82005-09-04 21:55:15 +00002375 if(startpos == audiobuflen)
2376 startpos = 0;
2377 }
2378}
2379
2380static void update_header(void)
2381{
2382 int fd, framelen;
2383 unsigned long frames;
2384
2385 if (last_rec_bytes > 0)
2386 {
2387 /* Create the Xing header */
2388 fd = open(delayed_filename, O_RDWR);
2389 if (fd < 0)
2390 panicf("rec upd: %d (%s)", fd, recording_filename);
2391
2392 frames = frame_count_end - frame_count_start;
2393 /* If the number of recorded frames has reached 0x7ffff,
2394 we can no longer trust it */
2395 if (frame_count_end == 0x7ffff)
2396 frames = 0;
2397
2398 /* saved_header is saved right before stopping the MAS */
2399 framelen = create_xing_header(fd, 0, last_rec_bytes, xing_buffer,
Jens Arnoldba966c12005-09-15 05:29:26 +00002400 frames, last_rec_time * (1000/HZ),
Thomas Martitzd1322b72011-08-14 15:13:00 +00002401 saved_header, NULL, false,
2402 mpeg_audiobuf, audiobuflen);
Jens Arnold9352ac82005-09-04 21:55:15 +00002403
2404 lseek(fd, MPEG_RESERVED_HEADER_SPACE - framelen, SEEK_SET);
2405 write(fd, xing_buffer, framelen);
2406 close(fd);
2407 }
2408}
2409
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002410static void start_prerecording(void)
2411{
2412 unsigned long val;
2413
2414 DEBUGF("Starting prerecording\n");
Michael Sevakisffa86262013-07-12 12:03:20 -04002415
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002416 prerecord_index = 0;
2417 prerecord_count = 0;
2418 prerecord_timeout = current_tick + HZ;
2419 memset(prerecord_buffer, 0, sizeof(prerecord_buffer));
2420 reset_mp3_buffer();
Michael Sevakisffa86262013-07-12 12:03:20 -04002421
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002422 is_prerecording = true;
2423
2424 /* Stop monitoring and start the encoder */
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002425 shadow_io_control_main &= ~(1 << 10);
2426 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
2427 DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002428
2429 /* Wait until the DSP has accepted the settings */
2430 do
2431 {
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002432 mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002433 } while(val & 1);
Michael Sevakisffa86262013-07-12 12:03:20 -04002434
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002435 is_recording = true;
Jens Arnolde03f4022005-06-04 11:29:39 +00002436 saving_status = NOT_SAVING;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002437
2438 demand_irq_enable(true);
2439}
2440
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002441static void start_recording(void)
2442{
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +00002443 unsigned long val;
2444
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002445 if(is_prerecording)
Linus Nielsen Feltzingcde27c32002-11-25 20:16:44 +00002446 {
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002447 /* This will make the IRQ handler start recording
2448 for real, i.e send MPEG_SAVE_DATA messages when
2449 the buffer is full */
2450 is_prerecording = false;
2451 }
2452 else
2453 {
2454 /* If prerecording is off, we need to stop the monitoring
2455 and start the encoder */
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002456 shadow_io_control_main &= ~(1 << 10);
2457 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
2458 DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main);
Linus Nielsen Feltzingd554d802004-03-30 08:21:53 +00002459
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002460 /* Wait until the DSP has accepted the settings */
2461 do
2462 {
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002463 mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002464 } while(val & 1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002465 }
Michael Sevakisffa86262013-07-12 12:03:20 -04002466
Linus Nielsen Feltzing1fcd31d2003-02-14 02:48:12 +00002467 is_recording = true;
Jens Arnolde03f4022005-06-04 11:29:39 +00002468 saving_status = NOT_SAVING;
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002469 paused = false;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002470
2471 /* Store the current time */
2472 if(prerecording)
2473 record_start_time = current_tick - prerecord_count * HZ;
2474 else
2475 record_start_time = current_tick;
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002476
2477 pause_start_time = 0;
Jens Arnoldba966c12005-09-15 05:29:26 +00002478
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002479 demand_irq_enable(true);
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002480}
2481
Linus Nielsen Feltzing52486412004-04-01 14:07:56 +00002482static void pause_recording(void)
2483{
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002484 pause_start_time = current_tick;
Linus Nielsen Feltzingce3482c2004-06-04 10:40:26 +00002485
Linus Nielsen Feltzing52486412004-04-01 14:07:56 +00002486 /* Set the pause bit */
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002487 shadow_soft_mute |= 2;
2488 mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute, 1);
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002489
2490 paused = true;
Linus Nielsen Feltzing52486412004-04-01 14:07:56 +00002491}
2492
2493static void resume_recording(void)
2494{
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002495 paused = false;
Michael Sevakisffa86262013-07-12 12:03:20 -04002496
Linus Nielsen Feltzing52486412004-04-01 14:07:56 +00002497 /* Clear the pause bit */
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002498 shadow_soft_mute &= ~2;
2499 mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute, 1);
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002500
2501 /* Compensate for the time we have been paused */
2502 if(pause_start_time)
2503 {
2504 record_start_time =
2505 current_tick - (pause_start_time - record_start_time);
2506 pause_start_time = 0;
2507 }
Linus Nielsen Feltzing52486412004-04-01 14:07:56 +00002508}
2509
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +00002510static void stop_recording(void)
2511{
2512 unsigned long val;
2513
Linus Nielsen Feltzing52486412004-04-01 14:07:56 +00002514 /* Let it finish the last frame */
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002515 if(!paused)
2516 pause_recording();
Linus Nielsen Feltzing52486412004-04-01 14:07:56 +00002517 sleep(HZ/5);
Michael Sevakisffa86262013-07-12 12:03:20 -04002518
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002519 demand_irq_enable(false);
Linus Nielsen Feltzing2bf4a052003-04-01 20:58:31 +00002520
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002521 is_recording = false;
2522 is_prerecording = false;
Jens Arnold9352ac82005-09-04 21:55:15 +00002523
2524 last_rec_bytes = num_rec_bytes;
2525 mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count_end, 1);
Jens Arnoldba966c12005-09-15 05:29:26 +00002526 last_rec_time = current_tick - record_start_time;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002527
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +00002528 /* Start monitoring */
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002529 shadow_io_control_main |= (1 << 10);
2530 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
2531 DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main);
Michael Sevakisffa86262013-07-12 12:03:20 -04002532
Linus Nielsen Feltzingcde27c32002-11-25 20:16:44 +00002533 /* Wait until the DSP has accepted the settings */
2534 do
2535 {
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002536 mas_readmem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &val,1);
Linus Nielsen Feltzingcde27c32002-11-25 20:16:44 +00002537 } while(val & 1);
Linus Nielsen Feltzing52486412004-04-01 14:07:56 +00002538
2539 resume_recording();
Linus Nielsen Feltzing2c0b72f2002-11-25 00:02:54 +00002540}
2541
Michael Sevakis0f5cb942006-11-06 18:07:30 +00002542void audio_set_recording_options(struct audio_recording_options *options)
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002543{
2544 bool is_mpeg1;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002545
Bertrik Sikkenab222c12009-05-21 14:15:24 +00002546 is_mpeg1 = (options->rec_frequency < 3);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002547
2548 rec_version_index = is_mpeg1?3:2;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00002549 rec_frequency_index = options->rec_frequency % 3;
Jens Arnoldff3add92005-05-23 18:56:15 +00002550
Michael Sevakis0f5cb942006-11-06 18:07:30 +00002551 shadow_encoder_control = (options->rec_quality << 17) |
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002552 (rec_frequency_index << 10) |
2553 ((is_mpeg1?1:0) << 9) |
Michael Sevakis0f5cb942006-11-06 18:07:30 +00002554 (((options->rec_channels * 2 + 1) & 3) << 6) |
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002555 (1 << 5) /* MS-stereo */ |
2556 (1 << 2) /* Is an original */;
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002557 mas_writemem(MAS_BANK_D0, MAS_D0_ENCODER_CONTROL, &shadow_encoder_control,1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002558
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002559 DEBUGF("mas_writemem(MAS_BANK_D0, ENCODER_CONTROL, %x)\n", shadow_encoder_control);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002560
Björn Stenberg9558c492008-10-14 11:12:20 +00002561#if CONFIG_TUNER & S1A0903X01
2562 /* Store the (unpitched) MAS PLL frequency. Used for avoiding FM
2563 interference with the Samsung tuner. */
2564 if (rec_frequency_index)
2565 mas_store_pllfreq(24576000);
2566 else
2567 mas_store_pllfreq(22579000);
Michael Sevakisffa86262013-07-12 12:03:20 -04002568#endif
Björn Stenberg9558c492008-10-14 11:12:20 +00002569
Michael Sevakis0f5cb942006-11-06 18:07:30 +00002570 shadow_soft_mute = options->rec_editable?4:0;
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002571 mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute,1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002572
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002573 DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002574
Andyf6da6d82005-11-12 14:49:43 +00002575 shadow_io_control_main = ((1 << 10) | /* Monitoring ON */
Michael Sevakis0f5cb942006-11-06 18:07:30 +00002576 ((options->rec_source < 2)?1:2) << 8) | /* Input select */
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002577 (1 << 5) | /* SDO strobe invert */
2578 ((is_mpeg1?0:1) << 3) |
2579 (1 << 2) | /* Inverted SIBC clock signal */
2580 1; /* Validate */
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002581 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main,1);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002582
Jens Arnoldeaa1f732004-09-29 19:51:41 +00002583 DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002584
Michael Sevakis0f5cb942006-11-06 18:07:30 +00002585 if(options->rec_source == AUDIO_SRC_MIC)
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002586 {
2587 /* Copy left channel to right (mono mode) */
2588 mas_codec_writereg(8, 0x8000);
2589 }
2590 else
2591 {
2592 /* Stereo input mode */
2593 mas_codec_writereg(8, 0);
2594 }
2595
Michael Sevakis0f5cb942006-11-06 18:07:30 +00002596 prerecording_max_seconds = options->rec_prerecord_time;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002597 if(prerecording_max_seconds)
2598 {
2599 prerecording = true;
2600 start_prerecording();
2601 }
2602 else
2603 {
2604 prerecording = false;
2605 is_prerecording = false;
2606 is_recording = false;
2607 }
2608}
2609
2610/* If use_mic is true, the left gain is used */
Andye6e54962005-11-12 04:00:56 +00002611void audio_set_recording_gain(int left, int right, int type)
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002612{
2613 /* Enable both left and right A/D */
Jörg Hohensohn3bf321f2004-12-21 23:49:43 +00002614 shadow_codec_reg0 = (left << 12) |
2615 (right << 8) |
2616 (left << 4) |
Andye6e54962005-11-12 04:00:56 +00002617 (type==AUDIO_GAIN_MIC?0x0008:0) | /* Connect left A/D to mic */
Jörg Hohensohn3bf321f2004-12-21 23:49:43 +00002618 0x0007;
2619 mas_codec_writereg(0x0, shadow_codec_reg0);
2620}
2621
2622/* try to make some kind of beep, also in recording mode */
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002623void audio_beep(int duration)
Jörg Hohensohn3bf321f2004-12-21 23:49:43 +00002624{
Jörg Hohensohn3bf321f2004-12-21 23:49:43 +00002625 long starttick = current_tick;
2626 do
Jörg Hohensohndfa95c32004-12-24 08:42:45 +00002627 { /* toggle bit 0 of codec register 0, toggling the DAC off & on.
2628 * While this is still audible even without an external signal,
2629 * it doesn't affect the (pre-)recording. */
2630 mas_codec_writereg(0, shadow_codec_reg0 ^ 1);
2631 mas_codec_writereg(0, shadow_codec_reg0);
Jens Arnoldfbaf5032005-09-05 23:36:29 +00002632 yield();
Jörg Hohensohn3bf321f2004-12-21 23:49:43 +00002633 }
2634 while (current_tick - starttick < duration);
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002635}
2636
Andye6e54962005-11-12 04:00:56 +00002637void audio_new_file(const char *filename)
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00002638{
2639 mpeg_errno = 0;
Jens Arnolde1a19262005-01-09 00:58:59 +00002640
Nils Wallménius3d4701a2009-07-14 13:57:45 +00002641 strlcpy(recording_filename, filename, MAX_PATH);
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00002642
Michael Sevakis4b902672006-12-19 16:50:07 +00002643 queue_post(&mpeg_queue, MPEG_NEW_FILE, 0);
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +00002644}
2645
Andye6e54962005-11-12 04:00:56 +00002646unsigned long audio_recorded_time(void)
Linus Nielsen Feltzingd7033892002-11-19 21:07:44 +00002647{
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002648 if(is_prerecording)
2649 return prerecord_count * HZ;
Michael Sevakisffa86262013-07-12 12:03:20 -04002650
Linus Nielsen Feltzingd7033892002-11-19 21:07:44 +00002651 if(is_recording)
Linus Nielsen Feltzingf487ebe2004-06-03 12:10:40 +00002652 {
2653 if(paused)
2654 return pause_start_time - record_start_time;
2655 else
2656 return current_tick - record_start_time;
2657 }
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002658
2659 return 0;
Linus Nielsen Feltzingd7033892002-11-19 21:07:44 +00002660}
Linus Nielsen Feltzing77d9c7c2002-11-20 22:23:20 +00002661
Andye6e54962005-11-12 04:00:56 +00002662unsigned long audio_num_recorded_bytes(void)
Linus Nielsen Feltzing77d9c7c2002-11-20 22:23:20 +00002663{
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002664 int num_bytes;
2665 int index;
Michael Sevakisffa86262013-07-12 12:03:20 -04002666
Linus Nielsen Feltzing77d9c7c2002-11-20 22:23:20 +00002667 if(is_recording)
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002668 {
2669 if(is_prerecording)
2670 {
2671 index = prerecord_index - prerecord_count;
2672 if(index < 0)
2673 index += prerecording_max_seconds;
Michael Sevakisffa86262013-07-12 12:03:20 -04002674
Jens Arnold9352ac82005-09-04 21:55:15 +00002675 num_bytes = audiobuf_write - prerecord_buffer[index].mempos;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002676 if(num_bytes < 0)
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +00002677 num_bytes += audiobuflen;
Michael Sevakisffa86262013-07-12 12:03:20 -04002678
Bertrik Sikken4f87abf2009-03-04 18:15:06 +00002679 return num_bytes;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002680 }
2681 else
2682 return num_rec_bytes;
2683 }
Linus Nielsen Feltzing77d9c7c2002-11-20 22:23:20 +00002684 else
2685 return 0;
2686}
Linus Nielsen Feltzing2bf4a052003-04-01 20:58:31 +00002687
Jens Arnold8051a0b2005-11-06 23:12:11 +00002688#else /* SIMULATOR */
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002689
Jens Arnold8051a0b2005-11-06 23:12:11 +00002690/* dummies coming up */
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002691
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002692void audio_init_playback(void)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002693{
2694 /* a dummy */
2695}
Andye6e54962005-11-12 04:00:56 +00002696unsigned long audio_recorded_time(void)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002697{
2698 /* a dummy */
Daniel Stenberge81fb192005-02-03 10:07:11 +00002699 return 0;
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002700}
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002701void audio_beep(int duration)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002702{
2703 /* a dummy */
Daniel Stenberge81fb192005-02-03 10:07:11 +00002704 (void)duration;
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002705}
Andye6e54962005-11-12 04:00:56 +00002706void audio_pause_recording(void)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002707{
2708 /* a dummy */
2709}
Andye6e54962005-11-12 04:00:56 +00002710void audio_resume_recording(void)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002711{
2712 /* a dummy */
2713}
Andye6e54962005-11-12 04:00:56 +00002714unsigned long audio_num_recorded_bytes(void)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002715{
2716 /* a dummy */
Daniel Stenberge81fb192005-02-03 10:07:11 +00002717 return 0;
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002718}
Andye6e54962005-11-12 04:00:56 +00002719void audio_record(const char *filename)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002720{
2721 /* a dummy */
Daniel Stenberge81fb192005-02-03 10:07:11 +00002722 (void)filename;
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002723}
Andye6e54962005-11-12 04:00:56 +00002724void audio_new_file(const char *filename)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002725{
2726 /* a dummy */
Daniel Stenberge81fb192005-02-03 10:07:11 +00002727 (void)filename;
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002728}
2729
Andye6e54962005-11-12 04:00:56 +00002730void audio_set_recording_gain(int left, int right, int type)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002731{
2732 /* a dummy */
Daniel Stenberge81fb192005-02-03 10:07:11 +00002733 (void)left;
2734 (void)right;
Andye6e54962005-11-12 04:00:56 +00002735 (void)type;
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002736}
Thomas Martitz8a701e52011-08-14 15:37:05 +00002737void audio_init_recording(void)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002738{
2739 /* a dummy */
2740}
Michael Sevakis4aa01ed2006-11-06 18:36:10 +00002741void audio_set_recording_options(struct audio_recording_options *options)
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002742{
2743 /* a dummy */
Michael Sevakis4aa01ed2006-11-06 18:36:10 +00002744 (void)options;
Daniel Stenberg301f53f2005-02-02 22:04:15 +00002745}
Jens Arnold8051a0b2005-11-06 23:12:11 +00002746#endif /* SIMULATOR */
2747#endif /* CONFIG_CODEC == MAS3587F */
Linus Nielsen Feltzing893095d2002-11-10 16:37:26 +00002748
Thomas Martitz2a8eacd2011-11-17 17:55:02 +00002749size_t audio_buffer_size(void)
Thomas Martitzd0b72e22011-08-30 14:01:33 +00002750{
2751 if (audiobuf_handle > 0)
2752 return audiobuflen;
Thomas Martitz2a8eacd2011-11-17 17:55:02 +00002753 return 0;
2754}
2755
2756size_t audio_buffer_available(void)
2757{
2758 size_t size = 0;
2759 size_t core_size = core_available();
2760 if (audiobuf_handle > 0)
2761 return audiobuflen - AUDIO_BUFFER_RESERVE - 128;
2762 return MAX(core_size, size);
Thomas Martitzd0b72e22011-08-30 14:01:33 +00002763}
2764
Thomas Martitzbaa070c2011-08-30 14:01:45 +00002765static void audio_reset_buffer_noalloc(void* buf, size_t bufsize)
Thomas Martitzd1322b72011-08-14 15:13:00 +00002766{
Thomas Martitzbaa070c2011-08-30 14:01:45 +00002767 mpeg_audiobuf = buf;
2768 audiobuflen = bufsize;
2769 if (global_settings.cuesheet)
2770 { /* enable cuesheet support */
2771 curr_cuesheet = (struct cuesheet*)mpeg_audiobuf;
2772 mpeg_audiobuf = SKIPBYTES(mpeg_audiobuf, sizeof(struct cuesheet));
2773 audiobuflen -= sizeof(struct cuesheet);
2774 }
Thomas Martitzbaa070c2011-08-30 14:01:45 +00002775}
2776
2777static void audio_reset_buffer(void)
2778{
2779 size_t bufsize = audiobuflen;
Thomas Martitzd1322b72011-08-14 15:13:00 +00002780
Thomas Martitz22e802e2013-05-30 11:24:16 +02002781 /* alloc buffer if it's was never allocated or freed by audio_hard_stop()
2782 * because voice cannot be played during audio playback make
2783 * talk.c give up all buffers and disable itself */
Thomas Martitzd0b72e22011-08-30 14:01:33 +00002784 if (!audiobuf_handle)
Thomas Martitz22e802e2013-05-30 11:24:16 +02002785 {
2786 talk_buffer_set_policy(TALK_BUFFER_LOOSE);
Thomas Martitzd0b72e22011-08-30 14:01:33 +00002787 audiobuf_handle = core_alloc_maximum("audiobuf", &bufsize, &ops);
Thomas Martitz22e802e2013-05-30 11:24:16 +02002788 }
Thomas Martitzbaa070c2011-08-30 14:01:45 +00002789
2790 audio_reset_buffer_noalloc(core_get_data(audiobuf_handle), bufsize);
Thomas Martitzd1322b72011-08-14 15:13:00 +00002791}
2792
Michael Sevakis31b71222013-07-14 07:59:39 -04002793void audio_play(unsigned long elapsed, unsigned long offset)
Björn Stenberg3c260772002-05-24 15:27:55 +00002794{
Thomas Martitzd1322b72011-08-14 15:13:00 +00002795 audio_reset_buffer();
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +00002796#ifdef SIMULATOR
Jens Arnold5bea40f2010-08-22 20:58:32 +00002797 char name_buf[MAX_PATH+1];
Steve Bavin9697b372010-05-07 16:41:14 +00002798 const char* trackname;
Daniel Stenberg22633d62002-08-22 07:58:18 +00002799 int steps=0;
2800
Linus Nielsen Feltzing030b6bf2002-08-28 11:03:43 +00002801 is_playing = true;
Michael Sevakisffa86262013-07-12 12:03:20 -04002802
Daniel Stenberg22633d62002-08-22 07:58:18 +00002803 do {
Jens Arnold5bea40f2010-08-22 20:58:32 +00002804 trackname = playlist_peek(steps, name_buf, sizeof(name_buf));
Daniel Stenberg57392ac2002-08-23 07:56:36 +00002805 if (!trackname)
Daniel Stenberg22633d62002-08-22 07:58:18 +00002806 break;
Thom Johansen294ec1d2007-09-19 10:40:55 +00002807 if(mp3info(&taginfo, trackname)) {
Daniel Stenberg57392ac2002-08-23 07:56:36 +00002808 /* bad mp3, move on */
Daniel Stenberg3aab18a2002-10-15 13:07:32 +00002809 if(++steps > playlist_amount())
2810 break;
Daniel Stenberg57392ac2002-08-23 07:56:36 +00002811 continue;
Daniel Stenberg22633d62002-08-22 07:58:18 +00002812 }
Linus Nielsen Feltzing4242a342004-07-08 10:12:39 +00002813#ifdef HAVE_MPEG_PLAY
Jens Arnold1d38aa12005-08-19 06:43:50 +00002814 real_mpeg_play(trackname);
Linus Nielsen Feltzing4242a342004-07-08 10:12:39 +00002815#endif
Linus Nielsen Feltzing97bead32002-08-28 10:54:01 +00002816 playlist_next(steps);
Michael Sevakis31b71222013-07-14 07:59:39 -04002817 if (!offset && elapsed)
2818 {
2819 /* has an elapsed time but no offset; elapsed may take
2820 precedence in this case */
2821 taginfo.elapsed = elapsed;
2822 taginfo.offset = audio_get_file_pos_int(&taginfo);
2823 }
2824 else
2825 {
2826 taginfo.offset = offset;
2827 set_elapsed(&taginfo);
2828 }
Linus Nielsen Feltzing97bead32002-08-28 10:54:01 +00002829 is_playing = true;
Daniel Stenberg57392ac2002-08-23 07:56:36 +00002830 playing = true;
2831 break;
Daniel Stenberg22633d62002-08-22 07:58:18 +00002832 } while(1);
Jens Arnold1d38aa12005-08-19 06:43:50 +00002833#else /* !SIMULATOR */
Michael Sevakis31b71222013-07-14 07:59:39 -04002834 static struct audio_resume_info resume;
Linus Nielsen Feltzing030b6bf2002-08-28 11:03:43 +00002835 is_playing = true;
Michael Sevakis31b71222013-07-14 07:59:39 -04002836 resume.elapsed = elapsed;
2837 resume.offset = offset;
2838 queue_post(&mpeg_queue, MPEG_PLAY, (intptr_t)&resume);
Jens Arnold1d38aa12005-08-19 06:43:50 +00002839#endif /* !SIMULATOR */
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +00002840
2841 mpeg_errno = 0;
Björn Stenberg3c260772002-05-24 15:27:55 +00002842}
2843
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002844void audio_stop(void)
Björn Stenberg3c260772002-05-24 15:27:55 +00002845{
Thomas Martitz22e802e2013-05-30 11:24:16 +02002846 if (audiobuf_handle <= 0)
2847 return; /* nothing to do, must be hard-stopped already */
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +00002848#ifndef SIMULATOR
Linus Nielsen Feltzingbf0ac612003-02-13 16:25:36 +00002849 mpeg_stop_done = false;
Michael Sevakis4b902672006-12-19 16:50:07 +00002850 queue_post(&mpeg_queue, MPEG_STOP, 0);
Linus Nielsen Feltzingbf0ac612003-02-13 16:25:36 +00002851 while(!mpeg_stop_done)
2852 yield();
Jens Arnold1d38aa12005-08-19 06:43:50 +00002853#else /* SIMULATOR */
Linus Nielsen Feltzingbc9f60d2004-01-13 12:40:52 +00002854 paused = false;
Linus Nielsen Feltzing97bead32002-08-28 10:54:01 +00002855 is_playing = false;
Björn Stenberg66b7ade2002-08-08 16:44:20 +00002856 playing = false;
Jens Arnold1d38aa12005-08-19 06:43:50 +00002857#endif /* SIMULATOR */
Björn Stenberg3c260772002-05-24 15:27:55 +00002858}
2859
Andye6e54962005-11-12 04:00:56 +00002860/* dummy */
2861void audio_stop_recording(void)
2862{
Michael Sevakisffa86262013-07-12 12:03:20 -04002863 audio_stop();
Andye6e54962005-11-12 04:00:56 +00002864}
2865
Thomas Martitzd1322b72011-08-14 15:13:00 +00002866void audio_hard_stop(void)
2867{
Thomas Martitzd0b72e22011-08-30 14:01:33 +00002868 if (audiobuf_handle > 0)
2869 {
Thomas Martitz22e802e2013-05-30 11:24:16 +02002870 audio_stop();
Thomas Martitzd0b72e22011-08-30 14:01:33 +00002871 audiobuf_handle = core_free(audiobuf_handle);
2872 mpeg_audiobuf = NULL;
Thomas Martitz22e802e2013-05-30 11:24:16 +02002873 talk_buffer_set_policy(TALK_BUFFER_DEFAULT);
Thomas Martitzd0b72e22011-08-30 14:01:33 +00002874 }
Thomas Martitzd1322b72011-08-14 15:13:00 +00002875}
2876
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002877void audio_pause(void)
Björn Stenberg3c260772002-05-24 15:27:55 +00002878{
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +00002879#ifndef SIMULATOR
Michael Sevakis4b902672006-12-19 16:50:07 +00002880 queue_post(&mpeg_queue, MPEG_PAUSE, 0);
Jens Arnold1d38aa12005-08-19 06:43:50 +00002881#else /* SIMULATOR */
Björn Stenberg924b5312002-08-30 00:32:57 +00002882 is_playing = true;
Björn Stenberg66b7ade2002-08-08 16:44:20 +00002883 playing = false;
Björn Stenberg34486b72002-08-19 11:00:29 +00002884 paused = true;
Jens Arnold1d38aa12005-08-19 06:43:50 +00002885#endif /* SIMULATOR */
Björn Stenberg3c260772002-05-24 15:27:55 +00002886}
2887
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002888void audio_resume(void)
Björn Stenberg3c260772002-05-24 15:27:55 +00002889{
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +00002890#ifndef SIMULATOR
Michael Sevakis4b902672006-12-19 16:50:07 +00002891 queue_post(&mpeg_queue, MPEG_RESUME, 0);
Jens Arnold1d38aa12005-08-19 06:43:50 +00002892#else /* SIMULATOR */
Linus Nielsen Feltzing97bead32002-08-28 10:54:01 +00002893 is_playing = true;
Björn Stenberg66b7ade2002-08-08 16:44:20 +00002894 playing = true;
Björn Stenberg34486b72002-08-19 11:00:29 +00002895 paused = false;
Jens Arnold1d38aa12005-08-19 06:43:50 +00002896#endif /* SIMULATOR */
Björn Stenberg3c260772002-05-24 15:27:55 +00002897}
2898
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002899void audio_next(void)
Björn Stenberga61617f2002-06-26 21:27:17 +00002900{
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +00002901#ifndef SIMULATOR
Linus Nielsen Feltzing4950b552006-10-19 11:43:13 +00002902 queue_remove_from_head(&mpeg_queue, MPEG_NEED_DATA);
Michael Sevakis4b902672006-12-19 16:50:07 +00002903 queue_post(&mpeg_queue, MPEG_NEXT, 0);
Jens Arnold1d38aa12005-08-19 06:43:50 +00002904#else /* SIMULATOR */
Jens Arnold5bea40f2010-08-22 20:58:32 +00002905 char name_buf[MAX_PATH+1];
Steve Bavinb08222c2010-05-07 16:35:37 +00002906 const char* file;
Daniel Stenberg22633d62002-08-22 07:58:18 +00002907 int steps = 1;
2908
2909 do {
Jens Arnold5bea40f2010-08-22 20:58:32 +00002910 file = playlist_peek(steps, name_buf, sizeof(name_buf));
Daniel Stenberg57392ac2002-08-23 07:56:36 +00002911 if(!file)
2912 break;
Thom Johansen294ec1d2007-09-19 10:40:55 +00002913 if(mp3info(&taginfo, file)) {
Daniel Stenberg3aab18a2002-10-15 13:07:32 +00002914 if(++steps > playlist_amount())
2915 break;
Daniel Stenberg22633d62002-08-22 07:58:18 +00002916 continue;
2917 }
Andree Buschmannecb4d2d2011-05-23 19:09:04 +00002918 playlist_next(steps);
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00002919 current_track_counter++;
Linus Nielsen Feltzing97bead32002-08-28 10:54:01 +00002920 is_playing = true;
Daniel Stenberg22633d62002-08-22 07:58:18 +00002921 playing = true;
2922 break;
2923 } while(1);
Jens Arnold1d38aa12005-08-19 06:43:50 +00002924#endif /* SIMULATOR */
Björn Stenberga61617f2002-06-26 21:27:17 +00002925}
2926
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002927void audio_prev(void)
Björn Stenberga61617f2002-06-26 21:27:17 +00002928{
Linus Nielsen Feltzingcb30e542002-06-30 14:36:58 +00002929#ifndef SIMULATOR
Linus Nielsen Feltzing4950b552006-10-19 11:43:13 +00002930 queue_remove_from_head(&mpeg_queue, MPEG_NEED_DATA);
Michael Sevakis4b902672006-12-19 16:50:07 +00002931 queue_post(&mpeg_queue, MPEG_PREV, 0);
Jens Arnold1d38aa12005-08-19 06:43:50 +00002932#else /* SIMULATOR */
Jens Arnold5bea40f2010-08-22 20:58:32 +00002933 char name_buf[MAX_PATH+1];
Steve Bavinb08222c2010-05-07 16:35:37 +00002934 const char* file;
Daniel Stenberg22633d62002-08-22 07:58:18 +00002935 int steps = -1;
2936
2937 do {
Jens Arnold5bea40f2010-08-22 20:58:32 +00002938 file = playlist_peek(steps, name_buf, sizeof(name_buf));
Daniel Stenberg57392ac2002-08-23 07:56:36 +00002939 if(!file)
2940 break;
Thom Johansen294ec1d2007-09-19 10:40:55 +00002941 if(mp3info(&taginfo, file)) {
Daniel Stenberg22633d62002-08-22 07:58:18 +00002942 steps--;
2943 continue;
2944 }
Andree Buschmannecb4d2d2011-05-23 19:09:04 +00002945 playlist_next(steps);
Hardeep Sidhud3d1b982002-12-19 00:58:11 +00002946 current_track_counter++;
Linus Nielsen Feltzing97bead32002-08-28 10:54:01 +00002947 is_playing = true;
Daniel Stenberg22633d62002-08-22 07:58:18 +00002948 playing = true;
2949 break;
2950 } while(1);
Jens Arnold1d38aa12005-08-19 06:43:50 +00002951#endif /* SIMULATOR */
Björn Stenberga61617f2002-06-26 21:27:17 +00002952}
2953
Jeffrey Goodedb82be42009-11-16 20:09:46 +00002954void audio_ff_rewind(long newpos)
Björn Stenberg05704972002-08-14 19:23:34 +00002955{
2956#ifndef SIMULATOR
Jeffrey Goodedb82be42009-11-16 20:09:46 +00002957 queue_post(&mpeg_queue, MPEG_FF_REWIND, newpos);
Jens Arnold1d38aa12005-08-19 06:43:50 +00002958#else /* SIMULATOR */
Jeffrey Goodedb82be42009-11-16 20:09:46 +00002959 (void)newpos;
Jens Arnold1d38aa12005-08-19 06:43:50 +00002960#endif /* SIMULATOR */
Björn Stenberg05704972002-08-14 19:23:34 +00002961}
2962
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002963void audio_flush_and_reload_tracks(void)
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00002964{
2965#ifndef SIMULATOR
Michael Sevakis4b902672006-12-19 16:50:07 +00002966 queue_post(&mpeg_queue, MPEG_FLUSH_RELOAD, 0);
Jens Arnold1d38aa12005-08-19 06:43:50 +00002967#endif /* !SIMULATOR*/
Hardeep Sidhu62bec9e2002-09-10 08:50:40 +00002968}
2969
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002970int audio_status(void)
Linus Nielsen Feltzing958025b2002-07-01 20:11:46 +00002971{
Linus Nielsen Feltzingf0777102002-09-24 07:49:16 +00002972 int ret = 0;
2973
2974 if(is_playing)
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002975 ret |= AUDIO_STATUS_PLAY;
Linus Nielsen Feltzingf0777102002-09-24 07:49:16 +00002976
2977 if(paused)
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002978 ret |= AUDIO_STATUS_PAUSE;
Michael Sevakisffa86262013-07-12 12:03:20 -04002979
Jens Arnold8051a0b2005-11-06 23:12:11 +00002980#if (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR)
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002981 if(is_recording && !is_prerecording)
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002982 ret |= AUDIO_STATUS_RECORD;
Linus Nielsen Feltzing74976c12003-12-31 03:13:29 +00002983
2984 if(is_prerecording)
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002985 ret |= AUDIO_STATUS_PRERECORD;
Jens Arnoldd6c05452005-08-29 21:15:27 +00002986#endif /* CONFIG_CODEC == MAS3587F */
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +00002987
2988 if(mpeg_errno)
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002989 ret |= AUDIO_STATUS_ERROR;
Michael Sevakisffa86262013-07-12 12:03:20 -04002990
Linus Nielsen Feltzingf0777102002-09-24 07:49:16 +00002991 return ret;
Linus Nielsen Feltzing958025b2002-07-01 20:11:46 +00002992}
2993
Jeffrey Goodedb82be42009-11-16 20:09:46 +00002994/* Unused function
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00002995unsigned int audio_error(void)
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +00002996{
2997 return mpeg_errno;
2998}
Jeffrey Goodedb82be42009-11-16 20:09:46 +00002999*/
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +00003000
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00003001void audio_error_clear(void)
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +00003002{
3003 mpeg_errno = 0;
3004}
3005
Kjell Ericsonddefd1e2003-01-10 09:19:10 +00003006#ifdef SIMULATOR
Kjell Ericsonddefd1e2003-01-10 09:19:10 +00003007static void mpeg_thread(void)
3008{
3009 struct mp3entry* id3;
3010 while ( 1 ) {
3011 if (is_playing) {
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00003012 id3 = audio_current_track();
Björn Stenbergb4902af2003-02-11 14:20:54 +00003013 if (!paused)
Hardeep Sidhu166dc172003-12-09 08:15:22 +00003014 {
Björn Stenbergb4902af2003-02-11 14:20:54 +00003015 id3->elapsed+=1000;
Hardeep Sidhu166dc172003-12-09 08:15:22 +00003016 id3->offset+=1000;
3017 }
Kjell Ericsonddefd1e2003-01-10 09:19:10 +00003018 if (id3->elapsed>=id3->length)
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00003019 audio_next();
Kjell Ericsonddefd1e2003-01-10 09:19:10 +00003020 }
Björn Stenbergb4902af2003-02-11 14:20:54 +00003021 sleep(HZ);
Kjell Ericsonddefd1e2003-01-10 09:19:10 +00003022 }
3023}
Jens Arnold1d38aa12005-08-19 06:43:50 +00003024#endif /* SIMULATOR */
Kjell Ericsonddefd1e2003-01-10 09:19:10 +00003025
Linus Nielsen Feltzing8a237a82005-04-04 12:06:29 +00003026void audio_init(void)
Björn Stenberg1ac46002002-05-24 12:22:14 +00003027{
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +00003028 mpeg_errno = 0;
Linus Nielsen Feltzingc833a812002-11-24 00:23:49 +00003029
Thomas Martitzd0b72e22011-08-30 14:01:33 +00003030 audio_reset_buffer();
3031
Jörg Hohensohn881b53f2004-01-05 22:46:54 +00003032#ifndef SIMULATOR
Miika Pekkarinena85044b2006-09-16 16:18:11 +00003033 queue_init(&mpeg_queue, true);
Jens Arnold1d38aa12005-08-19 06:43:50 +00003034#endif /* !SIMULATOR */
Thomas Martitzbaa070c2011-08-30 14:01:45 +00003035 audio_thread_id = create_thread(mpeg_thread, mpeg_stack,
3036 sizeof(mpeg_stack), 0, mpeg_thread_name
3037 IF_PRIO(, PRIORITY_SYSTEM)
3038 IF_COP(, CPU));
Linus Nielsen Feltzing0dcd47e2002-11-19 09:50:19 +00003039
Tom Rossc6457522009-03-02 01:40:41 +00003040 memset(trackdata, 0, sizeof(trackdata));
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +00003041
Jens Arnold8051a0b2005-11-06 23:12:11 +00003042#if (CONFIG_CODEC == MAS3587F) && !defined(SIMULATOR)
Jens Arnold8636e692007-04-11 23:51:00 +00003043 if (HW_MASK & PR_ACTIVE_HIGH)
Jens Arnold2cae1da2004-05-04 06:29:41 +00003044 and_b(~0x08, &PADRH);
Linus Nielsen Feltzing0dcd47e2002-11-19 09:50:19 +00003045 else
Jens Arnold2cae1da2004-05-04 06:29:41 +00003046 or_b(0x08, &PADRH);
Jens Arnoldd6c05452005-08-29 21:15:27 +00003047#endif /* CONFIG_CODEC == MAS3587F */
Jens Arnold2cae1da2004-05-04 06:29:41 +00003048
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +00003049#ifdef DEBUG
Björn Stenberge76c69f2008-10-10 13:12:28 +00003050#ifndef SIMULATOR
Linus Nielsen Feltzing03c13a12002-10-08 07:43:52 +00003051 dbg_timer_start();
Linus Nielsen Feltzing6f62bc22002-10-08 12:18:12 +00003052 dbg_cnt2us(0);
Björn Stenberge76c69f2008-10-10 13:12:28 +00003053#endif /* !SIMULATOR */
Jörg Hohensohn881b53f2004-01-05 22:46:54 +00003054#endif /* DEBUG */
Jens Arnold0aa12a92011-10-09 16:19:51 +00003055 audio_is_initialized = true;
Björn Stenberg1ac46002002-05-24 12:22:14 +00003056}
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00003057
Jens Arnoldd6c05452005-08-29 21:15:27 +00003058#endif /* CONFIG_CODEC != SWCODEC */