为啥我在 Chrome 中运行时在 Android 中收到“无法为 m-section 设置远程视频描述发送参数,mid='0'”错误?

Posted

技术标签:

【中文标题】为啥我在 Chrome 中运行时在 Android 中收到“无法为 m-section 设置远程视频描述发送参数,mid=\'0\'”错误?【英文标题】:Why am I getting "Failed to set remote video description send parameters for m-section with mid='0'" error in Android when it works in Chrome?为什么我在 Chrome 中运行时在 Android 中收到“无法为 m-section 设置远程视频描述发送参数,mid='0'”错误? 【发布时间】:2021-12-24 11:58:11 【问题描述】:

背景资料

您好,我正在尝试在 android 中构建一个 WebRTC 客户端,该客户端订阅正在使用 NodeJS 和 javascript 广播的视频源。

广播公司代码可以完整查看in this lovely article by Gabriel Tanner。

在 Chrome 中 http://localhost:4000/broadcaster.html 下的 localhost 中运行它,然后从网络上的另一台设备访问我的 IP 地址时,它运行良好。我可以看到视频,它几乎是实时的。

我已经尝试过使用两种不同的网络摄像头设备,一个是内置网络摄像头,一个是 USB 网络摄像头,但即使 JavaScript Broadcaster 和客户端工作正常,Android 客户端也无法工作。

手头的任务

按照教程并让示例运行后,我决定尝试实现我自己的 Android 应用程序,可以查看其整个源代码 right here on my GitHub。

我已经关注了这个地方的各种教程,但问题总是源于尝试设置远程描述,该描述使用以下代码完成:

    private void setRemoteDescription(Object[] arguments) 
        JSONObject message = (JSONObject) arguments[1];
        try 
            String sdp = message.getString("sdp");
            SessionDescription sessionDescription = new SessionDescription(OFFER, sdp);
            peerConnection.setRemoteDescription(new SimpleSdpObserver(), sessionDescription);
         catch (JSONException e) 
            Log.e(TAG, "setRemoteDescription: failed to parse JSON", e);
        
    

就像我说的那样,可以在 GitHub 中查看完整的代码,我不想把这篇文章弄得太乱,但基本上按照 Gabriel 的教程,当套接字在连接时发出“观察者”时(Android 应用程序正确)然后它会发回一个“offer”,然后在客户端进行监听,如下所示:

    private void bindSocketEvents() 
        socket.on(EVENT_CONNECT, args -> 
            socket.emit("watcher");
        ).on("broadcaster", args -> 
            socket.emit("watcher");
        ).on("offer", args -> 
            setRemoteDescription(args);
            performAnswer();
        ).on("candidate", this::addIceCandidate);
    

然后我们看到,在“offer”时,我们使用 JavaScript 中的 args 调用代码并尝试设置远程描述,但它失败了。

这是我通过触发它获得的示例 SDP:

v=0
o=- 7040957491050894781 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=extmap-allow-mixed
a=msid-semantic: WMS l91G3Ekmme9tlvEso1ApTqS6djaxtsamgfLu
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 121 127 120 125 107 108 109 35 36 124 119 123
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:XEnc
a=ice-pwd:2PyQmLOm9YPPf1Pozvonticd
a=ice-options:trickle
a=fingerprint:sha-256 64:22:D7:93:FD:6C:A9:94:E3:65:76:B0:DB:4E:E9:8E:91:46:56:87:B1:E3:E9:B3:24:D0:CF:A5:3F:91:0A:FD
a=setup:actpass
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 urn:3gpp:video-orientation
a=extmap:4 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendrecv
a=msid:l91G3Ekmme9tlvEso1ApTqS6djaxtsamgfLu 7eb4296c-f3e4-4e95-9f6f-05aa386a3176
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=fmtp:98 profile-id=0
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:100 VP9/90000
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=fmtp:100 profile-id=2
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:102 H264/90000
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 transport-cc
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtpmap:121 rtx/90000
a=fmtp:121 apt=102
a=rtpmap:127 H264/90000
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 transport-cc
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=rtpmap:120 rtx/90000
a=fmtp:120 apt=127
a=rtpmap:125 H264/90000
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 transport-cc
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtpmap:108 H264/90000
a=rtcp-fb:108 goog-remb
a=rtcp-fb:108 transport-cc
a=rtcp-fb:108 ccm fir
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtpmap:109 rtx/90000
a=fmtp:109 apt=108
a=rtpmap:35 AV1X/90000
a=rtcp-fb:35 goog-remb
a=rtcp-fb:35 transport-cc
a=rtcp-fb:35 ccm fir
a=rtcp-fb:35 nack
a=rtcp-fb:35 nack pli
a=rtpmap:36 rtx/90000
a=fmtp:36 apt=35
a=rtpmap:124 red/90000
a=rtpmap:119 rtx/90000
a=fmtp:119 apt=124
a=rtpmap:123 ulpfec/90000
a=s-s-rc-group:FID 4173041010 2470630943
a=s-s-rc:4173041010 cname:VrEB0NYLt23UUzRD
a=s-s-rc:4173041010 msid:l91G3Ekmme9tlvEso1ApTqS6djaxtsamgfLu 7eb4296c-f3e4-4e95-9f6f-05aa386a3176
a=s-s-rc:4173041010 mslabel:l91G3Ekmme9tlvEso1ApTqS6djaxtsamgfLu
a=s-s-rc:4173041010 label:7eb4296c-f3e4-4e95-9f6f-05aa386a3176
a=s-s-rc:2470630943 cname:VrEB0NYLt23UUzRD
a=s-s-rc:2470630943 msid:l91G3Ekmme9tlvEso1ApTqS6djaxtsamgfLu 7eb4296c-f3e4-4e95-9f6f-05aa386a3176
a=s-s-rc:2470630943 mslabel:l91G3Ekmme9tlvEso1ApTqS6djaxtsamgfLu
a=s-s-rc:2470630943 label:7eb4296c-f3e4-4e95-9f6f-05aa386a3176

错误

现在的问题是,当我尝试设置此远程描述时,会抛出这些错误,而我们永远无法尝试peerConnection.createAnswer

2021-11-12 13:45:52.819 26795-27780/au.com.australiandroid.androidclient D/CustomPeerConnectionObs: onSignalingChange: new signaling state is HAVE_REMOTE_OFFER
2021-11-12 13:45:52.820 26795-27780/au.com.australiandroid.androidclient E/SimpleSdpObserver: onSetFailure: failed to set the remote description: Failed to set remote offer sdp: Failed to set remote video description send parameters for m-section with mid='0'.
2021-11-12 13:45:52.820 26795-27780/au.com.australiandroid.androidclient E/MainActivity: onCreateFailure: failed to create answer: Session error code: ERROR_CONTENT. Session error description: Failed to set remote video description send parameters for m-section with mid='0'..

如果您有任何信息说明为什么它无法设置远程描述,或者即使您对如何实现 Android WebRTC 客户端有任何建议,那么此时任何事情都会有所帮助。我已经挣扎了几个星期,我不知道从哪里开始,因为谷歌搜索这个错误没有帮助。要么是因为我根本不理解答案,要么是因为答案不相关。我不知道,但请不要只粘贴指向 Google 热门文章的链接,因为我已经阅读了很多。

【问题讨论】:

如果您从报价中删除 H264 编解码器,这种情况会消失吗?您可能遇到了bugs.chromium.org/p/webrtc/issues/detail?id=9774 的实例 我没有尝试从报价中删除 H264 编解码器。你有关于如何做到这一点的任何信息吗?否则我可以自己谷歌一下。感谢您的提示。似乎 chromium 错误已作为版本控制问题关闭,但我在 Android as per this website 上使用最新版本的 WebRTC SDK,并且可能是最新版本的 chrome。所以 - 我不认为这是因为图书馆太旧了,但我会研究 H264 的事情。 将字符串“H264”的所有实例替换为“this-codec-is-not-supported”对于第一次测试应该足够了。 非常感谢菲利普的建议。您的建议使我走上了追求硬件编码的道路,并让我发现我的对等连接工厂存在错误,导致我没有在 Android 客户端正确启用硬件编码/解码。一旦我完成了这些修复,它让我走上了一条充满其他错误和问题的道路,但最终导致我有了一个可行的解决方案。当我有时间时,我会用确切的过程回答我自己的问题。但感谢您的建议,正是它让我得到了答案。 总是h264硬件编码:-) 【参考方案1】:

由于包含 H264 编解码器的报价而触发了错误消息,而 Android 客户端未预期 H264 并且未设置为对该特定硬件编码流进行编码和/或解码。

修复是确保连接工厂设置如下:

    private void createPeerConnectionFactory() 
        PeerConnectionFactory.InitializationOptions initializationOptions =
                PeerConnectionFactory.InitializationOptions.builder(this)
                        .createInitializationOptions();

        PeerConnectionFactory.initialize(initializationOptions);
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();

        VideoEncoderFactory encoderFactory = new DefaultVideoEncoderFactory(rootEglBase.getEglBaseContext(), true, true);
        VideoDecoderFactory decoderFactory = new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext());

        peerConnectionFactory = PeerConnectionFactory.builder()
                .setOptions(options)
                .setVideoDecoderFactory(decoderFactory)
                .setVideoEncoderFactory(encoderFactory)
                .createPeerConnectionFactory();

        List<PeerConnection.IceServer> iceServers = new ArrayList<>();
        PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers);
        createPeerConnection(rtcConfig);
    

rootEglBase 之前是通过在活动中定义一个变量(如 private EglBase rootEglBase;)来设置的,然后在活动 onCreate 方法中使用 EglBase.create() 创建它的新实例。

peerConnectionFactory 中的实际获胜线是定义 encoderFactorydecoderFactory 并指定正确的标志来告诉 WebRTC 我们要使用 h264HighProfile。

在这一行中可以看到: VideoEncoderFactory encoderFactory = new DefaultVideoEncoderFactory(rootEglBase.getEglBaseContext(), true, true);

第一个true boolean 用于启用VP8 编码,第二个用于H264

一旦设置正确,它会在尝试setRemoteDescription 时接受报价,并引导我走上正确的道路,以解决我的代码中仍然存在的许多其他问题。

因此,如果您收到相同的错误消息,可能是因为某种形式的硬件编码可能与 H264 有关。

如果您发现这个问题和我的答案,但它不太有意义,那么只需给我发私信或对此答案发表评论,我会尽力帮助您使其正常工作。

【讨论】:

伙计,我希望我在半年前就找到了你的帖子! 我在 WebView 中接收 webrtc 流时遇到了同样的问题,但我不确定如何继续,因为我认为我无法设置编码器/解码器。我尝试为应用启用硬件加速,但无济于事。 @Lior 您可以尝试手动操作 SDP。如果您查看我的原始问题,您会发现我提供了 SDP;并且一些 cmets 正在谈论从 SDP 本身中删除某些编码器/解码器。不确定您的代码是什么样的,但我假设您将在 JavaScript 中使用服务器,然后this article might help you。 还有@Lior;不确定您的背景,但如果您可能是 WebRTC 新手,那么 MDN WebRTC API docs 非常有用,尤其是 description of the SDP 可能对您有用。

以上是关于为啥我在 Chrome 中运行时在 Android 中收到“无法为 m-section 设置远程视频描述发送参数,mid='0'”错误?的主要内容,如果未能解决你的问题,请参考以下文章

在 chrome 中运行时,cordova.js 不可用

在Android Studio终端中运行时出现IO异常[重复]

为啥我的代码在线程 6:NSOperationQueue 中运行时会崩溃?

当程序在 IntelliJ 中运行时,为啥我会收到 SSLHandshakeException 作为 JAR?

为啥实体框架在不同的 AppDomain 中运行时会明显变慢?

为啥在火花中运行时配置单元查询不起作用