繁体   English   中英

在Java中,通过TCP套接字从C#应用程序接收音频数据流,并在接收时播放流

[英]In Java, receive audio data streaming from a C# app over TCP sockets and play streaming as it is received

我在C#应用中有一些原始的PCM音频数据。 我需要将其放入Java应用程序并作为音频播放。

第一步,我希望Java应用程序在流进音频时立即播放音频(而不是保存临时文件并播放,而是在接收到它时播放它)。

我在用C#正确格式化PCM音频数据并将其发送到Java应用程序时遇到问题。 我目前仅使用一个简单的TCP套接字系统来执行此操作,将C#应用程序(由Unity制造)称为“客户端”,将Java应用程序称为“服务器”。

在Unity C#客户端上,我正在使用NatMic来获取Mic的原始PCM数据。 随着数据的传入,每秒多次调用此函数:

void IAudioProcessor.OnSampleBuffer(float[] sampleBuffer, int sampleRate, int channelCount, long timestamp)

我有一个浮点数组和两个整数来描述音频数据。

如何将这些数据打包为要发送给Java的字节?

我有一个TCP设置,可以在其中向Java发送字节,并且在测试仅在客户端和服务器之间来回发送简单字符串消息时,它似乎可以正常工作。

但是,当我尝试打包音频并将其发送过来时,它永远无法工作。 我总是收到这样的错误:

javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input stream

这是Java方面的一个片段,它展示了我如何尝试在Java方面播放音频作为测试(当客户端连接时,我只运行一次):

    inputStream = client.getInputStream();
    bInputStream = new BufferedInputStream(inputStream);
    Clip clip = AudioSystem.getClip();
    audioStream = AudioSystem.getAudioInputStream(bInputStream);
    clip.open(audioStream);
    clip.start();

我应该如何包装float [],int和int以发送到Java服务器,以便它将其识别为音频流?

首先,您需要将数据输出为SourceDataLine而不是Clip Clip不能播放,直到它接收到整个声音文件。

通常的计划是以您想要的任何方式读取输入行,并在调用sdl.write()方法的循环中将其转换为正确的格式。

对于传入的数据,应遵循以下内容

while(playerRunning)
{
    readBuffer = getInputPCM();
    audioBytes = convertToFollowAudioFormat(readBuffer);
    sourceDataLine.write(audioBytes, 0, sdlBufferSize);
}

如果您输入的数据是浮点数,范围是-1到1,并且您以基本的“ CD Quality” Java格式(44100 fps,16位,立体声,小字节序)输出,那么转换可能类似于以下内容:

for (int i = 0, n = buffer.length; i < n; i++)
{
    buffer[i] *= 32767;
    audioBytes[i*2] = (byte) buffer[i];
    audioBytes[i*2 + 1] = (byte)((int)buffer[i] >> 8 );
}
return audioBytes;

根据PCM的形式,您可能需要做更多或更少的事情。 例如,如果您正在读取从-32767到32767的整数或短裤,则不需要乘法步骤。

要获得在默认音频行上输出“ CD Quality”音频格式的SourceDataLine ,请执行以下操作:

AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 
                44100, 16, 2, 4, 44100, false);
Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
SourceDataLine sdl = (SourceDataLine)AudioSystem.getLine(info);

就您的getInputPCM方法而言,我假设您只能在流中显示PCM数据,而无需进一步解析。 如果要在运送前完成将PCM转换为C#中的字节的任务,那也完全有效。

Java教程的Sampled Package路径中有更多关于各种输出格式的文章。

对于以上内容,我主要是从github项目AudioCue复制/编辑代码,这是一种增强的Clip

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM