我想使用AudioTrack播放 android 的TextToSpeech.synthesizeToFile的输出,但担心我向 AudioTrack 的构建器传递了错误的参数。如果您想亲自查看 TextToSpeech.synthesizeToFile 的输出,我使用 adb 复制了使用 TextToSpeech.synthesizeToFile 生成的文件之一,并将其放入此 github 文件中。当我在 linux 中运行时,该文件会播放我写的文本 ( hello world ),并打印以下内容:play tempSoundFile8290688667049742717.wav
play WARN alsa: can't encode 0-bit Unknown or not applicable
tempSoundFile8290688667049742717.wav:
File Size: 39.4k Bit Rate: 353k
Encoding: Signed PCM
Channels: 1 @ 16-bit
Samplerate: 22050Hz
Replaygain: off
Duration: 00:00:00.89
In:100% 00:00:00.89 [00:00:00.00] Out:19.7k [!=====|=====!] Clip:0
Done.
因此,我将 AudioTrack 的参数设置如下:
private AudioDeviceInfo findAudioDevice(int deviceFlag, int deviceType) {
AudioManager manager = (AudioManager) this.context.getSystemService(Context.AUDIO_SERVICE);
AudioDeviceInfo[] adis = manager.getDevices(deviceFlag);
for (AudioDeviceInfo adi : adis) {
if (adi.getType() == deviceType) {
return adi;
}
}
return null;
}
AudioDeviceInfo mAudioOutputDevice = findAudioDevice(AudioManager.GET_DEVICES_OUTPUTS,
AudioDeviceInfo.TYPE_BUS);
AudioAttributes.Builder audioAttributesBuilder = new AudioAttributes.Builder().
setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING).
setContentType(AudioAttributes.CONTENT_TYPE_SPEECH).
setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED);
attributes = audioAttributesBuilder.build();
int minBufferSize = AudioTrack.getMinBufferSize(22050, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
AudioTrack.Builder atBuilder = new AudioTrack.Builder();
//builder.setAudioAttributes()
AudioFormat.Builder afBuilder = new AudioFormat.Builder();
afBuilder.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.setSampleRate(22050);
atBuilder.setAudioFormat(afBuilder.build())
.setTransferMode(AudioTrack.MODE_STREAM)
.setBufferSizeInBytes(minBufferSize)
.setAudioAttributes(attributes);
at = atBuilder.build();
at.setPreferredDevice(mAudioOutputDevice);
File myFile = File.createTempFile("tempSoundFile", ".wav");
myFile.deleteOnExit();
myFile.setWritable(true);
myFile.setReadable(true);
然后使用此处的代码播放文件:
/**
* Code taken from here:
* https://stackoverflow.com/questions/7372813/android-audiotrack-playing-wav-file-getting-only-white-noise
*/
private void playWav(){
Log.d(TAG, "Playing speech to text wav file");
String filepath = this.myFile.getAbsolutePath();
int i = 0;
int BUFFER_SIZE = 512;
byte[] s = new byte[BUFFER_SIZE];
try {
Log.i(TAG, "file path is: " + filepath);
FileInputStream fin = new FileInputStream(filepath);
DataInputStream dis = new DataInputStream(fin);
at.play();
while((i = dis.read(s, 0, BUFFER_SIZE)) > -1){
at.write(s, 0, i);
Log.v(TAG, Arrays.toString(s));
}
at.stop();
at.release();
dis.close();
fin.close();
} catch (FileNotFoundException e) {
// TODO
e.printStackTrace();
} catch (IOException e) {
// TODO
e.printStackTrace();
}
}
当然,正如您在我的代码中看到的那样,对这些的调用分布在不同的异步调用中,但是我已经使用日志语句和调试器调试了所有这些,并且没有发现任何问题。playWav() 在我期望的时候被击中,但没有播放任何东西。
编辑:
我使用 AudioTrack 的主要动机是使其 TextToSpeech 与树莓派语音套件的android things 库兼容。使用 AudioTrack 将允许我通过 I2S(或我选择的任何扬声器)播放 textToSpeech。
编辑2,更深入的了解:
根据这个网站,wav 文件有一个 44 字节的标头,说明所有这些参数是什么。在此标题中,位于:
- 位置 20,指示文件类型的 2 个字节(小端)(PCM 为 16)
- 位置 22,2 个字节,指示通道数(1 表示单声道,2 表示立体声)(小端序)
- 位置 24,指示采样率的 4 个字节(小端)
- 最后在第 34 位,2 个字节指示每个样本的位数(小端序)
这是上述文件的十六进制转储:
$ hd -n 44 tempSoundFile8290688667049742717.wav 00000000 52 49 46 46 f8 99 00 00 57 41 56 45 66 6d 74 20 |RIFF....WAVEfmt | 00000010 10 00 00 00 01 00 01 00 22 56 00 00 44 交流 00 00 |........"V..D...| 00000020 02 00 10 00 64 61 74 61 d4 99 00 00 |....数据....| 0000002c