All pastes #604480 Raw Edit

Miscellany

public c v1 · immutable
#604480 ·published 2007-07-05 15:36 UTC
rendered paste body
/*************************************************************************** *             __________               __   ___. *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  / *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  < *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \ *                     \/            \/     \/    \/            \/ * $Id$ * * Copyright (C) 2007 Nicolas Pennequin * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/#include "plugin.h"PLUGIN_HEADERstruct plugin_api* rb;#define GUARD_SIZE   (32*1024)/* amount of data to read in one read() call */#define AUDIO_DEFAULT_FILECHUNK      (1024*32)/* Ring buffer helper macros *//* Buffer pointer (p) plus value (v), wrapped if necessary */#define RINGBUF_ADD(p,v) ((p+v)<buffer_len ? p+v : p+v-buffer_len)/* Buffer pointer (p) minus value (v), wrapped if necessary */#define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+buffer_len-v)/* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */#define RINGBUF_ADD_CROSS(p1,v,p2) \((p1<p2) ? (int)(p1+v)-(int)p2 : (int)(p1+v-p2)-(int)buffer_len)/* Bytes available in the buffer */#define BUF_USED RINGBUF_SUB(buf_widx, buf_ridx)struct memory_handle {    int id;              /* A unique ID for the handle */    //enum data_type type;    //enum data_state state;    char path[MAX_PATH];    int fd;    size_t data;         /* Start index of the handle's data buffer */    size_t ridx;         /* Current read pointer, relative to the main buffer */    size_t widx;         /* Current write pointer */    size_t filesize;     /* File total length */    size_t filerem;      /* Remaining bytes of file NOT in buffer */    size_t available;    /* Available bytes to read from buffer */    size_t offset;       /* Offset at which we started reading the file */    struct memory_handle *next;};static char *buffer;static char *guard_buffer;static size_t buffer_len;static size_t buf_widx;static size_t buf_ridx;static size_t conf_filechunk;/* current memory handle in the linked list. NULL when the list is empty. */static struct memory_handle *cur_handle;/* first memory handle in the linked list. NULL when the list is empty. */static struct memory_handle *first_handle;static int num_handles;static void graph_view(int width);/* add a new handle to the linked list and return it. It will have become the   new current handle */static struct memory_handle *add_handle(void){    rb->logf("add_handle");    /* this will give each handle a unique id */    static int cur_handle_id = 0;    int data_size = sizeof(struct memory_handle);    /* check that we actually can add the handle and its data */    if (RINGBUF_ADD_CROSS(buf_widx, data_size, buf_ridx) >= 0) {        return NULL;    }    struct memory_handle *new_handle = (struct memory_handle *)(buffer + buf_widx);    buf_widx = RINGBUF_ADD(buf_widx, data_size);    if (!first_handle) {        /* the new handle is the first one */        first_handle = new_handle;    }    if (cur_handle) {        cur_handle->next = new_handle;    }    cur_handle = new_handle;    rb->logf("cur_handle_id: %d", cur_handle_id);    cur_handle->id = cur_handle_id;    rb->logf("cur_handle->id: %d", cur_handle->id);    cur_handle->next = NULL;    num_handles++;    cur_handle_id++;    rb->logf("cur_handle: %lx", (unsigned long)cur_handle);    rb->logf("cur_handle->id: %d", cur_handle->id);    return cur_handle;}/* delete a given memory handle from the linked list   and return true for success. Nothing is actually erased from memory. */static bool rm_handle(struct memory_handle *h){    if (h == first_handle) {        first_handle = h->next;        if (h == cur_handle) {            rb->logf("removing the first and last handle\n");            cur_handle = NULL;            buf_ridx = buf_widx;        } else {            buf_ridx = (void *)first_handle - (void *)buffer;        }    } else {        struct memory_handle *m = first_handle;        while (m && m->next != h) {            m = m->next;        }        if (h && m && m->next == h) {            m->next = h->next;            if (h == cur_handle) {                cur_handle = m;            }        } else {            return false;        }    }    num_handles--;    return true;}/* these are unfortunalty needed to be global    so move_handle can invalidate them */static int cached_handle_id = -1;static struct memory_handle *cached_handle = NULL;/* Return a pointer to the memory handle of given ID.   NULL if the handle wasn't found */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_id == handle_id && cached_handle_id == cached_handle->id)            return cached_handle;        else if (cached_handle->next && (cached_handle->next->id == handle_id))        {            /* JD's quick testing showd this block was only entered               2/1971 calls to find_handle.               8/1971 calls to find_handle resulted in a cache miss */            cached_handle = cached_handle->next;            cached_handle_id = handle_id;            return cached_handle;        }    }    struct memory_handle *m = first_handle;    while (m && m->id != handle_id) {        m = m->next;    }    cached_handle_id = handle_id;    cached_handle = m;    return (m && m->id == handle_id) ? m : NULL;}/* Move a memory handle to newpos.   Return a pointer to the new location of the handle */static struct memory_handle *move_handle(size_t newpos, struct memory_handle *h){    struct memory_handle *dest = (struct memory_handle *)(buffer + newpos);    /* Invalidate the cache to prevent it from keeping the old location of h */    if (h == cached_handle)        cached_handle = NULL;    /* the cur_handle pointer might need updating */    if (h == cur_handle) {        cur_handle = dest;    }    if (h == first_handle) {        first_handle = dest;        buf_ridx = newpos;    } else {        struct memory_handle *m = first_handle;        while (m && m->next != h) {            m = m->next;        }        if (h && m && m->next == h) {            m->next = dest;        } else {            return NULL;        }    }    rb->memmove(dest, h, sizeof(struct memory_handle));    return dest;}/* Buffer data for the given handle. Return the amount of data buffered   or -1 if the handle wasn't found */static int buffer_handle(int handle_id){    rb->logf("buffer_handle(%d)", handle_id);    struct memory_handle *h = find_handle(handle_id);    if (!h)        return -1;    if (h->filerem == 0) {        /* nothing left to buffer */        return 0;    }    if (h->fd < 0)  /* file closed, reopen */    {        if (*h->path)            h->fd = rb->open(h->path, O_RDONLY);        else            return -1;        if (h->fd < 0)            return -1;        if (h->offset)            rb->lseek(h->fd, h->offset, SEEK_SET);    }    int ret = 0;    while (h->filerem > 0)    {        //rb->logf("h: %d\n", (void *)h - (void *)buffer);        //rb->logf("buf_widx: %ld\n", (long)buf_widx);        /* max amount to copy */        size_t copy_n = MIN(conf_filechunk, buffer_len - buf_widx);        /* stop copying if it would overwrite the reading position */        if (RINGBUF_ADD_CROSS(buf_widx, copy_n, buf_ridx) >= 0)            break;        /* rc is the actual amount read */        int rc = rb->read(h->fd, &buffer[buf_widx], copy_n);        if (rc < 0)        {            //rb->logf("failed on fd %d at buf_widx = %ld for handle %d\n", h->fd, (long)buf_widx, h->id);            rb->logf("File ended %ld bytes early\n", (long)h->filerem);            h->filesize -= h->filerem;            h->filerem = 0;            break;        }        /* Advance buffer */        h->widx = RINGBUF_ADD(h->widx, rc);        if (h == cur_handle)            buf_widx = h->widx;        h->available += rc;        ret += rc;        h->filerem -= rc;    }    if (h->filerem == 0) {        /* finished buffering the file */        rb->close(h->fd);    }    rb->logf("buffered %d bytes (%d of %d available, remaining: %d)\n",           ret, h->available, h->filesize, h->filerem);    return ret;}/* Free buffer space by moving the first handle struct right before the useful   part of its data buffer */static void free_buffer(int handle_id){    rb->logf("free_buffer(%d)\n", handle_id);    struct memory_handle *h = find_handle(handle_id);    if (!h)        return;    size_t delta = RINGBUF_SUB(h->ridx, h->data);    size_t dest = RINGBUF_ADD((void *)h - (void *)buffer, delta);    //rb->logf("buf_ridx: %ld, buf_widx: %ld\n", (long)buf_ridx, (long)buf_widx);    //rb->logf("dest: %ld, delta: %ld\n", (long)dest, (long)delta);    h = move_handle(dest, h);    h->data = RINGBUF_ADD(h->data, delta);    h->ridx = h->data;    h->available -= delta;    //graph_view(100);}/* Request a file be buffered    filename: name of the file t open    offset:   starting offset to buffer from the file    RETURNS:  <0 if the file cannot be opened, or one file already                queued to be opened, otherwise the handle for the file in the buffer*/int bufopen(char *file, size_t offset){    /* add the file to the buffering queue. */    /* for now, we'll assume the queue is always empty, so the handle       gets added immediately */    rb->logf("bufopen: %s (offset: %d)\n", file, offset);    int fd = rb->open(file, O_RDONLY);    if (fd < 0)        return -1;    if (offset)        rb->lseek(fd, offset, SEEK_SET);    struct memory_handle *h = add_handle();    if (!h)        return -1;    rb->strncpy(h->path, file, MAX_PATH);    h->fd = fd;    h->filesize = rb->filesize(fd);    h->filerem = h->filesize - offset;    h->offset = offset;    h->ridx = buf_widx;    h->widx = buf_widx;    h->data = buf_widx;    h->available = 0;    rb->logf("h: %lx", (unsigned long)h);    rb->logf("h->id: %d", h->id);    rb->logf("added handle : %d\n", h->id);    return h->id;}/* Close the handle. Return 0 for success and < 0 for failure */int bufclose(int handle_id){    rb->logf("bufclose(%d)\n", handle_id);    struct memory_handle *h = find_handle(handle_id);    if (!h)        return -1;    rm_handle(h);    return 0;}/* Set the reading index in a handle (relatively to the start of the handle data).   Return 0 for success and < 0 for failure */int bufseek(int handle_id, size_t offset){    struct memory_handle *h = find_handle(handle_id);    if (!h)        return -1;    if (offset > h->available)        return -2;    h->ridx = RINGBUF_ADD(h->data, offset);    return 0;}/* Advance the reading index in a handle (relatively to its current position).   Return 0 for success and < 0 for failure */int bufadvance(int handle_id, ssize_t offset){    struct memory_handle *h = find_handle(handle_id);    if (!h)        return -1;    if (offset >= 0)    {        if (offset > h->available - RINGBUF_SUB(h->ridx, h->data))            return -2;        h->ridx = RINGBUF_ADD(h->ridx, offset);    }    else    {        if (-offset > RINGBUF_SUB(h->ridx, h->data))            return -2;        h->ridx = RINGBUF_SUB(h->ridx, -offset);    }    return 0;}/* Copy data from the given handle to the dest buffer.   Return the number of bytes copied or -1 for failure. */int bufread(int handle_id, size_t size, char *dest){    struct memory_handle *h = find_handle(handle_id);    size_t buffered_data;    if (!h)        return -1;    if (h->available == 0)        return 0;    buffered_data = MIN(size, h->available);    if (h->ridx + buffered_data > buffer_len)    {        size_t read = buffer_len - h->ridx;        rb->memcpy(dest, &buffer[h->ridx], read);        rb->memcpy(dest+read, buffer, buffered_data - read);    }    else rb->memcpy(dest, &buffer[h->ridx], buffered_data);    h->ridx = RINGBUF_ADD(h->ridx, buffered_data);    h->available -= buffered_data;    return buffered_data;}/* Update the "data" pointer to make the handle's data available to the caller.   Return the length of the available linear data or -1 for failure. */long bufgetdata(int handle_id, size_t size, unsigned char **data){    struct memory_handle *h = find_handle(handle_id);    if (!h)        return -1;    long ret;    if (h->ridx + size > buffer_len &&        h->available - RINGBUF_SUB(h->ridx, h->data) >= size)    {        /* use the guard buffer to provide what was requested. */        int copy_n = h->ridx + size - buffer_len;        rb->memcpy(guard_buffer, (unsigned char *)buffer, copy_n);        ret = size;    }    else    {        ret = MIN(h->available - RINGBUF_SUB(h->ridx, h->data),                  buffer_len - h->ridx);    }    *data = (unsigned char *)(buffer + h->ridx);    //rb->logf("bufgetdata(%d): h->ridx=%ld, ret=%ld\n", handle_id, (long)h->ridx, ret);    return ret;}bool test_ll(void){    struct memory_handle *m1, *m2, *m3, *m4;    if (cur_handle != NULL || first_handle != NULL)        return false;    m1 = add_handle();    if (cur_handle != m1 || first_handle != m1 || m1->next != NULL)        return false;    m2 = add_handle();    if (cur_handle != m2 || first_handle != m1 || m1->next != m2 || m2->next != NULL)        return false;    m3 = add_handle();    if (cur_handle != m3 || first_handle != m1 || m2->next != m3 || m3->next != NULL)        return false;    rm_handle(m2);    if (cur_handle != m3 || first_handle != m1 || m1->next != m3)        return false;    rm_handle(m3);    if (cur_handle != m1 || first_handle != m1 || m1->next != NULL)        return false;    m4 = add_handle();    if (cur_handle != m4 || first_handle != m1 || m1->next != m4 || m4->next != NULL)        return false;    rm_handle(m1);    if (cur_handle != m4 || first_handle != m4)        return false;    rm_handle(m4);    if (cur_handle != NULL || first_handle != NULL)        return false;    m1 = add_handle();    m2 = add_handle();    m3 = add_handle();    m4 = add_handle();    if (cur_handle != m4 || first_handle != m1)        return false;/*    int m2id = m2->id;    m2 = move_handle(m2->data + 1024*1024, m2);    if (cur_handle != m4 || first_handle != m1 || m1->next != m2 || m2->next != m3 ||        find_handle(m2id) != m2)        return false;    int m1id = m1->id;    m1 = move_handle(m1->data + 1024*1024*3, m1);    if (cur_handle != m4 || first_handle != m1 || m1->next != m2 ||        find_handle(m1id) != m1)        return false;*/    rm_handle(m1);    rm_handle(m2);    rm_handle(m3);    rm_handle(m4);    if (cur_handle != NULL || first_handle != NULL)        return false;    return true;}#if 0static void list_handles(void){    struct memory_handle *m = first_handle;    while (m) {        rb->logf("%02d - %d\n", m->id, (void *)m-(void *)buffer);        m = m->next;    }}#endif/* display a nice graphical view of the ringbuffer. */static void graph_view(int width){    int i, r_pos, w_pos;    r_pos = buf_ridx * width / buffer_len;    w_pos = buf_widx * width / buffer_len;    rb->logf("|");    for (i=0; i <= width; i++)    {        if (i != r_pos && i != w_pos)        {            if (buf_ridx <= buf_widx)            {                if (i > r_pos && i < w_pos) {                    rb->logf(">");                } else {                    rb->logf("-");                }            }            else            {                if (i > r_pos || i < w_pos) {                    rb->logf(">");                } else {                    rb->logf("-");                }            }        }        else        {            if (i == r_pos && i == w_pos)            {                if (buf_ridx <= buf_widx) {                    rb->logf("RW");                } else {                    rb->logf("WR");                }            } else if (i == r_pos) {                rb->logf("R");            } else if (i == w_pos) {                rb->logf("W");            }        }    }    rb->logf("|");    rb->logf("\n");}bool buffer_init(void){    buffer = rb->plugin_get_audio_buffer(&buffer_len);    if (!buffer)    {        rb->logf("couldn't allocate buffer\n");        return false;    }    buffer_len -= GUARD_SIZE;    guard_buffer = buffer + buffer_len;    buf_widx = 0;    buf_ridx = 0;    first_handle = NULL;    num_handles = 0;    conf_filechunk = AUDIO_DEFAULT_FILECHUNK;    return true;}/* returns true if the file still has some on disk unread */bool handle_has_data(int handle){    struct memory_handle *m = find_handle(handle);    if (m)    {        return m->filerem != 0;    }    return false;}bool need_rebuffer(void){    size_t free, wasted;    wasted = first_handle? RINGBUF_SUB(first_handle->ridx, first_handle->data) : 0;    while (wasted > buffer_len / 2)    {        free_buffer(first_handle->id);        wasted = first_handle? RINGBUF_SUB(first_handle->ridx, first_handle->data) : 0;    }    free = buffer_len - BUF_USED;    return ((free >= buffer_len/4));}bool disk_is_spinning(void){    return true;}#define MAX_HANDLES 64/* this is the plugin entry point */enum plugin_status plugin_start(struct plugin_api* api, void* parameter){    (void)parameter;    rb = api;    int argc = 6;    char *argv[] = { NULL,            "/070623 - David Vendetta.mp3",            "/africanism all stars feat the hard boys - hard (bob sinclair remix).mp3",            "/alan_braxe__kris_menace_-_lumberjack.mp3",            "/Ame - Rej (A Hundred Birds Remix).mp3",            "/Antena - Camino del Sol (Joakim Remix).mp3" };    int next_file = 1;    int last_handle = -1;    int handle_order[MAX_HANDLES];    int reading_handle = 0;    bool done_buffering = false, done_playing = false;    //char read_buffer[GUARD_SIZE];    unsigned char *data;    int fd = -1; /* used to write the files out as they are read */    int current_handle = -1;    struct memory_handle *m = NULL;    buffer_init();    if (!test_ll())    {        rb->logf("linked list test failed\n");        rb->splash(HZ, "linked list test failed");        return PLUGIN_ERROR;    }    buffer_init();        rb->logf("test\n");    while (!done_buffering || !done_playing)    {        rb->logf("buffer usage: %d handles_used: %d\n", BUF_USED, num_handles);        //graph_view(100);        /* "Buffering thread" section */        if (!done_buffering && need_rebuffer() && disk_is_spinning())        {            m = find_handle(current_handle);            if ( !m || ((m->filerem == 0) && (m->next == NULL)))            {                int h = bufopen(argv[next_file], 0);                m = find_handle(h);                if (h >= 0)                {                    next_file++;                    //rb->logf("new handle %d\n",h);                    last_handle++;                    handle_order[last_handle] = h;                    buffer_handle(m->id);                }                else                {                    rb->logf("error\n");                }                current_handle = h;            }            else            {                if (m->filerem == 0)                {                    m = m->next;                    current_handle = m?m->id:-1;                }                if (m)                {                    rb->logf("buffering handle %d\n",m->id);                    buffer_handle(m->id);                }            }            if (next_file == argc && m->filerem == 0)                done_buffering = true;        }        /* "Playback thread" section */        else        {            rb->logf("reading handle: %d\n", handle_order[reading_handle]);            long read;            long total = 0;            char file[MAX_PATH];            if (reading_handle >= last_handle                && !handle_has_data(handle_order[reading_handle]))                done_playing = true;            if (fd < 0)            {                rb->snprintf(file, MAX_PATH, "/file%d.mp3", reading_handle);                fd = rb->open(file, O_CREAT|O_TRUNC|O_WRONLY);                if (fd < 0)                {                    rb->logf("ERROROROROR\n");                    rb->splash(HZ, "couldn't create file");                    return PLUGIN_ERROR;                }            }            do            {                //read = bufread(handle_order[reading_handle], GUARD_SIZE,read_buffer);                //write(fd, read_buffer, read);                read = bufgetdata(handle_order[reading_handle], GUARD_SIZE, &data);                read = MIN(read, GUARD_SIZE);                rb->write(fd, data, read);                total += read;                bufadvance(handle_order[reading_handle], read);            }            while (read > 0);            rb->logf("read %ld bytes from handle %d\n", total, handle_order[reading_handle]);            /* close the fd/handle if there is no more data or an error */            if (read < 0 || handle_has_data(handle_order[reading_handle]) == false)            {                rb->logf("finished reading %d\n",handle_order[reading_handle]);                bufclose(handle_order[reading_handle]);                rb->close(fd);                reading_handle++;                fd = -1;            }            else            {                rb->logf("there is data left to buffer for %d\n", handle_order[reading_handle]);            }        }    }    rb->logf("buffer usage: %d handles_used: %d\n", BUF_USED,num_handles);    //graph_view(100);    return 0;    return PLUGIN_OK;}