You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android Wear音频保存至外部存储后无法播放问题求助

问题分析与解决方案

首先,你遇到的核心问题是导出的PCM文件无法被播放器识别,这是因为PCM是原始音频数据,没有包含音频格式信息的文件头(比如WAV的RIFF头),绝大多数音频播放器无法直接解析裸PCM数据。另外你的代码里还有几处细节bug需要修正,下面逐一说明:

1. 裸PCM无法被播放器识别的解决办法

你录制的是原始PCM音频,要让播放器能打开,需要给它加上标准音频格式的文件头,转换成WAV格式是最直接的方案。这里提供一个给PCM添加WAV头的工具方法:

private void convertPcmToWav(File pcmFile, File wavFile, int sampleRate, int channels, int bitDepth) throws IOException {
    long totalAudioLen = pcmFile.length();
    long totalDataLen = totalAudioLen + 36;
    long byteRate = sampleRate * channels * bitDepth / 8;

    byte[] header = new byte[44];
    // RIFF/WAV 头部标识
    header[0] = 'R';
    header[1] = 'I';
    header[2] = 'F';
    header[3] = 'F';
    header[4] = (byte) (totalDataLen & 0xff);
    header[5] = (byte) ((totalDataLen >> 8) & 0xff);
    header[6] = (byte) ((totalDataLen >> 16) & 0xff);
    header[7] = (byte) ((totalDataLen >> 24) & 0xff);
    // WAVE 标识
    header[8] = 'W';
    header[9] = 'A';
    header[10] = 'V';
    header[11] = 'E';
    // fmt 块标识
    header[12] = 'f';
    header[13] = 'm';
    header[14] = 't';
    header[15] = ' ';
    // fmt 块大小(PCM格式固定为16)
    header[16] = 16;
    header[17] = 0;
    header[18] = 0;
    header[19] = 0;
    // 格式类型(PCM为1)
    header[20] = 1;
    header[21] = 0;
    // 声道数
    header[22] = (byte) channels;
    header[23] = 0;
    // 采样率
    header[24] = (byte) (sampleRate & 0xff);
    header[25] = (byte) ((sampleRate >> 8) & 0xff);
    header[26] = (byte) ((sampleRate >> 16) & 0xff);
    header[27] = (byte) ((sampleRate >> 24) & 0xff);
    // 字节率
    header[28] = (byte) (byteRate & 0xff);
    header[29] = (byte) ((byteRate >> 8) & 0xff);
    header[30] = (byte) ((byteRate >> 16) & 0xff);
    header[31] = (byte) ((byteRate >> 24) & 0xff);
    // 块对齐
    header[32] = (byte) (channels * bitDepth / 8);
    header[33] = 0;
    // 位深度
    header[34] = (byte) bitDepth;
    header[35] = 0;
    // data 块标识
    header[36] = 'd';
    header[37] = 'a';
    header[38] = 't';
    header[39] = 'a';
    // 音频数据长度
    header[40] = (byte) (totalAudioLen & 0xff);
    header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
    header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
    header[43] = (byte) ((totalAudioLen >> 24) & 0xff);

    FileInputStream in = new FileInputStream(pcmFile);
    FileOutputStream out = new FileOutputStream(wavFile);
    out.write(header, 0, 44);
    byte[] buffer = new byte[1024];
    int len;
    while ((len = in.read(buffer)) != -1) {
        out.write(buffer, 0, len);
    }
    in.close();
    out.close();
}

使用时,在复制PCM文件完成后,调用这个方法转换成WAV:

// 示例:替换成你的实际文件对象和录制参数
File inputPcm = new File(getFilesDir(), mOutputFileName);
File outputWav = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC), "recorded.wav");
// RECORDING_RATE、CHANNEL_IN、FORMAT要和你录制时的参数一致
convertPcmToWav(inputPcm, outputWav, RECORDING_RATE, 
                CHANNEL_IN == AudioFormat.CHANNEL_IN_MONO ? 1 : 2, 
                FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 16 : 8);

2. 代码中的其他bug修复

(1)缺失文件复制核心逻辑

你的copyImageToMemory方法里调用了copy(bis, os),但这个方法没有实现,导致文件根本没复制成功。补充实现:

private void copy(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[1024];
    int len;
    while ((len = in.read(buffer)) != -1) {
        out.write(buffer, 0, len);
    }
    // 记得关闭流释放资源
    in.close();
    out.close();
}

(2)文件名变量未正确获取

onCreate方法里,你给EditText设置了默认文本,但没有获取fileName的值,导致后续操作可能用了空值或错误文件名:

EditText name=(EditText)findViewById(R.id.file_name_input);
name.setText("a.pcm");
// 加上这行获取输入的文件名
String fileName = name.getText().toString().trim();

(3)复制方法中的变量错误

copyImageToMemory里的openFileInput(test.getName())是错误的,应该使用你要复制的目标文件名fileName

// 原错误代码:BufferedInputStream(openFileInput(test.getName()));
// 修正为:
in = getApplicationContext().openFileInput(fileName);
bis = new BufferedInputStream(in);

3. 验证步骤

  1. 修复上述代码后,重启手表录制音频
  2. 导出文件时自动转换成WAV格式
  3. 用文件管理器找到导出的WAV文件,尝试用播放器打开,应该就能正常播放了

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

火山引擎 最新活动