使用带有 Android AudioTrack 的缓冲区

Posted

技术标签:

【中文标题】使用带有 Android AudioTrack 的缓冲区【英文标题】:Using a buffer with Android AudioTrack 【发布时间】:2013-12-11 05:22:27 【问题描述】:

我试图弄清楚如何使用带有AudioTrack 的缓冲区来有效地流式传输音乐。我知道您可以使用write 方法对音频进行排队,但是一旦音频排队,您如何判断剩余的数量与已使用/播放的数量?抱歉,如果这是一个基本问题。我了解缓冲区的概念,但不知道如何编写,尤其是使用 AudioTrack。

【问题讨论】:

您为什么想知道:“还剩多少与已使用/播放了多少”?? 通知用户应用正在缓冲并执行相关逻辑。 【参考方案1】:

AudioTrack.write() 以 int 形式返回“写入的字节数”,您在构造 AudioTrack 时指定缓冲区中的字节数。

因此,要跟踪剩余的缓冲区空间,您可以保留一个累加器变量,以便知道总共写入了多少字节,并在调用AudioTrack.flush() 时将此变量设置为零。但是,链接文档指出“通常使用总大小的 1/2 的块来允许双缓冲”,因此它可能很简单,只需记住自调用 flush 以来是否写过零、一次或两次.

要知道已经播放了多少缓冲区,请使用AudioTrack.getPlaybackHeadPosition(),它返回当前缓冲区已播放的帧数(即重置为停止、刷新或重新加载时为零)作为有符号 32 位整数,但被解释为无符号 32 位整数。这实际上意味着您将其分配给一个 int,如下所示。

int bufferPlaybackFrame = myAudioTrack.getPlaybackHeadPosition() & 0xFF;

您可以将帧视为等同于样本。即,您可以从用于构造 AudioTrack 的 AudioFormat 中计算出每个样本使用了多少位(以及因此字节)。

最后,如果有人想知道,您将永远无法知道有多少源文件或流要通过该对象播放(一个原因是它被设计为与永久 24/7 流一起使用,具有没有结束),所以如果你想像在某些视频播放网站上看到的那样进行计算,暂停流直到缓冲足够的 id 以当前下载速率查看整个视频,你必须在一些中传递该信息另一种方式。

【讨论】:

谢谢,非常有帮助的回答。 @Andrew 如果我想从服务器下载(一次)音频文件,然后文件应该离线播放。 ? @DevendraSingh 那么您将一起使用不同的类和方法(我没有直觉)。这是为了访问您无法真正下载和离线播放的持续、无休止的 24/7 流。 我认为帧不等同于样本。如果输出为单声道,则帧数等于样本数。如果是立体声,则样本数是帧数的两倍,因为每一帧将是左声道的一个样本,右声道的一个样本。【参考方案2】:

*此代码将有助于使用缓冲区播放音频*

  private void PlayShortAudioFileViaAudioTrack(String filePath) throws IOException
    

    // We keep temporarily filePath globally as we have only two sample sounds now..

    if (filePath==null)                                                                     
    return;

    //Reading the file..

    byte[] byteData = null; 
    File file = null; 
    file = new File(filePath); 

    // for ex. path= "/sdcard/samplesound.pcm" or "/sdcard/samplesound.wav"

    byteData = new byte[(int) file.length()];
    FileInputStream in = null;
     try 
    in = new FileInputStream( file );
     in.read( byteData );
     in.close(); 
     catch (FileNotFoundException e) 

    // TODO Auto-generated catch block
    e.printStackTrace();
    
    // Set and push to audio track..

    int intSize = android.media.AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
    AudioFormat.ENCODING_PCM_8BIT); 
    AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
    AudioFormat.ENCODING_PCM_8BIT, intSize, AudioTrack.MODE_STREAM); 
    if (at!=null)  
    at.play();

    // Write the byte array to the track

at.write(byteData, 0, byteData.length); 
    at.stop();
    at.release();
    
    else
     Log.d("TCAudio", "audio track is not initialised ");
     

【讨论】:

对不起,我应该更具体。我无法访问整个文件,因为我正在流式传输它,因此我无法在播放之前将整个文件加载到缓冲区中。

以上是关于使用带有 Android AudioTrack 的缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

Android音频系统AudioTrack使用方法详解

Android使用AudioTrack发送红外信号

Android使用AudioTrack播放WAV音频文件

Android音视频之AudioTrack播放音频

调节 Android AudioTrack 播放速度

Android 音频开发——AudioTrack播放