首页 > 解决方案 > 在 Android 中播放内存流中的 WAV 音频

问题描述

我将从 REST 服务接收非常短的音频数据。它们将以 WAV 格式到达。然后我需要在 Android 设备上播放它们。我想在不将数据保存到文件的情况下做到这一点——它只会让它变得比需要的更复杂。但是我不能让它从内存流中工作。下面是我正在使用的测试代码(使用资产文件夹中的 .wav 文件):

public void PlayAudioFile(string fileName)
    {
        bool useMemoryStream = true;

        if (useMemoryStream)
        {
            //this doesn't work
            MemoryStream ms = GetMS(fileName);
            byte[] msData = new byte[ms.Length];
            ms.Position = 0;
            ms.Read(msData, 0, (int)ms.Length);
            String base64EncodedString = Base64.EncodeToString(msData, Base64Flags.Default);

            String url = "data:audio/wav;base64," + base64EncodedString;
            MediaPlayer player = new MediaPlayer();

            player.Prepared += (s, e) =>
            {
                player.Start();
            };

            player.SetDataSource(url);
            player.Prepare();
        }
        else
        {
            //this works
            MediaPlayer player = new MediaPlayer();

            var fd = global::Android.App.Application.Context.Assets.OpenFd(fileName);
            player.Prepared += (s, e) =>
            {
                player.Start();
            };

            player.SetDataSource(fd.FileDescriptor, fd.StartOffset, fd.Length);
            player.Prepare();
        }
    }

    private MemoryStream GetMS(string fileName)
    {
        MemoryStream ms = new MemoryStream();

        Context context = Android.App.Application.Context;

        using (System.IO.Stream stream = context.Assets.Open(fileName))
        {
            stream.CopyTo(ms);
        }

        return ms;
    }

当我从文件中播放它时它很好,但是内存流方法给了我一个 IOException Prepare Failed 错误。我怀疑问题可能出在音频/wav 值上。我找不到任何有关此支持值的文档。当我尝试使用 MP3 文件并将其更改为音频/mp3 时,它可以从内存流中正常工作。有任何想法吗!

标签: androidaudioxamarin.androidwav

解决方案


您应该使用AudioTrack

在这种情况下,您可以为您的 wav 文件指定音频参数:

  • 采样率(HZ)
  • 编码类型(例如 8bit 或 16bit pcm)
  • 通道(单声道\立体声)

然后设置缓冲区大小和传输模式。打电话玩。

例子:

    int minBufferSize = AudioTrack.getMinBufferSize(16000, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
    track =  new AudioTrack.Builder().setAudioFormat(new AudioFormat.Builder()
                                        .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
                                        .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                                        .setSampleRate(44100)
                                        .build())
                                .setTransferMode(AudioTrack.MODE_STREAM)
                                .setBufferSizeInBytes(minBufferSize)
                                .build();
track.play();

如果一切正常。您可以开始将数据写入缓冲区(为此使用后台线程)。

 int size = 512;//(for example)
 byte[] veryShortPiecesOfAudioAataFromRESTService = new byte[size];
 track.write(veryShortPiecesOfAudioAataFromRESTService, 0, size);

推荐阅读