You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android音频播放器开发:读取WAV/MP3字节流并播放(禁用MediaPlayer类)

Alright, let's tackle this problem head-on—building an Android audio player from scratch that reads WAV/MP3 files as bytes and plays them without relying on MediaPlayer or other high-level ready-made classes. This is going to involve getting your hands dirty with raw audio data, format decoding, and low-level audio output. Here's a step-by-step breakdown:

Core Overview

You'll need to nail three critical steps:

  1. Read audio files as byte streams
  2. Decode WAV/MP3 byte data into raw PCM audio samples (the only format Android's audio hardware can understand natively)
  3. Feed those PCM samples to Android's low-level audio output system

Step 1: Read Audio Files as Bytes

This is straightforward—use standard Java/Android I/O classes to pull bytes from the file. If you're accessing files from the system media library, use ContentResolver instead of FileInputStream, but the core logic stays similar.

Example code for local file reading:

// Replace with your file path
File audioFile = new File(getFilesDir(), "my_audio.wav");
FileInputStream fis = null;
try {
    fis = new FileInputStream(audioFile);
    byte[] readBuffer = new byte[4096]; // 4KB buffer—adjust based on your needs
    int bytesRead;
    
    while ((bytesRead = fis.read(readBuffer)) != -1) {
        // Pass the read byte chunk to your decoding logic
        processAudioChunk(readBuffer, bytesRead);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Step 2: Decode Audio Formats to PCM

This is the most complex part—each format has unique decoding rules:

2.1 WAV Format Decoding

WAV is uncompressed, so decoding is mostly about parsing the file header to get critical audio parameters, then extracting the raw PCM data directly.

The WAV file structure has three key parts:

  • RIFF Header: Identifies the file as WAV
  • fmt Subchunk: Contains audio specs (sample rate, bit depth, channel count)
  • data Subchunk: Holds the raw PCM samples

Key code snippet to parse the WAV header:

// Simplified header parsing (you'll need to handle all header fields properly)
byte[] riffMarker = new byte[4];
fis.read(riffMarker);
if (!new String(riffMarker).equals("RIFF")) {
    throw new IllegalArgumentException("Not a valid WAV file");
}

// Skip over file size and format type fields, then locate the fmt subchunk
// ... (omitted: code to navigate to the fmt subchunk) ...

// Extract critical parameters (use little-endian byte order for WAV)
byte[] sampleRateBytes = new byte[4];
fis.read(sampleRateBytes);
int sampleRate = ByteBuffer.wrap(sampleRateBytes).order(ByteOrder.LITTLE_ENDIAN).getInt();

byte[] bitsPerSampleBytes = new byte[2];
fis.read(bitsPerSampleBytes);
int bitsPerSample = ByteBuffer.wrap(bitsPerSampleBytes).order(ByteOrder.LITTLE_ENDIAN).getShort();

byte[] channelBytes = new byte[2];
fis.read(channelBytes);
int channels = ByteBuffer.wrap(channelBytes).order(ByteOrder.LITTLE_ENDIAN).getShort();

// After parsing the header, all subsequent bytes are raw PCM data
// Pass this PCM data directly to your audio output logic

2.2 MP3 Format Decoding

MP3 is a compressed format—you can't parse a header and grab raw samples directly. Your best bet is to use a lightweight open-source decoder like minimp3 (it's tiny, dependency-free, and easy to integrate by copying its source files into your project).

Example usage with minimp3 (pseudo-code):

// Initialize the decoder
Minimp3Decoder decoder = new Minimp3Decoder();
Mp3Frame frame = new Mp3Frame();

// Process each byte chunk read from the file
while (decoder.decode(readBuffer, bytesRead, frame)) {
    // frame.pcm is a short array of decoded PCM samples
    // frame.sampleRate and frame.channels give you the audio specs
    playPcmSamples(frame.pcm, frame.sampleRate, frame.channels);
}

Step 3: Output PCM to Audio Hardware

Android's AudioTrack class is your go-to here—it's a low-level API for playing raw PCM data, and it doesn't count as a "ready-made player class" like MediaPlayer.

First, initialize AudioTrack using the parameters from your decoder:

int audioEncoding;
if (bitsPerSample == 16) {
    audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
} else if (bitsPerSample == 8) {
    audioEncoding = AudioFormat.ENCODING_PCM_8BIT;
} else {
    throw new UnsupportedOperationException("Unsupported bit depth");
}

int channelConfig = channels == 2 ? AudioFormat.CHANNEL_OUT_STEREO : AudioFormat.CHANNEL_OUT_MONO;
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioEncoding);

// Initialize AudioTrack in stream mode (good for continuous playback)
AudioTrack audioTrack = new AudioTrack(
    AudioManager.STREAM_MUSIC,
    sampleRate,
    channelConfig,
    audioEncoding,
    minBufferSize * 2, // Double the min buffer to avoid underruns
    AudioTrack.MODE_STREAM
);

// Start playback
audioTrack.play();

Then write your decoded PCM samples to AudioTrack:

// Convert short array (16-bit PCM) to byte array
byte[] pcmBytes = new byte[pcmSamples.length * 2];
ByteBuffer.wrap(pcmBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(pcmSamples);

// Write the bytes to AudioTrack
audioTrack.write(pcmBytes, 0, pcmBytes.length);

Critical Things to Keep in Mind

  • Threading: Never run decoding or playback on the UI thread—use a dedicated background thread or Coroutine to avoid ANRs.
  • Buffer Management: Adjust your read/decode buffer sizes based on device performance to balance memory usage and playback smoothness.
  • Resource Cleanup: Always release AudioTrack, input streams, and decoder resources when playback ends to avoid memory leaks.
  • Error Handling: Add checks for unsupported formats, corrupted files, and audio hardware errors to make your player robust.

内容的提问来源于stack exchange,提问作者Majd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:06:31