Преглед на файлове

update on wma decoder

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@41 bbd45198-f89e-11dd-88c7-29a3b14d5316
bernard.xiong преди 15 години
родител
ревизия
f0c313051d
променени са 2 файла, в които са добавени 894 реда и са изтрити 409 реда
  1. 514 0
      bsp/stm32_radio/asf.c
  2. 380 409
      bsp/stm32_radio/wma.c

+ 514 - 0
bsp/stm32_radio/asf.c

@@ -0,0 +1,514 @@
+#include <rtthread.h>
+#include <dfs_posix.h>
+#include "libwma/asf.h"
+
+#define DEBUGF rt_kprintf
+
+/* always little endian */
+#define read_uint16le(fd,buf) read((fd), (buf), 2)
+#define read_uint32le(fd,buf) read((fd), (buf), 4)
+#define read_uint64le(fd,buf) read((fd), (buf), 8)
+
+/* TODO: Just read the GUIDs into a 16-byte array, and use memcmp to compare */
+struct guid_s {
+    rt_uint32_t v1;
+    rt_uint16_t v2;
+    rt_uint16_t v3;
+    rt_uint8_t  v4[8];
+};
+typedef struct guid_s guid_t;
+typedef long long rt_uint64_t;
+
+struct asf_object_s {
+    guid_t       	guid;
+    rt_uint64_t     size;
+    rt_uint64_t     datalen;
+};
+typedef struct asf_object_s asf_object_t;
+
+enum asf_error_e {
+    ASF_ERROR_INTERNAL       = -1,  /* incorrect input to API calls */
+    ASF_ERROR_OUTOFMEM       = -2,  /* some malloc inside program failed */
+    ASF_ERROR_EOF            = -3,  /* unexpected end of file */
+    ASF_ERROR_IO             = -4,  /* error reading or writing to file */
+    ASF_ERROR_INVALID_LENGTH = -5,  /* length value conflict in input data */
+    ASF_ERROR_INVALID_VALUE  = -6,  /* other value conflict in input data */
+    ASF_ERROR_INVALID_OBJECT = -7,  /* ASF object missing or in wrong place */
+    ASF_ERROR_OBJECT_SIZE    = -8,  /* invalid ASF object size (too small) */
+    ASF_ERROR_SEEKABLE       = -9,  /* file not seekable */
+    ASF_ERROR_SEEK           = -10, /* file is seekable but seeking failed */
+    ASF_ERROR_ENCRYPTED      = -11  /* file is encrypted */
+};
+
+static const guid_t asf_guid_null =
+{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+
+/* top level object guids */
+
+static const guid_t asf_guid_header =
+{0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
+
+static const guid_t asf_guid_data =
+{0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
+
+static const guid_t asf_guid_index =
+{0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
+
+/* header level object guids */
+
+static const guid_t asf_guid_file_properties =
+{0x8cabdca1, 0xa947, 0x11cf, {0x8E, 0xe4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
+
+static const guid_t asf_guid_stream_properties =
+{0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
+
+static const guid_t asf_guid_content_description =
+{0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
+
+static const guid_t asf_guid_extended_content_description =
+{0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}};
+
+static const guid_t asf_guid_content_encryption =
+{0x2211b3fb, 0xbd23, 0x11d2, {0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e}};
+
+static const guid_t asf_guid_extended_content_encryption =
+{0x298ae614, 0x2622, 0x4c17, {0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c}};
+
+/* stream type guids */
+
+static const guid_t asf_guid_stream_type_audio =
+{0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
+
+static int asf_guid_match(const guid_t *guid1, const guid_t *guid2)
+{
+    if((guid1->v1 != guid2->v1) ||
+       (guid1->v2 != guid2->v2) ||
+       (guid1->v3 != guid2->v3) ||
+       (rt_memcmp(guid1->v4, guid2->v4, 8)))
+	{
+        return 0;
+    }
+
+    return 1;
+}
+
+/* Read the 16 byte GUID from a file */
+static void asf_readGUID(int fd, guid_t* guid)
+{
+    read_uint32le(fd, &guid->v1);
+    read_uint16le(fd, &guid->v2);
+    read_uint16le(fd, &guid->v3);
+    read(fd, guid->v4, 8);
+}
+
+static void asf_read_object_header(asf_object_t *obj, int fd)
+{
+    asf_readGUID(fd, &obj->guid);
+    read_uint64le(fd, &obj->size);
+    obj->datalen = 0;
+}
+
+/* Parse an integer from the extended content object - we always
+   convert to an int, regardless of native format.
+*/
+static int asf_intdecode(int fd, int type, int length)
+{
+    rt_uint16_t tmp16;
+    rt_uint32_t tmp32;
+    rt_uint64_t tmp64;
+
+    if (type==3) {
+        read_uint32le(fd, &tmp32);
+        lseek(fd,length - 4,SEEK_CUR);
+        return (int)tmp32;
+    } else if (type==4) {
+        read_uint64le(fd, &tmp64);
+        lseek(fd,length - 8,SEEK_CUR);
+        return (int)tmp64;
+    } else if (type == 5) {
+        read_uint16le(fd, &tmp16);
+        lseek(fd,length - 2,SEEK_CUR);
+        return (int)tmp16;
+    }
+
+    return 0;
+}
+
+/* Decode a LE utf16 string from a disk buffer into a fixed-sized
+   utf8 buffer.
+*/
+static void asf_utf16LEdecode(int fd,
+	rt_uint16_t utf16bytes,
+	unsigned char **utf8,
+	int* utf8bytes)
+{
+    unsigned long ucs;
+    int n;
+    unsigned char utf16buf[256];
+    unsigned char* utf16 = utf16buf;
+    unsigned char* newutf8;
+
+    n = read(fd, utf16buf, MIN(sizeof(utf16buf), utf16bytes));
+    utf16bytes -= n;
+
+    while (n > 0) {
+        /* Check for a surrogate pair */
+        if (utf16[1] >= 0xD8 && utf16[1] < 0xE0) {
+            if (n < 4) {
+                /* Run out of utf16 bytes, read some more */
+                utf16buf[0] = utf16[0];
+                utf16buf[1] = utf16[1];
+
+                n = read(fd, utf16buf + 2, MIN(sizeof(utf16buf)-2, utf16bytes));
+                utf16 = utf16buf;
+                utf16bytes -= n;
+                n += 2;
+            }
+
+            if (n < 4) {
+                /* Truncated utf16 string, abort */
+                break;
+            }
+            ucs = 0x10000 + ((utf16[0] << 10) | ((utf16[1] - 0xD8) << 18)
+                             | utf16[2] | ((utf16[3] - 0xDC) << 8));
+            utf16 += 4;
+            n -= 4;
+        } else {
+            ucs = (utf16[0] | (utf16[1] << 8));
+            utf16 += 2;
+            n -= 2;
+        }
+
+        if (*utf8bytes > 6) {
+            newutf8 = utf8encode(ucs, *utf8);
+            *utf8bytes -= (newutf8 - *utf8);
+            *utf8 += (newutf8 - *utf8);
+        }
+
+        /* We have run out of utf16 bytes, read more if available */
+        if ((n == 0) && (utf16bytes > 0)) {
+            n = read(fd, utf16buf, MIN(sizeof(utf16buf), utf16bytes));
+            utf16 = utf16buf;
+            utf16bytes -= n;
+        }
+    }
+
+    *utf8[0] = 0;
+    --*utf8bytes;
+
+    if (utf16bytes > 0) {
+        /* Skip any remaining bytes */
+        lseek(fd, utf16bytes, SEEK_CUR);
+    }
+    return;
+}
+
+static int asf_parse_header(int fd, struct mp3entry* id3,
+                                    asf_waveformatex_t* wfx)
+{
+    asf_object_t current;
+    asf_object_t header;
+    rt_uint64_t datalen;
+    int i;
+    int fileprop = 0;
+    rt_uint64_t play_duration;
+    rt_uint16_t flags;
+    rt_uint32_t subobjects;
+    rt_uint8_t utf8buf[512];
+    int id3buf_remaining = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf);
+    unsigned char* id3buf = (unsigned char*)id3->id3v2buf;
+
+    asf_read_object_header((asf_object_t *) &header, fd);
+
+    //DEBUGF("header.size=%d\n",(int)header.size);
+    if (header.size < 30) {
+        /* invalid size for header object */
+        return ASF_ERROR_OBJECT_SIZE;
+    }
+
+    read_uint32le(fd, &subobjects);
+
+    /* Two reserved bytes - do we need to read them? */
+    lseek(fd, 2, SEEK_CUR);
+
+    //DEBUGF("Read header - size=%d, subobjects=%d\n",(int)header.size, (int)subobjects);
+
+    if (subobjects > 0) {
+        header.datalen = header.size - 30;
+
+        /* TODO: Check that we have datalen bytes left in the file */
+        datalen = header.datalen;
+
+        for (i=0; i<(int)subobjects; i++) {
+            //DEBUGF("Parsing header object %d - datalen=%d\n",i,(int)datalen);
+            if (datalen < 24) {
+                //DEBUGF("not enough data for reading object\n");
+                break;
+            }
+
+            asf_read_object_header(&current, fd);
+
+            if (current.size > datalen || current.size < 24) {
+                //DEBUGF("invalid object size - current.size=%d, datalen=%d\n",(int)current.size,(int)datalen);
+                break;
+            }
+
+            if (asf_guid_match(&current.guid, &asf_guid_file_properties)) {
+                    if (current.size < 104)
+                        return ASF_ERROR_OBJECT_SIZE;
+
+                    if (fileprop) {
+                        /* multiple file properties objects not allowed */
+                        return ASF_ERROR_INVALID_OBJECT;
+                    }
+
+                    fileprop = 1;
+                    /* All we want is the play duration - uint64_t at offset 40 */
+                    lseek(fd, 40, SEEK_CUR);
+
+                    read_uint64le(fd, &play_duration);
+                    id3->length = play_duration / 10000;
+
+                    //DEBUGF("****** length = %lums\n", id3->length);
+
+                    /* Read the packet size - uint32_t at offset 68 */
+                    lseek(fd, 20, SEEK_CUR);
+                    read_uint32le(fd, &wfx->packet_size);
+
+                    /* Skip bytes remaining in object */
+                    lseek(fd, current.size - 24 - 72, SEEK_CUR);
+            } else if (asf_guid_match(&current.guid, &asf_guid_stream_properties)) {
+                    guid_t guid;
+                    rt_uint32_t propdatalen;
+
+                    if (current.size < 78)
+                        return ASF_ERROR_OBJECT_SIZE;
+
+                    asf_readGUID(fd, &guid);
+
+                    lseek(fd, 24, SEEK_CUR);
+                    read_uint32le(fd, &propdatalen);
+                    lseek(fd, 4, SEEK_CUR);
+                    read_uint16le(fd, &flags);
+
+                    if (!asf_guid_match(&guid, &asf_guid_stream_type_audio)) {
+                        //DEBUGF("Found stream properties for non audio stream, skipping\n");
+                        lseek(fd,current.size - 24 - 50,SEEK_CUR);
+                    } else if (wfx->audiostream == -1) {
+                        lseek(fd, 4, SEEK_CUR);
+                        //DEBUGF("Found stream properties for audio stream %d\n",flags&0x7f);
+
+                        if (propdatalen < 18) {
+                            return ASF_ERROR_INVALID_LENGTH;
+                        }
+
+                        read_uint16le(fd, &wfx->codec_id);
+                        read_uint16le(fd, &wfx->channels);
+                        read_uint32le(fd, &wfx->rate);
+                        read_uint32le(fd, &wfx->bitrate);
+                        wfx->bitrate *= 8;
+                        read_uint16le(fd, &wfx->blockalign);
+                        read_uint16le(fd, &wfx->bitspersample);
+                        read_uint16le(fd, &wfx->datalen);
+
+                        /* Round bitrate to the nearest kbit */
+                        id3->bitrate = (wfx->bitrate + 500) / 1000;
+                        id3->frequency = wfx->rate;
+
+                        if (wfx->codec_id == ASF_CODEC_ID_WMAV1) {
+                            read(fd, wfx->data, 4);
+                            lseek(fd,current.size - 24 - 72 - 4,SEEK_CUR);
+                            wfx->audiostream = flags&0x7f;
+                        } else if (wfx->codec_id == ASF_CODEC_ID_WMAV2) {
+                            read(fd, wfx->data, 6);
+                            lseek(fd,current.size - 24 - 72 - 6,SEEK_CUR);
+                            wfx->audiostream = flags&0x7f;
+                        } else {
+                            DEBUGF("Unsupported WMA codec (Pro, Lossless, Voice, etc)\n");
+                            lseek(fd,current.size - 24 - 72,SEEK_CUR);
+                        }
+
+                    }
+            } else if (asf_guid_match(&current.guid, &asf_guid_content_description)) {
+                    /* Object contains five 16-bit string lengths, followed by the five strings:
+                       title, artist, copyright, description, rating
+                     */
+                    rt_uint16_t strlength[5];
+                    int i;
+
+                    //DEBUGF("Found GUID_CONTENT_DESCRIPTION - size=%d\n",(int)(current.size - 24));
+
+                    /* Read the 5 string lengths - number of bytes included trailing zero */
+                    for (i=0; i<5; i++) {
+                        read_uint16le(fd, &strlength[i]);
+                        //DEBUGF("strlength = %u\n",strlength[i]);
+                    }
+
+                    if (strlength[0] > 0) {  /* 0 - Title */
+                        id3->title = id3buf;
+                        asf_utf16LEdecode(fd, strlength[0], &id3buf, &id3buf_remaining);
+                    }
+
+                    if (strlength[1] > 0) {  /* 1 - Artist */
+                        id3->artist = id3buf;
+                        asf_utf16LEdecode(fd, strlength[1], &id3buf, &id3buf_remaining);
+                    }
+
+                    lseek(fd, strlength[2], SEEK_CUR); /* 2 - copyright */
+
+                    if (strlength[3] > 0) {  /* 3 - description */
+                        id3->comment = id3buf;
+                        asf_utf16LEdecode(fd, strlength[3], &id3buf, &id3buf_remaining);
+                    }
+
+                    lseek(fd, strlength[4], SEEK_CUR); /* 4 - rating */
+            } else if (asf_guid_match(&current.guid, &asf_guid_extended_content_description)) {
+                    rt_uint16_t count;
+                    int i;
+                    int bytesleft = current.size - 24;
+                    //DEBUGF("Found GUID_EXTENDED_CONTENT_DESCRIPTION\n");
+
+                    read_uint16le(fd, &count);
+                    bytesleft -= 2;
+                    //DEBUGF("extended metadata count = %u\n",count);
+
+                    for (i=0; i < count; i++) {
+                        rt_uint16_t length, type;
+                        unsigned char* utf8 = utf8buf;
+                        int utf8length = 512;
+
+                        read_uint16le(fd, &length);
+                        asf_utf16LEdecode(fd, length, &utf8, &utf8length);
+                        bytesleft -= 2 + length;
+
+                        read_uint16le(fd, &type);
+                        read_uint16le(fd, &length);
+
+                        if (!strcmp("WM/TrackNumber",utf8buf)) {
+                            if (type == 0) {
+                                id3->track_string = id3buf;
+                                asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
+                                id3->tracknum = atoi(id3->track_string);
+                            } else if ((type >=2) && (type <= 5)) {
+                                id3->tracknum = asf_intdecode(fd, type, length);
+                            } else {
+                                lseek(fd, length, SEEK_CUR);
+                            }
+                        } else if ((!strcmp("WM/Genre",utf8buf)) && (type == 0)) {
+                            id3->genre_string = id3buf;
+                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
+                        } else if ((!strcmp("WM/AlbumTitle",utf8buf)) && (type == 0)) {
+                            id3->album = id3buf;
+                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
+                        } else if ((!strcmp("WM/AlbumArtist",utf8buf)) && (type == 0)) {
+                            id3->albumartist = id3buf;
+                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
+                        } else if ((!strcmp("WM/Composer",utf8buf)) && (type == 0)) {
+                            id3->composer = id3buf;
+                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
+                        } else if (!strcmp("WM/Year",utf8buf)) {
+                            if (type == 0) {
+                                id3->year_string = id3buf;
+                                asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
+                                id3->year = atoi(id3->year_string);
+                            } else if ((type >=2) && (type <= 5)) {
+                                id3->year = asf_intdecode(fd, type, length);
+                            } else {
+                                lseek(fd, length, SEEK_CUR);
+                            }
+                        } else if (!strncmp("replaygain_", utf8buf, 11)) {
+                            char* value = id3buf;
+                            int buf_len = id3buf_remaining;
+                            int len;
+                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
+                            len = parse_replaygain(utf8buf, value, id3, 
+                                value, buf_len);
+                            
+                            if (len == 0) {
+                                /* Don't need to keep the value */
+                                id3buf = value;
+                                id3buf_remaining = buf_len;
+                            }
+                        } else if (!strcmp("MusicBrainz/Track Id", utf8buf)) {
+                            id3->mb_track_id = id3buf;
+                            asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
+                        } else {
+                            lseek(fd, length, SEEK_CUR);
+                        }
+                        bytesleft -= 4 + length;
+                    }
+
+                    lseek(fd, bytesleft, SEEK_CUR);
+            } else if (asf_guid_match(&current.guid, &asf_guid_content_encryption)
+                || asf_guid_match(&current.guid, &asf_guid_extended_content_encryption)) {
+                //DEBUGF("File is encrypted\n");
+                return ASF_ERROR_ENCRYPTED;
+            } else {
+                //DEBUGF("Skipping %d bytes of object\n",(int)(current.size - 24));
+                lseek(fd,current.size - 24,SEEK_CUR);
+            }
+
+            //DEBUGF("Parsed object - size = %d\n",(int)current.size);
+            datalen -= current.size;
+        }
+
+        if (i != (int)subobjects || datalen != 0) {
+            //DEBUGF("header data doesn't match given subobject count\n");
+            return ASF_ERROR_INVALID_VALUE;
+        }
+
+        //DEBUGF("%d subobjects read successfully\n", i);
+    }
+
+    //DEBUGF("header validated correctly\n");
+
+    return 0;
+}
+
+static off_t filesize(int fd)
+{
+    struct dfs_stat buf;
+
+    stat(fd,&buf);
+    return buf.st_size;
+}
+
+rt_bool_t get_asf_metadata(int fd, struct mp3entry* id3)
+{
+    int res;
+    asf_object_t obj;
+    asf_waveformatex_t wfx;
+
+    wfx.audiostream = -1;
+
+    res = asf_parse_header(fd, id3, &wfx);
+
+    if (res < 0) {
+        DEBUGF("ASF: parsing error - %d\n",res);
+        return RT_FALSE;
+    }
+
+    if (wfx.audiostream == -1) {
+        DEBUGF("ASF: No WMA streams found\n");
+        return RT_FALSE;
+    }
+
+    asf_read_object_header(&obj, fd);
+
+    if (!asf_guid_match(&obj.guid, &asf_guid_data)) {
+        DEBUGF("ASF: No data object found\n");
+        return RT_FALSE;
+    }
+
+    /* Store the current file position - no need to parse the header
+       again in the codec.  The +26 skips the rest of the data object
+       header.
+     */
+    id3->first_frame_offset = lseek(fd, 0, SEEK_CUR) + 26;
+    id3->filesize = filesize(fd);
+    /* We copy the wfx struct to the MP3 TOC field in the id3 struct so
+       the codec doesn't need to parse the header object again */
+    rt_memcpy(id3->toc, &wfx, sizeof(wfx));
+
+    return RT_TRUE;
+}

+ 380 - 409
bsp/stm32_radio/wma.c

@@ -1,409 +1,380 @@
-/* wma player test */
-#include "libwma/asf.h"
-#include "libwma/wmadec.h"
-
-/* The output buffer containing the decoded samples (channels 0 and 1)
-   BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2.
- */
-
-static uint32_t decoded[BLOCK_MAX_SIZE * MAX_CHANNELS];
-
-/* NOTE: WMADecodeContext is 120152 bytes (on x86) */
-static WMADecodeContext wmadec;
-
-enum asf_error_e {
-	ASF_ERROR_INTERNAL       = -1,  /* incorrect input to API calls */
-	ASF_ERROR_OUTOFMEM       = -2,  /* some malloc inside program failed */
-	ASF_ERROR_EOF            = -3,  /* unexpected end of file */
-	ASF_ERROR_IO             = -4,  /* error reading or writing to file */
-	ASF_ERROR_INVALID_LENGTH = -5,  /* length value conflict in input data */
-	ASF_ERROR_INVALID_VALUE  = -6,  /* other value conflict in input data */
-	ASF_ERROR_INVALID_OBJECT = -7,  /* ASF object missing or in wrong place */
-	ASF_ERROR_OBJECT_SIZE    = -8,  /* invalid ASF object size (too small) */
-	ASF_ERROR_SEEKABLE       = -9,  /* file not seekable */
-	ASF_ERROR_SEEK           = -10  /* file is seekable but seeking failed */
-};
-
-
-static int asf_read_packet(uint8_t** audiobuf, int* audiobufsize, int* packetlength, asf_waveformatex_t* wfx)
-{
-	uint8_t tmp8, packet_flags, packet_property;
-	int stream_id;
-	int ec_length, opaque_data, ec_length_type;
-	int datalen;
-	uint8_t data[18];
-	uint8_t* datap;
-	uint32_t length;
-	uint32_t padding_length;
-	uint32_t send_time;
-	uint16_t duration;
-	uint16_t payload_count;
-	int payload_length_type;
-	uint32_t payload_hdrlen;
-	int payload_datalen;
-	int multiple;
-	uint32_t replicated_length;
-	uint32_t media_object_number;
-	uint32_t media_object_offset;
-	uint32_t bytesread = 0;
-	uint8_t* buf;
-	size_t bufsize;
-	int i;
-
-	/* rt_kprintf("Reading new packet at %d bytes ", (int)ci->curpos); */
-
-	if (ci->read_filebuf(&tmp8, 1) == 0)
-	{
-		return ASF_ERROR_EOF;
-	}
-	bytesread++;
-
-	/* TODO: We need a better way to detect endofstream */
-	if (tmp8 != 0x82)
-	{
-		rt_kprintf("Read failed:  packet did not sync\n");
-		return -1;
-	}
-
-	if (tmp8 & 0x80)
-	{
-		ec_length = tmp8 & 0x0f;
-		opaque_data = (tmp8 >> 4) & 0x01;
-		ec_length_type = (tmp8 >> 5) & 0x03;
-
-		if (ec_length_type != 0x00 || opaque_data != 0 || ec_length != 0x02)
-		{
-			rt_kprintf("incorrect error correction flags\n");
-			return ASF_ERROR_INVALID_VALUE;
-		}
-
-		/* Skip ec_data */
-		ci->advance_buffer(ec_length);
-		bytesread += ec_length;
-	}
-	else
-	{
-		ec_length = 0;
-	}
-
-	if (ci->read_filebuf(&packet_flags, 1) == 0)
-	{
-		return ASF_ERROR_EOF;
-	}
-	if (ci->read_filebuf(&packet_property, 1) == 0)
-	{
-		return ASF_ERROR_EOF;
-	}
-	bytesread += 2;
-
-	datalen = GETLEN2b((packet_flags >> 1) & 0x03) +
-			  GETLEN2b((packet_flags >> 3) & 0x03) +
-			  GETLEN2b((packet_flags >> 5) & 0x03) + 6;
-
-	if (ci->read_filebuf(data, datalen) == 0)
-	{
-		return ASF_ERROR_EOF;
-	}
-
-	bytesread += datalen;
-
-	datap = data;
-	length = GETVALUE2b((packet_flags >> 5) & 0x03, datap);
-	datap += GETLEN2b((packet_flags >> 5) & 0x03);
-	/* sequence value is not used */
-	GETVALUE2b((packet_flags >> 1) & 0x03, datap);
-	datap += GETLEN2b((packet_flags >> 1) & 0x03);
-	padding_length = GETVALUE2b((packet_flags >> 3) & 0x03, datap);
-	datap += GETLEN2b((packet_flags >> 3) & 0x03);
-	send_time = get_long_le(datap);
-	datap += 4;
-	duration = get_short_le(datap);
-	datap += 2;
-	/* rt_kprintf("and duration %d ms\n", duration); */
-
-	/* this is really idiotic, packet length can (and often will) be
-	 * undefined and we just have to use the header packet size as the size
-	 * value */
-	if (!((packet_flags >> 5) & 0x03))
-	{
-		length = wfx->packet_size;
-	}
-
-	/* this is also really idiotic, if packet length is smaller than packet
-	 * size, we need to manually add the additional bytes into padding length
-	 */
-	if (length < wfx->packet_size)
-	{
-		padding_length += wfx->packet_size - length;
-		length = wfx->packet_size;
-	}
-
-	if (length > wfx->packet_size)
-	{
-		rt_kprintf("packet with too big length value\n");
-		return ASF_ERROR_INVALID_LENGTH;
-	}
-
-	/* check if we have multiple payloads */
-	if (packet_flags & 0x01)
-	{
-		if (ci->read_filebuf(&tmp8, 1) == 0)
-		{
-			return ASF_ERROR_EOF;
-		}
-		payload_count = tmp8 & 0x3f;
-		payload_length_type = (tmp8 >> 6) & 0x03;
-		bytesread++;
-	}
-	else
-	{
-		payload_count = 1;
-		payload_length_type = 0x02; /* not used */
-	}
-
-	if (length < bytesread)
-	{
-		rt_kprintf("header exceeded packet size, invalid file - length=%d, bytesread=%d\n",(int)length,(int)bytesread);
-		/* FIXME: should this be checked earlier? */
-		return ASF_ERROR_INVALID_LENGTH;
-	}
-
-	/* We now parse the individual payloads, and move all payloads
-	   belonging to our audio stream to a contiguous block, starting at
-	   the location of the first payload.
-	*/
-	*audiobuf = NULL;
-	*audiobufsize = 0;
-	*packetlength = length - bytesread;
-
-	buf = ci->request_buffer(&bufsize, length);
-	datap = buf;
-
-	if (bufsize != length)
-	{
-		/* This should only happen with packets larger than 32KB (the
-		   guard buffer size).  All the streams I've seen have
-		   relatively small packets less than about 8KB), but I don't
-		   know what is expected.
-		*/
-		rt_kprintf("Could not read packet (requested %d bytes, received %d), curpos=%d, aborting\n",
-				   (int)length,(int)bufsize,(int)ci->curpos);
-		return -1;
-	}
-
-	for (i=0; i<payload_count; i++)
-	{
-		stream_id = datap[0]&0x7f;
-		datap++;
-		bytesread++;
-
-		payload_hdrlen = GETLEN2b(packet_property & 0x03) +
-						 GETLEN2b((packet_property >> 2) & 0x03) +
-						 GETLEN2b((packet_property >> 4) & 0x03);
-
-		// rt_kprintf("payload_hdrlen = %d\n",payload_hdrlen);
-		if (payload_hdrlen > sizeof(data))
-		{
-			rt_kprintf("Unexpectedly long datalen in data - %d\n",datalen);
-			return ASF_ERROR_OUTOFMEM;
-		}
-
-		bytesread += payload_hdrlen;
-		media_object_number = GETVALUE2b((packet_property >> 4) & 0x03, datap);
-		datap += GETLEN2b((packet_property >> 4) & 0x03);
-		media_object_offset = GETVALUE2b((packet_property >> 2) & 0x03, datap);
-		datap += GETLEN2b((packet_property >> 2) & 0x03);
-		replicated_length = GETVALUE2b(packet_property & 0x03, datap);
-		datap += GETLEN2b(packet_property & 0x03);
-
-		/* TODO: Validate replicated_length */
-		/* TODO: Is the content of this important for us? */
-		datap += replicated_length;
-		bytesread += replicated_length;
-
-		multiple = packet_flags & 0x01;
-
-
-		if (multiple)
-		{
-			int x;
-
-			x = GETLEN2b(payload_length_type);
-
-			if (x != 2)
-			{
-				/* in multiple payloads datalen should be a word */
-				return ASF_ERROR_INVALID_VALUE;
-			}
-
-			payload_datalen = GETVALUE2b(payload_length_type, datap);
-			datap += x;
-			bytesread += x;
-		}
-		else
-		{
-			payload_datalen = length - bytesread - padding_length;
-		}
-
-		if (replicated_length==1)
-			datap++;
-
-		if (stream_id == wfx->audiostream)
-		{
-			if (*audiobuf == NULL)
-			{
-				/* The first payload can stay where it is */
-				*audiobuf = datap;
-				*audiobufsize = payload_datalen;
-			}
-			else
-			{
-				/* The second and subsequent payloads in this packet
-				   that belong to the audio stream need to be moved to be
-				   contiguous with the first payload.
-				*/
-				memmove(*audiobuf + *audiobufsize, datap, payload_datalen);
-				*audiobufsize += payload_datalen;
-			}
-		}
-		datap += payload_datalen;
-		bytesread += payload_datalen;
-	}
-
-	if (*audiobuf != NULL)
-		return 1;
-	else
-		return 0;
-}
-
-/* this is the codec entry point */
-void wma_run(void)
-{
-	uint32_t elapsedtime;
-	int retval;
-	asf_waveformatex_t wfx;
-	size_t resume_offset;
-	int i;
-	int wmares, res;
-	uint8_t* audiobuf;
-	int audiobufsize;
-	int packetlength = 0;
-	int errcount = 0;
-
-	/* Generic codec initialisation */
-next_track:
-
-	retval = CODEC_OK;
-
-	/* Remember the resume position - when the codec is opened, the
-	   playback engine will reset it. */
-	resume_offset = ci->id3->offset;
-
-restart_track:
-	if (codec_init())
-	{
-		LOGF("WMA: Error initialising codec\n");
-		retval = CODEC_ERROR;
-		goto exit;
-	}
-
-	/* 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));
-
-	if (wma_decode_init(&wmadec,&wfx) < 0)
-	{
-		LOGF("WMA: Unsupported or corrupt file\n");
-		retval = CODEC_ERROR;
-		goto exit;
-	}
-
-	if (resume_offset > ci->id3->first_frame_offset)
-	{
-		/* Get start of current packet */
-		int packet_offset = (resume_offset - ci->id3->first_frame_offset)
-							% wfx.packet_size;
-		ci->seek_buffer(resume_offset - packet_offset);
-		elapsedtime = get_timestamp(&i);
-		ci->set_elapsed(elapsedtime);
-	}
-	else
-	{
-		/* Now advance the file position to the first frame */
-		ci->seek_buffer(ci->id3->first_frame_offset);
-		elapsedtime = 0;
-	}
-
-	resume_offset = 0;
-
-	/* The main decoding loop */
-
-	res = 1;
-	while (res >= 0)
-	{
-		/* Deal with any pending seek requests */
-		errcount = 0;
-
-new_packet:
-		res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
-
-		if (res < 0)
-		{
-			/* We'll try to recover from a parse error a certain number of
-			 * times. If we succeed, the error counter will be reset.
-			 */
-
-			errcount++;
-			rt_kprintf("read_packet error %d, errcount %d\n",wmares, errcount);
-			if (errcount > 5)
-			{
-				goto done;
-			}
-			else
-			{
-				ci->advance_buffer(packetlength);
-				goto new_packet;
-			}
-		}
-		else if (res > 0)
-		{
-			wma_decode_superframe_init(&wmadec, audiobuf, audiobufsize);
-
-			for (i=0; i < wmadec.nb_frames; i++)
-			{
-				wmares = wma_decode_superframe_frame(&wmadec,
-													 decoded,
-													 audiobuf, audiobufsize);
-
-				if (wmares < 0)
-				{
-					/* Do the above, but for errors in decode. */
-					errcount++;
-					rt_kprintf("WMA decode error %d, errcount %d\n",wmares, errcount);
-					if (errcount > 5)
-					{
-						goto done;
-					}
-					else
-					{
-						ci->advance_buffer(packetlength);
-						goto new_packet;
-					}
-				}
-				else if (wmares > 0)
-				{
-					ci->pcmbuf_insert(decoded, NULL, wmares);
-				}
-			}
-		}
-	}
-	retval = CODEC_OK;
-
-done:
-	/*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/
-	return retval;
-}
-
-void wma()
-{}
-FINSH_FUNCTION_EXPORT(wma, wma test)
+#include "libwma/asf.h"
+#include "libwma/wmadec.h"
+
+int packet_count=0;
+
+/* The output buffer containing the decoded samples (channels 0 and 1)
+   BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2.
+ */
+
+static rt_uint32_t decoded[BLOCK_MAX_SIZE * MAX_CHANNELS];
+
+/* NOTE: WMADecodeContext is 120152 bytes (on x86) */
+static WMADecodeContext wmadec;
+
+enum asf_error_e {
+    ASF_ERROR_INTERNAL       = -1,  /* incorrect input to API calls */
+    ASF_ERROR_OUTOFMEM       = -2,  /* some malloc inside program failed */
+    ASF_ERROR_EOF            = -3,  /* unexpected end of file */
+    ASF_ERROR_IO             = -4,  /* error reading or writing to file */
+    ASF_ERROR_INVALID_LENGTH = -5,  /* length value conflict in input data */
+    ASF_ERROR_INVALID_VALUE  = -6,  /* other value conflict in input data */
+    ASF_ERROR_INVALID_OBJECT = -7,  /* ASF object missing or in wrong place */
+    ASF_ERROR_OBJECT_SIZE    = -8,  /* invalid ASF object size (too small) */
+    ASF_ERROR_SEEKABLE       = -9,  /* file not seekable */
+    ASF_ERROR_SEEK           = -10  /* file is seekable but seeking failed */
+};
+
+/* Read an unaligned 32-bit little endian long from buffer. */
+static unsigned long get_long_le(void* buf)
+{
+    unsigned char* p = (unsigned char*) buf;
+
+    return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+
+/* Read an unaligned 16-bit little endian short from buffer. */
+static unsigned short get_short_le(void* buf)
+{
+    unsigned char* p = (unsigned char*) buf;
+
+    return p[0] | (p[1] << 8);
+}
+
+#define GETLEN2b(bits) (((bits) == 0x03) ? 4 : bits)
+
+#define GETVALUE2b(bits, data) \
+        (((bits) != 0x03) ? ((bits) != 0x02) ? ((bits) != 0x01) ? \
+         0 : *(data) : get_short_le(data) : get_long_le(data))
+
+static int asf_read_packet(rt_uint8_t** audiobuf, int* audiobufsize, int* packetlength, asf_waveformatex_t* wfx)
+{
+    rt_uint8_t tmp8, packet_flags, packet_property;
+    int stream_id;
+    int ec_length, opaque_data, ec_length_type;
+    int datalen;
+    rt_uint8_t data[18];
+    rt_uint8_t* datap;
+    rt_uint32_t length;
+    rt_uint32_t padding_length;
+    rt_uint32_t send_time;
+    rt_uint16_t duration;
+    rt_uint16_t payload_count;
+    int payload_length_type;
+    rt_uint32_t payload_hdrlen;
+    int payload_datalen;
+    int multiple;
+    rt_uint32_t replicated_length;
+    rt_uint32_t media_object_number;
+    rt_uint32_t media_object_offset;
+    rt_uint32_t bytesread = 0;
+    rt_uint8_t* buf;
+    size_t bufsize;
+    int i;
+    /*DEBUGF("Reading new packet at %d bytes ", (int)ci->curpos);*/
+
+    if (ci->read_filebuf(&tmp8, 1) == 0) {
+        return ASF_ERROR_EOF;
+    }
+    bytesread++;
+
+    /* TODO: We need a better way to detect endofstream */
+    if (tmp8 != 0x82) {
+    DEBUGF("Read failed:  packet did not sync\n");
+    return -1;
+    }
+
+
+    if (tmp8 & 0x80) {
+       ec_length = tmp8 & 0x0f;
+       opaque_data = (tmp8 >> 4) & 0x01;
+       ec_length_type = (tmp8 >> 5) & 0x03;
+
+       if (ec_length_type != 0x00 || opaque_data != 0 || ec_length != 0x02) {
+            DEBUGF("incorrect error correction flags\n");
+            return ASF_ERROR_INVALID_VALUE;
+       }
+
+       /* Skip ec_data */
+       ci->advance_buffer(ec_length);
+       bytesread += ec_length;
+    } else {
+        ec_length = 0;
+    }
+
+    if (ci->read_filebuf(&packet_flags, 1) == 0) { return ASF_ERROR_EOF; }
+    if (ci->read_filebuf(&packet_property, 1) == 0) { return ASF_ERROR_EOF; }
+    bytesread += 2;
+
+    datalen = GETLEN2b((packet_flags >> 1) & 0x03) +
+              GETLEN2b((packet_flags >> 3) & 0x03) +
+              GETLEN2b((packet_flags >> 5) & 0x03) + 6;
+
+    if (ci->read_filebuf(data, datalen) == 0) {
+        return ASF_ERROR_EOF;
+    }
+
+    bytesread += datalen;
+
+    datap = data;
+    length = GETVALUE2b((packet_flags >> 5) & 0x03, datap);
+    datap += GETLEN2b((packet_flags >> 5) & 0x03);
+    /* sequence value is not used */
+    GETVALUE2b((packet_flags >> 1) & 0x03, datap);
+    datap += GETLEN2b((packet_flags >> 1) & 0x03);
+    padding_length = GETVALUE2b((packet_flags >> 3) & 0x03, datap);
+    datap += GETLEN2b((packet_flags >> 3) & 0x03);
+    send_time = get_long_le(datap);
+    datap += 4;
+    duration = get_short_le(datap);
+    datap += 2;
+    /*DEBUGF("and duration %d ms\n", duration);*/
+
+    /* this is really idiotic, packet length can (and often will) be
+     * undefined and we just have to use the header packet size as the size
+     * value */
+    if (!((packet_flags >> 5) & 0x03)) {
+         length = wfx->packet_size;
+    }
+
+    /* this is also really idiotic, if packet length is smaller than packet
+     * size, we need to manually add the additional bytes into padding length
+     */
+    if (length < wfx->packet_size) {
+        padding_length += wfx->packet_size - length;
+        length = wfx->packet_size;
+    }
+
+    if (length > wfx->packet_size) {
+        DEBUGF("packet with too big length value\n");
+        return ASF_ERROR_INVALID_LENGTH;
+    }
+
+    /* check if we have multiple payloads */
+    if (packet_flags & 0x01) {
+        if (ci->read_filebuf(&tmp8, 1) == 0) {
+            return ASF_ERROR_EOF;
+        }
+        payload_count = tmp8 & 0x3f;
+        payload_length_type = (tmp8 >> 6) & 0x03;
+        bytesread++;
+    } else {
+        payload_count = 1;
+        payload_length_type = 0x02; /* not used */
+    }
+
+    if (length < bytesread) {
+        DEBUGF("header exceeded packet size, invalid file - length=%d, bytesread=%d\n",(int)length,(int)bytesread);
+        /* FIXME: should this be checked earlier? */
+        return ASF_ERROR_INVALID_LENGTH;
+    }
+
+
+    /* We now parse the individual payloads, and move all payloads
+       belonging to our audio stream to a contiguous block, starting at
+       the location of the first payload.
+    */
+
+    *audiobuf = NULL;
+    *audiobufsize = 0;
+    *packetlength = length - bytesread;
+
+    buf = ci->request_buffer(&bufsize, length);
+    datap = buf;
+
+    if (bufsize != length) {
+        /* This should only happen with packets larger than 32KB (the
+           guard buffer size).  All the streams I've seen have
+           relatively small packets less than about 8KB), but I don't
+           know what is expected.
+        */
+        DEBUGF("Could not read packet (requested %d bytes, received %d), curpos=%d, aborting\n",
+               (int)length,(int)bufsize,(int)ci->curpos);
+        return -1;
+    }
+
+    for (i=0; i<payload_count; i++) {
+        stream_id = datap[0]&0x7f;
+        datap++;
+        bytesread++;
+
+        payload_hdrlen = GETLEN2b(packet_property & 0x03) +
+                         GETLEN2b((packet_property >> 2) & 0x03) +
+                         GETLEN2b((packet_property >> 4) & 0x03);
+
+        //DEBUGF("payload_hdrlen = %d\n",payload_hdrlen);
+        if (payload_hdrlen > sizeof(data)) {
+            DEBUGF("Unexpectedly long datalen in data - %d\n",datalen);
+            return ASF_ERROR_OUTOFMEM;
+        }
+
+        bytesread += payload_hdrlen;
+        media_object_number = GETVALUE2b((packet_property >> 4) & 0x03, datap);
+        datap += GETLEN2b((packet_property >> 4) & 0x03);
+        media_object_offset = GETVALUE2b((packet_property >> 2) & 0x03, datap);
+        datap += GETLEN2b((packet_property >> 2) & 0x03);
+        replicated_length = GETVALUE2b(packet_property & 0x03, datap);
+        datap += GETLEN2b(packet_property & 0x03);
+
+        /* TODO: Validate replicated_length */
+        /* TODO: Is the content of this important for us? */
+        datap += replicated_length;
+        bytesread += replicated_length;
+
+        multiple = packet_flags & 0x01;
+
+
+        if (multiple) {
+            int x;
+
+            x = GETLEN2b(payload_length_type);
+
+            if (x != 2) {
+                /* in multiple payloads datalen should be a word */
+                return ASF_ERROR_INVALID_VALUE;
+            }
+
+            payload_datalen = GETVALUE2b(payload_length_type, datap);
+            datap += x;
+            bytesread += x;
+        } else {
+            payload_datalen = length - bytesread - padding_length;
+        }
+
+        if (replicated_length==1)
+            datap++;
+
+        if (stream_id == wfx->audiostream)
+        {
+            if (*audiobuf == NULL) {
+                /* The first payload can stay where it is */
+                *audiobuf = datap;
+                *audiobufsize = payload_datalen;
+            } else {
+                /* The second and subsequent payloads in this packet
+                   that belong to the audio stream need to be moved to be
+                   contiguous with the first payload.
+                */
+                memmove(*audiobuf + *audiobufsize, datap, payload_datalen);
+                *audiobufsize += payload_datalen;
+            }
+        }
+        datap += payload_datalen;
+        bytesread += payload_datalen;
+    }
+
+    if (*audiobuf != NULL)
+        return 1;
+    else
+        return 0;
+}
+
+/* this is the codec entry point */
+void wma_codec_main(void)
+{
+    rt_uint32_t elapsedtime;
+    int retval;
+    asf_waveformatex_t wfx;
+    size_t resume_offset;
+    int i;
+    int wmares, res;
+    rt_uint8_t* audiobuf;
+    int audiobufsize;
+    int packetlength = 0;
+    int errcount = 0;
+
+    /* Remember the resume position - when the codec is opened, the
+       playback engine will reset it. */
+    resume_offset = ci->id3->offset;
+
+    /* 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));
+
+    if (wma_decode_init(&wmadec,&wfx) < 0) {
+        LOGF("WMA: Unsupported or corrupt file\n");
+        retval = CODEC_ERROR;
+        goto exit;
+    }
+
+    DEBUGF("**************** IN WMA.C ******************\n");
+
+    if (resume_offset > ci->id3->first_frame_offset)
+    {
+        /* Get start of current packet */
+        int packet_offset = (resume_offset - ci->id3->first_frame_offset)
+            % wfx.packet_size;
+        ci->seek_buffer(resume_offset - packet_offset);
+        elapsedtime = get_timestamp(&i);
+        ci->set_elapsed(elapsedtime);
+    }
+    else
+    {
+        /* Now advance the file position to the first frame */
+        ci->seek_buffer(ci->id3->first_frame_offset);
+        elapsedtime = 0;
+    }
+
+    resume_offset = 0;
+    ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate);
+    ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ?
+                  STEREO_MONO : STEREO_INTERLEAVED);
+    codec_set_replaygain(ci->id3);
+
+    /* The main decoding loop */
+
+    res = 1;
+    while (res >= 0)
+    {
+        errcount = 0;
+new_packet:
+        res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
+
+        if (res < 0) {
+            /* We'll try to recover from a parse error a certain number of
+             * times. If we succeed, the error counter will be reset.
+             */
+            errcount++;
+            DEBUGF("read_packet error %d, errcount %d\n",wmares, errcount);
+            if (errcount > 5) {
+                goto done;
+            } else {
+                ci->advance_buffer(packetlength);
+                goto new_packet;
+            }
+        } else if (res > 0) {
+            wma_decode_superframe_init(&wmadec, audiobuf, audiobufsize);
+
+            for (i=0; i < wmadec.nb_frames; i++)
+            {
+                wmares = wma_decode_superframe_frame(&wmadec,
+                                                     decoded,
+                                                     audiobuf, audiobufsize);
+
+                if (wmares < 0) {
+                    /* Do the above, but for errors in decode. */
+                    errcount++;
+                    DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount);
+                    if (errcount > 5) {
+                        goto done;
+                    } else {
+                        ci->advance_buffer(packetlength);
+                        goto new_packet;
+                    }
+                } else if (wmares > 0) {
+                	/* write to audio device */
+                    elapsedtime += (wmares*10)/(wfx.rate/100);
+                    ci->set_elapsed(elapsedtime);
+                }
+                ci->yield();
+            }
+        }
+
+        ci->advance_buffer(packetlength);
+    }
+
+done:
+exit:
+    return ;
+}
+