Search code examples
javascriptnode.jsstreammp3binary-data

Can't find mp3 frame header sync bits in node stream


I am almost at the end of my rope on this one. I am attempting to parse out mp3 frame data, but I am having a bear of a time locating any frames. I am using Node 0.10 and trying to make use of the newer stream api (although it doesn't work with the old one either)

I am looping through the buffer looking for the 11 bit sync word, but i never find it.

 var stream = fs.createReadStream('./myAudioFile.mp3')

 stream.on('readable', function(data){
    var chunk, header;

    while (null !== (chunk = stream.read())) {
        for (var i = 0; ( i + 4 ) <= chunk.length; i++) {
            header = chunk.readUInt32LE(i)

            if( (header & 0xFFE00000) === 0xFFE00000 ) {
              //NEVER GET HERE!!!
            }
        }
    }

Am i missing something here?


Solution

  • You're getting bitten by a quirk of Javascript bitwise operators. Let me demonstrate.

    > 0xffffffff & 0xffe00000
    -2097152
    > 0xffe00000
    4292870144
    

    The result of a Javascript bitwise operation is always treated as a signed 32-bit integer. Since your constant is an unsigned 32-bit integer, it'll never match.

    One potential fix is to use ~~ to perform the same mangling on your constant:

    if ((header & 0xffe00000) == ~~0xffe00000) {
    

    Another would be to just read in 16-bit integers instead, since the sync word will fit into that size anyway.

    Unrelated but worth mentioning:

    • You're actually going to need to use chunk.readUInt32BE(i) here, not LE. Right now you're finding instances of FE FF in the stream, not FF FE like you want.

    • In the rare instance that a sync word spans two chunks, your code misses it.