Commit FS#12069 - Playback rework - first stages. Gives as thorough as possible a treatment of codec management, track change and metadata logic as possible while maintaining fairly narrow focus and not rewriting everything all at once. Please see the rockbox-dev mail archive on 2011-04-25 (Playback engine rework) for a more thorough manifest of what was addressed. Plugins and codecs become incompatible.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29785 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2011-04-27 03:08:23 +00:00
parent dcf0f8de4a
commit c537d5958e
62 changed files with 6047 additions and 4221 deletions

View file

@ -35,6 +35,7 @@ enum {
PLAYBACK_EVENT_TRACK_BUFFER,
PLAYBACK_EVENT_TRACK_FINISH,
PLAYBACK_EVENT_TRACK_CHANGE,
PLAYBACK_EVENT_TRACK_SKIP,
PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
};

View file

@ -82,8 +82,6 @@
#define LOGFQUEUE_SYS_TIMEOUT(...)
#endif
/* default point to start buffer refill */
#define BUFFERING_DEFAULT_WATERMARK (1024*128)
/* amount of data to read in one read() call */
#define BUFFERING_DEFAULT_FILECHUNK (1024*32)
@ -94,6 +92,8 @@
struct memory_handle {
int id; /* A unique ID for the handle */
enum data_type type; /* Type of data buffered with this handle */
int8_t pinned; /* Count of references */
int8_t signaled; /* Stop any attempt at waiting to get the data */
char path[MAX_PATH]; /* Path if data originated in a file */
int fd; /* File descriptor to path (-1 if closed) */
size_t data; /* Start index of the handle's data buffer */
@ -125,9 +125,7 @@ static volatile size_t buf_ridx; /* current reading position */
/* Configuration */
static size_t conf_watermark = 0; /* Level to trigger filebuf fill */
#if MEMORYSIZE > 8
static size_t high_watermark = 0; /* High watermark for rebuffer */
#endif
/* current memory handle in the linked list. NULL when the list is empty. */
static struct memory_handle *cur_handle;
@ -162,7 +160,6 @@ enum
Q_REBUFFER_HANDLE, /* Request reset and rebuffering of a handle at a new
file starting position. */
Q_CLOSE_HANDLE, /* Request closing a handle */
Q_BASE_HANDLE, /* Set the reference handle for buf_useful_data */
/* Configuration: */
Q_START_FILL, /* Request that the buffering thread initiate a buffer
@ -222,6 +219,9 @@ static inline ssize_t ringbuf_add_cross(uintptr_t p1, size_t v, uintptr_t p2)
/* Bytes available in the buffer */
#define BUF_USED ringbuf_sub(buf_widx, buf_ridx)
/* Real buffer watermark */
#define BUF_WATERMARK MIN(conf_watermark, high_watermark)
/*
LINKED LIST MANAGEMENT
======================
@ -313,6 +313,12 @@ static struct memory_handle *add_handle(size_t data_size, bool can_wrap,
/* Prevent buffering thread from looking at it */
new_handle->filerem = 0;
/* Handle can be moved by default */
new_handle->pinned = 0;
/* Handle data can be waited for by default */
new_handle->signaled = 0;
/* only advance the buffer write index of the size of the struct */
buf_widx = ringbuf_add(buf_widx, sizeof(struct memory_handle));
@ -364,6 +370,9 @@ static bool rm_handle(const struct memory_handle *h)
buf_widx = cur_handle->widx;
}
} else {
/* If we don't find ourselves, this is a seriously incoherent
state with a corrupted list and severe action is needed! */
panicf("rm_handle fail: %d", h->id);
return false;
}
}
@ -385,8 +394,7 @@ static struct memory_handle *find_handle(int handle_id)
/* simple caching because most of the time the requested handle
will either be the same as the last, or the one after the last */
if (cached_handle)
{
if (cached_handle) {
if (cached_handle->id == handle_id) {
return cached_handle;
} else if (cached_handle->next &&
@ -618,20 +626,22 @@ static void update_data_counters(struct data_counters *dc)
static inline bool buffer_is_low(void)
{
update_data_counters(NULL);
return data_counters.useful < (conf_watermark / 2);
return data_counters.useful < BUF_WATERMARK / 2;
}
/* Q_BUFFER_HANDLE event and buffer data for the given handle.
Return whether or not the buffering should continue explicitly. */
static bool buffer_handle(int handle_id, size_t to_buffer)
{
logf("buffer_handle(%d)", handle_id);
logf("buffer_handle(%d, %lu)", handle_id, (unsigned long)to_buffer);
struct memory_handle *h = find_handle(handle_id);
bool stop = false;
if (!h)
return true;
logf(" type: %d", (int)h->type);
if (h->filerem == 0) {
/* nothing left to buffer */
return true;
@ -659,13 +669,13 @@ static bool buffer_handle(int handle_id, size_t to_buffer)
if (!get_metadata((struct mp3entry *)(buffer + h->data),
h->fd, h->path)) {
/* metadata parsing failed: clear the buffer. */
memset(buffer + h->data, 0, sizeof(struct mp3entry));
wipe_mp3entry((struct mp3entry *)(buffer + h->data));
}
close(h->fd);
h->fd = -1;
h->filerem = 0;
h->available = sizeof(struct mp3entry);
h->widx += sizeof(struct mp3entry);
h->widx = ringbuf_add(h->widx, sizeof(struct mp3entry));
send_event(BUFFER_EVENT_FINISHED, &handle_id);
return true;
}
@ -698,7 +708,7 @@ static bool buffer_handle(int handle_id, size_t to_buffer)
break;
}
DEBUGF("File ended %ld bytes early\n", (long)h->filerem);
logf("File ended %ld bytes early\n", (long)h->filerem);
h->filesize -= h->filerem;
h->filerem = 0;
break;
@ -770,22 +780,31 @@ static bool close_handle(int handle_id)
part of its data buffer or by moving all the data. */
static void shrink_handle(struct memory_handle *h)
{
size_t delta;
if (!h)
return;
if (h->type == TYPE_ID3 || h->type == TYPE_CUESHEET ||
h->type == TYPE_BITMAP || h->type == TYPE_CODEC ||
h->type == TYPE_ATOMIC_AUDIO)
{
if (h->type == TYPE_PACKET_AUDIO) {
/* only move the handle struct */
/* data is pinned by default - if we start moving packet audio,
the semantics will determine whether or not data is movable
but the handle will remain movable in either case */
size_t delta = ringbuf_sub(h->ridx, h->data);
/* The value of delta might change for alignment reasons */
if (!move_handle(&h, &delta, 0, true))
return;
h->data = ringbuf_add(h->data, delta);
h->available -= delta;
h->offset += delta;
} else {
/* metadata handle: we can move all of it */
if (!h->next || h->filerem != 0)
return; /* Last handle or not finished loading */
if (h->pinned || !h->next || h->filerem != 0)
return; /* Pinned, last handle or not finished loading */
uintptr_t handle_distance =
ringbuf_sub(ringbuf_offset(h->next), h->data);
delta = handle_distance - h->available;
size_t delta = handle_distance - h->available;
/* The value of delta might change for alignment reasons */
if (!move_handle(&h, &delta, h->available, h->type==TYPE_CODEC))
@ -806,15 +825,6 @@ static void shrink_handle(struct memory_handle *h)
struct bitmap *bmp = (struct bitmap *)&buffer[h->data];
bmp->data = &buffer[h->data + sizeof(struct bitmap)];
}
} else {
/* only move the handle struct */
delta = ringbuf_sub(h->ridx, h->data);
if (!move_handle(&h, &delta, 0, true))
return;
h->data = ringbuf_add(h->data, delta);
h->available -= delta;
h->offset += delta;
}
}
@ -962,6 +972,8 @@ int bufopen(const char *file, size_t offset, enum data_type type,
mutex_unlock(&llist_mutex);
return handle_id;
}
else if (type == TYPE_UNKNOWN)
return ERR_UNSUPPORTED_TYPE;
#ifdef APPLICATION
/* loading code from memory is not supported in application builds */
else if (type == TYPE_CODEC)
@ -1083,7 +1095,12 @@ int bufopen(const char *file, size_t offset, enum data_type type,
*/
int bufalloc(const void *src, size_t size, enum data_type type)
{
int handle_id = ERR_BUFFER_FULL;
int handle_id;
if (type == TYPE_UNKNOWN)
return ERR_UNSUPPORTED_TYPE;
handle_id = ERR_BUFFER_FULL;
mutex_lock(&llist_mutex);
@ -1124,7 +1141,14 @@ int bufalloc(const void *src, size_t size, enum data_type type)
bool bufclose(int handle_id)
{
logf("bufclose(%d)", handle_id);
#if 0
/* Don't interrupt the buffering thread if the handle is already
stale */
if (!find_handle(handle_id)) {
logf(" handle already closed");
return true;
}
#endif
LOGFQUEUE("buffering >| Q_CLOSE_HANDLE %d", handle_id);
return queue_send(&buffering_queue, Q_CLOSE_HANDLE, handle_id);
}
@ -1236,9 +1260,10 @@ static int seek_handle(struct memory_handle *h, size_t newpos)
/* Set reading index in handle (relatively to the start of the file).
Access before the available data will trigger a rebuffer.
Return 0 for success and < 0 for failure:
-1 if the handle wasn't found
-2 if the new requested position was beyond the end of the file
Return 0 for success and for failure:
ERR_HANDLE_NOT_FOUND if the handle wasn't found
ERR_INVALID_VALUE if the new requested position was beyond the end of
the file
*/
int bufseek(int handle_id, size_t newpos)
{
@ -1250,7 +1275,11 @@ int bufseek(int handle_id, size_t newpos)
}
/* Advance the reading index in a handle (relatively to its current position).
Return 0 for success and < 0 for failure */
Return 0 for success and for failure:
ERR_HANDLE_NOT_FOUND if the handle wasn't found
ERR_INVALID_VALUE if the new requested position was beyond the end of
the file
*/
int bufadvance(int handle_id, off_t offset)
{
struct memory_handle *h = find_handle(handle_id);
@ -1261,6 +1290,18 @@ int bufadvance(int handle_id, off_t offset)
return seek_handle(h, newpos);
}
/* Get the read position from the start of the file
Returns the offset from byte 0 of the file and for failure:
ERR_HANDLE_NOT_FOUND if the handle wasn't found
*/
off_t bufftell(int handle_id)
{
const struct memory_handle *h = find_handle(handle_id);
if (!h)
return ERR_HANDLE_NOT_FOUND;
return h->offset + ringbuf_sub(h->ridx, h->data);
}
/* Used by bufread and bufgetdata to prepare the buffer and retrieve the
* actual amount of data available for reading. This function explicitly
* does not check the validity of the input handle. It does do range checks
@ -1306,7 +1347,7 @@ static struct memory_handle *prep_bufdata(int handle_id, size_t *size,
/* it is not safe for a non-buffering thread to sleep while
* holding a handle */
h = find_handle(handle_id);
if (!h)
if (!h || h->signaled != 0)
return NULL;
avail = handle_size_available(h);
}
@ -1447,9 +1488,14 @@ SECONDARY EXPORTED FUNCTIONS
buf_handle_offset
buf_request_buffer_handle
buf_set_base_handle
buf_handle_data_type
buf_is_handle
buf_pin_handle
buf_signal_handle
buf_length
buf_used
register_buffering_callback
unregister_buffering_callback
buf_set_watermark
buf_get_watermark
These functions are exported, to allow interaction with the buffer.
They take care of the content of the structs, and rely on the linked list
@ -1472,8 +1518,61 @@ void buf_request_buffer_handle(int handle_id)
void buf_set_base_handle(int handle_id)
{
LOGFQUEUE("buffering > Q_BASE_HANDLE %d", handle_id);
queue_post(&buffering_queue, Q_BASE_HANDLE, handle_id);
mutex_lock(&llist_mutex);
base_handle_id = handle_id;
mutex_unlock(&llist_mutex);
}
enum data_type buf_handle_data_type(int handle_id)
{
const struct memory_handle *h = find_handle(handle_id);
if (!h)
return TYPE_UNKNOWN;
return h->type;
}
ssize_t buf_handle_remaining(int handle_id)
{
const struct memory_handle *h = find_handle(handle_id);
if (!h)
return ERR_HANDLE_NOT_FOUND;
return h->filerem;
}
bool buf_is_handle(int handle_id)
{
return find_handle(handle_id) != NULL;
}
bool buf_pin_handle(int handle_id, bool pin)
{
struct memory_handle *h = find_handle(handle_id);
if (!h)
return false;
if (pin) {
h->pinned++;
} else if (h->pinned > 0) {
h->pinned--;
}
return true;
}
bool buf_signal_handle(int handle_id, bool signal)
{
struct memory_handle *h = find_handle(handle_id);
if (!h)
return false;
h->signaled = signal ? 1 : 0;
return true;
}
/* Return the size of the ringbuffer */
size_t buf_length(void)
{
return buffer_len;
}
/* Return the amount of buffer space used */
@ -1487,6 +1586,21 @@ void buf_set_watermark(size_t bytes)
conf_watermark = bytes;
}
size_t buf_get_watermark(void)
{
return BUF_WATERMARK;
}
#ifdef HAVE_IO_PRIORITY
void buf_back_off_storage(bool back_off)
{
int priority = back_off ?
IO_PRIORITY_BACKGROUND : IO_PRIORITY_IMMEDIATE;
thread_set_io_priority(buffering_thread_id, priority);
}
#endif
/** -- buffer thread helpers -- **/
static void shrink_buffer_inner(struct memory_handle *h)
{
if (h == NULL)
@ -1503,7 +1617,7 @@ static void shrink_buffer(void)
shrink_buffer_inner(first_handle);
}
void buffering_thread(void)
static void NORETURN_ATTR buffering_thread(void)
{
bool filling = false;
struct queue_event ev;
@ -1511,19 +1625,21 @@ void buffering_thread(void)
while (true)
{
if (num_handles > 0) {
if (!filling) {
cancel_cpu_boost();
}
queue_wait_w_tmo(&buffering_queue, &ev, filling ? 5 : HZ/2);
queue_wait_w_tmo(&buffering_queue, &ev, filling ? 1 : HZ/2);
} else {
filling = false;
cancel_cpu_boost();
queue_wait(&buffering_queue, &ev);
}
switch (ev.id)
{
case Q_START_FILL:
LOGFQUEUE("buffering < Q_START_FILL %d", (int)ev.data);
/* Call buffer callbacks here because this is one of two ways
* to begin a full buffer fill */
send_event(BUFFER_EVENT_BUFFER_LOW, 0);
shrink_buffer();
queue_reply(&buffering_queue, 1);
filling |= buffer_handle((int)ev.data, 0);
@ -1553,36 +1669,21 @@ void buffering_thread(void)
filling = true;
break;
case Q_BASE_HANDLE:
LOGFQUEUE("buffering < Q_BASE_HANDLE %d", (int)ev.data);
base_handle_id = (int)ev.data;
break;
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
case SYS_USB_CONNECTED:
LOGFQUEUE("buffering < SYS_USB_CONNECTED");
usb_acknowledge(SYS_USB_CONNECTED_ACK);
usb_wait_for_disconnect(&buffering_queue);
break;
#endif
case SYS_TIMEOUT:
LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT");
break;
}
if (num_handles == 0 || !queue_empty(&buffering_queue))
continue;
update_data_counters(NULL);
/* If the buffer is low, call the callbacks to get new data */
if (num_handles > 0 && data_counters.useful <= conf_watermark)
send_event(BUFFER_EVENT_BUFFER_LOW, 0);
#if 0
/* TODO: This needs to be fixed to use the idle callback, disable it
* for simplicity until its done right */
#if MEMORYSIZE > 8
/* If the disk is spinning, take advantage by filling the buffer */
else if (storage_disk_is_active() && queue_empty(&buffering_queue)) {
else if (storage_disk_is_active()) {
if (num_handles > 0 && data_counters.useful <= high_watermark)
send_event(BUFFER_EVENT_BUFFER_LOW, 0);
@ -1597,15 +1698,23 @@ void buffering_thread(void)
#endif
#endif
if (queue_empty(&buffering_queue)) {
if (filling) {
if (data_counters.remaining > 0 && BUF_USED < buffer_len)
if (data_counters.remaining > 0 && BUF_USED < buffer_len) {
filling = fill_buffer();
else if (data_counters.remaining == 0)
}
else if (data_counters.remaining == 0) {
filling = false;
}
} else if (ev.id == SYS_TIMEOUT) {
if (data_counters.remaining > 0 &&
data_counters.useful <= conf_watermark) {
if (data_counters.useful < BUF_WATERMARK) {
/* The buffer is low and we're idle, just watching the levels
- call the callbacks to get new data */
send_event(BUFFER_EVENT_BUFFER_LOW, NULL);
/* Continue anything else we haven't finished - it might
get booted off or stop early because the receiver hasn't
had a chance to clear anything yet */
if (data_counters.remaining > 0) {
shrink_buffer();
filling = fill_buffer();
}
@ -1618,9 +1727,14 @@ void buffering_init(void)
{
mutex_init(&llist_mutex);
conf_watermark = BUFFERING_DEFAULT_WATERMARK;
queue_init(&buffering_queue, true);
/* Thread should absolutely not respond to USB because if it waits first,
then it cannot properly service the handles and leaks will happen -
this is a worker thread and shouldn't need to care about any system
notifications.
***
Whoever is using buffering should be responsible enough to clear all
the handles at the right time. */
queue_init(&buffering_queue, false);
buffering_thread_id = create_thread( buffering_thread, buffering_stack,
sizeof(buffering_stack), CREATE_THREAD_FROZEN,
buffering_thread_name IF_PRIO(, PRIORITY_BUFFERING)
@ -1636,6 +1750,9 @@ bool buffering_reset(char *buf, size_t buflen)
/* Wraps of storage-aligned data must also be storage aligned,
thus buf and buflen must be a aligned to an integer multiple of
the storage alignment */
buflen -= GUARD_BUFSIZE;
STORAGE_ALIGN_BUFFER(buf, buflen);
if (!buf || !buflen)
@ -1654,10 +1771,13 @@ bool buffering_reset(char *buf, size_t buflen)
num_handles = 0;
base_handle_id = -1;
/* Set the high watermark as 75% full...or 25% empty :) */
#if MEMORYSIZE > 8
/* Set the high watermark as 75% full...or 25% empty :)
This is the greatest fullness that will trigger low-buffer events
no matter what the setting because high-bitrate files can have
ludicrous margins that even exceed the buffer size - most common
with a huge anti-skip buffer but even without that setting,
staying constantly active in buffering is pointless */
high_watermark = 3*buflen / 4;
#endif
thread_thaw(buffering_thread_id);
@ -1673,5 +1793,5 @@ void buffering_get_debugdata(struct buffering_debug *dbgdata)
dbgdata->wasted_space = dc.wasted;
dbgdata->buffered_data = dc.buffered;
dbgdata->useful_data = dc.useful;
dbgdata->watermark = conf_watermark;
dbgdata->watermark = BUF_WATERMARK;
}

View file

@ -28,14 +28,13 @@
enum data_type {
TYPE_UNKNOWN = 0, /* invalid type indicator */
TYPE_ID3,
TYPE_CODEC,
TYPE_PACKET_AUDIO,
TYPE_ATOMIC_AUDIO,
TYPE_ID3,
TYPE_CUESHEET,
TYPE_BITMAP,
TYPE_BUFFER,
TYPE_UNKNOWN,
};
/* Error return values */
@ -63,6 +62,7 @@ bool buffering_reset(char *buf, size_t buflen);
* bufclose : Close an open handle
* bufseek : Set handle reading index, relatively to the start of the file
* bufadvance: Move handle reading index, relatively to current position
* bufftell : Return the handle's file read position
* bufread : Copy data from a handle to a buffer
* bufgetdata: Obtain a pointer for linear access to a "size" amount of data
* bufgettail: Out-of-band get the last size bytes of a handle.
@ -81,28 +81,40 @@ int bufalloc(const void *src, size_t size, enum data_type type);
bool bufclose(int handle_id);
int bufseek(int handle_id, size_t newpos);
int bufadvance(int handle_id, off_t offset);
off_t bufftell(int handle_id);
ssize_t bufread(int handle_id, size_t size, void *dest);
ssize_t bufgetdata(int handle_id, size_t size, void **data);
ssize_t bufgettail(int handle_id, size_t size, void **data);
ssize_t bufcuttail(int handle_id, size_t size);
/***************************************************************************
* SECONDARY FUNCTIONS
* ===================
*
* buf_handle_data_type: return the handle's data type
* buf_is_handle: is the handle valid?
* buf_pin_handle: Disallow/allow handle movement. Handle may still be removed.
* buf_handle_offset: Get the offset of the first buffered byte from the file
* buf_request_buffer_handle: Request buffering of a handle
* buf_set_base_handle: Tell the buffering thread which handle is currently read
* buf_length: Total size of ringbuffer
* buf_used: Total amount of buffer space used (including allocated space)
* buf_back_off_storage: tell buffering thread to take it easy
****************************************************************************/
enum data_type buf_handle_data_type(int handle_id);
ssize_t buf_handle_remaining(int handle_id);
bool buf_is_handle(int handle_id);
ssize_t buf_handle_offset(int handle_id);
void buf_request_buffer_handle(int handle_id);
void buf_set_base_handle(int handle_id);
size_t buf_length(void);
size_t buf_used(void);
bool buf_pin_handle(int handle_id, bool pin);
bool buf_signal_handle(int handle_id, bool signal);
#ifdef HAVE_IO_PRIORITY
void buf_back_off_storage(bool back_off);
#endif
/* Settings */
enum {
@ -110,6 +122,7 @@ enum {
BUFFERING_SET_CHUNKSIZE,
};
void buf_set_watermark(size_t bytes);
size_t buf_get_watermark(void);
/* Debugging */
struct buffering_debug {

View file

@ -9,6 +9,7 @@
*
* Copyright (C) 2005-2007 Miika Pekkarinen
* Copyright (C) 2007-2008 Nicolas Pennequin
* Copyright (C) 2011 Michael Sevakis
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -21,16 +22,14 @@
****************************************************************************/
#include "config.h"
#include "system.h"
#include "playback.h"
#include "codec_thread.h"
#include "kernel.h"
#include "codecs.h"
#include "buffering.h"
#include "codec_thread.h"
#include "pcmbuf.h"
#include "playback.h"
#include "buffering.h"
#include "dsp.h"
#include "abrepeat.h"
#include "metadata.h"
#include "splash.h"
/* Define LOGF_ENABLE to enable logf output in this file */
/*#define LOGF_ENABLE*/
@ -57,38 +56,45 @@
#define LOGFQUEUE_SYS_TIMEOUT(...)
#endif
/* Variables are commented with the threads that use them:
* A=audio, C=codec, V=voice. A suffix of - indicates that
* the variable is read but not updated on that thread.
* A=audio, C=codec
* - = reads only
*
* Unless otherwise noted, the extern variables are located
* in playback.c.
*/
/* Main state control */
/* Type of codec loaded? (C/A) */
static int current_codectype SHAREDBSS_ATTR = AFMT_UNKNOWN;
extern struct mp3entry *thistrack_id3, /* the currently playing track */
*othertrack_id3; /* prev track during track-change-transition, or end of playlist,
* next track otherwise */
/* Track change controls */
extern struct event_queue audio_queue SHAREDBSS_ATTR;
/* Q_LOAD_CODEC parameter data */
struct codec_load_info
{
int hid; /* audio handle id (specify < 0 to use afmt) */
int afmt; /* codec specification (AFMT_*) */
};
/** --- Main state control --- **/
static int codec_type = AFMT_UNKNOWN; /* Codec type (C,A-) */
/* Private interfaces to main playback control */
extern void audio_codec_update_elapsed(unsigned long value);
extern void audio_codec_update_offset(size_t value);
extern void audio_queue_post(long id, intptr_t data);
extern struct codec_api ci; /* from codecs.c */
/* Codec thread */
static unsigned int codec_thread_id; /* For modifying thread priority later */
static struct event_queue codec_queue SHAREDBSS_ATTR;
static struct queue_sender_list codec_queue_sender_list SHAREDBSS_ATTR;
static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
IBSS_ATTR;
static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] IBSS_ATTR;
static const char codec_thread_name[] = "codec";
static void unload_codec(void);
/* Messages are only ever sent one at a time to the codec from the audio
thread. This is important for correct operation unless playback is
stopped. */
/* static routines */
static void codec_queue_ack(intptr_t ackme)
{
@ -100,51 +106,62 @@ static intptr_t codec_queue_send(long id, intptr_t data)
return queue_send(&codec_queue, id, data);
}
/* Poll the state of the codec queue. Returns < 0 if the message is urgent
and any state should exit, > 0 if it's a run message (and it was
scrubbed), 0 if message was ignored. */
static int codec_check_queue__have_msg(void)
{
struct queue_event ev;
queue_peek(&codec_queue, &ev);
/* Seek, pause or stop? Just peek and return if so. Codec
must handle the command after returing. Inserts will not
be allowed until it complies. */
switch (ev.id)
{
case Q_CODEC_SEEK:
LOGFQUEUE("codec - Q_CODEC_SEEK", ev.id);
return -1;
case Q_CODEC_PAUSE:
LOGFQUEUE("codec - Q_CODEC_PAUSE", ev.id);
return -1;
case Q_CODEC_STOP:
LOGFQUEUE("codec - Q_CODEC_STOP", ev.id);
return -1;
}
/* This is in error in this context unless it's "go, go, go!" */
queue_wait(&codec_queue, &ev);
if (ev.id == Q_CODEC_RUN)
{
logf("codec < Q_CODEC_RUN: already running!");
codec_queue_ack(Q_CODEC_RUN);
return 1;
}
/* Ignore it */
logf("codec < bad req %ld (%s)", ev.id, __func__);
codec_queue_ack(Q_NULL);
return 0;
}
/* Does the audio format type equal CODEC_TYPE_ENCODER? */
static inline bool type_is_encoder(int afmt)
{
#ifdef AUDIO_HAVE_RECORDING
return (afmt & CODEC_TYPE_MASK) == CODEC_TYPE_ENCODER;
#else
return false;
(void)afmt;
#endif
}
/**************************************/
/** misc external functions */
/* Used to check whether a new codec must be loaded. See array audio_formats[]
* in metadata.c */
int get_codec_base_type(int type)
{
int base_type = type;
switch (type) {
case AFMT_MPA_L1:
case AFMT_MPA_L2:
case AFMT_MPA_L3:
base_type = AFMT_MPA_L3;
break;
case AFMT_MPC_SV7:
case AFMT_MPC_SV8:
base_type = AFMT_MPC_SV7;
break;
case AFMT_MP4_AAC:
case AFMT_MP4_AAC_HE:
base_type = AFMT_MP4_AAC;
break;
case AFMT_SAP:
case AFMT_CMC:
case AFMT_CM3:
case AFMT_CMR:
case AFMT_CMS:
case AFMT_DMC:
case AFMT_DLT:
case AFMT_MPT:
case AFMT_MPD:
case AFMT_RMT:
case AFMT_TMC:
case AFMT_TM8:
case AFMT_TM2:
base_type = AFMT_SAP;
break;
default:
break;
}
return base_type;
}
/** --- Miscellaneous external functions --- **/
const char * get_codec_filename(int cod_spec)
{
const char *fname;
@ -173,7 +190,7 @@ const char *get_codec_filename(int cod_spec)
#endif /* HAVE_RECORDING */
return fname;
} /* get_codec_filename */
}
/* Borrow the codec thread and return the ID */
void codec_thread_do_callback(void (*fn)(void), unsigned int *id)
@ -189,7 +206,7 @@ void codec_thread_do_callback(void (*fn)(void), unsigned int *id)
}
/** codec API callbacks */
/** --- codec API callbacks --- **/
static void * codec_get_buffer(size_t *size)
{
@ -215,15 +232,19 @@ static void codec_pcmbuf_insert_callback(
int inp_count;
char *dest;
/* Prevent audio from a previous track from playing */
if (ci.new_track || ci.stop_codec)
return;
while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
while (1)
{
if ((dest = pcmbuf_request_buffer(&out_count)) != NULL)
break;
cancel_cpu_boost();
sleep(1);
if (ci.seek_time || ci.new_track || ci.stop_codec)
/* It will be awhile before space is available but we want
"instant" response to any message */
queue_wait_w_tmo(&codec_queue, NULL, HZ/20);
if (!queue_empty(&codec_queue) &&
codec_check_queue__have_msg() < 0)
return;
}
@ -247,62 +268,28 @@ static void codec_pcmbuf_insert_callback(
count -= inp_count;
}
} /* codec_pcmbuf_insert_callback */
static void codec_set_elapsed_callback(unsigned long value)
{
if (ci.seek_time)
return;
#ifdef AB_REPEAT_ENABLE
ab_position_report(value);
#endif
unsigned long latency = pcmbuf_get_latency();
if (value < latency)
thistrack_id3->elapsed = 0;
else
{
unsigned long elapsed = value - latency;
if (elapsed > thistrack_id3->elapsed ||
elapsed < thistrack_id3->elapsed - 2)
{
thistrack_id3->elapsed = elapsed;
}
}
}
static void codec_set_offset_callback(size_t value)
{
if (ci.seek_time)
return;
unsigned long latency = pcmbuf_get_latency() * thistrack_id3->bitrate / 8;
if (value < latency)
thistrack_id3->offset = 0;
else
thistrack_id3->offset = value - latency;
}
/* helper function, not a callback */
static void codec_advance_buffer_counters(size_t amount)
static bool codec_advance_buffer_counters(size_t amount)
{
bufadvance(get_audio_hid(), amount);
if (bufadvance(ci.audio_hid, amount) < 0)
{
ci.curpos = ci.filesize;
return false;
}
ci.curpos += amount;
return true;
}
/* copy up-to size bytes into ptr and return the actual size copied */
static size_t codec_filebuf_callback(void *ptr, size_t size)
{
ssize_t copy_n;
if (ci.stop_codec)
return 0;
copy_n = bufread(get_audio_hid(), size, ptr);
ssize_t copy_n = bufread(ci.audio_hid, size, ptr);
/* Nothing requested OR nothing left */
if (copy_n == 0)
if (copy_n <= 0)
return 0;
/* Update read and other position pointers */
@ -310,7 +297,7 @@ static size_t codec_filebuf_callback(void *ptr, size_t size)
/* Return the actual amount of data copied to the buffer */
return copy_n;
} /* codec_filebuf_callback */
}
static void * codec_request_buffer_callback(size_t *realsize, size_t reqsize)
{
@ -318,7 +305,7 @@ static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
ssize_t ret;
void *ptr;
ret = bufgetdata(get_audio_hid(), reqsize, &ptr);
ret = bufgetdata(ci.audio_hid, reqsize, &ptr);
if (ret >= 0)
copy_n = MIN((size_t)ret, reqsize);
else
@ -329,101 +316,103 @@ static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
*realsize = copy_n;
return ptr;
} /* codec_request_buffer_callback */
}
static void codec_advance_buffer_callback(size_t amount)
{
codec_advance_buffer_counters(amount);
codec_set_offset_callback(ci.curpos);
if (!codec_advance_buffer_counters(amount))
return;
audio_codec_update_offset(ci.curpos);
}
static bool codec_seek_buffer_callback(size_t newpos)
{
logf("codec_seek_buffer_callback");
int ret = bufseek(get_audio_hid(), newpos);
if (ret == 0) {
int ret = bufseek(ci.audio_hid, newpos);
if (ret == 0)
{
ci.curpos = newpos;
return true;
}
else {
return false;
}
}
static void codec_seek_complete_callback(void)
{
struct queue_event ev;
logf("seek_complete");
/* Clear DSP */
dsp_configure(ci.dsp, DSP_FLUSH, 0);
/* Post notification to audio thread */
LOGFQUEUE("audio > Q_AUDIO_SEEK_COMPLETE");
queue_post(&audio_queue, Q_AUDIO_SEEK_COMPLETE, 0);
LOGFQUEUE("audio > Q_AUDIO_CODEC_SEEK_COMPLETE");
audio_queue_post(Q_AUDIO_CODEC_SEEK_COMPLETE, 0);
/* Wait for ACK */
queue_wait(&codec_queue, &ev);
/* ACK back in context */
codec_queue_ack(Q_AUDIO_SEEK_COMPLETE);
}
static bool codec_request_next_track_callback(void)
/* Wait for urgent or go message */
do
{
struct queue_event ev;
logf("Request new track");
audio_set_prev_elapsed(thistrack_id3->elapsed);
#ifdef AB_REPEAT_ENABLE
ab_end_of_track_report();
#endif
if (ci.stop_codec)
{
/* Handle ACK in outer loop */
LOGFQUEUE("codec: already stopping");
return false;
queue_wait(&codec_queue, NULL);
}
trigger_cpu_boost();
/* Post request to audio thread */
LOGFQUEUE("codec > audio Q_AUDIO_CHECK_NEW_TRACK");
queue_post(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0);
/* Wait for ACK */
queue_wait(&codec_queue, &ev);
if (ev.data == Q_CODEC_REQUEST_COMPLETE)
{
/* Seek to the beginning of the new track because if the struct
mp3entry was buffered, "elapsed" might not be zero (if the track has
been played already but not unbuffered) */
codec_seek_buffer_callback(thistrack_id3->first_frame_offset);
}
/* ACK back in context */
codec_queue_ack(Q_AUDIO_CHECK_NEW_TRACK);
if (ev.data != Q_CODEC_REQUEST_COMPLETE || ci.stop_codec)
{
LOGFQUEUE("codec <= request failed (%d)", ev.data);
return false;
}
LOGFQUEUE("codec <= Q_CODEC_REQEST_COMPLETE");
return true;
while (codec_check_queue__have_msg() == 0);
}
static void codec_configure_callback(int setting, intptr_t value)
{
if (!dsp_configure(ci.dsp, setting, value))
{ logf("Illegal key:%d", setting); }
{
logf("Illegal key: %d", setting);
}
}
static enum codec_command_action
codec_get_command_callback(intptr_t *param)
{
yield();
if (LIKELY(queue_empty(&codec_queue)))
return CODEC_ACTION_NULL; /* As you were */
/* Process the message - return requested action and data (if any should
be expected) */
while (1)
{
enum codec_command_action action = CODEC_ACTION_NULL;
struct queue_event ev;
queue_wait(&codec_queue, &ev);
switch (ev.id)
{
case Q_CODEC_RUN: /* Already running */
LOGFQUEUE("codec < Q_CODEC_RUN");
break;
case Q_CODEC_PAUSE: /* Stay here and wait */
LOGFQUEUE("codec < Q_CODEC_PAUSE");
codec_queue_ack(Q_CODEC_PAUSE);
continue;
case Q_CODEC_SEEK: /* Audio wants codec to seek */
LOGFQUEUE("codec < Q_CODEC_SEEK %ld", ev.data);
*param = ev.data;
action = CODEC_ACTION_SEEK_TIME;
break;
case Q_CODEC_STOP: /* Must only return 0 in main loop */
LOGFQUEUE("codec < Q_CODEC_STOP");
action = CODEC_ACTION_HALT;
break;
default: /* This is in error in this context. */
ev.id = Q_NULL;
logf("codec bad req %ld (%s)", ev.id, __func__);
}
codec_queue_ack(ev.id);
return action;
}
}
/* Initialize codec API */
@ -433,119 +422,215 @@ void codec_init_codec_api(void)
CODEC_IDX_AUDIO);
ci.codec_get_buffer = codec_get_buffer;
ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
ci.set_elapsed = codec_set_elapsed_callback;
ci.set_elapsed = audio_codec_update_elapsed;
ci.read_filebuf = codec_filebuf_callback;
ci.request_buffer = codec_request_buffer_callback;
ci.advance_buffer = codec_advance_buffer_callback;
ci.seek_buffer = codec_seek_buffer_callback;
ci.seek_complete = codec_seek_complete_callback;
ci.request_next_track = codec_request_next_track_callback;
ci.set_offset = codec_set_offset_callback;
ci.set_offset = audio_codec_update_offset;
ci.configure = codec_configure_callback;
ci.get_command = codec_get_command_callback;
}
/* track change */
/** --- CODEC THREAD --- **/
/** CODEC THREAD */
static void codec_thread(void)
/* Handle Q_CODEC_LOAD */
static void load_codec(const struct codec_load_info *ev_data)
{
int status = CODEC_ERROR;
/* Save a local copy so we can let the audio thread go ASAP */
struct codec_load_info data = *ev_data;
bool const encoder = type_is_encoder(data.afmt);
if (codec_type != AFMT_UNKNOWN)
{
/* Must have unloaded it first */
logf("a codec is already loaded");
if (data.hid >= 0)
bufclose(data.hid);
return;
}
trigger_cpu_boost();
if (!encoder)
{
/* Do this now because codec may set some things up at load time */
dsp_configure(ci.dsp, DSP_RESET, 0);
}
if (data.hid >= 0)
{
/* First try buffer load */
status = codec_load_buf(data.hid, &ci);
bufclose(data.hid);
}
if (status < 0)
{
/* Either not a valid handle or the buffer method failed */
const char *codec_fn = get_codec_filename(data.afmt);
if (codec_fn)
{
#ifdef HAVE_IO_PRIORITY
buf_back_off_storage(true);
#endif
status = codec_load_file(codec_fn, &ci);
#ifdef HAVE_IO_PRIORITY
buf_back_off_storage(false);
#endif
}
}
if (status >= 0)
{
codec_type = data.afmt;
codec_queue_ack(Q_CODEC_LOAD);
return;
}
/* Failed - get rid of it */
unload_codec();
}
/* Handle Q_CODEC_RUN */
static void run_codec(void)
{
bool const encoder = type_is_encoder(codec_type);
int status;
if (codec_type == AFMT_UNKNOWN)
{
logf("no codec to run");
return;
}
codec_queue_ack(Q_CODEC_RUN);
trigger_cpu_boost();
if (!encoder)
{
/* This will be either the initial buffered offset or where it left off
if it remained buffered and we're skipping back to it and it is best
to have ci.curpos in sync with the handle's read position - it's the
codec's responsibility to ensure it has the correct positions -
playback is sorta dumb and only has a vague idea about what to
buffer based upon what metadata has to say */
ci.curpos = bufftell(ci.audio_hid);
/* Pin the codec's audio data in place */
buf_pin_handle(ci.audio_hid, true);
}
status = codec_run_proc();
if (!encoder)
{
/* Codec is done with it - let it move */
buf_pin_handle(ci.audio_hid, false);
/* Notify audio that we're done for better or worse - advise of the
status */
LOGFQUEUE("codec > audio Q_AUDIO_CODEC_COMPLETE: %d", status);
audio_queue_post(Q_AUDIO_CODEC_COMPLETE, status);
}
}
/* Handle Q_CODEC_SEEK */
static void seek_codec(unsigned long time)
{
if (codec_type == AFMT_UNKNOWN)
{
logf("no codec to seek");
codec_queue_ack(Q_CODEC_SEEK);
codec_seek_complete_callback();
return;
}
/* Post it up one level */
queue_post(&codec_queue, Q_CODEC_SEEK, time);
codec_queue_ack(Q_CODEC_SEEK);
/* Have to run it again */
run_codec();
}
/* Handle Q_CODEC_UNLOAD */
static void unload_codec(void)
{
/* Tell codec to clean up */
codec_type = AFMT_UNKNOWN;
codec_close();
}
/* Handle Q_CODEC_DO_CALLBACK */
static void do_callback(void (* callback)(void))
{
codec_queue_ack(Q_CODEC_DO_CALLBACK);
if (callback)
{
cpucache_commit_discard();
callback();
cpucache_commit();
}
}
/* Codec thread function */
static void NORETURN_ATTR codec_thread(void)
{
struct queue_event ev;
while (1)
{
int status = CODEC_OK;
void *handle = NULL;
int hid;
const char *codec_fn;
#ifdef HAVE_CROSSFADE
if (!pcmbuf_is_crossfade_active())
#endif
{
cancel_cpu_boost();
}
queue_wait(&codec_queue, &ev);
switch (ev.id)
{
case Q_CODEC_LOAD_DISK:
LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
codec_fn = get_codec_filename(ev.data);
if (!codec_fn)
break;
#ifdef AUDIO_HAVE_RECORDING
if (ev.data & CODEC_TYPE_ENCODER)
{
ev.id = Q_ENCODER_LOAD_DISK;
handle = codec_load_file(codec_fn, &ci);
if (handle)
codec_queue_ack(Q_ENCODER_LOAD_DISK);
}
else
#endif
{
codec_queue_ack(Q_CODEC_LOAD_DISK);
handle = codec_load_file(codec_fn, &ci);
}
break;
case Q_CODEC_LOAD:
LOGFQUEUE("codec < Q_CODEC_LOAD");
codec_queue_ack(Q_CODEC_LOAD);
hid = (int)ev.data;
handle = codec_load_buf(hid, &ci);
bufclose(hid);
load_codec((const struct codec_load_info *)ev.data);
break;
case Q_CODEC_RUN:
LOGFQUEUE("codec < Q_CODEC_RUN");
run_codec();
break;
case Q_CODEC_PAUSE:
LOGFQUEUE("codec < Q_CODEC_PAUSE");
break;
case Q_CODEC_SEEK:
LOGFQUEUE("codec < Q_CODEC_SEEK: %lu", (unsigned long)ev.data);
seek_codec(ev.data);
break;
case Q_CODEC_UNLOAD:
LOGFQUEUE("codec < Q_CODEC_UNLOAD");
unload_codec();
break;
case Q_CODEC_DO_CALLBACK:
LOGFQUEUE("codec < Q_CODEC_DO_CALLBACK");
codec_queue_ack(Q_CODEC_DO_CALLBACK);
if ((void*)ev.data != NULL)
{
cpucache_commit_discard();
((void (*)(void))ev.data)();
cpucache_commit();
}
do_callback((void (*)(void))ev.data);
break;
default:
LOGFQUEUE("codec < default : %ld", ev.id);
}
if (handle)
{
/* Codec loaded - call the entrypoint */
yield();
logf("codec running");
status = codec_begin(handle);
logf("codec stopped");
codec_close(handle);
current_codectype = AFMT_UNKNOWN;
if (ci.stop_codec)
status = CODEC_OK;
}
switch (ev.id)
{
#ifdef AUDIO_HAVE_RECORDING
case Q_ENCODER_LOAD_DISK:
#endif
case Q_CODEC_LOAD_DISK:
case Q_CODEC_LOAD:
/* Notify about the status */
if (!handle)
status = CODEC_ERROR;
LOGFQUEUE("codec > audio notify status: %d", status);
queue_post(&audio_queue, ev.id, status);
break;
}
}
}
/** --- Miscellaneous external interfaces -- **/
/* Create the codec thread and init kernel objects */
void make_codec_thread(void)
{
queue_init(&codec_queue, false);
@ -558,78 +643,86 @@ void make_codec_thread(void)
codec_thread_id);
}
/* Unfreeze the codec thread */
void codec_thread_resume(void)
{
thread_thaw(codec_thread_id);
}
/* Is the current thread the codec thread? */
bool is_codec_thread(void)
{
return thread_self() == codec_thread_id;
}
#ifdef HAVE_PRIORITY_SCHEDULING
/* Obtain codec thread's current priority */
int codec_thread_get_priority(void)
{
return thread_get_priority(codec_thread_id);
}
/* Set the codec thread's priority and return the old value */
int codec_thread_set_priority(int priority)
{
return thread_set_priority(codec_thread_id, priority);
}
#endif /* HAVE_PRIORITY_SCHEDULING */
/* functions for audio thread use */
intptr_t codec_ack_msg(intptr_t data, bool stop_codec)
{
intptr_t resp;
LOGFQUEUE("codec >| Q_CODEC_ACK: %d", data);
if (stop_codec)
ci.stop_codec = true;
resp = codec_queue_send(Q_CODEC_ACK, data);
if (stop_codec)
codec_stop();
LOGFQUEUE(" ack: %ld", resp);
return resp;
}
/** --- Functions for audio thread use --- **/
/* Load a decoder or encoder and set the format type */
bool codec_load(int hid, int cod_spec)
{
bool retval = false;
struct codec_load_info parm = { hid, cod_spec };
ci.stop_codec = false;
current_codectype = cod_spec;
LOGFQUEUE("audio >| codec Q_CODEC_LOAD: %d, %d", hid, cod_spec);
return codec_queue_send(Q_CODEC_LOAD, (intptr_t)&parm) != 0;
}
if (hid >= 0)
/* Begin decoding the current file */
void codec_go(void)
{
LOGFQUEUE("audio >| codec Q_CODEC_LOAD: %d", hid);
retval = codec_queue_send(Q_CODEC_LOAD, hid) != Q_NULL;
LOGFQUEUE("audio >| codec Q_CODEC_RUN");
codec_queue_send(Q_CODEC_RUN, 0);
}
else
/* Instruct the codec to seek to the specified time (should be properly
paused or stopped first to avoid possible buffering deadlock) */
void codec_seek(long time)
{
LOGFQUEUE("audio >| codec Q_CODEC_LOAD_DISK: %d", cod_spec);
retval = codec_queue_send(Q_CODEC_LOAD_DISK, cod_spec) != Q_NULL;
LOGFQUEUE("audio > codec Q_CODEC_SEEK: %ld", time);
codec_queue_send(Q_CODEC_SEEK, time);
}
if (!retval)
/* Pause the codec and make it wait for further instructions inside the
command callback */
bool codec_pause(void)
{
ci.stop_codec = true;
current_codectype = AFMT_UNKNOWN;
}
return retval;
LOGFQUEUE("audio >| codec Q_CODEC_PAUSE");
return codec_queue_send(Q_CODEC_PAUSE, 0) != Q_NULL;
}
/* Stop codec if running - codec stays resident if loaded */
void codec_stop(void)
{
ci.stop_codec = true;
/* Wait until it's in the main loop */
while (codec_ack_msg(0, false) != Q_NULL);
current_codectype = AFMT_UNKNOWN;
LOGFQUEUE("audio >| codec Q_CODEC_STOP");
while (codec_queue_send(Q_CODEC_STOP, 0) != Q_NULL);
}
/* Call the codec's exit routine and close all references */
void codec_unload(void)
{
codec_stop();
LOGFQUEUE("audio >| codec Q_CODEC_UNLOAD");
codec_queue_send(Q_CODEC_UNLOAD, 0);
}
/* Return the afmt type of the loaded codec - sticks until calling
codec_unload unless initial load failed */
int codec_loaded(void)
{
return current_codectype;
return codec_type;
}

View file

@ -25,7 +25,6 @@
#include <stdbool.h>
/* codec identity */
int get_codec_base_type(int type);
const char *get_codec_filename(int cod_spec);
/* codec thread */
@ -44,10 +43,14 @@ int codec_thread_set_priority(int priority);
#endif
/* codec commands - on audio thread only! */
intptr_t codec_ack_msg(intptr_t data, bool stop_codec);
bool codec_load(int hid, int cod_spec);
void codec_go(void);
bool codec_pause(void);
void codec_seek(long time);
void codec_stop(void);
void codec_unload(void);
int codec_loaded(void);
/* */
#endif /* _CODEC_THREAD_H */

View file

@ -82,10 +82,7 @@ struct codec_api ci = {
0, /* filesize */
0, /* curpos */
NULL, /* id3 */
NULL, /* taginfo_ready */
false, /* stop_codec */
0, /* new_track */
0, /* seek_time */
ERR_HANDLE_NOT_FOUND, /* audio_hid */
NULL, /* struct dsp_config *dsp */
NULL, /* codec_get_buffer */
NULL, /* pcmbuf_insert */
@ -95,9 +92,9 @@ struct codec_api ci = {
NULL, /* advance_buffer */
NULL, /* seek_buffer */
NULL, /* seek_complete */
NULL, /* request_next_track */
NULL, /* set_offset */
NULL, /* configure */
NULL, /* get_command */
/* kernel/ system */
#if defined(CPU_ARM) && CONFIG_PLATFORM & PLATFORM_NATIVE
@ -174,10 +171,16 @@ void codec_get_full_path(char *path, const char *codec_root_fn)
CODECS_DIR, codec_root_fn);
}
static void * codec_load_ram(void *handle, struct codec_api *api)
/** codec loading and call interface **/
static void *curr_handle = NULL;
static struct codec_header *c_hdr = NULL;
static int codec_load_ram(struct codec_api *api)
{
struct codec_header *c_hdr = lc_get_header(handle);
struct lc_header *hdr = c_hdr ? &c_hdr->lc_hdr : NULL;
struct lc_header *hdr;
c_hdr = lc_get_header(curr_handle);
hdr = c_hdr ? &c_hdr->lc_hdr : NULL;
if (hdr == NULL
|| (hdr->magic != CODEC_MAGIC
@ -193,15 +196,17 @@ static void * codec_load_ram(void *handle, struct codec_api *api)
)
{
logf("codec header error");
lc_close(handle);
return NULL;
lc_close(curr_handle);
curr_handle = NULL;
return CODEC_ERROR;
}
if (hdr->api_version > CODEC_API_VERSION
|| hdr->api_version < CODEC_MIN_API_VERSION) {
logf("codec api version error");
lc_close(handle);
return NULL;
lc_close(curr_handle);
curr_handle = NULL;
return CODEC_ERROR;
}
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
@ -212,63 +217,66 @@ static void * codec_load_ram(void *handle, struct codec_api *api)
*(c_hdr->api) = api;
return handle;
logf("Codec: calling entrypoint");
return c_hdr->entry_point(CODEC_LOAD);
}
void * codec_load_buf(int hid, struct codec_api *api)
int codec_load_buf(int hid, struct codec_api *api)
{
int rc;
void *handle;
rc = bufread(hid, CODEC_SIZE, codecbuf);
int rc = bufread(hid, CODEC_SIZE, codecbuf);
if (rc < 0) {
logf("Codec: cannot read buf handle");
return NULL;
return CODEC_ERROR;
}
handle = lc_open_from_mem(codecbuf, rc);
curr_handle = lc_open_from_mem(codecbuf, rc);
if (handle == NULL) {
logf("error loading codec");
return NULL;
if (curr_handle == NULL) {
logf("Codec: load error");
return CODEC_ERROR;
}
return codec_load_ram(handle, api);
return codec_load_ram(api);
}
void * codec_load_file(const char *plugin, struct codec_api *api)
int codec_load_file(const char *plugin, struct codec_api *api)
{
char path[MAX_PATH];
void *handle;
codec_get_full_path(path, plugin);
handle = lc_open(path, codecbuf, CODEC_SIZE);
curr_handle = lc_open(path, codecbuf, CODEC_SIZE);
if (handle == NULL) {
if (curr_handle == NULL) {
logf("Codec: cannot read file");
return NULL;
return CODEC_ERROR;
}
return codec_load_ram(handle, api);
return codec_load_ram(api);
}
int codec_begin(void *handle)
int codec_run_proc(void)
{
int status = CODEC_ERROR;
struct codec_header *c_hdr;
if (curr_handle == NULL) {
logf("Codec: no codec to run");
return CODEC_ERROR;
}
c_hdr = lc_get_header(handle);
logf("Codec: entering run state");
return c_hdr->run_proc();
}
if (c_hdr != NULL) {
logf("Codec: calling entry_point");
status = c_hdr->entry_point();
int codec_close(void)
{
int status = CODEC_OK;
if (curr_handle != NULL) {
logf("Codec: cleaning up");
status = c_hdr->entry_point(CODEC_UNLOAD);
lc_close(curr_handle);
curr_handle = NULL;
}
return status;
}
void codec_close(void *handle)
{
if (handle)
lc_close(handle);
}

View file

@ -75,12 +75,18 @@
#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */
/* increase this every time the api struct changes */
#define CODEC_API_VERSION 41
#define CODEC_API_VERSION 42
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
#define CODEC_MIN_API_VERSION 41
#define CODEC_MIN_API_VERSION 42
/* reasons for calling codec main entrypoint */
enum codec_entry_call_reason {
CODEC_LOAD = 0,
CODEC_UNLOAD
};
/* codec return codes */
enum codec_status {
@ -88,6 +94,13 @@ enum codec_status {
CODEC_ERROR = -1,
};
/* codec command action codes */
enum codec_command_action {
CODEC_ACTION_HALT = -1,
CODEC_ACTION_NULL = 0,
CODEC_ACTION_SEEK_TIME = 1,
};
/* NOTE: To support backwards compatibility, only add new functions at
the end of the structure. Every time you add a new function,
remember to increase CODEC_API_VERSION. If you make changes to the
@ -95,23 +108,11 @@ enum codec_status {
version
*/
struct codec_api {
off_t filesize; /* Total file length */
off_t curpos; /* Current buffer position */
/* For gapless mp3 */
struct mp3entry *id3; /* TAG metadata pointer */
bool *taginfo_ready; /* Is metadata read */
/* Codec should periodically check if stop_codec is set to true.
In case it is, codec must return immediately */
volatile bool stop_codec;
/* Codec should periodically check if new_track is non zero.
When it is, the codec should request a new track. */
volatile int new_track;
/* If seek_time != 0, codec should seek to that song position (in ms)
if codec supports seeking. */
volatile long seek_time;
int audio_hid; /* Current audio handle */
/* The dsp instance to be used for audio output */
struct dsp_config *dsp;
@ -138,14 +139,12 @@ struct codec_api {
bool (*seek_buffer)(size_t newpos);
/* Codec should call this function when it has done the seeking. */
void (*seek_complete)(void);
/* Request file change from file buffer. Returns true is next
track is available and changed. If return value is false,
codec should exit immediately with PLUGIN_OK status. */
bool (*request_next_track)(void);
/* Update the current position */
void (*set_offset)(size_t value);
/* Configure different codec buffer parameters. */
void (*configure)(int setting, intptr_t value);
/* Obtain command action on what to do next */
enum codec_command_action (*get_command)(intptr_t *param);
/* kernel/ system */
#if defined(CPU_ARM) && CONFIG_PLATFORM & PLATFORM_NATIVE
@ -231,7 +230,8 @@ struct codec_api {
/* codec header */
struct codec_header {
struct lc_header lc_hdr; /* must be first */
enum codec_status(*entry_point)(void);
enum codec_status(*entry_point)(enum codec_entry_call_reason reason);
enum codec_status(*run_proc)(void);
struct codec_api **api;
};
@ -248,13 +248,15 @@ extern unsigned char plugin_end_addr[];
const struct codec_header __header \
__attribute__ ((section (".header")))= { \
{ CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
plugin_start_addr, plugin_end_addr }, codec_start, &ci };
plugin_start_addr, plugin_end_addr }, codec_start, \
codec_run, &ci };
/* encoders */
#define CODEC_ENC_HEADER \
const struct codec_header __header \
__attribute__ ((section (".header")))= { \
{ CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
plugin_start_addr, plugin_end_addr }, codec_start, &ci };
plugin_start_addr, plugin_end_addr }, codec_start, \
codec_run, &ci };
#else /* def SIMULATOR */
/* decoders */
@ -262,12 +264,12 @@ extern unsigned char plugin_end_addr[];
const struct codec_header __header \
__attribute__((visibility("default"))) = { \
{ CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \
codec_start, &ci };
codec_start, codec_run, &ci };
/* encoders */
#define CODEC_ENC_HEADER \
const struct codec_header __header = { \
{ CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \
codec_start, &ci };
codec_start, codec_run, &ci };
#endif /* SIMULATOR */
#endif /* CODEC */
@ -276,13 +278,14 @@ extern unsigned char plugin_end_addr[];
void codec_get_full_path(char *path, const char *codec_root_fn);
/* defined by the codec loader (codec.c) */
void * codec_load_buf(int hid, struct codec_api *api);
void * codec_load_file(const char* codec, struct codec_api *api);
int codec_begin(void *handle);
void codec_close(void *handle);
int codec_load_buf(int hid, struct codec_api *api);
int codec_load_file(const char* codec, struct codec_api *api);
int codec_run_proc(void);
int codec_halt(void);
int codec_close(void);
/* defined by the codec */
enum codec_status codec_start(void);
enum codec_status codec_main(void);
enum codec_status codec_start(enum codec_entry_call_reason reason);
enum codec_status codec_run(void);
#endif
#endif /* _CODECS_H_ */

View file

@ -116,27 +116,31 @@ static void a52_decode_data(uint8_t *start, uint8_t *end)
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
}
else if (reason == CODEC_UNLOAD) {
if (state)
a52_free(state);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
size_t n;
unsigned char *filebuf;
int sample_loc;
int retval;
intptr_t param;
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
next_track:
retval = CODEC_OK;
if (codec_init()) {
retval = CODEC_ERROR;
goto exit;
}
if (codec_wait_taginfo() != 0)
goto request_next_track;
if (codec_init())
return CODEC_ERROR;
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
codec_set_replaygain(ci->id3);
@ -153,15 +157,18 @@ next_track:
}
}
else {
ci->seek_buffer(ci->id3->first_frame_offset);
samplesdone = 0;
}
while (1) {
if (ci->stop_codec || ci->new_track)
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (ci->seek_time) {
sample_loc = (ci->seek_time - 1)/1000 * ci->id3->frequency;
if (action == CODEC_ACTION_SEEK_TIME) {
sample_loc = param/1000 * ci->id3->frequency;
if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*ci->id3->bytesperframe)) {
samplesdone = sample_loc;
@ -179,11 +186,5 @@ next_track:
ci->advance_buffer(n);
}
request_next_track:
if (ci->request_next_track())
goto next_track;
exit:
a52_free(state);
return retval;
return CODEC_OK;
}

View file

@ -124,36 +124,44 @@ static void a52_decode_data(uint8_t *start, uint8_t *end)
}
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
size_t n;
uint8_t *filebuf;
int retval, consumed, packet_offset;
int playback_on = -1;
size_t resume_offset;
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
next_track:
retval = CODEC_OK;
if (codec_init()) {
retval = CODEC_ERROR;
goto exit;
}
else if (reason == CODEC_UNLOAD) {
if (state)
a52_free(state);
}
if (codec_wait_taginfo() != 0)
goto request_next_track;
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
size_t n;
uint8_t *filebuf;
int consumed, packet_offset;
int playback_on = -1;
size_t resume_offset;
intptr_t param;
enum codec_command_action action = CODEC_ACTION_NULL;
if (codec_init()) {
return CODEC_ERROR;
}
resume_offset = ci->id3->offset;
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
codec_set_replaygain(ci->id3);
ci->seek_buffer(ci->id3->first_frame_offset);
/* Intializations */
state = a52_init(0);
ci->memset(&rmctx,0,sizeof(RMContext));
@ -165,26 +173,34 @@ next_track:
resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
/* put number of subpackets to skip in resume_offset */
resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE);
ci->seek_time = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
action = CODEC_ACTION_SEEK_TIME;
}
else {
/* Seek to the first packet */
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE );
}
/* The main decoding loop */
while((unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) {
ci->yield();
if (ci->stop_codec || ci->new_track)
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (ci->seek_time) {
packet_offset = ci->seek_time / ((rmctx.block_align*8*1000)/rmctx.bit_rate);
ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE));
if (action == CODEC_ACTION_SEEK_TIME) {
packet_offset = param / ((rmctx.block_align*8*1000)/rmctx.bit_rate);
ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE +
packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE));
rmctx.audio_pkt_cnt = packet_offset;
samplesdone = (rmctx.sample_rate/1000 * ci->seek_time);
samplesdone = (rmctx.sample_rate/1000 * param);
ci->set_elapsed(samplesdone/(frequency/1000));
ci->seek_complete();
}
action = CODEC_ACTION_NULL;
filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE);
consumed = rm_get_packet(&filebuf, &rmctx, &pkt);
@ -195,8 +211,7 @@ next_track:
return CODEC_ERROR;
}
else {
retval = CODEC_OK;
goto exit;
break;
}
}
@ -205,11 +220,5 @@ next_track:
ci->advance_buffer(pkt.length);
}
request_next_track:
if (ci->request_next_track())
goto next_track;
exit:
a52_free(state);
return retval;
return CODEC_OK;
}

View file

@ -33,7 +33,19 @@ CODEC_HEADER
#define FAAD_BYTE_BUFFER_SIZE (2048-12)
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
/* Note that when dealing with QuickTime/MPEG4 files, terminology is
* a bit confusing. Files with sound are split up in chunks, where
@ -59,25 +71,15 @@ enum codec_status codec_main(void)
uint32_t sbr_fac = 1;
unsigned char c = 0;
void *ret;
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
next_track:
err = CODEC_OK;
intptr_t param;
/* Clean and initialize decoder structures */
memset(&demux_res , 0, sizeof(demux_res));
if (codec_init()) {
LOGF("FAAD: Codec init error\n");
err = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
file_offset = ci->id3->offset;
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@ -85,12 +87,13 @@ next_track:
stream_create(&input_stream,ci);
ci->seek_buffer(ci->id3->first_frame_offset);
/* if qtmovie_read returns successfully, the stream is up to
* the movie data, which can be used directly by the decoder */
if (!qtmovie_read(&input_stream, &demux_res)) {
LOGF("FAAD: File init error\n");
err = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* initialise the sound converter */
@ -98,8 +101,7 @@ next_track:
if (!decoder) {
LOGF("FAAD: Decode open error\n");
err = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder);
@ -109,8 +111,7 @@ next_track:
err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c);
if (err) {
LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type);
err = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
#ifdef SBR_DEC
@ -150,20 +151,19 @@ next_track:
/* The main decoding loop */
while (i < demux_res.num_sample_byte_sizes) {
ci->yield();
enum codec_command_action action = ci->get_command(&param);
if (ci->stop_codec || ci->new_track) {
if (action == CODEC_ACTION_HALT)
break;
}
/* Deal with any pending seek requests */
if (ci->seek_time) {
if (action == CODEC_ACTION_SEEK_TIME) {
/* Seek to the desired time position. Important: When seeking in SBR
* upsampling files the seek_time must be divided by 2 when calling
* m4a_seek and the resulting sound_samples_done must be expanded
* by a factor 2. This is done via using sbr_fac. */
if (m4a_seek(&demux_res, &input_stream,
((ci->seek_time-1)/10/sbr_fac)*(ci->id3->frequency/100),
(param/10/sbr_fac)*(ci->id3->frequency/100),
&sound_samples_done, (int*) &i)) {
sound_samples_done *= sbr_fac;
elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
@ -194,8 +194,7 @@ next_track:
else if (file_offset == 0)
{
LOGF("AAC: get_sample_offset error\n");
err = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* Request the required number of bytes from the input buffer */
@ -207,8 +206,7 @@ next_track:
/* NeAACDecDecode may sometimes return NULL without setting error. */
if (ret == NULL || frame_info.error > 0) {
LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error));
err = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* Advance codec buffer (no need to call set_offset because of this) */
@ -251,12 +249,6 @@ next_track:
i++;
}
done:
LOGF("AAC: Decoded %lu samples\n", (unsigned long)sound_samples_done);
if (ci->request_next_track())
goto next_track;
exit:
return err;
return CODEC_OK;
}

View file

@ -45,7 +45,19 @@ static const long cutoff = 500;
static int16_t samples[WAV_CHUNK_SIZE] IBSS_ATTR;
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
/* we only render 16 bits */
ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int channels;
int sampleswritten, i;
@ -62,12 +74,8 @@ enum codec_status codec_main(void)
off_t chanstart, bufoff;
/*long coef1=0x7298L,coef2=-0x3350L;*/
long coef1, coef2;
intptr_t param;
/* Generic codec initialisation */
/* we only render 16 bits */
ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
next_track:
DEBUGF("ADX: next_track\n");
if (codec_init()) {
return CODEC_ERROR;
@ -77,10 +85,6 @@ next_track:
/* init history */
ch1_1=ch1_2=ch2_1=ch2_2=0;
/* wait for track info to load */
if (codec_wait_taginfo() != 0)
goto request_next_track;
codec_set_replaygain(ci->id3);
/* Get header */
@ -226,10 +230,10 @@ next_track:
/* The main decoder loop */
while (!endofstream) {
ci->yield();
if (ci->stop_codec || ci->new_track) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
}
/* do we need to loop? */
if (bufoff > end_adr-18*channels && looping) {
@ -254,17 +258,17 @@ next_track:
}
/* do we need to seek? */
if (ci->seek_time) {
if (action == CODEC_ACTION_SEEK_TIME) {
uint32_t newpos;
DEBUGF("ADX: seek to %ldms\n",ci->seek_time);
DEBUGF("ADX: seek to %ldms\n", (long)param);
endofstream = 0;
loop_count = 0;
fade_count = -1; /* disable fade */
fade_frames = 1;
newpos = (((uint64_t)avgbytespersec*(ci->seek_time - 1))
newpos = (((uint64_t)avgbytespersec*param)
/ (1000LL*18*channels))*(18*channels);
bufoff = chanstart + newpos;
while (bufoff > end_adr-18*channels) {
@ -385,9 +389,5 @@ next_track:
1000LL/avgbytespersec);
}
request_next_track:
if (ci->request_next_track())
goto next_track;
return CODEC_OK;
}

View file

@ -61,9 +61,20 @@ static const struct pcm_codec *get_codec(uint32_t formattag)
return NULL;
}
enum codec_status codec_main(void)
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int status;
struct pcm_format format;
uint32_t bytesdone, decodedsamples;
uint32_t num_sample_frames = 0;
@ -77,38 +88,28 @@ enum codec_status codec_main(void)
bool is_aifc = false;
const struct pcm_codec *codec;
uint32_t size;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
next_track:
status = CODEC_OK;
intptr_t param;
if (codec_init()) {
status = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
bytesdone = ci->id3->offset;
/* assume the AIFF header is less than 1024 bytes */
ci->seek_buffer(0);
buf = ci->request_buffer(&n, 1024);
if (n < 54) {
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (memcmp(buf, "FORM", 4) != 0)
{
DEBUGF("CODEC_ERROR: does not aiff format %4.4s\n", (char*)&buf[0]);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (memcmp(&buf[8], "AIFF", 4) == 0)
is_aifc = false;
@ -117,8 +118,7 @@ next_track:
else
{
DEBUGF("CODEC_ERROR: does not aiff format %4.4s\n", (char*)&buf[8]);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
buf += 12;
@ -141,8 +141,7 @@ next_track:
{
DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu < %d\n",
(unsigned long)size, (is_aifc)?22:18);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* num_channels */
format.channels = ((buf[8]<<8)|buf[9]);
@ -154,8 +153,7 @@ next_track:
/* sample_rate (don't use last 4 bytes, only integer fs) */
if (buf[16] != 0x40) {
DEBUGF("CODEC_ERROR: weird sampling rate (no @)\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
format.samplespersec = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1;
format.samplespersec >>= (16 + 14 - buf[17]);
@ -181,8 +179,7 @@ next_track:
} else if (memcmp(buf, "SSND", 4)==0) {
if (format.bitspersample == 0) {
DEBUGF("CODEC_ERROR: unsupported chunk order\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* offset2snd */
offset2snd = (buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11];
@ -205,21 +202,18 @@ next_track:
buf += size;
if (n < size) {
DEBUGF("CODEC_ERROR: AIFF header size > 1024\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
n -= size;
} /* while 'SSND' */
if (format.channels == 0) {
DEBUGF("CODEC_ERROR: 'COMM' chunk not found or 0-channels file\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (format.numbytes == 0) {
DEBUGF("CODEC_ERROR: 'SSND' chunk not found or has zero length\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
codec = get_codec(format.formattag);
@ -227,14 +221,12 @@ next_track:
{
DEBUGF("CODEC_ERROR: AIFC does not support compressionType: 0x%x\n",
(unsigned int)format.formattag);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (!codec->set_format(&format))
{
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@ -245,21 +237,18 @@ next_track:
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
} else {
DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (format.samplesperblock == 0)
{
DEBUGF("CODEC_ERROR: samplesperblock is 0\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (format.blockalign == 0)
{
DEBUGF("CODEC_ERROR: blockalign is 0\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* check chunksize */
@ -269,8 +258,7 @@ next_track:
if (format.chunksize == 0)
{
DEBUGF("CODEC_ERROR: chunksize is 0\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
firstblockposn = 1024 - n;
@ -283,13 +271,13 @@ next_track:
PCM_SEEK_POS, NULL);
if (newpos->pos > format.numbytes)
goto done;
return CODEC_OK;
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->seek_complete();
} else {
/* already where we need to be */
bytesdone = 0;
@ -299,21 +287,29 @@ next_track:
endofstream = 0;
while (!endofstream) {
ci->yield();
if (ci->stop_codec || ci->new_track)
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (ci->seek_time) {
if (action == CODEC_ACTION_SEEK_TIME) {
/* 3rd args(read_buffer) is unnecessary in the format which AIFF supports. */
struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, NULL);
struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME, NULL);
if (newpos->pos > format.numbytes)
{
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
break;
}
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
ci->seek_complete();
}
aifbuf = (uint8_t *)ci->request_buffer(&n, format.chunksize);
@ -326,11 +322,10 @@ next_track:
endofstream = 1;
}
status = codec->decode(aifbuf, n, samples, &bufcount);
if (status == CODEC_ERROR)
if (codec->decode(aifbuf, n, samples, &bufcount) == CODEC_ERROR)
{
DEBUGF("codec error\n");
goto done;
return CODEC_ERROR;
}
ci->pcmbuf_insert(samples, NULL, bufcount);
@ -343,13 +338,6 @@ next_track:
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
}
status = CODEC_OK;
done:
if (ci->request_next_track())
goto next_track;
exit:
return status;
return CODEC_OK;
}

View file

@ -359,23 +359,32 @@ static bool init_encoder(void)
return true;
} /* init_encoder */
/* main codec entry point */
enum codec_status codec_main(void)
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
if (!init_encoder())
return CODEC_ERROR;
}
else if (reason == CODEC_UNLOAD) {
/* reset parameters to initial state */
ci->enc_set_parameters(NULL);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
/* main encoding loop */
while(!ci->stop_codec)
{
uint32_t *src;
while ((src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL)
while (ci->get_command(NULL) != CODEC_ACTION_HALT)
{
uint32_t *src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE);
struct enc_chunk_hdr *chunk;
if (ci->stop_codec)
break;
if (src == NULL)
continue;
chunk = ci->enc_get_chunk();
chunk->enc_size = enc_size;
@ -385,14 +394,7 @@ enum codec_status codec_main(void)
chunk_to_aiff_format(src, (uint32_t *)chunk->enc_data);
ci->enc_finish_chunk();
ci->yield();
}
ci->yield();
}
/* reset parameters to initial state */
ci->enc_set_parameters(NULL);
return CODEC_OK;
} /* codec_start */
}

View file

@ -32,40 +32,43 @@ CODEC_HEADER
static int32_t outputbuffer[ALAC_MAX_CHANNELS][ALAC_BLOCKSIZE] IBSS_ATTR;
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, ALAC_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
size_t n;
demux_res_t demux_res;
stream_t input_stream;
uint32_t samplesdone;
uint32_t elapsedtime;
uint32_t elapsedtime = 0;
int samplesdecoded;
unsigned int i;
unsigned char* buffer;
alac_file alac;
int retval;
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, ALAC_OUTPUT_DEPTH-1);
next_track:
retval = CODEC_OK;
intptr_t param;
/* Clean and initialize decoder structures */
memset(&demux_res , 0, sizeof(demux_res));
if (codec_init()) {
LOGF("ALAC: Error initialising codec\n");
retval = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
codec_set_replaygain(ci->id3);
ci->seek_buffer(0);
stream_create(&input_stream,ci);
/* Read from ci->id3->offset before calling qtmovie_read. */
@ -76,8 +79,7 @@ enum codec_status codec_main(void)
* the movie data, which can be used directly by the decoder */
if (!qtmovie_read(&input_stream, &demux_res)) {
LOGF("ALAC: Error initialising file\n");
retval = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* initialise the sound converter */
@ -98,19 +100,22 @@ enum codec_status codec_main(void)
/* The main decoding loop */
while (i < demux_res.num_sample_byte_sizes) {
ci->yield();
if (ci->stop_codec || ci->new_track) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
}
/* Request the required number of bytes from the input buffer */
buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE);
/* Deal with any pending seek requests */
if (ci->seek_time) {
if (action == CODEC_ACTION_SEEK_TIME) {
if (m4a_seek(&demux_res, &input_stream,
((ci->seek_time-1)/10) * (ci->id3->frequency/100),
(param/10) * (ci->id3->frequency/100),
&samplesdone, (int *)&i)) {
elapsedtime=(samplesdone*10)/(ci->id3->frequency/100);
ci->set_elapsed(elapsedtime);
}
ci->set_elapsed(elapsedtime);
ci->seek_complete();
}
@ -118,14 +123,13 @@ enum codec_status codec_main(void)
buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE);
/* Decode one block - returned samples will be host-endian */
ci->yield();
samplesdecoded=alac_decode_frame(&alac, buffer, outputbuffer, ci->yield);
ci->yield();
/* Advance codec buffer by amount of consumed bytes */
ci->advance_buffer(alac.bytes_consumed);
/* Output the audio */
ci->yield();
ci->pcmbuf_insert(outputbuffer[0], outputbuffer[1], samplesdecoded);
/* Update the elapsed-time indicator */
@ -136,12 +140,6 @@ enum codec_status codec_main(void)
i++;
}
done:
LOGF("ALAC: Decoded %lu samples\n",(unsigned long)samplesdone);
if (ci->request_next_track())
goto next_track;
exit:
return retval;
return CODEC_OK;
}

View file

@ -127,13 +127,23 @@ static void ape_resume(struct ape_ctx_t* ape_ctx, size_t resume_offset,
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
struct ape_ctx_t ape_ctx;
uint32_t samplesdone;
uint32_t elapsedtime;
size_t bytesleft;
int retval;
uint32_t currentframe;
uint32_t newfilepos;
@ -145,33 +155,24 @@ enum codec_status codec_main(void)
int res;
int firstbyte;
size_t resume_offset;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
next_track:
retval = CODEC_OK;
intptr_t param;
if (codec_init()) {
LOGF("APE: Error initialising codec\n");
retval = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
/* Remember the resume position - when the codec is opened, the
playback engine will reset it. */
resume_offset = ci->id3->offset;
ci->seek_buffer(0);
inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
/* Read the file headers to populate the ape_ctx struct */
if (ape_parseheaderbuf(inbuffer,&ape_ctx) < 0) {
LOGF("APE: Error reading header\n");
retval = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
/* Initialise the seektable for this file */
@ -243,16 +244,16 @@ frame_start:
/* Decode the frame a chunk at a time */
while (nblocks > 0)
{
ci->yield();
if (ci->stop_codec || ci->new_track) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
goto done;
}
/* Deal with any pending seek requests */
if (ci->seek_time)
if (action == CODEC_ACTION_SEEK_TIME)
{
if (ape_calc_seekpos(&ape_ctx,
((ci->seek_time-1)/10) * (ci->id3->frequency/100),
(param/10) * (ci->id3->frequency/100),
&currentframe,
&newfilepos,
&samplestoskip))
@ -266,9 +267,12 @@ frame_start:
ci->seek_buffer(newfilepos);
inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
ci->set_elapsed(elapsedtime);
ci->seek_complete();
goto frame_start; /* Sorry... */
}
ci->seek_complete();
}
@ -281,8 +285,7 @@ frame_start:
{
/* Frame decoding error, abort */
LOGF("APE: Frame %lu, error %d\n",(unsigned long)currentframe,res);
retval = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
ci->yield();
@ -320,10 +323,5 @@ frame_start:
done:
LOGF("APE: Decoded %lu samples\n",(unsigned long)samplesdone);
if (ci->request_next_track())
goto next_track;
exit:
return retval;
return CODEC_OK;
}

View file

@ -29,24 +29,21 @@ CODEC_HEADER
static byte samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */
static ASAP_State asap; /* asap codec state */
/* this is the codec entry point */
enum codec_status codec_main(void)
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int n_bytes;
int song;
int duration;
char* module;
int bytesPerSample =2;
intptr_t param;
next_track:
if (codec_init()) {
DEBUGF("codec init failed\n");
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto request_next_track;
codec_set_replaygain(ci->id3);
int bytes_done =0;
@ -97,19 +94,20 @@ next_track:
/* The main decoder loop */
while (1) {
ci->yield();
if (ci->stop_codec || ci->new_track)
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (ci->seek_time) {
/* New time is ready in ci->seek_time */
if (action == CODEC_ACTION_SEEK_TIME) {
/* New time is ready in param */
/* seek to pos */
ASAP_Seek(&asap,ci->seek_time);
/* update elapsed */
ci->set_elapsed(ci->seek_time);
ASAP_Seek(&asap,param);
/* update bytes_done */
bytes_done = ci->seek_time*44.1*2;
bytes_done = param*44.1*2;
/* update elapsed */
ci->set_elapsed((bytes_done / 2) / 44.1);
/* seek ready */
ci->seek_complete();
}
@ -130,9 +128,5 @@ next_track:
break;
}
request_next_track:
if (ci->request_next_track())
goto next_track;
return CODEC_OK;
}

View file

@ -33,24 +33,22 @@ CODEC_HEADER
static ATRAC3Context q IBSS_ATTR;
/* this is the codec entry point */
enum codec_status codec_main(void)
/* this is called for each file to process */
enum codec_status codec_run(void)
{
static size_t buff_size;
int datasize, res, frame_counter, total_frames, seek_frame_offset;
uint8_t *bit_buffer;
int elapsed = 0;
size_t resume_offset;
intptr_t param;
enum codec_command_action action = CODEC_ACTION_NULL;
next_track:
if (codec_init()) {
DEBUGF("codec init failed\n");
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
resume_offset = ci->id3->offset;
codec_set_replaygain(ci->id3);
@ -61,63 +59,70 @@ next_track:
ci->configure(DSP_SET_STEREO_MODE, ci->id3->channels == 1 ?
STEREO_MONO : STEREO_NONINTERLEAVED);
ci->seek_buffer(0);
res = atrac3_decode_init(&q, ci->id3);
if(res < 0) {
DEBUGF("failed to initialize OMA atrac decoder\n");
return CODEC_ERROR;
}
total_frames = (ci->id3->filesize - ci->id3->first_frame_offset) / FRAMESIZE;
frame_counter = 0;
/* check for a mid-track resume and force a seek time accordingly */
if(resume_offset > ci->id3->first_frame_offset) {
resume_offset -= ci->id3->first_frame_offset;
/* calculate resume_offset in frames */
resume_offset = (int)resume_offset / FRAMESIZE;
ci->seek_time = (int)resume_offset * ((FRAMESIZE * 8)/BITRATE);
param = (int)resume_offset * ((FRAMESIZE * 8)/BITRATE);
action = CODEC_ACTION_SEEK_TIME;
}
total_frames = (ci->id3->filesize - ci->id3->first_frame_offset) / FRAMESIZE;
frame_counter = 0;
else {
ci->set_elapsed(0);
ci->seek_buffer(0);
ci->advance_buffer(ci->id3->first_frame_offset);
ci->seek_buffer(ci->id3->first_frame_offset);
}
/* The main decoder loop */
seek_start :
while(frame_counter < total_frames)
{
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE);
ci->yield();
if (ci->stop_codec || ci->new_track)
goto done;
if (ci->seek_time) {
ci->set_elapsed(ci->seek_time);
if (action == CODEC_ACTION_SEEK_TIME) {
/* Do not allow seeking beyond the file's length */
if ((unsigned) ci->seek_time > ci->id3->length) {
if ((unsigned) param > ci->id3->length) {
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
goto done;
break;
}
/* Seek to the start of the track */
if (ci->seek_time == 1) {
ci->set_elapsed(0);
ci->seek_complete();
ci->seek_buffer(ci->id3->first_frame_offset);
if (param == 0) {
elapsed = 0;
goto seek_start;
ci->set_elapsed(0);
ci->seek_buffer(ci->id3->first_frame_offset);
ci->seek_complete();
action = CODEC_ACTION_NULL;
continue;
}
seek_frame_offset = (ci->seek_time * BITRATE) / (8 * FRAMESIZE);
seek_frame_offset = (param * BITRATE) / (8 * FRAMESIZE);
frame_counter = seek_frame_offset;
ci->seek_buffer(ci->id3->first_frame_offset + seek_frame_offset* FRAMESIZE);
bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE);
elapsed = ci->seek_time;
elapsed = param;
ci->set_elapsed(elapsed);
ci->seek_complete();
}
action = CODEC_ACTION_NULL;
res = atrac3_decode_frame(FRAMESIZE, &q, &datasize, bit_buffer, FRAMESIZE);
if(res != (int)FRAMESIZE) {
@ -126,7 +131,8 @@ seek_start :
}
if(datasize)
ci->pcmbuf_insert(q.outSamples, q.outSamples + 1024, q.samples_per_frame / ci->id3->channels);
ci->pcmbuf_insert(q.outSamples, q.outSamples + 1024,
q.samples_per_frame / ci->id3->channels);
elapsed += (FRAMESIZE * 8) / BITRATE;
ci->set_elapsed(elapsed);
@ -135,9 +141,5 @@ seek_start :
frame_counter++;
}
done:
if (ci->request_next_track())
goto next_track;
return CODEC_OK;
}

View file

@ -41,8 +41,8 @@ static void init_rm(RMContext *rmctx)
memcpy(ci->id3->id3v2buf, (char*)rmctx->codec_extradata, rmctx->extradata_size*sizeof(char));
}
/* this is the codec entry point */
enum codec_status codec_main(void)
/* this is called for each file to process */
enum codec_status codec_run(void)
{
static size_t buff_size;
int datasize, res, consumed, i, time_offset;
@ -52,16 +52,14 @@ enum codec_status codec_main(void)
int scrambling_unit_size, num_units, elapsed = 0;
int playback_on = -1;
size_t resume_offset;
intptr_t param;
enum codec_command_action action = CODEC_ACTION_NULL;
next_track:
if (codec_init()) {
DEBUGF("codec init failed\n");
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
resume_offset = ci->id3->offset;
codec_set_replaygain(ci->id3);
@ -69,6 +67,7 @@ next_track:
ci->memset(&pkt,0,sizeof(RMPacket));
ci->memset(&q,0,sizeof(ATRAC3Context));
ci->seek_buffer(0);
init_rm(&rmctx);
ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
@ -96,10 +95,13 @@ next_track:
num_units = (int)resume_offset / scrambling_unit_size;
/* put number of subpackets to skip in resume_offset */
resume_offset /= (sps + PACKET_HEADER_SIZE);
ci->seek_time = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
action = CODEC_ACTION_SEEK_TIME;
}
else {
ci->set_elapsed(0);
}
ci->set_elapsed(0);
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
/* The main decoder loop */
@ -115,22 +117,23 @@ seek_start :
return CODEC_ERROR;
}
else
goto done;
return CODEC_OK;
}
for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++)
{
ci->yield();
if (ci->stop_codec || ci->new_track)
goto done;
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
if (ci->seek_time) {
ci->set_elapsed(ci->seek_time);
if (action == CODEC_ACTION_HALT)
return CODEC_OK;
if (action == CODEC_ACTION_SEEK_TIME) {
/* Do not allow seeking beyond the file's length */
if ((unsigned) ci->seek_time > ci->id3->length) {
if ((unsigned) param > ci->id3->length) {
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
goto done;
return CODEC_OK;
}
ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
@ -139,12 +142,13 @@ seek_start :
rmctx.frame_number = 0;
/* Seek to the start of the track */
if (ci->seek_time == 1) {
if (param == 0) {
ci->set_elapsed(0);
ci->seek_complete();
action = CODEC_ACTION_NULL;
goto seek_start;
}
num_units = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps));
num_units = (param/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps));
ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units);
bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size);
consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt);
@ -155,12 +159,12 @@ seek_start :
return CODEC_ERROR;
}
else
goto done;
return CODEC_OK;
}
packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units;
rmctx.frame_number = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate));
while(rmctx.audiotimestamp > (unsigned) ci->seek_time) {
rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate));
while(rmctx.audiotimestamp > (unsigned) param) {
rmctx.audio_pkt_cnt = 0;
ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1));
bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size);
@ -168,16 +172,19 @@ seek_start :
packet_count += rmctx.audio_pkt_cnt;
num_units--;
}
time_offset = ci->seek_time - rmctx.audiotimestamp;
time_offset = param - rmctx.audiotimestamp;
i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate));
elapsed = rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i;
ci->set_elapsed(elapsed);
ci->seek_complete();
}
action = CODEC_ACTION_NULL;
if(pkt.length)
res = atrac3_decode_frame(rmctx.block_align, &q, &datasize, pkt.frames[i], rmctx.block_align);
else /* indicates that there are no remaining frames */
goto done;
return CODEC_OK;
if(res != rmctx.block_align) {
DEBUGF("codec error\n");
@ -196,9 +203,5 @@ seek_start :
ci->advance_buffer(consumed);
}
done :
if (ci->request_next_track())
goto next_track;
return CODEC_OK;
}

View file

@ -106,9 +106,19 @@ static int convert_au_format(unsigned int encoding, struct pcm_format *fmt)
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int status;
struct pcm_format format;
uint32_t bytesdone, decodedsamples;
size_t n;
@ -119,22 +129,13 @@ enum codec_status codec_main(void)
off_t firstblockposn; /* position of the first block in file */
const struct pcm_codec *codec;
int offset = 0;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
next_track:
status = CODEC_OK;
intptr_t param;
if (codec_init()) {
DEBUGF("codec_init() error\n");
status = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
@ -145,6 +146,7 @@ next_track:
format.is_little_endian = false;
/* set format */
ci->seek_buffer(0);
buf = ci->request_buffer(&n, 24);
if (n < 24 || (memcmp(buf, ".snd", 4) != 0))
{
@ -170,8 +172,7 @@ next_track:
if (offset < 24)
{
DEBUGF("CODEC_ERROR: sun audio offset size is small: %d\n", offset);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* data size */
format.numbytes = get_be32(buf + 8);
@ -182,8 +183,7 @@ next_track:
if (format.formattag == AU_FORMAT_UNSUPPORT)
{
DEBUGF("CODEC_ERROR: sun audio unsupport format: %d\n", get_be32(buf + 12));
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* skip sample rate */
format.channels = get_be32(buf + 20);
@ -202,20 +202,17 @@ next_track:
if (!codec)
{
DEBUGF("CODEC_ERROR: unsupport sun audio format: %x\n", (int)format.formattag);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (!codec->set_format(&format))
{
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (format.numbytes == 0) {
DEBUGF("CODEC_ERROR: data size is 0\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* check chunksize */
@ -225,8 +222,7 @@ next_track:
if (format.chunksize == 0)
{
DEBUGF("CODEC_ERROR: chunksize is 0\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@ -236,8 +232,7 @@ next_track:
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
} else {
DEBUGF("CODEC_ERROR: more than 2 channels\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* make sure we're at the correct offset */
@ -253,7 +248,6 @@ next_track:
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->seek_complete();
} else {
/* already where we need to be */
bytesdone = 0;
@ -263,22 +257,29 @@ next_track:
endofstream = 0;
while (!endofstream) {
ci->yield();
if (ci->stop_codec || ci->new_track) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
/* 3rd args(read_buffer) is unnecessary in the format which Sun Audio supports. */
struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME, NULL);
if (newpos->pos > format.numbytes)
{
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
break;
}
if (ci->seek_time) {
/* 3rd args(read_buffer) is unnecessary in the format which Sun Audio supports. */
struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, NULL);
if (newpos->pos > format.numbytes)
break;
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
ci->seek_complete();
}
@ -290,11 +291,10 @@ next_track:
endofstream = 1;
}
status = codec->decode(aubuf, n, samples, &bufcount);
if (status == CODEC_ERROR)
if (codec->decode(aubuf, n, samples, &bufcount) == CODEC_ERROR)
{
DEBUGF("codec error\n");
goto done;
return CODEC_ERROR;
}
ci->pcmbuf_insert(samples, NULL, bufcount);
@ -308,9 +308,5 @@ next_track:
}
done:
if (ci->request_next_track())
goto next_track;
exit:
return status;
return CODEC_OK;
}

View file

@ -27,15 +27,17 @@ struct codec_api *ci DATA_ATTR;
extern unsigned char plugin_bss_start[];
extern unsigned char plugin_end_addr[];
extern enum codec_status codec_main(void);
extern enum codec_status codec_main(enum codec_entry_call_reason reason);
/* stub, the entry point is called via its reference in __header to
* avoid warning with certain compilers */
int _start(void) {return 0;}
enum codec_status codec_start(void)
enum codec_status codec_start(enum codec_entry_call_reason reason)
{
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
if (reason == CODEC_LOAD)
{
#ifdef USE_IRAM
extern char iramcopy[], iramstart[], iramend[], iedata[], iend[];
size_t iram_size = iramend - iramstart;
@ -57,9 +59,13 @@ enum codec_status codec_start(void)
* portalplayer has this). If we don't clear the cache, those aliases
* may read garbage */
ci->cpucache_invalidate();
#endif
}
#endif /* CONFIG_PLATFORM */
return codec_main();
/* Note: If for any reason codec_main would not be called with CODEC_LOAD
* because the above code failed then it must not be ever be called with
* any other value and some strategy to avoid doing so must be conceived */
return codec_main(reason);
}
#if defined(CPU_ARM) && (CONFIG_PLATFORM & PLATFORM_NATIVE)

View file

@ -38,8 +38,8 @@ static void init_rm(RMContext *rmctx)
memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext));
}
/* this is the codec entry point */
enum codec_status codec_main(void)
/* this is called for each file to process */
enum codec_status codec_run(void)
{
static size_t buff_size;
int datasize, res, consumed, i, time_offset;
@ -48,16 +48,14 @@ enum codec_status codec_main(void)
uint32_t packet_count;
int scrambling_unit_size, num_units;
size_t resume_offset;
intptr_t param = 0;
enum codec_command_action action = CODEC_ACTION_NULL;
next_track:
if (codec_init()) {
DEBUGF("codec init failed\n");
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
resume_offset = ci->id3->offset;
codec_set_replaygain(ci->id3);
@ -65,6 +63,8 @@ next_track:
ci->memset(&pkt,0,sizeof(RMPacket));
ci->memset(&q,0,sizeof(COOKContext));
ci->seek_buffer(0);
init_rm(&rmctx);
ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
@ -94,7 +94,8 @@ next_track:
num_units = (int)resume_offset / scrambling_unit_size;
/* put number of subpackets to skip in resume_offset */
resume_offset /= (sps + PACKET_HEADER_SIZE);
ci->seek_time = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
action = CODEC_ACTION_SEEK_TIME;
}
ci->set_elapsed(0);
@ -113,17 +114,18 @@ seek_start :
for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++)
{
ci->yield();
if (ci->stop_codec || ci->new_track)
goto done;
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
if (ci->seek_time) {
ci->set_elapsed(ci->seek_time);
if (action == CODEC_ACTION_HALT)
return CODEC_OK;
if (action == CODEC_ACTION_SEEK_TIME) {
/* Do not allow seeking beyond the file's length */
if ((unsigned) ci->seek_time > ci->id3->length) {
if ((unsigned) param > ci->id3->length) {
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
goto done;
return CODEC_OK;
}
ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
@ -132,22 +134,24 @@ seek_start :
rmctx.frame_number = 0;
/* Seek to the start of the track */
if (ci->seek_time == 1) {
if (param == 0) {
ci->set_elapsed(0);
ci->seek_complete();
action = CODEC_ACTION_NULL;
goto seek_start;
}
num_units = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps));
num_units = (param/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps));
ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units);
bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size);
consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt);
if(consumed < 0) {
DEBUGF("rm_get_packet failed\n");
ci->seek_complete();
return CODEC_ERROR;
}
packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units;
rmctx.frame_number = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate));
while(rmctx.audiotimestamp > (unsigned) ci->seek_time) {
rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate));
while(rmctx.audiotimestamp > (unsigned) param) {
rmctx.audio_pkt_cnt = 0;
ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1));
bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size);
@ -155,11 +159,14 @@ seek_start :
packet_count += rmctx.audio_pkt_cnt;
num_units--;
}
time_offset = ci->seek_time - rmctx.audiotimestamp;
time_offset = param - rmctx.audiotimestamp;
i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate));
ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i);
ci->seek_complete();
}
action = CODEC_ACTION_NULL;
res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], rmctx.block_align);
rmctx.frame_number++;
@ -181,9 +188,5 @@ seek_start :
ci->advance_buffer(consumed);
}
done :
if (ci->request_next_track())
goto next_track;
return CODEC_OK;
}

View file

@ -418,40 +418,40 @@ static bool flac_seek_offset(FLACContext* fc, uint32_t offset) {
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, FLAC_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int8_t *buf;
FLACContext fc;
uint32_t samplesdone = 0;
uint32_t samplesdone;
uint32_t elapsedtime;
size_t bytesleft;
int consumed;
int res;
int frame;
int retval;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, FLAC_OUTPUT_DEPTH-1);
next_track:
retval = CODEC_OK;
intptr_t param;
if (codec_init()) {
LOGF("FLAC: Error initialising codec\n");
retval = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
/* Need to save offset for later use (cleared indirectly by flac_init) */
samplesdone = ci->id3->offset;
if (!flac_init(&fc,ci->id3->first_frame_offset)) {
LOGF("FLAC: Error initialising codec\n");
retval = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@ -459,35 +459,34 @@ next_track:
STEREO_MONO : STEREO_NONINTERLEAVED);
codec_set_replaygain(ci->id3);
if (samplesdone) {
flac_seek_offset(&fc, samplesdone);
samplesdone=0;
}
/* The main decoding loop */
frame=0;
buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
while (bytesleft) {
ci->yield();
if (ci->stop_codec || ci->new_track) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
}
/* Deal with any pending seek requests */
if (ci->seek_time) {
if (flac_seek(&fc,(uint32_t)(((uint64_t)(ci->seek_time-1)
if (action == CODEC_ACTION_SEEK_TIME) {
if (flac_seek(&fc,(uint32_t)(((uint64_t)param
*ci->id3->frequency)/1000))) {
/* Refill the input buffer */
buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
}
ci->set_elapsed(param);
ci->seek_complete();
}
if((res=flac_decode_frame(&fc,decoded0,decoded1,buf,
bytesleft,ci->yield)) < 0) {
LOGF("FLAC: Frame %d, error %d\n",frame,res);
retval = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
consumed=fc.gb.index/8;
frame++;
@ -507,14 +506,7 @@ next_track:
buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
}
retval = CODEC_OK;
done:
LOGF("FLAC: Decoded %lu samples\n",(unsigned long)samplesdone);
if (ci->request_next_track())
goto next_track;
exit:
return retval;
return CODEC_OK;
}

View file

@ -33,6 +33,16 @@ unsigned char* mp3buf; // The actual MP3 buffer from Rockbox
unsigned char* mallocbuf; // 512K from the start of MP3 buffer
unsigned char* filebuf; // The rest of the MP3 buffer
/* this is the default codec entry point for when nothing needs to be done
on load or unload */
enum codec_status __attribute__((weak))
codec_main(enum codec_entry_call_reason reason)
{
/* Nothing to do */
return CODEC_OK;
(void)reason;
}
int codec_init(void)
{
mem_ptr = 0;
@ -41,7 +51,7 @@ int codec_init(void)
return 0;
}
void codec_set_replaygain(struct mp3entry* id3)
void codec_set_replaygain(const struct mp3entry *id3)
{
ci->configure(DSP_SET_TRACK_GAIN, id3->track_gain);
ci->configure(DSP_SET_ALBUM_GAIN, id3->album_gain);
@ -49,19 +59,6 @@ void codec_set_replaygain(struct mp3entry* id3)
ci->configure(DSP_SET_ALBUM_PEAK, id3->album_peak);
}
/* Note: codec really needs its own private metdata copy for the current
track being processed in order to be stable. */
int codec_wait_taginfo(void)
{
while (!*ci->taginfo_ready && !ci->stop_codec && !ci->new_track)
ci->sleep(0);
if (ci->stop_codec)
return -1;
if (ci->new_track)
return 1;
return 0;
}
/* Various "helper functions" common to all the xxx2wav decoder plugins */

View file

@ -156,8 +156,7 @@ static inline unsigned int bs_generic(unsigned int v, int mode)
/* Various codec helper functions */
int codec_init(void);
void codec_set_replaygain(struct mp3entry* id3);
int codec_wait_taginfo(void); /* 0 = success */
void codec_set_replaygain(const struct mp3entry *id3);
#ifdef RB_PROFILE
void __cyg_profile_func_enter(void *this_fn, void *call_site)

View file

@ -1218,47 +1218,37 @@ void synthrender(int32_t *renderbuffer, int samplecount)
}
}
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Make use of 44.1khz */
ci->configure(DSP_SET_FREQUENCY, 44100);
/* Sample depth is 28 bit host endian */
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
/* Stereo output */
ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
}
enum codec_status codec_main(void)
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
size_t n;
unsigned char *modfile;
int old_patterntableposition;
int bytesdone;
intptr_t param;
next_track:
if (codec_init()) {
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto request_next_track;
codec_set_replaygain(ci->id3);
/* Load MOD file */
/*
* This is the save way
size_t bytesfree;
unsigned int filesize;
p = modfile;
bytesfree=sizeof(modfile);
while ((n = ci->read_filebuf(p, bytesfree)) > 0) {
p += n;
bytesfree -= n;
if (bytesfree == 0)
return CODEC_ERROR;
}
filesize = p-modfile;
if (filesize == 0)
return CODEC_ERROR;
*/
/* Directly use mod in buffer */
ci->seek_buffer(0);
modfile = ci->request_buffer(&n, ci->filesize);
if (!modfile || n < (size_t)ci->filesize) {
@ -1268,27 +1258,22 @@ next_track:
initmodplayer();
loadmod(modfile);
/* Make use of 44.1khz */
ci->configure(DSP_SET_FREQUENCY, 44100);
/* Sample depth is 28 bit host endian */
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
/* Stereo output */
ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
/* The main decoder loop */
ci->set_elapsed(0);
bytesdone = 0;
old_patterntableposition = 0;
while (1) {
ci->yield();
if (ci->stop_codec || ci->new_track)
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (ci->seek_time) {
/* New time is ready in ci->seek_time */
modplayer.patterntableposition = ci->seek_time/1000;
if (action == CODEC_ACTION_SEEK_TIME) {
/* New time is ready in param */
modplayer.patterntableposition = param/1000;
modplayer.currentline = 0;
ci->set_elapsed(modplayer.patterntableposition*1000+500);
ci->seek_complete();
}
@ -1305,9 +1290,5 @@ next_track:
}
request_next_track:
if (ci->request_next_track())
goto next_track;
return CODEC_OK;
}

View file

@ -2584,23 +2584,32 @@ static bool enc_init(void)
return true;
} /* enc_init */
enum codec_status codec_main(void)
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
/* Generic codec initialisation */
if (reason == CODEC_LOAD) {
if (!enc_init())
return CODEC_ERROR;
}
else if (reason == CODEC_UNLOAD) {
/* reset parameters to initial state */
ci->enc_set_parameters(NULL);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
/* main encoding loop */
while (!ci->stop_codec)
{
char *buffer;
while ((buffer = ci->enc_get_pcm_data(pcm_chunk_size)) != NULL)
while(ci->get_command(NULL) != CODEC_ACTION_HALT)
{
char *buffer = buffer = ci->enc_get_pcm_data(pcm_chunk_size);
struct enc_chunk_hdr *chunk;
if (ci->stop_codec)
break;
if(buffer == NULL)
continue;
chunk = ci->enc_get_chunk();
chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
@ -2614,15 +2623,7 @@ enum codec_status codec_main(void)
}
ci->enc_finish_chunk();
ci->yield();
}
ci->yield();
}
/* reset parameters to initial state */
ci->enc_set_parameters(NULL);
return CODEC_OK;
} /* codec_start */
}

View file

@ -299,9 +299,30 @@ static inline void mad_synth_thread_unwait_pcm(void)
#endif /* MPA_SYNTH_ON_COP */
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Create a decoder instance */
if (codec_init())
return CODEC_ERROR;
ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS);
/* does nothing on 1 processor systems except return true */
if(!mad_synth_thread_create())
return CODEC_ERROR;
}
else if (reason == CODEC_UNLOAD) {
/* mop up COP thread - MT only */
mad_synth_thread_quit();
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int status;
size_t size;
int file_end;
int samples_to_skip; /* samples to skip in total for this file (at start) */
@ -312,27 +333,12 @@ enum codec_status codec_main(void)
unsigned long current_frequency = 0;
int framelength;
int padding = MAD_BUFFER_GUARD; /* to help mad decode the last frame */
if (codec_init())
return CODEC_ERROR;
/* Create a decoder instance */
ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS);
/*does nothing on 1 processor systems except return true*/
if(!mad_synth_thread_create())
return CODEC_ERROR;
next_track:
status = CODEC_OK;
intptr_t param;
/* Reinitializing seems to be necessary to avoid playback quircks when seeking. */
init_mad();
file_end = 0;
if (codec_wait_taginfo() != 0)
goto request_next_track;
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
current_frequency = ci->id3->frequency;
@ -379,29 +385,35 @@ next_track:
/* This is the decoding loop. */
while (1) {
ci->yield();
if (ci->stop_codec || ci->new_track)
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (ci->seek_time) {
if (action == CODEC_ACTION_SEEK_TIME) {
int newpos;
/*make sure the synth thread is idle before seeking - MT only*/
mad_synth_thread_wait_pcm();
mad_synth_thread_unwait_pcm();
samplesdone = ((int64_t)(ci->seek_time-1))*current_frequency/1000;
samplesdone = ((int64_t)param)*current_frequency/1000;
if (ci->seek_time-1 == 0) {
if (param == 0) {
newpos = ci->id3->first_frame_offset;
samples_to_skip = start_skip;
} else {
newpos = get_file_pos(ci->seek_time-1);
newpos = get_file_pos(param);
samples_to_skip = 0;
}
if (!ci->seek_buffer(newpos))
{
ci->seek_complete();
break;
}
ci->set_elapsed((samplesdone * 1000) / current_frequency);
ci->seek_complete();
init_mad();
framelength = 0;
@ -435,8 +447,7 @@ next_track:
continue;
} else {
/* Some other unrecoverable error */
status = CODEC_ERROR;
break;
return CODEC_ERROR;
}
}
@ -504,12 +515,5 @@ next_track:
framelength - stop_skip);
}
request_next_track:
if (ci->request_next_track())
goto next_track;
/*mop up COP thread - MT only*/
mad_synth_thread_quit();
return status;
return CODEC_OK;
}

View file

@ -52,8 +52,20 @@ static mpc_int32_t get_size_impl(mpc_reader *reader)
return ci->filesize;
}
/* This is the codec entry point. */
enum codec_status codec_main(void)
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* musepack's sample representation is 18.14
* DSP_SET_SAMPLE_DEPTH = 14 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 29 */
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
mpc_int64_t samplesdone;
uint32_t frequency; /* 0.1 kHz accuracy */
@ -64,39 +76,27 @@ enum codec_status codec_main(void)
mpc_streaminfo info;
mpc_frame_info frame;
mpc_demux *demux = NULL;
int retval;
intptr_t param;
frame.buffer = sample_buffer;
/* musepack's sample representation is 18.14
* DSP_SET_SAMPLE_DEPTH = 14 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 29 */
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
/* Create a decoder instance */
reader.read = read_impl;
reader.seek = seek_impl;
reader.tell = tell_impl;
reader.get_size = get_size_impl;
next_track:
retval = CODEC_OK;
if (codec_init())
{
retval = CODEC_ERROR;
goto exit;
}
return CODEC_ERROR;
if (codec_wait_taginfo() != 0)
goto done;
/* Prep position */
ci->seek_buffer(0);
/* Initialize demux/decoder. */
demux = mpc_demux_init(&reader);
if (NULL == demux)
{
retval = CODEC_ERROR;
goto done;
}
return CODEC_ERROR;
/* Read file's streaminfo data. */
mpc_demux_get_info(demux, &info);
@ -118,10 +118,7 @@ next_track:
else if (info.channels == 1)
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
else
{
retval = CODEC_ERROR;
goto done;
}
return CODEC_ERROR;
codec_set_replaygain(ci->id3);
@ -142,21 +139,24 @@ next_track:
/* This is the decoding loop. */
do
{
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
return CODEC_OK;
/* Complete seek handler. */
if (ci->seek_time)
if (action == CODEC_ACTION_SEEK_TIME)
{
mpc_int64_t new_offset = ((ci->seek_time - 1)/10)*frequency;
mpc_int64_t new_offset = (param/10)*frequency;
if (mpc_demux_seek_sample(demux, new_offset) == MPC_STATUS_OK)
{
samplesdone = new_offset;
ci->set_elapsed(ci->seek_time);
}
ci->seek_complete();
}
/* Stop or skip occured, exit decoding loop. */
if (ci->stop_codec || ci->new_track)
break;
elapsed_time = (samplesdone*10)/frequency;
ci->set_elapsed(elapsed_time);
ci->seek_complete();
}
/* Decode one frame. */
status = mpc_demux_decode(demux, &frame);
@ -164,8 +164,7 @@ next_track:
if (frame.bits == -1)
{
/* Decoding error, exit decoding loop. */
retval = (status == MPC_STATUS_OK) ? CODEC_OK : CODEC_ERROR;
goto done;
return (status == MPC_STATUS_OK) ? CODEC_OK : CODEC_ERROR;
}
else
{
@ -181,11 +180,4 @@ next_track:
ci->set_offset( (samplesdone * byterate)/(frequency*100) );
}
} while (true);
done:
if (ci->request_next_track())
goto next_track;
exit:
return retval;
}

View file

@ -4307,46 +4307,44 @@ static void set_codec_track(int t, int d) {
nSilenceTrackMS=5000;
SetFadeTime(track,track+fade, fNSFPlaybackSpeed,def);
}
ci->id3->elapsed=d*1000; /* d is track no to display */
ci->set_elapsed(d*1000); /* d is track no to display */
}
/** Operational info **/
static int track = 0;
static char last_path[MAX_PATH];
static int dontresettrack = 0;
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* we only render 16 bits, 44.1KHz, Stereo */
ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
ci->configure(DSP_SET_FREQUENCY, 44100);
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
RebuildOutputTables();
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int written;
uint8_t *buf;
size_t n;
int endofstream; /* end of stream flag */
int track;
int dontresettrack;
char last_path[MAX_PATH];
int usingplaylist;
int usingplaylist = 0;
/* we only render 16 bits */
ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
ci->configure(DSP_SET_FREQUENCY, 44100);
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
RebuildOutputTables();
dontresettrack=0;
last_path[0]='\0';
track=0;
next_track:
usingplaylist=0;
DEBUGF("NSF: next_track\n");
if (codec_init()) {
return CODEC_ERROR;
}
DEBUGF("NSF: after init\n");
/* wait for track info to load */
if (codec_wait_taginfo() != 0)
goto request_next_track;
codec_set_replaygain(ci->id3);
/* Read the entire file */
@ -4408,23 +4406,28 @@ init_nsf:
reset_profile_timers();
while (!endofstream) {
intptr_t param;
enum codec_command_action action = ci->get_command(&param);
ci->yield();
if (ci->stop_codec || ci->new_track) {
if (action == CODEC_ACTION_HALT)
break;
}
if (ci->seek_time >0) {
track=ci->seek_time/1000;
if (action == CODEC_ACTION_SEEK_TIME) {
if (param > 0) {
track=param/1000;
if (usingplaylist) {
if (track>=nPlaylistSize) break;
} else {
if (track>=nTrackCount) break;
}
ci->seek_complete();
dontresettrack=1;
ci->seek_complete();
goto init_nsf;
}
else {
ci->seek_complete();
}
}
ENTER_TIMER(total);
written=GetSamples((uint8_t*)samples,WAV_CHUNK_SIZE/2);
@ -4449,22 +4452,17 @@ init_nsf:
print_timers(last_path,track);
request_next_track:
if (ci->request_next_track()) {
if (ci->global_settings->repeat_mode==REPEAT_ONE) {
/* in repeat one mode just advance to the next track */
track++;
if (track>=nTrackCount) track=0;
dontresettrack=1;
/* at this point we can't tell if another file has been selected */
goto next_track;
} else {
/* otherwise do a proper load of the next file */
dontresettrack=0;
last_path[0]='\0';
}
goto next_track; /* when we fall through here we'll reload the file */
}
return CODEC_OK;
}

View file

@ -35,8 +35,21 @@ static void init_rm(RMContext *rmctx)
static RMContext rmctx;
static RMPacket pkt;
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
static NeAACDecFrameInfo frame_info;
NeAACDecHandle decoder;
@ -49,26 +62,21 @@ enum codec_status codec_main(void)
unsigned char c = 0; /* channels */
int playback_on = -1;
size_t resume_offset;
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
next_track:
err = CODEC_OK;
intptr_t param;
enum codec_command_action action = CODEC_ACTION_NULL;
if (codec_init()) {
DEBUGF("FAAD: Codec init error\n");
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
resume_offset = ci->id3->offset;
ci->memset(&rmctx,0,sizeof(RMContext));
ci->memset(&pkt,0,sizeof(RMPacket));
ci->seek_buffer(0);
init_rm(&rmctx);
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
codec_set_replaygain(ci->id3);
@ -78,9 +86,9 @@ next_track:
if (!decoder) {
DEBUGF("FAAD: Decode open error\n");
err = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder);
conf->outputFormat = FAAD_FMT_16BIT; /* irrelevant, we don't convert */
NeAACDecSetConfiguration(decoder, conf);
@ -91,8 +99,7 @@ next_track:
if (err) {
DEBUGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type);
err = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* check for a mid-track resume and force a seek time accordingly */
@ -100,36 +107,38 @@ next_track:
resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
/* put number of subpackets to skip in resume_offset */
resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE);
ci->seek_time = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
action = CODEC_ACTION_SEEK_TIME;
}
ci->id3->frequency = s;
ci->id3->frequency = s; /* FIXME: Won't get it to the UI */
ci->set_elapsed(0);
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
/* The main decoding loop */
seek_start:
while (1) {
ci->yield();
if (ci->stop_codec || ci->new_track) {
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
}
if (ci->seek_time) {
if (action == CODEC_ACTION_SEEK_TIME) {
/* Do not allow seeking beyond the file's length */
if ((unsigned) ci->seek_time > ci->id3->length) {
if ((unsigned) param > ci->id3->length) {
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
goto done;
break;
}
ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
/* Seek to the start of the track */
if (ci->seek_time == 1) {
if (param == 0) {
ci->set_elapsed(0);
ci->seek_complete();
goto seek_start;
action = CODEC_ACTION_NULL;
continue;
}
skipped = 0;
@ -141,21 +150,30 @@ seek_start:
if(playback_on == -1) {
/* Error only if packet-parsing failed and playback hadn't started */
DEBUGF("rm_get_packet failed\n");
ci->seek_complete();
return CODEC_ERROR;
}
else
goto done;
else {
ci->seek_complete();
return CODEC_OK;
}
}
skipped += pkt.length;
if(pkt.timestamp > (unsigned)ci->seek_time) break;
if(pkt.timestamp > (unsigned)param)
break;
ci->advance_buffer(pkt.length);
}
ci->seek_buffer(pkt_offset + rmctx.data_offset + DATA_HEADER_SIZE);
buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000);
NeAACDecPostSeekReset(decoder, decoder->frame);
ci->set_elapsed(pkt.timestamp);
ci->seek_complete();
}
action = CODEC_ACTION_NULL;
/* Request the required number of bytes from the input buffer */
buffer=ci->request_buffer(&n,rmctx.audio_framesize + 1000);
consumed = rm_get_packet(&buffer, &rmctx, &pkt);
@ -167,20 +185,20 @@ seek_start:
return CODEC_ERROR;
}
else
goto done;
break;
}
playback_on = 1;
if (pkt.timestamp >= ci->id3->length)
goto done;
break;
/* Decode one block - returned samples will be host-endian */
for(i = 0; i < rmctx.sub_packet_cnt; i++) {
ret = NeAACDecDecode(decoder, &frame_info, buffer, rmctx.sub_packet_lengths[i]);
buffer += rmctx.sub_packet_lengths[i];
if (frame_info.error > 0) {
DEBUGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error));
err = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
ci->pcmbuf_insert(decoder->time_out[0],
decoder->time_out[1],
@ -191,11 +209,5 @@ seek_start:
ci->advance_buffer(pkt.length);
}
done:
if (ci->request_next_track())
goto next_track;
exit:
return err;
return CODEC_OK;
}

View file

@ -37,7 +37,19 @@ static int32_t offset1[MAX_OFFSET_SIZE] IBSS_ATTR;
static int8_t ibuf[MAX_BUFFER_SIZE] IBSS_ATTR;
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, SHN_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
ShortenContext sc;
uint32_t samplesdone;
@ -45,21 +57,14 @@ enum codec_status codec_main(void)
int8_t *buf;
int consumed, res, nsamples;
size_t bytesleft;
intptr_t param;
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, SHN_OUTPUT_DEPTH-1);
next_track:
/* Codec initialization */
if (codec_init()) {
LOGF("Shorten: codec_init error\n");
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto request_next_track;
codec_set_replaygain(ci->id3);
/* Shorten decoder initialization */
@ -103,14 +108,15 @@ seek_start:
samplesdone = 0;
buf = ci->request_buffer(&bytesleft, MAX_BUFFER_SIZE);
while (bytesleft) {
ci->yield();
if (ci->stop_codec || ci->new_track) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
}
/* Seek to start of track */
if (ci->seek_time == 1) {
if (ci->seek_buffer(sc.header_bits/8 + ci->id3->first_frame_offset)) {
if (action == CODEC_ACTION_SEEK_TIME) {
if (param == 0 &&
ci->seek_buffer(sc.header_bits/8 + ci->id3->first_frame_offset)) {
sc.bitindex = sc.header_bits - 8*(sc.header_bits/8);
ci->set_elapsed(0);
ci->seek_complete();
@ -128,7 +134,7 @@ seek_start:
if (res == FN_ERROR) {
LOGF("Shorten: shorten_decode_frames error (%lu)\n",
(unsigned long)samplesdone);
break;
return CODEC_ERROR;
} else {
/* Insert decoded samples in pcmbuf */
if (nsamples) {
@ -153,9 +159,5 @@ seek_start:
sc.bitindex = sc.gb.index - 8*consumed;
}
request_next_track:
if (ci->request_next_track())
goto next_track;
return CODEC_OK;
}

View file

@ -1203,34 +1203,47 @@ unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
return *load_addr;
}
static int nSamplesRendered = 0;
static int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
static int nSamplesToRender = 0;
enum codec_status codec_main(void)
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Make use of 44.1khz */
ci->configure(DSP_SWITCH_FREQUENCY, 44100);
/* Sample depth is 28 bit host endian */
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
/* Mono output */
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
unsigned int filesize;
unsigned short load_addr, init_addr, play_addr;
unsigned char subSongsMax, subSong, song_speed;
intptr_t param;
int nSamplesRendered = 0;
int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
int nSamplesToRender = 0;
next_track:
if (codec_init()) {
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto request_next_track;
codec_set_replaygain(ci->id3);
/* Load SID file the read_filebuf callback will return the full requested
* size if at all possible, so there is no need to loop */
ci->seek_buffer(0);
filesize = ci->read_filebuf(sidfile, sizeof(sidfile));
if (filesize == 0)
if (filesize == 0) {
return CODEC_ERROR;
}
c64Init(44100);
LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
@ -1239,37 +1252,30 @@ next_track:
cpuJSR(init_addr, subSong); /* Start the song initialize */
/* Make use of 44.1khz */
ci->configure(DSP_SWITCH_FREQUENCY, 44100);
/* Sample depth is 28 bit host endian */
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
/* Mono output */
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
/* Set the elapsed time to the current subsong (in seconds) */
ci->set_elapsed(subSong*1000);
/* The main decoder loop */
while (1) {
ci->yield();
if (ci->stop_codec || ci->new_track)
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (ci->seek_time) {
/* New time is ready in ci->seek_time */
if (action == CODEC_ACTION_SEEK_TIME) {
/* New time is ready in param */
/* Start playing from scratch */
c64Init(44100);
LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, &subSongsMax, &subSong, &song_speed, filesize);
LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
&subSongsMax, &subSong, &song_speed, filesize);
sidPoke(24, 15); /* Turn on full volume */
subSong = ci->seek_time / 1000; /* Now use the current seek time in seconds as subsong */
subSong = param / 1000; /* Now use the current seek time in seconds as subsong */
cpuJSR(init_addr, subSong); /* Start the song initialize */
nSamplesToRender = 0; /* Start the rendering from scratch */
ci->seek_complete();
/* Set the elapsed time to the current subsong (in seconds) */
ci->seek_complete();
ci->set_elapsed(subSong*1000);
}
@ -1306,9 +1312,5 @@ next_track:
ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE);
}
request_next_track:
if (ci->request_next_track())
goto next_track;
return CODEC_OK;
}

View file

@ -332,9 +332,20 @@ static uint8_t *read_buffer(size_t *realsize)
return buffer;
}
enum codec_status codec_main(void)
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int status;
uint32_t decodedsamples;
size_t n;
int bufcount;
@ -342,20 +353,10 @@ enum codec_status codec_main(void)
uint8_t *smafbuf;
off_t firstblockposn; /* position of the first block in file */
const struct pcm_codec *codec;
intptr_t param;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
next_track:
status = CODEC_OK;
if (codec_init()) {
status = CODEC_ERROR;
goto exit;
}
if (codec_wait_taginfo() != 0)
goto done;
if (codec_init())
return CODEC_ERROR;
codec_set_replaygain(ci->id3);
@ -365,24 +366,22 @@ next_track:
decodedsamples = 0;
codec = 0;
ci->seek_buffer(0);
if (!parse_header(&format, &firstblockposn))
{
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
codec = get_codec(format.formattag);
if (codec == 0)
{
DEBUGF("CODEC_ERROR: unsupport audio format: 0x%x\n", (int)format.formattag);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (!codec->set_format(&format))
{
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* check chunksize */
@ -392,8 +391,7 @@ next_track:
if (format.chunksize == 0)
{
DEBUGF("CODEC_ERROR: chunksize is 0\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@ -404,12 +402,10 @@ next_track:
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
} else {
DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
ci->seek_buffer(firstblockposn);
ci->seek_complete();
/* make sure we're at the correct offset */
if (bytesdone > (uint32_t) firstblockposn)
@ -419,13 +415,13 @@ next_track:
PCM_SEEK_POS, &read_buffer);
if (newpos->pos > format.numbytes)
goto done;
return CODEC_OK;
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->seek_complete();
}
else
{
@ -437,23 +433,32 @@ next_track:
endofstream = 0;
while (!endofstream) {
ci->yield();
if (ci->stop_codec || ci->new_track)
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (ci->seek_time) {
struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME,
if (action == CODEC_ACTION_SEEK_TIME) {
struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME,
&read_buffer);
if (newpos->pos > format.numbytes)
{
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
break;
}
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
ci->seek_complete();
}
smafbuf = (uint8_t *)ci->request_buffer(&n, format.chunksize);
if (n == 0)
@ -464,11 +469,10 @@ next_track:
endofstream = 1;
}
status = codec->decode(smafbuf, n, samples, &bufcount);
if (status == CODEC_ERROR)
if (codec->decode(smafbuf, n, samples, &bufcount) == CODEC_ERROR)
{
DEBUGF("codec error\n");
goto done;
return CODEC_ERROR;
}
ci->pcmbuf_insert(samples, NULL, bufcount);
@ -482,11 +486,5 @@ next_track:
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
}
done:
if (ci->request_next_track())
goto next_track;
exit:
return status;
return CODEC_OK;
}

View file

@ -260,14 +260,6 @@ static inline void samples_release_rdbuf(void)
static inline int32_t * samples_get_rdbuf(void)
{
ci->semaphore_wait(&sample_queue.emu_sem_head, TIMEOUT_BLOCK);
if (ci->stop_codec || ci->new_track)
{
/* Told to stop. Buffer must be released. */
samples_release_rdbuf();
return NULL;
}
return sample_queue.wav_chunk[sample_queue.head & WAV_CHUNK_MASK].audio;
}
@ -390,11 +382,10 @@ static inline void spc_emu_quit(void)
}
}
static inline bool spc_play_get_samples(int32_t **samples)
static inline int32_t * spc_play_get_samples(void)
{
/* obtain filled samples buffer */
*samples = samples_get_rdbuf();
return *samples != NULL;
return samples_get_rdbuf();
}
static inline void spc_play_send_samples(int32_t *samples)
@ -433,15 +424,14 @@ static inline void spc_play_send_samples(int32_t *samples)
#define spc_emu_quit()
#define samples_release_rdbuf()
static inline bool spc_play_get_samples(int32_t **samples)
static inline int32_t * spc_play_get_samples(void)
{
ENTER_TIMER(render);
/* fill samples buffer */
if ( SPC_play(&spc_emu,WAV_CHUNK_SIZE*2,wav_chunk) )
assert( false );
EXIT_TIMER(render);
*samples = wav_chunk;
return true;
return wav_chunk;
}
#endif /* SPC_DUAL_CORE */
@ -454,6 +444,7 @@ static int play_track( void )
unsigned long fadeendsample = (ID666.length+ID666.fade)*(long long) SAMPLE_RATE/1000;
int fadedec = 0;
int fadevol = 0x7fffffffl;
intptr_t param;
if (fadeendsample>fadestartsample)
fadedec=0x7fffffffl/(fadeendsample-fadestartsample)+1;
@ -462,25 +453,26 @@ static int play_track( void )
while ( 1 )
{
ci->yield();
if (ci->stop_codec || ci->new_track) {
break;
}
enum codec_command_action action = ci->get_command(&param);
if (ci->seek_time) {
if (action == CODEC_ACTION_HALT)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
int curtime = sampleswritten*1000LL/SAMPLE_RATE;
DEBUGF("seek to %ld\ncurrently at %d\n",ci->seek_time,curtime);
if (ci->seek_time < curtime) {
DEBUGF("seek to %ld\ncurrently at %d\n", (long)param, curtime);
if (param < curtime) {
DEBUGF("seek backwards = reset\n");
ci->set_elapsed(0);
ci->seek_complete();
return 1;
}
ci->set_elapsed(curtime);
ci->seek_complete();
}
int32_t *samples;
if (!spc_play_get_samples(&samples))
break;
int32_t *samples = spc_play_get_samples();
sampleswritten += WAV_CHUNK_SIZE;
@ -532,28 +524,30 @@ static int play_track( void )
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
enum codec_status stat = CODEC_ERROR;
if (reason == CODEC_LOAD) {
if (!spc_emu_start())
goto codec_quit;
do
{
DEBUGF("SPC: next_track\n");
if (codec_init()) {
goto codec_quit;
}
DEBUGF("SPC: after init\n");
return CODEC_ERROR;
ci->configure(DSP_SET_SAMPLE_DEPTH, 24);
ci->configure(DSP_SET_FREQUENCY, SAMPLE_RATE);
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
}
else if (reason == CODEC_UNLOAD) {
spc_emu_quit();
}
/* wait for track info to load */
if (codec_wait_taginfo() != 0)
continue;
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
DEBUGF("SPC: next_track\n");
if (codec_init())
return CODEC_ERROR;
DEBUGF("SPC: after init\n");
codec_set_replaygain(ci->id3);
@ -562,16 +556,15 @@ enum codec_status codec_main(void)
ci->seek_buffer(0);
size_t buffersize;
uint8_t* buffer = ci->request_buffer(&buffersize, ci->filesize);
if (!buffer) {
goto codec_quit;
}
if (!buffer)
return CODEC_ERROR;
DEBUGF("SPC: read size = 0x%lx\n",(unsigned long)buffersize);
do
{
if (load_spc_buffer(buffer, buffersize)) {
DEBUGF("SPC load failure\n");
goto codec_quit;
return CODEC_ERROR;
}
LoadID666(buffer+0x2e);
@ -586,13 +579,6 @@ enum codec_status codec_main(void)
while ( play_track() );
print_timers(ci->id3->path);
}
while ( ci->request_next_track() );
stat = CODEC_OK;
codec_quit:
spc_emu_quit();
return stat;
return CODEC_OK;
}

View file

@ -367,11 +367,12 @@ static void *process_header(spx_ogg_packet *op,
return st;
}
/* this is the codec entry point */
enum codec_status codec_main(void)
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int error = CODEC_ERROR;
SpeexBits bits;
int error;
int eof = 0;
spx_ogg_sync_state oy;
spx_ogg_page og;
@ -383,7 +384,7 @@ enum codec_status codec_main(void)
int eos = 0;
SpeexStereoState *stereo;
int channels = -1;
int rate = 0, samplerate = 0;
int samplerate = 0;
int extra_headers = 0;
int stream_init = 0;
int page_nb_packets, frame_size, packet_count = 0;
@ -392,26 +393,22 @@ enum codec_status codec_main(void)
unsigned long strtoffset = 0;
void *st = NULL;
int j = 0;
intptr_t param;
memset(&bits, 0, sizeof(bits));
memset(&oy, 0, sizeof(oy));
/* Ogg handling still uses mallocs, so reset the malloc buffer per track */
next_track:
error = CODEC_OK;
if (codec_init()) {
error = CODEC_ERROR;
goto exit;
}
ci->seek_buffer(0);
stereo = speex_stereo_state_init();
spx_ogg_sync_init(&oy);
spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE);
if (codec_wait_taginfo() != 0)
goto done;
strtoffset = ci->id3->offset;
samplerate = ci->id3->frequency;
@ -419,30 +416,32 @@ next_track:
eof = 0;
while (!eof) {
ci->yield();
if (ci->stop_codec || ci->new_track)
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
/*seek (seeks to the page before the position) */
if (ci->seek_time) {
if (action == CODEC_ACTION_SEEK_TIME) {
if(samplerate!=0&&packet_count>1){
LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n",
((spx_int64_t)ci->seek_time/1000) *
((spx_int64_t)param/1000) *
(spx_int64_t)samplerate,
page_granule, ci->seek_time,
page_granule, param,
(page_granule/samplerate)*1000, samplerate);
speex_seek_page_granule(((spx_int64_t)ci->seek_time/1000) *
speex_seek_page_granule(((spx_int64_t)param/1000) *
(spx_int64_t)samplerate,
page_granule, &oy, headerssize);
ci->seek_complete();
}
ci->set_elapsed(param);
ci->seek_complete();
}
next_page:
/*Get the ogg buffer for writing*/
if(get_more_data(&oy)<1){/*read error*/
error=CODEC_ERROR;
goto done;
}
@ -477,8 +476,7 @@ next_page:
nframes=1;
if (!st){
error=CODEC_ERROR;
goto exit;
goto done;
}
ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
@ -557,31 +555,18 @@ next_page:
}
done:
if (ci->request_next_track()) {
/* Clean things up for the next track */
speex_bits_destroy(&bits);
if (st)
if (st)
speex_decoder_destroy(st);
if (stream_init == 1)
spx_ogg_stream_reset(&os);
spx_ogg_sync_reset(&oy);
cur_granule = stream_init = rate = samplerate = headerssize
= packet_count = eos = 0;
goto next_track;
}
exit:
speex_bits_destroy(&bits);
if (stream_init)
spx_ogg_stream_destroy(&os);
spx_ogg_sync_destroy(&oy);
exit:
return error;
}

View file

@ -34,36 +34,36 @@ CODEC_HEADER
static int32_t samples[PCM_BUFFER_LENGTH * 2] IBSS_ATTR;
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, TTA_OUTPUT_DEPTH - 1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
tta_info info;
int status;
unsigned int decodedsamples;
int endofstream;
int new_pos = 0;
int sample_count;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, TTA_OUTPUT_DEPTH - 1);
next_track:
status = CODEC_OK;
intptr_t param;
if (codec_init())
{
DEBUGF("codec_init() error\n");
status = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
ci->seek_buffer(0);
if (set_tta_info(&info) < 0 || player_init(&info) < 0)
{
status = CODEC_ERROR;
goto exit;
}
return CODEC_ERROR;
codec_set_replaygain(ci->id3);
@ -74,8 +74,8 @@ next_track:
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
} else {
DEBUGF("CODEC_ERROR: more than 2 channels\n");
status = CODEC_ERROR;
goto done;
player_stop();
return CODEC_ERROR;
}
/* The main decoder loop */
@ -88,31 +88,31 @@ next_track:
new_pos = set_position(ci->id3->offset, TTA_SEEK_POS);
if (new_pos >= 0)
decodedsamples = new_pos;
ci->seek_complete();
}
while (!endofstream)
{
ci->yield();
if (ci->stop_codec || ci->new_track)
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (ci->seek_time)
if (action == CODEC_ACTION_SEEK_TIME)
{
new_pos = set_position(ci->seek_time / SEEK_STEP, TTA_SEEK_TIME);
new_pos = set_position(param / SEEK_STEP, TTA_SEEK_TIME);
if (new_pos >= 0)
{
decodedsamples = new_pos;
ci->seek_complete();
}
ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH);
ci->seek_complete();
}
sample_count = get_samples(samples);
if (sample_count < 0)
{
status = CODEC_ERROR;
break;
}
ci->pcmbuf_insert(samples, NULL, sample_count);
decodedsamples += sample_count;
if (decodedsamples >= info.DATALENGTH)
@ -120,11 +120,6 @@ next_track:
ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH);
}
done:
player_stop();
if (ci->request_next_track())
goto next_track;
exit:
return status;
return CODEC_OK;
}

View file

@ -104,14 +104,25 @@ static bool vorbis_set_codec_parameters(OggVorbis_File *vf)
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
if (codec_init())
return CODEC_ERROR;
ci->configure(DSP_SET_SAMPLE_DEPTH, 24);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
ov_callbacks callbacks;
OggVorbis_File vf;
ogg_int32_t **pcm;
bool initialized = false; /* First init done? */
int error;
int error = CODEC_ERROR;
long n;
int current_section;
int previous_section;
@ -120,36 +131,24 @@ enum codec_status codec_main(void)
ogg_int64_t vf_dataoffsets;
ogg_uint32_t vf_serialnos;
ogg_int64_t vf_pcmlengths[2];
ci->configure(DSP_SET_SAMPLE_DEPTH, 24);
if (codec_init()) {
error = CODEC_ERROR;
goto exit;
}
intptr_t param;
#if defined(CPU_ARM) || defined(CPU_COLDFIRE) || defined(CPU_MIPS)
if (setjmp(rb_jump_buf) != 0) {
/* malloc failed; skip to next track */
error = CODEC_ERROR;
/* malloc failed; finish with this track */
goto done;
}
#endif
next_track:
error = CODEC_OK;
ogg_malloc_init();
if (codec_wait_taginfo() != 0)
goto done;
/* Create a decoder instance */
callbacks.read_func = read_handler;
callbacks.seek_func = initial_seek_handler;
callbacks.tell_func = tell_handler;
callbacks.close_func = close_handler;
ci->seek_buffer(0);
/* Open a non-seekable stream */
error = ov_open_callbacks(ci, &vf, NULL, 0, callbacks);
@ -186,15 +185,13 @@ next_track:
vf.end = ci->id3->filesize;
vf.ready_state = OPENED;
vf.links = 1;
initialized = true;
} else {
DEBUGF("Vorbis: ov_open failed: %d\n", error);
error = CODEC_ERROR;
goto done;
}
if (ci->id3->offset) {
ci->advance_buffer(ci->id3->offset);
ci->seek_buffer(ci->id3->offset);
ov_raw_seek(&vf, ci->id3->offset);
ci->set_elapsed(ov_time_tell(&vf));
ci->set_offset(ov_raw_tell(&vf));
@ -203,14 +200,17 @@ next_track:
previous_section = -1;
eof = 0;
while (!eof) {
ci->yield();
if (ci->stop_codec || ci->new_track)
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (ci->seek_time) {
if (ov_time_seek(&vf, ci->seek_time - 1)) {
if (action == CODEC_ACTION_SEEK_TIME) {
if (ov_time_seek(&vf, param)) {
//ci->logf("ov_time_seek failed");
}
ci->set_elapsed(ov_time_tell(&vf));
ci->seek_complete();
}
@ -220,7 +220,6 @@ next_track:
/* Change DSP and buffer settings for this bitstream */
if (current_section != previous_section) {
if (!vorbis_set_codec_parameters(&vf)) {
error = CODEC_ERROR;
goto done;
} else {
previous_section = current_section;
@ -238,6 +237,7 @@ next_track:
}
}
error = CODEC_OK;
done:
#if 0 /* defined(SIMULATOR) */
{
@ -249,18 +249,12 @@ done:
#endif
ogg_malloc_destroy();
if (ci->request_next_track()) {
if (!initialized)
goto next_track;
/* Clean things up for the next track */
vf.dataoffsets = NULL;
vf.offsets = NULL;
vf.serialnos = NULL;
vf.pcmlengths = NULL;
ov_clear(&vf);
goto next_track;
}
exit:
return error;
}

View file

@ -44,9 +44,19 @@ static uint8_t *read_buffer(size_t *realsize)
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int status;
uint32_t decodedsamples;
size_t n;
int bufcount;
@ -54,26 +64,18 @@ enum codec_status codec_main(void)
uint8_t *voxbuf;
off_t firstblockposn = 0; /* position of the first block in file */
const struct pcm_codec *codec;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
next_track:
status = CODEC_OK;
intptr_t param;
if (codec_init()) {
DEBUGF("codec_init() error\n");
status = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
bytesdone = ci->id3->offset;
ci->seek_buffer(0);
ci->memset(&format, 0, sizeof(struct pcm_format));
@ -96,20 +98,16 @@ next_track:
if (!codec)
{
DEBUGF("CODEC_ERROR: dialogic oki adpcm codec does not load.\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (!codec->set_format(&format))
{
status = CODEC_ERROR;
goto done;
if (!codec->set_format(&format)) {
return CODEC_ERROR;
}
if (format.numbytes == 0) {
DEBUGF("CODEC_ERROR: data size is 0\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* check chunksize */
@ -118,8 +116,7 @@ next_track:
if (format.chunksize == 0)
{
DEBUGF("CODEC_ERROR: chunksize is 0\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@ -131,14 +128,14 @@ next_track:
struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn,
PCM_SEEK_POS, &read_buffer);
if (newpos->pos > format.numbytes)
goto done;
if (newpos->pos > format.numbytes) {
return CODEC_OK;
}
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->seek_complete();
} else {
/* already where we need to be */
bytesdone = 0;
@ -148,22 +145,29 @@ next_track:
endofstream = 0;
while (!endofstream) {
ci->yield();
if (ci->stop_codec || ci->new_track) {
break;
}
enum codec_command_action action = ci->get_command(&param);
if (ci->seek_time) {
struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME,
if (action == CODEC_ACTION_HALT)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME,
&read_buffer);
if (newpos->pos > format.numbytes)
{
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
break;
}
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
ci->seek_complete();
}
@ -175,11 +179,10 @@ next_track:
endofstream = 1;
}
status = codec->decode(voxbuf, n, samples, &bufcount);
if (status == CODEC_ERROR)
if (codec->decode(voxbuf, n, samples, &bufcount) == CODEC_ERROR)
{
DEBUGF("codec error\n");
goto done;
return CODEC_ERROR;
}
ci->pcmbuf_insert(samples, NULL, bufcount);
@ -192,10 +195,5 @@ next_track:
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
}
done:
if (ci->request_next_track())
goto next_track;
exit:
return status;
return CODEC_OK;
}

View file

@ -151,9 +151,19 @@ static uint8_t *read_buffer(size_t *realsize)
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int status;
uint32_t decodedsamples;
size_t n;
int bufcount;
@ -163,38 +173,28 @@ enum codec_status codec_main(void)
off_t firstblockposn; /* position of the first block in file */
const struct pcm_codec *codec;
uint32_t size;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
next_track:
status = CODEC_OK;
intptr_t param;
if (codec_init()) {
DEBUGF("codec_init() error\n");
status = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
bytesdone = ci->id3->offset;
/* get RIFF chunk header */
ci->seek_buffer(0);
buf = ci->request_buffer(&n, 12);
if (n < 12) {
DEBUGF("request_buffer error\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) {
DEBUGF("CODEC_ERROR: missing riff header\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* advance to first WAVE chunk */
@ -215,8 +215,7 @@ next_track:
if (n < 8) {
DEBUGF("data chunk request_buffer error\n");
/* no more chunks, 'data' chunk must not have been found */
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* chunkSize */
@ -225,8 +224,7 @@ next_track:
if (size < 16) {
DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%lu < 16\n",
(unsigned long)size);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* wFormatTag */
format.formattag=buf[8]|(buf[9]<<8);
@ -256,8 +254,7 @@ next_track:
if (format.size < 22) {
DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is "
"missing extension\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* wValidBitsPerSample */
format.bitspersample = buf[26]|(buf[27]<<8);
@ -273,8 +270,7 @@ next_track:
{
if (!set_msadpcm_coeffs(buf))
{
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
}
@ -284,8 +280,7 @@ next_track:
{
DEBUGF("CODEC_ERROR: unsupported wave format 0x%x\n",
(unsigned int) format.formattag);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* riff 8bit linear pcm is unsigned */
@ -295,8 +290,7 @@ next_track:
/* set format, parse codec specific tag, check format, and calculate chunk size */
if (!codec->set_format(&format))
{
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
} else if (memcmp(buf, "data", 4) == 0) {
format.numbytes = size;
@ -324,31 +318,26 @@ next_track:
if (!codec)
{
DEBUGF("CODEC_ERROR: 'fmt ' chunk not found\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* common format check */
if (format.channels == 0) {
DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (format.samplesperblock == 0) {
DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (format.blockalign == 0)
{
DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (format.numbytes == 0) {
DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* check chunksize */
@ -358,8 +347,7 @@ next_track:
if (format.chunksize == 0)
{
DEBUGF("CODEC_ERROR: chunksize is 0\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@ -369,8 +357,7 @@ next_track:
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
} else {
DEBUGF("CODEC_ERROR: more than 2 channels\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* make sure we're at the correct offset */
@ -380,13 +367,12 @@ next_track:
PCM_SEEK_POS, &read_buffer);
if (newpos->pos > format.numbytes)
goto done;
return CODEC_OK;
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->seek_complete();
} else {
/* already where we need to be */
bytesdone = 0;
@ -396,22 +382,28 @@ next_track:
endofstream = 0;
while (!endofstream) {
ci->yield();
if (ci->stop_codec || ci->new_track) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME,
&read_buffer);
if (newpos->pos > format.numbytes)
{
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
break;
}
if (ci->seek_time) {
struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME,
&read_buffer);
if (newpos->pos > format.numbytes)
break;
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
ci->seek_complete();
}
@ -423,11 +415,10 @@ next_track:
endofstream = 1;
}
status = codec->decode(wavbuf, n, samples, &bufcount);
if (status == CODEC_ERROR)
if (codec->decode(wavbuf, n, samples, &bufcount) == CODEC_ERROR)
{
DEBUGF("codec error\n");
goto done;
return CODEC_ERROR;
}
ci->pcmbuf_insert(samples, NULL, bufcount);
@ -440,10 +431,5 @@ next_track:
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
}
done:
if (ci->request_next_track())
goto next_track;
exit:
return status;
return CODEC_OK;
}

View file

@ -159,9 +159,19 @@ static uint8_t *read_buffer(size_t *realsize)
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int status;
uint32_t decodedsamples;
size_t n;
int bufcount;
@ -171,39 +181,29 @@ enum codec_status codec_main(void)
off_t firstblockposn; /* position of the first block in file */
const struct pcm_codec *codec;
uint64_t size;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
next_track:
status = CODEC_OK;
intptr_t param;
if (codec_init()) {
DEBUGF("codec_init() error\n");
status = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (codec_wait_taginfo() != 0)
goto done;
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
bytesdone = ci->id3->offset;
/* get RIFF chunk header */
ci->seek_buffer(0);
buf = ci->request_buffer(&n, 40);
if (n < 40) {
DEBUGF("request_buffer error\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if ((memcmp(buf , WAVE64_GUID_RIFF, 16) != 0) ||
(memcmp(buf+24, WAVE64_GUID_WAVE, 16) != 0))
{
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* advance to first WAVE chunk */
@ -224,8 +224,7 @@ next_track:
if (n < 8) {
DEBUGF("data chunk request_buffer error\n");
/* no more chunks, 'data' chunk must not have been found */
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* chunkSize */
@ -233,8 +232,7 @@ next_track:
if (memcmp(buf, WAVE64_GUID_FMT, 16) == 0) {
if (size < 16) {
DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%d < 16\n", (int)size);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* wFormatTag */
format.formattag=buf[24]|(buf[25]<<8);
@ -263,8 +261,7 @@ next_track:
if (format.size < 22) {
DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is "
"missing extension\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* wValidBitsPerSample */
format.bitspersample = buf[42]|(buf[43]<<8);
@ -279,10 +276,7 @@ next_track:
if (format.formattag == WAVE_FORMAT_ADPCM)
{
if (!set_msadpcm_coeffs(buf))
{
status = CODEC_ERROR;
goto done;
}
return CODEC_ERROR;
}
/* get codec */
@ -291,8 +285,7 @@ next_track:
{
DEBUGF("CODEC_ERROR: unsupported wave format 0x%x\n",
(unsigned int) format.formattag);
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* riff 8bit linear pcm is unsigned */
@ -301,10 +294,7 @@ next_track:
/* check format, and calculate chunk size */
if (!codec->set_format(&format))
{
status = CODEC_ERROR;
goto done;
}
return CODEC_ERROR;
} else if (memcmp(buf, WAVE64_GUID_DATA, 16) == 0) {
format.numbytes = size;
/* advance to start of data */
@ -330,31 +320,26 @@ next_track:
if (!codec)
{
DEBUGF("CODEC_ERROR: 'fmt ' chunk not found\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* common format check */
if (format.channels == 0) {
DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (format.samplesperblock == 0) {
DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (format.blockalign == 0)
{
DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
if (format.numbytes == 0) {
DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* check chunksize */
@ -364,8 +349,7 @@ next_track:
if (format.chunksize == 0)
{
DEBUGF("CODEC_ERROR: chunksize is 0\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@ -375,8 +359,7 @@ next_track:
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
} else {
DEBUGF("CODEC_ERROR: more than 2 channels\n");
status = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* make sure we're at the correct offset */
@ -385,14 +368,14 @@ next_track:
struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn,
PCM_SEEK_POS, &read_buffer);
if (newpos->pos > format.numbytes)
goto done;
if (newpos->pos > format.numbytes) {
return CODEC_OK;
}
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->seek_complete();
} else {
/* already where we need to be */
bytesdone = 0;
@ -402,22 +385,29 @@ next_track:
endofstream = 0;
while (!endofstream) {
ci->yield();
if (ci->stop_codec || ci->new_track) {
break;
}
enum codec_command_action action = ci->get_command(&param);
if (ci->seek_time) {
struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME,
if (action == CODEC_ACTION_HALT)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME,
&read_buffer);
if (newpos->pos > format.numbytes)
{
ci->set_elapsed(ci->id3->length);
ci->seek_complete();
break;
}
if (ci->seek_buffer(firstblockposn + newpos->pos))
{
bytesdone = newpos->pos;
decodedsamples = newpos->samples;
}
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
ci->seek_complete();
}
@ -429,11 +419,10 @@ next_track:
endofstream = 1;
}
status = codec->decode(wavbuf, n, samples, &bufcount);
if (status == CODEC_ERROR)
if (codec->decode(wavbuf, n, samples, &bufcount) == CODEC_ERROR)
{
DEBUGF("codec error\n");
goto done;
return CODEC_ERROR;
}
ci->pcmbuf_insert(samples, NULL, bufcount);
@ -445,12 +434,6 @@ next_track:
endofstream = 1;
ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
}
status = CODEC_OK;
done:
if (ci->request_next_track())
goto next_track;
exit:
return status;
return CODEC_OK;
}

View file

@ -345,23 +345,32 @@ static bool init_encoder(void)
return true;
} /* init_encoder */
/* main codec entry point */
enum codec_status codec_main(void)
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
if (!init_encoder())
return CODEC_ERROR;
}
else if (reason == CODEC_UNLOAD) {
/* reset parameters to initial state */
ci->enc_set_parameters(NULL);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
/* main encoding loop */
while(!ci->stop_codec)
{
uint32_t *src;
while ((src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL)
while(ci->get_command(NULL) != CODEC_ACTION_HALT)
{
uint32_t *src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE);
struct enc_chunk_hdr *chunk;
if (ci->stop_codec)
break;
if(src == NULL)
continue;
chunk = ci->enc_get_chunk();
chunk->enc_size = enc_size;
@ -371,14 +380,7 @@ enum codec_status codec_main(void)
chunk_to_wav_format(src, (uint32_t *)chunk->enc_data);
ci->enc_finish_chunk();
ci->yield();
}
ci->yield();
}
/* reset parameters to initial state */
ci->enc_set_parameters(NULL);
return CODEC_OK;
} /* codec_start */
}

View file

@ -31,39 +31,39 @@ static int32_t temp_buffer [BUFFER_SIZE] IBSS_ATTR;
static int32_t read_callback (void *buffer, int32_t bytes)
{
int32_t retval = ci->read_filebuf (buffer, bytes);
ci->id3->offset = ci->curpos;
ci->set_offset(ci->curpos);
return retval;
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
WavpackContext *wpc;
char error [80];
int bps, nchans, sr_100;
int retval;
intptr_t param;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
if (codec_init())
return CODEC_ERROR;
next_track:
retval = CODEC_OK;
if (codec_init()) {
retval = CODEC_ERROR;
goto exit;
}
if (codec_wait_taginfo() != 0)
goto done;
ci->seek_buffer (ci->id3->offset);
/* Create a decoder instance */
wpc = WavpackOpenFileInput (read_callback, error);
if (!wpc) {
retval = CODEC_ERROR;
goto done;
}
if (!wpc)
return CODEC_ERROR;
ci->configure(DSP_SWITCH_FREQUENCY, WavpackGetSampleRate (wpc));
codec_set_replaygain(ci->id3);
@ -78,55 +78,47 @@ next_track:
while (1) {
int32_t nsamples;
enum codec_command_action action = ci->get_command(&param);
if (ci->seek_time && ci->taginfo_ready && ci->id3->length) {
ci->seek_time--;
if (action == CODEC_ACTION_HALT)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10;
int n, d, skip;
if (ci->seek_time > curpos_ms) {
n = ci->seek_time - curpos_ms;
if (param > curpos_ms) {
n = param - curpos_ms;
d = ci->id3->length - curpos_ms;
skip = (int)((int64_t)(ci->filesize - ci->curpos) * n / d);
ci->seek_buffer (ci->curpos + skip);
}
else {
n = curpos_ms - ci->seek_time;
else if (curpos_ms != 0) {
n = curpos_ms - param;
d = curpos_ms;
skip = (int)((int64_t) ci->curpos * n / d);
ci->seek_buffer (ci->curpos - skip);
}
wpc = WavpackOpenFileInput (read_callback, error);
ci->seek_complete();
if (!wpc)
{
ci->seek_complete();
break;
}
ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10);
ci->yield ();
ci->seek_complete();
}
nsamples = WavpackUnpackSamples (wpc, temp_buffer, BUFFER_SIZE / nchans);
if (!nsamples || ci->stop_codec || ci->new_track)
break;
ci->yield ();
if (ci->stop_codec || ci->new_track)
if (!nsamples)
break;
ci->pcmbuf_insert (temp_buffer, NULL, nsamples);
ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10);
ci->yield ();
}
done:
if (ci->request_next_track())
goto next_track;
exit:
return retval;
return CODEC_OK;
}

View file

@ -389,28 +389,36 @@ static bool init_encoder(void)
return true;
} /* init_encoder */
enum codec_status codec_main(void)
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* initialize params and config */
if (!init_encoder())
return CODEC_ERROR;
}
else if (reason == CODEC_UNLOAD) {
/* reset parameters to initial state */
ci->enc_set_parameters(NULL);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
/* main encoding loop */
while(!ci->stop_codec)
{
uint8_t *src;
while ((src = ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL)
while(ci->get_command(NULL) != CODEC_ACTION_HALT)
{
uint8_t *src = (uint8_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE);
struct enc_chunk_hdr *chunk;
bool abort_chunk;
uint8_t *dst;
uint8_t *src_end;
if(ci->stop_codec)
break;
abort_chunk = true;
if(src == NULL)
continue;
chunk = ci->enc_get_chunk();
@ -430,14 +438,14 @@ enum codec_status codec_main(void)
/* encode chunk in four steps yielding between each */
do
{
abort_chunk = true;
if (WavpackPackSamples(wpc, (int32_t *)src,
PCM_SAMP_PER_CHUNK/4))
{
chunk->num_pcm += PCM_SAMP_PER_CHUNK/4;
ci->yield();
/* could've been stopped in some way */
abort_chunk = ci->stop_codec ||
(chunk->flags & CHUNKF_ABORT);
abort_chunk = chunk->flags & CHUNKF_ABORT;
}
src += input_step;
@ -455,11 +463,5 @@ enum codec_status codec_main(void)
}
}
ci->yield();
}
/* reset parameters to initial state */
ci->enc_set_parameters(NULL);
return CODEC_OK;
} /* codec_start */
}

View file

@ -29,53 +29,52 @@ CODEC_HEADER
static WMADecodeContext wmadec;
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
uint32_t elapsedtime;
int retval;
asf_waveformatex_t wfx;
size_t resume_offset;
int i;
int wmares, res;
int wmares;
int res = 0;
uint8_t* audiobuf;
int audiobufsize;
int packetlength = 0;
int errcount = 0;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
next_track:
retval = CODEC_OK;
intptr_t param;
/* Proper reset of the decoder context. */
memset(&wmadec, 0, sizeof(wmadec));
/* Wait for the metadata to be read */
if (codec_wait_taginfo() != 0)
goto done;
/* Remember the resume position - when the codec is opened, the
playback engine will reset it. */
resume_offset = ci->id3->offset;
restart_track:
retval = CODEC_OK;
if (codec_init()) {
LOGF("WMA: Error initialising codec\n");
retval = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
/* Copy the format metadata we've stored in the id3 TOC field. This
saves us from parsing it again here. */
memcpy(&wfx, ci->id3->toc, sizeof(wfx));
ci->seek_buffer(ci->id3->first_frame_offset);
if (wma_decode_init(&wmadec,&wfx) < 0) {
LOGF("WMA: Unsupported or corrupt file\n");
retval = CODEC_ERROR;
goto exit;
return CODEC_ERROR;
}
if (resume_offset > ci->id3->first_frame_offset)
@ -101,34 +100,35 @@ restart_track:
codec_set_replaygain(ci->id3);
/* The main decoding loop */
res = 1;
while (res >= 0)
{
ci->yield();
if (ci->stop_codec || ci->new_track) {
goto done;
}
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
/* Deal with any pending seek requests */
if (ci->seek_time){
if (action == CODEC_ACTION_SEEK_TIME) {
if (ci->seek_time == 1) {
if (param == 0) {
ci->set_elapsed(0);
ci->seek_complete();
goto restart_track; /* Pretend you never saw this... */
}
elapsedtime = asf_seek(ci->seek_time, &wfx);
elapsedtime = asf_seek(param, &wfx);
if (elapsedtime < 1){
ci->set_elapsed(0);
ci->seek_complete();
goto next_track;
break;
}
/*DEBUGF("Seek returned %d\n", (int)elapsedtime);*/
ci->set_elapsed(elapsedtime);
/*flush the wma decoder state*/
wmadec.last_superframe_len = 0;
wmadec.last_bitoffset = 0;
ci->set_elapsed(elapsedtime);
ci->seek_complete();
}
errcount = 0;
@ -140,10 +140,15 @@ new_packet:
* times. If we succeed, the error counter will be reset.
*/
if (res == ASF_ERROR_EOF) {
/* File ended - not an error */
break;
}
errcount++;
DEBUGF("read_packet error %d, errcount %d\n",wmares, errcount);
if (errcount > 5) {
goto done;
return CODEC_ERROR;
} else {
ci->advance_buffer(packetlength);
goto new_packet;
@ -163,7 +168,7 @@ new_packet:
errcount++;
DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount);
if (errcount > 5) {
goto done;
return CODEC_ERROR;
} else {
ci->advance_buffer(packetlength);
goto new_packet;
@ -173,18 +178,12 @@ new_packet:
elapsedtime += (wmares*10)/(wfx.rate/100);
ci->set_elapsed(elapsedtime);
}
ci->yield();
}
}
ci->advance_buffer(packetlength);
}
done:
/*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/
if (ci->request_next_track())
goto next_track;
exit:
return retval;
return CODEC_OK;
}

View file

@ -27,11 +27,22 @@ CODEC_HEADER
int32_t *dec[2]; /* pointers to the output buffers in WMAProDecodeCtx in wmaprodec.c */
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, WMAPRO_DSP_SAMPLE_DEPTH);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
uint32_t elapsedtime;
int retval;
asf_waveformatex_t wfx; /* Holds the stream properties */
size_t resume_offset;
int res; /* Return values from asf_read_packet() and decode_packet() */
@ -42,28 +53,15 @@ enum codec_status codec_main(void)
int pktcnt = 0; /* Count of the packets played */
uint8_t *data; /* Pointer to decoder input buffer */
int size; /* Size of the input frame to the decoder */
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, WMAPRO_DSP_SAMPLE_DEPTH);
next_track:
retval = CODEC_OK;
/* Wait for the metadata to be read */
if (codec_wait_taginfo() != 0)
goto done;
intptr_t param;
/* Remember the resume position */
resume_offset = ci->id3->offset;
restart_track:
retval = CODEC_OK;
if (codec_init()) {
LOGF("(WMA PRO) Error: Error initialising codec\n");
retval = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* Copy the format metadata we've stored in the id3 TOC field. This
@ -77,8 +75,7 @@ restart_track:
if (decode_init(&wfx) < 0) {
LOGF("(WMA PRO) Error: Unsupported or corrupt file\n");
retval = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* Now advance the file position to the first frame */
@ -91,23 +88,24 @@ restart_track:
while (pktcnt < wfx.numpackets)
{
ci->yield();
if (ci->stop_codec || ci->new_track) {
goto done;
}
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
/* Deal with any pending seek requests */
if (ci->seek_time){
if (ci->seek_time == 1) {
if (action == CODEC_ACTION_SEEK_TIME) {
if (param == 0) {
ci->set_elapsed(0);
ci->seek_complete();
goto restart_track; /* Pretend you never saw this... */
}
elapsedtime = asf_seek(ci->seek_time, &wfx);
elapsedtime = asf_seek(param, &wfx);
if (elapsedtime < 1){
ci->set_elapsed(0);
ci->seek_complete();
goto next_track;
break;
}
ci->set_elapsed(elapsedtime);
@ -118,7 +116,7 @@ restart_track:
if (res < 0) {
LOGF("(WMA PRO) Warning: asf_read_packet returned %d", res);
goto done;
return CODEC_ERROR;
} else {
data = audiobuf;
size = audiobufsize;
@ -132,7 +130,7 @@ restart_track:
res = decode_packet(&wfx, dec, &outlen, data, size);
if(res < 0) {
LOGF("(WMA PRO) Error: decode_packet returned %d", res);
goto done;
return CODEC_ERROR;
}
data += res;
size -= res;
@ -152,10 +150,6 @@ restart_track:
ci->advance_buffer(packetlength);
}
done:
if (ci->request_next_track())
goto next_track;
return retval;
return CODEC_OK;
}

View file

@ -52,10 +52,20 @@ static void init_codec_ctx(AVCodecContext *avctx, asf_waveformatex_t *wfx)
}
/* this is the codec entry point */
enum codec_status codec_main(void)
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, 31);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
uint32_t elapsedtime;
int retval;
asf_waveformatex_t wfx; /* Holds the stream properties */
size_t resume_offset;
int res; /* Return values from asf_read_packet() and decode_packet() */
@ -64,27 +74,14 @@ enum codec_status codec_main(void)
int packetlength = 0; /* Logical packet size (minus the header size) */
int outlen = 0; /* Number of bytes written to the output buffer */
int pktcnt = 0; /* Count of the packets played */
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, 31);
next_track:
retval = CODEC_OK;
/* Wait for the metadata to be read */
if (codec_wait_taginfo() != 0)
goto done;
intptr_t param;
/* Remember the resume position */
resume_offset = ci->id3->offset;
restart_track:
retval = CODEC_OK;
if (codec_init()) {
LOGF("(WMA Voice) Error: Error initialising codec\n");
retval = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* Copy the format metadata we've stored in the id3 TOC field. This
@ -98,13 +95,14 @@ restart_track:
STEREO_MONO : STEREO_INTERLEAVED);
codec_set_replaygain(ci->id3);
ci->seek_buffer(0);
/* Initialise the AVCodecContext */
init_codec_ctx(&avctx, &wfx);
if (wmavoice_decode_init(&avctx) < 0) {
LOGF("(WMA Voice) Error: Unsupported or corrupt file\n");
retval = CODEC_ERROR;
goto done;
return CODEC_ERROR;
}
/* Now advance the file position to the first frame */
@ -117,21 +115,24 @@ restart_track:
while (pktcnt < wfx.numpackets)
{
ci->yield();
if (ci->stop_codec || ci->new_track) {
goto done;
}
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
/* Deal with any pending seek requests */
if (ci->seek_time){
if (action == CODEC_ACTION_SEEK_TIME) {
ci->set_elapsed(param);
if (ci->seek_time == 1) {
if (param == 0) {
ci->set_elapsed(0);
ci->seek_complete();
goto restart_track; /* Pretend you never saw this... */
}
elapsedtime = asf_seek(ci->seek_time, &wfx);
elapsedtime = asf_seek(param, &wfx);
if (elapsedtime < 1){
ci->set_elapsed(0);
ci->seek_complete();
goto next_track;
}
@ -145,7 +146,7 @@ new_packet:
if (res < 0) {
LOGF("(WMA Voice) read_packet error %d\n",res);
goto done;
return CODEC_ERROR;
} else {
avpkt.data = audiobuf;
avpkt.size = audiobufsize;
@ -165,8 +166,9 @@ new_packet:
ci->advance_buffer(packetlength);
goto new_packet;
}
else
goto done;
else {
return CODEC_ERROR;
}
}
avpkt.data += res;
avpkt.size -= res;
@ -186,10 +188,6 @@ new_packet:
ci->advance_buffer(packetlength);
}
done:
if (ci->request_next_track())
goto next_track;
return retval;
return CODEC_OK;
}

View file

@ -219,10 +219,10 @@ static int skintouch_to_wps(struct wps_data *data)
#endif
case ACTION_TOUCH_SCROLLBAR:
skin_get_global_state()->id3->elapsed = skin_get_global_state()->id3->length*offset/100;
if (!skin_get_global_state()->paused)
#if (CONFIG_CODEC == SWCODEC)
audio_pre_ff_rewind();
#else
if (!skin_get_global_state()->paused)
audio_pause();
#endif
audio_ff_rewind(skin_get_global_state()->id3->elapsed);
@ -300,10 +300,10 @@ bool ffwd_rew(int button)
if ( (audio_status() & AUDIO_STATUS_PLAY) &&
skin_get_global_state()->id3 && skin_get_global_state()->id3->length )
{
if (!skin_get_global_state()->paused)
#if (CONFIG_CODEC == SWCODEC)
audio_pre_ff_rewind();
#else
if (!skin_get_global_state()->paused)
audio_pause();
#endif
#if CONFIG_KEYPAD == PLAYER_PAD
@ -472,10 +472,10 @@ static void prev_track(unsigned long skip_thresh)
return;
}
if (!state->paused)
#if (CONFIG_CODEC == SWCODEC)
audio_pre_ff_rewind();
#else
if (!state->paused)
audio_pause();
#endif
@ -554,16 +554,20 @@ static void play_hop(int direction)
{
elapsed += step * direction;
}
if((audio_status() & AUDIO_STATUS_PLAY) && !state->paused)
if(audio_status() & AUDIO_STATUS_PLAY)
{
#if (CONFIG_CODEC == SWCODEC)
audio_pre_ff_rewind();
#else
if (!state->paused)
audio_pause();
#endif
}
#if (CONFIG_CODEC == SWCODEC)
audio_ff_rewind(elapsed);
#else
audio_ff_rewind(state->id3->elapsed = elapsed);
#if (CONFIG_CODEC != SWCODEC)
if (!state->paused)
audio_resume();
#endif
@ -849,10 +853,10 @@ long gui_wps_show(void)
{
if (state->id3->cuesheet)
{
if (!state->paused)
#if (CONFIG_CODEC == SWCODEC)
audio_pre_ff_rewind();
#else
if (!state->paused)
audio_pause();
#endif
audio_ff_rewind(0);
@ -1146,6 +1150,17 @@ static void nextid3available_callback(void* param)
skin_request_full_update(WPS);
}
#ifdef AUDIO_FAST_SKIP_PREVIEW
/* this is called on the audio_skip caller thread */
static void track_skip_callback(void *param)
{
struct wps_state *state = skin_get_global_state();
state->id3 = audio_current_track();
state->nid3 = audio_next_track();
skin_request_full_update(WPS);
(void)param;
}
#endif /* AUDIO_FAST_SKIP_PREVIEW */
static void wps_state_init(void)
{
@ -1167,6 +1182,9 @@ static void wps_state_init(void)
/* add the WPS track event callbacks */
add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, track_changed_callback);
add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, false, nextid3available_callback);
#ifdef AUDIO_FAST_SKIP_PREVIEW
add_event(PLAYBACK_EVENT_TRACK_SKIP, false, track_skip_callback);
#endif
}

View file

@ -159,9 +159,13 @@ static int cuesheet_callback(int action,const struct menu_item_ex *this_item)
switch (action)
{
case ACTION_EXIT_MENUITEM: /* on exit */
#if CONFIG_CODEC == SWCODEC
audio_set_cuesheet(global_settings.cuesheet);
#else
if (global_settings.cuesheet)
splash(HZ*2, ID2P(LANG_PLEASE_REBOOT));
break;
#endif
}
return action;
}

View file

@ -33,7 +33,7 @@
#if CONFIG_CODEC == SWCODEC
/* For trailing tag stripping */
/* For trailing tag stripping and base audio data types */
#include "buffering.h"
#include "metadata/metadata_common.h"
@ -239,6 +239,94 @@ const int afmt_rec_format[AFMT_NUM_CODECS] =
};
#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
#if CONFIG_CODEC == SWCODEC
/* Get the canonical AFMT type */
int get_audio_base_codec_type(int type)
{
int base_type = type;
switch (type) {
case AFMT_MPA_L1:
case AFMT_MPA_L2:
case AFMT_MPA_L3:
base_type = AFMT_MPA_L3;
break;
case AFMT_MPC_SV7:
case AFMT_MPC_SV8:
base_type = AFMT_MPC_SV7;
break;
case AFMT_MP4_AAC:
case AFMT_MP4_AAC_HE:
base_type = AFMT_MP4_AAC;
break;
case AFMT_SAP:
case AFMT_CMC:
case AFMT_CM3:
case AFMT_CMR:
case AFMT_CMS:
case AFMT_DMC:
case AFMT_DLT:
case AFMT_MPT:
case AFMT_MPD:
case AFMT_RMT:
case AFMT_TMC:
case AFMT_TM8:
case AFMT_TM2:
base_type = AFMT_SAP;
break;
default:
break;
}
return base_type;
}
/* Get the basic audio type */
enum data_type get_audio_base_data_type(int afmt)
{
if ((unsigned)afmt >= AFMT_NUM_CODECS)
return TYPE_UNKNOWN;
switch (get_audio_base_codec_type(afmt))
{
case AFMT_NSF:
case AFMT_SPC:
case AFMT_SID:
case AFMT_MOD:
case AFMT_SAP:
/* Type must be allocated and loaded in its entirety onto
the buffer */
return TYPE_ATOMIC_AUDIO;
default:
/* Assume type may be loaded and discarded incrementally */
return TYPE_PACKET_AUDIO;
case AFMT_UNKNOWN:
/* Have no idea at all */
return TYPE_UNKNOWN;
}
}
/* Is the format allowed to buffer starting at some offset other than 0
or first frame only for resume purposes? */
bool format_buffers_with_offset(int afmt)
{
switch (afmt)
{
case AFMT_MPA_L1:
case AFMT_MPA_L2:
case AFMT_MPA_L3:
case AFMT_WAVPACK:
/* Format may be loaded at the first needed frame */
return true;
default:
/* Format must be loaded from the beginning of the file
(does not imply 'atomic', while 'atomic' implies 'no offset') */
return false;
}
}
#endif /* CONFIG_CODEC == SWCODEC */
/* Simple file type probing by looking at the filename extension. */
unsigned int probe_file_format(const char *filename)
@ -313,7 +401,7 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
}
/* Clear the mp3entry to avoid having bogus pointers appear */
memset(id3, 0, sizeof(struct mp3entry));
wipe_mp3entry(id3);
/* Take our best guess at the codec type based on file extension */
id3->codectype = probe_file_format(trackname);
@ -414,6 +502,44 @@ void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig)
adjust_mp3entry(dest, dest, orig);
}
/* A shortcut to simplify the common task of clearing the struct */
void wipe_mp3entry(struct mp3entry *id3)
{
memset(id3, 0, sizeof (struct mp3entry));
}
#if CONFIG_CODEC == SWCODEC
/* Glean what is possible from the filename alone - does not parse metadata */
void fill_metadata_from_path(struct mp3entry *id3, const char *trackname)
{
char *p;
/* Clear the mp3entry to avoid having bogus pointers appear */
wipe_mp3entry(id3);
/* Find the filename portion of the path */
p = strrchr(trackname, '/');
strlcpy(id3->id3v2buf, p ? ++p : id3->path, ID3V2_BUF_SIZE);
/* Get the format from the extension and trim it off */
p = strrchr(id3->id3v2buf, '.');
if (p)
{
/* Might be wrong for container formats - should we bother? */
id3->codectype = probe_file_format(p);
if (id3->codectype != AFMT_UNKNOWN)
*p = '\0';
}
/* Set the filename as the title */
id3->title = id3->id3v2buf;
/* Copy the path info */
strlcpy(id3->path, trackname, sizeof (id3->path));
}
#endif /* CONFIG_CODEC == SWCODEC */
#ifndef __PCTOOL__
#ifdef HAVE_TAGCACHE
#if CONFIG_CODEC == SWCODEC

View file

@ -266,9 +266,7 @@ struct mp3entry {
/* resume related */
unsigned long offset; /* bytes played */
#if CONFIG_CODEC != SWCODEC
int index; /* playlist index */
#endif
#ifdef HAVE_TAGCACHE
unsigned char autoresumable; /* caches result of autoresumable() */
@ -309,9 +307,14 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname);
bool mp3info(struct mp3entry *entry, const char *filename);
void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig);
void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig);
void wipe_mp3entry(struct mp3entry *id3);
#if CONFIG_CODEC == SWCODEC
void fill_metadata_from_path(struct mp3entry *id3, const char *trackname);
int get_audio_base_codec_type(int type);
void strip_tags(int handle_id);
enum data_type get_audio_base_data_type(int afmt);
bool format_buffers_with_offset(int afmt);
#endif
#ifdef HAVE_TAGCACHE

View file

@ -40,6 +40,9 @@ bool get_nsf_metadata(int fd, struct mp3entry* id3)
p = id3->id3v2buf;
/* Length */
id3->length = buf[6]*1000;
/* Title */
memcpy(p, &buf[14], 32);
id3->title = p;

View file

@ -86,6 +86,8 @@ static size_t pcmbuffer_pos IDATA_ATTR;
/* Amount pcmbuffer_pos will be increased.*/
static size_t pcmbuffer_fillpos IDATA_ATTR;
static struct chunkdesc *first_desc;
/* Gapless playback */
static bool track_transition IDATA_ATTR;
@ -144,6 +146,11 @@ static void write_to_crossfade(size_t length);
static void pcmbuf_finish_crossfade_enable(void);
#endif
/* Callbacks into playback.c */
extern void audio_pcmbuf_position_callback(unsigned int time);
extern void audio_pcmbuf_track_change(bool pcmbuf);
extern bool audio_pcmbuf_may_play(void);
/**************************************/
@ -153,9 +160,8 @@ static void pcmbuf_finish_crossfade_enable(void);
#ifndef SIMULATOR
#undef DESC_DEBUG
#endif
#ifdef DESC_DEBUG
static struct chunkdesc *first_desc;
static bool show_desc_in_use = false;
#define DISPLAY_DESC(caller) while(!show_desc(caller))
#define DESC_IDX(desc) (desc ? desc - first_desc : -1)
#define SHOW_DESC(desc) if(DESC_IDX(desc)==-1) DEBUGF("--"); \
@ -231,6 +237,7 @@ static void commit_chunk(bool flush_next_time)
/* Flush! Discard all data after the currently playing chunk,
and make the current chunk play next */
logf("commit_chunk: flush");
pcm_play_lock();
write_end_chunk->link = read_chunk->link;
read_chunk->link = pcmbuf_current;
while (write_end_chunk->link)
@ -238,6 +245,9 @@ static void commit_chunk(bool flush_next_time)
write_end_chunk = write_end_chunk->link;
pcmbuf_unplayed_bytes -= write_end_chunk->size;
}
read_chunk->end_of_track = track_transition;
pcm_play_unlock();
}
/* If there is already a read buffer setup, add to it */
else
@ -354,7 +364,7 @@ static bool prepare_insert(size_t length)
#endif
{
logf("pcm starting");
if (!(audio_status() & AUDIO_STATUS_PAUSE))
if (audio_pcmbuf_may_play())
pcmbuf_play_start();
}
}
@ -373,9 +383,13 @@ void *pcmbuf_request_buffer(int *count)
/* crossfade has begun, put the new track samples in fadebuf */
if (crossfade_active)
{
*count = MIN(*count, CROSSFADE_BUFSIZE/4);
int cnt = MIN(*count, CROSSFADE_BUFSIZE/4);
if (prepare_insert(cnt << 2))
{
*count = cnt;
return fadebuf;
}
}
else
#endif
/* if possible, reserve room in the PCM buffer for new samples */
@ -421,9 +435,7 @@ void pcmbuf_write_complete(int count)
static inline void init_pcmbuffers(void)
{
#ifdef DESC_DEBUG
first_desc = write_chunk;
#endif
struct chunkdesc *next = write_chunk;
next++;
write_end_chunk = write_chunk;
@ -494,19 +506,27 @@ void pcmbuf_monitor_track_change(bool monitor)
currently playing chunk. If not, cancel notification. */
track_transition = monitor;
read_end_chunk->end_of_track = monitor;
if (!monitor)
{
/* Clear all notifications */
struct chunkdesc *desc = first_desc;
struct chunkdesc *end = desc + pcmbuf_descs();
while (desc < end)
desc++->end_of_track = false;
}
}
else
{
/* Post now if PCM stopped and last buffer was sent. */
track_transition = false;
if (monitor)
audio_post_track_change(false);
audio_pcmbuf_track_change(false);
}
pcm_play_unlock();
}
void pcmbuf_start_track_change(bool auto_skip)
bool pcmbuf_start_track_change(bool auto_skip)
{
bool crossfade = false;
#ifdef HAVE_CROSSFADE
@ -547,9 +567,6 @@ void pcmbuf_start_track_change(bool auto_skip)
/* Cancel any pending automatic gapless transition */
pcmbuf_monitor_track_change(false);
/* Notify the wps that the track change starts now */
audio_post_track_change(false);
/* Can't do two crossfades at once and, no fade if pcm is off now */
if (
#ifdef HAVE_CROSSFADE
@ -559,7 +576,8 @@ void pcmbuf_start_track_change(bool auto_skip)
{
pcmbuf_play_stop();
pcm_play_unlock();
return;
/* Notify playback that the track change starts now */
return true;
}
/* Not enough data, or not crossfading, flush the old data instead */
@ -584,6 +602,9 @@ void pcmbuf_start_track_change(bool auto_skip)
/* Keep trigger outside the play lock or HW FIFO underruns can happen
since frequency scaling is *not* always fast */
trigger_cpu_boost();
/* Notify playback that the track change starts now */
return true;
}
else /* automatic and not crossfading, so do gapless track change */
{
@ -593,6 +614,7 @@ void pcmbuf_start_track_change(bool auto_skip)
* as the last one in the track. */
logf(" gapless track change");
pcmbuf_monitor_track_change(true);
return false;
}
}
@ -623,7 +645,7 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size)
if (pcmbuf_current->end_of_track)
{
track_transition = false;
audio_post_track_change(true);
audio_pcmbuf_track_change(true);
}
/* Put the finished chunk back into circulation */
@ -955,9 +977,6 @@ static void write_to_crossfade(size_t length)
return;
}
/* Commit samples to the buffer */
while (!prepare_insert(length))
sleep(1);
while (length > 0)
{
COMMIT_IF_NEEDED;

View file

@ -33,13 +33,21 @@ void pcmbuf_play_start(void);
void pcmbuf_play_stop(void);
void pcmbuf_pause(bool pause);
void pcmbuf_monitor_track_change(bool monitor);
void pcmbuf_start_track_change(bool manual_skip);
bool pcmbuf_start_track_change(bool manual_skip);
/* Crossfade */
#ifdef HAVE_CROSSFADE
bool pcmbuf_is_crossfade_active(void);
void pcmbuf_request_crossfade_enable(bool on_off);
bool pcmbuf_is_same_size(void);
#else
/* Dummy functions with sensible returns */
static inline bool pcmbuf_is_crossfade_active(void)
{ return false; }
static inline void pcmbuf_request_crossfade_enable(bool on_off)
{ return; (void)on_off; }
static inline bool pcmbuf_is_same_size(void)
{ return true; }
#endif
/* Voice */

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,16 @@
#include <stdlib.h>
#include "config.h"
#if CONFIG_CODEC == SWCODEC
/* Including the code for fast previews is entirely optional since it
does add two more mp3entry's - for certain targets it may be less
beneficial such as flash-only storage */
#if MEMORYSIZE > 2
#define AUDIO_FAST_SKIP_PREVIEW
#endif
#endif /* CONFIG_CODEC == SWCODEC */
#ifdef HAVE_ALBUMART
#include "bmp.h"
@ -67,6 +77,8 @@ long audio_filebufused(void);
void audio_pre_ff_rewind(void);
void audio_skip(int direction);
void audio_hard_stop(void); /* Stops audio from serving playback */
void audio_set_cuesheet(int enable);
#ifdef HAVE_CROSSFADE
void audio_set_crossfade(int enable);
#endif
@ -78,11 +90,10 @@ enum
};
bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
size_t audio_get_filebuflen(void);
void audio_pcmbuf_position_callback(unsigned int time) ICODE_ATTR;
void audio_post_track_change(bool pcmbuf);
int get_audio_hid(void);
void audio_set_prev_elapsed(unsigned long setting);
bool audio_buffer_state_trashed(void);
/* Automatic transition? Only valid to call during the track change events,
otherwise the result is undefined. */
bool audio_automatic_skip(void);
/* Define one constant that includes recording related functionality */
@ -91,35 +102,62 @@ bool audio_automatic_skip(void);
#endif
enum {
Q_NULL = 0,
Q_NULL = 0, /* reserved */
/* -> audio */
Q_AUDIO_PLAY = 1,
Q_AUDIO_STOP,
Q_AUDIO_PAUSE,
Q_AUDIO_SKIP,
Q_AUDIO_PRE_FF_REWIND,
Q_AUDIO_FF_REWIND,
Q_AUDIO_CHECK_NEW_TRACK,
Q_AUDIO_FLUSH,
Q_AUDIO_TRACK_CHANGED,
Q_AUDIO_SEEK_COMPLETE,
Q_AUDIO_DIR_SKIP,
Q_AUDIO_POSTINIT,
Q_AUDIO_FILL_BUFFER,
Q_AUDIO_FINISH_LOAD,
Q_CODEC_REQUEST_COMPLETE,
Q_CODEC_REQUEST_FAILED,
/* pcmbuf -> audio */
Q_AUDIO_TRACK_CHANGED,
/* audio -> audio */
Q_AUDIO_FILL_BUFFER, /* continue buffering next track */
/* buffering -> audio */
Q_AUDIO_BUFFERING, /* some buffer event */
Q_AUDIO_FINISH_LOAD_TRACK, /* metadata is buffered */
Q_AUDIO_HANDLE_FINISHED, /* some other type is buffered */
/* codec -> audio (*) */
Q_AUDIO_CODEC_SEEK_COMPLETE,
Q_AUDIO_CODEC_COMPLETE,
/* audio -> codec */
Q_CODEC_LOAD,
Q_CODEC_LOAD_DISK,
Q_CODEC_RUN,
Q_CODEC_PAUSE,
Q_CODEC_SEEK,
Q_CODEC_STOP,
Q_CODEC_UNLOAD,
/*- miscellanous -*/
#ifdef AUDIO_HAVE_RECORDING
Q_AUDIO_LOAD_ENCODER,
Q_ENCODER_LOAD_DISK,
Q_ENCODER_RECORD,
/* -> codec */
Q_AUDIO_LOAD_ENCODER, /* load an encoder for recording */
#endif
/* -> codec */
Q_CODEC_DO_CALLBACK,
Q_CODEC_ACK,
/*- settings -*/
#ifdef HAVE_DISK_STORAGE
/* -> audio */
Q_AUDIO_UPDATE_WATERMARK, /* buffering watermark needs updating */
#endif
/* -> audio */
Q_AUDIO_REMAKE_AUDIO_BUFFER, /* buffer needs to be reinitialized */
};
#endif
/* (*) If you change these, you must check audio_clear_track_notifications
in playback.c for correctness */
#endif /* _PLAYBACK_H */

View file

@ -822,9 +822,6 @@ static int add_track_to_playlist(struct playlist_info* playlist,
playlist->amount++;
playlist->num_inserted_tracks++;
/* Update index for resume. */
playlist_update_resume_index();
return insert_position;
}
@ -925,9 +922,6 @@ static int remove_track_from_playlist(struct playlist_info* playlist,
sync_control(playlist, false);
}
/* Update index for resume. */
playlist_update_resume_index();
return 0;
}
@ -987,9 +981,6 @@ static int randomise_playlist(struct playlist_info* playlist,
playlist->first_index, NULL, NULL, NULL);
}
/* Update index for resume. */
playlist_update_resume_index();
return 0;
}
@ -1030,9 +1021,6 @@ static int sort_playlist(struct playlist_info* playlist, bool start_current,
playlist->first_index, -1, NULL, NULL, NULL);
}
/* Update index for resume. */
playlist_update_resume_index();
return 0;
}
@ -1205,9 +1193,6 @@ static void find_and_set_playlist_index(struct playlist_info* playlist,
break;
}
}
/* Update index for resume. */
playlist_update_resume_index();
}
/*
@ -2486,6 +2471,12 @@ const char* playlist_peek(int steps, char* buf, size_t buf_size)
if (index < 0)
return NULL;
#if CONFIG_CODEC == SWCODEC
/* Just testing - don't care about the file name */
if (!buf || !buf_size)
return "";
#endif
control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK;
seek = playlist->indices[index] & PLAYLIST_SEEK_MASK;
@ -2632,19 +2623,6 @@ int playlist_get_resume_info(int *resume_index)
return 0;
}
/* Get current playlist index. */
int playlist_get_index(void)
{
return current_playlist.index;
}
/* Update resume index within playlist_info structure. */
void playlist_update_resume_index(void)
{
struct playlist_info* playlist = &current_playlist;
playlist->resume_index = playlist->index;
}
/* Update resume info for current playing song. Returns -1 on error. */
int playlist_update_resume_info(const struct mp3entry* id3)
{
@ -2652,10 +2630,10 @@ int playlist_update_resume_info(const struct mp3entry* id3)
if (id3)
{
if (global_status.resume_index != playlist->resume_index ||
if (global_status.resume_index != playlist->index ||
global_status.resume_offset != id3->offset)
{
global_status.resume_index = playlist->resume_index;
global_status.resume_index = playlist->index;
global_status.resume_offset = id3->offset;
status_save();
}
@ -3203,9 +3181,6 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index)
queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0);
#endif
/* Update index for resume. */
playlist_update_resume_index();
return result;
}

View file

@ -90,7 +90,6 @@ struct playlist_info
int buffer_end_pos; /* last position where buffer was written */
int index; /* index of current playing track */
int first_index; /* index of first song in playlist */
int resume_index; /* index of playing track to resume */
int amount; /* number of tracks in the index */
int last_insert_pos; /* last position we inserted a track */
int seed; /* shuffle seed */
@ -132,7 +131,6 @@ const char *playlist_peek(int steps, char* buf, size_t buf_size);
int playlist_next(int steps);
bool playlist_next_dir(int direction);
int playlist_get_resume_info(int *resume_index);
int playlist_get_index(void);
int playlist_update_resume_info(const struct mp3entry* id3);
int playlist_get_display_index(void);
int playlist_amount(void);
@ -176,6 +174,5 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
int (*callback)(char*, void*),
void* context);
int playlist_remove_all_tracks(struct playlist_info *playlist);
void playlist_update_resume_index(void);
#endif /* __PLAYLIST_H__ */

View file

@ -692,7 +692,7 @@ static const struct plugin_api rockbox_api = {
#if CONFIG_CODEC == SWCODEC
codec_thread_do_callback,
codec_load_file,
codec_begin,
codec_run_proc,
codec_close,
get_codec_filename,
find_array_ptr,

View file

@ -145,12 +145,12 @@ void* plugin_get_buffer(size_t *buffer_size);
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 203
#define PLUGIN_API_VERSION 204
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
#define PLUGIN_MIN_API_VERSION 203
#define PLUGIN_MIN_API_VERSION 204
/* plugin return codes */
/* internal returns start at 0x100 to make exit(1..255) work */
@ -799,9 +799,9 @@ struct plugin_api {
#if CONFIG_CODEC == SWCODEC
void (*codec_thread_do_callback)(void (*fn)(void),
unsigned int *audio_thread_id);
void * (*codec_load_file)(const char* codec, struct codec_api *api);
int (*codec_begin)(void *handle);
void (*codec_close)(void *handle);
int (*codec_load_file)(const char* codec, struct codec_api *api);
int (*codec_run_proc)(void);
int (*codec_close)(void);
const char *(*get_codec_filename)(int cod_spec);
void ** (*find_array_ptr)(void **arr, void *ptr);
int (*remove_array_ptr)(void **arr, void *ptr);

View file

@ -127,7 +127,6 @@ struct test_track_info {
};
static struct test_track_info track;
static bool taginfo_ready = true;
static bool use_dsp;
@ -433,6 +432,7 @@ static void pcmbuf_insert_wav_checksum(const void *ch1, const void *ch2, int cou
static void set_elapsed(unsigned long value)
{
elapsed = value;
ci.id3->elapsed = value;
}
@ -482,6 +482,7 @@ static void* request_buffer(size_t *realsize, size_t reqsize)
static void advance_buffer(size_t amount)
{
ci.curpos += amount;
ci.id3->offset = ci.curpos;
}
@ -499,20 +500,17 @@ static void seek_complete(void)
/* Do nothing */
}
/* Request file change from file buffer. Returns true is next
track is available and changed. If return value is false,
codec should exit immediately with PLUGIN_OK status. */
static bool request_next_track(void)
/* Codec calls this to know what it should do next. */
static enum codec_command_action get_command(intptr_t *param)
{
/* We are only decoding a single track */
return false;
rb->yield();
return CODEC_ACTION_NULL; /* just continue processing */
(void)param;
}
static void set_offset(size_t value)
{
/* ??? */
(void)value;
ci.id3->offset = value;
}
@ -546,6 +544,9 @@ static void init_ci(void)
{
/* --- Our "fake" implementations of the codec API functions. --- */
ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP,
CODEC_IDX_AUDIO);
ci.codec_get_buffer = codec_get_buffer;
if (wavinfo.fd >= 0 || checksum) {
@ -560,11 +561,9 @@ static void init_ci(void)
ci.advance_buffer = advance_buffer;
ci.seek_buffer = seek_buffer;
ci.seek_complete = seek_complete;
ci.request_next_track = request_next_track;
ci.set_offset = set_offset;
ci.configure = configure;
ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP,
CODEC_IDX_AUDIO);
ci.get_command = get_command;
/* --- "Core" functions --- */
@ -620,20 +619,22 @@ static void init_ci(void)
static void codec_thread(void)
{
const char* codecname;
void *handle;
int res = CODEC_ERROR;
int res;
codecname = rb->get_codec_filename(track.id3.codectype);
/* Load the codec and start decoding. */
handle = rb->codec_load_file(codecname,&ci);
/* Load the codec */
res = rb->codec_load_file(codecname, &ci);
if (handle != NULL)
if (res >= 0)
{
res = rb->codec_begin(handle);
rb->codec_close(handle);
/* Decode the file */
res = rb->codec_run_proc();
}
/* Clean up */
rb->codec_close();
/* Signal to the main thread that we are done */
endtick = *rb->current_tick - rebuffertick;
codec_playing = false;
@ -705,11 +706,7 @@ static enum plugin_status test_track(const char* filename)
/* Prepare the codec struct for playing the whole file */
ci.filesize = track.filesize;
ci.id3 = &track.id3;
ci.taginfo_ready = &taginfo_ready;
ci.curpos = 0;
ci.stop_codec = false;
ci.new_track = 0;
ci.seek_time = 0;
if (use_dsp)
rb->dsp_configure(ci.dsp, DSP_RESET, 0);

View file

@ -86,6 +86,7 @@
#define SYS_VOLUME_CHANGED MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 5)
#define IS_SYSEVENT(ev) ((ev & SYS_EVENT) == SYS_EVENT)
#define EVENT_RESERVED (~0)
#ifndef TIMEOUT_BLOCK
#define TIMEOUT_BLOCK -1
@ -249,6 +250,15 @@ extern bool queue_in_queue_send(struct event_queue *q);
#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */
extern bool queue_empty(const struct event_queue* q);
extern bool queue_peek(struct event_queue *q, struct queue_event *ev);
#define QPEEK_FILTER_COUNT_MASK (0xffu) /* 0x00=1 filter, 0xff=256 filters */
#define QPEEK_FILTER_HEAD_ONLY (1u << 8) /* Ignored if no filters */
#define QPEEK_REMOVE_EVENTS (1u << 9) /* Remove or discard events */
extern bool queue_peek_ex(struct event_queue *q,
struct queue_event *ev,
unsigned int flags,
const long (*filters)[2]);
extern void queue_clear(struct event_queue* q);
extern void queue_remove_from_head(struct event_queue *q, long id);
extern int queue_count(const struct event_queue *q);

View file

@ -516,8 +516,10 @@ void queue_wait(struct event_queue *q, struct queue_event *ev)
oldlevel = disable_irq_save();
corelock_lock(&q->cl);
/* auto-reply */
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
/* Auto-reply (even if ev is NULL to avoid stalling a waiting thread) */
queue_do_auto_reply(q->send);
#endif
while(1)
{
@ -541,12 +543,18 @@ void queue_wait(struct event_queue *q, struct queue_event *ev)
corelock_lock(&q->cl);
}
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
if(ev)
#endif
{
q->read = rd + 1;
rd &= QUEUE_LENGTH_MASK;
*ev = q->events[rd];
/* Get data for a waiting thread if one */
queue_do_fetch_sender(q->send, rd);
}
/* else just waiting on non-empty */
corelock_unlock(&q->cl);
restore_irq(oldlevel);
@ -566,8 +574,10 @@ void queue_wait_w_tmo(struct event_queue *q, struct queue_event *ev, int ticks)
oldlevel = disable_irq_save();
corelock_lock(&q->cl);
/* Auto-reply */
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
/* Auto-reply (even if ev is NULL to avoid stalling a waiting thread) */
queue_do_auto_reply(q->send);
#endif
rd = q->read;
wr = q->write;
@ -590,6 +600,10 @@ void queue_wait_w_tmo(struct event_queue *q, struct queue_event *ev, int ticks)
wr = q->write;
}
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
if(ev)
#endif
{
/* no worry about a removed message here - status is checked inside
locks - perhaps verify if timeout or false alarm */
if (rd != wr)
@ -604,6 +618,8 @@ void queue_wait_w_tmo(struct event_queue *q, struct queue_event *ev, int ticks)
{
ev->id = SYS_TIMEOUT;
}
}
/* else just waiting on non-empty */
corelock_unlock(&q->cl);
restore_irq(oldlevel);
@ -740,6 +756,120 @@ void queue_reply(struct event_queue *q, intptr_t retval)
}
#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
/* Scan the even queue from head to tail, returning any event from the
filter list that was found, optionally removing the event. If an
event is returned, synchronous events are handled in the same manner as
with queue_wait(_w_tmo); if discarded, then as queue_clear.
If filters are NULL, any event matches. If filters exist, the default
is to search the full queue depth.
Earlier filters take precedence.
Return true if an event was found, false otherwise. */
bool queue_peek_ex(struct event_queue *q, struct queue_event *ev,
unsigned int flags, const long (*filters)[2])
{
bool have_msg;
unsigned int rd, wr;
int oldlevel;
if(LIKELY(q->read == q->write))
return false; /* Empty: do nothing further */
have_msg = false;
oldlevel = disable_irq_save();
corelock_lock(&q->cl);
/* Starting at the head, find first match */
for(rd = q->read, wr = q->write; rd != wr; rd++)
{
struct queue_event *e = &q->events[rd & QUEUE_LENGTH_MASK];
if(filters)
{
/* Have filters - find the first thing that passes */
const long (* f)[2] = filters;
const long (* const f_last)[2] =
&filters[flags & QPEEK_FILTER_COUNT_MASK];
long id = e->id;
do
{
if(UNLIKELY(id >= (*f)[0] && id <= (*f)[1]))
goto passed_filter;
}
while(++f <= f_last);
if(LIKELY(!(flags & QPEEK_FILTER_HEAD_ONLY)))
continue; /* No match; test next event */
else
break; /* Only check the head */
}
/* else - anything passes */
passed_filter:
/* Found a matching event */
have_msg = true;
if(ev)
*ev = *e; /* Caller wants the event */
if(flags & QPEEK_REMOVE_EVENTS)
{
/* Do event removal */
unsigned int r = q->read;
q->read = r + 1; /* Advance head */
if(ev)
{
/* Auto-reply */
queue_do_auto_reply(q->send);
/* Get the thread waiting for reply, if any */
queue_do_fetch_sender(q->send, rd & QUEUE_LENGTH_MASK);
}
else
{
/* Release any thread waiting on this message */
queue_do_unblock_sender(q->send, rd & QUEUE_LENGTH_MASK);
}
/* Slide messages forward into the gap if not at the head */
while(rd != r)
{
unsigned int dst = rd & QUEUE_LENGTH_MASK;
unsigned int src = --rd & QUEUE_LENGTH_MASK;
q->events[dst] = q->events[src];
/* Keep sender wait list in sync */
if(q->send)
q->send->senders[dst] = q->send->senders[src];
}
}
break;
}
corelock_unlock(&q->cl);
restore_irq(oldlevel);
return have_msg;
}
bool queue_peek(struct event_queue *q, struct queue_event *ev)
{
return queue_peek_ex(q, ev, 0, NULL);
}
void queue_remove_from_head(struct event_queue *q, long id)
{
const long f[2] = { id, id };
while (queue_peek_ex(q, NULL,
QPEEK_FILTER_HEAD_ONLY | QPEEK_REMOVE_EVENTS, &f));
}
#else /* !HAVE_EXTENDED_MESSAGING_AND_NAME */
/* The more powerful routines aren't required */
bool queue_peek(struct event_queue *q, struct queue_event *ev)
{
unsigned int rd;
@ -765,32 +895,6 @@ bool queue_peek(struct event_queue *q, struct queue_event *ev)
return have_msg;
}
/* Poll queue to see if a message exists - careful in using the result if
* queue_remove_from_head is called when messages are posted - possibly use
* queue_wait_w_tmo(&q, 0) in that case or else a removed message that
* unsignals the queue may cause an unwanted block */
bool queue_empty(const struct event_queue* q)
{
return ( q->read == q->write );
}
void queue_clear(struct event_queue* q)
{
int oldlevel;
oldlevel = disable_irq_save();
corelock_lock(&q->cl);
/* Release all threads waiting in the queue for a reply -
dequeued sent message will be handled by owning thread */
queue_release_all_senders(q);
q->read = q->write;
corelock_unlock(&q->cl);
restore_irq(oldlevel);
}
void queue_remove_from_head(struct event_queue *q, long id)
{
int oldlevel;
@ -816,6 +920,33 @@ void queue_remove_from_head(struct event_queue *q, long id)
corelock_unlock(&q->cl);
restore_irq(oldlevel);
}
#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */
/* Poll queue to see if a message exists - careful in using the result if
* queue_remove_from_head is called when messages are posted - possibly use
* queue_wait_w_tmo(&q, 0) in that case or else a removed message that
* unsignals the queue may cause an unwanted block */
bool queue_empty(const struct event_queue* q)
{
return ( q->read == q->write );
}
void queue_clear(struct event_queue* q)
{
int oldlevel;
oldlevel = disable_irq_save();
corelock_lock(&q->cl);
/* Release all threads waiting in the queue for a reply -
dequeued sent message will be handled by owning thread */
queue_release_all_senders(q);
q->read = q->write;
corelock_unlock(&q->cl);
restore_irq(oldlevel);
}
/**
* The number of events waiting in the queue.