首页 > 解决方案 > 在 Android 上使用 TarsosDSP 播放 wav 文件

问题描述

问题:Wav 文件加载并由 AudioDispatcher 处理,但没有声音播放。

一、权限:

public void checkPermissions() {
    if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this.requireContext(), Manifest.permission.RECORD_AUDIO)) {
        //When permission is not granted by user, show them message why this permission is needed.
        if (ActivityCompat.shouldShowRequestPermissionRationale(this.requireActivity(), Manifest.permission.RECORD_AUDIO)) {
            Toast.makeText(this.getContext(), "Please grant permissions to record audio", Toast.LENGTH_LONG).show();
            //Give user option to still opt-in the permissions
        }

        ActivityCompat.requestPermissions(this.requireActivity(), new String[]{Manifest.permission.RECORD_AUDIO}, MY_PERMISSIONS_RECORD_AUDIO);
        launchProfile();
    }
    //If permission is granted, then proceed
    else if (ContextCompat.checkSelfPermission(this.requireContext(), Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
        launchProfile();
    }
}

然后是 launchProfile() 函数:

public void launchProfile() {
        AudioMethods.test(getActivity().getApplicationContext());
        //Other fragments load after this that actually do things with the audio file, but 
        //I want to get this working before anything else runs.
}

然后是 AudioMethods.test 函数:

public static void test(Context context){
    String fileName = "audio-samples/samplefile.wav";
    try{
        releaseStaticDispatcher(dispatcher);

        TarsosDSPAudioFormat tarsosDSPAudioFormat = new TarsosDSPAudioFormat(TarsosDSPAudioFormat.Encoding.PCM_SIGNED,
                22050,
                16, //based on the screenshot from Audacity, should this be 32?
                1,
                2,
                22050,
                ByteOrder.BIG_ENDIAN.equals(ByteOrder.nativeOrder()));

        AssetManager assetManager = context.getAssets();
        AssetFileDescriptor fileDescriptor = assetManager.openFd(fileName);

        InputStream stream = fileDescriptor.createInputStream();
        dispatcher = new AudioDispatcher(new UniversalAudioInputStream(stream, tarsosDSPAudioFormat),1024,512);
        
        //Not playing sound for some reason...
        final AudioProcessor playerProcessor = new AndroidAudioPlayer(tarsosDSPAudioFormat, 22050, AudioManager.STREAM_MUSIC);
        dispatcher.addAudioProcessor(playerProcessor);


        dispatcher.run();

        Thread audioThread = new Thread(dispatcher, "Test Audio Thread");
        audioThread.start();

    } catch (Exception e) {
        e.printStackTrace();
    }
}

控制台输出。没有错误,只有警告:

W/AudioTrack: Use of stream types is deprecated for operations other than volume control
See the documentation of AudioTrack() for what to use instead with android.media.AudioAttributes to qualify your playback use case
D/AudioTrack: stop(38): called with 12288 frames delivered

因为 AudioTrack 正在传递帧,并且没有任何运行时错误,所以我假设我只是因为没有足够的权限而错过了一些愚蠢的东西,或者我在设置我的 AndroidAudioPlayer 时错过了一些东西。我通过在 Audacity 中打开文件并查看那里的统计数据得到了 22050 号码:

在此处输入图像描述

任何帮助表示赞赏!谢谢 :)

标签: javaandroidtarsosdsp

解决方案


好的,我想通了。

我将按照最初出现的方式解决我的问题:

TarsosDSPAudioFormat tarsosDSPAudioFormat = new TarsosDSPAudioFormat(TarsosDSPAudioFormat.Encoding.PCM_SIGNED,
            22050,
            16, //based on the screenshot from Audacity, should this be 32?
            1,
            2,
            22050,
            ByteOrder.BIG_ENDIAN.equals(ByteOrder.nativeOrder()));

ANS:不。根据以下 TarsosDSP AndroidAudioPlayer 标头(复制如下),我限制为 16:

 /**
 * Constructs a new AndroidAudioPlayer from an audio format, default buffer size and stream type.
 *
 * @param audioFormat The audio format of the stream that this AndroidAudioPlayer will process.
 *                    This can only be 1 channel, PCM 16 bit.
 * @param bufferSizeInSamples  The requested buffer size in samples.
 * @param streamType  The type of audio stream that the internal AudioTrack should use. For
 *                    example, {@link AudioManager#STREAM_MUSIC}.
 * @throws IllegalArgumentException if audioFormat is not valid or if the requested buffer size is invalid.
 * @see AudioTrack
 */

需要对 test() 方法进行以下修改(这对我有用):

 public static void test(Context context){
    String fileName = "audio-samples/samplefile.wav";
    try{
        releaseStaticDispatcher(dispatcher);

        TarsosDSPAudioFormat tarsosDSPAudioFormat = new TarsosDSPAudioFormat(TarsosDSPAudioFormat.Encoding.PCM_SIGNED,
                22050,
                16,
                1,
                2,
                22050,
                ByteOrder.BIG_ENDIAN.equals(ByteOrder.nativeOrder()));

        AssetManager assetManager = context.getAssets();
        AssetFileDescriptor fileDescriptor = assetManager.openFd(fileName);
        FileInputStream stream = fileDescriptor.createInputStream();  
        
        dispatcher = new AudioDispatcher(new UniversalAudioInputStream(stream, tarsosDSPAudioFormat),2048,1024);     //2048 corresponds to the buffer size in samples, 1024 is the buffer overlap and should just be half of the 'buffer size in samples' number (so...1024)
        AudioProcessor playerProcessor = new customAudioPlayer(tarsosDSPAudioFormat, 2048); //again, 2048 is the buffer size in samples
        
        dispatcher.addAudioProcessor(playerProcessor);
        dispatcher.run();
        Thread audioThread = new Thread(dispatcher, "Test Audio Thread");
        audioThread.start();

    } catch (Exception e) {
        e.printStackTrace();
    }
}

您会注意到我现在创建了一个“customAudioPlayer”,实际上是直接从TarsosDSP AndroidAudioPlayer复制粘贴并进行了两个小调整:

  1. 我在 AudioAttributes .Builder() 方法中对流类型进行了硬编码,因此不再传递它们。

  2. 我正在使用 AudioTrack.Builder() 方法,因为不推荐使用流类型进行播放。诚然,我不确定这是修复它的更改,还是缓冲区大小的更改(或两者兼而有之?)。

     /*
      * Constructs a new AndroidAudioPlayer from an audio format, default buffer size and stream type.
      *
      * @param audioFormat The audio format of the stream that this AndroidAudioPlayer will process.
      *                    This can only be 1 channel, PCM 16 bit.
      * @param bufferSizeInSamples  The requested buffer size in samples.
      * @throws IllegalArgumentException if audioFormat is not valid or if the requested buffer size is invalid.
      * @see AudioTrack
      */
      public customAudioPlayer(TarsosDSPAudioFormat audioFormat, int bufferSizeInSamples) {
         if (audioFormat.getChannels() != 1) {
             throw new IllegalArgumentException("TarsosDSP only supports mono audio channel count: " + audioFormat.getChannels());
         }
    
         // The requested sample rate
         int sampleRate = (int) audioFormat.getSampleRate();
    
         //The buffer size in bytes is twice the buffer size expressed in samples if 16bit samples are used:
         int bufferSizeInBytes = bufferSizeInSamples * audioFormat.getSampleSizeInBits()/8;
    
         // From the Android API about getMinBufferSize():
         // The total size (in bytes) of the internal buffer where audio data is read from for playback.
         // If track's creation mode is MODE_STREAM, you can write data into this buffer in chunks less than or equal to this size,
         // and it is typical to use chunks of 1/2 of the total size to permit double-buffering. If the track's creation mode is MODE_STATIC,
         // this is the maximum length sample, or audio clip, that can be played by this instance. See getMinBufferSize(int, int, int) to determine
         // the minimum required buffer size for the successful creation of an AudioTrack instance in streaming mode. Using values smaller
         // than getMinBufferSize() will result in an initialization failure.
         int minBufferSizeInBytes = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_MONO,  AudioFormat.ENCODING_PCM_16BIT);
         if(minBufferSizeInBytes > bufferSizeInBytes){
             throw new IllegalArgumentException("The buffer size should be at least " + (minBufferSizeInBytes/(audioFormat.getSampleSizeInBits()/8)) + " (samples) according to  AudioTrack.getMinBufferSize().");
         }
    
         //http://developer.android.com/reference/android/media/AudioTrack.html#AudioTrack(int, int, int, int, int, int)
         //audioTrack = new AudioTrack(streamType, sampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes,AudioTrack.MODE_STREAM);
         try {
             audioTrack = new AudioTrack.Builder()
                     .setAudioAttributes(new AudioAttributes.Builder()
                             .setUsage(AudioAttributes.USAGE_MEDIA)
                             .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                             .build())
                     .setAudioFormat(new AudioFormat.Builder()
                             .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                             .setSampleRate(sampleRate)
                             .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
                             .build())
                     .setBufferSizeInBytes(bufferSizeInBytes)
                     .build();
    
             audioTrack.play();
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
    

另外,在我的设备上,我注意到音量控制摇杆开关默认只控制铃声音量。我必须打开一个音频菜单(当铃声音量“激活”时,三个小点)来调高媒体音量。


推荐阅读