Skip to content

Latest commit

 

History

History
139 lines (106 loc) · 5.1 KB

File metadata and controls

139 lines (106 loc) · 5.1 KB

MP3 Parser - Agent Context

Project Purpose

An API service that analyzes MP3 files and returns the number of audio frames. Specifically designed for MPEG Version 1 Audio Layer 3 files. Built using Bun's native Bun.serve() API without external HTTP frameworks.

API Specification

POST /file-upload

Accepts multipart/form-data with an MP3 file and returns the frame count.

Request:

  • Content-Type: multipart/form-data
  • Body: form field file containing the MP3 file

Response:

  • Success (200): { "frameCount": <number> }
  • Error (400/415/500): { "error": "<message>" }

Architecture

src/
├── index.ts                    # Root barrel export
├── http/                       # HTTP infrastructure layer
│   ├── index.ts               # Barrel export
│   ├── server.ts              # HTTPServer class with Bun.serve()
│   ├── routes.ts              # Route definitions
│   ├── types.ts               # HTTP types (RouteHandler, HttpMethod, etc.)
│   └── helpers.ts             # HTTP utilities (jsonResponse)
├── parser/                     # MP3 parsing domain
│   ├── index.ts               # Barrel export
│   ├── mp3-parser.ts          # MP3Parser class for frame parsing
│   ├── constants.ts           # MPEG1 Layer 3 tables and bit masks
│   ├── types.ts               # Parser types (FrameHeader)
│   └── errors.ts              # Custom error classes
└── controllers/                # Request handlers
    ├── index.ts               # Barrel export
    └── file-upload.controller.ts

tests/
├── mp3-parser.test.ts         # Unit tests for MP3Parser
└── server.test.ts             # Integration tests for API

Core Classes

MP3Parser

  • Constructor accepts Uint8Array of file data
  • Static fromArrayBuffer(buffer) factory method
  • Static fromStream(stream) async factory method (uses for await on ReadableStream)
  • countFrames() returns number (the count of audio frames)

HTTPServer

  • Constructor accepts optional port (default: 3000)
  • route(method, path, handler) registers a route (chainable)
  • get(path, handler) shorthand for GET routes (chainable)
  • post(path, handler) shorthand for POST routes (chainable)
  • put(path, handler) shorthand for PUT routes (chainable)
  • patch(path, handler) shorthand for PATCH routes (chainable)
  • delete(path, handler) shorthand for DELETE routes (chainable)
  • start() builds routes and starts the HTTP server
  • stop() stops the server
  • getPort() returns current port
  • Routes use AdonisJS-style registration via chained method calls

Route Registration

Routes are registered using AdonisJS-style chainable methods in src/http/routes.ts:

export function registerRoutes(server: HTTPServer): void {
  server.post("/file-upload", handleFileUpload);
}

Multiple methods can be chained on the same path without overwriting:

server
  .get("/health", handleHealthCheck)
  .post("/file-upload", handleFileUpload)
  .delete("/file-upload", handleFileDelete);

MP3 Parsing Approach

  1. Skip ID3v2 tags at file start (syncsafe integer size calculation)
  2. Find frame sync patterns (0xFF followed by 0xE_ where top 3 bits set)
  3. Validate MPEG Version 1 Layer 3 headers
  4. Skip Xing/Info VBR metadata frames (contain no audio data)
  5. Calculate frame size: floor(144 * bitrate / sampleRate) + padding
  6. Count valid audio frames until end of file

Xing/Info Frame Detection

VBR files contain a metadata frame at the start with a "Xing" or "Info" identifier. This frame:

  • Has a valid MP3 frame header but contains no audio
  • Located at offset = FRAME_HEADER_SIZE (4) + side_info_size (32 for stereo, 17 for mono)
  • Must be skipped to get accurate audio frame count

Constants

All magic numbers are defined in src/parser/constants.ts:

  • Lookup Tables: MPEG1_LAYER3_BITRATES, MPEG1_SAMPLE_RATES
  • Identifiers: ID3V2_IDENTIFIER, XING_IDENTIFIER, INFO_IDENTIFIER
  • Frame Sync: FRAME_SYNC_BYTE1 (0xFF), FRAME_SYNC_MASK (0xE0)
  • Version/Layer: MPEG_VERSION_1 (0b11), LAYER_3 (0b01)
  • Bit Masks: TWO_BIT_MASK, ONE_BIT_MASK, FOUR_BIT_MASK, SYNCSAFE_BYTE_MASK
  • Sizes: FRAME_HEADER_SIZE (4), ID3V2_HEADER_SIZE (10), SIDE_INFO_SIZE_STEREO (32), SIDE_INFO_SIZE_MONO (17)
  • Invalid Indices: INVALID_BITRATE_INDEX_FREE, INVALID_BITRATE_INDEX_RESERVED, INVALID_SAMPLE_RATE_INDEX
  • Channel Mode: CHANNEL_MODE_MONO (3)

Key Technical Details

  • Frame sync: first 11 bits all 1s (0xFF 0xE0 mask)
  • MPEG1 version bits: 11 (positions 19-20)
  • Layer 3 bits: 01 (positions 17-18)
  • Bitrates: 32-320 kbps (indices 1-14)
  • Sample rates: 44100, 48000, 32000 Hz

References

Running

bun run dev      # Development with hot reload
bun run start    # Production
bun test         # Run tests

Environment

  • PORT: Server port (default: 3000)