Android AudioTrack 播放 .wav 文件,只得到白噪声

Posted

技术标签:

【中文标题】Android AudioTrack 播放 .wav 文件,只得到白噪声【英文标题】:Android AudioTrack playing .wav file, getting only white noise 【发布时间】:2011-11-14 10:15:54 【问题描述】:

当我使用以下代码播放文件时:

private void PlayAudioFileViaAudioTrack(int ResId) throws IOException 

    int intSize = android.media.AudioTrack.getMinBufferSize(11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);

    AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, intSize,
            AudioTrack.MODE_STREAM);

    int count = 256 * 1024; // 256 kb
    byte[] byteData = null;
    byteData = new byte[(int) count];
    InputStream in = null;
    AssetFileDescriptor fd = null;
    fd = mResources.openRawResourceFd(ResId);
    in = mResources.openRawResource(ResId);

    int bytesRead = 0, amount = 0;
    int size = (int) fd.getLength();
    at.play();
    while (bytesRead < size) 
        amount = in.read(byteData, 0, count);
        if (amount != -1) 
            at.write(byteData, 0, amount);
        
    
    in.close();
    at.stop();
    at.release();


我唯一听到的是静态的白噪声。我检查了我的 .wav 文件是否具有相同的属性(采样率、比特率)。我没有太多关于原始音频数据 (PCM) 的知识,所以我想知道是否有人能看出我的代码有什么问题。

【问题讨论】:

【参考方案1】:

这看起来比我做的要复杂得多。我用这个播放声音。我认为 .wav 文件也可以。

MediaPlayer mpPlayProgram = new MediaPlayer();
mpPlayProgram.setDataSource("/sdcard/file.mp3");
mpPlayProgram.prepare();
mpPlayProgram.start();
mpPlayProgram.release();

对于静态资源,就更简单了:

MediaPlayer mpStart = MediaPlayer.create(this, resID);
mpStart.start();
mpStart.release();

【讨论】:

我没有使用 MediaPlayer 类,因为它的级别非常高。我正在使用 AudioTrack,这对我正在做的事情来说更好。【参考方案2】:

从您的代码中,我可以看到您只是从 wav 文件中读取数据并将它们导入到 AudioTrack。 Wav 文件有一个小标题,您可以在此处看到 https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ 所以您必须跳过标题并将文件描述符指向实际音频数据所在的正确位置。

此外,当您播放音频文件并处理字节操作时,您应该注意字节序。看这里Using AudioTrack in Android to play a WAV file

在我的代码下方(缺少一些检查和 WAV 标头跳过),它适用于 Nexus One 和 Galaxy S,带有频率为 8000Hz 和 16 位编码的 wav 文件。

public void playWav()
    int minBufferSize = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
    int bufferSize = 512;
    AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
    String filepath = Environment.getExternalStorageDirectory().getAbsolutePath();

    int i = 0;
    byte[] s = new byte[bufferSize];
    try 
        FileInputStream fin = new FileInputStream(filepath + "/REFERENCE.wav");
        DataInputStream dis = new DataInputStream(fin);

        at.play();
        while((i = dis.read(s, 0, bufferSize)) > -1)
            at.write(s, 0, i);

        
        at.stop();
        at.release();
        dis.close();
        fin.close();

     catch (FileNotFoundException e) 
        // TODO
        e.printStackTrace();
     catch (IOException e) 
        // TODO
        e.printStackTrace();
           

【讨论】:

标题只够播放几毫秒的声音,之后应该可以正常播放。你能向我解释一下你所说的“照顾好Endianess”是什么意思吗? 哦,对不起我关于 Endianess 的错误。我以为您正在以短裤的形式读取数据,但您正在以字节的形式读取数据,因此字节序在这里不是问题。为了确保我编写了一个小程序(我可以提供源代码),它读取 .wav 文件并将其写入 AudioTrack。它在我的手机上正常播放 wav 文件。也许您在 AudioTrack 的构造函数中的配置参数可能是错误的。您是否检查过您的 wav 文件的属性?也许它有不同的采样频率或编码。 嗯,很奇怪......我在第一次回答时添加了我的代码。如您所见,我处理 AudioTrack 的方式是相同的。唯一的区别是文件的打开和读取。向 logcat 添加一些调试消息,以查看这些操作是否出现问题。 我建议再做两个实验:1) 尝试将缓冲区归零并写入 - 在这种情况下必须没有白噪声; 2)尝试反转shorts(即强制endian转换) @Manos:不错的代码。是否可以将 byte[] s 更改为 short[] s?因为我想从该数据中计算 RMS,但它仅适用于 short[] 类型。谢谢【参考方案3】:

如果您保存了 wav 格式的文件并想使用 AudioTrack 播放它,请按照以下代码操作:

             File file=new File(Environment.getExternalStorageDirectory()+"/AudioRecorder/fahim.wav");

               InputStream is;
             DataInputStream         dis = null ;
             BufferedInputStream     bis;

            try 
            
                is = new FileInputStream(file);
                bis = new BufferedInputStream(is, 8000);
                dis  = new DataInputStream(bis);      //  Create a DataInputStream to read the audio data from the saved file

            
            catch (FileNotFoundException e1) 
            
                ShowToast("fILE NOT FOUND:"+e1.getMessage());
            

            int i = 0;                                                          //  Read the file into the "music" array
            music=new byte[(int) file.length()];
            try 
            
                while (dis.available() > 0)
                
                    music[i] = dis.readByte();                                      //  This assignment does not reverse the order
                    i++;
                
             
            catch (IOException e) 
            
                ShowToast("I/O Exception:"+e.getMessage());
            

            try dis.close(); catch (IOException e) e.printStackTrace();

            int minBufferSize = AudioTrack.getMinBufferSize(11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);

            AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM);
            at.play();

            ShowToast("size:"+music.length);
            //*/
            at.write(music, 0, music.length);

【讨论】:

以上是关于Android AudioTrack 播放 .wav 文件,只得到白噪声的主要内容,如果未能解决你的问题,请参考以下文章

Android使用AudioTrack播放WAV音频文件

Android 音频开发——AudioTrack播放

Android AudioTrack 播放 .wav 文件,只得到白噪声

如何在 android 上播放 webrtc.AudioTrack(无视频)

Android 音频播放——AudioTrack直接播PCMMediaPlayer播媒体文件可以是audio

如何播放来自服务器的流式 PCM 数据,如 Android AudioTrack 类?