接收 RTP 流 - AudioStream, AudioGroup

Posted

技术标签:

【中文标题】接收 RTP 流 - AudioStream, AudioGroup【英文标题】:Receiving RTP stream - AudioStream, AudioGroup 【发布时间】:2015-01-31 20:25:41 【问题描述】:

我想收听 RTP 音频流,但声音中的间隙很小 - 不能继续。可能是什么解决方案?我是否在 Receiver(android) 端或 Streamer(ffmpeg) 端遗漏了什么?

我正在使用 ffmpeg 流式传输 RTP 音频,

ffmpeg -f lavfi -i aevalsrc="sin(400*2*PI*t)" -ar 8000 -vcodec pcm_u8 -f rtp rtp://192.168.0.15:41954 (port changes.)

这是我相关的android代码:

Audiostream audioStream;
AudioGroup audioGroup;
@Override
public void onStart() 
    super.onStart();
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitNetwork().build();
    StrictMode.setThreadPolicy(policy);
    AudioManager audio = (AudioManager)getSystemService(AUDIO_SERVICE);
    audio.setMode(AudioManager.MODE_IN_COMMUNICATION);
    audioGroup = new AudioGroup();
    audioGroup.setMode(AudioGroup.MODE_ECHO_SUPPRESSION);
    InetAddress inetAddress;
    try 
        inetAddress = InetAddress.getByName("192.168.0.15");
        audioStream = new AudioStream(inetAddress);
        audioStream.setCodec(AudioCodec.PCMU);
        audioStream.setMode(RtpStream.MODE_NORMAL);
        InetAddress inetAddressRemote = InetAddress.getByName("192.168.0.14");
        audioStream.associate(inetAddressRemote, 6000);
        ((TextView)findViewById(R.id.tv_port)).setText("Port : " + String.valueOf(audioStream.getLocalPort()));
        audioStream.join(audioGroup);
    
    catch ( UnknownHostException e ) 
        e.printStackTrace();
    
    catch ( SocketException e ) 
        e.printStackTrace();
    

【问题讨论】:

您是否尝试过在 VLC 中打开 RTP 流以检查它在发送时没有播放(数据丢失)。这也将允许您对网络流量进行 Wireshark 处理,我相信 VLC 会让您将其流式传输出去,允许您将设备连接到该设备并查看它是否与 pc 上接收到的流不同 是的,我检查过了。 VLC 的音频效果很好。 如果你从 vlc 重新发送它并让你的设备连接到那会更好 没有更好的。结果相同。 如果在设备上使用 vlc 会怎样。如果您可以在设备上安装 vlc 或其他播放器,您能否监控从服务器到设备的流量,这可能有助于排除 ffmeg 导致连接问题的问题 【参考方案1】:

回答我自己的问题,问题在于 android rtp 数据包管理。

Android 在AudioGroup source file 中表示... assume packet interval is 50ms or less.

但是,RTP 数据包以 60 毫秒的间隔发送。

这意味着 50 毫秒是不够的,这会导致如下所述的问题。

Incoming: X X X X X X Y Y Y Y Y Y X X X X X X Y Y Y Y Y Y X X X X X X
Reading : X X X X X Y Y Y Y Y X X X X X Y Y Y Y Y X X X X X Y Y Y Y Y
          ^ ^ ^ ^ ^ - - - - - - - - - - - - - - - - - - - - ^ ^ ^ ^ ^ 
          ^                                                 ^
          |                                                 |
          |---- just these overlapping packets is valid ----|
          |---- and other packets discarding due to --------|
          |---- invalid RTP headers. -----------------------|

X, Y < packets

我每 300 毫秒间隔只有一个数据包。这会产生抖动的声音。

我会为此发送一个错误报告,希望它对某人有所帮助。

对于真正想收听原始RTP流的人,我建议他们手动读取数据包并将其解码为PCM 16bit(这是android声卡支持的唯一音频格式)并将其写入AudioTrack。

【讨论】:

我不能重建 rtp 库或 vlc 库来修复差距吗?以及如何? 它是实时的吗?你能给出一些示例代码或链接吗?谢谢!【参考方案2】:

如果以下内容愚蠢,请道歉:

ffmpeg 命令行似乎正在生成测试声音并将其作为 pcm 数据流通过 RTP 发出。

RTP 本身并不能保证流式数据的可靠传输,它仅提供足够的信息来告诉接收器是否已收到所有数据,以及如果在传输过程中丢失了一些数据,则确切丢失了哪些数据。另外,它通常通过 UDP 使用。

因此,对于 RTP,重点在于 RTP 的用户发送以这种方式编码的数据(即,使用纠错编码、数据中的冗余等),以便接收者可以重建足够的原始数据以满足应用程序的需求。因此,对于音频流,您需要某种适合的编码格式。

我没有找到 pcm_u8 含义的参考资料,但它强烈暗示它是一个简单的脉冲编码调制数据流,具有 8 位数据。听起来它没有内置任何纠错编码或数据冗余。丢失一个字节就意味着丢失了一个样本,接收端没有什么可以填写的。

所以我认为发生的事情是您的网络中的某些东西正在丢弃 UDP 数据包,RTP 告诉 AudioStream 哪些数据丢失了,结果是间隙,因为 pcm_u8 数据流中没有纠错或数据冗余允许丢失的数据将由 AudioStream 重建。

我见过像 VMWare 故意在虚拟网络上丢弃 UDP 数据包以确保良好性能的一种方式,其理由是 UDP 无论如何都不能保证交付,所以“没关系”。这严重刺痛了一位正在使用 RTP 并期望保证交付但没有得到它的同事。他有一个封闭的网段,线路的每一端都有一个服务器,其中一个托管一个虚拟机。

因此,这可能只是更改您正在使用的编解码器的情况。我无法推荐一个。首先,值得研究一下广播数字媒体流使用什么。 DVB-T 使用 MPEG 传输流(具有纠错编码等)作为 AFAIK,它是 MPEG-2 的包装器。

【讨论】:

看来 android 有一个 RTP 打包的错误。看看我的答案。

以上是关于接收 RTP 流 - AudioStream, AudioGroup的主要内容,如果未能解决你的问题,请参考以下文章

RTP 接发ps流工具改进

使用 VLC 从其他计算机上的 ffmpeg 接收 rtp (opus) 流

iOS RTP 实时音频接收

如何指定VLC的RTSP拉流方式(RTP over UDP/TCP)

webrtc音视频解析流程分析

使用 gstreamer 播放传入的 RTP 视频流