我目前正在开发一个简单的VoIP项目,其中多个客户端将其语音发送到服务器,之后服务器将这些语音混合在一起。
但是,我不能通过使用简单的数学加法直接混合它。每个周期,客户端都会向混音器发送3584字节语音数据。
以下是接收缓冲区中包含的值的片段:
BYTE buffer[3584];
[0] 0 unsigned char
[1] 192 'À' unsigned char
[2] 176 '°' unsigned char
[3] 61 '=' unsigned char
[4] 0 unsigned char
[5] 80 'P' unsigned char
[6] 172 '¬' unsigned char
[7] 61 '=' unsigned char
[8] 0 unsigned char
[9] 144 '' unsigned char
[10] 183 '·' unsigned char
[11] 61 '=' unsigned char
.
.
.
我不太确定如何从客户端以这种方式生成缓冲区内的模式,但我认为它可能是波形模式。现在让我说我有另外类似的数据,如何将声音混合在一起。
请帮忙。谢谢。
答案 0 :(得分:3)
您需要了解您的VoIP系统是否使用压缩。它可能会,在这种情况下,您需要做的第一件事是解压缩流,然后混合它们,然后重新压缩。
答案 1 :(得分:2)
这可能是一个浮点数组(不太可能是由于字节模式显示)或者是整数,如果是原始PCM数据,那么请尝试使用它。混合到PCM流是相当简单的,只需将它们加在一起并将它们除以2(使用其他加权进行音量控制)。
答案 2 :(得分:1)
我再次查看了你的数据,它们似乎是浮点值,我在上一篇文章中错误的原因可能与我在大端系统上工作了一段时间有关。但是,您的数据处于小端IEEE浮点数。以下是转换后获得的值。
0.089630127 -> 0x0090b73d
0.084136963 -> 0x0050ac3d
0.086303711 -> 0x00c0b03d
正如您所看到的,值非常小,因此在应用卷时您可能需要考虑这一点;通常的惯例是将这些数据分别设置在0..1或-1..1之间,分别用于最小和最大卷。
以下是我几年前写过的混音循环的一部分,供参考,完整的混音器是available here
for(int i = 0; i < a_Sample->count() / a_Sample->channels(); i++){
float l_Volume = a_Sample->volume() * m_MasterVolume;
*l_Output++ += *l_Left * l_PanLeft * l_Volume;
*l_Output++ += *l_Right * l_PanRight * l_Volume;
l_Left += a_Sample->channels();
l_Right += a_Sample->channels();
}
请注意,对于输出,您可能需要将数据转换为有符号整数,以便在混音器或输出设备负责时正确通信。
答案 3 :(得分:0)
正如其他人所提到的,你必须知道缓冲区的格式。你不能简单地直接操作字节(好吧,你可以,但它会变得非常复杂)。大多数原始PCM数据通常是44100位/秒,16位,2通道。然而,情况并非总是如此。每一个都可以是不同的。它不会影响太多,但这是一个例子。但是,即使是WAV文件也可以采用其他格式(如IEEE Float)。您需要将缓冲区正确解释为适当的数据类型才能对其进行操作。
像:
BYTE buffer[3584];
if (SampleTypeIsPcm16Bit())
{
short *data = reinterpret_cast<short *>(buffer);
// Rock on
}
else if (SampleTypeIsFloat())
{
float *data = reinterpret_cast<float *>(buffer);
// Rock on
}
当然,您可以使用模板使其更通用,但忽略知识:P。
请记住,如果您正在处理浮动,则需要将其限制在-1.0和1.0的范围内。
那么,你现在说“添加两个值并除以2”(Jasper提到)不起作用吗?当你听到沉默时,你是如何播放数据的?我想知道这是不是一个问题,因为如果你的数学已经关闭,你可能会听到音频故障(弹出/点击/等等),而不仅仅是沉默。