gpt4 book ai didi

audio - android AudioTrack播放短数组(16bit)

转载 作者:行者123 更新时间:2023-12-03 01:37:28 35 4
gpt4 key购买 nike

我有一个播放音频的应用程序。它通过 RTP 获取编码的音频数据并将其解码为 16 位数组。解码后的 16 位数组被转换为 8 位数组(字节数组),因为这是一些其他功能所必需的。

即使音频播放正常,它也会不断中断并且很难识别音频输出。如果我仔细听,我可以知道它正在播放正确的音频。

我怀疑这是因为我将 16 位数据流转换为字节数组并使用 AudioTrack 类的 write(byte[], int, int, AudioTrack.WRITE_NON_BLOCKING) 进行音频播放。

因此,我将字节数组转换回短数组并使用 write(short[], int, int, AudioTrack.WRITE_NON_BLOCKING) 方法查看是否可以解决问题。

但是现在根本没有音频声音。在调试输出中,我可以看到短数组有数据。

可能是什么原因?

这是 AUdioTrak 初始化

            sampleRate      =AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);

minimumBufferSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);

audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
minimumBufferSize,
AudioTrack.MODE_STREAM);

这是将短数组转换为字节数组的代码
for (int i=0;i<internalBuffer.length;i++){

bufferIndex = i*2;
buffer[bufferIndex] = shortToByte(internalBuffer[i])[0];
buffer[bufferIndex+1] = shortToByte(internalBuffer[i])[1];
}

这是将字节数组转换为短数组的方法。
public short[] getShortAudioBuffer(byte[] b){
short audioBuffer[] = null;
int index = 0;
int audioSize = 0;
ByteBuffer byteBuffer = ByteBuffer.allocate(2);

if ((b ==null) && (b.length<2)){
return null;
}else{
audioSize = (b.length - (b.length%2));
audioBuffer = new short[audioSize/2];
}

if ((audioSize/2) < 2)
return null;

byteBuffer.order(ByteOrder.LITTLE_ENDIAN);


for(int i=0;i<audioSize/2;i++){
index = i*2;
byteBuffer.put(b[index]);
byteBuffer.put(b[index+1]);
audioBuffer[i] = byteBuffer.getShort(0);
byteBuffer.clear();
System.out.print(Integer.toHexString(audioBuffer[i]) + " ");
}
System.out.println();

return audioBuffer;
}

音频使用 opus 库解码,配置如下;
opus_decoder_ctl(dec,OPUS_SET_APPLICATION(OPUS_APPLICATION_AUDIO));
opus_decoder_ctl(dec,OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC));
opus_decoder_ctl(dec,OPUS_SET_FORCE_CHANNELS(OPUS_AUTO));
opus_decoder_ctl(dec,OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
opus_decoder_ctl(dec,OPUS_SET_PACKET_LOSS_PERC(0));
opus_decoder_ctl(dec,OPUS_SET_COMPLEXITY(10)); // highest complexity
opus_decoder_ctl(dec,OPUS_SET_LSB_DEPTH(16)); // 16bit = two byte samples
opus_decoder_ctl(dec,OPUS_SET_DTX(0)); // default - not using discontinuous transmission
opus_decoder_ctl(dec,OPUS_SET_VBR(1)); // use variable bit rate
opus_decoder_ctl(dec,OPUS_SET_VBR_CONSTRAINT(0)); // unconstrained
opus_decoder_ctl(dec,OPUS_SET_INBAND_FEC(0)); // no forward error correction

最佳答案

假设您有一个 short[]包含要播放的 16 位单声道数据的数组。
然后每个样本是一个介于 -32768 和 32767 之间的值,它代表确切时刻的信号幅度。 0 值表示中间点(无信号)。该数组可以通过 ENCODING_PCM_16BIT 传递给音轨格式编码。

但是玩 ENCODING_PCM_8BIT 时事情变得很奇怪被使用(见 AudioFormat)

在这种情况下,每个样本由一个字节编码。但是每个字节都是无符号的。也就是说,它的值在 0 到 255 之间,而 128 代表中间点。

Java 没有无符号字节格式。字节格式已签名。 IE。值 -128...-1 将表示 128...255 的实际值。所以在转换成字节数组的时候一定要小心,否则会是一个几乎无法辨认音源的噪音。

short[] input16 = ... // the source 16-bit audio data;

byte[] output8 = new byte[input16.length];

for (int i = 0 ; i < input16.length ; i++) {
// To convert 16 bit signed sample to 8 bit unsigned
// We add 128 (for rounding), then shift it right 8 positions
// Then add 128 to be in range 0..255
int sample = ((input16[i] + 128) >> 8) + 128;
if (sample > 255) sample = 255; // strip out overload
output8[i] = (byte)(sample); // cast to signed byte type
}

执行反向转换都应该是相同的:每个单个样本都被转换为输出信号的一个样本
byte[] input8 = // source 8-bit unsigned audio data;

short[] output16 = new short[input8.length];

for (int i = 0 ; i < input8.length ; i++) {
// to convert signed byte back to unsigned value just use bitwise AND with 0xFF
// then we need subtract 128 offset
// Then, just scale up the value by 256 to fit 16-bit range
output16[i] = (short)(((input8[i] & 0xFF) - 128) * 256);
}

关于audio - android AudioTrack播放短数组(16bit),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51278201/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com