android AudioTrack播放短阵列(16位)

android AudioTrack播放短阵列(16位),audio,streaming,audiotrack,Audio,Streaming,Audiotrack,我有一个播放音频的应用程序。它通过RTP接收编码的音频数据,并将其解码为16位阵列。解码后的16位数组转换为8位数组(字节数组),因为这是某些其他功能所必需的 尽管音频播放正在工作,但它仍在不断中断,很难识别音频输出。如果我仔细听,我可以判断它正在播放正确的音频 我怀疑这是因为我将16位数据流转换为字节数组,并使用AudioTrack类的write(byte[],int,int,AudioTrack.write_NON_BLOCKING)进行音频播放 因此,我将字节数组转换回一个短数组,并使用w

我有一个播放音频的应用程序。它通过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];
    }

假设您有一个
short[]
数组,其中包含要播放的16位单通道数据。 然后,每个样本是一个介于-32768和32767之间的值,该值表示精确时刻的信号振幅。0表示中间点(无信号)。此阵列可以通过
编码\u PCM\u 16位
格式编码传递到音频曲目

但是当使用
编码时,事情会变得很奇怪(请参阅)

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

Java没有无符号字节格式。字节格式是有符号的。即,值-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
}
short[]input16=…//源16位音频数据;
字节[]输出8=新字节[input16.length];
for(int i=0;i>8)+128;
如果(sample>255)sample=255;//去掉重载
output8[i]=(字节)(示例);//转换为有符号字节类型
}
要执行反向转换,所有采样都应该是相同的:每个采样都要转换为输出信号的一个采样

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);
}
byte[]input8=//源8位无符号音频数据;
short[]output16=新的short[input8.length];
对于(inti=0;i
当使用位运算符而不是ByteArray时,无法将数据从字节数组转换为短数组的问题得到了解决。这可能是由于没有在ByteArray中设置正确的参数,或者不适合这种转换

然而,使用位运算符实现转换解决了这个问题。由于原来的问题已经解决了这种方法,请考虑这是最终的答案。 我将为播放问题提出一个单独的主题


感谢您的支持。

尼尔·汤森(Neil Townsend)介绍了一些有关将短文本内容转换为字节的信息,但不是我想要的。感谢AterLux对音频编码的详细解释。关于从短到字节的转换,我没有修改内容。我只是使用以下方法将数据表示方式从短改为字节。私有字节[]shortToByte(short val){byte converted[]=新字节[2];converted[0]=(byte)(val&0xff);converted[1]=(byte)((val>>8)&0xff);return converted;}因此,一旦转换回short,它就不能正常播放了吗?所以,您有了short[]数组,它可以播放,然后您将它转换成byte[](仍然播放每个样本16位,即2字节)并且它不播放god,然后将其转换回short[]它根本不播放,是吗?如果是的话,你能把转换数组的两种代码都带来吗?我已经将字节数组转换回短数组,音频波动仍然保持不变。下面是我如何转换回短数组的。请注意,内容没有被修改。例如(int i=0;iI不明白,那么,你有什么问题?声音在被转换后会发生变化吗?你给出了源代码的不同部分,没有人给出将短[]数组转换为字节[]的整个过程然后再回来。我刚刚添加了用于从短数组到字节数组转换为原始问题的逻辑。声音随使用短数组播放或字节数组播放的音轨播放而波动。这可能是解码器的问题吗?我也在原始问题中添加了解码器配置。
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);
}