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

使用AudioTrack播放230MB/20分钟PCM16位WAV文件的技术咨询

Correct AudioTrack Implementation for Your Large WAV File

Great question! Let's break down how to play your WAV file correctly with AudioTrack—especially since it's a 230MB large file that needs careful memory handling to avoid crashes.

First, let's align your audio parameters with what AudioTrack expects (your ffmpeg output gives all the critical details):

  • Sample Rate: 44100 Hz (matches your file)
  • Channels: Stereo (use AudioFormat.CHANNEL_OUT_STEREO; note CHANNEL_CONFIGURATION_STEREO is deprecated since API 16, so we'll add a backward-compatible check)
  • Encoding: 16-bit PCM (AudioFormat.ENCODING_PCM_16BIT, which matches your pcm_s16le format)
  • Bitrate: 1411 kb/s (this is automatically calculated from the above parameters, so no extra config needed)

Since your file is far too large to load entirely into memory, we'll use STREAM mode for AudioTrack. This lets us read chunks of the file and play them incrementally, avoiding OutOfMemoryErrors.

Step-by-Step Implementation

1. Add Required Permissions

If your WAV file is stored in external storage, add this to your AndroidManifest.xml (and request runtime permission if targeting API 23+):

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

2. Full Robust Code Example

Here's a complete implementation with stream-based playback, error handling, and proper resource cleanup:

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Build;
import java.io.FileInputStream;
import java.io.IOException;

public class WavStreamPlayer {
    private AudioTrack audioTrack;
    private Thread playbackThread;
    private boolean isPlaying = false;
    // Match your WAV file's parameters
    private static final int SAMPLE_RATE = 44100;
    private static final int CHANNEL_CONFIG = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
            ? AudioFormat.CHANNEL_OUT_STEREO
            : AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    private static final int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;

    public void startPlayback(String wavFilePath) {
        // Calculate the minimum buffer size required for stream mode
        int minBufferSize = AudioTrack.getMinBufferSize(
                SAMPLE_RATE,
                CHANNEL_CONFIG,
                AUDIO_ENCODING
        );

        // Validate buffer size calculation
        if (minBufferSize == AudioTrack.ERROR_BAD_VALUE || minBufferSize == AudioTrack.ERROR) {
            throw new RuntimeException("Failed to calculate valid buffer size");
        }

        // Initialize AudioTrack with a buffer larger than the minimum for smoother playback
        audioTrack = new AudioTrack(
                AudioManager.STREAM_MUSIC,
                SAMPLE_RATE,
                CHANNEL_CONFIG,
                AUDIO_ENCODING,
                minBufferSize * 2, // Double the min buffer for better stability
                AudioTrack.MODE_STREAM
        );

        if (audioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
            throw new RuntimeException("Failed to initialize AudioTrack");
        }

        isPlaying = true;
        playbackThread = new Thread(() -> {
            FileInputStream fileInputStream = null;
            try {
                fileInputStream = new FileInputStream(wavFilePath);
                byte[] playbackBuffer = new byte[minBufferSize * 2];
                int bytesRead;

                // Start playback
                audioTrack.play();

                // Read and write chunks until end of file or playback is stopped
                while (isPlaying && (bytesRead = fileInputStream.read(playbackBuffer)) != -1) {
                    int bytesWritten = audioTrack.write(playbackBuffer, 0, bytesRead);
                    if (bytesWritten == AudioTrack.ERROR_INVALID_OPERATION || bytesWritten == AudioTrack.ERROR_BAD_VALUE) {
                        throw new RuntimeException("Failed to write audio data to AudioTrack");
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                // Clean up resources regardless of success/failure
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                stopPlayback();
            }
        });

        playbackThread.start();
    }

    public void stopPlayback() {
        isPlaying = false;
        if (audioTrack != null) {
            if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
                audioTrack.stop();
            }
            audioTrack.release();
            audioTrack = null;
        }
        if (playbackThread != null) {
            try {
                playbackThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            playbackThread = null;
        }
    }
}

Key Details to Note:

  • Buffer Size: We use AudioTrack.getMinBufferSize() to get the minimum required buffer, then double it for smoother playback (adjust this multiplier based on your device's performance if needed).
  • Deprecated Constants: We handle older Android versions (pre-API 16) with a version check to avoid using deprecated channel configs.
  • Threading: Playback runs on a background thread to avoid blocking the main UI thread (critical for app responsiveness).
  • Resource Cleanup: Always release() the AudioTrack and close the file stream when playback ends or is stopped to prevent memory leaks.
  • Error Handling: Added checks for initialization failures and write errors to make the implementation robust.

Usage Example

Call this from your Activity/Fragment (don't forget to request runtime storage permissions first if your file is in external storage):

WavStreamPlayer player = new WavStreamPlayer();
player.startPlayback("/storage/emulated/0/your_folder/1.wav");

// To stop playback later (e.g., in onPause() or a button click):
// player.stopPlayback();

Why Avoid STATIC Mode?

STATIC mode loads the entire audio file into memory before playing. For your 230MB file, this would consume massive amounts of RAM and almost certainly trigger an OutOfMemoryError—so STREAM mode is the only practical choice here.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:54:12