Realmedia related codecs fixes and enhancements

 * More tolerance to the file format variations.
 * AC3 coded files in realaudio format are now playable

Full credit to Igor Poretsky

Change-Id: Id24e94bc00623e89fb8c80403efa92f69ab1e5d7
diff --git a/lib/rbcodec/codecs/a52_rm.c b/lib/rbcodec/codecs/a52_rm.c
index bbfd1c7..e520476 100644
--- a/lib/rbcodec/codecs/a52_rm.c
+++ b/lib/rbcodec/codecs/a52_rm.c
@@ -44,6 +44,14 @@
 
 /* used outside liba52 */
 static uint8_t buf[3840] IBSS_ATTR;
+static uint8_t *bufptr = buf;
+static uint8_t *bufpos = buf + 7;
+
+static void a52_decoder_reset(void)
+{
+    bufptr = buf;
+    bufpos = buf + 7;
+}
 
 /* The following two functions, a52_decode_data and output_audio are taken from a52.c */
 static inline void output_audio(sample_t *samples)
@@ -52,10 +60,8 @@
     ci->pcmbuf_insert(&samples[0], &samples[256], 256);
 }
 
-static void a52_decode_data(uint8_t *start, uint8_t *end)
+static size_t a52_decode_data(uint8_t *start, uint8_t *end)
 {
-    static uint8_t *bufptr = buf;
-    static uint8_t *bufpos = buf + 7;
     /*
      * sample_rate and flags are static because this routine could
      * exit between the a52_syncinfo() and the ao_setup(), and we want
@@ -65,6 +71,7 @@
     static int flags;
     int bit_rate;
     int len;
+    size_t consumed = 0;
 
     while (1) {
         len = end - start;
@@ -75,6 +82,7 @@
         memcpy(bufptr, start, len);
         bufptr += len;
         start += len;
+        consumed += len;
         if (bufptr == bufpos) {
             if (bufpos == buf + 7) {
                 int length;
@@ -114,7 +122,7 @@
                 ci->set_elapsed(samplesdone/(frequency/1000));
                 bufptr = buf;
                 bufpos = buf + 7;
-                continue;
+                break;
             error:
                 //logf("Error decoding A52 stream\n");
                 bufptr = buf;
@@ -122,6 +130,7 @@
             }
         }   
     }
+    return consumed;
 }
 
 /* this is the codec entry point */
@@ -143,11 +152,13 @@
 /* this is called for each file to process */
 enum codec_status codec_run(void)
 {
-    size_t n;
+    size_t consumed = 0, n = 0;
     uint8_t *filebuf;
-    int consumed, packet_offset;
+    int packet_offset;
     int playback_on = -1;
     size_t resume_offset;
+    size_t data_offset;
+    size_t packet_size;
     long action;
     intptr_t param;
 
@@ -162,21 +173,28 @@
     ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
     codec_set_replaygain(ci->id3);
 
-    ci->seek_buffer(ci->id3->first_frame_offset);
+    ci->seek_buffer(0);
 
-    /* Intializations */
+    /* Initializations */
     state = a52_init(0);
     ci->memset(&rmctx,0,sizeof(RMContext)); 
     ci->memset(&pkt,0,sizeof(RMPacket));
     init_rm(&rmctx);
+    data_offset = rmctx.data_offset +
+      ((rmctx.flags & RM_RAW_DATASTREAM) ? 0 : DATA_HEADER_SIZE);
+    packet_size = rmctx.block_align +
+      ((rmctx.flags & RM_RAW_DATASTREAM) ?
+       0 :
+       (PACKET_HEADER_SIZE +
+        ((rmctx.flags & RM_PKT_V1) ? 1 : 0)));
 
     samplesdone = 0;
 
     /* check for a mid-track resume and force a seek time accordingly */
     if (resume_offset) {
-        resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE);
+        resume_offset -= MIN(resume_offset, data_offset);
         /* put number of subpackets to skip in resume_offset */
-        resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE);
+        resume_offset /= packet_size;
         param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
     }
 
@@ -186,11 +204,11 @@
     else {
         /* Seek to the first packet */
         ci->set_elapsed(0);
-        ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE );
+        ci->advance_buffer(data_offset);
     }
 
     /* The main decoding loop */
-    while((unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) {
+    while ((rmctx.flags & RM_RAW_DATASTREAM) || (unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) {
         if (action == CODEC_ACTION_NULL)
             action = ci->get_command(&param);
 
@@ -198,34 +216,69 @@
             break;
 
         if (action == CODEC_ACTION_SEEK_TIME) {
+            /* Do not allow seeking beyond the file's length */
+            if ((unsigned) param > ci->id3->length) {
+                ci->set_elapsed(ci->id3->length);
+                ci->seek_complete();
+                break;
+            }
+
+            if (n)
+                rm_ac3_swap_bytes(filebuf, (rmctx.flags & RM_RAW_DATASTREAM) ? n : rmctx.block_align);
             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));
+            ci->seek_buffer(data_offset + packet_offset * packet_size);
             rmctx.audio_pkt_cnt = packet_offset;
-            samplesdone = (rmctx.sample_rate/1000 * param);
-            ci->set_elapsed(samplesdone/(frequency/1000));
+            samplesdone = packet_offset * A52_SAMPLESPERFRAME;
+            ci->set_elapsed(samplesdone/(ci->id3->frequency/1000));
             ci->seek_complete();
+            a52_decoder_reset();
+            consumed = 0;
+            n = 0;
         }
 
         action = CODEC_ACTION_NULL;
 
-        filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE);
-        consumed = rm_get_packet(&filebuf, &rmctx, &pkt);
-
-        if(consumed < 0 && playback_on != 0) {
-            if(playback_on == -1) {
-            /* Error only if packet-parsing failed and playback hadn't started */
-                DEBUGF("rm_get_packet failed\n");
-                return CODEC_ERROR;
+        if (rmctx.flags & RM_RAW_DATASTREAM) {
+            if (n > consumed) {
+                consumed += a52_decode_data(filebuf + consumed, filebuf + n);
+                ci->set_offset(ci->curpos + consumed);
             }
             else {
-                break;
+                if (n) {
+                    rm_ac3_swap_bytes(filebuf, n);
+                    ci->advance_buffer(n);
+                }
+                filebuf = ci->request_buffer(&n, BUFFER_SIZE);
+                if (n == 0)
+                    break;
+                rm_ac3_swap_bytes(filebuf, n);
+                consumed = 0;
             }
         }
+        else {
+            filebuf = ci->request_buffer(&n, packet_size);
 
-        playback_on = 1;
-        a52_decode_data(filebuf, filebuf + rmctx.block_align);
-        ci->advance_buffer(pkt.length);
+            if (n == 0)
+                break;
+
+            if (rm_get_packet(&filebuf, &rmctx, &pkt) < 0 && playback_on != 0) {
+                if(playback_on == -1) {
+                    /* Error only if packet-parsing failed and playback hadn't started */
+                    DEBUGF("rm_get_packet failed\n");
+                    return CODEC_ERROR;
+                }
+                else {
+                    break;
+                }
+            }
+
+            playback_on = 1;
+            consumed = 0;
+            while (consumed < rmctx.block_align)
+                consumed += a52_decode_data(filebuf + consumed, filebuf + rmctx.block_align);
+            rm_ac3_swap_bytes(filebuf, rmctx.block_align);
+            ci->advance_buffer(pkt.length);
+        }
     }
 
     return CODEC_OK;
diff --git a/lib/rbcodec/codecs/atrac3_rm.c b/lib/rbcodec/codecs/atrac3_rm.c
index 59dbd29..af38b79 100644
--- a/lib/rbcodec/codecs/atrac3_rm.c
+++ b/lib/rbcodec/codecs/atrac3_rm.c
@@ -21,7 +21,6 @@
 
 #include <string.h>
 
-#include "logf.h"
 #include "codeclib.h"
 #include "inttypes.h"
 #include "libatrac/atrac3.h"
@@ -37,10 +36,26 @@
     /* initialize the RMContext */
     memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext));
 
-    /* and atrac3 expects extadata in id3v2buf, so we shall give it that */
+    /* and atrac3 expects extradata in id3v2buf, so we shall give it that */
     memcpy(ci->id3->id3v2buf, (char*)rmctx->codec_extradata, rmctx->extradata_size*sizeof(char));
 }
 
+static int request_packet(int size)
+{
+    int consumed = 0;
+    while (1)
+    {
+        uint8_t *buffer = ci->request_buffer((size_t *)(&consumed), size);
+        if (!consumed)
+            break;
+        consumed = rm_get_packet(&buffer, &rmctx, &pkt);
+        if (consumed < 0 || consumed == size)
+            break;
+        ci->advance_buffer(size);
+    }
+    return consumed;
+}
+
 /* this is the codec entry point */
 enum codec_status codec_main(enum codec_entry_call_reason reason)
 {
@@ -52,12 +67,10 @@
 /* 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;
-    uint8_t *bit_buffer;
     uint16_t fs,sps,h;
     uint32_t packet_count;
-    int scrambling_unit_size, num_units, elapsed;
+    int spn, packet_header_size, scrambling_unit_size, num_units, elapsed;
     int playback_on = -1;
     size_t resume_offset;
     intptr_t param;
@@ -85,14 +98,17 @@
     ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ?
         STEREO_MONO : STEREO_NONINTERLEAVED);
 
+    packet_header_size = PACKET_HEADER_SIZE +
+      ((rmctx.flags & RM_PKT_V1) ? 1 : 0);
     packet_count = rmctx.nb_packets;
     rmctx.audio_framesize = rmctx.block_align;
     rmctx.block_align = rmctx.sub_packet_size;
     fs = rmctx.audio_framesize;
     sps= rmctx.block_align;
     h = rmctx.sub_packet_h;
-    scrambling_unit_size = h * (fs + PACKET_HEADER_SIZE);
-    
+    scrambling_unit_size = h * (fs + packet_header_size);
+    spn = h * fs / sps;
+
     res = atrac3_decode_init(&q, ci->id3);
     if(res < 0) {
         DEBUGF("failed to initialize RM atrac decoder\n");
@@ -102,10 +118,10 @@
     /* check for a mid-track resume and force a seek time accordingly */
     if(resume_offset) {
         resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE);
-        num_units = (int)resume_offset / scrambling_unit_size;        
-        /* put number of subpackets to skip in resume_offset */
-        resume_offset /= (sps + PACKET_HEADER_SIZE);
-        elapsed = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
+        num_units = (int)resume_offset / scrambling_unit_size;
+        /* put number of packets to skip in resume_offset */
+        resume_offset = num_units * h;
+        elapsed = (int)resume_offset * ((8000LL * fs)/rmctx.bit_rate);
     }
 
     if (elapsed > 0) {
@@ -123,8 +139,9 @@
 seek_start :         
     while((unsigned)elapsed < rmctx.duration)
     {  
-        bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size);
-        consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt);
+        consumed = request_packet(scrambling_unit_size);
+        if (!consumed)
+            break;
         if(consumed < 0 && playback_on != 0) {
             if(playback_on == -1) {
             /* Error only if packet-parsing failed and playback hadn't started */
@@ -135,7 +152,7 @@
                 return CODEC_OK;
         }
 
-        for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++)
+        for (i = 0; i < spn; i++)
         { 
             if (action == CODEC_ACTION_NULL)
                 action = ci->get_command(&param);
@@ -164,10 +181,11 @@
                     action = CODEC_ACTION_NULL;
                     goto seek_start;           
                 }                                                                
-                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);
+                num_units = (param/(sps*1000*8/rmctx.bit_rate))/spn;
+                ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units);
+                consumed = request_packet(scrambling_unit_size);
+                if (!consumed)
+                    return CODEC_OK;
                 if(consumed < 0 && playback_on != 0) {
                     if(playback_on == -1) {
                     /* Error only if packet-parsing failed and playback hadn't started */
@@ -178,19 +196,32 @@
                         return CODEC_OK;
                 }
 
-                packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units;
+                packet_count = rmctx.nb_packets - h * num_units;
                 rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate)); 
-                while(rmctx.audiotimestamp > (unsigned) param) {
+                while (rmctx.audiotimestamp > (unsigned)param && num_units-- > 0) {
                     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); 
-                    consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt);                                                                             
-                    packet_count += rmctx.audio_pkt_cnt;
-                    num_units--;
+                    ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units);
+                    consumed = request_packet(scrambling_unit_size);
+                    if (!consumed)
+                        return CODEC_OK;
+                    if(consumed < 0 && playback_on != 0) {
+                        if(playback_on == -1) {
+                        /* Error only if packet-parsing failed and playback hadn't started */
+                            DEBUGF("rm_get_packet failed\n");
+                            return CODEC_ERROR;
+                        }
+                        else
+                            return CODEC_OK;
+                    }
+
+                    packet_count += h;
                 }
+
+                if (num_units < 0)
+                    rmctx.audiotimestamp = 0;
                 time_offset = param - rmctx.audiotimestamp;
                 i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate));
-                elapsed = rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i;
+                elapsed = param;
                 ci->set_elapsed(elapsed);
                 ci->seek_complete(); 
             }
@@ -198,11 +229,11 @@
             action = CODEC_ACTION_NULL;
 
             if(pkt.length)    
-                res = atrac3_decode_frame(rmctx.block_align, &q, &datasize, pkt.frames[i], rmctx.block_align);
+                res = atrac3_decode_frame(sps, &q, &datasize, pkt.frames[i], sps);
             else /* indicates that there are no remaining frames */
                 return CODEC_OK;
 
-            if(res != rmctx.block_align) {
+            if (res != sps) {
                 DEBUGF("codec error\n");
                 return CODEC_ERROR;
             }
@@ -214,9 +245,9 @@
             ci->set_elapsed(elapsed);
             rmctx.frame_number++;
         }
-        packet_count -= rmctx.audio_pkt_cnt;
+        packet_count -= h;
         rmctx.audio_pkt_cnt = 0;
-        ci->advance_buffer(consumed);
+        ci->advance_buffer(scrambling_unit_size);
     }
 
     return CODEC_OK;
diff --git a/lib/rbcodec/codecs/cook.c b/lib/rbcodec/codecs/cook.c
index af1f5e1..254e71f 100644
--- a/lib/rbcodec/codecs/cook.c
+++ b/lib/rbcodec/codecs/cook.c
@@ -21,7 +21,6 @@
 
 #include <string.h>
 
-#include "logf.h"
 #include "codeclib.h"
 #include "inttypes.h"
 #include "libcook/cook.h"
@@ -38,6 +37,22 @@
     memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext));
 }
 
+static int request_packet(int size)
+{
+    int consumed = 0;
+    while (1)
+    {
+        uint8_t *buffer = ci->request_buffer((size_t *)(&consumed), size);
+        if (!consumed)
+            break;
+        consumed = rm_get_packet(&buffer, &rmctx, &pkt);
+        if (consumed < 0 || consumed == size)
+            break;
+        ci->advance_buffer(size);
+    }
+    return consumed;
+}
+
 /* this is the codec entry point */
 enum codec_status codec_main(enum codec_entry_call_reason reason)
 {
@@ -49,12 +64,10 @@
 /* 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;
-    uint8_t *bit_buffer;
     uint16_t fs,sps,h;
     uint32_t packet_count;
-    int scrambling_unit_size, num_units;
+    int spn, packet_header_size, scrambling_unit_size, num_units;
     size_t resume_offset;
     intptr_t param;
     long action;
@@ -84,14 +97,17 @@
     ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ?
                   STEREO_MONO : STEREO_NONINTERLEAVED);
 
+    packet_header_size = PACKET_HEADER_SIZE +
+      ((rmctx.flags & RM_PKT_V1) ? 1 : 0);
     packet_count = rmctx.nb_packets;
     rmctx.audio_framesize = rmctx.block_align;
     rmctx.block_align = rmctx.sub_packet_size;
     fs = rmctx.audio_framesize;
     sps= rmctx.block_align;
     h = rmctx.sub_packet_h;
-    scrambling_unit_size = h * (fs + PACKET_HEADER_SIZE);
-    
+    scrambling_unit_size = h * (fs + packet_header_size);
+    spn = h * fs / sps;
+
     res =cook_decode_init(&rmctx, &q);
     if(res < 0) {
         DEBUGF("failed to initialize cook decoder\n");
@@ -101,10 +117,10 @@
     /* check for a mid-track resume and force a seek time accordingly */
     if(resume_offset) {
         resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE);
-        num_units = (int)resume_offset / scrambling_unit_size;    
-        /* put number of subpackets to skip in resume_offset */
-        resume_offset /= (sps + PACKET_HEADER_SIZE);
-        param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
+        num_units = (int)resume_offset / scrambling_unit_size;
+        /* put number of packets to skip in resume_offset */
+        resume_offset = num_units * h;
+        param = (int)resume_offset * ((8000LL * fs)/rmctx.bit_rate);
     }
 
     if (param) {
@@ -120,14 +136,15 @@
 seek_start :         
     while(packet_count)
     {  
-        bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size);
-        consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt);
+        consumed = request_packet(scrambling_unit_size);
+        if (!consumed)
+            break;
         if(consumed < 0) {
             DEBUGF("rm_get_packet failed\n");
             return CODEC_ERROR;
         }
-       
-        for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++)
+
+        for (i = 0; i < spn; i++)
         {
             if (action == CODEC_ACTION_NULL)
                 action = ci->get_command(&param);
@@ -155,52 +172,65 @@
                     action = CODEC_ACTION_NULL;
                     goto seek_start;           
                 }                                                                
-                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);
+                num_units = (param/(sps*1000*8/rmctx.bit_rate))/spn;
+                ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units);
+                consumed = request_packet(scrambling_unit_size);
+                if (!consumed) {
+                    ci->seek_complete();
+                    return CODEC_OK;
+                }
                 if(consumed < 0) {
-                     DEBUGF("rm_get_packet failed\n");
+                    DEBUGF("rm_get_packet failed\n");
                     ci->seek_complete();
                     return CODEC_ERROR;
                 } 
-                packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units;
+
+                packet_count = rmctx.nb_packets - h * num_units;
                 rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate)); 
-                while(rmctx.audiotimestamp > (unsigned) param) {
+                while(rmctx.audiotimestamp > (unsigned)param && num_units-- > 0) {
                     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); 
-                    consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt);                                                                             
-                    packet_count += rmctx.audio_pkt_cnt;
-                    num_units--;
+                    ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units);
+                    consumed = request_packet(scrambling_unit_size);
+                    if (!consumed) {
+                        ci->seek_complete();
+                        return CODEC_OK;
+                    }
+                    if(consumed < 0) {
+                        ci->seek_complete();
+                        DEBUGF("rm_get_packet failed\n");
+                        return CODEC_ERROR;
+                    }
+
+                    packet_count += h;
                 }
+
+                if (num_units < 0)
+                    rmctx.audiotimestamp = 0;
                 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->set_elapsed(param);
                 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++;
+            res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], sps);
 
-            /* skip the first two frames; no valid audio */
-            if(rmctx.frame_number < 3) continue;
-
-            if(res != rmctx.block_align) {
+            if (res != sps) {
                 DEBUGF("codec error\n");
                 return CODEC_ERROR;
             }
 
-            ci->pcmbuf_insert(rm_outbuf, 
-                              rm_outbuf+q.samples_per_channel,
-                              q.samples_per_channel);
+            if(datasize)
+                ci->pcmbuf_insert(rm_outbuf,
+                                  rm_outbuf+q.samples_per_channel,
+                                  q.samples_per_channel);
             ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i);  
+            rmctx.frame_number++;
         }
-        packet_count -= rmctx.audio_pkt_cnt;
+        packet_count -= h;
         rmctx.audio_pkt_cnt = 0;
-        ci->advance_buffer(consumed);
+        ci->advance_buffer(scrambling_unit_size);
     }
 
     return CODEC_OK;
diff --git a/lib/rbcodec/codecs/librm/rm.c b/lib/rbcodec/codecs/librm/rm.c
index eabbe5d..e499961 100644
--- a/lib/rbcodec/codecs/librm/rm.c
+++ b/lib/rbcodec/codecs/librm/rm.c
@@ -27,8 +27,6 @@
 #include "codeclib.h"
 #endif
 
-#define SWAP(a, b) do{uint8_t SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)
-
 #ifdef TEST
 #include <fcntl.h>
 #include <unistd.h>
@@ -500,17 +498,33 @@
 }
 #endif /*TEST*/
 
+void rm_ac3_swap_bytes(uint8_t *buf, int bufsize)
+{
+    uint8_t *bufptr;
+    for (bufptr = buf; bufptr < buf + bufsize - 1; bufptr += 2)
+    {
+        bufptr[0] ^= bufptr[1];
+        bufptr[1] ^= bufptr[0];
+        bufptr[0] ^= bufptr[1];
+    }
+}
+
 int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt)
 {   
     int consumed = 0;
+    int headerlen;
     /* rockbox: comment 'set but unused' variables
     uint8_t unknown;
     */
-    uint16_t x, place;
+    uint16_t x;
     uint16_t sps = rmctx->sub_packet_size;
     uint16_t h = rmctx->sub_packet_h;
-    uint16_t y = rmctx->sub_packet_cnt;
+    uint16_t y = 0;
     uint16_t w = rmctx->audio_framesize;
+
+    rmctx->sub_packet_cnt = 0;
+    rmctx->audio_pkt_cnt = 0;
+
     do
     {
         y = rmctx->sub_packet_cnt;
@@ -523,6 +537,7 @@
              return -1;
         }
         
+        headerlen = PACKET_HEADER_SIZE + (pkt->version ? 1 : 0);
         pkt->length        = rm_get_uint16be(*src+2);
         pkt->stream_number = rm_get_uint16be(*src+4);
         pkt->timestamp     = rm_get_uint32be(*src+6);
@@ -534,25 +549,27 @@
         pkt->flags   = rm_get_uint8(*src+11);
 
         if(pkt->version == 1)
-            /* unknown = */ rm_get_uint8(*src+10);
+            /* unknown = */ rm_get_uint8(*src+12);
 
-        if (pkt->flags & 2) /* keyframe */
-            y = rmctx->sub_packet_cnt = 0;
+        if (pkt->flags & 2) { /* keyframe */
+            if (y)
+                return consumed;
+            y = 0;
+        }
         if (!y)
             rmctx->audiotimestamp = pkt->timestamp;
-        
+
         /* Skip packet header */
-        advance_buffer(src, PACKET_HEADER_SIZE);
-        consumed += PACKET_HEADER_SIZE;
+        advance_buffer(src, headerlen);
+        consumed += headerlen;
         if (rmctx->codec_type == CODEC_COOK || rmctx->codec_type == CODEC_ATRAC) {
             for(x = 0 ; x < w/sps; x++)
             {
-                place = sps*(h*x+((h+1)/2)*(y&1)+(y>>1)); 
-                pkt->frames[place/sps] = *src;
+                pkt->frames[h*x+((h+1)/2)*(y&1)+(y>>1)] = *src;
                 advance_buffer(src,sps);
                 consumed += sps;
             }
-         }
+        }
         else if (rmctx->codec_type == CODEC_AAC) {
             rmctx->sub_packet_cnt = (rm_get_uint16be(*src) & 0xf0) >> 4;
             advance_buffer(src, 2);
@@ -563,22 +580,22 @@
                     advance_buffer(src, 2);
                     consumed += 2;
                 }                
-                rmctx->audio_pkt_cnt = --rmctx->sub_packet_cnt;
+                rmctx->audio_pkt_cnt = rmctx->sub_packet_cnt;
             }
+            break;
         } 
 
         else if (rmctx->codec_type == CODEC_AC3) {
         /* The byte order of the data is reversed from standard AC3 */
-            for(x = 0; x < pkt->length - PACKET_HEADER_SIZE; x+=2) {
-                SWAP((*src)[0], (*src)[1]);
-                *src += 2;                                
-            }
-            *src -= x;
+            rm_ac3_swap_bytes(*src, pkt->length - headerlen);
+            break;
         }
+        else return -1; /* invalid codec type */
+
         rmctx->audio_pkt_cnt++;
     }while(++(rmctx->sub_packet_cnt) < h);
 
-return consumed;
+    return consumed;
 }
 
 #ifdef DEBUG
@@ -587,6 +604,6 @@
     DEBUGF("block_align = %d\n", rmctx->block_align);
     DEBUGF("nb_channels = %d\n", rmctx->nb_channels);
     DEBUGF("sample_rate = %d\n", rmctx->sample_rate);
-    DEBUGF("bit_rate    = %d\n", rmctx->bit_rate   );
+    DEBUGF("bit_rate    = %ld\n", rmctx->bit_rate   );
 }
 #endif
diff --git a/lib/rbcodec/codecs/librm/rm.h b/lib/rbcodec/codecs/librm/rm.h
index c4a4e3a..47ea559 100644
--- a/lib/rbcodec/codecs/librm/rm.h
+++ b/lib/rbcodec/codecs/librm/rm.h
@@ -25,6 +25,9 @@
 #include <inttypes.h>
 #include "bytestream.h"
 
+#define RM_RAW_DATASTREAM 0x0100
+#define RM_PKT_V1 0x0200
+
 #define MAX_EXTRADATA_SIZE 16
 #define DATA_HEADER_SIZE 18
 #define PACKET_HEADER_SIZE 12
@@ -86,6 +89,8 @@
 
 int real_parse_header(int fd, RMContext *rmctx);
 
+void rm_ac3_swap_bytes(uint8_t *buf, int bufsize);
+
 /* Get a (sub_packet_h*frames_per_packet) number of audio frames from a memory buffer */
 int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt);
 
diff --git a/lib/rbcodec/codecs/raac.c b/lib/rbcodec/codecs/raac.c
index e77d432..6856afc 100644
--- a/lib/rbcodec/codecs/raac.c
+++ b/lib/rbcodec/codecs/raac.c
@@ -109,7 +109,8 @@
     if (resume_offset) {
         resume_offset -= MIN(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);
+        resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE +
+                          ((rmctx.flags & RM_PKT_V1) ? 1 : 0));
         param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
     }
 
diff --git a/lib/rbcodec/metadata/metadata.c b/lib/rbcodec/metadata/metadata.c
index 87ea922..7ca4b1a 100644
--- a/lib/rbcodec/metadata/metadata.c
+++ b/lib/rbcodec/metadata/metadata.c
@@ -444,13 +444,13 @@
     /* Load codec specific track tag information and confirm the codec type. */
     if (!entry->parse_func)
     {
-        DEBUGF("nothing to parse for %s (format %s)", trackname, entry->label);
+        DEBUGF("nothing to parse for %s (format %s)\n", trackname, entry->label);
         return false;
     }
 
     if (!entry->parse_func(fd, id3))
     {
-        DEBUGF("parsing %s failed (format: %s)", trackname, entry->label);
+        DEBUGF("parsing %s failed (format: %s)\n", trackname, entry->label);
         return false;
     }
 
diff --git a/lib/rbcodec/metadata/rm.c b/lib/rbcodec/metadata/rm.c
index 2a5a289..1e33f0b 100644
--- a/lib/rbcodec/metadata/rm.c
+++ b/lib/rbcodec/metadata/rm.c
@@ -89,7 +89,7 @@
 }
 #endif
 
-static inline int real_read_audio_stream_info(int fd, RMContext *rmctx)
+static int real_read_audio_stream_info(int fd, RMContext *rmctx)
 {
     int skipped = 0;
     uint32_t version;
@@ -111,6 +111,7 @@
     DEBUGF("    version=0x%04lx\n",((version >> 16) & 0xff));
     if (((version >> 16) & 0xff) == 3) {
         /* Very old version */
+        return -1;
     } else {
 #ifdef SIMULATOR
        real_read_object_header(fd, &obj);
@@ -218,7 +219,7 @@
     return skipped;
 }
 
-static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3)
+static inline int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3)
 {
     struct real_object_t obj;
     int res;
@@ -242,6 +243,7 @@
     uint32_t max_bitrate;
     uint16_t num_streams;
     uint32_t next_data_off;
+    uint16_t pkt_version;
     uint8_t  header_end;
 
     memset(&obj,0,sizeof(obj));
@@ -250,6 +252,35 @@
 
     if (obj.fourcc == FOURCC('.','r','a',0xfd))
     {
+        lseek(fd, 4, SEEK_SET);
+        skipped = real_read_audio_stream_info(fd, rmctx);
+        if (skipped > 0 && rmctx->codec_type == CODEC_AC3)
+        {
+            read_uint8(fd,&len);
+            skipped += (int)read_string(fd, id3->id3v1buf[0], sizeof(id3->id3v1buf[0]), '\0', len);
+            read_uint8(fd,&len);
+            skipped += (int)read_string(fd, id3->id3v1buf[1], sizeof(id3->id3v1buf[1]), '\0', len);
+            read_uint8(fd,&len);
+            skipped += (int)read_string(fd, id3->id3v1buf[2], sizeof(id3->id3v1buf[2]), '\0', len);
+            read_uint8(fd,&len);
+            skipped += (int)read_string(fd, id3->id3v1buf[3], sizeof(id3->id3v1buf[3]), '\0', len);
+            rmctx->data_offset = skipped + 8;
+            rmctx->bit_rate = rmctx->block_align * rmctx->sample_rate / 192;
+            if (rmctx->block_align)
+                rmctx->nb_packets = (filesize(fd) - rmctx->data_offset) / rmctx->block_align;
+            if (rmctx->sample_rate)
+                rmctx->duration = (uint32_t)(256LL * 6 * 1000 * rmctx->nb_packets / rmctx->sample_rate);
+            rmctx->flags |= RM_RAW_DATASTREAM;
+
+            DEBUGF("    data_offset = %ld\n",rmctx->data_offset);
+            DEBUGF("    avg_bitrate = %ld\n",rmctx->bit_rate);
+            DEBUGF("    duration = %ld\n",rmctx->duration);
+            DEBUGF("    title=\"%s\"\n",id3->id3v1buf[0]);
+            DEBUGF("    author=\"%s\"\n",id3->id3v1buf[1]);
+            DEBUGF("    copyright=\"%s\"\n",id3->id3v1buf[2]);
+            DEBUGF("    comment=\"%s\"\n",id3->id3v1buf[3]);
+            return 0;
+        }
         /* Very old .ra format - not yet supported */
         return -1;
     } 
@@ -305,6 +336,8 @@
                 DEBUGF("    data_offset = %ld\n",rmctx->data_offset);
                 DEBUGF("    num_streams = %d\n",num_streams);
                 DEBUGF("    flags=0x%04x\n",rmctx->flags);
+
+                rmctx->flags &= 0x00FF;
                 break;
 
             case FOURCC('C','O','N','T'):
@@ -409,7 +442,22 @@
 
                 DEBUGF("    data_nb_packets = %ld\n",rmctx->nb_packets);
                 DEBUGF("    next DATA offset = %ld\n",next_data_off);
-                header_end = 1;         
+
+                if (!next_data_off)
+                {
+                    if (rmctx->duration == 0 && rmctx->bit_rate != 0)
+                    {
+                        rmctx->duration = (uint32_t)(8000LL * rmctx->nb_packets * rmctx->block_align / rmctx->bit_rate);
+                        DEBUGF("    estimated duration = %ld\n",rmctx->duration);
+                    }
+                    read_uint16be(fd, &pkt_version);
+                    skipped += 2;
+                    DEBUGF("    pkt_version=0x%04x\n", pkt_version);
+                    if (pkt_version)
+                        rmctx->flags |= RM_PKT_V1;
+                    rmctx->data_offset = curpos;
+                    header_end = 1;
+                }
                 break; 
         }
         if(header_end) break;
@@ -456,7 +504,7 @@
 
     id3->channels = rmctx->nb_channels;
     id3->extradata_size = rmctx->extradata_size;
-    id3->bitrate = rmctx->bit_rate / 1000;
+    id3->bitrate = (rmctx->bit_rate + 500) / 1000;
     id3->frequency = rmctx->sample_rate;
     id3->length = rmctx->duration;
     id3->filesize = filesize(fd);