如何通过 RTP 流发送 G722 编码的音频?

How to send G722 encoded audio over an RTP stream?

我有一个小型 SIP 应用程序,基本上就是 UserAgentServer example from SipSorcery。我可以使用 ulaw 编码音频设置 RTP 流,然后我的软电话可以毫无问题地接收它。

现在我使用 ffmepg 创建了一个带有 g722 编码音频的文件:ffmpeg -i sample.wav -ar 16000 -acodec g722 sample.g722。我可以通过 ffplay sample.g722 很好地播放这段音频,文件大小约为每秒 8000 字节。

我用以下方式回答邀请请求:

v=0
o=- 55811 0 IN IP4 192.168.1.36
s=sipsorcery
c=IN IP4 192.168.1.36
t=0 0
m=audio 49000 RTP/AVP 9
a=rtpmap:9 G722/8000
a=sendrecv

但后来出了点问题。因为在 wireshark 中我看到我的 RTP 流的有效负载是 'RTPType-96' 而软电话的 RTP 流显示为 g722。因此,编解码器类型似乎已正确协商,但不知何故,我的实际 RTP 流仍然缺少一些信息。

我通过 RPT 流从我的 g722 编码文件发送字节,如下所示:

private async Task SendG722()
{
    uint timestamp = 0;
    using (StreamReader sr = new StreamReader(this.AudioFileName))
    {
        var interval = 20;
        var bytesPerSecond = 8000;
        var packetsPerSecond = 1000 / interval;
        var bufferSize = bytesPerSecond / packetsPerSecond;

        byte[] buffer = new byte[bufferSize];
        int bytesRead = sr.BaseStream.Read(buffer, 0, buffer.Length);

        while (bytesRead > 0 && !this.CancellationTokenSource.IsCancellationRequested)
        {                
            this.Session.SendAudioFrame(this.RtpSocket, this.DestinationRtpEndPoint, timestamp, buffer);
            timestamp += (uint)buffer.Length;                    

            await Task.Delay(interval, this.CancellationTokenSource.Token);
            bytesRead = sr.BaseStream.Read(buffer, 0, buffer.Length);
        }
    }
}

但是当字节被发送到某处时,RTP 流和数据包出现在 wireshark 中。我的软电话听不到任何声音。而且 wireshark 甚至无法弄清楚有关流的任何信息。

我怀疑您需要做的就是设置 RTP 数据包负载类型以匹配您的 SDP 报价。

下面的行将 RTP 数据包中的负载类型 header 设置为 0。

var rtpSession = new RTPSession(RTPPayloadTypesEnum.PCMU, null, null);

您的问题是您的 SDP 提议告诉接收方期望 RTP 数据包 header.

中的负载类型为 9

修复应该像将 ENUM 更改为一样简单:

public enum RTPPayloadTypesEnum
{
    PCMU = 0,
    PCMA = 1,
    G722 = 9,
    Dynamic = 96,
}

然后

var rtpSession = new RTPSession(RTPPayloadTypesEnum.G722, null, null);