static parseFrame(data, offset) {
    if (offset + 8 > data.length) {
      // not enough bytes left
      return null;
    }

    if (data[offset] !== 0x0b || data[offset + 1] !== 0x77) {
      // invalid magic
      return null;
    }

    // get sample rate
    const samplingRateCode = data[offset + 4] >> 6;
    if (samplingRateCode >= 3) {
      // invalid sampling rate
      return null;
    }

    const samplingRateMap = [48000, 44100, 32000];

    // get frame size
    const frameSizeCode = data[offset + 4] & 0x3f;
    const frameSizeMap = [
      64, 69, 96, 64, 70, 96, 80, 87, 120, 80, 88, 120, 96, 104, 144, 96, 105,
      144, 112, 121, 168, 112, 122, 168, 128, 139, 192, 128, 140, 192, 160,
      174, 240, 160, 175, 240, 192, 208, 288, 192, 209, 288, 224, 243, 336,
      224, 244, 336, 256, 278, 384, 256, 279, 384, 320, 348, 480, 320, 349,
      480, 384, 417, 576, 384, 418, 576, 448, 487, 672, 448, 488, 672, 512,
      557, 768, 512, 558, 768, 640, 696, 960, 640, 697, 960, 768, 835, 1152,
      768, 836, 1152, 896, 975, 1344, 896, 976, 1344, 1024, 1114, 1536, 1024,
      1115, 1536, 1152, 1253, 1728, 1152, 1254, 1728, 1280, 1393, 1920, 1280,
      1394, 1920,
    ];

    const frameLength = frameSizeMap[frameSizeCode * 3 + samplingRateCode] * 2;
    if (offset + frameLength > data.length) {
      return null;
    }

    // get channel count
    const channelMode = data[offset + 6] >> 5;
    let skipCount = 0;
    if (channelMode === 2) {
      skipCount += 2;
    } else {
      if ((channelMode & 1) && channelMode !== 1) {
        skipCount += 2;
      }
      if (channelMode & 4) {
        skipCount += 2;
      }
    }

    const lowFrequencyEffectsChannelOn =
      (((data[offset + 6] << 8) | data[offset + 7]) >> (12 - skipCount)) & 1;

    const channelsMap = [2, 1, 2, 3, 3, 4, 4, 5];

    // Audio config for DAC3 box
    const bitStreamIdentification = data[offset + 5] >> 3;
    const bitStreamMode = data[offset + 5] & 7;

    const config = new Uint8Array([
      (samplingRateCode << 6) |
          (bitStreamIdentification << 1) |
          (bitStreamMode >> 2),
      ((bitStreamMode & 3) << 6) |
          (channelMode << 3) |
          (lowFrequencyEffectsChannelOn << 2) |
          (frameSizeCode >> 4),
      (frameSizeCode << 4) & 0xe0,
    ]);

    return {
      sampleRate: samplingRateMap[samplingRateCode],
      channelCount: channelsMap[channelMode] + lowFrequencyEffectsChannelOn,
      audioConfig: config,
      frameLength: frameLength,
    };
  }
@param {!Uint8Array} data
@param {!number} offset
@return {?{sampleRate: number, channelCount: number,
         audioConfig: !Uint8Array, frameLength: number}}