我正在尝试播放通过网络收到的音频,这些音频作为短片阵列到达。我试图使用来自NAudio的WaveOut对象来完成这项工作,但是从我能找到的内容来看,这只适用于byte []。所以到目前为止我的问题是:
它并不多,但我现在拥有的是它(显然是从字节[]播放音频):
protected override void Write(VoiceSource source, VoicePacket packet)
{
if (connected)
{
try
{
dispatcher.Invoke((WriteCallback)provider.Write, packet.Data);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
WriteCallback
定义为:
private delegate void WriteCallback(byte[] data);
我写的提供者是IWaveProvider
接口的实现。
我已经尝试了马克告诉我的“技巧”,我的界面看起来像这样:
interface ISampleBuffer {
byte[] Bytes { get; set; }
short[] Shorts { get; set; }
}
缓冲区结构如下所示:
[StructLayout(LayoutKind.Explicit, Pack = 2)]
public struct SampleBuffer : ISampleBuffer
{
[FieldOffset(0)]
private byte[] bytes;
[FieldOffset(0)]
private short[] shorts;
public byte[] Bytes { get { return bytes; } set { bytes = value; } }
public short[] Shorts { get { return shorts; } set { shorts = value; } }
}
我已经像这样实现了这个缓冲区:
short[] audio = decoder.Decode(packet.Data);
buffer.Bytes = new byte[audio.Length * 2];
buffer.Shorts = audio;
dispatcher.Invoke((WriteCallback)provider.Write, buffer.Bytes);
但是,每当我运行此设置时,我的日志中都会出现以下异常的堆栈跟踪:
Object of type 'System.Int16[]' cannot be converted to type 'System.Byte[]'.
我的实施方式有问题吗?
答案 0 :(得分:3)
NAudio包含一个聪明的技巧(或根据你的观点进行肮脏的黑客攻击),允许你从short[]
“投射”到byte[]
。它被称为WaveBuffer
类,通过使用具有显式布局的结构来工作。只需写入ShortBuffer
属性并读出ByteBuffer
属性。
Buffer.BlockCopy
的费用。
答案 1 :(得分:2)
不确定NAudio位,但我可以帮助您将short[]
转换为byte[]
。 Buffer.BlockCopy
在这里可能很有用,因为它可以在不同类型的数组之间复制字节:
short[] shortArray = ...
byte[] byteArray = new byte[shortArray.Length*2];
Buffer.BlockCopy(shortArray, 0, byteArray, 0, byteArray.Length);
但是,你可能会遇到endian问题。你需要尝试一下,看看会发生什么。如果需要交换包含单个short的两个字节,可以手动交换它:
for (int i=0; i<byteArray.Length; i += 2) {
byte b = byteArray[i];
byteArray[i] = byteArray[i+1];
byteArray[i] = b;
}
或者,如果您想要的东西更整洁,并且不想担心字节序转换,您可以使用BinaryWriter
为您进行转换:
BinaryWriter writer = new BinaryWriter(new MemoryStream(shortArray.Length*2));
foreach (short s in shortArray)
writer.Write(s);
byte[] byteArray = ((MemoryStream)writer.BaseStream).ToArray();