java - 在 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 号码:
任何帮助表示赞赏!谢谢 :)
解决方案
好的,我想通了。
我将按照最初出现的方式解决我的问题:
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复制粘贴并进行了两个小调整:
我在 AudioAttributes .Builder() 方法中对流类型进行了硬编码,因此不再传递它们。
我正在使用 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(); } }
另外,在我的设备上,我注意到音量控制摇杆开关默认只控制铃声音量。我必须打开一个音频菜单(当铃声音量“激活”时,三个小点)来调高媒体音量。
推荐阅读
- git - 有没有一种安全的方法来删除在 Git 中占用大量空间的旧提交?
- python - 使用 xlrd,从 excel 中获取整数列表
- python - 长错误消息的样式指南(例如 PEP8)
- java - 如何在请求 URL(Java 11)中添加参数?
- python - list.remove() 不起作用,但当 llist.remove() 两次时起作用
- django - Celery shared_task 挂在任务调用上
- python - 为什么我的条形图没有显示在我的 matplotlib 中
- javascript - 网站无法通过 index.html 正常运行
- c - C99: Equality operator expression to bool conversion warning
- javascript - JSON 数据未定义