{"id":762,"date":"2022-06-26T16:33:22","date_gmt":"2022-06-26T08:33:22","guid":{"rendered":"https:\/\/www.fanyamin.com\/wordpress\/?p=762"},"modified":"2022-06-26T16:33:22","modified_gmt":"2022-06-26T08:33:22","slug":"webrtc-simulcast","status":"publish","type":"post","link":"https:\/\/www.fanyamin.com\/wordpress\/?p=762","title":{"rendered":"WebRTC Simulcast"},"content":{"rendered":"<h1>\u7b80\u4ecb<\/h1>\n<p>Simulcast \u53ef\u4ee5\u7ffb\u8bd1\u6210\u8054\u64ad\uff0c\u4e0d\u662f\u65b0\u95fb\u8054\u64ad\uff0c\u800c\u662f\u591a\u4e2a\u5a92\u4f53\u6d41\u7684\u4f20\u64ad\uff0c\u5982\u56fe\u6240\u793a<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/upload-images.jianshu.io\/upload_images\/1598924-27afe561467d4f56.png?imageMogr2\/auto-orient\/strip%7CimageView2\/2\/w\/1240\" alt=\"\" \/><\/p>\n<p>\u6ce8: SFU \u5373 Selective Forward Unit, \u5a92\u4f53\u8f6c\u53d1\u670d\u52a1\u5668<\/p>\n<p>\u521a\u5f00\u59cb\uff0c\u53d1\u9001\u65b9 sender \u53d1\u9001\u4e00\u8def 1080p \u7684\u89c6\u9891\u6d41\u7ed9\u670d\u52a1\u5668 SFU\uff0c SFU \u518d\u8f6c\u53d1\u7ed9\u591a\u4e2a\u63a5\u6536\u65b9 receiver1, receiver2 \u548c receiver3\u3002<\/p>\n<p>\u4e00\u4f1a\u513f\uff0creceiver 2 \u548c receiver 3 \u901a\u8fc7 RTCP \u53cd\u9988\u5e26\u5bbd\u4e0d\u591f\uff0c\u4e22\u5305\u7387\u548c\u5ef6\u8fdf\u90fd\u6bd4\u8f83\u5927\uff0c\u4e5f\u5c31\u662f\u8bf4<\/p>\n<ul>\n<li>\u4e0a\u884c\u5e26\u5bbd\u5bf9\u4e8e  sender \u662f\u8db3\u591f\u7684\uff0c<\/li>\n<li>\u4e0b\u884c\u5e26\u5bbd\u5bf9\u4e8e  receiver 1 \u4e5f\u662f\u6ca1\u95ee\u9898\u7684 <\/li>\n<li>\u4e0b\u884c\u5e26\u5bbd\u5bf9\u4e8e receiver 2 \u548c receiver 3 \u90fd\u6709\u95ee\u9898<\/li>\n<\/ul>\n<p>\u8fd9\u6837\u8054\u64ad\u7684\u597d\u5904\u5c31\u6765\u4e86\uff0cSFU \u53ef\u4ee5\u6839\u636e\u5e26\u5bbd\u8bc4\u4f30\u7684\u7ed3\u679c\u8ba9 Sender \u540c\u65f6\u53d1\u9001 1080p, 360p \u548c 180p \u4e09\u8def\u6d41\uff0c\u5e76\u5206\u522b\u8f6c\u53d1\u7ed9 receiver1,  receiver 2 \u548c receiver 3\u3002<\/p>\n<p>\u4e3a\u4e86\u8ba9\u6d4f\u89c8\u5668\u548c\u670d\u52a1\u5668\u90fd\u652f\u6301 simulcast \uff0c\u6211\u4eec\u9700\u8981\u5728 SDP \u548c RTP \u5305\u683c\u5f0f\u4e0a\u505a\u51fa\u4e9b\u6269\u5c55\uff0c\u76ee\u7684\u662f\u8ba9 SFU \u548c\u63a5\u6536\u7aef\u77e5\u9053\u54ea\u51e0\u8def\u6d41\u662f\u96b6\u5c5e\u4e8e\u4e00\u4e2a\u5a92\u4f53\u6e90\u7684\uff0c\u800c\u4e14\u5b83\u4eec\u7684\u53c2\u6570\u662f\u591a\u5c11, \u4f8b\u5982<\/p>\n<ul>\n<li>\u5e26\u5bbdbitrate<\/li>\n<li>\u5206\u8fa8\u7387 resolution<\/li>\n<li>\u5e27\u7387 frameRate<\/li>\n<\/ul>\n<p><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc8853\">RFC8853<\/a> \u5bf9\u6b64\u6709\u8be6\u7ec6\u9610\u8ff0<\/p>\n<h1>\u672f\u8bed<\/h1>\n<ul>\n<li>\n<p>Simulcast stream:   \u4e00\u7ec4\u540c\u65f6\u4f20\u8f93\u7684\u5a92\u4f53\u7f16\u7801\u6d41\u548c\u53ef\u9009\u7684\u4f9d\u8d56\u7684\u5a92\u4f53\u6d41\u5176\u4e2d\u4e2d\u7684\u4e00\u4e2a\u5a92\u4f53\u6d41\uff0c\u5b83\u4eec\u90fd\u5171\u4eab\u4e00\u4e2a\u5171\u540c\u7684\u5a92\u4f53\u6e90 (media source\uff0c\u4f8b\u5982\u4e00\u4e2a\u6444\u50cf\u5934) \uff0c\u5982 <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc7656\">RFC7656<\/a> \u4e2d\u6240\u5b9a\u4e49\u3002<br \/>\n\u4f8b\u5982\uff0c\u5355\u4e2a\u5a92\u4f53\u6e90\u7684\u9ad8\u6e05\u56fe\u50cf\u548c\u7f29\u7565\u56fe\u50cf\u7684\u89c6\u9891\u6d41\u7531\u8054\u64ad\u5404\u81ea\u4f5c\u4e3a\u5355\u72ec\u7684 RTP \u6d41\u540c\u65f6\u53d1\u9001\u3002<\/p>\n<\/li>\n<li>\n<p>Simulcast format:  simulcast stream \u7684\u4e0d\u540c\u683c\u5f0f\u4e0e\u975e simulcast stream \u7684 SDP \u4e2d\u7684\u66ff\u4ee3 RTP \u6709\u6548payload \u7c7b\u578b\u5177\u6709\u76f8\u540c\u7684\u76ee\u7684\uff1a\u5141\u8bb8\u6307\u5b9a RTP \u6d41\u4e2d\u4f7f\u7528\u591a\u79cd\u4e0d\u540c\u7684\u53ef\u66ff\u4ee3\u7684\u5a92\u4f53\u683c\u5f0f\u3002 <\/p>\n<\/li>\n<\/ul>\n<p>\u5bf9\u4e8e\u5728 SDP Offer\/Answer \u4e2d\u7684  m-line \u91cc\u6709\u591a\u4e2a RTP payload \u7684\u60c5\u5f62\uff0c\u4efb\u4f55\u4e00\u79cd\u534f\u5546\u7684\u66ff\u4ee3\u683c\u5f0f\u90fd\u53ef\u4ee5\u5728\u7ed9\u5b9a\u7684\u65f6\u95f4\u70b9\u5728\u5355\u4e2a RTP \u6d41\u4e2d\u4f7f\u7528\uff0c\u4f46\u4e0d\u8d85\u8fc7\u4e00\u79cd\uff08\u57fa\u4e8e RTP \u65f6\u95f4\u6233 \uff09, \u6362\u53e5\u8bdd\u8bf4\uff0c\u5373\u540c\u4e00\u65f6\u523b\u7684\u5355\u4e2a  RTP stream \u4e2d\u4e0d\u4f1a\u6709\u591a\u79cd Payload.\u4f7f\u7528\u7684\u683c\u5f0f\u53ef\u4ee5\u4ece\u4e00\u4e2a RTP \u6570\u636e\u5305\u52a8\u6001\u66f4\u6539\u4e3a\u53e6\u4e00\u4e2a\u3002<\/p>\n<h1>SDP \u5bf9\u4e8e Simulcast \u7684\u652f\u6301<\/h1>\n<p>\u5728 SDP \u6269\u5c55\u4e2d\uff0c\u4e3b\u8981\u6709\u4e24\u79cd\u65b9\u6cd5\u6765\u544a\u77e5\u670d\u52a1\u5668\u53ca\u63a5\u6536\u65b9\u54ea\u4e9b\u6d41\u662f simulcast stream<\/p>\n<p>1) SSRC Group: \u5c06 simulcast streams \u653e\u7f6e\u5728\u4e00\u4e2a\u4e2a\u7ec4\u4e2d<br \/>\n2) RtpStreamId: \u4e3a simulcast streams \u52a0\u4e00\u4e2a\u6807\u8bc6\uff0c\u5e76\u5728 RTP \u5305\u4e2d\u643a\u5e26\u3002<\/p>\n<h2>1) SSRC Group<\/h2>\n<p>\u65e9\u671f\u4e3a\u4e86\u652f\u6301 RTX(RTP Retransmission Payload Format) , \u53c2\u89c1<a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc4588\">RFC4588<\/a> , SDP \u652f\u6301\u7528 SSRC group \u7684\u65b9\u5f0f\u6765\u58f0\u660e\u5a92\u4f53\u6d41\u548c\u91cd\u4f20\u6d41\u4e4b\u95f4\u7684\u5173\u7cfb<\/p>\n<p>\u5982\u4e0b\u4f8b\u6240\u793a\uff0c\u8fd9\u91cc\u6709\u4e24\u8def\u6d41\uff0c\u4e00\u8def\u6d41\u662f 6596, \u53e6\u4e00\u8def\u6d41\u662f9814\uff0c\u5b83\u4eec\u5176\u5b9e\u8fd8\u662f\u5355\u6d41 9814 \u662f\u7528\u6765\u91cd\u4f20\u4e22\u5931\u5305\u7684 retransmission\u7684\uff0c \u7528\u4e00\u4e2a FID ssrc-group \u5c06\u5b83\u4eec\u5173\u8054\u8d77\u6765<\/p>\n<pre><code>a=ssrc:659652645 cname:Taj3\/ieCnLbsUFoH\na=ssrc:659652645 msid:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk 028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:659652645 mslabel:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk\na=ssrc:659652645 label:028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:98148385 cname:Taj3\/ieCnLbsUFoH\na=ssrc:98148385 msid:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk 028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:98148385 mslabel:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk\na=ssrc:98148385 label:028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc-group:FID 659652645 98148385\n<\/code><\/pre>\n<p>\u4e3a\u652f\u6301\u591a\u6d41(multi stream)\u548c\u8054\u64ad(simulcast) \uff0c \u53c8\u5f15\u5165\u4e86 SIM ssrc group, \u4f8b\u5982:<\/p>\n<pre><code>a=ssrc:659652645 cname:Taj3\/ieCnLbsUFoH\na=ssrc:659652645 msid:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk 028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:659652645 mslabel:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk\na=ssrc:659652645 label:028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:98148385 cname:Taj3\/ieCnLbsUFoH\na=ssrc:98148385 msid:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk 028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:98148385 mslabel:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk\na=ssrc:98148385 label:028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:1982135572 cname:Taj3\/ieCnLbsUFoH\na=ssrc:1982135572 msid:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk 028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:1982135572 mslabel:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk\na=ssrc:1982135572 label:028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:2523084908 cname:Taj3\/ieCnLbsUFoH\na=ssrc:2523084908 msid:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk 028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:2523084908 mslabel:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk\na=ssrc:2523084908 label:028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:3604909222 cname:Taj3\/ieCnLbsUFoH\na=ssrc:3604909222 msid:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk 028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:3604909222 mslabel:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk\na=ssrc:3604909222 label:028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:1893605472 cname:Taj3\/ieCnLbsUFoH\na=ssrc:1893605472 msid:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk 028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc:1893605472 mslabel:i1zOaprU7rZzMDaOXFdqwkq7Q6wP6f3cgUgk\na=ssrc:1893605472 label:028ab73b-cdd0-4b61-a282-ea0ed0c6a9bb\na=ssrc-group:SIM 659652645 1982135572 3604909222\na=ssrc-group:FID 659652645 98148385\na=ssrc-group:FID 1982135572 2523084908\na=ssrc-group:FID 3604909222 1893605472<\/code><\/pre>\n<p>\u53ef\u4ee5\u4ece\u4e0a\u9762\u7684 SDP \u5f97\u77e5\uff0c \u6709\u4e09\u8def\u6d41, SSRC \u5206\u522b\u4e3a 659652645, 1982135572, 3604909222, \u5b83\u4eec\u4e3a\u4e00\u4e2a\u8054\u64ad\u7ec4 simulcast group\uff0c\u8868\u793a\u4e3a\u65f6\u95f4\u4e0a(temporal layers)\u6216\u7a7a\u95f4\u4e0a(spatial layers)\u4e0d\u540c\u7684\u8d28\u91cf\u7684\u5a92\u4f53\u6d41\uff08frameRate \u6216 resolution \u4e0d\u540c\uff09\uff0c\u6bcf\u4e00\u8def\u6d41\u53c8\u6709\u5404\u81ea\u7684\u91cd\u4f20\u6d41\uff0c\u4e00\u5171\u6709 3 * 2 = 6 \u4e2a  ssrc\uff0c Chrome and Safari \u6309\u7167\u8d28\u91cf\u7684\u9012\u589e\u987a\u5e8f i (low, medium and high quality) \u6765\u6392\u5217  SSRCs<\/p>\n<p>\u8fd9\u79cd\u65b9\u6cd5\u663e\u7136\u4e0d\u592a\u597d\uff0c\u4e00\u662f\u6bd4\u8f83\u7e41\u7410\uff0c\u4e8c\u662f\u6ca1\u6709\u663e\u5f0f\u7684\u6307\u660e\u6bcf\u8def\u6d41\u7684\u53c2\u6570<br \/>\n<a href=\"https:\/\/w3c.github.io\/webrtc-pc\/\">https:\/\/w3c.github.io\/webrtc-pc\/<\/a> \u6807\u51c6\u4e2d 5.4.1 Simulcast functionality \u63d0\u5230<\/p>\n<p>Simulcast \u7ecf\u5e38\u7528\u4e8e\u5411 SFU \u53d1\u9001\u591a\u4e2a\u7f16\u7801\uff0c\u7136\u540e SFU \u4f1a\u5c06\u5176\u4e2d\u4e00\u4e2a\u6216\u51e0\u4e2a Simulcast \u6d41\u8f6c\u53d1\u7ed9\u4e0d\u540c\u7684\u6700\u7ec8\u7528\u6237\u3002 \u56e0\u6b64\uff0cSFU \u9700\u8981\u5728\u4e0d\u540c\u7684\u7f16\u7801\u4e4b\u95f4\u5206\u914d\u5408\u7406\u7684\u5e26\u5bbd\uff0c\u4ee5\u4f7f\u6240\u6709 Simulcast \u6d41\u90fd\u53ef\u4ee5\u4f7f\u7528\u5404\u81ea\u62e5\u6709\u7684\u5e26\u5bbd\uff1b \u4f8b\u5982\uff0c\u5982\u679c\u4e24\u4e2aSimulcast \u6d41 \u5177\u6709\u76f8\u540c\u7684 <code>maxBitrate<\/code> \u53c2\u6570\uff0c\u4eba\u4eec\u4f1a\u671f\u671b\u5728\u4e24\u4e2a\u6d41\u4e0a\u770b\u5230\u76f8\u4f3c\u7684\u6bd4\u7279\u7387\u3002 \u5982\u679c\u5e26\u5bbd\u4e0d\u5141\u8bb8\u6240\u6709simulcast \u6d41\u4ee5\u53ef\u7528\u7684\u5f62\u5f0f\u53d1\u9001\uff0cSFU \u5e94\u8be5\u505c\u6b62\u53d1\u9001\u4e00\u4e9b simulcast \u6d41\uff0c\u6216\u8005\u8981\u6c42\u53d1\u9001\u6539\u53d8\u53d1\u9001\u53c2\u6570\u3002<\/p>\n<p>\u53d1\u9001\u7aef\u4f1a\u53d1\u9001\u4e00\u4e2a\u6216\u591a\u4e2a simulcast \u6d41, \u6216\u8005\u5728\u4e0d\u540c\u53c2\u6570(\u7801\u7387\uff0c\u5206\u8fa8\u7387\uff0c\u5e27\u7387\u7b49) \u7684\u6d41\u4e4b\u95f4\u5207\u6362\uff0c\u8fd9\u4e9b\u6d41\u6709\u72ec\u81ea\u7684 SSRC \u548c SequenceNumber \u7a7a\u95f4\uff0c\u8fd9\u5bf9 SFU \u548c\u63a5\u6536\u7aef\u90fd\u6709\u4e00\u5b9a\u7684\u8981\u6c42<\/p>\n<h2>2) RtpStreamId<\/h2>\n<p>\u8fd9\u79cd\u65b9\u6cd5\u4e5f\u662f <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc8853\">RFC8853<\/a> \u4e2d\u7684\u63a8\u8350\u505a\u6cd5\uff0c\u4e3a RTP \u5305\u589e\u52a0\u4e00\u4e2a\u6269\u5c55\u5934 RtpStreamId\uff0c \u5728 SDP \u4e2d\u4e3a\u4e0d\u540c\u7684 simulcast \u6d41\u58f0\u660e\u4e00\u4e2a rid \u6807\u8bc6\u3002 \u4f8b\u5982,  SDP Offer \u5982\u4e0b<\/p>\n<ul>\n<li>SDP Offer<\/li>\n<\/ul>\n<pre><code>   m=video 49300 RTP\/AVP 97 98 99\n   a=rtpmap:97 H264\/90000\n   a=rtpmap:98 H264\/90000\n   a=rtpmap:99 VP8\/90000\n   a=fmtp:97 profile-level-id=42c01f;max-fs=3600;max-mbps=108000\n   a=fmtp:98 profile-level-id=42c00b;max-fs=240;max-mbps=3600\n   a=fmtp:99 max-fs=240; max-fr=30\n   a=rid:1 send pt=97;max-width=1280;max-height=720\n   a=rid:2 send pt=98;max-width=320;max-height=180\n   a=rid:3 send pt=99;max-width=320;max-height=180\n   a=rid:4 recv pt=97\n   a=simulcast:send 1;2,3 recv 4\n   a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\n<\/code><\/pre>\n<p>\u63d0\u4f9b\u8005\u80fd\u591f\u53d1\u9001\u4e24\u4e2a\u8054\u64ad RTP \u6d41\uff1a\u4e00\u4e2a\u9ad8\u8fbe 720p \u5206\u8fa8\u7387\u7684 H.264 \u7f16\u7801\u6d41\uff0c\u4ee5\u53ca\u4e00\u4e2a\u7f16\u7801\u4e3a H.264 \u6216 VP8 \u7684\u9644\u52a0\u6d41\uff0c\u6700\u5927\u5206\u8fa8\u7387\u4e3a 320x180 \u50cf\u7d20\u3002 \u63d0\u4f9b\u8005\u53ef\u4ee5\u63a5\u6536\u4e00\u4e2a\u6700\u5927 720p \u5206\u8fa8\u7387\u7684 H.264 \u6d41<\/p>\n<ul>\n<li>SDP Answer<\/li>\n<\/ul>\n<pre><code>   m=video 49674 RTP\/AVP 97 98\n   a=rtpmap:97 H264\/90000\n   a=rtpmap:98 H264\/90000\n   a=fmtp:97 profile-level-id=42c01f;max-fs=3600;max-mbps=108000\n   a=fmtp:98 profile-level-id=42c00b;max-fs=240;max-mbps=3600\n   a=rid:1 recv pt=97;max-width=1280;max-height=720\n   a=rid:2 recv pt=98;max-width=320;max-height=180\n   a=rid:4 send pt=97\n   a=simulcast:recv 1;2 send 4\n   a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id<\/code><\/pre>\n<p>\u5728\u8fd9\u4e2a SDP \u5e94\u7b54\u4e2d\uff0c\u201crecv\u201d\u90e8\u5206\u8868\u660e\u5b83\u60f3\u8981\u63a5\u6536\u4e24\u4e2aH264 \u7f16\u7801\u7684 Simulcast \u6d41\u3002 \u5e76\u5df2\u7ecf\u5220\u9664\u4e86\u5b83\u4e0d\u652f\u6301\u7684 VP8 \u7f16\u7801\u7684 Simulcast \u6d41\uff08rid=3\uff09\u3002 \u201c\u53d1\u9001\u201d\u90e8\u5206\u5411 offer \u65b9\u786e\u8ba4\u5b83\u5c06\u6839\u636e rid=4  \u6765\u53d1\u9001\u4e00\u4e2a\u5a92\u4f53\u6d41<\/p>\n<h1>\u8054\u64ad\u548c\u5197\u4f59<\/h1>\n<p>\u4e3a\u4e86\u63d0\u9ad8\u6297\u4e22\u5305\u7684\u80fd\u529b\uff0c\u5728\u53d1\u9001 Simulcast \u6d41\u65f6\uff0c\u901a\u5e38\u6211\u4eec\u4f1a\u53d1\u9001\u4e00\u4e9b\u5197\u4f59\u7684 RTP \u5305\uff0c\u5f53\u4e00\u4e9b\u5305\u4e22\u5931\u4e86\uff0c\u6211\u4eec\u53ef\u4ee5\u5728\u63a5\u6536\u7aef\u901a\u8fc7\u5197\u4f59\u5305\u6765\u6062\u590d\uff0c\u5e38\u7528\u7684\u65b9\u6cd5\u6709 FEC \u548c RTX\u3002 \u4e3a\u4e86\u8ba9\u5927\u5bb6\u77e5\u9053\u5197\u4f59\u5305\u6240\u5728\u7684\u5a92\u4f53\u6d41\uff0c\u6211\u4eec\u57fa\u4e8e RtpStreamId(rid) \u7684\u65b9\u6848\u53ef\u4ee5\u518d\u5f15\u5165\u4e00\u5e74 RepeairedRtpStreamId - rrid<\/p>\n<p>\u4f8b\u5982\uff0c\u5bf9\u4e8e\u5355\u6d41\u7684\u60c5\u51b5\uff0c\u4e00\u8def\u5a92\u4f53\u6d41\uff0c\u4e00\u8def\u5a92\u4f53\u5197\u4f59\u6d41\uff0c\u53ea\u9700\u8981\u901a\u8fc7 payload type \u7684\u4e0d\u540c\u5c31\u53ef\u4ee5\u533a\u5206\u51fa\u6765\u4e86<\/p>\n<pre><code>   v=0\n   o=mascha 2980675221 2980675778 IN IP4 host.example.net\n   c=IN IP4 192.0.2.0\n   a=group:FID 1 2\n   a=group:FID 3 4\n   m=audio 49170 RTP\/AVPF 96\n   a=rtpmap:96 AMR\/8000\n   a=fmtp:96 octet-align=1\n   a=rtcp-fb:96 nack\n   a=mid:1\n   m=audio 49172 RTP\/AVPF 97\n   a=rtpmap:97 rtx\/8000\n   a=fmtp:97 apt=96;rtx-time=3000\n   a=mid:2\n   m=video 49174 RTP\/AVPF 98\n   a=rtpmap:98 MP4V-ES\/90000\n   a=rtcp-fb:98 nack\n   a=fmtp:98 profile-level-id=8;config=01010000012000884006682C209\\\n   0A21F\n   a=mid:3\n   m=video 49176 RTP\/AVPF 99\n   a=rtpmap:99 rtx\/90000\n   a=fmtp:99 apt=98;rtx-time=3000\n   a=mid:4<\/code><\/pre>\n<p>\u4e0a\u4f8b\u4e2d\u901a\u8fc7 <code> a=fmtp:99 apt=98;rtx-time=3000<\/code> \u6211\u4eec\u5c31\u77e5\u9053\u8fd9\u8def\u6d41\u662f RTX \u6d41\uff0c\u5b83\u7684 payload type \u662f99\uff0c \u800c\u5b83\u6240\u8981\u4fee\u590d\u7684\u6d41\u7684 Payload type \u662f98\u3002<\/p>\n<p>\u4f46\u662f\u5bf9\u4e8e\u591a\u8def Simulcast \u6d41\uff0c\u4ec5\u4ec5\u7528 payload type \u6765\u533a\u5206\u5c31\u4e0d\u591f\u4e86\uff0c\u5047\u8bbe\u7528\u4e09\u8def\u5a92\u4f53\u6d41, \u5b83\u4eec\u7684\u5206\u8fa8\u7387\u4e0d\u540c\uff0c\u4f46\u662f payload type \u90fd\u4e00\u6837\uff0c\u4e0d\u8fc7 rid \u662f\u4e0d\u4e00\u6837\u7684\uff0c\u540c\u65f6\uff0c\u6bcf\u4e00\u8def\u6d41\u8fd8\u6709\u76f8\u5e94\u7684\u5197\u4f59\u6d41\uff0c\u8fd9\u5c31\u6709\u70b9\u9ebb\u70e6\u4e86\u3002\u8fd9\u65f6\u5019\uff0c\u6211\u4eec\u53ef\u4ee5\u5f15\u5165 rrid(repaired-rtp-stream-id)<\/p>\n<p>RFC 8853 \u4e2d\u4e3e\u4e86\u4e00\u4e2a\u4f8b\u5b50\uff0c\u4f7f\u7528\u4e86\u97f3\u89c6\u9891\u7684 Simulcast \u548c\u5197\u4f59(FEC\/RTX)\u683c\u5f0f\u3002<\/p>\n<ul>\n<li>Audio SDP Offer \u4f7f\u7528\u4e86\u7f16\u89e3\u7801\u5668\u548c\u6bd4\u7279\u7387\u9650\u5236\uff0c\u7ed3\u5408\u4e86\u5197\u4f59\u97f3\u9891\u6570\u636e RED [RFC2198] \u4ee5\u589e\u5f3a\u4e22\u5305\u5f39\u6027\u3002<\/li>\n<\/ul>\n<p>\u97f3\u9891\u4f5c\u4e3a\u4e24\u4e2a Simulcast \u6d41\u53d1\u9001\u3002\u7b2c\u4e00\u4e2aSimulcast \u6d41\u4f7f\u7528 Opus \u7f16\u7801\uff0c\u9650\u5236\u4e3a 64 kbps (rid=1)\uff0c\u7b2c\u4e8c\u4e2aSimulcast \u6d41 (rid-id=2) \u88ab\u7f16\u7801\u4e0e G.711 \u6216 G.711 \u7ed3\u5408\u7ebf\u6027\u9884\u6d4b\u7f16\u7801 (LPC) \u7528\u4e8e\u5197\u4f59\u548c\u663e\u5f0f\u8212\u9002\u566a\u58f0 (CN)\u3002\u4e24\u4e2a Simulcast  \u6d41\u90fd\u5305\u62ec\u4e86 Telephony Event \u529f\u80fd( \u7528\u4e8e DTMF \u4f20\u8f93)\u3002<\/p>\n<p>\u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c \u5355\u72ec\u7684 LPC \u4e0d\u4f5c\u4e3a\u7b2c\u4e8c\u4e2a\u53ef\u80fd\u7684\u6709\u6548\u8f7d\u8377\u7c7b\u578b\u63d0\u4f9b Simulcast \u6d41\u7684 RID\uff0c\u5176\u52a8\u673a\u53ef\u80fd\u662f\u5176\u4e0d\u63d0\u4f9b\u8db3\u591f\u597d\u7684\u97f3\u9891\u8d28\u91cf\u3002<\/p>\n<ul>\n<li>Video SDP Offer \u5e94\u7528\u4e86\u5206\u8fa8\u7387\u548c\u6bd4\u7279\u7387\u7684\u9650\u5236\uff0c\u5e76\u7ed3\u5408\u4e86\u524d\u5411\u7ea0\u9519 (FEC)  <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc8627\">RFC8627<\/a> \u548c RTP \u91cd\u4f20 <a href=\"4588\">RFC4588<\/a>\u3002<\/li>\n<\/ul>\n<p>\u89c6\u9891\u6e90\u53ef\u4f5c\u4e3a\u4e24\u4e2aSimulcast\u6d41\u53d1\u9001\uff0c\u5747\u5177\u6709\u4e24\u79cd\u53ef\u9009Simulcast\u683c\u5f0f\u3002 \u5197\u4f59\u548c\u4fee\u590d\u4ee5 Flexible FEC \u548c RTP \u91cd\u4f20\u7684\u5f62\u5f0f\u63d0\u4f9b\u3002 Flexible FEC \u4e0d\u7ed1\u5b9a\u5230\u4efb\u4f55\u7279\u5b9a\u7684 RTP \u6d41\uff0c\u56e0\u6b64\u80fd\u591f\u5728\u4f5c\u4e3a\u8be5\u5a92\u4f53\u63cf\u8ff0\u7684\u4e00\u90e8\u5206\u53d1\u9001\u7684\u6240\u6709 RTP \u6d41\u4e2d\u4f7f\u7528\u3002<\/p>\n<pre><code>   o=fred 238947129 823479223 IN IP6 2001:db8::c000:27d\n   s=Offer from Simulcast-Enabled Client using Redundancy\n   c=IN IP6 2001:db8::c000:27d\n   t=0 0\n   a=group:BUNDLE foo bar\n   m=audio 49200 RTP\/AVP 97 98 99 100 101 102\n   a=mid:foo\n   a=rtpmap:97 G711\/8000\n   a=rtpmap:98 LPC\/8000\n   a=rtpmap:99 OPUS\/48000\/1\n   a=rtpmap:100 RED\/8000\/1\n   a=rtpmap:101 CN\/8000\n   a=rtpmap:102 telephone-event\/8000\n   a=fmtp:99 useinbandfec=1;usedtx=0\n   a=fmtp:100 97\/98\n   a=fmtp:102 0-15\n   a=ptime:20\n   a=maxptime:40\n   a=rid:1 send pt=99,102;max-br=64000\n   a=rid:2 send pt=100,97,101,102\n   a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid\n   a=extmap:2 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\n   a=simulcast:send 1;2\n   m=video 49600 RTP\/AVPF 103 104 105 106 107\n   a=mid:bar\n   a=rtpmap:103 H264\/90000\n   a=rtpmap:104 VP8\/90000\n   a=rtpmap:105 rtx\/90000\n   a=rtpmap:106 rtx\/90000\n   a=rtpmap:107 flexfec\/90000\n   a=fmtp:103 profile-level-id=42c00d;max-fs=3600;max-mbps=108000\n   a=fmtp:104 max-fs=3600; max-fr=30\n   a=fmtp:105 apt=103;rtx-time=200\n   a=fmtp:106 apt=104;rtx-time=200\n   a=fmtp:107 repair-window=100000\n   a=rid:1 send pt=103;max-width=1280;max-height=720;max-fps=30\n   a=rid:2 send pt=104;max-width=1280;max-height=720;max-fps=30\n   a=rid:3 send pt=103;max-width=640;max-height=360;max-br=300000\n   a=rid:4 send pt=104;max-width=640;max-height=360;max-br=300000\n   a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid\n   a=extmap:2 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\n   a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\n   a=rtcp-fb:* ccm pause nowait\n   a=simulcast:send 1,2;3,4\n\n                 Figure 8: Simulcast and Redundancy Example<\/code><\/pre>\n<h1>WebRTC API \u5bf9\u4e8e Simulcast \u7684\u652f\u6301<\/h1>\n<p>WebRTC \u63d0\u4f9b\u4e86 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/RTCRtpEncodingParameters\">RTCRtpEncodingParameters<\/a> \u4f5c\u4e3a\u63a5\u53e3\uff0c\u5e94\u7528\u4e8e <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/RTCRtpSender\"><code>RTCRtpSender<\/code><\/a>.<\/p>\n<p>\u5c5e\u6027\u6709<\/p>\n<ul>\n<li>active<\/li>\n<\/ul>\n<p>If true, the described encoding is currently actively being used. That is, for RTP senders, the encoding is currently being used to send data, while for receivers, the encoding is being used to decode received data. The default value is true.<\/p>\n<ul>\n<li>codecPayloadType<\/li>\n<\/ul>\n<p>When describing a codec for an RTCRtpSender, codecPayloadType is a single 8-bit byte (or octet) specifying the codec to use for sending the stream; the value matches one from the owning RTCRtpParameters object's codecs parameter. This value can only be set when creating the transceiver; after that, this value is read only.<\/p>\n<ul>\n<li>dtx Deprecated<\/li>\n<\/ul>\n<p>Only used for an RTCRtpSender whose kind is audio, this property indicates whether or not to use discontinuous transmission (a feature by which a phone is turned off or the microphone muted automatically in the absence of voice activity). The value is taken either enabled or disabled.<\/p>\n<ul>\n<li>\n<p>maxBitrate<br \/>\nAn unsigned long integer indicating the maximum number of bits per second to allow for this encoding. Other parameters may further constrain the bit rate, such as the value of maxFramerate or transport or physical network limitations.<\/p>\n<\/li>\n<li>\n<p>maxFramerate<br \/>\nA value specifying the maximum number of frames per second to allow for this encoding.<\/p>\n<\/li>\n<li>\n<p>ptime<br \/>\nAn unsigned long integer value indicating the preferred duration of a media packet in milliseconds. This is typically only relevant for audio encodings. The user agent will try to match this as well as it can, but there is no guarantee.<\/p>\n<\/li>\n<li>\n<p>rid<br \/>\nA string which, if set, specifies an RTP stream ID (RID) to be sent using the RID header extension. This parameter cannot be modified using setParameters(). Its value can only be set when the transceiver is first created.<\/p>\n<\/li>\n<li>\n<p>scaleResolutionDownBy<br \/>\nOnly used for senders whose track's kind is video, this is a double-precision floating-point value specifying a factor by which to scale down the video during encoding. The default value, 1.0, means that the sent video's size will be the same as the original. A value of 2.0 scales the video frames down by a factor of 2 in each dimension, resulting in a video 1\/4 the size of the original. The value must not be less than 1.0 (you can't use this to scale the video up).<\/p>\n<\/li>\n<\/ul>\n<p>\u4ee3\u7801\u793a\u4f8b <a href=\"https:\/\/www.fanyamin.com\/webrtc\/examples\/local_peer_connection.html\">https:\/\/www.fanyamin.com\/webrtc\/examples\/local_peer_connection.html<\/a><\/p>\n<pre><code>                for(const audioTrack of local_stream.getAudioTracks()) {\n                    pc.addTransceiver(audioTrack, {direction:  WT.call.getDirection(), streams: [local_stream]});\n                }\n\n                var encodings = [\n                    {rid: &#039;high&#039;, maxBitrate: 2500000, active: true, priority: &quot;high&quot;},\n                    {rid: &#039;middle&#039;, maxBitrate: 1500000, active: true, scaleResolutionDownBy: 2.0},\n                    {rid: &#039;low&#039;, maxBitrate: 100000, active: true, scaleResolutionDownBy: 4.0}\n                ];\n\n                for(const videoTrack of local_stream.getVideoTracks()) {\n                    pc.addTransceiver(videoTrack, {direction:  WT.call.getDirection(), sendEncodings: encodings, streams: [local_stream]});\n                }<\/code><\/pre>\n<h1>\u53c2\u8003\u8d44\u6599<\/h1>\n<ul>\n<li><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc8872\">RFC8872<\/a>: Guidelines for Using the Multiplexing Features of RTP to Support Multiple Media Streams<\/li>\n<li><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc8108\">RFC8108<\/a>: Sending Multiple RTP Streams in a Single RTP Session<\/li>\n<li><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc4588\">RFC4588<\/a>: RTP Retransmission Payload Forma<\/li>\n<li><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc8852\">RFC8852<\/a>: RTP Stream Identifier Source Description (SDES)<\/li>\n<li><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc8830\">RFC8830<\/a> WebRTC MediaStream Identification in the Session Description Protocol<\/li>\n<li><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc8853\">RFC8853<\/a>:  Using Simulcast in Session Description Protocol (SDP) and RTP Sessions<\/li>\n<li><a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1164187\">https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1164187<\/a><\/li>\n<li><a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc7656\">RFC7656<\/a>: A Taxonomy of Semantics and Mechanisms for  Real-Time Transport Protocol (RTP) Sources<\/li>\n<li><a href=\"https:\/\/www.meetecho.com\/blog\/simulcast-janus-ssrc\/\">https:\/\/www.meetecho.com\/blog\/simulcast-janus-ssrc\/<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>\u7b80\u4ecb Simulcast \u53ef\u4ee5\u7ffb\u8bd1\u6210\u8054\u64ad\uff0c\u4e0d\u662f\u65b0\u95fb\u8054\u64ad\uff0c\u800c\u662f\u591a\u4e2a\u5a92\u4f53\u6d41\u7684\u4f20\u64ad\uff0c\u5982\u56fe\u6240\u793a \u6ce8: SFU \u5373 Selective Forward Unit, \u5a92\u4f53\u8f6c\u53d1\u670d\u52a1\u5668 \u521a\u5f00\u59cb\uff0c\u53d1\u9001\u65b9 sender \u53d1\u9001\u4e00\u8def 1080p \u7684\u89c6\u9891\u6d41\u7ed9\u670d\u52a1\u5668 SFU\uff0c SFU \u518d\u8f6c\u53d1\u7ed9\u591a\u4e2a\u63a5\u6536\u65b9 receiver1, receiver2 \u548c receiver3\u3002 \u4e00\u4f1a\u513f\uff0creceiver 2 \u548c receiver 3 \u901a\u8fc7 RTCP \u53cd\u9988\u5e26\u5bbd\u4e0d\u591f\uff0c\u4e22\u5305\u7387\u548c\u5ef6\u8fdf\u90fd\u6bd4\u8f83\u5927\uff0c\u4e5f\u5c31\u662f\u8bf4 \u4e0a\u884c\u5e26\u5bbd\u5bf9\u4e8e sender \u662f\u8db3\u591f\u7684\uff0c \u4e0b\u884c\u5e26\u5bbd\u5bf9\u4e8e receiver 1 \u4e5f\u662f\u6ca1\u95ee\u9898\u7684 \u4e0b\u884c\u5e26\u5bbd\u5bf9\u4e8e receiver 2 \u548c receiver 3 \u90fd\u6709\u95ee\u9898 \u8fd9\u6837\u8054\u64ad\u7684\u597d\u5904\u5c31\u6765\u4e86\uff0cSFU \u53ef\u4ee5\u6839\u636e\u5e26\u5bbd\u8bc4\u4f30\u7684\u7ed3\u679c\u8ba9 Sender \u540c\u65f6\u53d1\u9001 1080p, 360p \u548c 180p \u4e09\u8def\u6d41\uff0c\u5e76\u5206\u522b\u8f6c\u53d1\u7ed9 receiver1, receiver [&hellip;] <a class=\"read-more\" href=\"https:\/\/www.fanyamin.com\/wordpress\/?p=762\" title=\"Permanent Link to: WebRTC Simulcast\">&rarr;Read&nbsp;more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-762","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/762"}],"collection":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=762"}],"version-history":[{"count":2,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/762\/revisions"}],"predecessor-version":[{"id":779,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/762\/revisions\/779"}],"wp:attachment":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=762"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=762"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=762"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}