twilio-video 2.34.0 → 2.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release.json +1 -2
- package/CHANGELOG.md +11 -0
- package/README.md +9 -10
- package/dist/twilio-video.js +29836 -32994
- package/dist/twilio-video.min.js +2 -23
- package/es5/cancelableroompromise.js +4 -4
- package/es5/cancelableroompromise.js.map +1 -1
- package/es5/connect.js +86 -90
- package/es5/connect.js.map +1 -1
- package/es5/createlocaltrack.js +7 -7
- package/es5/createlocaltrack.js.map +1 -1
- package/es5/createlocaltracks.js +111 -195
- package/es5/createlocaltracks.js.map +1 -1
- package/es5/data/receiver.js +16 -34
- package/es5/data/receiver.js.map +1 -1
- package/es5/data/sender.js +28 -47
- package/es5/data/sender.js.map +1 -1
- package/es5/data/transceiver.js +6 -24
- package/es5/data/transceiver.js.map +1 -1
- package/es5/data/transport.js +18 -37
- package/es5/data/transport.js.map +1 -1
- package/es5/encodingparameters.js +14 -33
- package/es5/encodingparameters.js.map +1 -1
- package/es5/eventemitter.js +2 -2
- package/es5/eventemitter.js.map +1 -1
- package/es5/eventtarget.js +12 -40
- package/es5/eventtarget.js.map +1 -1
- package/es5/index.js +21 -32
- package/es5/index.js.map +1 -1
- package/es5/insights/applicationmonitor.js +16 -18
- package/es5/insights/applicationmonitor.js.map +1 -1
- package/es5/insights/computepressuremonitor.js +33 -79
- package/es5/insights/computepressuremonitor.js.map +1 -1
- package/es5/insights/events/application.js +9 -10
- package/es5/insights/events/application.js.map +1 -1
- package/es5/insights/events/getusermedia.js +9 -10
- package/es5/insights/events/getusermedia.js.map +1 -1
- package/es5/insights/events/network.js +14 -16
- package/es5/insights/events/network.js.map +1 -1
- package/es5/insights/events/peerconnection.js +31 -44
- package/es5/insights/events/peerconnection.js.map +1 -1
- package/es5/insights/events/quality.js +13 -14
- package/es5/insights/events/quality.js.map +1 -1
- package/es5/insights/events/room.js +12 -13
- package/es5/insights/events/room.js.map +1 -1
- package/es5/insights/events/system.js +6 -7
- package/es5/insights/events/system.js.map +1 -1
- package/es5/insights/events/track.js +15 -18
- package/es5/insights/events/track.js.map +1 -1
- package/es5/insights/monitorregistry.js +10 -12
- package/es5/insights/monitorregistry.js.map +1 -1
- package/es5/insights/networkmonitor.js +17 -18
- package/es5/insights/networkmonitor.js.map +1 -1
- package/es5/insights/resourcemonitor.js +15 -17
- package/es5/insights/resourcemonitor.js.map +1 -1
- package/es5/insights/statsmonitor.js +100 -172
- package/es5/insights/statsmonitor.js.map +1 -1
- package/es5/insights/telemetry.js +40 -47
- package/es5/insights/telemetry.js.map +1 -1
- package/es5/localparticipant.js +122 -148
- package/es5/localparticipant.js.map +1 -1
- package/es5/media/track/audiotrack.js +11 -28
- package/es5/media/track/audiotrack.js.map +1 -1
- package/es5/media/track/capturevideoframes.js +21 -37
- package/es5/media/track/capturevideoframes.js.map +1 -1
- package/es5/media/track/es5/localaudiotrack.js +3 -3
- package/es5/media/track/es5/localaudiotrack.js.map +1 -1
- package/es5/media/track/es5/localdatatrack.js +3 -3
- package/es5/media/track/es5/localdatatrack.js.map +1 -1
- package/es5/media/track/es5/localvideotrack.js +3 -3
- package/es5/media/track/es5/localvideotrack.js.map +1 -1
- package/es5/media/track/index.js +17 -36
- package/es5/media/track/index.js.map +1 -1
- package/es5/media/track/localaudiotrack.js +80 -105
- package/es5/media/track/localaudiotrack.js.map +1 -1
- package/es5/media/track/localaudiotrackpublication.js +8 -25
- package/es5/media/track/localaudiotrackpublication.js.map +1 -1
- package/es5/media/track/localdatatrack.js +11 -30
- package/es5/media/track/localdatatrack.js.map +1 -1
- package/es5/media/track/localdatatrackpublication.js +8 -25
- package/es5/media/track/localdatatrackpublication.js.map +1 -1
- package/es5/media/track/localmediatrack.js +104 -129
- package/es5/media/track/localmediatrack.js.map +1 -1
- package/es5/media/track/localtrackpublication.js +24 -82
- package/es5/media/track/localtrackpublication.js.map +1 -1
- package/es5/media/track/localvideotrack.js +87 -112
- package/es5/media/track/localvideotrack.js.map +1 -1
- package/es5/media/track/localvideotrackpublication.js +8 -25
- package/es5/media/track/localvideotrackpublication.js.map +1 -1
- package/es5/media/track/mediatrack.js +71 -95
- package/es5/media/track/mediatrack.js.map +1 -1
- package/es5/media/track/noisecancellationimpl.js +63 -129
- package/es5/media/track/noisecancellationimpl.js.map +1 -1
- package/es5/media/track/receiver.js +5 -22
- package/es5/media/track/receiver.js.map +1 -1
- package/es5/media/track/remoteaudiotrack.js +16 -33
- package/es5/media/track/remoteaudiotrack.js.map +1 -1
- package/es5/media/track/remoteaudiotrackpublication.js +8 -25
- package/es5/media/track/remoteaudiotrackpublication.js.map +1 -1
- package/es5/media/track/remotedatatrack.js +18 -61
- package/es5/media/track/remotedatatrack.js.map +1 -1
- package/es5/media/track/remotedatatrackpublication.js +8 -25
- package/es5/media/track/remotedatatrackpublication.js.map +1 -1
- package/es5/media/track/remotemediatrack.js +36 -80
- package/es5/media/track/remotemediatrack.js.map +1 -1
- package/es5/media/track/remotetrackpublication.js +30 -48
- package/es5/media/track/remotetrackpublication.js.map +1 -1
- package/es5/media/track/remotevideotrack.js +94 -133
- package/es5/media/track/remotevideotrack.js.map +1 -1
- package/es5/media/track/remotevideotrackpublication.js +8 -25
- package/es5/media/track/remotevideotrackpublication.js.map +1 -1
- package/es5/media/track/sender.js +46 -83
- package/es5/media/track/sender.js.map +1 -1
- package/es5/media/track/trackpublication.js +17 -35
- package/es5/media/track/trackpublication.js.map +1 -1
- package/es5/media/track/transceiver.js +12 -30
- package/es5/media/track/transceiver.js.map +1 -1
- package/es5/media/track/videoprocessoreventobserver.js +47 -65
- package/es5/media/track/videoprocessoreventobserver.js.map +1 -1
- package/es5/media/track/videotrack.js +103 -124
- package/es5/media/track/videotrack.js.map +1 -1
- package/es5/networkqualityconfiguration.js +12 -48
- package/es5/networkqualityconfiguration.js.map +1 -1
- package/es5/noisecancellationadapter.js +72 -120
- package/es5/noisecancellationadapter.js.map +1 -1
- package/es5/participant.js +126 -179
- package/es5/participant.js.map +1 -1
- package/es5/preflight/getCombinedConnectionStats.js +44 -95
- package/es5/preflight/getCombinedConnectionStats.js.map +1 -1
- package/es5/preflight/getturncredentials.js +13 -13
- package/es5/preflight/getturncredentials.js.map +1 -1
- package/es5/preflight/makestat.js +4 -29
- package/es5/preflight/makestat.js.map +1 -1
- package/es5/preflight/mos.js +5 -5
- package/es5/preflight/mos.js.map +1 -1
- package/es5/preflight/preflighttest.js +240 -381
- package/es5/preflight/preflighttest.js.map +1 -1
- package/es5/preflight/syntheticaudio.js +8 -8
- package/es5/preflight/syntheticaudio.js.map +1 -1
- package/es5/preflight/syntheticvideo.js +13 -14
- package/es5/preflight/syntheticvideo.js.map +1 -1
- package/es5/preflight/timer.js +9 -10
- package/es5/preflight/timer.js.map +1 -1
- package/es5/queueingeventemitter.js +16 -60
- package/es5/queueingeventemitter.js.map +1 -1
- package/es5/remoteparticipant.js +33 -76
- package/es5/remoteparticipant.js.map +1 -1
- package/es5/room.js +89 -169
- package/es5/room.js.map +1 -1
- package/es5/signaling/index.js +36 -55
- package/es5/signaling/index.js.map +1 -1
- package/es5/signaling/localparticipant.js +18 -37
- package/es5/signaling/localparticipant.js.map +1 -1
- package/es5/signaling/localtrackpublication.js +28 -51
- package/es5/signaling/localtrackpublication.js.map +1 -1
- package/es5/signaling/participant.js +37 -63
- package/es5/signaling/participant.js.map +1 -1
- package/es5/signaling/recording.js +11 -29
- package/es5/signaling/recording.js.map +1 -1
- package/es5/signaling/remoteparticipant.js +6 -24
- package/es5/signaling/remoteparticipant.js.map +1 -1
- package/es5/signaling/remotetrackpublication.js +27 -53
- package/es5/signaling/remotetrackpublication.js.map +1 -1
- package/es5/signaling/room.js +40 -59
- package/es5/signaling/room.js.map +1 -1
- package/es5/signaling/track.js +52 -90
- package/es5/signaling/track.js.map +1 -1
- package/es5/signaling/v2/cancelableroomsignalingpromise.js +46 -46
- package/es5/signaling/v2/cancelableroomsignalingpromise.js.map +1 -1
- package/es5/signaling/v2/dominantspeakersignaling.js +18 -40
- package/es5/signaling/v2/dominantspeakersignaling.js.map +1 -1
- package/es5/signaling/v2/icebox.js +12 -13
- package/es5/signaling/v2/icebox.js.map +1 -1
- package/es5/signaling/v2/iceconnectionmonitor.js +28 -32
- package/es5/signaling/v2/iceconnectionmonitor.js.map +1 -1
- package/es5/signaling/v2/index.js +12 -31
- package/es5/signaling/v2/index.js.map +1 -1
- package/es5/signaling/v2/localparticipant.js +65 -85
- package/es5/signaling/v2/localparticipant.js.map +1 -1
- package/es5/signaling/v2/localtrackpublication.js +21 -39
- package/es5/signaling/v2/localtrackpublication.js.map +1 -1
- package/es5/signaling/v2/mediasignaling.js +25 -48
- package/es5/signaling/v2/mediasignaling.js.map +1 -1
- package/es5/signaling/v2/networkqualitymonitor.js +50 -97
- package/es5/signaling/v2/networkqualitymonitor.js.map +1 -1
- package/es5/signaling/v2/networkqualitysignaling.js +56 -88
- package/es5/signaling/v2/networkqualitysignaling.js.map +1 -1
- package/es5/signaling/v2/peerconnection.js +523 -648
- package/es5/signaling/v2/peerconnection.js.map +1 -1
- package/es5/signaling/v2/peerconnectionmanager.js +111 -167
- package/es5/signaling/v2/peerconnectionmanager.js.map +1 -1
- package/es5/signaling/v2/publisherhintsignaling.js +22 -42
- package/es5/signaling/v2/publisherhintsignaling.js.map +1 -1
- package/es5/signaling/v2/recording.js +8 -26
- package/es5/signaling/v2/recording.js.map +1 -1
- package/es5/signaling/v2/remoteparticipant.js +25 -43
- package/es5/signaling/v2/remoteparticipant.js.map +1 -1
- package/es5/signaling/v2/remotetrackpublication.js +7 -24
- package/es5/signaling/v2/remotetrackpublication.js.map +1 -1
- package/es5/signaling/v2/renderhintssignaling.js +40 -61
- package/es5/signaling/v2/renderhintssignaling.js.map +1 -1
- package/es5/signaling/v2/room.js +216 -280
- package/es5/signaling/v2/room.js.map +1 -1
- package/es5/signaling/v2/trackprioritysignaling.js +11 -29
- package/es5/signaling/v2/trackprioritysignaling.js.map +1 -1
- package/es5/signaling/v2/trackswitchoffsignaling.js +10 -28
- package/es5/signaling/v2/trackswitchoffsignaling.js.map +1 -1
- package/es5/signaling/v2/transcriptionsignaling.js +8 -26
- package/es5/signaling/v2/transcriptionsignaling.js.map +1 -1
- package/es5/signaling/v2/twilioconnectiontransport.js +62 -82
- package/es5/signaling/v2/twilioconnectiontransport.js.map +1 -1
- package/es5/statemachine.js +75 -121
- package/es5/statemachine.js.map +1 -1
- package/es5/stats/average.js +2 -2
- package/es5/stats/average.js.map +1 -1
- package/es5/stats/icereport.js +11 -12
- package/es5/stats/icereport.js.map +1 -1
- package/es5/stats/icereportfactory.js +8 -9
- package/es5/stats/icereportfactory.js.map +1 -1
- package/es5/stats/localaudiotrackstats.js +6 -24
- package/es5/stats/localaudiotrackstats.js.map +1 -1
- package/es5/stats/localtrackstats.js +6 -24
- package/es5/stats/localtrackstats.js.map +1 -1
- package/es5/stats/localvideotrackstats.js +9 -27
- package/es5/stats/localvideotrackstats.js.map +1 -1
- package/es5/stats/networkqualityaudiostats.js +5 -22
- package/es5/stats/networkqualityaudiostats.js.map +1 -1
- package/es5/stats/networkqualitybandwidthstats.js +3 -5
- package/es5/stats/networkqualitybandwidthstats.js.map +1 -1
- package/es5/stats/networkqualityfractionloststats.js +3 -5
- package/es5/stats/networkqualityfractionloststats.js.map +1 -1
- package/es5/stats/networkqualitylatencystats.js +3 -5
- package/es5/stats/networkqualitylatencystats.js.map +1 -1
- package/es5/stats/networkqualitymediastats.js +5 -7
- package/es5/stats/networkqualitymediastats.js.map +1 -1
- package/es5/stats/networkqualityrecvstats.js +5 -22
- package/es5/stats/networkqualityrecvstats.js.map +1 -1
- package/es5/stats/networkqualitysendorrecvstats.js +6 -8
- package/es5/stats/networkqualitysendorrecvstats.js.map +1 -1
- package/es5/stats/networkqualitysendstats.js +5 -22
- package/es5/stats/networkqualitysendstats.js.map +1 -1
- package/es5/stats/networkqualitystats.js +5 -7
- package/es5/stats/networkqualitystats.js.map +1 -1
- package/es5/stats/networkqualityvideostats.js +5 -22
- package/es5/stats/networkqualityvideostats.js.map +1 -1
- package/es5/stats/peerconnectionreport.js +13 -14
- package/es5/stats/peerconnectionreport.js.map +1 -1
- package/es5/stats/peerconnectionreportfactory.js +89 -185
- package/es5/stats/peerconnectionreportfactory.js.map +1 -1
- package/es5/stats/receiverreport.js +28 -46
- package/es5/stats/receiverreport.js.map +1 -1
- package/es5/stats/receiverreportfactory.js +11 -29
- package/es5/stats/receiverreportfactory.js.map +1 -1
- package/es5/stats/remoteaudiotrackstats.js +6 -24
- package/es5/stats/remoteaudiotrackstats.js.map +1 -1
- package/es5/stats/remotetrackstats.js +6 -24
- package/es5/stats/remotetrackstats.js.map +1 -1
- package/es5/stats/remotevideotrackstats.js +7 -25
- package/es5/stats/remotevideotrackstats.js.map +1 -1
- package/es5/stats/senderorreceiverreport.js +3 -4
- package/es5/stats/senderorreceiverreport.js.map +1 -1
- package/es5/stats/senderorreceiverreportfactory.js +3 -4
- package/es5/stats/senderorreceiverreportfactory.js.map +1 -1
- package/es5/stats/senderreport.js +20 -38
- package/es5/stats/senderreport.js.map +1 -1
- package/es5/stats/senderreportfactory.js +11 -29
- package/es5/stats/senderreportfactory.js.map +1 -1
- package/es5/stats/statsreport.js +11 -12
- package/es5/stats/statsreport.js.map +1 -1
- package/es5/stats/sum.js +1 -1
- package/es5/stats/sum.js.map +1 -1
- package/es5/stats/trackstats.js +3 -4
- package/es5/stats/trackstats.js.map +1 -1
- package/es5/transceiver.js +8 -26
- package/es5/transceiver.js.map +1 -1
- package/es5/twilioconnection.js +166 -223
- package/es5/twilioconnection.js.map +1 -1
- package/es5/util/asyncvar.js +12 -14
- package/es5/util/asyncvar.js.map +1 -1
- package/es5/util/backoff.js +14 -16
- package/es5/util/backoff.js.map +1 -1
- package/es5/util/browserdetection.js +19 -35
- package/es5/util/browserdetection.js.map +1 -1
- package/es5/util/cancelablepromise.js +30 -57
- package/es5/util/cancelablepromise.js.map +1 -1
- package/es5/util/constants.js +13 -13
- package/es5/util/constants.js.map +1 -1
- package/es5/util/detectsilentaudio.js +10 -10
- package/es5/util/detectsilentaudio.js.map +1 -1
- package/es5/util/detectsilentvideo.js +12 -12
- package/es5/util/detectsilentvideo.js.map +1 -1
- package/es5/util/documentvisibilitymonitor.js +34 -41
- package/es5/util/documentvisibilitymonitor.js.map +1 -1
- package/es5/util/dynamicimport.js +4 -4
- package/es5/util/dynamicimport.js.map +1 -1
- package/es5/util/eventobserver.js +19 -39
- package/es5/util/eventobserver.js.map +1 -1
- package/es5/util/filter.js +11 -12
- package/es5/util/filter.js.map +1 -1
- package/es5/util/index.js +96 -165
- package/es5/util/index.js.map +1 -1
- package/es5/util/insightspublisher/index.js +48 -78
- package/es5/util/insightspublisher/index.js.map +1 -1
- package/es5/util/insightspublisher/null.js +9 -10
- package/es5/util/insightspublisher/null.js.map +1 -1
- package/es5/util/localmediarestartdeferreds.js +10 -11
- package/es5/util/localmediarestartdeferreds.js.map +1 -1
- package/es5/util/log.js +44 -70
- package/es5/util/log.js.map +1 -1
- package/es5/util/movingaveragedelta.js +12 -13
- package/es5/util/movingaveragedelta.js.map +1 -1
- package/es5/util/networkmonitor.js +26 -30
- package/es5/util/networkmonitor.js.map +1 -1
- package/es5/util/nullobserver.js +22 -48
- package/es5/util/nullobserver.js.map +1 -1
- package/es5/util/sdp/index.js +109 -134
- package/es5/util/sdp/index.js.map +1 -1
- package/es5/util/sdp/issue8329.js +56 -57
- package/es5/util/sdp/issue8329.js.map +1 -1
- package/es5/util/sdp/simulcast.js +55 -73
- package/es5/util/sdp/simulcast.js.map +1 -1
- package/es5/util/sdp/trackmatcher.js +14 -15
- package/es5/util/sdp/trackmatcher.js.map +1 -1
- package/es5/util/sid.js +5 -5
- package/es5/util/sid.js.map +1 -1
- package/es5/util/support.js +13 -16
- package/es5/util/support.js.map +1 -1
- package/es5/util/timeout.js +28 -39
- package/es5/util/timeout.js.map +1 -1
- package/es5/util/timeoutpromise.js +38 -84
- package/es5/util/timeoutpromise.js.map +1 -1
- package/es5/util/twilio-video-errors.js +277 -457
- package/es5/util/twilio-video-errors.js.map +1 -1
- package/es5/util/twilioerror.js +13 -57
- package/es5/util/twilioerror.js.map +1 -1
- package/es5/util/twiliowarning.js +1 -1
- package/es5/util/twiliowarning.js.map +1 -1
- package/es5/util/validate.js +13 -15
- package/es5/util/validate.js.map +1 -1
- package/es5/vendor/inherits.js +3 -5
- package/es5/vendor/inherits.js.map +1 -1
- package/es5/webaudio/audiocontext.js +8 -9
- package/es5/webaudio/audiocontext.js.map +1 -1
- package/es5/webaudio/detectsilence.js +9 -9
- package/es5/webaudio/detectsilence.js.map +1 -1
- package/es5/webaudio/workaround180748.js +15 -13
- package/es5/webaudio/workaround180748.js.map +1 -1
- package/es5/webrtc/getstats.js +242 -448
- package/es5/webrtc/getstats.js.map +1 -1
- package/es5/webrtc/getusermedia.js +1 -2
- package/es5/webrtc/getusermedia.js.map +1 -1
- package/es5/webrtc/index.js +1 -17
- package/es5/webrtc/index.js.map +1 -1
- package/es5/webrtc/rtcpeerconnection/chrome.js +102 -295
- package/es5/webrtc/rtcpeerconnection/chrome.js.map +1 -1
- package/es5/webrtc/rtcpeerconnection/firefox.js +69 -146
- package/es5/webrtc/rtcpeerconnection/firefox.js.map +1 -1
- package/es5/webrtc/rtcpeerconnection/index.js +1 -1
- package/es5/webrtc/rtcpeerconnection/index.js.map +1 -1
- package/es5/webrtc/rtcpeerconnection/safari.js +110 -192
- package/es5/webrtc/rtcpeerconnection/safari.js.map +1 -1
- package/es5/webrtc/rtcrtpsender.js +3 -4
- package/es5/webrtc/rtcrtpsender.js.map +1 -1
- package/es5/webrtc/util/index.js +28 -63
- package/es5/webrtc/util/index.js.map +1 -1
- package/es5/webrtc/util/latch.js +21 -28
- package/es5/webrtc/util/latch.js.map +1 -1
- package/es5/webrtc/util/sdp.js +41 -211
- package/es5/webrtc/util/sdp.js.map +1 -1
- package/lib/connect.js +0 -1
- package/lib/createlocaltracks.ts +2 -2
- package/lib/localparticipant.js +0 -1
- package/lib/media/track/mediatrack.js +0 -2
- package/lib/media/track/noisecancellationimpl.ts +2 -2
- package/lib/noisecancellationadapter.ts +2 -2
- package/lib/preflight/getCombinedConnectionStats.ts +1 -1
- package/lib/preflight/getturncredentials.ts +2 -2
- package/lib/preflight/preflighttest.ts +3 -3
- package/lib/signaling/v2/peerconnection.js +2 -4
- package/lib/util/sdp/index.js +1 -2
- package/lib/util/sdp/issue8329.js +0 -2
- package/lib/util/support.js +4 -7
- package/lib/webrtc/getstats.js +6 -21
- package/lib/webrtc/index.js +0 -16
- package/lib/webrtc/rtcpeerconnection/chrome.js +13 -123
- package/lib/webrtc/rtcpeerconnection/firefox.js +5 -6
- package/lib/webrtc/rtcpeerconnection/safari.js +9 -19
- package/lib/webrtc/util/sdp.js +13 -194
- package/package.json +16 -11
- package/rollup.config.mjs +85 -0
- package/tsconfig.json +5 -5
- package/es5/webrtc/mediastream.js +0 -11
- package/es5/webrtc/mediastream.js.map +0 -1
- package/es5/webrtc/mediastreamtrack.js +0 -11
- package/es5/webrtc/mediastreamtrack.js.map +0 -1
- package/es5/webrtc/rtcicecandidate.js +0 -11
- package/es5/webrtc/rtcicecandidate.js.map +0 -1
- package/es5/webrtc/rtcsessiondescription/chrome.js +0 -43
- package/es5/webrtc/rtcsessiondescription/chrome.js.map +0 -1
- package/es5/webrtc/rtcsessiondescription/firefox.js +0 -4
- package/es5/webrtc/rtcsessiondescription/firefox.js.map +0 -1
- package/es5/webrtc/rtcsessiondescription/index.js +0 -22
- package/es5/webrtc/rtcsessiondescription/index.js.map +0 -1
- package/lib/webrtc/mediastream.js +0 -10
- package/lib/webrtc/mediastreamtrack.js +0 -10
- package/lib/webrtc/rtcicecandidate.js +0 -10
- package/lib/webrtc/rtcsessiondescription/chrome.js +0 -39
- package/lib/webrtc/rtcsessiondescription/firefox.js +0 -4
- package/lib/webrtc/rtcsessiondescription/index.js +0 -21
- package/src/twilio-video.js +0 -16
|
@@ -1,66 +1,26 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
catch (error) { e = { error: error }; }
|
|
25
|
-
finally {
|
|
26
|
-
try {
|
|
27
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
28
|
-
}
|
|
29
|
-
finally { if (e) throw e.error; }
|
|
30
|
-
}
|
|
31
|
-
return ar;
|
|
32
|
-
};
|
|
33
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
34
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
35
|
-
if (ar || !(i in from)) {
|
|
36
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
37
|
-
ar[i] = from[i];
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
41
|
-
};
|
|
42
|
-
var DefaultBackoff = require('../../util/backoff');
|
|
43
|
-
var _a = require('../../webrtc'), DefaultRTCIceCandidate = _a.RTCIceCandidate, DefaultRTCPeerConnection = _a.RTCPeerConnection, DefaultRTCSessionDescription = _a.RTCSessionDescription, getStatistics = _a.getStats;
|
|
44
|
-
var util = require('../../webrtc/util');
|
|
45
|
-
var _b = require('../../util/constants'), DEFAULT_ICE_GATHERING_TIMEOUT_MS = _b.DEFAULT_ICE_GATHERING_TIMEOUT_MS, DEFAULT_LOG_LEVEL = _b.DEFAULT_LOG_LEVEL, DEFAULT_SESSION_TIMEOUT_SEC = _b.DEFAULT_SESSION_TIMEOUT_SEC, iceRestartBackoffConfig = _b.iceRestartBackoffConfig;
|
|
46
|
-
var _c = require('../../util/sdp'), addOrRewriteNewTrackIds = _c.addOrRewriteNewTrackIds, addOrRewriteTrackIds = _c.addOrRewriteTrackIds, createCodecMapForMediaSection = _c.createCodecMapForMediaSection, disableRtx = _c.disableRtx, enableDtxForOpus = _c.enableDtxForOpus, getMediaSections = _c.getMediaSections, removeUnreferencedCodecAttributes = _c.removeUnreferencedCodecAttributes, removeSSRCAttributes = _c.removeSSRCAttributes, revertSimulcast = _c.revertSimulcast, setCodecPreferences = _c.setCodecPreferences, setSimulcast = _c.setSimulcast;
|
|
47
|
-
var DefaultTimeout = require('../../util/timeout');
|
|
48
|
-
var _d = require('../../util/twilio-video-errors'), MediaClientLocalDescFailedError = _d.MediaClientLocalDescFailedError, MediaClientRemoteDescFailedError = _d.MediaClientRemoteDescFailedError;
|
|
49
|
-
var _e = require('../../util'), buildLogLevels = _e.buildLogLevels, isChromeScreenShareTrack = _e.isChromeScreenShareTrack, oncePerTick = _e.oncePerTick, defer = _e.defer;
|
|
50
|
-
var IceBox = require('./icebox');
|
|
51
|
-
var DefaultIceConnectionMonitor = require('./iceconnectionmonitor.js');
|
|
52
|
-
var DataTrackReceiver = require('../../data/receiver');
|
|
53
|
-
var MediaTrackReceiver = require('../../media/track/receiver');
|
|
54
|
-
var StateMachine = require('../../statemachine');
|
|
55
|
-
var Log = require('../../util/log');
|
|
56
|
-
var TrackMatcher = require('../../util/sdp/trackmatcher');
|
|
57
|
-
var workaroundIssue8329 = require('../../util/sdp/issue8329');
|
|
58
|
-
var telemetry = require('../../insights/telemetry');
|
|
59
|
-
var guess = util.guessBrowser();
|
|
60
|
-
var isChrome = guess === 'chrome';
|
|
61
|
-
var isFirefox = guess === 'firefox';
|
|
62
|
-
var isSafari = guess === 'safari';
|
|
63
|
-
var nInstances = 0;
|
|
2
|
+
const DefaultBackoff = require('../../util/backoff');
|
|
3
|
+
const { RTCPeerConnection: DefaultRTCPeerConnection, getStats: getStatistics } = require('../../webrtc');
|
|
4
|
+
const util = require('../../webrtc/util');
|
|
5
|
+
const { DEFAULT_ICE_GATHERING_TIMEOUT_MS, DEFAULT_LOG_LEVEL, DEFAULT_SESSION_TIMEOUT_SEC, iceRestartBackoffConfig } = require('../../util/constants');
|
|
6
|
+
const { addOrRewriteNewTrackIds, addOrRewriteTrackIds, createCodecMapForMediaSection, disableRtx, enableDtxForOpus, getMediaSections, removeUnreferencedCodecAttributes, removeSSRCAttributes, revertSimulcast, setCodecPreferences, setSimulcast } = require('../../util/sdp');
|
|
7
|
+
const DefaultTimeout = require('../../util/timeout');
|
|
8
|
+
const { MediaClientLocalDescFailedError, MediaClientRemoteDescFailedError } = require('../../util/twilio-video-errors');
|
|
9
|
+
const { buildLogLevels, isChromeScreenShareTrack, oncePerTick, defer } = require('../../util');
|
|
10
|
+
const IceBox = require('./icebox');
|
|
11
|
+
const DefaultIceConnectionMonitor = require('./iceconnectionmonitor.js');
|
|
12
|
+
const DataTrackReceiver = require('../../data/receiver');
|
|
13
|
+
const MediaTrackReceiver = require('../../media/track/receiver');
|
|
14
|
+
const StateMachine = require('../../statemachine');
|
|
15
|
+
const Log = require('../../util/log');
|
|
16
|
+
const TrackMatcher = require('../../util/sdp/trackmatcher');
|
|
17
|
+
const workaroundIssue8329 = require('../../util/sdp/issue8329');
|
|
18
|
+
const telemetry = require('../../insights/telemetry');
|
|
19
|
+
const guess = util.guessBrowser();
|
|
20
|
+
const isChrome = guess === 'chrome';
|
|
21
|
+
const isFirefox = guess === 'firefox';
|
|
22
|
+
const isSafari = guess === 'safari';
|
|
23
|
+
let nInstances = 0;
|
|
64
24
|
/*
|
|
65
25
|
PeerConnectionV2 States
|
|
66
26
|
-----------------------
|
|
@@ -81,7 +41,7 @@ PeerConnectionV2 States
|
|
|
81
41
|
+----------+
|
|
82
42
|
|
|
83
43
|
*/
|
|
84
|
-
|
|
44
|
+
const states = {
|
|
85
45
|
open: [
|
|
86
46
|
'closed',
|
|
87
47
|
'updating'
|
|
@@ -100,8 +60,7 @@ var states = {
|
|
|
100
60
|
* @emits PeerConnectionV2#candidates
|
|
101
61
|
* @emits PeerConnectionV2#description
|
|
102
62
|
*/
|
|
103
|
-
|
|
104
|
-
__extends(PeerConnectionV2, _super);
|
|
63
|
+
class PeerConnectionV2 extends StateMachine {
|
|
105
64
|
/**
|
|
106
65
|
* Construct a {@link PeerConnectionV2}.
|
|
107
66
|
* @param {string} id
|
|
@@ -109,46 +68,46 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
109
68
|
* @param {PreferredCodecs} preferredCodecs
|
|
110
69
|
* @param {object} [options]
|
|
111
70
|
*/
|
|
112
|
-
|
|
113
|
-
|
|
71
|
+
constructor(id, encodingParameters, preferredCodecs, options) {
|
|
72
|
+
super('open', states);
|
|
114
73
|
options = Object.assign({
|
|
115
74
|
enableDscp: false,
|
|
116
75
|
dummyAudioMediaStreamTrack: null,
|
|
117
|
-
isChromeScreenShareTrack
|
|
76
|
+
isChromeScreenShareTrack,
|
|
118
77
|
iceServers: [],
|
|
119
78
|
logLevel: DEFAULT_LOG_LEVEL,
|
|
120
79
|
offerOptions: {},
|
|
121
|
-
revertSimulcast
|
|
80
|
+
revertSimulcast,
|
|
122
81
|
sessionTimeout: DEFAULT_SESSION_TIMEOUT_SEC * 1000,
|
|
123
|
-
setCodecPreferences
|
|
124
|
-
setSimulcast
|
|
82
|
+
setCodecPreferences,
|
|
83
|
+
setSimulcast,
|
|
125
84
|
Backoff: DefaultBackoff,
|
|
126
85
|
IceConnectionMonitor: DefaultIceConnectionMonitor,
|
|
127
|
-
RTCIceCandidate
|
|
86
|
+
RTCIceCandidate,
|
|
128
87
|
RTCPeerConnection: DefaultRTCPeerConnection,
|
|
129
|
-
RTCSessionDescription
|
|
88
|
+
RTCSessionDescription,
|
|
130
89
|
Timeout: DefaultTimeout
|
|
131
90
|
}, options);
|
|
132
91
|
// NOTE(lrivas): We intentionally include the options object for backward compatibility.
|
|
133
92
|
// The ConnectOptions 'iceServers' and 'iceTransportPolicy' are part of the 'RTCConfiguration' interface and should be passed
|
|
134
93
|
// as 'rtcConfiguration.iceServers' and 'rtcConfiguration.iceTransportPolicy' respectively.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
94
|
+
const configuration = getConfiguration(Object.assign({}, options, options.rtcConfiguration));
|
|
95
|
+
const logLevels = buildLogLevels(options.logLevel);
|
|
96
|
+
const RTCPeerConnection = options.RTCPeerConnection;
|
|
138
97
|
if (options.enableDscp === true) {
|
|
139
98
|
options.chromeSpecificConstraints = options.chromeSpecificConstraints || {};
|
|
140
99
|
options.chromeSpecificConstraints.optional = options.chromeSpecificConstraints.optional || [];
|
|
141
100
|
options.chromeSpecificConstraints.optional.push({ googDscp: true });
|
|
142
101
|
}
|
|
143
|
-
|
|
144
|
-
|
|
102
|
+
const log = options.log ? options.log.createLog('webrtc', this) : new Log('webrtc', this, logLevels, options.loggerName);
|
|
103
|
+
const peerConnection = new RTCPeerConnection(configuration, {
|
|
145
104
|
chromeSpecificConstraints: options.chromeSpecificConstraints,
|
|
146
|
-
applyCodecPreferences:
|
|
105
|
+
applyCodecPreferences: transceiver => this._applyCodecPreferencesToTransceiver(transceiver)
|
|
147
106
|
});
|
|
148
107
|
if (options.dummyAudioMediaStreamTrack) {
|
|
149
108
|
peerConnection.addTrack(options.dummyAudioMediaStreamTrack);
|
|
150
109
|
}
|
|
151
|
-
Object.defineProperties(
|
|
110
|
+
Object.defineProperties(this, {
|
|
152
111
|
_appliedTrackIdsToAttributes: {
|
|
153
112
|
value: new Map(),
|
|
154
113
|
writable: true
|
|
@@ -185,7 +144,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
185
144
|
writable: true
|
|
186
145
|
},
|
|
187
146
|
_iceGatheringTimeout: {
|
|
188
|
-
value: new options.Timeout(
|
|
147
|
+
value: new options.Timeout(() => this._handleIceGatheringTimeout(), DEFAULT_ICE_GATHERING_TIMEOUT_MS, false)
|
|
189
148
|
},
|
|
190
149
|
_iceRestartBackoff: {
|
|
191
150
|
value: new options.Backoff(iceRestartBackoffConfig)
|
|
@@ -274,9 +233,9 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
274
233
|
value: options.offerOptions
|
|
275
234
|
},
|
|
276
235
|
_onEncodingParametersChanged: {
|
|
277
|
-
value: oncePerTick(
|
|
278
|
-
if (!
|
|
279
|
-
updateEncodingParameters(
|
|
236
|
+
value: oncePerTick(() => {
|
|
237
|
+
if (!this._needsAnswer) {
|
|
238
|
+
updateEncodingParameters(this);
|
|
280
239
|
}
|
|
281
240
|
})
|
|
282
241
|
},
|
|
@@ -290,23 +249,17 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
290
249
|
value: preferredCodecs.video
|
|
291
250
|
},
|
|
292
251
|
_shouldApplyDtx: {
|
|
293
|
-
value: preferredCodecs.audio.every(
|
|
294
|
-
|
|
295
|
-
return codec !== 'opus';
|
|
296
|
-
})
|
|
297
|
-
|| preferredCodecs.audio.some(function (_a) {
|
|
298
|
-
var codec = _a.codec, dtx = _a.dtx;
|
|
299
|
-
return codec === 'opus' && dtx;
|
|
300
|
-
})
|
|
252
|
+
value: preferredCodecs.audio.every(({ codec }) => codec !== 'opus')
|
|
253
|
+
|| preferredCodecs.audio.some(({ codec, dtx }) => codec === 'opus' && dtx)
|
|
301
254
|
},
|
|
302
255
|
_queuedDescription: {
|
|
303
256
|
writable: true,
|
|
304
257
|
value: null
|
|
305
258
|
},
|
|
306
259
|
_iceReconnectTimeout: {
|
|
307
|
-
value: new options.Timeout(
|
|
260
|
+
value: new options.Timeout(() => {
|
|
308
261
|
log.debug('ICE reconnect timed out');
|
|
309
|
-
|
|
262
|
+
this.close();
|
|
310
263
|
}, options.sessionTimeout, false)
|
|
311
264
|
},
|
|
312
265
|
_recycledTransceivers: {
|
|
@@ -364,139 +317,117 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
364
317
|
value: id
|
|
365
318
|
}
|
|
366
319
|
});
|
|
367
|
-
encodingParameters.on('changed',
|
|
368
|
-
telemetry.pc.signalingState(
|
|
369
|
-
telemetry.pc.iceGatheringState(
|
|
370
|
-
telemetry.pc.iceConnectionState(
|
|
371
|
-
telemetry.pc.connectionState(
|
|
372
|
-
peerConnection.addEventListener('connectionstatechange',
|
|
373
|
-
peerConnection.addEventListener('datachannel',
|
|
374
|
-
peerConnection.addEventListener('icecandidate',
|
|
375
|
-
peerConnection.addEventListener('iceconnectionstatechange',
|
|
376
|
-
peerConnection.addEventListener('icegatheringstatechange',
|
|
377
|
-
peerConnection.addEventListener('signalingstatechange',
|
|
378
|
-
peerConnection.addEventListener('track',
|
|
379
|
-
|
|
380
|
-
|
|
320
|
+
encodingParameters.on('changed', this._onEncodingParametersChanged);
|
|
321
|
+
telemetry.pc.signalingState(this.id, peerConnection.signalingState);
|
|
322
|
+
telemetry.pc.iceGatheringState(this.id, peerConnection.iceGatheringState);
|
|
323
|
+
telemetry.pc.iceConnectionState(this.id, peerConnection.iceConnectionState);
|
|
324
|
+
telemetry.pc.connectionState(this.id, this.connectionState);
|
|
325
|
+
peerConnection.addEventListener('connectionstatechange', this._handleConnectionStateChange.bind(this));
|
|
326
|
+
peerConnection.addEventListener('datachannel', this._handleDataChannelEvent.bind(this));
|
|
327
|
+
peerConnection.addEventListener('icecandidate', this._handleIceCandidateEvent.bind(this));
|
|
328
|
+
peerConnection.addEventListener('iceconnectionstatechange', this._handleIceConnectionStateChange.bind(this));
|
|
329
|
+
peerConnection.addEventListener('icegatheringstatechange', this._handleIceGatheringStateChange.bind(this));
|
|
330
|
+
peerConnection.addEventListener('signalingstatechange', this._handleSignalingStateChange.bind(this));
|
|
331
|
+
peerConnection.addEventListener('track', this._handleTrackEvent.bind(this));
|
|
332
|
+
const self = this;
|
|
333
|
+
this.on('stateChanged', function stateChanged(state) {
|
|
381
334
|
if (state !== 'closed') {
|
|
382
335
|
return;
|
|
383
336
|
}
|
|
384
337
|
self.removeListener('stateChanged', stateChanged);
|
|
385
|
-
self._dataChannels.forEach(
|
|
338
|
+
self._dataChannels.forEach((dataChannel, dataTrackSender) => {
|
|
386
339
|
self.removeDataTrackSender(dataTrackSender);
|
|
387
340
|
});
|
|
388
341
|
});
|
|
389
|
-
return _this;
|
|
390
342
|
}
|
|
391
|
-
|
|
392
|
-
return
|
|
393
|
-
}
|
|
394
|
-
|
|
343
|
+
toString() {
|
|
344
|
+
return `[PeerConnectionV2 #${this._instanceId}: ${this.id}]`;
|
|
345
|
+
}
|
|
346
|
+
setEffectiveAdaptiveSimulcast(effectiveAdaptiveSimulcast) {
|
|
395
347
|
this._log.debug('Setting setEffectiveAdaptiveSimulcast: ', effectiveAdaptiveSimulcast);
|
|
396
348
|
// clear adaptive simulcast from codec preferences if it was set.
|
|
397
|
-
this._preferredVideoCodecs.forEach(
|
|
349
|
+
this._preferredVideoCodecs.forEach(cs => {
|
|
398
350
|
if ('adaptiveSimulcast' in cs) {
|
|
399
351
|
cs.adaptiveSimulcast = effectiveAdaptiveSimulcast;
|
|
400
352
|
}
|
|
401
353
|
});
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
? getMediaSections(this._peerConnection.localDescription.sdp, 'application').length > 0
|
|
454
|
-
: false;
|
|
455
|
-
}
|
|
456
|
-
return true;
|
|
457
|
-
},
|
|
458
|
-
enumerable: false,
|
|
459
|
-
configurable: true
|
|
460
|
-
});
|
|
461
|
-
Object.defineProperty(PeerConnectionV2.prototype, "_isAdaptiveSimulcastEnabled", {
|
|
462
|
-
/**
|
|
463
|
-
* Whether adaptive simulcast is enabled.
|
|
464
|
-
* @returns {boolean}
|
|
465
|
-
*/
|
|
466
|
-
get: function () {
|
|
467
|
-
var adaptiveSimulcastEntry = this._preferredVideoCodecs.find(function (cs) { return 'adaptiveSimulcast' in cs; });
|
|
468
|
-
return adaptiveSimulcastEntry && adaptiveSimulcastEntry.adaptiveSimulcast === true;
|
|
469
|
-
},
|
|
470
|
-
enumerable: false,
|
|
471
|
-
configurable: true
|
|
472
|
-
});
|
|
354
|
+
}
|
|
355
|
+
get _shouldApplySimulcast() {
|
|
356
|
+
if (!isChrome && !isSafari) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
// adaptiveSimulcast is set to false after connected message is received if other party does not support it.
|
|
360
|
+
const simulcast = this._preferredVideoCodecs.some(cs => {
|
|
361
|
+
return cs.codec.toLowerCase() === 'vp8' && cs.simulcast && cs.adaptiveSimulcast !== false;
|
|
362
|
+
});
|
|
363
|
+
return simulcast;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* The {@link PeerConnectionV2}'s underlying RTCPeerConnection's RTCPeerConnectionState
|
|
367
|
+
* if supported by the browser, its RTCIceConnectionState otherwise.
|
|
368
|
+
* @property {RTCPeerConnectionState}
|
|
369
|
+
*/
|
|
370
|
+
get connectionState() {
|
|
371
|
+
return this.iceConnectionState === 'failed'
|
|
372
|
+
? 'failed' : (this._peerConnection.connectionState || this.iceConnectionState);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* The {@link PeerConnectionV2}'s underlying RTCPeerConnection's
|
|
376
|
+
* RTCIceConnectionState.
|
|
377
|
+
* @property {RTCIceConnectionState}
|
|
378
|
+
*/
|
|
379
|
+
get iceConnectionState() {
|
|
380
|
+
return ((this._isIceConnectionInactive && this._peerConnection.iceConnectionState === 'disconnected') || this._iceGatheringFailed)
|
|
381
|
+
? 'failed' : this._peerConnection.iceConnectionState;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Whether the {@link PeerConnectionV2} has negotiated or is in the process
|
|
385
|
+
* of negotiating the application m= section.
|
|
386
|
+
* @returns {boolean}
|
|
387
|
+
*/
|
|
388
|
+
get isApplicationSectionNegotiated() {
|
|
389
|
+
if (this._peerConnection.signalingState !== 'closed') {
|
|
390
|
+
// accessing .localDescription in 'closed' state causes it throw exceptions.
|
|
391
|
+
return this._peerConnection.localDescription
|
|
392
|
+
? getMediaSections(this._peerConnection.localDescription.sdp, 'application').length > 0
|
|
393
|
+
: false;
|
|
394
|
+
}
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Whether adaptive simulcast is enabled.
|
|
399
|
+
* @returns {boolean}
|
|
400
|
+
*/
|
|
401
|
+
get _isAdaptiveSimulcastEnabled() {
|
|
402
|
+
const adaptiveSimulcastEntry = this._preferredVideoCodecs.find(cs => 'adaptiveSimulcast' in cs);
|
|
403
|
+
return adaptiveSimulcastEntry && adaptiveSimulcastEntry.adaptiveSimulcast === true;
|
|
404
|
+
}
|
|
473
405
|
/**
|
|
474
406
|
* @param {MediaStreamTrack} track
|
|
475
407
|
* @param {Array<RTCRtpEncodingParameters>} encodings
|
|
476
408
|
* @param {boolean} trackReplaced
|
|
477
409
|
* @returns {boolean} true if encodings were updated.
|
|
478
410
|
*/
|
|
479
|
-
|
|
480
|
-
if (trackReplaced === void 0) { trackReplaced = false; }
|
|
411
|
+
_maybeUpdateEncodings(track, encodings, trackReplaced = false) {
|
|
481
412
|
if (track.kind !== 'video' || track.readyState === 'ended') {
|
|
482
413
|
return false;
|
|
483
414
|
}
|
|
484
415
|
// NOTE(mmalavalli): There is no guarantee that CanvasCaptureMediaStreamTracks will always have "width" and "height"
|
|
485
416
|
// in their settings. So, we don't update the encodings if they are not present.
|
|
486
417
|
// Chromium bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1367082
|
|
487
|
-
|
|
418
|
+
const { height, width } = track.getSettings();
|
|
488
419
|
if (typeof height !== 'number' || typeof width !== 'number') {
|
|
489
420
|
return false;
|
|
490
421
|
}
|
|
491
422
|
// Note(mpatwardhan): always configure encodings for safari.
|
|
492
423
|
// for chrome only when adaptive simulcast enabled.
|
|
493
|
-
|
|
424
|
+
const browser = util.guessBrowser();
|
|
494
425
|
if (browser === 'safari' || (browser === 'chrome' && this._isAdaptiveSimulcastEnabled)) {
|
|
495
426
|
this._updateEncodings(track, encodings, trackReplaced);
|
|
496
427
|
return true;
|
|
497
428
|
}
|
|
498
429
|
return false;
|
|
499
|
-
}
|
|
430
|
+
}
|
|
500
431
|
/**
|
|
501
432
|
* Configures with default encodings depending on track type and resolution.
|
|
502
433
|
* Default configuration sets some encodings to disabled, and for others set scaleResolutionDownBy
|
|
@@ -506,14 +437,14 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
506
437
|
* @param {Array<RTCRtpEncodingParameters>} encodings
|
|
507
438
|
* @param {boolean} trackReplaced
|
|
508
439
|
*/
|
|
509
|
-
|
|
440
|
+
_updateEncodings(track, encodings, trackReplaced) {
|
|
510
441
|
if (this._isChromeScreenShareTrack(track)) {
|
|
511
|
-
|
|
442
|
+
const screenShareActiveLayerConfig = [
|
|
512
443
|
{ scaleResolutionDownBy: 1 },
|
|
513
444
|
{ scaleResolutionDownBy: 1 }
|
|
514
445
|
];
|
|
515
|
-
encodings.forEach(
|
|
516
|
-
|
|
446
|
+
encodings.forEach((encoding, i) => {
|
|
447
|
+
const activeLayerConfig = screenShareActiveLayerConfig[i];
|
|
517
448
|
if (activeLayerConfig) {
|
|
518
449
|
encoding.scaleResolutionDownBy = activeLayerConfig.scaleResolutionDownBy;
|
|
519
450
|
if (trackReplaced) {
|
|
@@ -527,21 +458,21 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
527
458
|
});
|
|
528
459
|
}
|
|
529
460
|
else {
|
|
530
|
-
|
|
461
|
+
const { width, height } = track.getSettings();
|
|
531
462
|
// NOTE(mpatwardhan): for non-screen share tracks
|
|
532
463
|
// enable layers depending on track resolutions
|
|
533
|
-
|
|
464
|
+
const pixelsToMaxActiveLayers = [
|
|
534
465
|
{ pixels: 960 * 540, maxActiveLayers: 3 },
|
|
535
466
|
{ pixels: 480 * 270, maxActiveLayers: 2 },
|
|
536
467
|
{ pixels: 0, maxActiveLayers: 1 }
|
|
537
468
|
];
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
encodings.forEach(
|
|
542
|
-
|
|
469
|
+
const trackPixels = width * height;
|
|
470
|
+
const activeLayersInfo = pixelsToMaxActiveLayers.find(layer => trackPixels >= layer.pixels);
|
|
471
|
+
const activeLayers = Math.min(encodings.length, activeLayersInfo.maxActiveLayers);
|
|
472
|
+
encodings.forEach((encoding, i) => {
|
|
473
|
+
const enabled = i < activeLayers;
|
|
543
474
|
if (enabled) {
|
|
544
|
-
encoding.scaleResolutionDownBy = 1 << (
|
|
475
|
+
encoding.scaleResolutionDownBy = 1 << (activeLayers - i - 1);
|
|
545
476
|
if (trackReplaced) {
|
|
546
477
|
encoding.active = true;
|
|
547
478
|
}
|
|
@@ -552,24 +483,20 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
552
483
|
}
|
|
553
484
|
});
|
|
554
485
|
}
|
|
555
|
-
this._log.debug('_updateEncodings:', encodings.map(
|
|
556
|
-
|
|
557
|
-
return "[".concat(i, ": ").concat(active, ", ").concat(scaleResolutionDownBy || 0, "]");
|
|
558
|
-
}).join(', '));
|
|
559
|
-
};
|
|
486
|
+
this._log.debug('_updateEncodings:', encodings.map(({ active, scaleResolutionDownBy }, i) => `[${i}: ${active}, ${scaleResolutionDownBy || 0}]`).join(', '));
|
|
487
|
+
}
|
|
560
488
|
/**
|
|
561
489
|
* Add an ICE candidate to the {@link PeerConnectionV2}.
|
|
562
490
|
* @private
|
|
563
491
|
* @param {object} candidate
|
|
564
492
|
* @returns {Promise<void>}
|
|
565
493
|
*/
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
}).catch(function (error) {
|
|
494
|
+
_addIceCandidate(candidate) {
|
|
495
|
+
return Promise.resolve().then(() => {
|
|
496
|
+
telemetry.pc.iceCandidate(this.id, candidate, true);
|
|
497
|
+
candidate = new this._RTCIceCandidate(candidate);
|
|
498
|
+
return this._peerConnection.addIceCandidate(candidate);
|
|
499
|
+
}).catch(error => {
|
|
573
500
|
// NOTE(mmalavalli): Firefox 68+ now generates an RTCIceCandidate with an
|
|
574
501
|
// empty candidate string to signal end-of-candidates, followed by a null
|
|
575
502
|
// candidate. As of now, Chrome and Safari reject this RTCIceCandidate. Since
|
|
@@ -578,45 +505,45 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
578
505
|
//
|
|
579
506
|
// Chrome bug: https://bugs.chromium.org/p/chromium/issues/detail?id=978582
|
|
580
507
|
//
|
|
581
|
-
|
|
508
|
+
this._log.warn(`Failed to add RTCIceCandidate ${candidate ? `"${candidate.candidate}"` : 'null'}: `
|
|
582
509
|
+ error.message);
|
|
583
510
|
});
|
|
584
|
-
}
|
|
511
|
+
}
|
|
585
512
|
/**
|
|
586
513
|
* Add ICE candidates to the {@link PeerConnectionV2}.
|
|
587
514
|
* @private
|
|
588
515
|
* @param {Array<object>} candidates
|
|
589
516
|
* @returns {Promise<void>}
|
|
590
517
|
*/
|
|
591
|
-
|
|
592
|
-
return Promise.all(candidates.map(this._addIceCandidate, this)).then(
|
|
593
|
-
}
|
|
518
|
+
_addIceCandidates(candidates) {
|
|
519
|
+
return Promise.all(candidates.map(this._addIceCandidate, this)).then(() => { });
|
|
520
|
+
}
|
|
594
521
|
/**
|
|
595
522
|
* Apply codec preferences to a transceiver.
|
|
596
523
|
* @private
|
|
597
524
|
* @param {RTCRtpTransceiver} transceiver
|
|
598
525
|
* @returns {void}
|
|
599
526
|
*/
|
|
600
|
-
|
|
527
|
+
_applyCodecPreferencesToTransceiver(transceiver) {
|
|
601
528
|
if (!transceiver || !transceiver.receiver || !transceiver.receiver.track) {
|
|
602
529
|
return;
|
|
603
530
|
}
|
|
604
|
-
|
|
605
|
-
|
|
531
|
+
const kind = transceiver.receiver.track.kind;
|
|
532
|
+
const preferredCodecs = kind === 'audio'
|
|
606
533
|
? this._preferredAudioCodecs
|
|
607
534
|
: this._preferredVideoCodecs;
|
|
608
535
|
if (!preferredCodecs || preferredCodecs.length === 0) {
|
|
609
536
|
return;
|
|
610
537
|
}
|
|
611
538
|
try {
|
|
612
|
-
|
|
613
|
-
|
|
539
|
+
const availableCodecs = RTCRtpReceiver.getCapabilities(kind).codecs;
|
|
540
|
+
const sortedCodecs = this._sortCodecsByPreference(availableCodecs, preferredCodecs);
|
|
614
541
|
transceiver.setCodecPreferences(sortedCodecs);
|
|
615
542
|
}
|
|
616
543
|
catch (error) {
|
|
617
544
|
this._log.warn('Failed to apply codec preferences:', error);
|
|
618
545
|
}
|
|
619
|
-
}
|
|
546
|
+
}
|
|
620
547
|
/**
|
|
621
548
|
* Sort codecs by preference.
|
|
622
549
|
* @private
|
|
@@ -624,15 +551,13 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
624
551
|
* @param {Array} preferredCodecs
|
|
625
552
|
* @returns {Array}
|
|
626
553
|
*/
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
var codecName = codec.mimeType.split('/')[1].toLowerCase();
|
|
635
|
-
var index = preferredNames.indexOf(codecName);
|
|
554
|
+
_sortCodecsByPreference(availableCodecs, preferredCodecs) {
|
|
555
|
+
const preferred = [];
|
|
556
|
+
const remaining = [];
|
|
557
|
+
const preferredNames = preferredCodecs.map(c => (typeof c === 'string' ? c : c.codec).toLowerCase());
|
|
558
|
+
availableCodecs.forEach(codec => {
|
|
559
|
+
const codecName = codec.mimeType.split('/')[1].toLowerCase();
|
|
560
|
+
const index = preferredNames.indexOf(codecName);
|
|
636
561
|
if (index >= 0) {
|
|
637
562
|
if (!preferred[index]) {
|
|
638
563
|
preferred[index] = [];
|
|
@@ -644,7 +569,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
644
569
|
}
|
|
645
570
|
});
|
|
646
571
|
return preferred.flat().concat(remaining);
|
|
647
|
-
}
|
|
572
|
+
}
|
|
648
573
|
/**
|
|
649
574
|
* Add a new RTCRtpTransceiver or update an existing RTCRtpTransceiver for the
|
|
650
575
|
* given MediaStreamTrack.
|
|
@@ -652,68 +577,66 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
652
577
|
* @param {MediaStreamTrack} track
|
|
653
578
|
* @returns {RTCRtpTransceiver}
|
|
654
579
|
*/
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
var transceiver = takeRecycledTransceiver(this, track.kind);
|
|
580
|
+
_addOrUpdateTransceiver(track) {
|
|
581
|
+
const transceiver = takeRecycledTransceiver(this, track.kind);
|
|
658
582
|
if (transceiver && transceiver.sender) {
|
|
659
|
-
|
|
583
|
+
const oldTrackId = transceiver.sender.track ? transceiver.sender.track.id : null;
|
|
660
584
|
if (oldTrackId) {
|
|
661
|
-
this._log.warn(
|
|
585
|
+
this._log.warn(`Reusing transceiver: ${transceiver.mid}] ${oldTrackId} => ${track.id}`);
|
|
662
586
|
}
|
|
663
587
|
// NOTE(mpatwardhan):remember this transceiver while we replace track.
|
|
664
588
|
// we recycle transceivers that are not in use after 'negotiationCompleted', but we want to prevent
|
|
665
589
|
// this one from getting recycled while replaceTrack is pending.
|
|
666
|
-
this._replaceTrackPromises.set(transceiver, transceiver.sender.replaceTrack(track).then(
|
|
590
|
+
this._replaceTrackPromises.set(transceiver, transceiver.sender.replaceTrack(track).then(() => {
|
|
667
591
|
transceiver.direction = 'sendrecv';
|
|
668
|
-
},
|
|
592
|
+
}, () => {
|
|
669
593
|
// Do nothing.
|
|
670
|
-
}).finally(
|
|
671
|
-
|
|
594
|
+
}).finally(() => {
|
|
595
|
+
this._replaceTrackPromises.delete(transceiver);
|
|
672
596
|
}));
|
|
673
597
|
return transceiver;
|
|
674
598
|
}
|
|
675
599
|
// NOTE(lrivas): The second argument {} is optional in the specification but required by the Citrix VDI implementations.
|
|
676
|
-
|
|
600
|
+
const newTransceiver = this._peerConnection.addTransceiver(track, {});
|
|
677
601
|
this._applyCodecPreferencesToTransceiver(newTransceiver);
|
|
678
602
|
return newTransceiver;
|
|
679
|
-
}
|
|
603
|
+
}
|
|
680
604
|
/**
|
|
681
605
|
* Check the {@link IceBox}.
|
|
682
606
|
* @private
|
|
683
607
|
* @param {RTCSessionDescriptionInit} description
|
|
684
608
|
* @returns {Promise<void>}
|
|
685
609
|
*/
|
|
686
|
-
|
|
687
|
-
|
|
610
|
+
_checkIceBox(description) {
|
|
611
|
+
const ufrag = getUfrag(description);
|
|
688
612
|
if (!ufrag) {
|
|
689
613
|
return Promise.resolve();
|
|
690
614
|
}
|
|
691
|
-
|
|
615
|
+
const candidates = this._remoteCandidates.setUfrag(ufrag);
|
|
692
616
|
return this._addIceCandidates(candidates);
|
|
693
|
-
}
|
|
617
|
+
}
|
|
694
618
|
/**
|
|
695
619
|
* Create an answer and set it on the {@link PeerConnectionV2}.
|
|
696
620
|
* @private
|
|
697
621
|
* @param {RTCSessionDescriptionInit} offer
|
|
698
622
|
* @returns {Promise<boolean>}
|
|
699
623
|
*/
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
_this._negotiationRole = 'answerer';
|
|
624
|
+
_answer(offer) {
|
|
625
|
+
return Promise.resolve().then(() => {
|
|
626
|
+
if (!this._negotiationRole) {
|
|
627
|
+
this._negotiationRole = 'answerer';
|
|
705
628
|
}
|
|
706
|
-
return
|
|
707
|
-
}).catch(
|
|
629
|
+
return this._setRemoteDescription(offer);
|
|
630
|
+
}).catch(() => {
|
|
708
631
|
throw new MediaClientRemoteDescFailedError();
|
|
709
|
-
}).then(
|
|
710
|
-
return
|
|
711
|
-
}).then(
|
|
632
|
+
}).then(() => {
|
|
633
|
+
return this._peerConnection.createAnswer();
|
|
634
|
+
}).then(answer => {
|
|
712
635
|
if (isFirefox) {
|
|
713
636
|
// NOTE(mmalavalli): We work around Chromium bug 1106157 by disabling
|
|
714
637
|
// RTX in Firefox 79+. For more details about the bug, please go here:
|
|
715
638
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1106157
|
|
716
|
-
answer = new
|
|
639
|
+
answer = new this._RTCSessionDescription({
|
|
717
640
|
sdp: disableRtx(answer.sdp),
|
|
718
641
|
type: answer.type
|
|
719
642
|
});
|
|
@@ -726,47 +649,47 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
726
649
|
// and PSA: https://groups.google.com/forum/#!searchin/discuss-webrtc/PSA%7Csort:date/discuss-webrtc/jcZO-Wj0Wus/k2XvPCvoAwAJ
|
|
727
650
|
// We are not referencing those attributes, but this changes goes ahead and removes them to see if it works.
|
|
728
651
|
// this also helps reduce bytes on wires
|
|
729
|
-
|
|
730
|
-
if (
|
|
731
|
-
|
|
732
|
-
updatedSdp =
|
|
652
|
+
let updatedSdp = removeSSRCAttributes(answer.sdp, ['mslabel', 'label']);
|
|
653
|
+
if (this._shouldApplySimulcast) {
|
|
654
|
+
let sdpWithoutSimulcast = updatedSdp;
|
|
655
|
+
updatedSdp = this._setSimulcast(sdpWithoutSimulcast, this._trackIdsToAttributes);
|
|
733
656
|
// NOTE(syerrapragada): VMS does not support H264 simulcast. So,
|
|
734
657
|
// unset simulcast for sections in local offer where corresponding
|
|
735
658
|
// sections in answer doesn't have vp8 as preferred codec and reapply offer.
|
|
736
|
-
updatedSdp =
|
|
659
|
+
updatedSdp = this._revertSimulcast(updatedSdp, sdpWithoutSimulcast, offer.sdp);
|
|
737
660
|
}
|
|
738
661
|
// NOTE(mmalavalli): Work around Chromium bug 1074421.
|
|
739
662
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1074421
|
|
740
663
|
updatedSdp = updatedSdp.replace(/42e015/g, '42e01f');
|
|
741
|
-
return
|
|
664
|
+
return this._setLocalDescription({
|
|
742
665
|
type: answer.type,
|
|
743
666
|
sdp: updatedSdp
|
|
744
667
|
});
|
|
745
|
-
}).then(
|
|
746
|
-
return
|
|
747
|
-
}).then(
|
|
748
|
-
return
|
|
749
|
-
&&
|
|
750
|
-
}).then(
|
|
751
|
-
|
|
752
|
-
return
|
|
753
|
-
}).catch(
|
|
754
|
-
|
|
755
|
-
|
|
668
|
+
}).then(() => {
|
|
669
|
+
return this._checkIceBox(offer);
|
|
670
|
+
}).then(() => {
|
|
671
|
+
return this._queuedDescription
|
|
672
|
+
&& this._updateDescription(this._queuedDescription);
|
|
673
|
+
}).then(() => {
|
|
674
|
+
this._queuedDescription = null;
|
|
675
|
+
return this._maybeReoffer(this._peerConnection.localDescription);
|
|
676
|
+
}).catch(error => {
|
|
677
|
+
const errorToThrow = error instanceof MediaClientRemoteDescFailedError ? error : new MediaClientLocalDescFailedError();
|
|
678
|
+
this._publishMediaWarning({
|
|
756
679
|
message: 'Failed to _answer',
|
|
757
680
|
code: errorToThrow.code,
|
|
758
|
-
error
|
|
681
|
+
error
|
|
759
682
|
});
|
|
760
683
|
throw errorToThrow;
|
|
761
684
|
});
|
|
762
|
-
}
|
|
685
|
+
}
|
|
763
686
|
/**
|
|
764
687
|
* Close the underlying RTCPeerConnection. Returns false if the
|
|
765
688
|
* RTCPeerConnection was already closed.
|
|
766
689
|
* @private
|
|
767
690
|
* @returns {boolean}
|
|
768
691
|
*/
|
|
769
|
-
|
|
692
|
+
_close() {
|
|
770
693
|
this._iceConnectionMonitor.stop();
|
|
771
694
|
if (this._peerConnection.signalingState !== 'closed') {
|
|
772
695
|
this._peerConnection.close();
|
|
@@ -783,71 +706,68 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
783
706
|
return true;
|
|
784
707
|
}
|
|
785
708
|
return false;
|
|
786
|
-
}
|
|
709
|
+
}
|
|
787
710
|
/**
|
|
788
711
|
* Handle a "connectionstatechange" event.
|
|
789
712
|
* @private
|
|
790
713
|
* @returns {void}
|
|
791
714
|
*/
|
|
792
|
-
|
|
715
|
+
_handleConnectionStateChange() {
|
|
793
716
|
telemetry.pc.connectionState(this.id, this.connectionState);
|
|
794
717
|
this.emit('connectionStateChanged');
|
|
795
|
-
}
|
|
718
|
+
}
|
|
796
719
|
/**
|
|
797
720
|
* Handle a "datachannel" event.
|
|
798
721
|
* @private
|
|
799
722
|
* @param {RTCDataChannelEvent} event
|
|
800
723
|
* @returns {void}
|
|
801
724
|
*/
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
var dataTrackReceiver = new DataTrackReceiver(dataChannel);
|
|
725
|
+
_handleDataChannelEvent(event) {
|
|
726
|
+
const dataChannel = event.channel;
|
|
727
|
+
const dataTrackReceiver = new DataTrackReceiver(dataChannel);
|
|
806
728
|
this._dataTrackReceivers.add(dataTrackReceiver);
|
|
807
|
-
dataChannel.addEventListener('close',
|
|
808
|
-
|
|
729
|
+
dataChannel.addEventListener('close', () => {
|
|
730
|
+
this._dataTrackReceivers.delete(dataTrackReceiver);
|
|
809
731
|
});
|
|
810
732
|
this.emit('trackAdded', dataTrackReceiver);
|
|
811
|
-
}
|
|
733
|
+
}
|
|
812
734
|
/**
|
|
813
735
|
* Handle a glare scenario on the {@link PeerConnectionV2}.
|
|
814
736
|
* @private
|
|
815
737
|
* @param {RTCSessionDescriptionInit} offer
|
|
816
738
|
* @returns {Promise<void>}
|
|
817
739
|
*/
|
|
818
|
-
|
|
819
|
-
var _this = this;
|
|
740
|
+
_handleGlare(offer) {
|
|
820
741
|
this._log.debug('Glare detected; rolling back');
|
|
821
742
|
if (this._isRestartingIce) {
|
|
822
743
|
this._log.debug('An ICE restart was in progress; we\'ll need to restart ICE again after rolling back');
|
|
823
744
|
this._isRestartingIce = false;
|
|
824
745
|
this._shouldRestartIce = true;
|
|
825
746
|
}
|
|
826
|
-
return Promise.resolve().then(
|
|
827
|
-
|
|
828
|
-
return
|
|
829
|
-
}).then(
|
|
830
|
-
|
|
831
|
-
return
|
|
832
|
-
}).then(
|
|
833
|
-
return didReoffer ? Promise.resolve() :
|
|
747
|
+
return Promise.resolve().then(() => {
|
|
748
|
+
this._trackIdsToAttributes = new Map(this._appliedTrackIdsToAttributes);
|
|
749
|
+
return this._setLocalDescription({ type: 'rollback' });
|
|
750
|
+
}).then(() => {
|
|
751
|
+
this._needsAnswer = false;
|
|
752
|
+
return this._answer(offer);
|
|
753
|
+
}).then(didReoffer => {
|
|
754
|
+
return didReoffer ? Promise.resolve() : this._offer();
|
|
834
755
|
});
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
var message = _a.message, code = _a.code, error = _a.error, sdp = _a.sdp;
|
|
756
|
+
}
|
|
757
|
+
_publishMediaWarning({ message, code, error, sdp }) {
|
|
838
758
|
this._eventObserver.emit('event', { level: 'warning', name: 'error', group: 'media', payload: {
|
|
839
|
-
message
|
|
840
|
-
code
|
|
841
|
-
context: JSON.stringify({ error: error.message, sdp
|
|
759
|
+
message,
|
|
760
|
+
code,
|
|
761
|
+
context: JSON.stringify({ error: error.message, sdp })
|
|
842
762
|
} });
|
|
843
|
-
}
|
|
763
|
+
}
|
|
844
764
|
/**
|
|
845
765
|
* Handle an ICE candidate event.
|
|
846
766
|
* @private
|
|
847
767
|
* @param {Event} event
|
|
848
768
|
* @returns {void}
|
|
849
769
|
*/
|
|
850
|
-
|
|
770
|
+
_handleIceCandidateEvent(event) {
|
|
851
771
|
if (event.candidate) {
|
|
852
772
|
this._log.debug('Clearing ICE gathering timeout');
|
|
853
773
|
this._didGenerateLocalCandidates = true;
|
|
@@ -855,7 +775,7 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
855
775
|
this._localCandidates.push(event.candidate);
|
|
856
776
|
telemetry.pc.iceCandidate(this.id, event.candidate);
|
|
857
777
|
}
|
|
858
|
-
|
|
778
|
+
const peerConnectionState = {
|
|
859
779
|
ice: {
|
|
860
780
|
candidates: this._isIceLite ? [] : this._localCandidates.slice(),
|
|
861
781
|
ufrag: this._localUfrag
|
|
@@ -869,18 +789,17 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
869
789
|
peerConnectionState.ice.revision = this._localCandidatesRevision++;
|
|
870
790
|
this.emit('candidates', peerConnectionState);
|
|
871
791
|
}
|
|
872
|
-
}
|
|
792
|
+
}
|
|
873
793
|
/**
|
|
874
794
|
* Handle an ICE connection state change event.
|
|
875
795
|
* @private
|
|
876
796
|
* @returns {void}
|
|
877
797
|
*/
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
log.debug("ICE connection state is \"".concat(iceConnectionState, "\""));
|
|
798
|
+
_handleIceConnectionStateChange() {
|
|
799
|
+
const { iceConnectionState } = this._peerConnection;
|
|
800
|
+
const isIceConnectedOrComplete = ['connected', 'completed'].includes(iceConnectionState);
|
|
801
|
+
const log = this._log;
|
|
802
|
+
log.debug(`ICE connection state is "${iceConnectionState}"`);
|
|
884
803
|
telemetry.pc.iceConnectionState(this.id, iceConnectionState);
|
|
885
804
|
if (isIceConnectedOrComplete) {
|
|
886
805
|
this._iceReconnectTimeout.clear();
|
|
@@ -898,16 +817,16 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
898
817
|
// start monitor media when connected, and continue to monitor while state is complete-disconnected-connected.
|
|
899
818
|
if (iceConnectionState === 'connected') {
|
|
900
819
|
this._isIceConnectionInactive = false;
|
|
901
|
-
this._iceConnectionMonitor.start(
|
|
820
|
+
this._iceConnectionMonitor.start(() => {
|
|
902
821
|
// note: iceConnection monitor waits for iceConnectionState=disconnected for
|
|
903
822
|
// detecting inactivity. Its possible that it may know about disconnected before _handleIceConnectionStateChange
|
|
904
|
-
|
|
905
|
-
if (!
|
|
823
|
+
this._iceConnectionMonitor.stop();
|
|
824
|
+
if (!this._shouldRestartIce && !this._isRestartingIce) {
|
|
906
825
|
log.warn('ICE Connection Monitor detected inactivity');
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
826
|
+
this._isIceConnectionInactive = true;
|
|
827
|
+
this._initiateIceRestartBackoff();
|
|
828
|
+
this.emit('iceConnectionStateChanged');
|
|
829
|
+
this.emit('connectionStateChanged');
|
|
911
830
|
}
|
|
912
831
|
});
|
|
913
832
|
}
|
|
@@ -917,217 +836,214 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
917
836
|
}
|
|
918
837
|
this._lastIceConnectionState = iceConnectionState;
|
|
919
838
|
this.emit('iceConnectionStateChanged');
|
|
920
|
-
}
|
|
839
|
+
}
|
|
921
840
|
/**
|
|
922
841
|
* Handle ICE gathering timeout.
|
|
923
842
|
* @private
|
|
924
843
|
* @returns {void}
|
|
925
844
|
*/
|
|
926
|
-
|
|
845
|
+
_handleIceGatheringTimeout() {
|
|
927
846
|
this._log.warn('ICE failed to gather any local candidates');
|
|
928
847
|
this._iceGatheringFailed = true;
|
|
929
848
|
this._initiateIceRestartBackoff();
|
|
930
849
|
this.emit('iceConnectionStateChanged');
|
|
931
850
|
this.emit('connectionStateChanged');
|
|
932
|
-
}
|
|
851
|
+
}
|
|
933
852
|
/**
|
|
934
853
|
* Handle an ICE gathering state change event.
|
|
935
854
|
* @private
|
|
936
855
|
* @returns {void}
|
|
937
856
|
*/
|
|
938
|
-
|
|
939
|
-
|
|
857
|
+
_handleIceGatheringStateChange() {
|
|
858
|
+
const { iceGatheringState } = this._peerConnection;
|
|
940
859
|
telemetry.pc.iceGatheringState(this.id, iceGatheringState);
|
|
941
|
-
|
|
942
|
-
log.debug(
|
|
860
|
+
const log = this._log;
|
|
861
|
+
log.debug(`ICE gathering state is "${iceGatheringState}"`);
|
|
943
862
|
// NOTE(mmalavalli): Start the ICE gathering timeout only if the RTCPeerConnection
|
|
944
863
|
// has started gathering candidates for the first time since the initial offer/answer
|
|
945
864
|
// or an offer/answer with ICE restart.
|
|
946
|
-
|
|
865
|
+
const { delay, isSet } = this._iceGatheringTimeout;
|
|
947
866
|
if (iceGatheringState === 'gathering' && !this._didGenerateLocalCandidates && !isSet) {
|
|
948
|
-
log.debug(
|
|
867
|
+
log.debug(`Starting ICE gathering timeout: ${delay}`);
|
|
949
868
|
this._iceGatheringFailed = false;
|
|
950
869
|
this._iceGatheringTimeout.start();
|
|
951
870
|
}
|
|
952
|
-
}
|
|
871
|
+
}
|
|
953
872
|
/**
|
|
954
873
|
* Handle a signaling state change event.
|
|
955
874
|
* @private
|
|
956
875
|
* @returns {void}
|
|
957
876
|
*/
|
|
958
|
-
|
|
877
|
+
_handleSignalingStateChange() {
|
|
959
878
|
telemetry.pc.signalingState(this.id, this._peerConnection.signalingState);
|
|
960
879
|
if (this._peerConnection.signalingState === 'stable') {
|
|
961
880
|
this._appliedTrackIdsToAttributes = new Map(this._trackIdsToAttributes);
|
|
962
881
|
}
|
|
963
|
-
}
|
|
882
|
+
}
|
|
964
883
|
/**
|
|
965
884
|
* Handle a DTLS transport state change event.
|
|
966
885
|
* @private
|
|
967
886
|
* @returns {void}
|
|
968
887
|
*/
|
|
969
|
-
|
|
970
|
-
|
|
888
|
+
_handleDtlsTransportStateChange() {
|
|
889
|
+
const transport = this._dtlsTransport;
|
|
971
890
|
if (transport) {
|
|
972
|
-
this._log.debug(
|
|
891
|
+
this._log.debug(`DTLS transport state is "${transport.state}"`);
|
|
973
892
|
telemetry.pc.dtlsTransportState(this.id, transport.state);
|
|
974
893
|
}
|
|
975
|
-
}
|
|
894
|
+
}
|
|
976
895
|
/**
|
|
977
896
|
* Handle a selected candidate pair change event.
|
|
978
897
|
* @private
|
|
979
898
|
* @returns {void}
|
|
980
899
|
*/
|
|
981
|
-
|
|
900
|
+
_handleSelectedCandidatePairChange() {
|
|
982
901
|
var _a;
|
|
983
|
-
|
|
902
|
+
const iceTransport = (_a = this._dtlsTransport) === null || _a === void 0 ? void 0 : _a.iceTransport;
|
|
984
903
|
if (iceTransport && typeof iceTransport.getSelectedCandidatePair === 'function') {
|
|
985
|
-
|
|
904
|
+
const pair = iceTransport.getSelectedCandidatePair();
|
|
986
905
|
if (pair) {
|
|
987
906
|
telemetry.pc.selectedCandidatePair(this.id, pair);
|
|
988
907
|
}
|
|
989
908
|
}
|
|
990
|
-
}
|
|
909
|
+
}
|
|
991
910
|
/**
|
|
992
911
|
* Handle a track event.
|
|
993
912
|
* @private
|
|
994
913
|
* @param {RTCTrackEvent} event
|
|
995
914
|
* @returns {void}
|
|
996
915
|
*/
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
var sdp = this._peerConnection.remoteDescription
|
|
916
|
+
_handleTrackEvent(event) {
|
|
917
|
+
const sdp = this._peerConnection.remoteDescription
|
|
1000
918
|
? this._peerConnection.remoteDescription.sdp
|
|
1001
919
|
: null;
|
|
1002
920
|
this._trackMatcher = this._trackMatcher || new TrackMatcher();
|
|
1003
921
|
this._trackMatcher.update(sdp);
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
922
|
+
const mediaStreamTrack = event.track;
|
|
923
|
+
const signaledTrackId = this._trackMatcher.match(event) || mediaStreamTrack.id;
|
|
924
|
+
const mediaTrackReceiver = new MediaTrackReceiver(signaledTrackId, mediaStreamTrack);
|
|
1007
925
|
// NOTE(mmalavalli): "ended" is not fired on the remote MediaStreamTrack when
|
|
1008
926
|
// the remote peer removes a track. So, when this MediaStreamTrack is re-used
|
|
1009
927
|
// for a different track due to the remote peer calling RTCRtpSender.replaceTrack(),
|
|
1010
928
|
// we delete the previous MediaTrackReceiver that owned this MediaStreamTrack
|
|
1011
929
|
// before adding the new MediaTrackReceiver.
|
|
1012
|
-
this._mediaTrackReceivers.forEach(
|
|
930
|
+
this._mediaTrackReceivers.forEach(trackReceiver => {
|
|
1013
931
|
if (trackReceiver.track.id === mediaTrackReceiver.track.id) {
|
|
1014
|
-
|
|
932
|
+
this._mediaTrackReceivers.delete(trackReceiver);
|
|
1015
933
|
}
|
|
1016
934
|
});
|
|
1017
935
|
this._mediaTrackReceivers.add(mediaTrackReceiver);
|
|
1018
936
|
if (mediaStreamTrack.addEventListener) {
|
|
1019
|
-
mediaStreamTrack.addEventListener('ended',
|
|
937
|
+
mediaStreamTrack.addEventListener('ended', () => this._mediaTrackReceivers.delete(mediaTrackReceiver));
|
|
1020
938
|
}
|
|
1021
939
|
else {
|
|
1022
|
-
mediaStreamTrack.onended =
|
|
940
|
+
mediaStreamTrack.onended = () => this._mediaTrackReceivers.delete(mediaTrackReceiver);
|
|
1023
941
|
}
|
|
1024
942
|
this.emit('trackAdded', mediaTrackReceiver);
|
|
1025
|
-
}
|
|
943
|
+
}
|
|
1026
944
|
/**
|
|
1027
945
|
* Initiate ICE Restart.
|
|
1028
946
|
* @private
|
|
1029
947
|
* @returns {void}
|
|
1030
948
|
*/
|
|
1031
|
-
|
|
949
|
+
_initiateIceRestart() {
|
|
1032
950
|
if (this._peerConnection.signalingState === 'closed') {
|
|
1033
951
|
return;
|
|
1034
952
|
}
|
|
1035
|
-
|
|
953
|
+
const log = this._log;
|
|
1036
954
|
log.warn('Attempting to restart ICE');
|
|
1037
955
|
this._didGenerateLocalCandidates = false;
|
|
1038
956
|
this._isIceRestartBackoffInProgress = false;
|
|
1039
957
|
this._shouldRestartIce = true;
|
|
1040
|
-
|
|
958
|
+
const { delay, isSet } = this._iceReconnectTimeout;
|
|
1041
959
|
if (!isSet) {
|
|
1042
|
-
log.debug(
|
|
960
|
+
log.debug(`Starting ICE reconnect timeout: ${delay}`);
|
|
1043
961
|
this._iceReconnectTimeout.start();
|
|
1044
962
|
}
|
|
1045
|
-
this.offer().catch(
|
|
1046
|
-
log.error(
|
|
963
|
+
this.offer().catch(ex => {
|
|
964
|
+
log.error(`offer failed in _initiateIceRestart with: ${ex.message}`);
|
|
1047
965
|
});
|
|
1048
|
-
}
|
|
966
|
+
}
|
|
1049
967
|
/**
|
|
1050
968
|
* Schedule an ICE Restart.
|
|
1051
969
|
* @private
|
|
1052
970
|
* @returns {void}
|
|
1053
971
|
*/
|
|
1054
|
-
|
|
1055
|
-
var _this = this;
|
|
972
|
+
_initiateIceRestartBackoff() {
|
|
1056
973
|
if (this._peerConnection.signalingState === 'closed' || this._isIceRestartBackoffInProgress) {
|
|
1057
974
|
return;
|
|
1058
975
|
}
|
|
1059
976
|
this._log.warn('An ICE restart has been scheduled');
|
|
1060
977
|
this._isIceRestartBackoffInProgress = true;
|
|
1061
|
-
this._iceRestartBackoff.backoff(
|
|
1062
|
-
}
|
|
978
|
+
this._iceRestartBackoff.backoff(() => this._initiateIceRestart());
|
|
979
|
+
}
|
|
1063
980
|
/**
|
|
1064
981
|
* Conditionally re-offer.
|
|
1065
982
|
* @private
|
|
1066
983
|
* @param {?RTCSessionDescriptionInit} localDescription
|
|
1067
984
|
* @returns {Promise<boolean>}
|
|
1068
985
|
*/
|
|
1069
|
-
|
|
1070
|
-
|
|
986
|
+
_maybeReoffer(localDescription) {
|
|
987
|
+
let shouldReoffer = this._shouldOffer;
|
|
1071
988
|
if (localDescription && localDescription.sdp) {
|
|
1072
989
|
// NOTE(mmalavalli): If the local RTCSessionDescription has fewer audio and/or
|
|
1073
990
|
// video send* m= lines than the corresponding RTCRtpSenders with non-null
|
|
1074
991
|
// MediaStreamTracks, it means that the newly added RTCRtpSenders require
|
|
1075
992
|
// renegotiation.
|
|
1076
|
-
|
|
1077
|
-
shouldReoffer = ['audio', 'video'].reduce(
|
|
1078
|
-
|
|
1079
|
-
|
|
993
|
+
const senders = this._peerConnection.getSenders().filter(sender => sender.track);
|
|
994
|
+
shouldReoffer = ['audio', 'video'].reduce((shouldOffer, kind) => {
|
|
995
|
+
const mediaSections = getMediaSections(localDescription.sdp, kind, '(sendrecv|sendonly)');
|
|
996
|
+
const sendersOfKind = senders.filter(isSenderOfKind.bind(null, kind));
|
|
1080
997
|
return shouldOffer || (mediaSections.length < sendersOfKind.length);
|
|
1081
998
|
}, shouldReoffer);
|
|
1082
999
|
// NOTE(mroberts): We also need to re-offer if we have a DataTrack to share
|
|
1083
1000
|
// but no m= application section.
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1001
|
+
const hasDataTrack = this._dataChannels.size > 0;
|
|
1002
|
+
const hasApplicationMediaSection = getMediaSections(localDescription.sdp, 'application').length > 0;
|
|
1003
|
+
const needsApplicationMediaSection = hasDataTrack && !hasApplicationMediaSection;
|
|
1087
1004
|
shouldReoffer = shouldReoffer || needsApplicationMediaSection;
|
|
1088
1005
|
}
|
|
1089
|
-
|
|
1090
|
-
return promise.then(
|
|
1091
|
-
}
|
|
1006
|
+
const promise = shouldReoffer ? this._offer() : Promise.resolve();
|
|
1007
|
+
return promise.then(() => shouldReoffer);
|
|
1008
|
+
}
|
|
1092
1009
|
/**
|
|
1093
1010
|
* Create an offer and set it on the {@link PeerConnectionV2}.
|
|
1094
1011
|
* @private
|
|
1095
1012
|
* @returns {Promise<void>}
|
|
1096
1013
|
*/
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
var offerOptions = Object.assign({}, this._offerOptions);
|
|
1014
|
+
_offer() {
|
|
1015
|
+
const offerOptions = Object.assign({}, this._offerOptions);
|
|
1100
1016
|
this._needsAnswer = true;
|
|
1101
1017
|
if (this._shouldRestartIce) {
|
|
1102
1018
|
this._shouldRestartIce = false;
|
|
1103
1019
|
this._isRestartingIce = true;
|
|
1104
1020
|
offerOptions.iceRestart = true;
|
|
1105
1021
|
}
|
|
1106
|
-
return Promise.all(this._replaceTrackPromises.values()).then(
|
|
1107
|
-
|
|
1108
|
-
transceivers.forEach(
|
|
1109
|
-
return
|
|
1110
|
-
}).catch(
|
|
1111
|
-
|
|
1112
|
-
|
|
1022
|
+
return Promise.all(this._replaceTrackPromises.values()).then(() => {
|
|
1023
|
+
const transceivers = this._peerConnection.getTransceivers();
|
|
1024
|
+
transceivers.forEach(transceiver => this._applyCodecPreferencesToTransceiver(transceiver));
|
|
1025
|
+
return this._peerConnection.createOffer(offerOptions);
|
|
1026
|
+
}).catch(error => {
|
|
1027
|
+
const errorToThrow = new MediaClientLocalDescFailedError();
|
|
1028
|
+
this._publishMediaWarning({
|
|
1113
1029
|
message: 'Failed to create offer',
|
|
1114
1030
|
code: errorToThrow.code,
|
|
1115
|
-
error
|
|
1031
|
+
error
|
|
1116
1032
|
});
|
|
1117
1033
|
throw errorToThrow;
|
|
1118
|
-
}).then(
|
|
1034
|
+
}).then(offer => {
|
|
1119
1035
|
if (isFirefox) {
|
|
1120
1036
|
// NOTE(mmalavalli): We work around Chromium bug 1106157 by disabling
|
|
1121
1037
|
// RTX in Firefox 79+. For more details about the bug, please go here:
|
|
1122
1038
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1106157
|
|
1123
|
-
|
|
1039
|
+
let sdp = disableRtx(offer.sdp);
|
|
1124
1040
|
// NOTE(lrivas): Work around Firefox bug where setCodecPreferences leaves
|
|
1125
1041
|
// unreferenced codec attributes (fmtp, rtpmap, rtcp-fb) for payload types not
|
|
1126
1042
|
// present in the m= line. For more details about the bug, please go here:
|
|
1127
1043
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1909443
|
|
1128
1044
|
sdp = removeUnreferencedCodecAttributes(sdp);
|
|
1129
|
-
offer = new
|
|
1130
|
-
sdp
|
|
1045
|
+
offer = new this._RTCSessionDescription({
|
|
1046
|
+
sdp,
|
|
1131
1047
|
type: offer.type
|
|
1132
1048
|
});
|
|
1133
1049
|
}
|
|
@@ -1139,24 +1055,24 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1139
1055
|
// and PSA: https://groups.google.com/forum/#!searchin/discuss-webrtc/PSA%7Csort:date/discuss-webrtc/jcZO-Wj0Wus/k2XvPCvoAwAJ
|
|
1140
1056
|
// Looks like we are not referencing those attributes, but this changes goes ahead and removes them to see if it works.
|
|
1141
1057
|
// this also helps reduce bytes on wires
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
if (!
|
|
1145
|
-
|
|
1058
|
+
let updatedSdp = removeSSRCAttributes(offer.sdp, ['mslabel', 'label']);
|
|
1059
|
+
this._shouldOffer = false;
|
|
1060
|
+
if (!this._negotiationRole) {
|
|
1061
|
+
this._negotiationRole = 'offerer';
|
|
1146
1062
|
}
|
|
1147
|
-
if (
|
|
1148
|
-
|
|
1063
|
+
if (this._shouldApplySimulcast) {
|
|
1064
|
+
this._localDescriptionWithoutSimulcast = {
|
|
1149
1065
|
type: 'offer',
|
|
1150
1066
|
sdp: updatedSdp
|
|
1151
1067
|
};
|
|
1152
|
-
updatedSdp =
|
|
1068
|
+
updatedSdp = this._setSimulcast(updatedSdp, this._trackIdsToAttributes);
|
|
1153
1069
|
}
|
|
1154
|
-
return
|
|
1070
|
+
return this._setLocalDescription({
|
|
1155
1071
|
type: 'offer',
|
|
1156
1072
|
sdp: updatedSdp
|
|
1157
1073
|
});
|
|
1158
1074
|
});
|
|
1159
|
-
}
|
|
1075
|
+
}
|
|
1160
1076
|
/**
|
|
1161
1077
|
* Get the MediaTrackSender ID of the given MediaStreamTrack ID.
|
|
1162
1078
|
* Since a MediaTrackSender's underlying MediaStreamTrack can be
|
|
@@ -1165,134 +1081,109 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1165
1081
|
* @param {Track.ID} id
|
|
1166
1082
|
* @returns {Track.ID}
|
|
1167
1083
|
*/
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
var id = _a.track.id;
|
|
1171
|
-
return id === trackId;
|
|
1172
|
-
});
|
|
1084
|
+
_getMediaTrackSenderId(trackId) {
|
|
1085
|
+
const mediaTrackSender = Array.from(this._rtpSenders.keys()).find(({ track: { id } }) => id === trackId);
|
|
1173
1086
|
return mediaTrackSender ? mediaTrackSender.id : trackId;
|
|
1174
|
-
}
|
|
1087
|
+
}
|
|
1175
1088
|
/**
|
|
1176
1089
|
* Add or rewrite local MediaStreamTrack IDs in the given RTCSessionDescription.
|
|
1177
1090
|
* @private
|
|
1178
1091
|
* @param {RTCSessionDescription} description
|
|
1179
1092
|
* @return {RTCSessionDescription}
|
|
1180
1093
|
*/
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
var activeTransceivers = transceivers.filter(function (_a) {
|
|
1185
|
-
var sender = _a.sender, stopped = _a.stopped;
|
|
1186
|
-
return !stopped && sender && sender.track;
|
|
1187
|
-
});
|
|
1094
|
+
_addOrRewriteLocalTrackIds(description) {
|
|
1095
|
+
const transceivers = this._peerConnection.getTransceivers();
|
|
1096
|
+
const activeTransceivers = transceivers.filter(({ sender, stopped }) => !stopped && sender && sender.track);
|
|
1188
1097
|
// NOTE(mmalavalli): There is no guarantee that MediaStreamTrack IDs will be present in
|
|
1189
1098
|
// SDPs, and even if they are, there is no guarantee that they will be the same as the
|
|
1190
1099
|
// actual MediaStreamTrack IDs. So, we add or re-write the actual MediaStreamTrack IDs
|
|
1191
1100
|
// to the assigned m= sections here.
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
});
|
|
1196
|
-
var midsToTrackIds = new Map(assignedTransceivers.map(function (_a) {
|
|
1197
|
-
var mid = _a.mid, sender = _a.sender;
|
|
1198
|
-
return [mid, _this._getMediaTrackSenderId(sender.track.id)];
|
|
1199
|
-
}));
|
|
1200
|
-
var sdp1 = addOrRewriteTrackIds(description.sdp, midsToTrackIds);
|
|
1101
|
+
const assignedTransceivers = activeTransceivers.filter(({ mid }) => mid);
|
|
1102
|
+
const midsToTrackIds = new Map(assignedTransceivers.map(({ mid, sender }) => [mid, this._getMediaTrackSenderId(sender.track.id)]));
|
|
1103
|
+
const sdp1 = addOrRewriteTrackIds(description.sdp, midsToTrackIds);
|
|
1201
1104
|
// NOTE(mmalavalli): Chrome and Safari do not apply the offer until they get an answer.
|
|
1202
1105
|
// So, we add or re-write the actual MediaStreamTrack IDs to the unassigned m= sections here.
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
return !mid;
|
|
1206
|
-
});
|
|
1207
|
-
var newTrackIdsByKind = new Map(['audio', 'video'].map(function (kind) { return [
|
|
1106
|
+
const unassignedTransceivers = activeTransceivers.filter(({ mid }) => !mid);
|
|
1107
|
+
const newTrackIdsByKind = new Map(['audio', 'video'].map(kind => [
|
|
1208
1108
|
kind,
|
|
1209
|
-
unassignedTransceivers.filter(
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
}).map(function (_a) {
|
|
1213
|
-
var sender = _a.sender;
|
|
1214
|
-
return _this._getMediaTrackSenderId(sender.track.id);
|
|
1215
|
-
})
|
|
1216
|
-
]; }));
|
|
1217
|
-
var sdp2 = addOrRewriteNewTrackIds(sdp1, midsToTrackIds, newTrackIdsByKind);
|
|
1109
|
+
unassignedTransceivers.filter(({ sender }) => sender.track.kind === kind).map(({ sender }) => this._getMediaTrackSenderId(sender.track.id))
|
|
1110
|
+
]));
|
|
1111
|
+
const sdp2 = addOrRewriteNewTrackIds(sdp1, midsToTrackIds, newTrackIdsByKind);
|
|
1218
1112
|
return new this._RTCSessionDescription({
|
|
1219
1113
|
sdp: sdp2,
|
|
1220
1114
|
type: description.type
|
|
1221
1115
|
});
|
|
1222
|
-
}
|
|
1116
|
+
}
|
|
1223
1117
|
/**
|
|
1224
1118
|
* Rollback and apply the given offer.
|
|
1225
1119
|
* @private
|
|
1226
1120
|
* @param {RTCSessionDescriptionInit} offer
|
|
1227
1121
|
* @returns {Promise<void>}
|
|
1228
1122
|
*/
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
};
|
|
1123
|
+
_rollbackAndApplyOffer(offer) {
|
|
1124
|
+
return this._setLocalDescription({ type: 'rollback' }).then(() => this._setLocalDescription(offer));
|
|
1125
|
+
}
|
|
1233
1126
|
/**
|
|
1234
1127
|
* Set a local description on the {@link PeerConnectionV2}.
|
|
1235
1128
|
* @private
|
|
1236
1129
|
* @param {RTCSessionDescription|RTCSessionDescriptionInit} description
|
|
1237
1130
|
* @returns {Promise<void>}
|
|
1238
1131
|
*/
|
|
1239
|
-
|
|
1240
|
-
var _this = this;
|
|
1132
|
+
_setLocalDescription(description) {
|
|
1241
1133
|
if (description.type !== 'rollback' && this._shouldApplyDtx) {
|
|
1242
1134
|
description = new this._RTCSessionDescription({
|
|
1243
1135
|
sdp: enableDtxForOpus(description.sdp),
|
|
1244
1136
|
type: description.type
|
|
1245
1137
|
});
|
|
1246
1138
|
}
|
|
1247
|
-
return this._peerConnection.setLocalDescription(description).catch(
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
message:
|
|
1139
|
+
return this._peerConnection.setLocalDescription(description).catch(error => {
|
|
1140
|
+
this._log.warn(`Calling setLocalDescription with an RTCSessionDescription of type "${description.type}" failed with the error "${error.message}".`, error);
|
|
1141
|
+
const errorToThrow = new MediaClientLocalDescFailedError();
|
|
1142
|
+
const publishWarning = {
|
|
1143
|
+
message: `Calling setLocalDescription with an RTCSessionDescription of type "${description.type}" failed`,
|
|
1252
1144
|
code: errorToThrow.code,
|
|
1253
|
-
error
|
|
1145
|
+
error
|
|
1254
1146
|
};
|
|
1255
1147
|
if (description.sdp) {
|
|
1256
|
-
|
|
1148
|
+
this._log.warn(`The SDP was ${description.sdp}`);
|
|
1257
1149
|
publishWarning.sdp = description.sdp;
|
|
1258
1150
|
}
|
|
1259
|
-
|
|
1151
|
+
this._publishMediaWarning(publishWarning);
|
|
1260
1152
|
throw errorToThrow;
|
|
1261
|
-
}).then(
|
|
1153
|
+
}).then(() => {
|
|
1262
1154
|
if (description.type !== 'rollback') {
|
|
1263
|
-
|
|
1155
|
+
this._localDescription = this._addOrRewriteLocalTrackIds(description);
|
|
1264
1156
|
// NOTE(mmalavalli): In order for this feature to be backward compatible with older
|
|
1265
1157
|
// SDK versions which to not support opus DTX, we append "usedtx=1" to the local SDP
|
|
1266
1158
|
// only while applying it. We will not send it over the wire to prevent inadvertent
|
|
1267
1159
|
// enabling of opus DTX in older SDKs. Newer SDKs will append "usedtx=1" by themselves
|
|
1268
1160
|
// if the developer has requested opus DTX to be enabled. (JSDK-3063)
|
|
1269
|
-
if (
|
|
1270
|
-
|
|
1271
|
-
sdp: enableDtxForOpus(
|
|
1272
|
-
type:
|
|
1161
|
+
if (this._shouldApplyDtx) {
|
|
1162
|
+
this._localDescription = new this._RTCSessionDescription({
|
|
1163
|
+
sdp: enableDtxForOpus(this._localDescription.sdp, []),
|
|
1164
|
+
type: this._localDescription.type
|
|
1273
1165
|
});
|
|
1274
1166
|
}
|
|
1275
|
-
|
|
1167
|
+
this._localCandidates = [];
|
|
1276
1168
|
if (description.type === 'offer') {
|
|
1277
|
-
|
|
1169
|
+
this._descriptionRevision++;
|
|
1278
1170
|
}
|
|
1279
1171
|
else if (description.type === 'answer') {
|
|
1280
|
-
|
|
1281
|
-
negotiationCompleted(
|
|
1172
|
+
this._lastStableDescriptionRevision = this._descriptionRevision;
|
|
1173
|
+
negotiationCompleted(this);
|
|
1282
1174
|
}
|
|
1283
|
-
|
|
1284
|
-
|
|
1175
|
+
this._localUfrag = getUfrag(description);
|
|
1176
|
+
this.emit('description', this.getState());
|
|
1285
1177
|
}
|
|
1286
1178
|
});
|
|
1287
|
-
}
|
|
1179
|
+
}
|
|
1288
1180
|
/**
|
|
1289
1181
|
* Set a remote RTCSessionDescription on the {@link PeerConnectionV2}.
|
|
1290
1182
|
* @private
|
|
1291
1183
|
* @param {RTCSessionDescriptionInit} description
|
|
1292
1184
|
* @returns {Promise<void>}
|
|
1293
1185
|
*/
|
|
1294
|
-
|
|
1295
|
-
var _this = this;
|
|
1186
|
+
_setRemoteDescription(description) {
|
|
1296
1187
|
if (description.sdp) {
|
|
1297
1188
|
description.sdp = this._setCodecPreferences(description.sdp, this._preferredAudioCodecs, this._preferredVideoCodecs);
|
|
1298
1189
|
if (this._shouldApplyDtx) {
|
|
@@ -1316,48 +1207,47 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1316
1207
|
}
|
|
1317
1208
|
description = new this._RTCSessionDescription(description);
|
|
1318
1209
|
// eslint-disable-next-line consistent-return
|
|
1319
|
-
return Promise.resolve().then(
|
|
1210
|
+
return Promise.resolve().then(() => {
|
|
1320
1211
|
// NOTE(syerrapragada): VMS does not support H264 simulcast. So,
|
|
1321
1212
|
// unset simulcast for sections in local offer where corresponding
|
|
1322
1213
|
// sections in answer doesn't have vp8 as preferred codec and reapply offer.
|
|
1323
|
-
if (description.type === 'answer' &&
|
|
1214
|
+
if (description.type === 'answer' && this._localDescriptionWithoutSimulcast) {
|
|
1324
1215
|
// NOTE(mpatwardhan):if we were using adaptive simulcast, and if its not supported by server
|
|
1325
1216
|
// revert simulcast even for vp8.
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
if (sdpWithoutSimulcastForNonVP8MediaSections !==
|
|
1331
|
-
return
|
|
1332
|
-
type:
|
|
1217
|
+
const adaptiveSimulcastEntry = this._preferredVideoCodecs.find(cs => 'adaptiveSimulcast' in cs);
|
|
1218
|
+
const revertForAll = !!adaptiveSimulcastEntry && adaptiveSimulcastEntry.adaptiveSimulcast === false;
|
|
1219
|
+
const sdpWithoutSimulcastForNonVP8MediaSections = this._revertSimulcast(this._localDescription.sdp, this._localDescriptionWithoutSimulcast.sdp, description.sdp, revertForAll);
|
|
1220
|
+
this._localDescriptionWithoutSimulcast = null;
|
|
1221
|
+
if (sdpWithoutSimulcastForNonVP8MediaSections !== this._localDescription.sdp) {
|
|
1222
|
+
return this._rollbackAndApplyOffer({
|
|
1223
|
+
type: this._localDescription.type,
|
|
1333
1224
|
sdp: sdpWithoutSimulcastForNonVP8MediaSections
|
|
1334
1225
|
});
|
|
1335
1226
|
}
|
|
1336
1227
|
}
|
|
1337
|
-
}).then(
|
|
1228
|
+
}).then(() => this._peerConnection.setRemoteDescription(description)).then(() => {
|
|
1338
1229
|
if (description.type === 'answer') {
|
|
1339
|
-
if (
|
|
1340
|
-
|
|
1341
|
-
|
|
1230
|
+
if (this._isRestartingIce) {
|
|
1231
|
+
this._log.debug('An ICE restart was in-progress and is now completed');
|
|
1232
|
+
this._isRestartingIce = false;
|
|
1342
1233
|
}
|
|
1343
|
-
negotiationCompleted(
|
|
1234
|
+
negotiationCompleted(this);
|
|
1344
1235
|
}
|
|
1345
|
-
},
|
|
1346
|
-
|
|
1236
|
+
}, error => {
|
|
1237
|
+
this._log.warn(`Calling setRemoteDescription with an RTCSessionDescription of type "${description.type}" failed with the error "${error.message}".`, error);
|
|
1347
1238
|
if (description.sdp) {
|
|
1348
|
-
|
|
1239
|
+
this._log.warn(`The SDP was ${description.sdp}`);
|
|
1349
1240
|
}
|
|
1350
1241
|
throw error;
|
|
1351
1242
|
});
|
|
1352
|
-
}
|
|
1243
|
+
}
|
|
1353
1244
|
/**
|
|
1354
1245
|
* Update the {@link PeerConnectionV2}'s description.
|
|
1355
1246
|
* @private
|
|
1356
1247
|
* @param {RTCSessionDescriptionInit} description
|
|
1357
1248
|
* @returns {Promise<void>}
|
|
1358
1249
|
*/
|
|
1359
|
-
|
|
1360
|
-
var _this = this;
|
|
1250
|
+
_updateDescription(description) {
|
|
1361
1251
|
switch (description.type) {
|
|
1362
1252
|
case 'answer':
|
|
1363
1253
|
case 'pranswer':
|
|
@@ -1401,56 +1291,56 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1401
1291
|
return this._handleGlare(description);
|
|
1402
1292
|
}
|
|
1403
1293
|
this._descriptionRevision = description.revision;
|
|
1404
|
-
return this._answer(description).then(
|
|
1294
|
+
return this._answer(description).then(() => { });
|
|
1405
1295
|
default:
|
|
1406
1296
|
// Do nothing.
|
|
1407
1297
|
}
|
|
1408
1298
|
// Handle answer or pranswer.
|
|
1409
|
-
|
|
1410
|
-
return Promise.resolve().then(
|
|
1411
|
-
return
|
|
1412
|
-
}).catch(
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
message:
|
|
1299
|
+
const revision = description.revision;
|
|
1300
|
+
return Promise.resolve().then(() => {
|
|
1301
|
+
return this._setRemoteDescription(description);
|
|
1302
|
+
}).catch(error => {
|
|
1303
|
+
const errorToThrow = new MediaClientRemoteDescFailedError();
|
|
1304
|
+
this._publishMediaWarning({
|
|
1305
|
+
message: `Calling setRemoteDescription with an RTCSessionDescription of type "${description.type}" failed`,
|
|
1416
1306
|
code: errorToThrow.code,
|
|
1417
|
-
error
|
|
1307
|
+
error,
|
|
1418
1308
|
sdp: description.sdp
|
|
1419
1309
|
});
|
|
1420
1310
|
throw errorToThrow;
|
|
1421
|
-
}).then(
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
return
|
|
1425
|
-
}).then(
|
|
1426
|
-
return
|
|
1427
|
-
&&
|
|
1428
|
-
}).then(
|
|
1429
|
-
|
|
1430
|
-
return
|
|
1311
|
+
}).then(() => {
|
|
1312
|
+
this._lastStableDescriptionRevision = revision;
|
|
1313
|
+
this._needsAnswer = false;
|
|
1314
|
+
return this._checkIceBox(description);
|
|
1315
|
+
}).then(() => {
|
|
1316
|
+
return this._queuedDescription
|
|
1317
|
+
&& this._updateDescription(this._queuedDescription);
|
|
1318
|
+
}).then(() => {
|
|
1319
|
+
this._queuedDescription = null;
|
|
1320
|
+
return this._maybeReoffer(this._peerConnection.localDescription).then(() => { });
|
|
1431
1321
|
});
|
|
1432
|
-
}
|
|
1322
|
+
}
|
|
1433
1323
|
/**
|
|
1434
1324
|
* Update the {@link PeerConnectionV2}'s ICE candidates.
|
|
1435
1325
|
* @private
|
|
1436
1326
|
* @param {object} iceState
|
|
1437
1327
|
* @returns {Promise<void>}
|
|
1438
1328
|
*/
|
|
1439
|
-
|
|
1440
|
-
|
|
1329
|
+
_updateIce(iceState) {
|
|
1330
|
+
const candidates = this._remoteCandidates.update(iceState);
|
|
1441
1331
|
return this._addIceCandidates(candidates);
|
|
1442
|
-
}
|
|
1332
|
+
}
|
|
1443
1333
|
/**
|
|
1444
1334
|
* Add a {@link DataTrackSender} to the {@link PeerConnectionV2}.
|
|
1445
1335
|
* @param {DataTrackSender} dataTrackSender
|
|
1446
1336
|
* @returns {void}
|
|
1447
1337
|
*/
|
|
1448
|
-
|
|
1338
|
+
addDataTrackSender(dataTrackSender) {
|
|
1449
1339
|
if (this._dataChannels.has(dataTrackSender)) {
|
|
1450
1340
|
return;
|
|
1451
1341
|
}
|
|
1452
1342
|
try {
|
|
1453
|
-
|
|
1343
|
+
const dataChannelDict = {
|
|
1454
1344
|
ordered: dataTrackSender.ordered
|
|
1455
1345
|
};
|
|
1456
1346
|
if (dataTrackSender.maxPacketLifeTime !== null) {
|
|
@@ -1459,26 +1349,24 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1459
1349
|
if (dataTrackSender.maxRetransmits !== null) {
|
|
1460
1350
|
dataChannelDict.maxRetransmits = dataTrackSender.maxRetransmits;
|
|
1461
1351
|
}
|
|
1462
|
-
|
|
1352
|
+
const dataChannel = this._peerConnection.createDataChannel(dataTrackSender.id, dataChannelDict);
|
|
1463
1353
|
dataTrackSender.addDataChannel(dataChannel);
|
|
1464
1354
|
this._dataChannels.set(dataTrackSender, dataChannel);
|
|
1465
1355
|
}
|
|
1466
1356
|
catch (error) {
|
|
1467
|
-
this._log.warn(
|
|
1357
|
+
this._log.warn(`Error creating an RTCDataChannel for DataTrack "${dataTrackSender.id}": ${error.message}`);
|
|
1468
1358
|
}
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
var _this = this;
|
|
1359
|
+
}
|
|
1360
|
+
_handleQueuedPublisherHints() {
|
|
1472
1361
|
if (this._peerConnection.signalingState === 'stable') {
|
|
1473
|
-
this._mediaTrackSenderToPublisherHints.forEach(
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
.
|
|
1478
|
-
.catch(function (error) { return deferred.reject(error); });
|
|
1362
|
+
this._mediaTrackSenderToPublisherHints.forEach(({ deferred, encodings }, mediaTrackSender) => {
|
|
1363
|
+
this._mediaTrackSenderToPublisherHints.delete(mediaTrackSender);
|
|
1364
|
+
this._setPublisherHint(mediaTrackSender, encodings)
|
|
1365
|
+
.then(result => deferred.resolve(result))
|
|
1366
|
+
.catch(error => deferred.reject(error));
|
|
1479
1367
|
});
|
|
1480
1368
|
}
|
|
1481
|
-
}
|
|
1369
|
+
}
|
|
1482
1370
|
/**
|
|
1483
1371
|
* updates encodings for simulcast layers of given sender.
|
|
1484
1372
|
* @param {RTCRtpSender} sender
|
|
@@ -1486,18 +1374,17 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1486
1374
|
* @returns {Promise<string>} string indicating result of the operation. can be one of
|
|
1487
1375
|
* "OK", "INVALID_HINT", "COULD_NOT_APPLY_HINT", "UNKNOWN_TRACK"
|
|
1488
1376
|
*/
|
|
1489
|
-
|
|
1490
|
-
var _this = this;
|
|
1377
|
+
_setPublisherHint(mediaTrackSender, encodings) {
|
|
1491
1378
|
if (isFirefox) {
|
|
1492
1379
|
return Promise.resolve('COULD_NOT_APPLY_HINT');
|
|
1493
1380
|
}
|
|
1494
1381
|
if (this._mediaTrackSenderToPublisherHints.has(mediaTrackSender)) {
|
|
1495
1382
|
// skip any stale hint associated with the mediaTrackSender.
|
|
1496
|
-
|
|
1383
|
+
const queuedHint = this._mediaTrackSenderToPublisherHints.get(mediaTrackSender);
|
|
1497
1384
|
queuedHint.deferred.resolve('REQUEST_SKIPPED');
|
|
1498
1385
|
this._mediaTrackSenderToPublisherHints.delete(mediaTrackSender);
|
|
1499
1386
|
}
|
|
1500
|
-
|
|
1387
|
+
const sender = this._rtpSenders.get(mediaTrackSender);
|
|
1501
1388
|
if (!sender) {
|
|
1502
1389
|
this._log.warn('Could not apply publisher hint because RTCRtpSender was not found');
|
|
1503
1390
|
return Promise.resolve('UNKNOWN_TRACK');
|
|
@@ -1509,20 +1396,19 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1509
1396
|
if (this._peerConnection.signalingState !== 'stable') {
|
|
1510
1397
|
// enqueue this hint to be applied when pc becomes stable.
|
|
1511
1398
|
this._log.debug('Queuing up publisher hint because signalingState:', this._peerConnection.signalingState);
|
|
1512
|
-
|
|
1513
|
-
this._mediaTrackSenderToPublisherHints.set(mediaTrackSender, { deferred
|
|
1399
|
+
const deferred = defer();
|
|
1400
|
+
this._mediaTrackSenderToPublisherHints.set(mediaTrackSender, { deferred, encodings });
|
|
1514
1401
|
return deferred.promise;
|
|
1515
1402
|
}
|
|
1516
|
-
|
|
1403
|
+
const parameters = sender.getParameters();
|
|
1517
1404
|
if (encodings !== null) {
|
|
1518
|
-
encodings.forEach(
|
|
1519
|
-
var enabled = _a.enabled, layerIndex = _a.layer_index;
|
|
1405
|
+
encodings.forEach(({ enabled, layer_index: layerIndex }) => {
|
|
1520
1406
|
if (parameters.encodings.length > layerIndex) {
|
|
1521
|
-
|
|
1407
|
+
this._log.debug(`layer:${layerIndex}, active:${parameters.encodings[layerIndex].active} => ${enabled}`);
|
|
1522
1408
|
parameters.encodings[layerIndex].active = enabled;
|
|
1523
1409
|
}
|
|
1524
1410
|
else {
|
|
1525
|
-
|
|
1411
|
+
this._log.warn(`invalid layer:${layerIndex}, active:${enabled}`);
|
|
1526
1412
|
}
|
|
1527
1413
|
});
|
|
1528
1414
|
}
|
|
@@ -1531,51 +1417,50 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1531
1417
|
// When encodings===null (that is we are asked to reset encodings for replaceTrack)
|
|
1532
1418
|
// along with disabling encodings, clear active flag for encodings that should not be disabled
|
|
1533
1419
|
this._maybeUpdateEncodings(sender.track, parameters.encodings, encodings === null /* trackReplaced */);
|
|
1534
|
-
return sender.setParameters(parameters).then(
|
|
1535
|
-
|
|
1420
|
+
return sender.setParameters(parameters).then(() => 'OK').catch(error => {
|
|
1421
|
+
this._log.error('Failed to apply publisher hints:', error);
|
|
1536
1422
|
return 'COULD_NOT_APPLY_HINT';
|
|
1537
1423
|
});
|
|
1538
|
-
}
|
|
1424
|
+
}
|
|
1539
1425
|
/**
|
|
1540
1426
|
* Add the {@link MediaTrackSender} to the {@link PeerConnectionV2}.
|
|
1541
1427
|
* @param {MediaTrackSender} mediaTrackSender
|
|
1542
1428
|
* @returns {void}
|
|
1543
1429
|
*/
|
|
1544
|
-
|
|
1545
|
-
var _this = this;
|
|
1430
|
+
addMediaTrackSender(mediaTrackSender) {
|
|
1546
1431
|
if (this._peerConnection.signalingState === 'closed' || this._rtpSenders.has(mediaTrackSender)) {
|
|
1547
1432
|
return;
|
|
1548
1433
|
}
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
mediaTrackSender.addSender(sender,
|
|
1434
|
+
const transceiver = this._addOrUpdateTransceiver(mediaTrackSender.track);
|
|
1435
|
+
const { sender } = transceiver;
|
|
1436
|
+
mediaTrackSender.addSender(sender, encodings => this._setPublisherHint(mediaTrackSender, encodings));
|
|
1552
1437
|
this._rtpNewSenders.add(sender);
|
|
1553
1438
|
this._rtpSenders.set(mediaTrackSender, sender);
|
|
1554
|
-
}
|
|
1439
|
+
}
|
|
1555
1440
|
/**
|
|
1556
1441
|
* Close the {@link PeerConnectionV2}.
|
|
1557
1442
|
* @returns {void}
|
|
1558
1443
|
*/
|
|
1559
|
-
|
|
1444
|
+
close() {
|
|
1560
1445
|
if (this._close()) {
|
|
1561
1446
|
this._descriptionRevision++;
|
|
1562
1447
|
this._localDescription = { type: 'close' };
|
|
1563
1448
|
this.emit('description', this.getState());
|
|
1564
1449
|
}
|
|
1565
|
-
}
|
|
1450
|
+
}
|
|
1566
1451
|
/**
|
|
1567
1452
|
* Get the {@link DataTrackReceiver}s and the {@link MediaTrackReceiver}s on the
|
|
1568
1453
|
* {@link PeerConnectionV2}.
|
|
1569
1454
|
* @returns {Array<DataTrackReceiver|MediaTrackReceiver>} trackReceivers
|
|
1570
1455
|
*/
|
|
1571
|
-
|
|
1456
|
+
getTrackReceivers() {
|
|
1572
1457
|
return Array.from(this._dataTrackReceivers).concat(Array.from(this._mediaTrackReceivers));
|
|
1573
|
-
}
|
|
1458
|
+
}
|
|
1574
1459
|
/**
|
|
1575
1460
|
* Get the {@link PeerConnectionV2}'s state (specifically, its description).
|
|
1576
1461
|
* @returns {?object}
|
|
1577
1462
|
*/
|
|
1578
|
-
|
|
1463
|
+
getState() {
|
|
1579
1464
|
if (!this._localDescription) {
|
|
1580
1465
|
return null;
|
|
1581
1466
|
}
|
|
@@ -1583,8 +1468,8 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1583
1468
|
// answer, and this method is called for sending a "sync" message while the next remote offer is being processed,
|
|
1584
1469
|
// we need to send the most recent stable description revision instead of the current description revision,
|
|
1585
1470
|
// which is supposed to be for the next local answer.
|
|
1586
|
-
|
|
1587
|
-
|
|
1471
|
+
const localDescriptionRevision = this._localDescription.type === 'answer' ? this._lastStableDescriptionRevision : this._descriptionRevision;
|
|
1472
|
+
const localDescription = {
|
|
1588
1473
|
type: this._localDescription.type,
|
|
1589
1474
|
revision: localDescriptionRevision
|
|
1590
1475
|
};
|
|
@@ -1595,48 +1480,47 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1595
1480
|
description: localDescription,
|
|
1596
1481
|
id: this.id
|
|
1597
1482
|
};
|
|
1598
|
-
}
|
|
1483
|
+
}
|
|
1599
1484
|
/**
|
|
1600
1485
|
* Create an offer and set it on the {@link PeerConnectionV2}.
|
|
1601
1486
|
* @returns {Promise<void>}
|
|
1602
1487
|
*/
|
|
1603
|
-
|
|
1604
|
-
var _this = this;
|
|
1488
|
+
offer() {
|
|
1605
1489
|
if (this._needsAnswer || this._isRestartingIce) {
|
|
1606
1490
|
this._shouldOffer = true;
|
|
1607
1491
|
return Promise.resolve();
|
|
1608
1492
|
}
|
|
1609
|
-
return this.bracket('offering',
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
return promise.then(
|
|
1613
|
-
|
|
1614
|
-
},
|
|
1615
|
-
|
|
1493
|
+
return this.bracket('offering', key => {
|
|
1494
|
+
this.transition('updating', key);
|
|
1495
|
+
const promise = this._needsAnswer || this._isRestartingIce ? Promise.resolve() : this._offer();
|
|
1496
|
+
return promise.then(() => {
|
|
1497
|
+
this.tryTransition('open', key);
|
|
1498
|
+
}, error => {
|
|
1499
|
+
this.tryTransition('open', key);
|
|
1616
1500
|
throw error;
|
|
1617
1501
|
});
|
|
1618
1502
|
});
|
|
1619
|
-
}
|
|
1503
|
+
}
|
|
1620
1504
|
/**
|
|
1621
1505
|
* Remove a {@link DataTrackSender} from the {@link PeerConnectionV2}.
|
|
1622
1506
|
* @param {DataTrackSender} dataTrackSender
|
|
1623
1507
|
* @returns {void}
|
|
1624
1508
|
*/
|
|
1625
|
-
|
|
1626
|
-
|
|
1509
|
+
removeDataTrackSender(dataTrackSender) {
|
|
1510
|
+
const dataChannel = this._dataChannels.get(dataTrackSender);
|
|
1627
1511
|
if (dataChannel) {
|
|
1628
1512
|
dataTrackSender.removeDataChannel(dataChannel);
|
|
1629
1513
|
this._dataChannels.delete(dataTrackSender);
|
|
1630
1514
|
dataChannel.close();
|
|
1631
1515
|
}
|
|
1632
|
-
}
|
|
1516
|
+
}
|
|
1633
1517
|
/**
|
|
1634
1518
|
* Remove the {@link MediaTrackSender} from the {@link PeerConnectionV2}.
|
|
1635
1519
|
* @param {MediaTrackSender} mediaTrackSender
|
|
1636
1520
|
* @returns {void}
|
|
1637
1521
|
*/
|
|
1638
|
-
|
|
1639
|
-
|
|
1522
|
+
removeMediaTrackSender(mediaTrackSender) {
|
|
1523
|
+
const sender = this._rtpSenders.get(mediaTrackSender);
|
|
1640
1524
|
if (!sender) {
|
|
1641
1525
|
return;
|
|
1642
1526
|
}
|
|
@@ -1646,85 +1530,83 @@ var PeerConnectionV2 = /** @class */ (function (_super) {
|
|
|
1646
1530
|
mediaTrackSender.removeSender(sender);
|
|
1647
1531
|
// clean up any pending publisher hints associated with this mediaTrackSender.
|
|
1648
1532
|
if (this._mediaTrackSenderToPublisherHints.has(mediaTrackSender)) {
|
|
1649
|
-
|
|
1533
|
+
const queuedHint = this._mediaTrackSenderToPublisherHints.get(mediaTrackSender);
|
|
1650
1534
|
queuedHint.deferred.resolve('UNKNOWN_TRACK');
|
|
1651
1535
|
this._mediaTrackSenderToPublisherHints.delete(mediaTrackSender);
|
|
1652
1536
|
}
|
|
1653
1537
|
this._rtpNewSenders.delete(sender);
|
|
1654
1538
|
this._rtpSenders.delete(mediaTrackSender);
|
|
1655
|
-
}
|
|
1539
|
+
}
|
|
1656
1540
|
/**
|
|
1657
1541
|
* Set the RTCConfiguration on the underlying RTCPeerConnection.
|
|
1658
1542
|
* @param {RTCConfiguration} configuration
|
|
1659
1543
|
* @returns {void}
|
|
1660
1544
|
*/
|
|
1661
|
-
|
|
1545
|
+
setConfiguration(configuration) {
|
|
1662
1546
|
if (typeof this._peerConnection.setConfiguration === 'function') {
|
|
1663
1547
|
this._peerConnection.setConfiguration(getConfiguration(configuration));
|
|
1664
1548
|
}
|
|
1665
|
-
}
|
|
1549
|
+
}
|
|
1666
1550
|
/**
|
|
1667
1551
|
* Set the ICE reconnect timeout period.
|
|
1668
1552
|
* @param {number} period - Period in milliseconds.
|
|
1669
1553
|
* @returns {this}
|
|
1670
1554
|
*/
|
|
1671
|
-
|
|
1555
|
+
setIceReconnectTimeout(period) {
|
|
1672
1556
|
this._iceReconnectTimeout.setDelay(period);
|
|
1673
1557
|
this._log.debug('Updated ICE reconnection timeout period:', this._iceReconnectTimeout.delay);
|
|
1674
1558
|
return this;
|
|
1675
|
-
}
|
|
1559
|
+
}
|
|
1676
1560
|
/**
|
|
1677
1561
|
* Update the {@link PeerConnectionV2}.
|
|
1678
1562
|
* @param {object} peerConnectionState
|
|
1679
1563
|
* @returns {Promise<void>}
|
|
1680
1564
|
*/
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
if (_this.state === 'closed') {
|
|
1565
|
+
update(peerConnectionState) {
|
|
1566
|
+
return this.bracket('updating', key => {
|
|
1567
|
+
if (this.state === 'closed') {
|
|
1685
1568
|
return Promise.resolve();
|
|
1686
1569
|
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1570
|
+
this.transition('updating', key);
|
|
1571
|
+
const updates = [];
|
|
1689
1572
|
if (peerConnectionState.ice) {
|
|
1690
|
-
updates.push(
|
|
1573
|
+
updates.push(this._updateIce(peerConnectionState.ice));
|
|
1691
1574
|
}
|
|
1692
1575
|
if (peerConnectionState.description) {
|
|
1693
|
-
updates.push(
|
|
1576
|
+
updates.push(this._updateDescription(peerConnectionState.description));
|
|
1694
1577
|
}
|
|
1695
|
-
return Promise.all(updates).then(
|
|
1696
|
-
|
|
1697
|
-
},
|
|
1698
|
-
|
|
1578
|
+
return Promise.all(updates).then(() => {
|
|
1579
|
+
this.tryTransition('open', key);
|
|
1580
|
+
}, error => {
|
|
1581
|
+
this.tryTransition('open', key);
|
|
1699
1582
|
throw error;
|
|
1700
1583
|
});
|
|
1701
1584
|
});
|
|
1702
|
-
}
|
|
1585
|
+
}
|
|
1703
1586
|
/**
|
|
1704
1587
|
* Get the {@link PeerConnectionV2}'s media statistics.
|
|
1705
1588
|
* @returns {Promise<StandardizedStatsResponse>}
|
|
1706
1589
|
*/
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
return PeerConnectionV2;
|
|
1712
|
-
}(StateMachine));
|
|
1590
|
+
getStats() {
|
|
1591
|
+
return getStatistics(this._peerConnection, { log: this._log }).then(response => rewriteTrackIds(this, response));
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1713
1594
|
function rewriteLocalTrackId(pcv2, stats) {
|
|
1714
|
-
|
|
1715
|
-
return Object.assign(stats, { trackId
|
|
1595
|
+
const trackId = pcv2._getMediaTrackSenderId(stats.trackId);
|
|
1596
|
+
return Object.assign(stats, { trackId });
|
|
1716
1597
|
}
|
|
1717
1598
|
function rewriteTrackId(pcv2, stats) {
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1599
|
+
const receiver = [...pcv2._mediaTrackReceivers]
|
|
1600
|
+
.find(receiver => receiver.track.id === stats.trackId);
|
|
1601
|
+
const trackId = receiver ? receiver.id : null;
|
|
1602
|
+
return Object.assign(stats, { trackId });
|
|
1721
1603
|
}
|
|
1722
1604
|
function rewriteTrackIds(pcv2, response) {
|
|
1723
1605
|
return Object.assign(response, {
|
|
1724
|
-
remoteAudioTrackStats: response.remoteAudioTrackStats.map(
|
|
1725
|
-
remoteVideoTrackStats: response.remoteVideoTrackStats.map(
|
|
1726
|
-
localAudioTrackStats: response.localAudioTrackStats.map(
|
|
1727
|
-
localVideoTrackStats: response.localVideoTrackStats.map(
|
|
1606
|
+
remoteAudioTrackStats: response.remoteAudioTrackStats.map(stats => rewriteTrackId(pcv2, stats)),
|
|
1607
|
+
remoteVideoTrackStats: response.remoteVideoTrackStats.map(stats => rewriteTrackId(pcv2, stats)),
|
|
1608
|
+
localAudioTrackStats: response.localAudioTrackStats.map(stats => rewriteLocalTrackId(pcv2, stats)),
|
|
1609
|
+
localVideoTrackStats: response.localVideoTrackStats.map(stats => rewriteLocalTrackId(pcv2, stats)),
|
|
1728
1610
|
});
|
|
1729
1611
|
}
|
|
1730
1612
|
/**
|
|
@@ -1747,7 +1629,7 @@ function rewriteTrackIds(pcv2, response) {
|
|
|
1747
1629
|
*/
|
|
1748
1630
|
function getUfrag(description) {
|
|
1749
1631
|
if (description.sdp) {
|
|
1750
|
-
|
|
1632
|
+
const match = description.sdp.match(/^a=ice-ufrag:([a-zA-Z0-9+/]+)/m);
|
|
1751
1633
|
if (match) {
|
|
1752
1634
|
return match[1];
|
|
1753
1635
|
}
|
|
@@ -1762,8 +1644,7 @@ function getUfrag(description) {
|
|
|
1762
1644
|
* @param {RTCConfiguration} [configuration={}] - Optional RTCConfiguration object
|
|
1763
1645
|
* @returns {RTCConfiguration}
|
|
1764
1646
|
*/
|
|
1765
|
-
function getConfiguration(configuration) {
|
|
1766
|
-
if (configuration === void 0) { configuration = {}; }
|
|
1647
|
+
function getConfiguration(configuration = {}) {
|
|
1767
1648
|
return Object.assign({
|
|
1768
1649
|
bundlePolicy: 'max-bundle',
|
|
1769
1650
|
rtcpMuxPolicy: 'require'
|
|
@@ -1778,7 +1659,7 @@ function getConfiguration(configuration) {
|
|
|
1778
1659
|
* @return {boolean}
|
|
1779
1660
|
*/
|
|
1780
1661
|
function isSenderOfKind(kind, sender) {
|
|
1781
|
-
|
|
1662
|
+
const track = sender.track;
|
|
1782
1663
|
return track && track.kind === kind && track.readyState !== 'ended';
|
|
1783
1664
|
}
|
|
1784
1665
|
/**
|
|
@@ -1807,23 +1688,17 @@ function shouldRecycleTransceiver(transceiver, pcv2) {
|
|
|
1807
1688
|
* @returns {?RTCRtpTransceiver}
|
|
1808
1689
|
*/
|
|
1809
1690
|
function takeRecycledTransceiver(pcv2, kind) {
|
|
1810
|
-
|
|
1811
|
-
audio: pcv2._preferredAudioCodecs.map(
|
|
1812
|
-
|
|
1813
|
-
return codec.toLowerCase();
|
|
1814
|
-
}),
|
|
1815
|
-
video: pcv2._preferredVideoCodecs.map(function (_a) {
|
|
1816
|
-
var codec = _a.codec;
|
|
1817
|
-
return codec.toLowerCase();
|
|
1818
|
-
})
|
|
1691
|
+
const preferredCodecs = {
|
|
1692
|
+
audio: pcv2._preferredAudioCodecs.map(({ codec }) => codec.toLowerCase()),
|
|
1693
|
+
video: pcv2._preferredVideoCodecs.map(({ codec }) => codec.toLowerCase())
|
|
1819
1694
|
}[kind];
|
|
1820
|
-
|
|
1821
|
-
|
|
1695
|
+
const recycledTransceivers = pcv2._recycledTransceivers[kind];
|
|
1696
|
+
const localCodec = preferredCodecs.find(codec => pcv2._localCodecs.has(codec));
|
|
1822
1697
|
if (!localCodec) {
|
|
1823
1698
|
return recycledTransceivers.shift();
|
|
1824
1699
|
}
|
|
1825
|
-
|
|
1826
|
-
|
|
1700
|
+
const transceiver = recycledTransceivers.find(transceiver => {
|
|
1701
|
+
const remoteCodecMap = pcv2._remoteCodecMaps.get(transceiver.mid);
|
|
1827
1702
|
return remoteCodecMap && remoteCodecMap.has(localCodec);
|
|
1828
1703
|
});
|
|
1829
1704
|
if (transceiver) {
|
|
@@ -1837,13 +1712,13 @@ function takeRecycledTransceiver(pcv2, kind) {
|
|
|
1837
1712
|
* @returns {void}
|
|
1838
1713
|
*/
|
|
1839
1714
|
function updateLocalCodecs(pcv2) {
|
|
1840
|
-
|
|
1715
|
+
const description = pcv2._peerConnection.localDescription;
|
|
1841
1716
|
if (!description || !description.sdp) {
|
|
1842
1717
|
return;
|
|
1843
1718
|
}
|
|
1844
|
-
getMediaSections(description.sdp).forEach(
|
|
1845
|
-
|
|
1846
|
-
codecMap.forEach(
|
|
1719
|
+
getMediaSections(description.sdp).forEach(section => {
|
|
1720
|
+
const codecMap = createCodecMapForMediaSection(section);
|
|
1721
|
+
codecMap.forEach((pts, codec) => pcv2._localCodecs.add(codec));
|
|
1847
1722
|
});
|
|
1848
1723
|
}
|
|
1849
1724
|
/**
|
|
@@ -1852,17 +1727,17 @@ function updateLocalCodecs(pcv2) {
|
|
|
1852
1727
|
* @returns {void}
|
|
1853
1728
|
*/
|
|
1854
1729
|
function updateRemoteCodecMaps(pcv2) {
|
|
1855
|
-
|
|
1730
|
+
const description = pcv2._peerConnection.remoteDescription;
|
|
1856
1731
|
if (!description || !description.sdp) {
|
|
1857
1732
|
return;
|
|
1858
1733
|
}
|
|
1859
|
-
getMediaSections(description.sdp).forEach(
|
|
1860
|
-
|
|
1734
|
+
getMediaSections(description.sdp).forEach(section => {
|
|
1735
|
+
const matched = section.match(/^a=mid:(.+)$/m);
|
|
1861
1736
|
if (!matched || !matched[1]) {
|
|
1862
1737
|
return;
|
|
1863
1738
|
}
|
|
1864
|
-
|
|
1865
|
-
|
|
1739
|
+
const mid = matched[1];
|
|
1740
|
+
const codecMap = createCodecMapForMediaSection(section);
|
|
1866
1741
|
pcv2._remoteCodecMaps.set(mid, codecMap);
|
|
1867
1742
|
});
|
|
1868
1743
|
}
|
|
@@ -1873,9 +1748,9 @@ function updateRemoteCodecMaps(pcv2) {
|
|
|
1873
1748
|
function updateRecycledTransceivers(pcv2) {
|
|
1874
1749
|
pcv2._recycledTransceivers.audio = [];
|
|
1875
1750
|
pcv2._recycledTransceivers.video = [];
|
|
1876
|
-
pcv2._peerConnection.getTransceivers().forEach(
|
|
1751
|
+
pcv2._peerConnection.getTransceivers().forEach(transceiver => {
|
|
1877
1752
|
if (shouldRecycleTransceiver(transceiver, pcv2)) {
|
|
1878
|
-
|
|
1753
|
+
const track = transceiver.receiver.track;
|
|
1879
1754
|
pcv2._recycledTransceivers[track.kind].push(transceiver);
|
|
1880
1755
|
}
|
|
1881
1756
|
});
|
|
@@ -1887,8 +1762,8 @@ function updateRecycledTransceivers(pcv2) {
|
|
|
1887
1762
|
*/
|
|
1888
1763
|
function updateDtlsTransport(pcv2) {
|
|
1889
1764
|
var _a;
|
|
1890
|
-
|
|
1891
|
-
|
|
1765
|
+
const senders = pcv2._peerConnection.getSenders();
|
|
1766
|
+
const transport = (_a = senders.find(sender => sender.transport)) === null || _a === void 0 ? void 0 : _a.transport;
|
|
1892
1767
|
if (transport && !pcv2._dtlsTransport) {
|
|
1893
1768
|
pcv2._dtlsTransport = transport;
|
|
1894
1769
|
transport.addEventListener('statechange', pcv2._handleDtlsTransportStateChange.bind(pcv2));
|
|
@@ -1897,7 +1772,7 @@ function updateDtlsTransport(pcv2) {
|
|
|
1897
1772
|
}
|
|
1898
1773
|
if (transport.iceTransport && typeof transport.iceTransport.getSelectedCandidatePair === 'function') {
|
|
1899
1774
|
transport.iceTransport.addEventListener('selectedcandidatepairchange', pcv2._handleSelectedCandidatePairChange.bind(pcv2));
|
|
1900
|
-
|
|
1775
|
+
const pair = transport.iceTransport.getSelectedCandidatePair();
|
|
1901
1776
|
if (pair) {
|
|
1902
1777
|
pcv2._handleSelectedCandidatePairChange();
|
|
1903
1778
|
}
|
|
@@ -1914,7 +1789,7 @@ function negotiationCompleted(pcv2) {
|
|
|
1914
1789
|
updateLocalCodecs(pcv2);
|
|
1915
1790
|
updateRemoteCodecMaps(pcv2);
|
|
1916
1791
|
updateDtlsTransport(pcv2);
|
|
1917
|
-
updateEncodingParameters(pcv2).then(
|
|
1792
|
+
updateEncodingParameters(pcv2).then(() => {
|
|
1918
1793
|
// if there any any publisher hints queued, apply them now.
|
|
1919
1794
|
pcv2._handleQueuedPublisherHints();
|
|
1920
1795
|
});
|
|
@@ -1925,22 +1800,22 @@ function negotiationCompleted(pcv2) {
|
|
|
1925
1800
|
* @returns {void}
|
|
1926
1801
|
*/
|
|
1927
1802
|
function updateEncodingParameters(pcv2) {
|
|
1928
|
-
|
|
1929
|
-
|
|
1803
|
+
const { maxAudioBitrate, maxVideoBitrate } = pcv2._encodingParameters;
|
|
1804
|
+
const maxBitrates = new Map([
|
|
1930
1805
|
['audio', maxAudioBitrate],
|
|
1931
1806
|
['video', maxVideoBitrate]
|
|
1932
1807
|
]);
|
|
1933
|
-
|
|
1934
|
-
pcv2._peerConnection.getSenders().filter(
|
|
1935
|
-
|
|
1936
|
-
|
|
1808
|
+
const promises = [];
|
|
1809
|
+
pcv2._peerConnection.getSenders().filter(sender => sender.track).forEach(sender => {
|
|
1810
|
+
const maxBitrate = maxBitrates.get(sender.track.kind);
|
|
1811
|
+
const params = sender.getParameters();
|
|
1937
1812
|
if (maxBitrate === null || maxBitrate === 0) {
|
|
1938
1813
|
removeMaxBitrate(params);
|
|
1939
1814
|
}
|
|
1940
1815
|
else if (pcv2._isChromeScreenShareTrack(sender.track)) {
|
|
1941
1816
|
// NOTE(mpatwardhan): Sometimes (JSDK-2557) chrome does not send any bytes on screen track if MaxBitRate is set on it via setParameters,
|
|
1942
1817
|
// To workaround this issue we will not apply maxBitrate if the track appears to be a screen share track created by chrome
|
|
1943
|
-
pcv2._log.warn(
|
|
1818
|
+
pcv2._log.warn(`Not setting maxBitrate for ${sender.track.kind} Track ${sender.track.id} because it appears to be screen share track: ${sender.track.label}`);
|
|
1944
1819
|
}
|
|
1945
1820
|
else {
|
|
1946
1821
|
setMaxBitrate(params, maxBitrate);
|
|
@@ -1970,11 +1845,11 @@ function updateEncodingParameters(pcv2) {
|
|
|
1970
1845
|
}
|
|
1971
1846
|
}
|
|
1972
1847
|
// when a sender is reused, delete any active encodings set by server.
|
|
1973
|
-
|
|
1848
|
+
const trackReplaced = pcv2._rtpNewSenders.has(sender);
|
|
1974
1849
|
pcv2._maybeUpdateEncodings(sender.track, params.encodings, trackReplaced);
|
|
1975
1850
|
pcv2._rtpNewSenders.delete(sender);
|
|
1976
|
-
|
|
1977
|
-
pcv2._log.warn(
|
|
1851
|
+
const promise = sender.setParameters(params).catch(error => {
|
|
1852
|
+
pcv2._log.warn(`Error while setting encodings parameters for ${sender.track.kind} Track ${sender.track.id}: ${error.message || error.name}`);
|
|
1978
1853
|
});
|
|
1979
1854
|
promises.push(promise);
|
|
1980
1855
|
});
|
|
@@ -1987,7 +1862,7 @@ function updateEncodingParameters(pcv2) {
|
|
|
1987
1862
|
*/
|
|
1988
1863
|
function removeMaxBitrate(params) {
|
|
1989
1864
|
if (Array.isArray(params.encodings)) {
|
|
1990
|
-
params.encodings.forEach(
|
|
1865
|
+
params.encodings.forEach(encoding => delete encoding.maxBitrate);
|
|
1991
1866
|
}
|
|
1992
1867
|
}
|
|
1993
1868
|
/**
|
|
@@ -1998,10 +1873,10 @@ function removeMaxBitrate(params) {
|
|
|
1998
1873
|
*/
|
|
1999
1874
|
function setMaxBitrate(params, maxBitrate) {
|
|
2000
1875
|
if (isFirefox) {
|
|
2001
|
-
params.encodings = [{ maxBitrate
|
|
1876
|
+
params.encodings = [{ maxBitrate }];
|
|
2002
1877
|
}
|
|
2003
1878
|
else {
|
|
2004
|
-
params.encodings.forEach(
|
|
1879
|
+
params.encodings.forEach(encoding => {
|
|
2005
1880
|
encoding.maxBitrate = maxBitrate;
|
|
2006
1881
|
});
|
|
2007
1882
|
}
|