From 8cb555460ff79e636a7907fb2589e16db98c8600 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Fri, 17 Jul 2020 00:01:32 -0400 Subject: [3/4] Completely remove HWCODEC support 'swcodec' is now always set (and recording_swcodec for recording-capable units) in feature.txt so the manual and language strings don't need to all be fixed up. Change-Id: Ib2c9d5d157af8d33653e2d4b4a12881b9aa6ddb0 --- apps/mpeg.c | 1979 ----------------------------------------------------------- 1 file changed, 1979 deletions(-) delete mode 100644 apps/mpeg.c (limited to 'apps/mpeg.c') diff --git a/apps/mpeg.c b/apps/mpeg.c deleted file mode 100644 index e04c227cb1..0000000000 --- a/apps/mpeg.c +++ /dev/null @@ -1,1979 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Linus Nielsen Feltzing - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include -#include -#include "config.h" - -#if CONFIG_CODEC != SWCODEC - -#include "debug.h" -#include "panic.h" -#include "metadata.h" -#include "mpeg.h" -#include "audio.h" -#include "storage.h" -#include "string.h" -#include -#include "thread.h" -#include "errno.h" -#include "mp3data.h" -#include "core_alloc.h" -#include "mp3_playback.h" -#include "talk.h" -#include "sound.h" -#include "system.h" -#include "appevents.h" -#include "playlist.h" -#include "cuesheet.h" -#include "settings.h" -#ifndef SIMULATOR -#include "i2c.h" -#include "system.h" -#include "usb.h" -#include "file.h" -#include "hwcompat.h" -#endif /* !SIMULATOR */ -#ifdef HAVE_LCD_BITMAP -#include "lcd.h" -#endif /* CONFIG_CODEC != SWCODEC */ - -#define MPEG_SWAP_CHUNKSIZE 0x2000 -#define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we - wouldn't be able to see the difference between - an empty buffer and a full one. */ -#define MPEG_LOW_WATER 0x60000 -#define MPEG_RECORDING_LOW_WATER 0x80000 -#define MPEG_LOW_WATER_CHUNKSIZE 0x40000 -#define MPEG_LOW_WATER_SWAP_CHUNKSIZE 0x10000 -#if (CONFIG_STORAGE & STORAGE_MMC) -#define MPEG_PLAY_PENDING_THRESHOLD 0x20000 -#define MPEG_PLAY_PENDING_SWAPSIZE 0x20000 -#else -#define MPEG_PLAY_PENDING_THRESHOLD 0x10000 -#define MPEG_PLAY_PENDING_SWAPSIZE 0x10000 -#endif - -#define MPEG_MAX_PRERECORD_SECONDS 30 - -/* For ID3 info and VBR header */ -#define MPEG_RESERVED_HEADER_SPACE (4096 + 576) - -#ifndef SIMULATOR -extern unsigned long mas_version_code; -#endif - -#define MPEG_PLAY 1 -#define MPEG_STOP 2 -#define MPEG_PAUSE 3 -#define MPEG_RESUME 4 -#define MPEG_NEXT 5 -#define MPEG_PREV 6 -#define MPEG_FF_REWIND 7 -#define MPEG_FLUSH_RELOAD 8 -#define MPEG_RECORD 9 -#define MPEG_INIT_RECORDING 10 -#define MPEG_INIT_PLAYBACK 11 -#define MPEG_NEW_FILE 12 -#define MPEG_PAUSE_RECORDING 13 -#define MPEG_RESUME_RECORDING 14 -#define MPEG_NEED_DATA 100 -#define MPEG_TRACK_CHANGE 101 -#define MPEG_SAVE_DATA 102 -#define MPEG_STOP_DONE 103 -#define MPEG_PRERECORDING_TICK 104 - -/* indicator for MPEG_NEED_DATA */ -#define GENERATE_UNBUFFER_EVENTS 1 - -/* list of tracks in memory */ -#define MAX_TRACK_ENTRIES (1<<4) /* Must be power of 2 */ -#define MAX_TRACK_ENTRIES_MASK (MAX_TRACK_ENTRIES - 1) - -struct trackdata -{ - struct mp3entry id3; - int mempos; - int load_ahead_index; -}; - -static struct trackdata trackdata[MAX_TRACK_ENTRIES]; - -static unsigned int current_track_counter = 0; - -#ifndef SIMULATOR -static void stop_playing(void); - -static int track_read_idx = 0; -static int track_write_idx = 0; -#endif /* !SIMULATOR */ - -/* Cuesheet support */ -static struct cuesheet *curr_cuesheet = NULL; -static bool checked_for_cuesheet = false; - -static const char mpeg_thread_name[] = "mpeg"; -static unsigned int audio_thread_id; -static bool audio_is_initialized; -static unsigned int mpeg_errno; - -static bool playing = false; /* We are playing an MP3 stream */ -static bool is_playing = false; /* We are (attempting to) playing MP3 files */ -static bool paused; /* playback is paused */ -static int audiobuf_handle; /* handle to the audio buffer */ -static char* mpeg_audiobuf; /* poiunter to the audio buffer */ -static long audiobuflen; /* length of the audio buffer */ -#define AUDIO_BUFFER_RESERVE (256*1024) -#ifdef SIMULATOR -static char mpeg_stack[DEFAULT_STACK_SIZE]; -static struct mp3entry taginfo; -#else /* !SIMULATOR */ -static struct event_queue mpeg_queue SHAREDBSS_ATTR; -static long mpeg_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; - -static int audiobuf_write; -static int audiobuf_swapwrite; -static long audiobuf_read; - -static int mpeg_file; - -static bool play_pending; /* We are about to start playing */ -static bool play_pending_track_change; /* When starting play we're starting a new file */ -static bool filling; /* We are filling the buffer with data from disk */ -static bool dma_underrun; /* True when the DMA has stopped because of - slow disk reading (read error, shaking) */ -static bool mpeg_stop_done; - -static int last_dma_tick = 0; -static int last_dma_chunk_size; - -static long low_watermark; /* Dynamic low watermark level */ -static long low_watermark_margin = 0; /* Extra time in seconds for watermark */ -static long lowest_watermark_level; /* Debug value to observe the buffer - usage */ - -struct audio_resume_info -{ - unsigned long elapsed; - unsigned long offset; -}; - -#ifdef HAVE_RECORDING -static const unsigned char empty_id3_header[] = -{ - 'I', 'D', '3', 0x03, 0x00, 0x00, - 0x00, 0x00, 0x1f, 0x76 /* Size is 4096 minus 10 bytes for the header */ -}; -#endif /* HAVE_RECORDING */ - - -static int get_unplayed_space(void); -static int get_playable_space(void); -static int get_unswapped_space(void); -#endif /* !SIMULATOR */ - -static void audio_reset_buffer_noalloc(void* buf, size_t bufsize); -static void audio_reset_buffer(void); - - -#ifndef SIMULATOR -static int num_tracks_in_memory(void) -{ - return (track_write_idx - track_read_idx) & MAX_TRACK_ENTRIES_MASK; -} - -#ifdef DEBUG_TAGS -static void debug_tags(void) -{ - int i; - - for(i = 0;i < MAX_TRACK_ENTRIES;i++) - { - DEBUGF("%d - %s\n", i, trackdata[i].id3.path); - } - DEBUGF("read: %d, write :%d\n", track_read_idx, track_write_idx); - DEBUGF("num_tracks_in_memory: %d\n", num_tracks_in_memory()); -} -#else /* !DEBUG_TAGS */ -#define debug_tags() -#endif /* !DEBUG_TAGS */ - -static void remove_current_tag(void) -{ - if(num_tracks_in_memory() > 0) - { - /* First move the index, so nobody tries to access the tag */ - track_read_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK; - checked_for_cuesheet = false; - debug_tags(); - } - else - { - DEBUGF("remove_current_tag: no tracks to remove\n"); - } -} - -static void remove_all_non_current_tags(void) -{ - track_write_idx = (track_read_idx+1) & MAX_TRACK_ENTRIES_MASK; - debug_tags(); -} - -static void remove_all_tags(void) -{ - track_write_idx = track_read_idx; - - debug_tags(); -} - -static struct trackdata *get_trackdata(int offset) -{ - if(offset >= num_tracks_in_memory()) - return NULL; - else - return &trackdata[(track_read_idx + offset) & MAX_TRACK_ENTRIES_MASK]; -} -#endif /* !SIMULATOR */ - -/***********************************************************************/ -/* audio event handling */ - -#define MAX_EVENT_HANDLERS 10 -struct event_handlers_table -{ - AUDIO_EVENT_HANDLER handler; - unsigned short mask; -}; -static struct event_handlers_table event_handlers[MAX_EVENT_HANDLERS]; -static int event_handlers_count = 0; - -void audio_register_event_handler(AUDIO_EVENT_HANDLER handler, unsigned short mask) -{ - if (event_handlers_count < MAX_EVENT_HANDLERS) - { - event_handlers[event_handlers_count].handler = handler; - event_handlers[event_handlers_count].mask = mask; - event_handlers_count++; - } -} - -/* dispatch calls each handler in the order registered and returns after some - handler actually handles the event (the event is assumed to no longer be valid - after this, due to the handler changing some condition); returns true if someone - handled the event, which is expected to cause the caller to skip its own handling - of the event */ -#ifndef SIMULATOR -static bool audio_dispatch_event(unsigned short event, unsigned long data) -{ - int i = 0; - for(i=0; i < event_handlers_count; i++) - { - if ( event_handlers[i].mask & event ) - { - int rc = event_handlers[i].handler(event, data); - if ( rc == AUDIO_EVENT_RC_HANDLED ) - return true; - } - } - return false; -} - -static void send_track_event(unsigned int id, struct mp3entry *id3) -{ - struct mp3entry *cur_id3 = - &trackdata[track_read_idx & MAX_TRACK_ENTRIES_MASK].id3; - unsigned int flags = id3 == cur_id3 ? TEF_CURRENT : 0; - send_event(id, &(struct track_event){ .flags = flags, .id3 = id3 }); -} -#endif /* SIMULATOR */ - -/***********************************************************************/ - -static void set_elapsed(struct mp3entry* id3) -{ - if ( id3->vbr ) { - if ( id3->has_toc ) { - /* calculate elapsed time using TOC */ - int i; - unsigned int remainder, plen, relpos, nextpos; - - /* find wich percent we're at */ - for (i=0; i<100; i++ ) - { - if ( id3->offset < id3->toc[i] * (id3->filesize / 256) ) - { - break; - } - } - - i--; - if (i < 0) - i = 0; - - relpos = id3->toc[i]; - - if (i < 99) - { - nextpos = id3->toc[i+1]; - } - else - { - nextpos = 256; - } - - remainder = id3->offset - (relpos * (id3->filesize / 256)); - - /* set time for this percent (divide before multiply to prevent - overflow on long files. loss of precision is negligible on - short files) */ - id3->elapsed = i * (id3->length / 100); - - /* calculate remainder time */ - plen = (nextpos - relpos) * (id3->filesize / 256); - id3->elapsed += (((remainder * 100) / plen) * - (id3->length / 10000)); - } - else { - /* no TOC exists. set a rough estimate using average bitrate */ - int tpk = id3->length / (id3->filesize / 1024); - id3->elapsed = id3->offset / 1024 * tpk; - } - } - else - /* constant bitrate, use exact calculation */ - id3->elapsed = id3->offset / (id3->bitrate / 8); -} - -static int audio_get_file_pos_int(struct mp3entry *id3) -{ - int pos = -1; - - if (id3->vbr) - { - if (id3->has_toc) - { - /* Use the TOC to find the new position */ - unsigned int percent, remainder; - int curtoc, nexttoc, plen; - - percent = (id3->elapsed*100)/id3->length; - if (percent > 99) - percent = 99; - - curtoc = id3->toc[percent]; - - if (percent < 99) - nexttoc = id3->toc[percent+1]; - else - nexttoc = 256; - - pos = (id3->filesize/256)*curtoc; - - /* Use the remainder to get a more accurate position */ - remainder = (id3->elapsed*100)%id3->length; - remainder = (remainder*100)/id3->length; - plen = (nexttoc - curtoc)*(id3->filesize/256); - pos += (plen/100)*remainder; - } - else - { - /* No TOC exists, estimate the new position */ - pos = (id3->filesize / (id3->length / 1000)) * - (id3->elapsed / 1000); - } - } - else if (id3->bitrate) - pos = id3->elapsed * (id3->bitrate / 8); - else - { - return -1; - } - - if (pos >= (int)(id3->filesize - id3->id3v1len)) - { - /* Don't seek right to the end of the file so that we can - transition properly to the next song */ - pos = id3->filesize - id3->id3v1len - 1; - } - else if (pos < (int)id3->first_frame_offset) - { - /* skip past id3v2 tag and other leading garbage */ - pos = id3->first_frame_offset; - } - return pos; -} - -int audio_get_file_pos(void) -{ - struct mp3entry *id3 = audio_current_track(); - return id3 ? audio_get_file_pos_int(id3) : 0; -} - -unsigned long mpeg_get_last_header(void) -{ -#ifdef SIMULATOR - return 0; -#else /* !SIMULATOR */ - unsigned long tmp[2]; - - /* Read the frame data from the MAS and reconstruct it with the - frame sync and all */ - mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_STATUS_1, tmp, 2); - return 0xffe00000 | ((tmp[0] & 0x7c00) << 6) | (tmp[1] & 0xffff); -#endif /* !SIMULATOR */ -} - -static void do_stop(void) -{ - is_playing = false; - paused = false; - -#ifndef SIMULATOR - if (playing) - playlist_update_resume_info(audio_current_track()); - - stop_playing(); - mpeg_stop_done = true; -#else - playing = false; -#endif -} - -/* Buffer must not move. */ -static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size) -{ - ssize_t extradata_size = old_size - audiobuflen; - /* check what buflib requests */ - size_t wanted_size = (hints & BUFLIB_SHRINK_SIZE_MASK); - ssize_t size = (ssize_t)old_size - wanted_size; - - /* keep at least 256K for the buffering */ - if ((size - extradata_size) < AUDIO_BUFFER_RESERVE) - { - /* check if buflib needs the memory really hard. if yes we give - * up playback for now, otherwise refuse to shrink to keep at least - * 256K for the buffering */ - if ((hints & BUFLIB_SHRINK_POS_MASK) != BUFLIB_SHRINK_POS_MASK) - return BUFLIB_CB_CANNOT_SHRINK; - } - /* TODO: Do it without stopping playback, if possible */ - bool playing = (audio_status() & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY; - struct mp3entry *id3 = audio_current_track(); - unsigned long elapsed = 0, offset = 0; - if (id3) - { - elapsed = id3->elapsed; - offset = id3->offset; - } - /* don't call audio_hard_stop() as it frees this handle */ - if (thread_self() == audio_thread_id) - { /* inline case MPEG_STOP (audio_stop()) response - * if we're in the audio thread since audio_stop() otherwise deadlocks */ - do_stop(); - } - else - audio_stop(); - - switch (hints & BUFLIB_SHRINK_POS_MASK) - { - case BUFLIB_SHRINK_POS_BACK: - core_shrink(handle, start, size); - audio_reset_buffer_noalloc(start, size); - break; - case BUFLIB_SHRINK_POS_FRONT: - core_shrink(handle, start + wanted_size, size); - audio_reset_buffer_noalloc(start + wanted_size, size); - break; - case BUFLIB_SHRINK_POS_MASK: - audiobuf_handle = core_free(audiobuf_handle); - mpeg_audiobuf = NULL; - talk_buffer_set_policy(TALK_BUFFER_DEFAULT); - playing = false; - break; - } - if (playing) - { /* safe to call even from the audio thread (due to queue_post()) */ - audio_play(elapsed, offset); - } - - return BUFLIB_CB_OK; -} - -static struct buflib_callbacks ops = { - .move_callback = NULL, - .shrink_callback = shrink_callback, -}; - -#ifndef SIMULATOR -/* Send callback events to notify about removing old tracks. */ -static void generate_unbuffer_events(void) -{ - int i; - int numentries = MAX_TRACK_ENTRIES - num_tracks_in_memory(); - int cur_idx = track_write_idx; - - for (i = 0; i < numentries; i++) - { - /* Send an event to notify that track has finished. */ - send_track_event(PLAYBACK_EVENT_TRACK_FINISH, &trackdata[cur_idx].id3); - cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; - } -} - -/* Send callback events to notify about new tracks. */ -static void generate_postbuffer_events(void) -{ - int i; - int numentries = num_tracks_in_memory(); - int cur_idx = track_read_idx; - - for (i = 0; i < numentries; i++) - { - send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, &trackdata[cur_idx].id3); - cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; - } -} - -static void recalculate_watermark(int bitrate) -{ - int bytes_per_sec; - int time = storage_spinup_time(); - - /* A bitrate of 0 probably means empty VBR header. We play safe - and set a high threshold */ - if(bitrate == 0) - bitrate = 320; - - bytes_per_sec = bitrate * 1000 / 8; - - if(time) - { - /* No drive spins up faster than 3.5s */ - if(time < 350) - time = 350; - - time = time * 3; - low_watermark = ((low_watermark_margin * HZ + time) * - bytes_per_sec) / HZ; - } - else - { - low_watermark = MPEG_LOW_WATER; - } -} - -#ifdef HAVE_DISK_STORAGE -void audio_set_buffer_margin(int setting) -{ - low_watermark_margin = setting; /* in seconds */ -} -#endif - -void audio_get_debugdata(struct audio_debug *dbgdata) -{ - dbgdata->audiobuflen = audiobuflen; - dbgdata->audiobuf_write = audiobuf_write; - dbgdata->audiobuf_swapwrite = audiobuf_swapwrite; - dbgdata->audiobuf_read = audiobuf_read; - - dbgdata->last_dma_chunk_size = last_dma_chunk_size; - - dbgdata->playing = playing; - dbgdata->play_pending = play_pending; - dbgdata->is_playing = is_playing; - dbgdata->filling = filling; - dbgdata->dma_underrun = dma_underrun; - - dbgdata->unplayed_space = get_unplayed_space(); - dbgdata->playable_space = get_playable_space(); - dbgdata->unswapped_space = get_unswapped_space(); - - dbgdata->low_watermark_level = low_watermark; - dbgdata->lowest_watermark_level = lowest_watermark_level; -} - -#ifdef DEBUG -static void dbg_timer_start(void) -{ - /* We are using timer 2 */ - - TSTR &= ~0x04; /* Stop the timer */ - TSNC &= ~0x04; /* No synchronization */ - TMDR &= ~0x44; /* Operate normally */ - - TCNT2 = 0; /* Start counting at 0 */ - TCR2 = 0x03; /* Sysclock/8 */ - - TSTR |= 0x04; /* Start timer 2 */ -} - -static int dbg_cnt2us(unsigned int cnt) -{ - return (cnt * 10000) / (FREQ/800); -} -#endif /* DEBUG */ - -static int get_unplayed_space(void) -{ - int space = audiobuf_write - audiobuf_read; - if (space < 0) - space += audiobuflen; - return space; -} - -static int get_playable_space(void) -{ - int space = audiobuf_swapwrite - audiobuf_read; - if (space < 0) - space += audiobuflen; - return space; -} - -static int get_unplayed_space_current_song(void) -{ - int space; - - if (num_tracks_in_memory() > 1) - { - space = get_trackdata(1)->mempos - audiobuf_read; - } - else - { - space = audiobuf_write - audiobuf_read; - } - - if (space < 0) - space += audiobuflen; - - return space; -} - -static int get_unswapped_space(void) -{ - int space = audiobuf_write - audiobuf_swapwrite; - if (space < 0) - space += audiobuflen; - return space; -} - -void playback_tick(void) -{ - struct trackdata *ptd = get_trackdata(0); - if(ptd) - { - ptd->id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ; - last_dma_tick = current_tick; - audio_dispatch_event(AUDIO_EVENT_POS_REPORT, - (unsigned long)ptd->id3.elapsed); - } -} - -static void reset_mp3_buffer(void) -{ - audiobuf_read = 0; - audiobuf_write = 0; - audiobuf_swapwrite = 0; - lowest_watermark_level = audiobuflen; -} - - /* DMA transfer end interrupt callback */ -static void transfer_end(const void** ppbuf, size_t* psize) -{ - if(playing && !paused) - { - int unplayed_space_left; - int space_until_end_of_buffer; - int track_offset = 1; - struct trackdata *track; - - audiobuf_read += last_dma_chunk_size; - if(audiobuf_read >= audiobuflen) - audiobuf_read = 0; - - /* First, check if we are on a track boundary */ - if (num_tracks_in_memory() > 1) - { - if (audiobuf_read == get_trackdata(track_offset)->mempos) - { - if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) ) - { - queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); - track_offset++; - } - } - } - - unplayed_space_left = get_unplayed_space(); - - space_until_end_of_buffer = audiobuflen - audiobuf_read; - - if(!filling && unplayed_space_left < low_watermark) - { - filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); - } - - if(unplayed_space_left) - { - last_dma_chunk_size = MIN(0x2000, unplayed_space_left); - last_dma_chunk_size = MIN(last_dma_chunk_size, - space_until_end_of_buffer); - - /* several tracks loaded? */ - track = get_trackdata(track_offset); - if(track) - { - /* will we move across the track boundary? */ - if (( audiobuf_read < track->mempos ) && - ((audiobuf_read+last_dma_chunk_size) > - track->mempos )) - { - /* Make sure that we end exactly on the boundary */ - last_dma_chunk_size = track->mempos - audiobuf_read; - } - } - - *psize = last_dma_chunk_size & 0xffff; - *ppbuf = mpeg_audiobuf + audiobuf_read; - track = get_trackdata(0); - if(track) - track->id3.offset += last_dma_chunk_size; - - /* Update the watermark debug level */ - if(unplayed_space_left < lowest_watermark_level) - lowest_watermark_level = unplayed_space_left; - } - else - { - /* Check if the end of data is because of a hard disk error. - If there is an open file handle, we are still playing music. - If not, the last file has been loaded, and the file handle is - closed. */ - if(mpeg_file >= 0) - { - /* Update the watermark debug level */ - if(unplayed_space_left < lowest_watermark_level) - lowest_watermark_level = unplayed_space_left; - - DEBUGF("DMA underrun.\n"); - dma_underrun = true; - } - else - { - if ( ! audio_dispatch_event(AUDIO_EVENT_END_OF_TRACK, 0) ) - { - DEBUGF("No more MP3 data. Stopping.\n"); - queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); - playing = false; - } - } - *psize = 0; /* no more transfer */ - } - } -} - -static struct trackdata *add_track_to_tag_list(const char *filename) -{ - struct trackdata *track; - bool send_nid3_event; - - if(num_tracks_in_memory() >= MAX_TRACK_ENTRIES) - { - DEBUGF("Tag memory is full\n"); - return NULL; - } - - track = &trackdata[track_write_idx]; - - /* grab id3 tag of new file and - remember where in memory it starts */ - if(mp3info(&track->id3, filename)) - { - DEBUGF("Bad mp3\n"); - return NULL; - } - track->mempos = audiobuf_write; - track->id3.elapsed = 0; -#ifdef HAVE_LCD_BITMAP - if (track->id3.title) - lcd_getstringsize(track->id3.title, NULL, NULL); - if (track->id3.artist) - lcd_getstringsize(track->id3.artist, NULL, NULL); - if (track->id3.album) - lcd_getstringsize(track->id3.album, NULL, NULL); -#endif - - /* if this track is the next track then let the UI know it can get it */ - send_nid3_event = (track_write_idx == track_read_idx + 1); - track_write_idx = (track_write_idx+1) & MAX_TRACK_ENTRIES_MASK; - if (send_nid3_event) - send_track_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, &track->id3); - debug_tags(); - return track; -} - -static int new_file(int steps) -{ - int max_steps = playlist_amount(); - int start = 0; - int i; - struct trackdata *track; - char name_buf[MAX_PATH+1]; - const char *trackname; - - /* Find out how many steps to advance. The load_ahead_index field tells - us how many playlist entries it had to skip to get to a valid one. - We add those together to find out where to start. */ - if(steps > 0 && num_tracks_in_memory() > 1) - { - /* Begin with the song after the currently playing one */ - i = 1; - while((track = get_trackdata(i++))) - { - start += track->load_ahead_index; - } - } - - do { - trackname = playlist_peek(start + steps, name_buf, sizeof(name_buf)); - if ( !trackname ) - return -1; - - DEBUGF("Loading %s\n", trackname); - - mpeg_file = open(trackname, O_RDONLY); - if(mpeg_file < 0) { - DEBUGF("Couldn't open file: %s\n",trackname); - if(steps < 0) - steps--; - else - steps++; - } - else - { - struct trackdata *track = add_track_to_tag_list(trackname); - - if(!track) - { - /* Bad mp3 file */ - if(steps < 0) - steps--; - else - steps++; - close(mpeg_file); - mpeg_file = -1; - } - else - { - /* skip past id3v2 tag */ - lseek(mpeg_file, - track->id3.first_frame_offset, - SEEK_SET); - track->id3.index = steps; - track->load_ahead_index = steps; - track->id3.offset = 0; - - if(track->id3.vbr) - /* Average bitrate * 1.5 */ - recalculate_watermark( - (track->id3.bitrate * 3) / 2); - else - recalculate_watermark( - track->id3.bitrate); - - } - } - - /* Bail out if no file could be opened */ - if(abs(steps) > max_steps) - return -1; - } while ( mpeg_file < 0 ); - - return 0; -} - -static void stop_playing(void) -{ - /* Stop the current stream */ - mp3_play_stop(); - playing = false; - filling = false; - - if(mpeg_file >= 0) - close(mpeg_file); - mpeg_file = -1; - remove_all_tags(); - generate_unbuffer_events(); - reset_mp3_buffer(); -} - -static void end_current_track(void) -{ - play_pending = false; - playing = false; - mp3_play_pause(false); - - reset_mp3_buffer(); - remove_all_tags(); - generate_unbuffer_events(); - - if(mpeg_file >= 0) - close(mpeg_file); -} - -/* Is this a really the end of playback or is a new playlist starting */ -static void check_playlist_end(int direction) -{ - /* Use the largest possible step size to account for skipped tracks */ - int steps = playlist_amount(); - - if (direction < 0) - steps = -steps; - - if (playlist_next(steps) < 0) - is_playing = false; -} - -static void update_playlist(void) -{ - if (num_tracks_in_memory() > 0) - { - struct trackdata *track = get_trackdata(0); - track->id3.index = playlist_next(track->id3.index); - } - else - { - /* End of playlist? */ - check_playlist_end(1); - } - - playlist_update_resume_info(audio_current_track()); -} - -static void track_change(void) -{ - DEBUGF("Track change\n"); - - if (num_tracks_in_memory() > 0) - { - remove_current_tag(); - update_playlist(); - if (is_playing) - { - send_track_event(PLAYBACK_EVENT_TRACK_CHANGE, - audio_current_track()); - } - } - - current_track_counter++; -} - -#ifdef DEBUG -void hexdump(const unsigned char *buf, int len) -{ - int i; - - for(i = 0;i < len;i++) - { - if(i && (i & 15) == 0) - { - DEBUGF("\n"); - } - DEBUGF("%02x ", buf[i]); - } - DEBUGF("\n"); -} -#endif /* DEBUG */ - -static void start_playback_if_ready(void) -{ - int playable_space; - - playable_space = audiobuf_swapwrite - audiobuf_read; - if(playable_space < 0) - playable_space += audiobuflen; - - /* See if we have started playing yet. If not, do it. */ - if(play_pending || dma_underrun) - { - /* If the filling has stopped, and we still haven't reached - the watermark, the file must be smaller than the - watermark. We must still play it. */ - if((playable_space >= MPEG_PLAY_PENDING_THRESHOLD) || - !filling || dma_underrun) - { - DEBUGF("P\n"); - if (play_pending) /* don't do this when recovering from DMA underrun */ - { - generate_postbuffer_events(); /* signal first track as buffered */ - if (play_pending_track_change) - { - play_pending_track_change = false; - send_track_event(PLAYBACK_EVENT_TRACK_CHANGE, - audio_current_track()); - } - play_pending = false; - } - playing = true; - - last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); - mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); - dma_underrun = false; - - if (!paused) - { - last_dma_tick = current_tick; - mp3_play_pause(true); - } - - /* Tell ourselves that we need more data */ - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); - } - } -} - -static bool swap_one_chunk(void) -{ - int free_space_left; - int amount_to_swap; - - free_space_left = get_unswapped_space(); - - if(free_space_left == 0 && !play_pending) - return false; - - /* Swap in larger chunks when the user is waiting for the playback - to start, or when there is dangerously little playable data left */ - if(play_pending) - amount_to_swap = MIN(MPEG_PLAY_PENDING_SWAPSIZE, free_space_left); - else - { - if(get_playable_space() < low_watermark) - amount_to_swap = MIN(MPEG_LOW_WATER_SWAP_CHUNKSIZE, - free_space_left); - else - amount_to_swap = MIN(MPEG_SWAP_CHUNKSIZE, free_space_left); - } - - if(audiobuf_write < audiobuf_swapwrite) - amount_to_swap = MIN(audiobuflen - audiobuf_swapwrite, - amount_to_swap); - else - amount_to_swap = MIN(audiobuf_write - audiobuf_swapwrite, - amount_to_swap); - - bitswap(mpeg_audiobuf + audiobuf_swapwrite, amount_to_swap); - - audiobuf_swapwrite += amount_to_swap; - if(audiobuf_swapwrite >= audiobuflen) - { - audiobuf_swapwrite = 0; - } - - return true; -} - -static void mpeg_thread(void) -{ - static int pause_tick = 0; - static unsigned int pause_track = 0; - struct queue_event ev; - int len; - int free_space_left; - int unplayed_space_left; - int amount_to_read; - int t1, t2; - unsigned long start_elapsed, start_offset; - - is_playing = false; - play_pending = false; - playing = false; - mpeg_file = -1; - - while(1) - { - yield(); - - /* Swap if necessary, and don't block on the queue_wait() */ - if(swap_one_chunk()) - { - queue_wait_w_tmo(&mpeg_queue, &ev, 0); - } - else if (playing) - { - /* periodically update resume info */ - queue_wait_w_tmo(&mpeg_queue, &ev, HZ/2); - } - else - { - DEBUGF("S R:%x W:%x SW:%x\n", - audiobuf_read, audiobuf_write, audiobuf_swapwrite); - queue_wait(&mpeg_queue, &ev); - } - - start_playback_if_ready(); - - switch(ev.id) - { - case MPEG_PLAY: - DEBUGF("MPEG_PLAY\n"); - -#if CONFIG_TUNER - /* Silence the A/D input, it may be on because the radio - may be playing */ - mas_codec_writereg(6, 0x0000); -#endif /* CONFIG_TUNER */ - - /* Stop the current stream */ - paused = false; - end_current_track(); - - if ( new_file(0) == -1 ) - { - is_playing = false; - track_change(); - break; - } - - start_elapsed = ((struct audio_resume_info *)ev.data)->elapsed; - start_offset = ((struct audio_resume_info *)ev.data)->offset; - - /* mid-song resume? */ - if (!start_offset && start_elapsed) { - struct mp3entry *id3 = &get_trackdata(0)->id3; - id3->elapsed = start_elapsed; - start_offset = audio_get_file_pos_int(id3); - } - - if (start_offset) { - struct mp3entry* id3 = &get_trackdata(0)->id3; - lseek(mpeg_file, start_offset, SEEK_SET); - id3->offset = start_offset; - set_elapsed(id3); - } - else { - /* skip past id3v2 tag */ - lseek(mpeg_file, - get_trackdata(0)->id3.first_frame_offset, - SEEK_SET); - - } - - /* Make it read more data */ - filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); - - /* Tell the file loading code that we want to start playing - as soon as we have some data */ - play_pending = true; - play_pending_track_change = true; - - update_playlist(); - current_track_counter++; - break; - - case MPEG_STOP: - do_stop(); - break; - - case MPEG_PAUSE: - DEBUGF("MPEG_PAUSE\n"); - /* Stop the current stream */ - if (playing) - playlist_update_resume_info(audio_current_track()); - paused = true; - playing = false; - pause_tick = current_tick; - pause_track = current_track_counter; - mp3_play_pause(false); - break; - - case MPEG_RESUME: - DEBUGF("MPEG_RESUME\n"); - /* Continue the current stream */ - paused = false; - if (!play_pending) - { - playing = true; - if ( current_track_counter == pause_track ) - last_dma_tick += current_tick - pause_tick; - else - last_dma_tick = current_tick; - pause_tick = 0; - mp3_play_pause(true); - } - break; - - case MPEG_NEXT: - DEBUGF("MPEG_NEXT\n"); - /* is next track in ram? */ - if ( num_tracks_in_memory() > 1 ) { - int unplayed_space_left, unswapped_space_left; - - /* stop the current stream */ - play_pending = false; - playing = false; - mp3_play_pause(false); - - track_change(); - audiobuf_read = get_trackdata(0)->mempos; - last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); - mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); - dma_underrun = false; - last_dma_tick = current_tick; - - unplayed_space_left = get_unplayed_space(); - unswapped_space_left = get_unswapped_space(); - - /* should we start reading more data? */ - if(!filling && (unplayed_space_left < low_watermark)) { - filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); - play_pending = true; - } else if(unswapped_space_left && - unswapped_space_left > unplayed_space_left) { - /* Stop swapping the data from the previous file */ - audiobuf_swapwrite = audiobuf_read; - play_pending = true; - } else { - playing = true; - if (!paused) - mp3_play_pause(true); - } - } - else { - if (!playlist_check(1)) - break; - - /* stop the current stream */ - end_current_track(); - - if (new_file(1) < 0) { - DEBUGF("No more files to play\n"); - filling = false; - - check_playlist_end(1); - current_track_counter++; - } else { - /* Make it read more data */ - filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); - - /* Tell the file loading code that we want - to start playing as soon as we have some data */ - play_pending = true; - play_pending_track_change = true; - - update_playlist(); - current_track_counter++; - } - } - break; - - case MPEG_PREV: { - DEBUGF("MPEG_PREV\n"); - - if (!playlist_check(-1)) - break; - - /* stop the current stream */ - end_current_track(); - - /* Open the next file */ - if (new_file(-1) < 0) { - DEBUGF("No more files to play\n"); - filling = false; - - check_playlist_end(-1); - current_track_counter++; - } else { - /* Make it read more data */ - filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); - - /* Tell the file loading code that we want to - start playing as soon as we have some data */ - play_pending = true; - play_pending_track_change = true; - - update_playlist(); - current_track_counter++; - } - break; - } - - case MPEG_FF_REWIND: { - struct mp3entry *id3 = audio_current_track(); - unsigned int oldtime = id3->elapsed; - unsigned int newtime = (unsigned int)ev.data; - int curpos, newpos, diffpos; - DEBUGF("MPEG_FF_REWIND\n"); - - id3->elapsed = newtime; - - newpos = audio_get_file_pos_int(id3); - if(newpos < 0) - { - id3->elapsed = oldtime; - break; - } - - if (mpeg_file >= 0) - curpos = lseek(mpeg_file, 0, SEEK_CUR); - else - curpos = id3->filesize; - - if (num_tracks_in_memory() > 1) - { - /* We have started loading other tracks that need to be - accounted for */ - struct trackdata *track; - int i = 0; - - while((track = get_trackdata(i++))) - { - curpos += track->id3.filesize; - } - } - - diffpos = curpos - newpos; - - if(!filling && diffpos >= 0 && diffpos < audiobuflen) - { - int unplayed_space_left, unswapped_space_left; - - /* We are changing to a position that's already in - memory, so we just move the DMA read pointer. */ - audiobuf_read = audiobuf_write - diffpos; - if (audiobuf_read < 0) - { - audiobuf_read += audiobuflen; - } - - unplayed_space_left = get_unplayed_space(); - unswapped_space_left = get_unswapped_space(); - - /* If unswapped_space_left is larger than - unplayed_space_left, it means that the swapwrite pointer - hasn't yet advanced up to the new location of the read - pointer. We just move it, there is no need to swap - data that won't be played anyway. */ - - if (unswapped_space_left > unplayed_space_left) - { - DEBUGF("Moved swapwrite\n"); - audiobuf_swapwrite = audiobuf_read; - play_pending = true; - } - - if (mpeg_file>=0 && unplayed_space_left < low_watermark) - { - /* We need to load more data before starting */ - filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); - play_pending = true; - } - else - { - /* resume will start at new position */ - last_dma_chunk_size = - MIN(0x2000, get_unplayed_space_current_song()); - mp3_play_data(mpeg_audiobuf + audiobuf_read, - last_dma_chunk_size, transfer_end); - dma_underrun = false; - } - } - else - { - /* Move to the new position in the file and start - loading data */ - reset_mp3_buffer(); - - if (num_tracks_in_memory() > 1) - { - /* We have to reload the current track */ - close(mpeg_file); - remove_all_non_current_tags(); - generate_unbuffer_events(); - mpeg_file = -1; - } - - if (mpeg_file < 0) - { - mpeg_file = open(id3->path, O_RDONLY); - if (mpeg_file < 0) - { - id3->elapsed = oldtime; - break; - } - } - - if(-1 == lseek(mpeg_file, newpos, SEEK_SET)) - { - id3->elapsed = oldtime; - break; - } - - filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); - - /* Tell the file loading code that we want to start playing - as soon as we have some data */ - play_pending = true; - } - - id3->offset = newpos; - - break; - } - - case MPEG_FLUSH_RELOAD: { - int numtracks = num_tracks_in_memory(); - bool reload_track = false; - - if (numtracks > 1) - { - /* Reset the buffer */ - audiobuf_write = get_trackdata(1)->mempos; - - /* Reset swapwrite unless we're still swapping current - track */ - if (get_unplayed_space() <= get_playable_space()) - audiobuf_swapwrite = audiobuf_write; - - close(mpeg_file); - remove_all_non_current_tags(); - generate_unbuffer_events(); - mpeg_file = -1; - reload_track = true; - } - else if (numtracks == 1 && mpeg_file < 0) - { - reload_track = true; - } - - if(reload_track && new_file(1) >= 0) - { - /* Tell ourselves that we want more data */ - filling = true; - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); - } - - break; - } - - case MPEG_NEED_DATA: - free_space_left = audiobuf_read - audiobuf_write; - - /* We interpret 0 as "empty buffer" */ - if(free_space_left <= 0) - free_space_left += audiobuflen; - - unplayed_space_left = audiobuflen - free_space_left; - - /* Make sure that we don't fill the entire buffer */ - free_space_left -= MPEG_HIGH_WATER; - - if (ev.data == GENERATE_UNBUFFER_EVENTS) - generate_unbuffer_events(); - - /* do we have any more buffer space to fill? */ - if(free_space_left <= 0) - { - DEBUGF("0\n"); - filling = false; - generate_postbuffer_events(); - storage_sleep(); - break; - } - - /* Read small chunks while we are below the low water mark */ - if(unplayed_space_left < low_watermark) - amount_to_read = MIN(MPEG_LOW_WATER_CHUNKSIZE, - free_space_left); - else - amount_to_read = free_space_left; - - /* Don't read more than until the end of the buffer */ - amount_to_read = MIN(audiobuflen - audiobuf_write, - amount_to_read); -#if (CONFIG_STORAGE & STORAGE_MMC) - /* MMC is slow, so don't read too large chunks */ - amount_to_read = MIN(0x40000, amount_to_read); -#elif MEMORYSIZE == 8 - amount_to_read = MIN(0x100000, amount_to_read); -#endif - - /* Read as much mpeg data as we can fit in the buffer */ - if(mpeg_file >= 0) - { - DEBUGF("R\n"); - t1 = current_tick; - len = read(mpeg_file, mpeg_audiobuf + audiobuf_write, - amount_to_read); - if(len > 0) - { - t2 = current_tick; - DEBUGF("time: %d\n", t2 - t1); - DEBUGF("R: %x\n", len); - - /* Now make sure that we don't feed the MAS with ID3V1 - data */ - if (len < amount_to_read) - { - int i; - static const unsigned char tag[] = "TAG"; - int taglen = 128; - int tagptr = audiobuf_write + len - 128; - - /* Really rare case: entire potential tag wasn't - read in this call AND audiobuf_write < 128 */ - if (tagptr < 0) - tagptr += audiobuflen; - - for(i = 0;i < 3;i++) - { - if(tagptr >= audiobuflen) - tagptr -= audiobuflen; - - if(mpeg_audiobuf[tagptr] != tag[i]) - { - taglen = 0; - break; - } - - tagptr++; - } - - if(taglen) - { - /* Skip id3v1 tag */ - DEBUGF("Skipping ID3v1 tag\n"); - len -= taglen; - - /* In the very rare case when the entire tag - wasn't read in this read() len will be < 0. - Take care of this when changing the write - pointer. */ - } - } - - audiobuf_write += len; - - if (audiobuf_write < 0) - audiobuf_write += audiobuflen; - - if(audiobuf_write >= audiobuflen) - { - audiobuf_write = 0; - DEBUGF("W\n"); - } - - /* Tell ourselves that we want more data */ - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); - } - else - { - if(len < 0) - { - DEBUGF("MPEG read error\n"); - } - - close(mpeg_file); - mpeg_file = -1; - - if(new_file(1) < 0) - { - /* No more data to play */ - DEBUGF("No more files to play\n"); - filling = false; - } - else - { - /* Tell ourselves that we want more data */ - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); - } - } - } - break; - - case MPEG_TRACK_CHANGE: - track_change(); - break; - -#ifndef USB_NONE - case SYS_USB_CONNECTED: - is_playing = false; - paused = false; - stop_playing(); - - /* Tell the USB thread that we are safe */ - DEBUGF("mpeg_thread got SYS_USB_CONNECTED\n"); - usb_acknowledge(SYS_USB_CONNECTED_ACK); - - /* Wait until the USB cable is extracted again */ - usb_wait_for_disconnect(&mpeg_queue); - break; -#endif /* !USB_NONE */ - - case SYS_TIMEOUT: - if (playing) - playlist_update_resume_info(audio_current_track()); - break; - } - } -} -#endif /* !SIMULATOR */ - -struct mp3entry* audio_current_track(void) -{ -#ifdef SIMULATOR - struct mp3entry *id3 = &taginfo; -#else /* !SIMULATOR */ - if(num_tracks_in_memory()) - { - struct mp3entry *id3 = &get_trackdata(0)->id3; -#endif - if (!checked_for_cuesheet && curr_cuesheet && id3->cuesheet == NULL) - { - checked_for_cuesheet = true; /* only check once per track */ - struct cuesheet_file cue_file; - - if (look_for_cuesheet_file(id3, &cue_file) && - parse_cuesheet(&cue_file, curr_cuesheet)) - { - id3->cuesheet = curr_cuesheet; - } - } - return id3; -#ifndef SIMULATOR - } - else - return NULL; -#endif /* !SIMULATOR */ -} - -struct mp3entry* audio_next_track(void) -{ -#ifdef SIMULATOR - return &taginfo; -#else /* !SIMULATOR */ - if(num_tracks_in_memory() > 1) - return &get_trackdata(1)->id3; - else - return NULL; -#endif /* !SIMULATOR */ -} - -size_t audio_buffer_size(void) -{ - if (audiobuf_handle > 0) - return audiobuflen; - return 0; -} - -size_t audio_buffer_available(void) -{ - size_t size = 0; - size_t core_size = core_available(); - if (audiobuf_handle > 0) - return audiobuflen - AUDIO_BUFFER_RESERVE - 128; - return MAX(core_size, size); -} - -static void audio_reset_buffer_noalloc(void* buf, size_t bufsize) -{ - mpeg_audiobuf = buf; - audiobuflen = bufsize; - if (global_settings.cuesheet) - { /* enable cuesheet support */ - curr_cuesheet = (struct cuesheet*)mpeg_audiobuf; - mpeg_audiobuf = SKIPBYTES(mpeg_audiobuf, sizeof(struct cuesheet)); - audiobuflen -= sizeof(struct cuesheet); - } -} - -static void audio_reset_buffer(void) -{ - size_t bufsize = audiobuflen; - - /* alloc buffer if it's was never allocated or freed by audio_hard_stop() - * because voice cannot be played during audio playback make - * talk.c give up all buffers and disable itself */ - if (!audiobuf_handle) - { - talk_buffer_set_policy(TALK_BUFFER_LOOSE); - audiobuf_handle = core_alloc_maximum("audiobuf", &bufsize, &ops); - } - - audio_reset_buffer_noalloc(core_get_data(audiobuf_handle), bufsize); -} - -void audio_play(unsigned long elapsed, unsigned long offset) -{ - audio_reset_buffer(); -#ifdef SIMULATOR - char name_buf[MAX_PATH+1]; - const char* trackname; - int steps=0; - - is_playing = true; - - do { - trackname = playlist_peek(steps, name_buf, sizeof(name_buf)); - if (!trackname) - break; - if(mp3info(&taginfo, trackname)) { - /* bad mp3, move on */ - if(++steps > playlist_amount()) - break; - continue; - } -#ifdef HAVE_MPEG_PLAY - real_mpeg_play(trackname); -#endif - playlist_next(steps); - if (!offset && elapsed) - { - /* has an elapsed time but no offset; elapsed may take - precedence in this case */ - taginfo.elapsed = elapsed; - taginfo.offset = audio_get_file_pos_int(&taginfo); - } - else - { - taginfo.offset = offset; - set_elapsed(&taginfo); - } - is_playing = true; - playing = true; - break; - } while(1); -#else /* !SIMULATOR */ - static struct audio_resume_info resume; - is_playing = true; - resume.elapsed = elapsed; - resume.offset = offset; - queue_post(&mpeg_queue, MPEG_PLAY, (intptr_t)&resume); -#endif /* !SIMULATOR */ - - mpeg_errno = 0; -} - -void audio_stop(void) -{ - if (audiobuf_handle <= 0) - return; /* nothing to do, must be hard-stopped already */ -#ifndef SIMULATOR - mpeg_stop_done = false; - queue_post(&mpeg_queue, MPEG_STOP, 0); - while(!mpeg_stop_done) - yield(); -#else /* SIMULATOR */ - paused = false; - is_playing = false; - playing = false; -#endif /* SIMULATOR */ -} - -/* dummy */ -void audio_stop_recording(void) -{ - audio_stop(); -} - -void audio_hard_stop(void) -{ - if (audiobuf_handle > 0) - { - audio_stop(); - audiobuf_handle = core_free(audiobuf_handle); - mpeg_audiobuf = NULL; - talk_buffer_set_policy(TALK_BUFFER_DEFAULT); - } -} - -void audio_pause(void) -{ -#ifndef SIMULATOR - queue_post(&mpeg_queue, MPEG_PAUSE, 0); -#else /* SIMULATOR */ - is_playing = true; - playing = false; - paused = true; -#endif /* SIMULATOR */ -} - -void audio_resume(void) -{ -#ifndef SIMULATOR - queue_post(&mpeg_queue, MPEG_RESUME, 0); -#else /* SIMULATOR */ - is_playing = true; - playing = true; - paused = false; -#endif /* SIMULATOR */ -} - -void audio_next(void) -{ -#ifndef SIMULATOR - queue_remove_from_head(&mpeg_queue, MPEG_NEED_DATA); - queue_post(&mpeg_queue, MPEG_NEXT, 0); -#else /* SIMULATOR */ - char name_buf[MAX_PATH+1]; - const char* file; - int steps = 1; - - do { - file = playlist_peek(steps, name_buf, sizeof(name_buf)); - if(!file) - break; - if(mp3info(&taginfo, file)) { - if(++steps > playlist_amount()) - break; - continue; - } - playlist_next(steps); - current_track_counter++; - is_playing = true; - playing = true; - break; - } while(1); -#endif /* SIMULATOR */ -} - -void audio_prev(void) -{ -#ifndef SIMULATOR - queue_remove_from_head(&mpeg_queue, MPEG_NEED_DATA); - queue_post(&mpeg_queue, MPEG_PREV, 0); -#else /* SIMULATOR */ - char name_buf[MAX_PATH+1]; - const char* file; - int steps = -1; - - do { - file = playlist_peek(steps, name_buf, sizeof(name_buf)); - if(!file) - break; - if(mp3info(&taginfo, file)) { - steps--; - continue; - } - playlist_next(steps); - current_track_counter++; - is_playing = true; - playing = true; - break; - } while(1); -#endif /* SIMULATOR */ -} - -void audio_ff_rewind(long newpos) -{ -#ifndef SIMULATOR - queue_post(&mpeg_queue, MPEG_FF_REWIND, newpos); -#else /* SIMULATOR */ - (void)newpos; -#endif /* SIMULATOR */ -} - -void audio_flush_and_reload_tracks(void) -{ -#ifndef SIMULATOR - queue_post(&mpeg_queue, MPEG_FLUSH_RELOAD, 0); -#endif /* !SIMULATOR*/ -} - -int audio_status(void) -{ - int ret = 0; - - if(is_playing) - ret |= AUDIO_STATUS_PLAY; - - if(paused) - ret |= AUDIO_STATUS_PAUSE; - - if(mpeg_errno) - ret |= AUDIO_STATUS_ERROR; - - return ret; -} - -/* Unused function -unsigned int audio_error(void) -{ - return mpeg_errno; -} -*/ - -void audio_error_clear(void) -{ - mpeg_errno = 0; -} - -#ifdef SIMULATOR -static void mpeg_thread(void) -{ - struct mp3entry* id3; - while ( 1 ) { - if (is_playing) { - id3 = audio_current_track(); - if (!paused) - { - id3->elapsed+=1000; - id3->offset+=1000; - } - if (id3->elapsed>=id3->length) - audio_next(); - } - sleep(HZ); - } -} -#endif /* SIMULATOR */ - -void audio_init(void) -{ - mpeg_errno = 0; - - audio_reset_buffer(); - -#ifndef SIMULATOR - queue_init(&mpeg_queue, true); -#endif /* !SIMULATOR */ - audio_thread_id = create_thread(mpeg_thread, mpeg_stack, - sizeof(mpeg_stack), 0, mpeg_thread_name - IF_PRIO(, PRIORITY_SYSTEM) - IF_COP(, CPU)); - - memset(trackdata, 0, sizeof(trackdata)); - -#ifdef DEBUG -#ifndef SIMULATOR - dbg_timer_start(); - dbg_cnt2us(0); -#endif /* !SIMULATOR */ -#endif /* DEBUG */ - audio_is_initialized = true; -} - -#endif /* CONFIG_CODEC != SWCODEC */ -- cgit v1.2.3