接收 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的主要内容,如果未能解决你的问题,请参考以下文章
使用 VLC 从其他计算机上的 ffmpeg 接收 rtp (opus) 流