【问题标题】:Using AudioTrack to play PCm data使用 AudioTrack 播放 PCm 数据
【发布时间】:2020-01-10 00:24:32
【问题描述】:

我得到一个解码的 PCm 字节 [] 流。然后我启动 AudioTrack 对象,在 while 循环内(直到流有数据为止),我读取该数据并通过 write() 函数将其发送到 AudioTrack。问题是,我播放了部分音乐,然后播放了几秒钟,然后你能听到的只有噪音,而且是连续的。我确实尝试增加缓冲区大小,但没有任何帮助。而且我时不时会收到这个错误:

12-30 17:57:44.012 D/dalvikvm( 9195): GC_CONCURRENT freed 438K, 15% free 10178K/11847K, paused 14ms+3ms, total 49ms

这是我的代码:

public void Read()
{
    System.Threading.Tasks.Task.Run(() =>
    {
        int _bufferSize;
        AudioTrack _output;

        _bufferSize = AudioTrack.GetMinBufferSize(44100, ChannelOut.Stereo, Android.Media.Encoding.Pcm16bit);
        _output = new AudioTrack(Android.Media.Stream.Music, 44100, ChannelOut.Stereo, Android.Media.Encoding.Pcm16bit,

       _bufferSize, AudioTrackMode.Stream);
       _output.Play();

       byte[] myReadBuffer = new byte[8000];

       while (mmInStream.CanRead)
       {
           try
           {
               mmInStream.Read(myReadBuffer, 0, myReadBuffer.Length);
               _output.Write(myReadBuffer, 0, myReadBuffer.Length);
           }
           catch (System.IO.IOException ex)
           {
               System.Diagnostics.Debug.WriteLine("Input stream was disconnected", ex);
           }
       }
       _output.Stop();
   }).ConfigureAwait(false);
}

我将如何修复此代码以便它可以在没有中断的情况下播放?


请注意,我将编辑问题。 实际上,我已经想通了,我现在从 AudioTrack 中得到一个恒定的声音,现在的问题是,我有时会出现短暂的口吃,而不是连续播放。然而,口吃会导致延迟,从而导致设备无法与其他设备同步播放音乐。这是我更新的代码:

    public void Read()
    {
        System.Threading.Tasks.Task.Run(() =>
        {
            int _bufferSize;
            AudioTrack _output;

            _output = new AudioTrack(Android.Media.Stream.Music, 44100, ChannelOut.Stereo, Android.Media.Encoding.Pcm16bit,
                10000, AudioTrackMode.Stream);
            _output.Play();

            byte[] myReadBuffer = new byte[1000];

            System.Threading.Tasks.Task.Run(() =>
            {
                while (true)
                {
                    try
                    {
                        mmInStream.Read(myReadBuffer, 0, myReadBuffer.Length);
                        _output.Write(myReadBuffer, 0, myReadBuffer.Length);
                    }
                    catch (System.IO.IOException ex)
                    {
                        System.Diagnostics.Debug.WriteLine("Input stream was disconnected", ex);
                    }
                }
            }).ConfigureAwait(false);
        }).ConfigureAwait(false);
    }

【问题讨论】:

  • 可以用原始的 PCm byte[] 代替解码的 PCm byte[] 进行测试吗?这有同样的问题吗?
  • Couses 同样的问题,但播放的歌曲更少。
  • @WendyZang-MSFT 实际上,如果我使用我的手机三星 Galaxy A5 2016 应用程序运行良好,但在我的测试手机三星 S4 mini(非常旧)上手机运行不佳。
  • 可能是版本问题,建议使用最新的。

标签: c# android xamarin


【解决方案1】:

您的代码中发生了缓冲区溢出。

根据缓冲区大小和采样率定期提交缓冲区。

在你的 while 循环中引入一些 Sleep

   /* First Buffer */
   if(mmInStream.CanRead)
   {
       try
       {
           mmInStream.Read(myReadBuffer, 0, myReadBuffer.Length);            
           _output.Write(myReadBuffer, 0, myReadBuffer.Length);
       }
       catch (System.IO.IOException ex)
       {
           System.Diagnostics.Debug.WriteLine("Input stream was disconnected", ex);
       }

   }

  while (mmInStream.CanRead)
   {
       try
       {
           mmInStream.Read(myReadBuffer, 0, myReadBuffer.Length);

           Sleep(x) --- calculate the x millisecond/second based on the buffer size & sampling frequency.

           _output.Write(myReadBuffer, 0, myReadBuffer.Length);
       }
       catch (System.IO.IOException ex)
       {
           System.Diagnostics.Debug.WriteLine("Input stream was disconnected", ex);
       }

   }

要获得正确的音频质量播放,请检查支持的缓冲区并将缓冲区提交给AudioTrack

查看更多关于 AudioTrack 用法的示例。

【讨论】:

  • 其实还有一个问题,我现在遇到了,看更新的问题。
  • 更新了我的回复,确保提交缓冲区的线程安排在适当的时间间隔。
  • 既然 mmInStread 会阻塞直到读取,_output 也会阻塞,所以问题不在于它读取速度不够快吗?
  • 您正在从静态文件中读取,因此您可以读取并保持数据准备就绪,然后进入睡眠状态。醒来后,您可以提交缓冲区。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-29
  • 2019-05-26
  • 2011-08-18
  • 2021-10-07
相关资源
最近更新 更多