This reverts commit f9f71b91ae073fdd2b89ff9df1204835aa3137eb. Reason for revert: Looks like it's breaking WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise, see https://ci.chromium.org/buildbot/chromium.webrtc.fyi/Mac%20Tester/48322 (win and lin testers are also failing on the same test). [ RUN ] WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise [12743:4099:0305/082149.300326:WARNING:notification_platform_bridge_mac.mm(510)] AlertNotificationService: XPC connection invalidated. [12743:88323:0305/082150.773242:WARNING:embedded_test_server.cc(228)] Request not handled. Returning 404: /favicon.ico [12743:775:0305/082150.774044:INFO:CONSOLE(13)] "Requesting doGetUserMedia: constraints: {"audio":true,"video":true}", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082150.969262:INFO:CONSOLE(13)] "Returning request-callback-granted to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082150.983959:INFO:CONSOLE(13)] "Returning ok-got-stream to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.741587:INFO:CONSOLE(13)] "Requesting doGetUserMedia: constraints: {"audio":true,"video":true}", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.749225:INFO:CONSOLE(13)] "Returning request-callback-granted to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.754982:INFO:CONSOLE(13)] "Returning ok-got-stream to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.761516:INFO:CONSOLE(13)] "Returning ok-peerconnection-created to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12752:775:0305/082151.762047:WARNING:RTCPeerConnection.cpp(1151)] mediaConstraints is not a supported argument to addStream. [12752:775:0305/082151.762096:WARNING:RTCPeerConnection.cpp(1153)] mediaConstraints was [12743:775:0305/082151.762953:INFO:CONSOLE(13)] "Added local stream.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.763010:INFO:CONSOLE(13)] "Returning ok-added to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.767078:INFO:CONSOLE(13)] "Returning ok-peerconnection-created to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12755:775:0305/082151.767614:WARNING:RTCPeerConnection.cpp(1151)] mediaConstraints is not a supported argument to addStream. [12755:775:0305/082151.767660:WARNING:RTCPeerConnection.cpp(1153)] mediaConstraints was [12743:775:0305/082151.768452:INFO:CONSOLE(13)] "Added local stream.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.768523:INFO:CONSOLE(13)] "Returning ok-added to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.776171:INFO:CONSOLE(13)] "Returning ok-created to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.777197:INFO:CONSOLE(13)] "Returning ok-created to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12752:42755:0305/082151.777736:WARNING:mediasession.cc(353)] Duplicate id found. Reassigning from 104 to 127 [12752:42755:0305/082151.777766:WARNING:mediasession.cc(353)] Duplicate id found. Reassigning from 106 to 125 [12752:42755:0305/082151.777829:WARNING:mediasession.cc(353)] Duplicate id found. Reassigning from 103 to 124 [12752:42755:0305/082151.777850:WARNING:mediasession.cc(353)] Duplicate id found. Reassigning from 105 to 123 [12743:775:0305/082151.778835:INFO:CONSOLE(13)] "createOffer(): success.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.779780:INFO:CONSOLE(13)] "Returning ok-{"type":"offer","sdp":"v=0\r\no=- 3491235150284933882 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video data\r\na=msid-semantic: WMS Nb7epCcAUJwMKKzTV36r1RGOlNSIxBooVpgU\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:ySYi\r\na=ice-pwd:5E4b4cjl+QFLqPoIgvleZ4m4\r\na=ice-options:trickle\r\na=fingerprint:sha-256 94:ED:E9:BB:45:FF:BE:85:C2:98:E5:45:3A:AB:A9:4B:3B:F0:04:D7:B1:05:45:E9:6D:14:3C:FE:62:5C:23:03\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3632917417 cname:J9N+OjIJeArKjXXh\r\na=ssrc:3632917417 msid:Nb7epCcAUJwMKKzTV36r1RGOlNSIxBooVpgU 6e608085-751b-4945-8982-6f4aedf7bef6\r\na=ssrc:3632917417 mslabel:Nb7epCcAUJwMKKzTV36r1RGOlNSIxBooVpgU\r\na=ssrc:3632917417 label:6e608085-751b-4945-8982-6f4aedf7bef6\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 124 127 123 125 107 108\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:ySYi\r\na=ice-pwd:5E4b4cjl+QFLqPoIgvleZ4m4\r\na=ice-options:trickle\r\na=fingerprint:sha-256 94:ED:E9:BB:45:FF:BE:85:C2:98:E5:45:3A:AB:A9:4B:3B:F0:04:D7:B1:05:45:E9:6D:14:3C:FE:62:5C:23:03\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=420032\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:124 rtx/90000\r\na=fmtp:124 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:123 rtx/90000\r\na=fmtp:123 apt=127\r\na=rtpmap:125 red/90000\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 ulpfec/90000\r\na=ssrc-group:FID 1955312265 3021315394\r\na=ssrc:1955312265 cname:J9N+OjIJeArKjXXh\r\na=ssrc:1955312265 msid:Nb7epCcAUJwMKKzTV36r1RGOlNSIxBooVpgU 7cd84f82-8fa1-42ca-b0ac-326aa0925f05\r\na=ssrc:1955312265 mslabel:Nb7epCcAUJwMKKzTV36r1RGOlNSIxBooVpgU\r\na=ssrc:1955312265 label:7cd84f82-8fa1-42ca-b0ac-326aa0925f05\r\na=ssrc:3021315394 cname:J9N+OjIJeArKjXXh\r\na=ssrc:3021315394 msid:Nb7epCcAUJwMKKzTV36r1RGOlNSIxBooVpgU 7cd84f82-8fa1-42ca-b0ac-326aa0925f05\r\na=ssrc:3021315394 mslabel:Nb7epCcAUJwMKKzTV36r1RGOlNSIxBooVpgU\r\na=ssrc:3021315394 label:7cd84f82-8fa1-42ca-b0ac-326aa0925f05\r\nm=application 9 DTLS/SCTP 5000\r\nc=IN IP4 0.0.0.0\r\na=ice-ufrag:ySYi\r\na=ice-pwd:5E4b4cjl+QFLqPoIgvleZ4m4\r\na=ice-options:trickle\r\na=fingerprint:sha-256 94:ED:E9:BB:45:FF:BE:85:C2:98:E5:45:3A:AB:A9:4B:3B:F0:04:D7:B1:05:45:E9:6D:14:3C:FE:62:5C:23:03\r\na=setup:actpass\r\na=mid:data\r\na=sctpmap:5000 webrtc-datachannel 1024\r\n"} to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.781514:INFO:CONSOLE(13)] "setLocalDescription(): success.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12755:41731:0305/082151.782411:WARNING:channel.cc(1039)] Trying to cache the Absolute Send Time extension id but the SRTP is not active. [12752:43011:0305/082151.884258:WARNING:p2ptransportchannel.cc(638)] Jingle:Port[0x7fab620da600:audio:1:0:local:Net[en0:192.168.195.x/24:Ethernet]]: SetOption(5, 0) failed: 0 [12752:43011:0305/082151.884438:WARNING:p2ptransportchannel.cc(638)] Jingle:Port[0x7fab620dd000:video:1:0:local:Net[en0:192.168.195.x/24:Ethernet]]: SetOption(1, 65536) failed: 0 [12752:43011:0305/082151.884481:WARNING:p2ptransportchannel.cc(638)] Jingle:Port[0x7fab620dd000:video:1:0:local:Net[en0:192.168.195.x/24:Ethernet]]: SetOption(2, 65536) failed: 0 [12752:43011:0305/082151.884513:WARNING:p2ptransportchannel.cc(638)] Jingle:Port[0x7fab620dd000:video:1:0:local:Net[en0:192.168.195.x/24:Ethernet]]: SetOption(5, 0) failed: 0 [12755:41731:0305/082151.922410:WARNING:channel.cc(1039)] Trying to cache the Absolute Send Time extension id but the SRTP is not active. [12743:775:0305/082151.924626:INFO:CONSOLE(13)] "createAnswer(): success.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.925506:INFO:CONSOLE(13)] "Returning ok-{"type":"answer","sdp":"v=0\r\no=- 6096510228474213355 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video data\r\na=msid-semantic: WMS 7RUsJxsD5w2UmR1xiHiKSWHyYY8RVKSGT8hN\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:X54X\r\na=ice-pwd:VsLK5tJ8so82vOn1y+R72WBi\r\na=ice-options:trickle\r\na=fingerprint:sha-256 EC:A9:2D:A2:D9:44:F0:A4:EE:58:FC:32:DF:C4:8C:B0:FC:25:C3:08:BE:7E:D7:59:B8:A0:20:16:DA:5A:A5:7F\r\na=setup:active\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3234277340 cname:PfS0qqt1exijuETX\r\na=ssrc:3234277340 msid:7RUsJxsD5w2UmR1xiHiKSWHyYY8RVKSGT8hN 9ddb9a77-20aa-42ba-8540-9e32f3dbb0af\r\na=ssrc:3234277340 mslabel:7RUsJxsD5w2UmR1xiHiKSWHyYY8RVKSGT8hN\r\na=ssrc:3234277340 label:9ddb9a77-20aa-42ba-8540-9e32f3dbb0af\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 124 127 123 125 107 108\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:X54X\r\na=ice-pwd:VsLK5tJ8so82vOn1y+R72WBi\r\na=ice-options:trickle\r\na=fingerprint:sha-256 EC:A9:2D:A2:D9:44:F0:A4:EE:58:FC:32:DF:C4:8C:B0:FC:25:C3:08:BE:7E:D7:59:B8:A0:20:16:DA:5A:A5:7F\r\na=setup:active\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=420032\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:124 rtx/90000\r\na=fmtp:124 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:123 rtx/90000\r\na=fmtp:123 apt=127\r\na=rtpmap:125 red/90000\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 ulpfec/90000\r\na=ssrc-group:FID 3517790794 302440277\r\na=ssrc:3517790794 cname:PfS0qqt1exijuETX\r\na=ssrc:3517790794 msid:7RUsJxsD5w2UmR1xiHiKSWHyYY8RVKSGT8hN 2ffa90e8-b71e-463b-a105-d5a65e0ac205\r\na=ssrc:3517790794 mslabel:7RUsJxsD5w2UmR1xiHiKSWHyYY8RVKSGT8hN\r\na=ssrc:3517790794 label:2ffa90e8-b71e-463b-a105-d5a65e0ac205\r\na=ssrc:302440277 cname:PfS0qqt1exijuETX\r\na=ssrc:302440277 msid:7RUsJxsD5w2UmR1xiHiKSWHyYY8RVKSGT8hN 2ffa90e8-b71e-463b-a105-d5a65e0ac205\r\na=ssrc:302440277 mslabel:7RUsJxsD5w2UmR1xiHiKSWHyYY8RVKSGT8hN\r\na=ssrc:302440277 label:2ffa90e8-b71e-463b-a105-d5a65e0ac205\r\nm=application 9 DTLS/SCTP 5000\r\nc=IN IP4 0.0.0.0\r\nb=AS:30\r\na=ice-ufrag:X54X\r\na=ice-pwd:VsLK5tJ8so82vOn1y+R72WBi\r\na=ice-options:trickle\r\na=fingerprint:sha-256 EC:A9:2D:A2:D9:44:F0:A4:EE:58:FC:32:DF:C4:8C:B0:FC:25:C3:08:BE:7E:D7:59:B8:A0:20:16:DA:5A:A5:7F\r\na=setup:active\r\na=mid:data\r\na=sctpmap:5000 webrtc-datachannel 1024\r\n"} to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.925954:INFO:CONSOLE(13)] "Receiving remote stream...", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.926204:INFO:CONSOLE(13)] "setRemoteDescription(): success.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.939935:INFO:CONSOLE(13)] "Returning ok-verified to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.940232:INFO:CONSOLE(13)] "setLocalDescription(): success.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12752:43011:0305/082151.942049:WARNING:p2ptransportchannel.cc(1093)] SetOption(1, 65536) failed: 0 [12752:43011:0305/082151.942084:WARNING:p2ptransportchannel.cc(1093)] SetOption(2, 65536) failed: 0 [12743:775:0305/082151.946009:INFO:CONSOLE(13)] "Receiving remote stream...", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.946327:INFO:CONSOLE(13)] "setRemoteDescription(): success.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.946367:INFO:CONSOLE(13)] "Returning ok-accepted-answer to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082151.950048:INFO:CONSOLE(368)] "Still ICE gathering - waiting...", source: http://127.0.0.1:50666/webrtc/peerconnection.js (368) [12755:41731:0305/082152.030690:WARNING:p2ptransportchannel.cc(638)] Jingle:Port[0x7f8a9c809a00:audio:1:0:local:Net[en0:192.168.195.x/24:Ethernet]]: SetOption(1, 65536) failed: 0 [12755:41731:0305/082152.030759:WARNING:p2ptransportchannel.cc(638)] Jingle:Port[0x7f8a9c809a00:audio:1:0:local:Net[en0:192.168.195.x/24:Ethernet]]: SetOption(2, 65536) failed: 0 [12755:41731:0305/082152.030785:WARNING:p2ptransportchannel.cc(638)] Jingle:Port[0x7f8a9c809a00:audio:1:0:local:Net[en0:192.168.195.x/24:Ethernet]]: SetOption(5, 0) failed: 0 [12743:775:0305/082152.048464:INFO:CONSOLE(13)] "Returning [{"candidate":"candidate:2504140996 1 udp 2122260223 192.168.195.156 65179 typ host generation 0 ufrag X54X network-id 1","sdpMid":"audio","sdpMLineIndex":0},{"candidate":"candidate:3686913076 1 tcp 1518280447 192.168.195.156 9 typ host tcptype active generation 0 ufrag X54X network-id 1","sdpMid":"audio","sdpMLineIndex":0}] to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082152.049868:INFO:CONSOLE(13)] "Returning ok-received-candidates to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082152.050468:INFO:CONSOLE(13)] "Returning [{"candidate":"candidate:2504140996 1 udp 2122260223 192.168.195.156 60484 typ host generation 0 ufrag ySYi network-id 1","sdpMid":"audio","sdpMLineIndex":0},{"candidate":"candidate:2504140996 1 udp 2122260223 192.168.195.156 62030 typ host generation 0 ufrag ySYi network-id 1","sdpMid":"video","sdpMLineIndex":1},{"candidate":"candidate:2504140996 1 udp 2122260223 192.168.195.156 50175 typ host generation 0 ufrag ySYi network-id 1","sdpMid":"data","sdpMLineIndex":2},{"candidate":"candidate:3686913076 1 tcp 1518280447 192.168.195.156 9 typ host tcptype active generation 0 ufrag ySYi network-id 1","sdpMid":"audio","sdpMLineIndex":0},{"candidate":"candidate:3686913076 1 tcp 1518280447 192.168.195.156 9 typ host tcptype active generation 0 ufrag ySYi network-id 1","sdpMid":"video","sdpMLineIndex":1},{"candidate":"candidate:3686913076 1 tcp 1518280447 192.168.195.156 9 typ host tcptype active generation 0 ufrag ySYi network-id 1","sdpMid":"data","sdpMLineIndex":2}] to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082152.052841:INFO:CONSOLE(13)] "Returning ok-received-candidates to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082152.053385:INFO:CONSOLE(13)] "Returning ["codec","inbound-rtp","outbound-rtp","peer-connection","stream","track","data-channel","transport","local-candidate","remote-candidate","candidate-pair","certificate"] to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) [12743:775:0305/082152.061797:INFO:CONSOLE(13)] "Returning Test failed: Error: stats.hugeFramesSent is not a whitelisted member: 0 at failTest (http://127.0.0.1:50666/webrtc/test_functions.js:46:15) at verifyStatsIsWhitelisted_ (http://127.0.0.1:50666/webrtc/peerconnection_getstats.js:386:13) at http://127.0.0.1:50666/webrtc/peerconnection_getstats.js:273:9 to test.", source: http://127.0.0.1:50666/webrtc/test_functions.js (13) ../../chrome/browser/media/webrtc/webrtc_browsertest_base.cc:533: Failure Value of: base::StartsWith(result, "ok-", base::CompareCase::SENSITIVE) Actual: false Expected: true ../../chrome/browser/media/webrtc/webrtc_browsertest_base.cc:138: Failure Value of: value Actual: false Expected: true BrowserTestBase received signal: Segmentation fault: 11. Backtrace: 0 browser_tests 0x0000000105c700cc base::debug::StackTrace::StackTrace(unsigned long) + 28 1 browser_tests 0x0000000106271902 content::(anonymous namespace)::DumpStackTraceSignalHandler(int) + 226 2 libsystem_platform.dylib 0x00007fffa63ccb3a _sigtramp + 26 3 ??? 0x0000000000000000 0x0 + 0 4 browser_tests 0x0000000102ee29e3 WebRtcTestBase::VerifyStatsGeneratedPromise(content::WebContents*) const + 467 5 browser_tests 0x0000000102edb4d1 WebRtcBrowserTest_RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise_Test::RunTestOnMainThread() + 817 6 browser_tests 0x000000010627162d content::BrowserTestBase::ProxyRunTestOnMainThreadLoop() + 557 7 browser_tests 0x0000000105da0d23 ChromeBrowserMainParts::PreMainMessageLoopRunImpl() + 4227 8 browser_tests 0x0000000105d9fb9e ChromeBrowserMainParts::PreMainMessageLoopRun() + 62 9 browser_tests 0x0000000104a3a3d3 content::BrowserMainLoop::PreMainMessageLoopRun() + 67 10 browser_tests 0x0000000104df0dc7 content::StartupTaskRunner::RunAllTasksNow() + 39 11 browser_tests 0x0000000104a38d35 content::BrowserMainLoop::CreateStartupTasks() + 661 12 browser_tests 0x0000000104a3c8f0 content::BrowserMainRunnerImpl::Initialize(content::MainFunctionParams const&) + 96 13 browser_tests 0x0000000104a36c94 content::BrowserMain(content::MainFunctionParams const&) + 180 14 browser_tests 0x0000000105c3ebb9 content::ContentMainRunnerImpl::Run() + 377 15 browser_tests 0x000000010784a8f4 service_manager::Main(service_manager::MainParams const&) + 2324 16 browser_tests 0x0000000105c3e094 content::ContentMain(content::ContentMainParams const&) + 68 17 browser_tests 0x0000000106271216 content::BrowserTestBase::SetUp() + 2550 18 browser_tests 0x0000000105d2993e InProcessBrowserTest::SetUp() + 398 19 browser_tests 0x0000000104032b51 testing::Test::Run() + 97 20 browser_tests 0x0000000104033770 testing::TestInfo::Run() + 288 21 browser_tests 0x0000000104033cd7 testing::TestCase::Run() + 263 22 browser_tests 0x000000010403b167 testing::internal::UnitTestImpl::RunAllTests() + 903 23 browser_tests 0x000000010403adb3 testing::UnitTest::Run() + 163 24 browser_tests 0x0000000105d41c67 base::TestSuite::Run() + 167 25 browser_tests 0x0000000105c63755 ChromeTestSuiteRunner::RunTestSuite(int, char**) + 37 26 browser_tests 0x00000001062b6597 content::LaunchTests(content::TestLauncherDelegate*, unsigned long, int, char**) + 391 27 browser_tests 0x0000000105c63c3c LaunchChromeTests(unsigned long, content::TestLauncherDelegate*, int, char**) + 348 28 browser_tests 0x0000000105c636ce main + 94 29 libdyld.dylib 0x00007fffa61bd235 start + 1 30 ??? 0x000000000000000a 0x0 + 10 Original change's description: > Add hugeFramesSent GetStats metric > > Bug: webrtc:8901 > Change-Id: I36021c1160c3426d3bfa0f37ff0adaa35710b93e > Reviewed-on: https://webrtc-review.googlesource.com/54420 > Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org> > Reviewed-by: Harald Alvestrand <hta@webrtc.org> > Reviewed-by: Henrik Boström <hbos@webrtc.org> > Reviewed-by: Erik Språng <sprang@webrtc.org> > Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org> > Cr-Commit-Position: refs/heads/master@{#22290} TBR=solenberg@webrtc.org,ilnik@webrtc.org,hbos@webrtc.org,sprang@webrtc.org,stefan@webrtc.org,hta@webrtc.org Change-Id: I6a7501c46f928281d357da37f9232bb92c5a4f19 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: webrtc:8901 Reviewed-on: https://webrtc-review.googlesource.com/60120 Reviewed-by: Max Morin <maxmorin@webrtc.org> Commit-Queue: Max Morin <maxmorin@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22303}
1207 lines
46 KiB
C++
1207 lines
46 KiB
C++
/*
|
|
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "video/send_statistics_proxy.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <utility>
|
|
|
|
#include "common_types.h" // NOLINT(build/include)
|
|
#include "modules/video_coding/include/video_codec_interface.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/logging.h"
|
|
#include "rtc_base/strings/string_builder.h"
|
|
#include "system_wrappers/include/field_trial.h"
|
|
#include "system_wrappers/include/metrics.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
const float kEncodeTimeWeigthFactor = 0.5f;
|
|
const size_t kMaxEncodedFrameMapSize = 150;
|
|
const int64_t kMaxEncodedFrameWindowMs = 800;
|
|
const int64_t kBucketSizeMs = 100;
|
|
const size_t kBucketCount = 10;
|
|
|
|
const char kVp8ForcedFallbackEncoderFieldTrial[] =
|
|
"WebRTC-VP8-Forced-Fallback-Encoder-v2";
|
|
const char kVp8SwCodecName[] = "libvpx";
|
|
|
|
// Used by histograms. Values of entries should not be changed.
|
|
enum HistogramCodecType {
|
|
kVideoUnknown = 0,
|
|
kVideoVp8 = 1,
|
|
kVideoVp9 = 2,
|
|
kVideoH264 = 3,
|
|
kVideoMax = 64,
|
|
};
|
|
|
|
const char* kRealtimePrefix = "WebRTC.Video.";
|
|
const char* kScreenPrefix = "WebRTC.Video.Screenshare.";
|
|
|
|
const char* GetUmaPrefix(VideoEncoderConfig::ContentType content_type) {
|
|
switch (content_type) {
|
|
case VideoEncoderConfig::ContentType::kRealtimeVideo:
|
|
return kRealtimePrefix;
|
|
case VideoEncoderConfig::ContentType::kScreen:
|
|
return kScreenPrefix;
|
|
}
|
|
RTC_NOTREACHED();
|
|
return nullptr;
|
|
}
|
|
|
|
HistogramCodecType PayloadNameToHistogramCodecType(
|
|
const std::string& payload_name) {
|
|
VideoCodecType codecType = PayloadStringToCodecType(payload_name);
|
|
switch (codecType) {
|
|
case kVideoCodecVP8:
|
|
return kVideoVp8;
|
|
case kVideoCodecVP9:
|
|
return kVideoVp9;
|
|
case kVideoCodecH264:
|
|
return kVideoH264;
|
|
default:
|
|
return kVideoUnknown;
|
|
}
|
|
}
|
|
|
|
void UpdateCodecTypeHistogram(const std::string& payload_name) {
|
|
RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
|
|
PayloadNameToHistogramCodecType(payload_name),
|
|
kVideoMax);
|
|
}
|
|
|
|
bool IsForcedFallbackPossible(const CodecSpecificInfo* codec_info) {
|
|
return codec_info->codecType == kVideoCodecVP8 &&
|
|
codec_info->codecSpecific.VP8.simulcastIdx == 0 &&
|
|
(codec_info->codecSpecific.VP8.temporalIdx == 0 ||
|
|
codec_info->codecSpecific.VP8.temporalIdx == kNoTemporalIdx);
|
|
}
|
|
|
|
rtc::Optional<int> GetFallbackMaxPixels(const std::string& group) {
|
|
if (group.empty())
|
|
return rtc::nullopt;
|
|
|
|
int min_pixels;
|
|
int max_pixels;
|
|
int min_bps;
|
|
if (sscanf(group.c_str(), "-%d,%d,%d", &min_pixels, &max_pixels, &min_bps) !=
|
|
3) {
|
|
return rtc::Optional<int>();
|
|
}
|
|
|
|
if (min_pixels <= 0 || max_pixels <= 0 || max_pixels < min_pixels)
|
|
return rtc::Optional<int>();
|
|
|
|
return rtc::Optional<int>(max_pixels);
|
|
}
|
|
|
|
rtc::Optional<int> GetFallbackMaxPixelsIfFieldTrialEnabled() {
|
|
std::string group =
|
|
webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
|
|
return (group.find("Enabled") == 0) ? GetFallbackMaxPixels(group.substr(7))
|
|
: rtc::Optional<int>();
|
|
}
|
|
|
|
rtc::Optional<int> GetFallbackMaxPixelsIfFieldTrialDisabled() {
|
|
std::string group =
|
|
webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
|
|
return (group.find("Disabled") == 0) ? GetFallbackMaxPixels(group.substr(8))
|
|
: rtc::Optional<int>();
|
|
}
|
|
} // namespace
|
|
|
|
|
|
const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
|
|
|
|
SendStatisticsProxy::SendStatisticsProxy(
|
|
Clock* clock,
|
|
const VideoSendStream::Config& config,
|
|
VideoEncoderConfig::ContentType content_type)
|
|
: clock_(clock),
|
|
payload_name_(config.encoder_settings.payload_name),
|
|
rtp_config_(config.rtp),
|
|
fallback_max_pixels_(GetFallbackMaxPixelsIfFieldTrialEnabled()),
|
|
fallback_max_pixels_disabled_(GetFallbackMaxPixelsIfFieldTrialDisabled()),
|
|
content_type_(content_type),
|
|
start_ms_(clock->TimeInMilliseconds()),
|
|
encode_time_(kEncodeTimeWeigthFactor),
|
|
quality_downscales_(-1),
|
|
cpu_downscales_(-1),
|
|
media_byte_rate_tracker_(kBucketSizeMs, kBucketCount),
|
|
encoded_frame_rate_tracker_(kBucketSizeMs, kBucketCount),
|
|
uma_container_(
|
|
new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
|
|
}
|
|
|
|
SendStatisticsProxy::~SendStatisticsProxy() {
|
|
rtc::CritScope lock(&crit_);
|
|
uma_container_->UpdateHistograms(rtp_config_, stats_);
|
|
|
|
int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
|
|
RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
|
|
elapsed_sec);
|
|
|
|
if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
|
|
UpdateCodecTypeHistogram(payload_name_);
|
|
}
|
|
|
|
SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
|
|
const char* prefix,
|
|
const VideoSendStream::Stats& stats,
|
|
Clock* const clock)
|
|
: uma_prefix_(prefix),
|
|
clock_(clock),
|
|
input_frame_rate_tracker_(100, 10u),
|
|
input_fps_counter_(clock, nullptr, true),
|
|
sent_fps_counter_(clock, nullptr, true),
|
|
total_byte_counter_(clock, nullptr, true),
|
|
media_byte_counter_(clock, nullptr, true),
|
|
rtx_byte_counter_(clock, nullptr, true),
|
|
padding_byte_counter_(clock, nullptr, true),
|
|
retransmit_byte_counter_(clock, nullptr, true),
|
|
fec_byte_counter_(clock, nullptr, true),
|
|
first_rtcp_stats_time_ms_(-1),
|
|
first_rtp_stats_time_ms_(-1),
|
|
start_stats_(stats),
|
|
num_streams_(0),
|
|
num_pixels_highest_stream_(0) {
|
|
InitializeBitrateCounters(stats);
|
|
}
|
|
|
|
SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
|
|
|
|
void SendStatisticsProxy::UmaSamplesContainer::InitializeBitrateCounters(
|
|
const VideoSendStream::Stats& stats) {
|
|
for (const auto& it : stats.substreams) {
|
|
uint32_t ssrc = it.first;
|
|
total_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
|
|
ssrc);
|
|
padding_byte_counter_.SetLast(it.second.rtp_stats.transmitted.padding_bytes,
|
|
ssrc);
|
|
retransmit_byte_counter_.SetLast(
|
|
it.second.rtp_stats.retransmitted.TotalBytes(), ssrc);
|
|
fec_byte_counter_.SetLast(it.second.rtp_stats.fec.TotalBytes(), ssrc);
|
|
if (it.second.is_rtx) {
|
|
rtx_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
|
|
ssrc);
|
|
} else {
|
|
media_byte_counter_.SetLast(it.second.rtp_stats.MediaPayloadBytes(),
|
|
ssrc);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SendStatisticsProxy::UmaSamplesContainer::RemoveOld(
|
|
int64_t now_ms,
|
|
bool* is_limited_in_resolution) {
|
|
while (!encoded_frames_.empty()) {
|
|
auto it = encoded_frames_.begin();
|
|
if (now_ms - it->second.send_ms < kMaxEncodedFrameWindowMs)
|
|
break;
|
|
|
|
// Use max per timestamp.
|
|
sent_width_counter_.Add(it->second.max_width);
|
|
sent_height_counter_.Add(it->second.max_height);
|
|
|
|
// Check number of encoded streams per timestamp.
|
|
if (num_streams_ > it->second.max_simulcast_idx) {
|
|
*is_limited_in_resolution = false;
|
|
if (num_streams_ > 1) {
|
|
int disabled_streams =
|
|
static_cast<int>(num_streams_ - 1 - it->second.max_simulcast_idx);
|
|
// Can be limited in resolution or framerate.
|
|
uint32_t pixels = it->second.max_width * it->second.max_height;
|
|
bool bw_limited_resolution =
|
|
disabled_streams > 0 && pixels < num_pixels_highest_stream_;
|
|
bw_limited_frame_counter_.Add(bw_limited_resolution);
|
|
if (bw_limited_resolution) {
|
|
bw_resolutions_disabled_counter_.Add(disabled_streams);
|
|
*is_limited_in_resolution = true;
|
|
}
|
|
}
|
|
}
|
|
encoded_frames_.erase(it);
|
|
}
|
|
}
|
|
|
|
bool SendStatisticsProxy::UmaSamplesContainer::InsertEncodedFrame(
|
|
const EncodedImage& encoded_frame,
|
|
size_t simulcast_idx,
|
|
bool* is_limited_in_resolution) {
|
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
|
RemoveOld(now_ms, is_limited_in_resolution);
|
|
if (encoded_frames_.size() > kMaxEncodedFrameMapSize) {
|
|
encoded_frames_.clear();
|
|
}
|
|
|
|
auto it = encoded_frames_.find(encoded_frame._timeStamp);
|
|
if (it == encoded_frames_.end()) {
|
|
// First frame with this timestamp.
|
|
encoded_frames_.insert(
|
|
std::make_pair(encoded_frame._timeStamp,
|
|
Frame(now_ms, encoded_frame._encodedWidth,
|
|
encoded_frame._encodedHeight, simulcast_idx)));
|
|
sent_fps_counter_.Add(1);
|
|
return true;
|
|
}
|
|
|
|
it->second.max_width =
|
|
std::max(it->second.max_width, encoded_frame._encodedWidth);
|
|
it->second.max_height =
|
|
std::max(it->second.max_height, encoded_frame._encodedHeight);
|
|
it->second.max_simulcast_idx =
|
|
std::max(it->second.max_simulcast_idx, simulcast_idx);
|
|
return false;
|
|
}
|
|
|
|
void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
|
|
const VideoSendStream::Config::Rtp& rtp_config,
|
|
const VideoSendStream::Stats& current_stats) {
|
|
RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
|
|
const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
|
|
const int kMinRequiredPeriodicSamples = 6;
|
|
rtc::SimpleStringBuilder<8 * 1024> log_stream;
|
|
int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
|
|
int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
|
|
if (in_width != -1) {
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
|
|
in_width);
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
|
|
in_height);
|
|
log_stream << uma_prefix_ << "InputWidthInPixels " << in_width << "\n"
|
|
<< uma_prefix_ << "InputHeightInPixels " << in_height << "\n";
|
|
}
|
|
AggregatedStats in_fps = input_fps_counter_.GetStats();
|
|
if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
|
|
RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
|
|
in_fps.average);
|
|
log_stream << uma_prefix_ << "InputFramesPerSecond " << in_fps.ToString()
|
|
<< "\n";
|
|
}
|
|
|
|
int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
|
|
int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
|
|
if (sent_width != -1) {
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
|
|
sent_width);
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
|
|
sent_height);
|
|
log_stream << uma_prefix_ << "SentWidthInPixels " << sent_width << "\n"
|
|
<< uma_prefix_ << "SentHeightInPixels " << sent_height << "\n";
|
|
}
|
|
AggregatedStats sent_fps = sent_fps_counter_.GetStats();
|
|
if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
|
|
RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
|
|
sent_fps.average);
|
|
log_stream << uma_prefix_ << "SentFramesPerSecond " << sent_fps.ToString()
|
|
<< "\n";
|
|
}
|
|
|
|
if (in_fps.num_samples > kMinRequiredPeriodicSamples &&
|
|
sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
|
|
int in_fps_avg = in_fps.average;
|
|
if (in_fps_avg > 0) {
|
|
int sent_fps_avg = sent_fps.average;
|
|
int sent_to_in_fps_ratio_percent =
|
|
(100 * sent_fps_avg + in_fps_avg / 2) / in_fps_avg;
|
|
// If reported period is small, it may happen that sent_fps is larger than
|
|
// input_fps briefly on average. This should be treated as 100% sent to
|
|
// input ratio.
|
|
if (sent_to_in_fps_ratio_percent > 100)
|
|
sent_to_in_fps_ratio_percent = 100;
|
|
RTC_HISTOGRAMS_PERCENTAGE(kIndex,
|
|
uma_prefix_ + "SentToInputFpsRatioPercent",
|
|
sent_to_in_fps_ratio_percent);
|
|
log_stream << uma_prefix_ << "SentToInputFpsRatioPercent "
|
|
<< sent_to_in_fps_ratio_percent << "\n";
|
|
}
|
|
}
|
|
|
|
int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
|
|
if (encode_ms != -1) {
|
|
RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
|
|
encode_ms);
|
|
log_stream << uma_prefix_ << "EncodeTimeInMs " << encode_ms << "\n";
|
|
}
|
|
int key_frames_permille =
|
|
key_frame_counter_.Permille(kMinRequiredMetricsSamples);
|
|
if (key_frames_permille != -1) {
|
|
RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "KeyFramesSentInPermille",
|
|
key_frames_permille);
|
|
log_stream << uma_prefix_ << "KeyFramesSentInPermille "
|
|
<< key_frames_permille << "\n";
|
|
}
|
|
int quality_limited =
|
|
quality_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
|
|
if (quality_limited != -1) {
|
|
RTC_HISTOGRAMS_PERCENTAGE(kIndex,
|
|
uma_prefix_ + "QualityLimitedResolutionInPercent",
|
|
quality_limited);
|
|
log_stream << uma_prefix_ << "QualityLimitedResolutionInPercent "
|
|
<< quality_limited << "\n";
|
|
}
|
|
int downscales = quality_downscales_counter_.Avg(kMinRequiredMetricsSamples);
|
|
if (downscales != -1) {
|
|
RTC_HISTOGRAMS_ENUMERATION(
|
|
kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
|
|
20);
|
|
}
|
|
int cpu_limited =
|
|
cpu_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
|
|
if (cpu_limited != -1) {
|
|
RTC_HISTOGRAMS_PERCENTAGE(
|
|
kIndex, uma_prefix_ + "CpuLimitedResolutionInPercent", cpu_limited);
|
|
}
|
|
int bw_limited =
|
|
bw_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
|
|
if (bw_limited != -1) {
|
|
RTC_HISTOGRAMS_PERCENTAGE(
|
|
kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
|
|
bw_limited);
|
|
}
|
|
int num_disabled =
|
|
bw_resolutions_disabled_counter_.Avg(kMinRequiredMetricsSamples);
|
|
if (num_disabled != -1) {
|
|
RTC_HISTOGRAMS_ENUMERATION(
|
|
kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
|
|
num_disabled, 10);
|
|
}
|
|
int delay_ms = delay_counter_.Avg(kMinRequiredMetricsSamples);
|
|
if (delay_ms != -1)
|
|
RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayInMs",
|
|
delay_ms);
|
|
|
|
int max_delay_ms = max_delay_counter_.Avg(kMinRequiredMetricsSamples);
|
|
if (max_delay_ms != -1) {
|
|
RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayMaxInMs",
|
|
max_delay_ms);
|
|
}
|
|
|
|
for (const auto& it : qp_counters_) {
|
|
int qp_vp8 = it.second.vp8.Avg(kMinRequiredMetricsSamples);
|
|
if (qp_vp8 != -1) {
|
|
int spatial_idx = it.first;
|
|
if (spatial_idx == -1) {
|
|
RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
|
|
qp_vp8);
|
|
} else if (spatial_idx == 0) {
|
|
RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0",
|
|
qp_vp8);
|
|
} else if (spatial_idx == 1) {
|
|
RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1",
|
|
qp_vp8);
|
|
} else if (spatial_idx == 2) {
|
|
RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2",
|
|
qp_vp8);
|
|
} else {
|
|
RTC_LOG(LS_WARNING)
|
|
<< "QP stats not recorded for VP8 spatial idx " << spatial_idx;
|
|
}
|
|
}
|
|
int qp_vp9 = it.second.vp9.Avg(kMinRequiredMetricsSamples);
|
|
if (qp_vp9 != -1) {
|
|
int spatial_idx = it.first;
|
|
if (spatial_idx == -1) {
|
|
RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
|
|
qp_vp9);
|
|
} else if (spatial_idx == 0) {
|
|
RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0",
|
|
qp_vp9);
|
|
} else if (spatial_idx == 1) {
|
|
RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1",
|
|
qp_vp9);
|
|
} else if (spatial_idx == 2) {
|
|
RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2",
|
|
qp_vp9);
|
|
} else {
|
|
RTC_LOG(LS_WARNING)
|
|
<< "QP stats not recorded for VP9 spatial layer " << spatial_idx;
|
|
}
|
|
}
|
|
int qp_h264 = it.second.h264.Avg(kMinRequiredMetricsSamples);
|
|
if (qp_h264 != -1) {
|
|
int spatial_idx = it.first;
|
|
RTC_DCHECK_EQ(-1, spatial_idx);
|
|
RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "Encoded.Qp.H264",
|
|
qp_h264);
|
|
}
|
|
}
|
|
|
|
if (first_rtp_stats_time_ms_ != -1) {
|
|
quality_adapt_timer_.Stop(clock_->TimeInMilliseconds());
|
|
int64_t elapsed_sec = quality_adapt_timer_.total_ms / 1000;
|
|
if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
|
|
int quality_changes = current_stats.number_of_quality_adapt_changes -
|
|
start_stats_.number_of_quality_adapt_changes;
|
|
// Only base stats on changes during a call, discard initial changes.
|
|
int initial_changes =
|
|
initial_quality_changes_.down + initial_quality_changes_.up;
|
|
if (initial_changes <= quality_changes)
|
|
quality_changes -= initial_changes;
|
|
RTC_HISTOGRAMS_COUNTS_100(kIndex,
|
|
uma_prefix_ + "AdaptChangesPerMinute.Quality",
|
|
quality_changes * 60 / elapsed_sec);
|
|
}
|
|
cpu_adapt_timer_.Stop(clock_->TimeInMilliseconds());
|
|
elapsed_sec = cpu_adapt_timer_.total_ms / 1000;
|
|
if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
|
|
int cpu_changes = current_stats.number_of_cpu_adapt_changes -
|
|
start_stats_.number_of_cpu_adapt_changes;
|
|
RTC_HISTOGRAMS_COUNTS_100(kIndex,
|
|
uma_prefix_ + "AdaptChangesPerMinute.Cpu",
|
|
cpu_changes * 60 / elapsed_sec);
|
|
}
|
|
}
|
|
|
|
if (first_rtcp_stats_time_ms_ != -1) {
|
|
int64_t elapsed_sec =
|
|
(clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
|
|
if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
|
|
int fraction_lost = report_block_stats_.FractionLostInPercent();
|
|
if (fraction_lost != -1) {
|
|
RTC_HISTOGRAMS_PERCENTAGE(
|
|
kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
|
|
log_stream << uma_prefix_ << "SentPacketsLostInPercent "
|
|
<< fraction_lost;
|
|
}
|
|
|
|
// The RTCP packet type counters, delivered via the
|
|
// RtcpPacketTypeCounterObserver interface, are aggregates over the entire
|
|
// life of the send stream and are not reset when switching content type.
|
|
// For the purpose of these statistics though, we want new counts when
|
|
// switching since we switch histogram name. On every reset of the
|
|
// UmaSamplesContainer, we save the initial state of the counters, so that
|
|
// we can calculate the delta here and aggregate over all ssrcs.
|
|
RtcpPacketTypeCounter counters;
|
|
for (uint32_t ssrc : rtp_config.ssrcs) {
|
|
auto kv = current_stats.substreams.find(ssrc);
|
|
if (kv == current_stats.substreams.end())
|
|
continue;
|
|
|
|
RtcpPacketTypeCounter stream_counters =
|
|
kv->second.rtcp_packet_type_counts;
|
|
kv = start_stats_.substreams.find(ssrc);
|
|
if (kv != start_stats_.substreams.end())
|
|
stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
|
|
|
|
counters.Add(stream_counters);
|
|
}
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex,
|
|
uma_prefix_ + "NackPacketsReceivedPerMinute",
|
|
counters.nack_packets * 60 / elapsed_sec);
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex,
|
|
uma_prefix_ + "FirPacketsReceivedPerMinute",
|
|
counters.fir_packets * 60 / elapsed_sec);
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex,
|
|
uma_prefix_ + "PliPacketsReceivedPerMinute",
|
|
counters.pli_packets * 60 / elapsed_sec);
|
|
if (counters.nack_requests > 0) {
|
|
RTC_HISTOGRAMS_PERCENTAGE(
|
|
kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
|
|
counters.UniqueNackRequestsInPercent());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (first_rtp_stats_time_ms_ != -1) {
|
|
int64_t elapsed_sec =
|
|
(clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
|
|
if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
|
|
RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "NumberOfPauseEvents",
|
|
target_rate_updates_.pause_resume_events);
|
|
log_stream << uma_prefix_ << "NumberOfPauseEvents "
|
|
<< target_rate_updates_.pause_resume_events << "\n";
|
|
|
|
int paused_time_percent =
|
|
paused_time_counter_.Percent(metrics::kMinRunTimeInSeconds * 1000);
|
|
if (paused_time_percent != -1) {
|
|
RTC_HISTOGRAMS_PERCENTAGE(kIndex, uma_prefix_ + "PausedTimeInPercent",
|
|
paused_time_percent);
|
|
log_stream << uma_prefix_ << "PausedTimeInPercent "
|
|
<< paused_time_percent << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fallback_info_.is_possible) {
|
|
// Double interval since there is some time before fallback may occur.
|
|
const int kMinRunTimeMs = 2 * metrics::kMinRunTimeInSeconds * 1000;
|
|
int64_t elapsed_ms = fallback_info_.elapsed_ms;
|
|
int fallback_time_percent = fallback_active_counter_.Percent(kMinRunTimeMs);
|
|
if (fallback_time_percent != -1 && elapsed_ms >= kMinRunTimeMs) {
|
|
RTC_HISTOGRAMS_PERCENTAGE(
|
|
kIndex, uma_prefix_ + "Encoder.ForcedSwFallbackTimeInPercent.Vp8",
|
|
fallback_time_percent);
|
|
RTC_HISTOGRAMS_COUNTS_100(
|
|
kIndex, uma_prefix_ + "Encoder.ForcedSwFallbackChangesPerMinute.Vp8",
|
|
fallback_info_.on_off_events * 60 / (elapsed_ms / 1000));
|
|
}
|
|
}
|
|
|
|
AggregatedStats total_bytes_per_sec = total_byte_counter_.GetStats();
|
|
if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "BitrateSentInKbps",
|
|
total_bytes_per_sec.average * 8 / 1000);
|
|
log_stream << uma_prefix_ << "BitrateSentInBps "
|
|
<< total_bytes_per_sec.ToStringWithMultiplier(8) << "\n";
|
|
}
|
|
AggregatedStats media_bytes_per_sec = media_byte_counter_.GetStats();
|
|
if (media_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
|
|
media_bytes_per_sec.average * 8 / 1000);
|
|
log_stream << uma_prefix_ << "MediaBitrateSentInBps "
|
|
<< media_bytes_per_sec.ToStringWithMultiplier(8) << "\n";
|
|
}
|
|
AggregatedStats padding_bytes_per_sec = padding_byte_counter_.GetStats();
|
|
if (padding_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex,
|
|
uma_prefix_ + "PaddingBitrateSentInKbps",
|
|
padding_bytes_per_sec.average * 8 / 1000);
|
|
log_stream << uma_prefix_ << "PaddingBitrateSentInBps "
|
|
<< padding_bytes_per_sec.ToStringWithMultiplier(8) << "\n";
|
|
}
|
|
AggregatedStats retransmit_bytes_per_sec =
|
|
retransmit_byte_counter_.GetStats();
|
|
if (retransmit_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex,
|
|
uma_prefix_ + "RetransmittedBitrateSentInKbps",
|
|
retransmit_bytes_per_sec.average * 8 / 1000);
|
|
log_stream << uma_prefix_ << "RetransmittedBitrateSentInBps "
|
|
<< retransmit_bytes_per_sec.ToStringWithMultiplier(8) << "\n";
|
|
}
|
|
if (!rtp_config.rtx.ssrcs.empty()) {
|
|
AggregatedStats rtx_bytes_per_sec = rtx_byte_counter_.GetStats();
|
|
int rtx_bytes_per_sec_avg = -1;
|
|
if (rtx_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
|
|
rtx_bytes_per_sec_avg = rtx_bytes_per_sec.average;
|
|
log_stream << uma_prefix_ << "RtxBitrateSentInBps "
|
|
<< rtx_bytes_per_sec.ToStringWithMultiplier(8) << "\n";
|
|
} else if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
|
|
rtx_bytes_per_sec_avg = 0; // RTX enabled but no RTX data sent, record 0.
|
|
}
|
|
if (rtx_bytes_per_sec_avg != -1) {
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
|
|
rtx_bytes_per_sec_avg * 8 / 1000);
|
|
}
|
|
}
|
|
if (rtp_config.flexfec.payload_type != -1 ||
|
|
rtp_config.ulpfec.red_payload_type != -1) {
|
|
AggregatedStats fec_bytes_per_sec = fec_byte_counter_.GetStats();
|
|
if (fec_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
|
|
RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "FecBitrateSentInKbps",
|
|
fec_bytes_per_sec.average * 8 / 1000);
|
|
log_stream << uma_prefix_ << "FecBitrateSentInBps "
|
|
<< fec_bytes_per_sec.ToStringWithMultiplier(8) << "\n";
|
|
}
|
|
}
|
|
log_stream << "Frames encoded " << current_stats.frames_encoded << "\n"
|
|
<< uma_prefix_ << "DroppedFrames.Capturer "
|
|
<< current_stats.frames_dropped_by_capturer << "\n";
|
|
RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Capturer",
|
|
current_stats.frames_dropped_by_capturer);
|
|
log_stream << uma_prefix_ << "DroppedFrames.EncoderQueue "
|
|
<< current_stats.frames_dropped_by_encoder_queue << "\n";
|
|
RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.EncoderQueue",
|
|
current_stats.frames_dropped_by_encoder_queue);
|
|
log_stream << uma_prefix_ << "DroppedFrames.Encoder "
|
|
<< current_stats.frames_dropped_by_encoder << "\n";
|
|
RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Encoder",
|
|
current_stats.frames_dropped_by_encoder);
|
|
log_stream << uma_prefix_ << "DroppedFrames.Ratelimiter "
|
|
<< current_stats.frames_dropped_by_rate_limiter;
|
|
RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Ratelimiter",
|
|
current_stats.frames_dropped_by_rate_limiter);
|
|
|
|
RTC_LOG(LS_INFO) << log_stream.str();
|
|
}
|
|
|
|
void SendStatisticsProxy::OnEncoderReconfigured(
|
|
const VideoEncoderConfig& config,
|
|
const std::vector<VideoStream>& streams,
|
|
uint32_t preferred_bitrate_bps) {
|
|
rtc::CritScope lock(&crit_);
|
|
stats_.preferred_media_bitrate_bps = preferred_bitrate_bps;
|
|
|
|
if (content_type_ != config.content_type) {
|
|
uma_container_->UpdateHistograms(rtp_config_, stats_);
|
|
uma_container_.reset(new UmaSamplesContainer(
|
|
GetUmaPrefix(config.content_type), stats_, clock_));
|
|
content_type_ = config.content_type;
|
|
}
|
|
uma_container_->encoded_frames_.clear();
|
|
uma_container_->num_streams_ = streams.size();
|
|
uma_container_->num_pixels_highest_stream_ =
|
|
streams.empty() ? 0 : (streams.back().width * streams.back().height);
|
|
}
|
|
|
|
void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
|
|
int encode_time_ms,
|
|
const CpuOveruseMetrics& metrics) {
|
|
rtc::CritScope lock(&crit_);
|
|
uma_container_->encode_time_counter_.Add(encode_time_ms);
|
|
encode_time_.Apply(1.0f, encode_time_ms);
|
|
stats_.avg_encode_time_ms = round(encode_time_.filtered());
|
|
stats_.encode_usage_percent = metrics.encode_usage_percent;
|
|
}
|
|
|
|
void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
|
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
|
rtc::CritScope lock(&crit_);
|
|
stats_.suspended = is_suspended;
|
|
if (is_suspended) {
|
|
// Pause framerate (add min pause time since there may be frames/packets
|
|
// that are not yet sent).
|
|
const int64_t kMinMs = 500;
|
|
uma_container_->input_fps_counter_.ProcessAndPauseForDuration(kMinMs);
|
|
uma_container_->sent_fps_counter_.ProcessAndPauseForDuration(kMinMs);
|
|
// Pause bitrate stats.
|
|
uma_container_->total_byte_counter_.ProcessAndPauseForDuration(kMinMs);
|
|
uma_container_->media_byte_counter_.ProcessAndPauseForDuration(kMinMs);
|
|
uma_container_->rtx_byte_counter_.ProcessAndPauseForDuration(kMinMs);
|
|
uma_container_->padding_byte_counter_.ProcessAndPauseForDuration(kMinMs);
|
|
uma_container_->retransmit_byte_counter_.ProcessAndPauseForDuration(kMinMs);
|
|
uma_container_->fec_byte_counter_.ProcessAndPauseForDuration(kMinMs);
|
|
// Stop adaptation stats.
|
|
uma_container_->cpu_adapt_timer_.Stop(now_ms);
|
|
uma_container_->quality_adapt_timer_.Stop(now_ms);
|
|
} else {
|
|
// Start adaptation stats if scaling is enabled.
|
|
if (cpu_downscales_ >= 0)
|
|
uma_container_->cpu_adapt_timer_.Start(now_ms);
|
|
if (quality_downscales_ >= 0)
|
|
uma_container_->quality_adapt_timer_.Start(now_ms);
|
|
// Stop pause explicitly for stats that may be zero/not updated for some
|
|
// time.
|
|
uma_container_->rtx_byte_counter_.ProcessAndStopPause();
|
|
uma_container_->padding_byte_counter_.ProcessAndStopPause();
|
|
uma_container_->retransmit_byte_counter_.ProcessAndStopPause();
|
|
uma_container_->fec_byte_counter_.ProcessAndStopPause();
|
|
}
|
|
}
|
|
|
|
VideoSendStream::Stats SendStatisticsProxy::GetStats() {
|
|
rtc::CritScope lock(&crit_);
|
|
PurgeOldStats();
|
|
stats_.input_frame_rate =
|
|
round(uma_container_->input_frame_rate_tracker_.ComputeRate());
|
|
stats_.content_type =
|
|
content_type_ == VideoEncoderConfig::ContentType::kRealtimeVideo
|
|
? VideoContentType::UNSPECIFIED
|
|
: VideoContentType::SCREENSHARE;
|
|
stats_.encode_frame_rate = round(encoded_frame_rate_tracker_.ComputeRate());
|
|
stats_.media_bitrate_bps = media_byte_rate_tracker_.ComputeRate() * 8;
|
|
return stats_;
|
|
}
|
|
|
|
void SendStatisticsProxy::PurgeOldStats() {
|
|
int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
|
|
for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
|
|
stats_.substreams.begin();
|
|
it != stats_.substreams.end(); ++it) {
|
|
uint32_t ssrc = it->first;
|
|
if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
|
|
it->second.width = 0;
|
|
it->second.height = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
|
|
uint32_t ssrc) {
|
|
std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
|
|
stats_.substreams.find(ssrc);
|
|
if (it != stats_.substreams.end())
|
|
return &it->second;
|
|
|
|
bool is_media = std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(),
|
|
ssrc) != rtp_config_.ssrcs.end();
|
|
bool is_flexfec = rtp_config_.flexfec.payload_type != -1 &&
|
|
ssrc == rtp_config_.flexfec.ssrc;
|
|
bool is_rtx =
|
|
std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(),
|
|
ssrc) != rtp_config_.rtx.ssrcs.end();
|
|
if (!is_media && !is_flexfec && !is_rtx)
|
|
return nullptr;
|
|
|
|
// Insert new entry and return ptr.
|
|
VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc];
|
|
entry->is_rtx = is_rtx;
|
|
entry->is_flexfec = is_flexfec;
|
|
|
|
return entry;
|
|
}
|
|
|
|
void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
|
|
rtc::CritScope lock(&crit_);
|
|
VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
|
|
if (!stats)
|
|
return;
|
|
|
|
stats->total_bitrate_bps = 0;
|
|
stats->retransmit_bitrate_bps = 0;
|
|
stats->height = 0;
|
|
stats->width = 0;
|
|
}
|
|
|
|
void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
|
|
rtc::CritScope lock(&crit_);
|
|
if (uma_container_->target_rate_updates_.last_ms == -1 && bitrate_bps == 0)
|
|
return; // Start on first non-zero bitrate, may initially be zero.
|
|
|
|
int64_t now = clock_->TimeInMilliseconds();
|
|
if (uma_container_->target_rate_updates_.last_ms != -1) {
|
|
bool was_paused = stats_.target_media_bitrate_bps == 0;
|
|
int64_t diff_ms = now - uma_container_->target_rate_updates_.last_ms;
|
|
uma_container_->paused_time_counter_.Add(was_paused, diff_ms);
|
|
|
|
// Use last to not include update when stream is stopped and video disabled.
|
|
if (uma_container_->target_rate_updates_.last_paused_or_resumed)
|
|
++uma_container_->target_rate_updates_.pause_resume_events;
|
|
|
|
// Check if video is paused/resumed.
|
|
uma_container_->target_rate_updates_.last_paused_or_resumed =
|
|
(bitrate_bps == 0) != was_paused;
|
|
}
|
|
uma_container_->target_rate_updates_.last_ms = now;
|
|
|
|
stats_.target_media_bitrate_bps = bitrate_bps;
|
|
}
|
|
|
|
void SendStatisticsProxy::UpdateEncoderFallbackStats(
|
|
const CodecSpecificInfo* codec_info,
|
|
int pixels) {
|
|
UpdateFallbackDisabledStats(codec_info, pixels);
|
|
|
|
if (!fallback_max_pixels_ || !uma_container_->fallback_info_.is_possible) {
|
|
return;
|
|
}
|
|
|
|
if (!IsForcedFallbackPossible(codec_info)) {
|
|
uma_container_->fallback_info_.is_possible = false;
|
|
return;
|
|
}
|
|
|
|
FallbackEncoderInfo* fallback_info = &uma_container_->fallback_info_;
|
|
|
|
const int64_t now_ms = clock_->TimeInMilliseconds();
|
|
bool is_active = fallback_info->is_active;
|
|
if (codec_info->codec_name != stats_.encoder_implementation_name) {
|
|
// Implementation changed.
|
|
is_active = strcmp(codec_info->codec_name, kVp8SwCodecName) == 0;
|
|
if (!is_active && stats_.encoder_implementation_name != kVp8SwCodecName) {
|
|
// First or not a VP8 SW change, update stats on next call.
|
|
return;
|
|
}
|
|
if (is_active && (pixels > *fallback_max_pixels_)) {
|
|
// Pixels should not be above |fallback_max_pixels_|. If above skip to
|
|
// avoid fallbacks due to failure.
|
|
fallback_info->is_possible = false;
|
|
return;
|
|
}
|
|
stats_.has_entered_low_resolution = true;
|
|
++fallback_info->on_off_events;
|
|
}
|
|
|
|
if (fallback_info->last_update_ms) {
|
|
int64_t diff_ms = now_ms - *(fallback_info->last_update_ms);
|
|
// If the time diff since last update is greater than |max_frame_diff_ms|,
|
|
// video is considered paused/muted and the change is not included.
|
|
if (diff_ms < fallback_info->max_frame_diff_ms) {
|
|
uma_container_->fallback_active_counter_.Add(fallback_info->is_active,
|
|
diff_ms);
|
|
fallback_info->elapsed_ms += diff_ms;
|
|
}
|
|
}
|
|
fallback_info->is_active = is_active;
|
|
fallback_info->last_update_ms.emplace(now_ms);
|
|
}
|
|
|
|
void SendStatisticsProxy::UpdateFallbackDisabledStats(
|
|
const CodecSpecificInfo* codec_info,
|
|
int pixels) {
|
|
if (!fallback_max_pixels_disabled_ ||
|
|
!uma_container_->fallback_info_disabled_.is_possible ||
|
|
stats_.has_entered_low_resolution) {
|
|
return;
|
|
}
|
|
|
|
if (!IsForcedFallbackPossible(codec_info) ||
|
|
strcmp(codec_info->codec_name, kVp8SwCodecName) == 0) {
|
|
uma_container_->fallback_info_disabled_.is_possible = false;
|
|
return;
|
|
}
|
|
|
|
if (pixels <= *fallback_max_pixels_disabled_ ||
|
|
uma_container_->fallback_info_disabled_.min_pixel_limit_reached) {
|
|
stats_.has_entered_low_resolution = true;
|
|
}
|
|
}
|
|
|
|
void SendStatisticsProxy::OnMinPixelLimitReached() {
|
|
rtc::CritScope lock(&crit_);
|
|
uma_container_->fallback_info_disabled_.min_pixel_limit_reached = true;
|
|
}
|
|
|
|
void SendStatisticsProxy::OnSendEncodedImage(
|
|
const EncodedImage& encoded_image,
|
|
const CodecSpecificInfo* codec_info) {
|
|
size_t simulcast_idx = 0;
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
++stats_.frames_encoded;
|
|
if (codec_info) {
|
|
if (codec_info->codecType == kVideoCodecVP8) {
|
|
simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
|
|
} else if (codec_info->codecType == kVideoCodecGeneric) {
|
|
simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
|
|
}
|
|
if (codec_info->codec_name) {
|
|
UpdateEncoderFallbackStats(codec_info, encoded_image._encodedWidth *
|
|
encoded_image._encodedHeight);
|
|
stats_.encoder_implementation_name = codec_info->codec_name;
|
|
}
|
|
}
|
|
|
|
if (simulcast_idx >= rtp_config_.ssrcs.size()) {
|
|
RTC_LOG(LS_ERROR) << "Encoded image outside simulcast range ("
|
|
<< simulcast_idx << " >= " << rtp_config_.ssrcs.size()
|
|
<< ").";
|
|
return;
|
|
}
|
|
uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx];
|
|
|
|
VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
|
|
if (!stats)
|
|
return;
|
|
|
|
// TODO(ssilkin): Fix stats reporting for spatial layers in SVC.
|
|
stats->width = encoded_image._encodedWidth;
|
|
stats->height = encoded_image._encodedHeight;
|
|
update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
|
|
|
|
uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
|
|
kVideoFrameKey);
|
|
|
|
if (encoded_image.qp_ != -1) {
|
|
if (!stats_.qp_sum)
|
|
stats_.qp_sum = 0;
|
|
*stats_.qp_sum += encoded_image.qp_;
|
|
|
|
if (codec_info) {
|
|
if (codec_info->codecType == kVideoCodecVP8) {
|
|
int spatial_idx = (rtp_config_.ssrcs.size() == 1)
|
|
? -1
|
|
: static_cast<int>(simulcast_idx);
|
|
uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
|
|
} else if (codec_info->codecType == kVideoCodecVP9) {
|
|
int spatial_idx =
|
|
(codec_info->codecSpecific.VP9.num_spatial_layers == 1)
|
|
? -1
|
|
: codec_info->codecSpecific.VP9.spatial_idx;
|
|
uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
|
|
} else if (codec_info->codecType == kVideoCodecH264) {
|
|
int spatial_idx = -1;
|
|
uma_container_->qp_counters_[spatial_idx].h264.Add(encoded_image.qp_);
|
|
}
|
|
}
|
|
}
|
|
|
|
media_byte_rate_tracker_.AddSamples(encoded_image._length);
|
|
|
|
// Initialize to current since |is_limited_in_resolution| is only updated
|
|
// when an encoded frame is removed from the EncodedFrameMap.
|
|
bool is_limited_in_resolution = stats_.bw_limited_resolution;
|
|
if (uma_container_->InsertEncodedFrame(encoded_image, simulcast_idx,
|
|
&is_limited_in_resolution)) {
|
|
encoded_frame_rate_tracker_.AddSamples(1);
|
|
}
|
|
|
|
stats_.bw_limited_resolution =
|
|
is_limited_in_resolution || quality_downscales_ > 0;
|
|
|
|
if (quality_downscales_ != -1) {
|
|
uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0);
|
|
if (quality_downscales_ > 0)
|
|
uma_container_->quality_downscales_counter_.Add(quality_downscales_);
|
|
}
|
|
}
|
|
|
|
int SendStatisticsProxy::GetSendFrameRate() const {
|
|
rtc::CritScope lock(&crit_);
|
|
return round(encoded_frame_rate_tracker_.ComputeRate());
|
|
}
|
|
|
|
void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
|
|
rtc::CritScope lock(&crit_);
|
|
uma_container_->input_frame_rate_tracker_.AddSamples(1);
|
|
uma_container_->input_fps_counter_.Add(1);
|
|
uma_container_->input_width_counter_.Add(width);
|
|
uma_container_->input_height_counter_.Add(height);
|
|
if (cpu_downscales_ >= 0) {
|
|
uma_container_->cpu_limited_frame_counter_.Add(
|
|
stats_.cpu_limited_resolution);
|
|
}
|
|
if (encoded_frame_rate_tracker_.TotalSampleCount() == 0) {
|
|
// Set start time now instead of when first key frame is encoded to avoid a
|
|
// too high initial estimate.
|
|
encoded_frame_rate_tracker_.AddSamples(0);
|
|
}
|
|
}
|
|
|
|
void SendStatisticsProxy::OnFrameDroppedBySource() {
|
|
rtc::CritScope lock(&crit_);
|
|
++stats_.frames_dropped_by_capturer;
|
|
}
|
|
|
|
void SendStatisticsProxy::OnFrameDroppedInEncoderQueue() {
|
|
rtc::CritScope lock(&crit_);
|
|
++stats_.frames_dropped_by_encoder_queue;
|
|
}
|
|
|
|
void SendStatisticsProxy::OnFrameDroppedByEncoder() {
|
|
rtc::CritScope lock(&crit_);
|
|
++stats_.frames_dropped_by_encoder;
|
|
}
|
|
|
|
void SendStatisticsProxy::OnFrameDroppedByMediaOptimizations() {
|
|
rtc::CritScope lock(&crit_);
|
|
++stats_.frames_dropped_by_rate_limiter;
|
|
}
|
|
|
|
void SendStatisticsProxy::SetAdaptationStats(
|
|
const VideoStreamEncoder::AdaptCounts& cpu_counts,
|
|
const VideoStreamEncoder::AdaptCounts& quality_counts) {
|
|
rtc::CritScope lock(&crit_);
|
|
SetAdaptTimer(cpu_counts, &uma_container_->cpu_adapt_timer_);
|
|
SetAdaptTimer(quality_counts, &uma_container_->quality_adapt_timer_);
|
|
UpdateAdaptationStats(cpu_counts, quality_counts);
|
|
}
|
|
|
|
void SendStatisticsProxy::OnCpuAdaptationChanged(
|
|
const VideoStreamEncoder::AdaptCounts& cpu_counts,
|
|
const VideoStreamEncoder::AdaptCounts& quality_counts) {
|
|
rtc::CritScope lock(&crit_);
|
|
++stats_.number_of_cpu_adapt_changes;
|
|
UpdateAdaptationStats(cpu_counts, quality_counts);
|
|
}
|
|
|
|
void SendStatisticsProxy::OnQualityAdaptationChanged(
|
|
const VideoStreamEncoder::AdaptCounts& cpu_counts,
|
|
const VideoStreamEncoder::AdaptCounts& quality_counts) {
|
|
rtc::CritScope lock(&crit_);
|
|
TryUpdateInitialQualityResolutionAdaptUp(quality_counts);
|
|
++stats_.number_of_quality_adapt_changes;
|
|
UpdateAdaptationStats(cpu_counts, quality_counts);
|
|
}
|
|
|
|
void SendStatisticsProxy::UpdateAdaptationStats(
|
|
const VideoStreamEncoder::AdaptCounts& cpu_counts,
|
|
const VideoStreamEncoder::AdaptCounts& quality_counts) {
|
|
cpu_downscales_ = cpu_counts.resolution;
|
|
quality_downscales_ = quality_counts.resolution;
|
|
|
|
stats_.cpu_limited_resolution = cpu_counts.resolution > 0;
|
|
stats_.cpu_limited_framerate = cpu_counts.fps > 0;
|
|
stats_.bw_limited_resolution = quality_counts.resolution > 0;
|
|
stats_.bw_limited_framerate = quality_counts.fps > 0;
|
|
}
|
|
|
|
// TODO(asapersson): Include fps changes.
|
|
void SendStatisticsProxy::OnInitialQualityResolutionAdaptDown() {
|
|
rtc::CritScope lock(&crit_);
|
|
++uma_container_->initial_quality_changes_.down;
|
|
}
|
|
|
|
void SendStatisticsProxy::TryUpdateInitialQualityResolutionAdaptUp(
|
|
const VideoStreamEncoder::AdaptCounts& quality_counts) {
|
|
if (uma_container_->initial_quality_changes_.down == 0)
|
|
return;
|
|
|
|
if (quality_downscales_ > 0 &&
|
|
quality_counts.resolution < quality_downscales_) {
|
|
// Adapting up in quality.
|
|
if (uma_container_->initial_quality_changes_.down >
|
|
uma_container_->initial_quality_changes_.up) {
|
|
++uma_container_->initial_quality_changes_.up;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SendStatisticsProxy::SetAdaptTimer(
|
|
const VideoStreamEncoder::AdaptCounts& counts,
|
|
StatsTimer* timer) {
|
|
if (counts.resolution >= 0 || counts.fps >= 0) {
|
|
// Adaptation enabled.
|
|
if (!stats_.suspended)
|
|
timer->Start(clock_->TimeInMilliseconds());
|
|
return;
|
|
}
|
|
timer->Stop(clock_->TimeInMilliseconds());
|
|
}
|
|
|
|
void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
|
|
uint32_t ssrc,
|
|
const RtcpPacketTypeCounter& packet_counter) {
|
|
rtc::CritScope lock(&crit_);
|
|
VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
|
|
if (!stats)
|
|
return;
|
|
|
|
stats->rtcp_packet_type_counts = packet_counter;
|
|
if (uma_container_->first_rtcp_stats_time_ms_ == -1)
|
|
uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
|
|
}
|
|
|
|
void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
|
|
uint32_t ssrc) {
|
|
rtc::CritScope lock(&crit_);
|
|
VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
|
|
if (!stats)
|
|
return;
|
|
|
|
stats->rtcp_stats = statistics;
|
|
uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
|
|
}
|
|
|
|
void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
|
|
|
|
void SendStatisticsProxy::DataCountersUpdated(
|
|
const StreamDataCounters& counters,
|
|
uint32_t ssrc) {
|
|
rtc::CritScope lock(&crit_);
|
|
VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
|
|
RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc " << ssrc;
|
|
|
|
if (stats->is_flexfec) {
|
|
// The same counters are reported for both the media ssrc and flexfec ssrc.
|
|
// Bitrate stats are summed for all SSRCs. Use fec stats from media update.
|
|
return;
|
|
}
|
|
|
|
stats->rtp_stats = counters;
|
|
if (uma_container_->first_rtp_stats_time_ms_ == -1) {
|
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
|
uma_container_->first_rtp_stats_time_ms_ = now_ms;
|
|
uma_container_->cpu_adapt_timer_.Restart(now_ms);
|
|
uma_container_->quality_adapt_timer_.Restart(now_ms);
|
|
}
|
|
|
|
uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(),
|
|
ssrc);
|
|
uma_container_->padding_byte_counter_.Set(counters.transmitted.padding_bytes,
|
|
ssrc);
|
|
uma_container_->retransmit_byte_counter_.Set(
|
|
counters.retransmitted.TotalBytes(), ssrc);
|
|
uma_container_->fec_byte_counter_.Set(counters.fec.TotalBytes(), ssrc);
|
|
if (stats->is_rtx) {
|
|
uma_container_->rtx_byte_counter_.Set(counters.transmitted.TotalBytes(),
|
|
ssrc);
|
|
} else {
|
|
uma_container_->media_byte_counter_.Set(counters.MediaPayloadBytes(), ssrc);
|
|
}
|
|
}
|
|
|
|
void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
|
|
uint32_t retransmit_bitrate_bps,
|
|
uint32_t ssrc) {
|
|
rtc::CritScope lock(&crit_);
|
|
VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
|
|
if (!stats)
|
|
return;
|
|
|
|
stats->total_bitrate_bps = total_bitrate_bps;
|
|
stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
|
|
}
|
|
|
|
void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
|
|
uint32_t ssrc) {
|
|
rtc::CritScope lock(&crit_);
|
|
VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
|
|
if (!stats)
|
|
return;
|
|
|
|
stats->frame_counts = frame_counts;
|
|
}
|
|
|
|
void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
|
|
int max_delay_ms,
|
|
uint32_t ssrc) {
|
|
rtc::CritScope lock(&crit_);
|
|
VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
|
|
if (!stats)
|
|
return;
|
|
stats->avg_delay_ms = avg_delay_ms;
|
|
stats->max_delay_ms = max_delay_ms;
|
|
|
|
uma_container_->delay_counter_.Add(avg_delay_ms);
|
|
uma_container_->max_delay_counter_.Add(max_delay_ms);
|
|
}
|
|
|
|
void SendStatisticsProxy::StatsTimer::Start(int64_t now_ms) {
|
|
if (start_ms == -1)
|
|
start_ms = now_ms;
|
|
}
|
|
|
|
void SendStatisticsProxy::StatsTimer::Stop(int64_t now_ms) {
|
|
if (start_ms != -1) {
|
|
total_ms += now_ms - start_ms;
|
|
start_ms = -1;
|
|
}
|
|
}
|
|
|
|
void SendStatisticsProxy::StatsTimer::Restart(int64_t now_ms) {
|
|
total_ms = 0;
|
|
if (start_ms != -1)
|
|
start_ms = now_ms;
|
|
}
|
|
|
|
void SendStatisticsProxy::SampleCounter::Add(int sample) {
|
|
sum += sample;
|
|
++num_samples;
|
|
}
|
|
|
|
int SendStatisticsProxy::SampleCounter::Avg(
|
|
int64_t min_required_samples) const {
|
|
if (num_samples < min_required_samples || num_samples == 0)
|
|
return -1;
|
|
return static_cast<int>((sum + (num_samples / 2)) / num_samples);
|
|
}
|
|
|
|
void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
|
|
if (sample)
|
|
++sum;
|
|
++num_samples;
|
|
}
|
|
|
|
void SendStatisticsProxy::BoolSampleCounter::Add(bool sample, int64_t count) {
|
|
if (sample)
|
|
sum += count;
|
|
num_samples += count;
|
|
}
|
|
int SendStatisticsProxy::BoolSampleCounter::Percent(
|
|
int64_t min_required_samples) const {
|
|
return Fraction(min_required_samples, 100.0f);
|
|
}
|
|
|
|
int SendStatisticsProxy::BoolSampleCounter::Permille(
|
|
int64_t min_required_samples) const {
|
|
return Fraction(min_required_samples, 1000.0f);
|
|
}
|
|
|
|
int SendStatisticsProxy::BoolSampleCounter::Fraction(
|
|
int64_t min_required_samples,
|
|
float multiplier) const {
|
|
if (num_samples < min_required_samples || num_samples == 0)
|
|
return -1;
|
|
return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
|
|
}
|
|
} // namespace webrtc
|