summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/libjingle/source
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/libjingle/source
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/libjingle/source')
-rw-r--r--chromium/third_party/libjingle/source/talk/OWNERS6
-rw-r--r--chromium/third_party/libjingle/source/talk/PRESUBMIT.py14
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/OWNERS3
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/audiotrack.h17
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/datachannel.cc159
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/datachannel.h36
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/datachannel_unittest.cc199
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/datachannelinterface.h4
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/jsepsessiondescription.cc16
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/jsepsessiondescription_unittest.cc31
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/localaudiosource.cc25
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.cc88
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h47
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediastream_unittest.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler.cc52
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler.h33
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler_unittest.cc36
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h81
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamprovider.h4
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling.cc223
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling.h28
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling_unittest.cc188
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamtrackproxy.h5
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/README13
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCAudioTrack.mm6
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCDataChannel+Internal.h55
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCDataChannel.mm273
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEAGLVideoView+Internal.h36
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEAGLVideoView.m244
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEnumConverter.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEnumConverter.mm10
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCI420Frame+Internal.h (renamed from chromium/third_party/libjingle/source/talk/media/devices/iosdeviceinfo.cc)16
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCI420Frame.mm64
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCICECandidate.mm16
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCICEServer.mm14
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaConstraints.mm14
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaSource.mm2
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaStream.mm54
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaStreamTrack.mm40
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCNSGLVideoView.m187
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCOpenGLVideoRenderer.mm457
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPair.m6
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnection+Internal.h7
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnection.mm191
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionFactory.mm59
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionObserver.h10
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionObserver.mm55
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCSessionDescription.mm10
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCStatsReport+Internal.h36
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCStatsReport.mm69
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoCapturer+Internal.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoCapturer.mm18
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoRenderer+Internal.h6
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoRenderer.mm72
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoSource.mm6
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoTrack.mm21
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCDataChannel.h112
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCEAGLVideoView.h (renamed from chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCVideoRendererDelegate.h)25
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCI420Frame.h19
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCICEServer.h4
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCMediaSource.h6
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCMediaStreamTrack.h12
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCNSGLVideoView.h48
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCOpenGLVideoRenderer.h73
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCPeerConnection.h35
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCPeerConnectionDelegate.h7
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCSessionDescriptionDelegate.h (renamed from chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCSessionDescriptonDelegate.h)6
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCStatsDelegate.h39
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCStatsReport.h (renamed from chromium/third_party/libjingle/source/talk/examples/plus/presencepushtask.h)38
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCTypes.h6
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCVideoRenderer.h38
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objctests/Info.plist14
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.h8
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m128
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm229
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCSessionDescriptionSyncObserver.h4
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCSessionDescriptionSyncObserver.m16
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objctests/mac/main.mm6
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection.cc173
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection.h26
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection_unittest.cc118
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionendtoend_unittest.cc200
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory.cc88
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory.h19
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory_unittest.cc92
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h83
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface_unittest.cc71
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionproxy.h5
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/portallocatorfactory.cc2
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/remoteaudiosource.cc72
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/remoteaudiosource.h (renamed from chromium/third_party/libjingle/source/talk/examples/chat/textchatreceivetask.h)55
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/sctputils.cc (renamed from chromium/third_party/libjingle/source/talk/media/sctp/sctputils.cc)44
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/sctputils.h (renamed from chromium/third_party/libjingle/source/talk/media/sctp/sctputils.h)20
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/sctputils_unittest.cc (renamed from chromium/third_party/libjingle/source/talk/media/sctp/sctputils_unittest.cc)50
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/statscollector.cc352
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/statscollector.h49
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/statscollector_unittest.cc938
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/statstypes.h21
-rwxr-xr-x[-rw-r--r--]chromium/third_party/libjingle/source/talk/app/webrtc/umametrics.h (renamed from chromium/third_party/libjingle/source/talk/examples/chat/textchatsendtask.h)47
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/videosource.cc31
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/videosource_unittest.cc11
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/webrtc.scons89
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsdp.cc179
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsdp_unittest.cc260
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession.cc530
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession.h62
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession_unittest.cc689
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsessiondescriptionfactory.cc16
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsessiondescriptionfactory.h4
-rw-r--r--chromium/third_party/libjingle/source/talk/base/asyncinvoker-inl.h146
-rw-r--r--chromium/third_party/libjingle/source/talk/base/asyncinvoker.cc108
-rw-r--r--chromium/third_party/libjingle/source/talk/base/asyncinvoker.h151
-rw-r--r--chromium/third_party/libjingle/source/talk/base/asyncpacketsocket.h43
-rw-r--r--chromium/third_party/libjingle/source/talk/base/asynctcpsocket.cc11
-rw-r--r--chromium/third_party/libjingle/source/talk/base/asynctcpsocket.h8
-rw-r--r--chromium/third_party/libjingle/source/talk/base/asyncudpsocket.cc8
-rw-r--r--chromium/third_party/libjingle/source/talk/base/asyncudpsocket.h19
-rw-r--r--chromium/third_party/libjingle/source/talk/base/bandwidthsmoother.cc2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/bind.h207
-rw-r--r--chromium/third_party/libjingle/source/talk/base/bind.h.pump30
-rw-r--r--chromium/third_party/libjingle/source/talk/base/bind_unittest.cc10
-rw-r--r--chromium/third_party/libjingle/source/talk/base/buffer.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/bytebuffer.cc5
-rw-r--r--chromium/third_party/libjingle/source/talk/base/byteorder.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/callback.h278
-rw-r--r--chromium/third_party/libjingle/source/talk/base/callback.h.pump120
-rw-r--r--chromium/third_party/libjingle/source/talk/base/callback_unittest.cc98
-rw-r--r--chromium/third_party/libjingle/source/talk/base/common.cc10
-rw-r--r--chromium/third_party/libjingle/source/talk/base/common.h20
-rw-r--r--chromium/third_party/libjingle/source/talk/base/cpumonitor.cc10
-rw-r--r--chromium/third_party/libjingle/source/talk/base/cpumonitor_unittest.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/base/criticalsection_unittest.cc163
-rw-r--r--chromium/third_party/libjingle/source/talk/base/cryptstring.h4
-rw-r--r--chromium/third_party/libjingle/source/talk/base/event.cc17
-rw-r--r--chromium/third_party/libjingle/source/talk/base/fakesslidentity.h22
-rw-r--r--chromium/third_party/libjingle/source/talk/base/fileutils.cc29
-rw-r--r--chromium/third_party/libjingle/source/talk/base/fileutils.h21
-rw-r--r--chromium/third_party/libjingle/source/talk/base/firewallsocketserver.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/base/gunit.h7
-rw-r--r--chromium/third_party/libjingle/source/talk/base/helpers.cc26
-rw-r--r--chromium/third_party/libjingle/source/talk/base/helpers_unittest.cc22
-rw-r--r--chromium/third_party/libjingle/source/talk/base/httpserver_unittest.cc6
-rw-r--r--chromium/third_party/libjingle/source/talk/base/iosfilesystem.mm70
-rw-r--r--chromium/third_party/libjingle/source/talk/base/ipaddress.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/base/ipaddress_unittest.cc12
-rw-r--r--chromium/third_party/libjingle/source/talk/base/json.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/base/latebindingsymboltable.cc.def13
-rw-r--r--chromium/third_party/libjingle/source/talk/base/latebindingsymboltable.h.def1
-rw-r--r--chromium/third_party/libjingle/source/talk/base/linux.cc83
-rw-r--r--chromium/third_party/libjingle/source/talk/base/linux.h5
-rw-r--r--chromium/third_party/libjingle/source/talk/base/linux_unittest.cc8
-rw-r--r--chromium/third_party/libjingle/source/talk/base/logging.cc5
-rw-r--r--chromium/third_party/libjingle/source/talk/base/logging.h7
-rw-r--r--chromium/third_party/libjingle/source/talk/base/maccocoasocketserver.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/maccocoasocketserver.mm63
-rw-r--r--chromium/third_party/libjingle/source/talk/base/messagedigest.cc13
-rw-r--r--chromium/third_party/libjingle/source/talk/base/messagedigest.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/base/messagehandler.h34
-rw-r--r--chromium/third_party/libjingle/source/talk/base/messagequeue.cc28
-rw-r--r--chromium/third_party/libjingle/source/talk/base/messagequeue.h9
-rw-r--r--chromium/third_party/libjingle/source/talk/base/natserver.cc9
-rw-r--r--chromium/third_party/libjingle/source/talk/base/natsocketfactory.cc8
-rw-r--r--chromium/third_party/libjingle/source/talk/base/nattypes.cc2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/nethelpers.cc9
-rw-r--r--chromium/third_party/libjingle/source/talk/base/nethelpers.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/network.cc119
-rw-r--r--chromium/third_party/libjingle/source/talk/base/network.h39
-rw-r--r--chromium/third_party/libjingle/source/talk/base/network_unittest.cc45
-rw-r--r--chromium/third_party/libjingle/source/talk/base/nssidentity.cc97
-rw-r--r--chromium/third_party/libjingle/source/talk/base/nssidentity.h16
-rw-r--r--chromium/third_party/libjingle/source/talk/base/nssstreamadapter.cc90
-rw-r--r--chromium/third_party/libjingle/source/talk/base/nssstreamadapter.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/base/openssl.h37
-rw-r--r--chromium/third_party/libjingle/source/talk/base/openssladapter.cc14
-rw-r--r--chromium/third_party/libjingle/source/talk/base/openssldigest.cc5
-rw-r--r--chromium/third_party/libjingle/source/talk/base/opensslidentity.cc85
-rw-r--r--chromium/third_party/libjingle/source/talk/base/opensslidentity.h22
-rw-r--r--chromium/third_party/libjingle/source/talk/base/opensslstreamadapter.cc155
-rw-r--r--chromium/third_party/libjingle/source/talk/base/opensslstreamadapter.h16
-rw-r--r--chromium/third_party/libjingle/source/talk/base/optionsfile_unittest.cc209
-rw-r--r--chromium/third_party/libjingle/source/talk/base/physicalsocketserver.cc44
-rw-r--r--chromium/third_party/libjingle/source/talk/base/physicalsocketserver.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/physicalsocketserver_unittest.cc13
-rw-r--r--chromium/third_party/libjingle/source/talk/base/profiler.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/profiler_unittest.cc8
-rw-r--r--chromium/third_party/libjingle/source/talk/base/proxydetect.cc30
-rw-r--r--chromium/third_party/libjingle/source/talk/base/proxydetect_unittest.cc1
-rw-r--r--chromium/third_party/libjingle/source/talk/base/refcount.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/rollingaccumulator.h82
-rw-r--r--chromium/third_party/libjingle/source/talk/base/rollingaccumulator_unittest.cc63
-rw-r--r--chromium/third_party/libjingle/source/talk/base/safe_conversions.h96
-rw-r--r--chromium/third_party/libjingle/source/talk/base/safe_conversions_impl.h205
-rw-r--r--chromium/third_party/libjingle/source/talk/base/scoped_ptr.h4
-rw-r--r--chromium/third_party/libjingle/source/talk/base/scoped_ref_ptr.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/scopedptrcollection.h (renamed from chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_unittest.cc)63
-rw-r--r--chromium/third_party/libjingle/source/talk/base/scopedptrcollection_unittest.cc90
-rw-r--r--chromium/third_party/libjingle/source/talk/base/sharedexclusivelock_unittest.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/base/signalthread_unittest.cc6
-rwxr-xr-xchromium/third_party/libjingle/source/talk/base/sigslottester.h216
-rwxr-xr-xchromium/third_party/libjingle/source/talk/base/sigslottester.h.pump102
-rwxr-xr-xchromium/third_party/libjingle/source/talk/base/sigslottester_unittest.cc74
-rw-r--r--chromium/third_party/libjingle/source/talk/base/socket.h19
-rw-r--r--chromium/third_party/libjingle/source/talk/base/socket_unittest.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/base/socketaddress.cc2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/sslfingerprint.cc114
-rw-r--r--chromium/third_party/libjingle/source/talk/base/sslfingerprint.h74
-rw-r--r--chromium/third_party/libjingle/source/talk/base/sslidentity.cc12
-rw-r--r--chromium/third_party/libjingle/source/talk/base/sslidentity.h20
-rw-r--r--chromium/third_party/libjingle/source/talk/base/sslidentity_unittest.cc45
-rw-r--r--chromium/third_party/libjingle/source/talk/base/sslstreamadapter.h33
-rw-r--r--chromium/third_party/libjingle/source/talk/base/sslstreamadapter_unittest.cc136
-rw-r--r--chromium/third_party/libjingle/source/talk/base/sslstreamadapterhelper.cc7
-rw-r--r--chromium/third_party/libjingle/source/talk/base/sslstreamadapterhelper.h11
-rw-r--r--chromium/third_party/libjingle/source/talk/base/stream.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/base/stream.h7
-rw-r--r--chromium/third_party/libjingle/source/talk/base/stringencode.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/base/stringutils.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/template_util.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/testclient.cc9
-rw-r--r--chromium/third_party/libjingle/source/talk/base/testechoserver.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/base/testutils.h37
-rw-r--r--chromium/third_party/libjingle/source/talk/base/thread.cc42
-rw-r--r--chromium/third_party/libjingle/source/talk/base/thread.h54
-rw-r--r--chromium/third_party/libjingle/source/talk/base/thread_unittest.cc191
-rw-r--r--chromium/third_party/libjingle/source/talk/base/timeutils.cc21
-rw-r--r--chromium/third_party/libjingle/source/talk/base/timeutils.h11
-rw-r--r--chromium/third_party/libjingle/source/talk/base/timeutils_unittest.cc23
-rw-r--r--chromium/third_party/libjingle/source/talk/base/transformadapter.cc2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/unittest_main.cc23
-rw-r--r--chromium/third_party/libjingle/source/talk/base/unixfilesystem.cc61
-rw-r--r--chromium/third_party/libjingle/source/talk/base/unixfilesystem.h14
-rw-r--r--chromium/third_party/libjingle/source/talk/base/versionparsing.cc2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/virtualsocket_unittest.cc9
-rw-r--r--chromium/third_party/libjingle/source/talk/base/virtualsocketserver.cc10
-rw-r--r--chromium/third_party/libjingle/source/talk/base/virtualsocketserver.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/base/win32regkey.cc60
-rw-r--r--chromium/third_party/libjingle/source/talk/base/win32toolhelp_unittest.cc1
-rw-r--r--chromium/third_party/libjingle/source/talk/base/windowpickerfactory.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/base/winping.cc2
-rw-r--r--chromium/third_party/libjingle/source/talk/build/OWNERS5
-rw-r--r--chromium/third_party/libjingle/source/talk/build/common.gypi55
-rw-r--r--chromium/third_party/libjingle/source/talk/build/ios_test.plist24
-rw-r--r--chromium/third_party/libjingle/source/talk/build/ios_tests.gypi55
-rw-r--r--chromium/third_party/libjingle/source/talk/build/isolate.gypi83
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/android/AndroidManifest.xml4
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/android/README14
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/call/call_main.cc12
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/call/console.cc14
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/call/console.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/chat/Info.plist11
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/chat/chat_main.cc159
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/chat/chatapp.cc251
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/chat/chatapp.h171
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/chat/consoletask.cc177
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/chat/consoletask.h92
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/chat/textchatsendtask.cc81
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppClient.m340
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.m454
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCViewController.m88
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/GAEChannelClient.m107
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/ios/README3
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/login/login_main.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCAppClient.h (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppClient.h)30
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCAppClient.m320
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCConnectionManager.h66
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCConnectionManager.m495
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/GAEChannelClient.h (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/GAEChannelClient.h)13
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/GAEChannelClient.m167
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/channel.html (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/ios_channel.html)30
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.h34
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.m (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.h)51
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.h (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCViewController.h)10
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m231
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/AppRTCDemo-Prefix.pch (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/AppRTCDemo-Prefix.pch)0
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/Default.png (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/Default.png)bin6540 -> 6540 bytes
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/Info.plist (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/Info.plist)15
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/ResourceRules.plist (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/ResourceRules.plist)0
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/en.lproj/APPRTCViewController.xib (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/en.lproj/APPRTCViewController.xib)321
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/main.m (renamed from chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/main.m)2
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCAppDelegate.h31
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCAppDelegate.m77
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.h34
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.m312
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/Info.plist29
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/main.m39
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/Icon.png (renamed from chromium/third_party/libjingle/source/talk/examples/ios/Icon.png)bin62469 -> 62469 bytes
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/objc/README3
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/pcp/pcp_main.cc715
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/peerconnection/client/conductor.cc1
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/peerconnection/client/linux/main.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/peerconnection/client/main.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/peerconnection/peerconnection.scons64
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/plus/libjingleplus.cc736
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/plus/libjingleplus.h154
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/plus/presencepushtask.cc201
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/plus/rostertask.cc218
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/plus/rostertask.h72
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_main.cc119
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_test_notifier.h101
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/relayserver/relayserver_main.cc (renamed from chromium/third_party/libjingle/source/talk/p2p/base/relayserver_main.cc)0
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/stunserver/stunserver_main.cc (renamed from chromium/third_party/libjingle/source/talk/p2p/base/stunserver_main.cc)0
-rw-r--r--chromium/third_party/libjingle/source/talk/examples/turnserver/turnserver_main.cc (renamed from chromium/third_party/libjingle/source/talk/p2p/base/turnserver_main.cc)0
-rwxr-xr-xchromium/third_party/libjingle/source/talk/libjingle.gyp140
-rw-r--r--chromium/third_party/libjingle/source/talk/libjingle.scons790
-rwxr-xr-xchromium/third_party/libjingle/source/talk/libjingle_examples.gyp85
-rw-r--r--chromium/third_party/libjingle/source/talk/libjingle_media_unittest.isolate4
-rw-r--r--chromium/third_party/libjingle/source/talk/libjingle_p2p_unittest.isolate4
-rw-r--r--chromium/third_party/libjingle/source/talk/libjingle_peerconnection_unittest.isolate4
-rw-r--r--chromium/third_party/libjingle/source/talk/libjingle_sound_unittest.isolate4
-rwxr-xr-xchromium/third_party/libjingle/source/talk/libjingle_tests.gyp115
-rw-r--r--chromium/third_party/libjingle/source/talk/libjingle_unittest.isolate4
-rw-r--r--chromium/third_party/libjingle/source/talk/main.scons889
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/audiorenderer.h30
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/codec.cc50
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/codec.h22
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/codec_unittest.cc135
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/constants.cc20
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/constants.h22
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/fakemediaengine.h93
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/fakevideorenderer.h28
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/filemediaengine.cc2
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/filemediaengine.h11
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine.cc14
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine.h5
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine_unittest.cc486
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/mediachannel.h217
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/mediaengine.cc50
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/mediaengine.h23
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/rtpdataengine.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/rtpdataengine.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/rtpdataengine_unittest.cc11
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/rtpdump.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/testutils.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/videoadapter.cc162
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/videoadapter.h76
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/videocapturer.cc100
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/videocapturer.h74
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/videocapturer_unittest.cc82
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/videocommon.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/videocommon.h13
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/videocommon_unittest.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/videoengine_unittest.h307
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/videoframe.cc2
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/yuvframegenerator.cc262
-rw-r--r--chromium/third_party/libjingle/source/talk/media/base/yuvframegenerator.h78
-rw-r--r--chromium/third_party/libjingle/source/talk/media/devices/devicemanager.cc66
-rw-r--r--chromium/third_party/libjingle/source/talk/media/devices/devicemanager.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/media/devices/filevideocapturer.cc6
-rw-r--r--chromium/third_party/libjingle/source/talk/media/devices/linuxdevicemanager.cc15
-rw-r--r--chromium/third_party/libjingle/source/talk/media/devices/macdevicemanager.cc1
-rw-r--r--chromium/third_party/libjingle/source/talk/media/devices/macdevicemanagermm.mm53
-rw-r--r--chromium/third_party/libjingle/source/talk/media/devices/v4llookup.cc7
-rw-r--r--chromium/third_party/libjingle/source/talk/media/devices/yuvframescapturer.cc173
-rw-r--r--chromium/third_party/libjingle/source/talk/media/devices/yuvframescapturer.h71
-rw-r--r--chromium/third_party/libjingle/source/talk/media/other/linphonemediaengine.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine.cc435
-rw-r--r--chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine.h36
-rw-r--r--chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine_unittest.cc260
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/OWNERS3
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvideocapturemodule.h37
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvideoengine.h173
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvoiceengine.h221
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcmediaengine.cc (renamed from chromium/third_party/libjingle/source/talk/examples/chat/textchatreceivetask.cc)64
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcmediaengine.h23
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideocapturer.cc30
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideocapturer.h4
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideochannelfactory.h44
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.cc1226
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.h52
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2.cc1778
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2.h367
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2_unittest.cc1367
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2_unittest.h157
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine_unittest.cc1416
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.cc29
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.h1
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine.cc707
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine.h36
-rw-r--r--chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine_unittest.cc622
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket.cc5
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket_unittest.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/candidate.h33
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/constants.cc5
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/constants.h4
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/dtlstransport.h78
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel.cc48
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel.h9
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel_unittest.cc51
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/fakesession.h18
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc77
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h5
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel_unittest.cc168
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/port.cc104
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/port.h41
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/port_unittest.cc298
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/portallocator.h1
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/portinterface.h5
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/portproxy.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/portproxy.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc24
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.h6
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/relayport.cc54
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/relayport.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/relayport_unittest.cc9
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/relayserver.cc11
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/relayserver_unittest.cc16
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/session.cc82
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/session.h43
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/session_unittest.cc34
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/stun.cc9
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/stun_unittest.cc99
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/stunport.cc29
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/stunport.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/stunport_unittest.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/stunrequest_unittest.cc8
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/stunserver.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/stunserver_unittest.cc2
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/tcpport.cc42
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/tcpport.h4
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/transport.cc206
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/transport.h32
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/transport_unittest.cc69
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/transportchannel.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/transportchannelimpl.h6
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc5
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h2
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/turnport.cc151
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/turnport.h51
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/turnport_unittest.cc113
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/base/turnserver.cc9
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/client/basicportallocator.cc201
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/client/basicportallocator.h10
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/client/connectivitychecker.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/client/connectivitychecker_unittest.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/client/httpportallocator.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/p2p/client/portallocator_unittest.cc198
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/audiomonitor.cc2
-rwxr-xr-x[-rw-r--r--]chromium/third_party/libjingle/source/talk/session/media/bundlefilter.cc (renamed from chromium/third_party/libjingle/source/talk/session/media/ssrcmuxfilter.cc)77
-rwxr-xr-x[-rw-r--r--]chromium/third_party/libjingle/source/talk/session/media/bundlefilter.h (renamed from chromium/third_party/libjingle/source/talk/session/media/ssrcmuxfilter.h)35
-rwxr-xr-x[-rw-r--r--]chromium/third_party/libjingle/source/talk/session/media/bundlefilter_unittest.cc (renamed from chromium/third_party/libjingle/source/talk/session/media/ssrcmuxfilter_unittest.cc)148
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/call.cc53
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/call.h26
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/channel.cc1114
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/channel.h136
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/channel_unittest.cc321
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/channelmanager.cc38
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/channelmanager.h11
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/channelmanager_unittest.cc23
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor.cc43
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor.h39
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor_unittest.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/externalhmac.cc173
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/externalhmac.h90
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/mediamessages.cc7
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/mediasession.cc101
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/mediasession.h34
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/mediasession_unittest.cc104
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/mediasessionclient.cc10
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/mediasessionclient_unittest.cc6
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/planarfunctions_unittest.cc1010
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/srtpfilter.cc94
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/srtpfilter.h16
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/srtpfilter_unittest.cc30
-rw-r--r--chromium/third_party/libjingle/source/talk/session/media/yuvscaler_unittest.cc615
-rw-r--r--chromium/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.cc16
-rw-r--r--chromium/third_party/libjingle/source/talk/site_scons/site_tools/talk_linux.py313
-rw-r--r--chromium/third_party/libjingle/source/talk/site_scons/site_tools/talk_noops.py20
-rw-r--r--chromium/third_party/libjingle/source/talk/site_scons/talk.py635
-rw-r--r--chromium/third_party/libjingle/source/talk/xmllite/xmlparser.cc5
-rw-r--r--chromium/third_party/libjingle/source/talk/xmllite/xmlparser.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/chatroommoduleimpl.cc9
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/constants.cc7
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/constants.h5
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient.cc247
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient.h25
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient_unittest.cc6
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/pubsubclient.cc9
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/pubsubclient.h3
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/pubsubstateclient.cc42
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/pubsubstateclient.h287
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/pubsubtasks.cc9
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/pubsubtasks.h1
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/rostermoduleimpl.cc4
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/xmppengineimpl.cc3
-rw-r--r--chromium/third_party/libjingle/source/talk/xmpp/xmppengineimpl.h2
488 files changed, 28815 insertions, 14317 deletions
diff --git a/chromium/third_party/libjingle/source/talk/OWNERS b/chromium/third_party/libjingle/source/talk/OWNERS
index ddb55cf3daa..570953a6872 100644
--- a/chromium/third_party/libjingle/source/talk/OWNERS
+++ b/chromium/third_party/libjingle/source/talk/OWNERS
@@ -5,8 +5,14 @@ hta@webrtc.org
juberti@webrtc.org
mallinath@webrtc.org
perkj@webrtc.org
+pthatcher@webrtc.org
sergeyu@chromium.org
tommi@webrtc.org
wu@webrtc.org
per-file *.isolate=kjellander@webrtc.org
+
+# These are for the common case of adding or renaming files. If you're doing
+# structural changes, please get a review from a reviewer in this file.
+per-file *.gyp=*
+per-file *.gypi=*
diff --git a/chromium/third_party/libjingle/source/talk/PRESUBMIT.py b/chromium/third_party/libjingle/source/talk/PRESUBMIT.py
index 4118e107234..8e1a2e3945e 100644
--- a/chromium/third_party/libjingle/source/talk/PRESUBMIT.py
+++ b/chromium/third_party/libjingle/source/talk/PRESUBMIT.py
@@ -25,16 +25,7 @@
# List of files that should not be committed to
DO_NOT_SUBMIT_FILES = [
- "talk/app/webrtc/mediaconstraintsinterface.h",
- "talk/app/webrtc/webrtcsdp_unittest.cc",
- "talk/base/linux.cc",
- "talk/base/linux.h",
- "talk/base/linux_unittest.cc",
- "talk/main.scons",
- "talk/media/base/hybridvideoengine.cc",
- "talk/media/base/mediaengine.cc",
"talk/media/base/mutedvideocapturer.cc",
- "talk/media/base/streamparams.h",
"talk/media/base/videocapturer.cc",
"talk/media/base/videocapturer.h",
"talk/media/base/videocapturer_unittest.cc",
@@ -50,9 +41,7 @@ DO_NOT_SUBMIT_FILES = [
"talk/media/webrtc/webrtcvoiceengine.cc",
"talk/media/webrtc/webrtcvoiceengine.h",
"talk/media/webrtc/webrtcvoiceengine_unittest.cc",
- "talk/p2p/base/session.cc",
- "talk/session/media/channel.cc",
- "talk/session/media/mediasession_unittest.cc"]
+ "talk/session/media/channel.cc"]
def _LicenseHeader(input_api):
"""Returns the license header regexp."""
@@ -60,6 +49,7 @@ def _LicenseHeader(input_api):
current_year = int(input_api.time.strftime('%Y'))
allowed_years = (str(s) for s in reversed(xrange(2004, current_year + 1)))
years_re = '(' + '|'.join(allowed_years) + ')'
+ years_re = '%s(--%s)?' % (years_re, years_re)
license_header = (
r'.*? libjingle\n'
r'.*? Copyright %(year)s,? Google Inc\.\n'
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/OWNERS b/chromium/third_party/libjingle/source/talk/app/webrtc/OWNERS
index 40c5bdc1408..967930cf41c 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/OWNERS
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/OWNERS
@@ -1,6 +1,7 @@
+glaznev@webrtc.org
hellner@google.com
juberti@google.com
mallinath@google.com
perkj@google.com
ronghuawu@google.com
-tommi@google.com \ No newline at end of file
+tommi@google.com
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/audiotrack.h b/chromium/third_party/libjingle/source/talk/app/webrtc/audiotrack.h
index fc09d2b9ef1..2f96527f64a 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/audiotrack.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/audiotrack.h
@@ -41,17 +41,22 @@ class AudioTrack : public MediaStreamTrack<AudioTrackInterface> {
static talk_base::scoped_refptr<AudioTrack> Create(
const std::string& id, AudioSourceInterface* source);
- virtual AudioSourceInterface* GetSource() const {
+ // AudioTrackInterface implementation.
+ virtual AudioSourceInterface* GetSource() const OVERRIDE {
return audio_source_.get();
}
-
- // This method is used for supporting multiple sources/sinks for AudioTracks.
- virtual cricket::AudioRenderer* GetRenderer() {
+ // TODO(xians): Implement these methods.
+ virtual void AddSink(AudioTrackSinkInterface* sink) OVERRIDE {}
+ virtual void RemoveSink(AudioTrackSinkInterface* sink) OVERRIDE {}
+ virtual bool GetSignalLevel(int* level) OVERRIDE { return false; }
+ virtual talk_base::scoped_refptr<AudioProcessorInterface> GetAudioProcessor()
+ OVERRIDE { return NULL; }
+ virtual cricket::AudioRenderer* GetRenderer() OVERRIDE {
return NULL;
}
- // Implement MediaStreamTrack
- virtual std::string kind() const;
+ // MediaStreamTrack implementation.
+ virtual std::string kind() const OVERRIDE;
protected:
AudioTrack(const std::string& label, AudioSourceInterface* audio_source);
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel.cc
index 6c9e0bc43ff..14caa416b48 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel.cc
@@ -29,9 +29,9 @@
#include <string>
#include "talk/app/webrtc/mediastreamprovider.h"
+#include "talk/app/webrtc/sctputils.h"
#include "talk/base/logging.h"
#include "talk/base/refcount.h"
-#include "talk/media/sctp/sctputils.h"
namespace webrtc {
@@ -46,7 +46,7 @@ talk_base::scoped_refptr<DataChannel> DataChannel::Create(
DataChannelProviderInterface* provider,
cricket::DataChannelType dct,
const std::string& label,
- const DataChannelInit* config) {
+ const InternalDataChannelInit& config) {
talk_base::scoped_refptr<DataChannel> channel(
new talk_base::RefCountedObject<DataChannel>(provider, dct, label));
if (!channel->Init(config)) {
@@ -62,39 +62,40 @@ DataChannel::DataChannel(
: label_(label),
observer_(NULL),
state_(kConnecting),
- was_ever_writable_(false),
- connected_to_provider_(false),
data_channel_type_(dct),
provider_(provider),
+ waiting_for_open_ack_(false),
+ was_ever_writable_(false),
+ connected_to_provider_(false),
send_ssrc_set_(false),
- send_ssrc_(0),
receive_ssrc_set_(false),
+ send_ssrc_(0),
receive_ssrc_(0) {
}
-bool DataChannel::Init(const DataChannelInit* config) {
+bool DataChannel::Init(const InternalDataChannelInit& config) {
if (data_channel_type_ == cricket::DCT_RTP &&
- (config->reliable ||
- config->id != -1 ||
- config->maxRetransmits != -1 ||
- config->maxRetransmitTime != -1)) {
+ (config.reliable ||
+ config.id != -1 ||
+ config.maxRetransmits != -1 ||
+ config.maxRetransmitTime != -1)) {
LOG(LS_ERROR) << "Failed to initialize the RTP data channel due to "
<< "invalid DataChannelInit.";
return false;
} else if (data_channel_type_ == cricket::DCT_SCTP) {
- if (config->id < -1 ||
- config->maxRetransmits < -1 ||
- config->maxRetransmitTime < -1) {
+ if (config.id < -1 ||
+ config.maxRetransmits < -1 ||
+ config.maxRetransmitTime < -1) {
LOG(LS_ERROR) << "Failed to initialize the SCTP data channel due to "
<< "invalid DataChannelInit.";
return false;
}
- if (config->maxRetransmits != -1 && config->maxRetransmitTime != -1) {
+ if (config.maxRetransmits != -1 && config.maxRetransmitTime != -1) {
LOG(LS_ERROR) <<
"maxRetransmits and maxRetransmitTime should not be both set.";
return false;
}
- config_ = *config;
+ config_ = config;
// Try to connect to the transport in case the transport channel already
// exists.
@@ -163,17 +164,23 @@ bool DataChannel::Send(const DataBuffer& buffer) {
// If the queue is non-empty, we're waiting for SignalReadyToSend,
// so just add to the end of the queue and keep waiting.
if (!queued_send_data_.empty()) {
- return QueueSendData(buffer);
+ if (!QueueSendData(buffer)) {
+ if (data_channel_type_ == cricket::DCT_RTP) {
+ return false;
+ }
+ Close();
+ }
+ return true;
}
cricket::SendDataResult send_result;
if (!InternalSendWithoutQueueing(buffer, &send_result)) {
- if (send_result == cricket::SDR_BLOCK) {
- return QueueSendData(buffer);
+ if (data_channel_type_ == cricket::DCT_RTP) {
+ return false;
+ }
+ if (send_result != cricket::SDR_BLOCK || !QueueSendData(buffer)) {
+ Close();
}
- // Fail for other results.
- // TODO(jiayl): We should close the data channel in this case.
- return false;
}
return true;
}
@@ -197,9 +204,44 @@ bool DataChannel::SendOpenMessage(const talk_base::Buffer* raw_buffer) {
cricket::SendDataResult send_result;
bool retval = provider_->SendData(send_params, *buffer, &send_result);
- if (!retval && send_result == cricket::SDR_BLOCK) {
+ if (retval) {
+ LOG(LS_INFO) << "Sent OPEN message on channel " << config_.id;
+ // Send data as ordered before we receive any mesage from the remote peer
+ // to make sure the remote peer will not receive any data before it receives
+ // the OPEN message.
+ waiting_for_open_ack_ = true;
+ } else if (send_result == cricket::SDR_BLOCK) {
// Link is congested. Queue for later.
QueueControl(buffer.release());
+ } else {
+ LOG(LS_ERROR) << "Failed to send OPEN message with result "
+ << send_result << " on channel " << config_.id;
+ }
+ return retval;
+}
+
+bool DataChannel::SendOpenAckMessage(const talk_base::Buffer* raw_buffer) {
+ ASSERT(data_channel_type_ == cricket::DCT_SCTP &&
+ was_ever_writable_ &&
+ config_.id >= 0);
+
+ talk_base::scoped_ptr<const talk_base::Buffer> buffer(raw_buffer);
+
+ cricket::SendDataParams send_params;
+ send_params.ssrc = config_.id;
+ send_params.ordered = config_.ordered;
+ send_params.type = cricket::DMT_CONTROL;
+
+ cricket::SendDataResult send_result;
+ bool retval = provider_->SendData(send_params, *buffer, &send_result);
+ if (retval) {
+ LOG(LS_INFO) << "Sent OPEN_ACK message on channel " << config_.id;
+ } else if (send_result == cricket::SDR_BLOCK) {
+ // Link is congested. Queue for later.
+ QueueControl(buffer.release());
+ } else {
+ LOG(LS_ERROR) << "Failed to send OPEN_ACK message with result "
+ << send_result << " on channel " << config_.id;
}
return retval;
}
@@ -254,15 +296,43 @@ void DataChannel::OnDataReceived(cricket::DataChannel* channel,
return;
}
+ if (params.type == cricket::DMT_CONTROL) {
+ ASSERT(data_channel_type_ == cricket::DCT_SCTP);
+ if (!waiting_for_open_ack_) {
+ // Ignore it if we are not expecting an ACK message.
+ LOG(LS_WARNING) << "DataChannel received unexpected CONTROL message, "
+ << "sid = " << params.ssrc;
+ return;
+ }
+ if (ParseDataChannelOpenAckMessage(payload)) {
+ // We can send unordered as soon as we receive the ACK message.
+ waiting_for_open_ack_ = false;
+ LOG(LS_INFO) << "DataChannel received OPEN_ACK message, sid = "
+ << params.ssrc;
+ } else {
+ LOG(LS_WARNING) << "DataChannel failed to parse OPEN_ACK message, sid = "
+ << params.ssrc;
+ }
+ return;
+ }
+
+ ASSERT(params.type == cricket::DMT_BINARY ||
+ params.type == cricket::DMT_TEXT);
+
+ LOG(LS_VERBOSE) << "DataChannel received DATA message, sid = " << params.ssrc;
+ // We can send unordered as soon as we receive any DATA message since the
+ // remote side must have received the OPEN (and old clients do not send
+ // OPEN_ACK).
+ waiting_for_open_ack_ = false;
+
bool binary = (params.type == cricket::DMT_BINARY);
talk_base::scoped_ptr<DataBuffer> buffer(new DataBuffer(payload, binary));
if (was_ever_writable_ && observer_) {
observer_->OnMessage(*buffer.get());
} else {
if (queued_received_data_.size() > kMaxQueuedReceivedDataPackets) {
- // TODO(jiayl): We should close the data channel in this case.
LOG(LS_ERROR)
- << "Queued received data exceeds the max number of packes.";
+ << "Queued received data exceeds the max number of packets.";
ClearQueuedReceivedData();
}
queued_received_data_.push(buffer.release());
@@ -279,14 +349,17 @@ void DataChannel::OnChannelReady(bool writable) {
if (!was_ever_writable_) {
was_ever_writable_ = true;
- if (data_channel_type_ == cricket::DCT_SCTP && !config_.negotiated) {
- talk_base::Buffer* payload = new talk_base::Buffer;
- if (!cricket::WriteDataChannelOpenMessage(label_, config_, payload)) {
- // TODO(jiayl): close the data channel on this error.
- LOG(LS_ERROR) << "Could not write data channel OPEN message";
- return;
+ if (data_channel_type_ == cricket::DCT_SCTP) {
+ if (config_.open_handshake_role == InternalDataChannelInit::kOpener) {
+ talk_base::Buffer* payload = new talk_base::Buffer;
+ WriteDataChannelOpenMessage(label_, config_, payload);
+ SendOpenMessage(payload);
+ } else if (config_.open_handshake_role ==
+ InternalDataChannelInit::kAcker) {
+ talk_base::Buffer* payload = new talk_base::Buffer;
+ WriteDataChannelOpenAckMessage(payload);
+ SendOpenAckMessage(payload);
}
- SendOpenMessage(payload);
}
UpdateState();
@@ -297,6 +370,9 @@ void DataChannel::OnChannelReady(bool writable) {
}
void DataChannel::DoClose() {
+ if (state_ == kClosed)
+ return;
+
receive_ssrc_set_ = false;
send_ssrc_set_ = false;
SetState(kClosing);
@@ -339,6 +415,9 @@ void DataChannel::UpdateState() {
}
void DataChannel::SetState(DataState state) {
+ if (state_ == state)
+ return;
+
state_ = state;
if (observer_) {
observer_->OnStateChange();
@@ -412,7 +491,12 @@ void DataChannel::DeliverQueuedControlData() {
while (!queued_control_data_.empty()) {
const talk_base::Buffer* buf = queued_control_data_.front();
queued_control_data_.pop();
- SendOpenMessage(buf);
+ if (config_.open_handshake_role == InternalDataChannelInit::kOpener) {
+ SendOpenMessage(buf);
+ } else {
+ ASSERT(config_.open_handshake_role == InternalDataChannelInit::kAcker);
+ SendOpenAckMessage(buf);
+ }
}
}
@@ -430,6 +514,13 @@ bool DataChannel::InternalSendWithoutQueueing(
if (data_channel_type_ == cricket::DCT_SCTP) {
send_params.ordered = config_.ordered;
+ // Send as ordered if it is waiting for the OPEN_ACK message.
+ if (waiting_for_open_ack_ && !config_.ordered) {
+ send_params.ordered = true;
+ LOG(LS_VERBOSE) << "Sending data as ordered for unordered DataChannel "
+ << "because the OPEN_ACK message has not been received.";
+ }
+
send_params.max_rtx_count = config_.maxRetransmits;
send_params.max_rtx_ms = config_.maxRetransmitTime;
send_params.ssrc = config_.id;
@@ -442,8 +533,8 @@ bool DataChannel::InternalSendWithoutQueueing(
}
bool DataChannel::QueueSendData(const DataBuffer& buffer) {
- if (queued_send_data_.size() > kMaxQueuedSendDataPackets) {
- LOG(LS_ERROR) << "Can't buffer any more data in the data channel.";
+ if (queued_send_data_.size() >= kMaxQueuedSendDataPackets) {
+ LOG(LS_ERROR) << "Can't buffer any more data for the data channel.";
return false;
}
queued_send_data_.push_back(new DataBuffer(buffer));
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel.h b/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel.h
index bf31aed5d53..9256e0e071f 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel.h
@@ -64,6 +64,25 @@ class DataChannelProviderInterface {
virtual ~DataChannelProviderInterface() {}
};
+struct InternalDataChannelInit : public DataChannelInit {
+ enum OpenHandshakeRole {
+ kOpener,
+ kAcker,
+ kNone
+ };
+ // The default role is kOpener because the default |negotiated| is false.
+ InternalDataChannelInit() : open_handshake_role(kOpener) {}
+ explicit InternalDataChannelInit(const DataChannelInit& base)
+ : DataChannelInit(base), open_handshake_role(kOpener) {
+ // If the channel is externally negotiated, do not send the OPEN message.
+ if (base.negotiated) {
+ open_handshake_role = kNone;
+ }
+ }
+
+ OpenHandshakeRole open_handshake_role;
+};
+
// DataChannel is a an implementation of the DataChannelInterface based on
// libjingle's data engine. It provides an implementation of unreliable or
// reliabledata channels. Currently this class is specifically designed to use
@@ -87,7 +106,7 @@ class DataChannel : public DataChannelInterface,
DataChannelProviderInterface* provider,
cricket::DataChannelType dct,
const std::string& label,
- const DataChannelInit* config);
+ const InternalDataChannelInit& config);
virtual void RegisterObserver(DataChannelObserver* observer);
virtual void UnregisterObserver();
@@ -156,7 +175,7 @@ class DataChannel : public DataChannelInterface,
virtual ~DataChannel();
private:
- bool Init(const DataChannelInit* config);
+ bool Init(const InternalDataChannelInit& config);
void DoClose();
void UpdateState();
void SetState(DataState state);
@@ -172,19 +191,20 @@ class DataChannel : public DataChannelInterface,
cricket::SendDataResult* send_result);
bool QueueSendData(const DataBuffer& buffer);
bool SendOpenMessage(const talk_base::Buffer* buffer);
-
+ bool SendOpenAckMessage(const talk_base::Buffer* buffer);
std::string label_;
- DataChannelInit config_;
+ InternalDataChannelInit config_;
DataChannelObserver* observer_;
DataState state_;
- bool was_ever_writable_;
- bool connected_to_provider_;
cricket::DataChannelType data_channel_type_;
DataChannelProviderInterface* provider_;
+ bool waiting_for_open_ack_;
+ bool was_ever_writable_;
+ bool connected_to_provider_;
bool send_ssrc_set_;
- uint32 send_ssrc_;
bool receive_ssrc_set_;
+ uint32 send_ssrc_;
uint32 receive_ssrc_;
// Control messages that always have to get sent out before any queued
// data.
@@ -197,7 +217,7 @@ class DataChannelFactory {
public:
virtual talk_base::scoped_refptr<DataChannel> CreateDataChannel(
const std::string& label,
- const DataChannelInit* config) = 0;
+ const InternalDataChannelInit* config) = 0;
protected:
virtual ~DataChannelFactory() {}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel_unittest.cc
index fdcd2f2cd11..991ae0cae7a 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/datachannel_unittest.cc
@@ -26,23 +26,48 @@
*/
#include "talk/app/webrtc/datachannel.h"
+#include "talk/app/webrtc/sctputils.h"
#include "talk/app/webrtc/test/fakedatachannelprovider.h"
#include "talk/base/gunit.h"
-#include "testing/base/public/gmock.h"
using webrtc::DataChannel;
class FakeDataChannelObserver : public webrtc::DataChannelObserver {
public:
- MOCK_METHOD0(OnStateChange, void());
- MOCK_METHOD1(OnMessage, void(const webrtc::DataBuffer& buffer));
+ FakeDataChannelObserver()
+ : messages_received_(0), on_state_change_count_(0) {}
+
+ void OnStateChange() {
+ ++on_state_change_count_;
+ }
+
+ void OnMessage(const webrtc::DataBuffer& buffer) {
+ ++messages_received_;
+ }
+
+ size_t messages_received() const {
+ return messages_received_;
+ }
+
+ void ResetOnStateChangeCount() {
+ on_state_change_count_ = 0;
+ }
+
+ size_t on_state_change_count() const {
+ return on_state_change_count_;
+ }
+
+ private:
+ size_t messages_received_;
+ size_t on_state_change_count_;
};
class SctpDataChannelTest : public testing::Test {
protected:
SctpDataChannelTest()
: webrtc_data_channel_(
- DataChannel::Create(&provider_, cricket::DCT_SCTP, "test", &init_)) {
+ DataChannel::Create(
+ &provider_, cricket::DCT_SCTP, "test", init_)) {
}
void SetChannelReady() {
@@ -59,7 +84,7 @@ class SctpDataChannelTest : public testing::Test {
webrtc_data_channel_->RegisterObserver(observer_.get());
}
- webrtc::DataChannelInit init_;
+ webrtc::InternalDataChannelInit init_;
FakeDataChannelProvider provider_;
talk_base::scoped_ptr<FakeDataChannelObserver> observer_;
talk_base::scoped_refptr<DataChannel> webrtc_data_channel_;
@@ -69,7 +94,7 @@ class SctpDataChannelTest : public testing::Test {
TEST_F(SctpDataChannelTest, ConnectedToTransportOnCreated) {
provider_.set_transport_available(true);
talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
- &provider_, cricket::DCT_SCTP, "test1", &init_);
+ &provider_, cricket::DCT_SCTP, "test1", init_);
EXPECT_TRUE(provider_.IsConnected(dc.get()));
// The sid is not set yet, so it should not have added the streams.
@@ -153,15 +178,69 @@ TEST_F(SctpDataChannelTest, OpenMessageSent) {
// state.
TEST_F(SctpDataChannelTest, LateCreatedChannelTransitionToOpen) {
SetChannelReady();
- webrtc::DataChannelInit init;
+ webrtc::InternalDataChannelInit init;
init.id = 1;
- talk_base::scoped_refptr<DataChannel> dc =
- DataChannel::Create(&provider_, cricket::DCT_SCTP, "test1", &init);
+ talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
+ &provider_, cricket::DCT_SCTP, "test1", init);
EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, dc->state());
EXPECT_TRUE_WAIT(webrtc::DataChannelInterface::kOpen == dc->state(),
1000);
}
+// Tests that an unordered DataChannel sends data as ordered until the OPEN_ACK
+// message is received.
+TEST_F(SctpDataChannelTest, SendUnorderedAfterReceivesOpenAck) {
+ SetChannelReady();
+ webrtc::InternalDataChannelInit init;
+ init.id = 1;
+ init.ordered = false;
+ talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
+ &provider_, cricket::DCT_SCTP, "test1", init);
+
+ EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
+
+ // Sends a message and verifies it's ordered.
+ webrtc::DataBuffer buffer("some data");
+ ASSERT_TRUE(dc->Send(buffer));
+ EXPECT_TRUE(provider_.last_send_data_params().ordered);
+
+ // Emulates receiving an OPEN_ACK message.
+ cricket::ReceiveDataParams params;
+ params.ssrc = init.id;
+ params.type = cricket::DMT_CONTROL;
+ talk_base::Buffer payload;
+ webrtc::WriteDataChannelOpenAckMessage(&payload);
+ dc->OnDataReceived(NULL, params, payload);
+
+ // Sends another message and verifies it's unordered.
+ ASSERT_TRUE(dc->Send(buffer));
+ EXPECT_FALSE(provider_.last_send_data_params().ordered);
+}
+
+// Tests that an unordered DataChannel sends unordered data after any DATA
+// message is received.
+TEST_F(SctpDataChannelTest, SendUnorderedAfterReceiveData) {
+ SetChannelReady();
+ webrtc::InternalDataChannelInit init;
+ init.id = 1;
+ init.ordered = false;
+ talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
+ &provider_, cricket::DCT_SCTP, "test1", init);
+
+ EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
+
+ // Emulates receiving a DATA message.
+ cricket::ReceiveDataParams params;
+ params.ssrc = init.id;
+ params.type = cricket::DMT_TEXT;
+ webrtc::DataBuffer buffer("data");
+ dc->OnDataReceived(NULL, params, buffer.data);
+
+ // Sends a message and verifies it's unordered.
+ ASSERT_TRUE(dc->Send(buffer));
+ EXPECT_FALSE(provider_.last_send_data_params().ordered);
+}
+
// Tests that messages are sent with the right ssrc.
TEST_F(SctpDataChannelTest, SendDataSsrc) {
webrtc_data_channel_->SetSctpSid(1);
@@ -177,12 +256,13 @@ TEST_F(SctpDataChannelTest, ReceiveDataWithInvalidSsrc) {
SetChannelReady();
AddObserver();
- EXPECT_CALL(*(observer_.get()), OnMessage(testing::_)).Times(0);
cricket::ReceiveDataParams params;
params.ssrc = 0;
webrtc::DataBuffer buffer("abcd");
webrtc_data_channel_->OnDataReceived(NULL, params, buffer.data);
+
+ EXPECT_EQ(0U, observer_->messages_received());
}
// Tests that the incoming messages with right ssrcs are acceted.
@@ -191,11 +271,108 @@ TEST_F(SctpDataChannelTest, ReceiveDataWithValidSsrc) {
SetChannelReady();
AddObserver();
- EXPECT_CALL(*(observer_.get()), OnMessage(testing::_)).Times(1);
cricket::ReceiveDataParams params;
params.ssrc = 1;
webrtc::DataBuffer buffer("abcd");
webrtc_data_channel_->OnDataReceived(NULL, params, buffer.data);
+ EXPECT_EQ(1U, observer_->messages_received());
+}
+
+// Tests that no CONTROL message is sent if the datachannel is negotiated and
+// not created from an OPEN message.
+TEST_F(SctpDataChannelTest, NoMsgSentIfNegotiatedAndNotFromOpenMsg) {
+ webrtc::InternalDataChannelInit config;
+ config.id = 1;
+ config.negotiated = true;
+ config.open_handshake_role = webrtc::InternalDataChannelInit::kNone;
+
+ SetChannelReady();
+ talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
+ &provider_, cricket::DCT_SCTP, "test1", config);
+
+ EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
+ EXPECT_EQ(0U, provider_.last_send_data_params().ssrc);
+}
+
+// Tests that OPEN_ACK message is sent if the datachannel is created from an
+// OPEN message.
+TEST_F(SctpDataChannelTest, OpenAckSentIfCreatedFromOpenMessage) {
+ webrtc::InternalDataChannelInit config;
+ config.id = 1;
+ config.negotiated = true;
+ config.open_handshake_role = webrtc::InternalDataChannelInit::kAcker;
+
+ SetChannelReady();
+ talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
+ &provider_, cricket::DCT_SCTP, "test1", config);
+
+ EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
+
+ EXPECT_EQ(static_cast<unsigned int>(config.id),
+ provider_.last_send_data_params().ssrc);
+ EXPECT_EQ(cricket::DMT_CONTROL, provider_.last_send_data_params().type);
}
+
+// Tests the OPEN_ACK role assigned by InternalDataChannelInit.
+TEST_F(SctpDataChannelTest, OpenAckRoleInitialization) {
+ webrtc::InternalDataChannelInit init;
+ EXPECT_EQ(webrtc::InternalDataChannelInit::kOpener, init.open_handshake_role);
+ EXPECT_FALSE(init.negotiated);
+
+ webrtc::DataChannelInit base;
+ base.negotiated = true;
+ webrtc::InternalDataChannelInit init2(base);
+ EXPECT_EQ(webrtc::InternalDataChannelInit::kNone, init2.open_handshake_role);
+}
+
+// Tests that the DataChannel is closed if the sending buffer is full.
+TEST_F(SctpDataChannelTest, ClosedWhenSendBufferFull) {
+ SetChannelReady();
+ webrtc::DataBuffer buffer("abcd");
+ provider_.set_send_blocked(true);
+
+ for (size_t i = 0; i < 101; ++i) {
+ EXPECT_TRUE(webrtc_data_channel_->Send(buffer));
+ }
+
+ EXPECT_EQ(webrtc::DataChannelInterface::kClosed,
+ webrtc_data_channel_->state());
+}
+
+// Tests that the DataChannel is closed on transport errors.
+TEST_F(SctpDataChannelTest, ClosedOnTransportError) {
+ SetChannelReady();
+ webrtc::DataBuffer buffer("abcd");
+ provider_.set_transport_error();
+
+ EXPECT_TRUE(webrtc_data_channel_->Send(buffer));
+
+ EXPECT_EQ(webrtc::DataChannelInterface::kClosed,
+ webrtc_data_channel_->state());
+}
+
+// Tests that a already closed DataChannel does not fire onStateChange again.
+TEST_F(SctpDataChannelTest, ClosedDataChannelDoesNotFireOnStateChange) {
+ AddObserver();
+ webrtc_data_channel_->Close();
+ // OnStateChange called for kClosing and kClosed.
+ EXPECT_EQ(2U, observer_->on_state_change_count());
+
+ observer_->ResetOnStateChangeCount();
+ webrtc_data_channel_->RemotePeerRequestClose();
+ EXPECT_EQ(0U, observer_->on_state_change_count());
+}
+
+// Tests that RemotePeerRequestClose closes the local DataChannel.
+TEST_F(SctpDataChannelTest, RemotePeerRequestClose) {
+ AddObserver();
+ webrtc_data_channel_->RemotePeerRequestClose();
+
+ // OnStateChange called for kClosing and kClosed.
+ EXPECT_EQ(2U, observer_->on_state_change_count());
+ EXPECT_EQ(webrtc::DataChannelInterface::kClosed,
+ webrtc_data_channel_->state());
+}
+
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/datachannelinterface.h b/chromium/third_party/libjingle/source/talk/app/webrtc/datachannelinterface.h
index 7be8a50f5d4..57fe200cfe6 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/datachannelinterface.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/datachannelinterface.h
@@ -97,7 +97,9 @@ class DataChannelObserver {
class DataChannelInterface : public talk_base::RefCountInterface {
public:
- enum DataState { // Keep in sync with DataChannel.java:State.
+ // Keep in sync with DataChannel.java:State and
+ // RTCDataChannel.h:RTCDataChannelState.
+ enum DataState {
kConnecting,
kOpen, // The DataChannel is ready to send data.
kClosing,
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/jsepsessiondescription.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/jsepsessiondescription.cc
index 8ec145808aa..d7b37b5d761 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/jsepsessiondescription.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/jsepsessiondescription.cc
@@ -118,9 +118,6 @@ bool JsepSessionDescription::AddCandidate(
}
if (mediasection_index >= number_of_mediasections())
return false;
- if (candidate_collection_[mediasection_index].HasCandidate(candidate)) {
- return true; // Silently ignore this candidate if we already have it.
- }
const std::string content_name =
description_->contents()[mediasection_index].name;
const cricket::TransportInfo* transport_info =
@@ -137,10 +134,15 @@ bool JsepSessionDescription::AddCandidate(
updated_candidate.set_password(transport_info->description.ice_pwd);
}
- candidate_collection_[mediasection_index].add(
- new JsepIceCandidate(candidate->sdp_mid(),
- static_cast<int>(mediasection_index),
- updated_candidate));
+ scoped_ptr<JsepIceCandidate> updated_candidate_wrapper(
+ new JsepIceCandidate(candidate->sdp_mid(),
+ static_cast<int>(mediasection_index),
+ updated_candidate));
+ if (!candidate_collection_[mediasection_index].HasCandidate(
+ updated_candidate_wrapper.get()))
+ candidate_collection_[mediasection_index].add(
+ updated_candidate_wrapper.release());
+
return true;
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/jsepsessiondescription_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/jsepsessiondescription_unittest.cc
index e2b59fba205..55eb3d53925 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/jsepsessiondescription_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/jsepsessiondescription_unittest.cc
@@ -32,6 +32,7 @@
#include "talk/base/gunit.h"
#include "talk/base/helpers.h"
#include "talk/base/scoped_ptr.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/stringencode.h"
#include "talk/p2p/base/candidate.h"
#include "talk/p2p/base/constants.h"
@@ -96,6 +97,14 @@ static cricket::SessionDescription* CreateCricketSessionDescription() {
class JsepSessionDescriptionTest : public testing::Test {
protected:
+ static void SetUpTestCase() {
+ talk_base::InitializeSSL();
+ }
+
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
+ }
+
virtual void SetUp() {
int port = 1234;
talk_base::SocketAddress address("127.0.0.1", port++);
@@ -195,6 +204,28 @@ TEST_F(JsepSessionDescriptionTest, AddBadCandidate) {
EXPECT_FALSE(jsep_desc_->AddCandidate(&bad_candidate2));
}
+// Tests that repeatedly adding the same candidate, with or without credentials,
+// does not increase the number of candidates in the description.
+TEST_F(JsepSessionDescriptionTest, AddCandidateDuplicates) {
+ JsepIceCandidate jsep_candidate("", 0, candidate_);
+ EXPECT_TRUE(jsep_desc_->AddCandidate(&jsep_candidate));
+ EXPECT_EQ(1u, jsep_desc_->candidates(0)->count());
+
+ // Add the same candidate again. It should be ignored.
+ EXPECT_TRUE(jsep_desc_->AddCandidate(&jsep_candidate));
+ EXPECT_EQ(1u, jsep_desc_->candidates(0)->count());
+
+ // Create a new candidate, identical except that the ufrag and pwd are now
+ // populated.
+ candidate_.set_username(kCandidateUfragVoice);
+ candidate_.set_password(kCandidatePwdVoice);
+ JsepIceCandidate jsep_candidate_with_credentials("", 0, candidate_);
+
+ // This should also be identified as redundant and ignored.
+ EXPECT_TRUE(jsep_desc_->AddCandidate(&jsep_candidate_with_credentials));
+ EXPECT_EQ(1u, jsep_desc_->candidates(0)->count());
+}
+
// Test that we can serialize a JsepSessionDescription and deserialize it again.
TEST_F(JsepSessionDescriptionTest, SerializeDeserialize) {
std::string sdp = Serialize(jsep_desc_.get());
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/localaudiosource.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/localaudiosource.cc
index 2cd472a5a01..ab9ae4fa99c 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/localaudiosource.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/localaudiosource.cc
@@ -37,26 +37,6 @@ using webrtc::MediaSourceInterface;
namespace webrtc {
-// Constraint keys.
-// They are declared as static members in mediaconstraintsinterface.h
-const char MediaConstraintsInterface::kEchoCancellation[] =
- "googEchoCancellation";
-const char MediaConstraintsInterface::kExperimentalEchoCancellation[] =
- "googEchoCancellation2";
-const char MediaConstraintsInterface::kAutoGainControl[] =
- "googAutoGainControl";
-const char MediaConstraintsInterface::kExperimentalAutoGainControl[] =
- "googAutoGainControl2";
-const char MediaConstraintsInterface::kNoiseSuppression[] =
- "googNoiseSuppression";
-const char MediaConstraintsInterface::kHighpassFilter[] =
- "googHighpassFilter";
-const char MediaConstraintsInterface::kTypingNoiseDetection[] =
- "googTypingNoiseDetection";
-const char MediaConstraintsInterface::kAudioMirroring[] = "googAudioMirroring";
-// TODO(perkj): Remove kInternalAecDump once its not used by Chrome.
-const char MediaConstraintsInterface::kInternalAecDump[] = "deprecatedAecDump";
-
namespace {
// Convert constraints to audio options. Return false if constraints are
@@ -90,6 +70,9 @@ bool FromConstraints(const MediaConstraintsInterface::Constraints& constraints,
options->experimental_agc.Set(value);
else if (iter->key == MediaConstraintsInterface::kNoiseSuppression)
options->noise_suppression.Set(value);
+ else if (iter->key ==
+ MediaConstraintsInterface::kExperimentalNoiseSuppression)
+ options->experimental_ns.Set(value);
else if (iter->key == MediaConstraintsInterface::kHighpassFilter)
options->highpass_filter.Set(value);
else if (iter->key == MediaConstraintsInterface::kTypingNoiseDetection)
@@ -129,8 +112,6 @@ void LocalAudioSource::Initialize(
return;
}
options_.SetAll(audio_options);
- if (options.enable_aec_dump)
- options_.aec_dump.Set(true);
source_state_ = kLive;
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.cc
index 2e6af7728fd..0ecadd6913e 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.cc
@@ -34,6 +34,94 @@ namespace webrtc {
const char MediaConstraintsInterface::kValueTrue[] = "true";
const char MediaConstraintsInterface::kValueFalse[] = "false";
+// Constraints declared as static members in mediastreaminterface.h
+// Specified by draft-alvestrand-constraints-resolution-00b
+const char MediaConstraintsInterface::kMinAspectRatio[] = "minAspectRatio";
+const char MediaConstraintsInterface::kMaxAspectRatio[] = "maxAspectRatio";
+const char MediaConstraintsInterface::kMaxWidth[] = "maxWidth";
+const char MediaConstraintsInterface::kMinWidth[] = "minWidth";
+const char MediaConstraintsInterface::kMaxHeight[] = "maxHeight";
+const char MediaConstraintsInterface::kMinHeight[] = "minHeight";
+const char MediaConstraintsInterface::kMaxFrameRate[] = "maxFrameRate";
+const char MediaConstraintsInterface::kMinFrameRate[] = "minFrameRate";
+
+// Audio constraints.
+const char MediaConstraintsInterface::kEchoCancellation[] =
+ "googEchoCancellation";
+const char MediaConstraintsInterface::kExperimentalEchoCancellation[] =
+ "googEchoCancellation2";
+const char MediaConstraintsInterface::kAutoGainControl[] =
+ "googAutoGainControl";
+const char MediaConstraintsInterface::kExperimentalAutoGainControl[] =
+ "googAutoGainControl2";
+const char MediaConstraintsInterface::kNoiseSuppression[] =
+ "googNoiseSuppression";
+const char MediaConstraintsInterface::kExperimentalNoiseSuppression[] =
+ "googNoiseSuppression2";
+const char MediaConstraintsInterface::kHighpassFilter[] =
+ "googHighpassFilter";
+const char MediaConstraintsInterface::kTypingNoiseDetection[] =
+ "googTypingNoiseDetection";
+const char MediaConstraintsInterface::kAudioMirroring[] = "googAudioMirroring";
+
+// Google-specific constraint keys for a local video source (getUserMedia).
+const char MediaConstraintsInterface::kNoiseReduction[] = "googNoiseReduction";
+const char MediaConstraintsInterface::kLeakyBucket[] = "googLeakyBucket";
+const char MediaConstraintsInterface::kTemporalLayeredScreencast[] =
+ "googTemporalLayeredScreencast";
+
+// Constraint keys for CreateOffer / CreateAnswer defined in W3C specification.
+const char MediaConstraintsInterface::kOfferToReceiveAudio[] =
+ "OfferToReceiveAudio";
+const char MediaConstraintsInterface::kOfferToReceiveVideo[] =
+ "OfferToReceiveVideo";
+const char MediaConstraintsInterface::kVoiceActivityDetection[] =
+ "VoiceActivityDetection";
+const char MediaConstraintsInterface::kIceRestart[] =
+ "IceRestart";
+// Google specific constraint for BUNDLE enable/disable.
+const char MediaConstraintsInterface::kUseRtpMux[] =
+ "googUseRtpMUX";
+
+// Below constraints should be used during PeerConnection construction.
+const char MediaConstraintsInterface::kEnableDtlsSrtp[] =
+ "DtlsSrtpKeyAgreement";
+const char MediaConstraintsInterface::kEnableRtpDataChannels[] =
+ "RtpDataChannels";
+// Google-specific constraint keys.
+const char MediaConstraintsInterface::kEnableDscp[] = "googDscp";
+const char MediaConstraintsInterface::kEnableIPv6[] = "googIPv6";
+const char MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate[] =
+ "googSuspendBelowMinBitrate";
+const char MediaConstraintsInterface::kImprovedWifiBwe[] =
+ "googImprovedWifiBwe";
+const char MediaConstraintsInterface::kScreencastMinBitrate[] =
+ "googScreencastMinBitrate";
+const char MediaConstraintsInterface::kSkipEncodingUnusedStreams[] =
+ "googSkipEncodingUnusedStreams";
+// TODO(ronghuawu): Remove once cpu overuse detection is stable.
+const char MediaConstraintsInterface::kCpuOveruseDetection[] =
+ "googCpuOveruseDetection";
+const char MediaConstraintsInterface::kCpuUnderuseThreshold[] =
+ "googCpuUnderuseThreshold";
+const char MediaConstraintsInterface::kCpuOveruseThreshold[] =
+ "googCpuOveruseThreshold";
+const char MediaConstraintsInterface::kCpuUnderuseEncodeRsdThreshold[] =
+ "googCpuUnderuseEncodeRsdThreshold";
+const char MediaConstraintsInterface::kCpuOveruseEncodeRsdThreshold[] =
+ "googCpuOveruseEncodeRsdThreshold";
+const char MediaConstraintsInterface::kCpuOveruseEncodeUsage[] =
+ "googCpuOveruseEncodeUsage";
+const char MediaConstraintsInterface::kHighStartBitrate[] =
+ "googHighStartBitrate";
+const char MediaConstraintsInterface::kHighBitrate[] =
+ "googHighBitrate";
+const char MediaConstraintsInterface::kVeryHighBitrate[] =
+ "googVeryHighBitrate";
+const char MediaConstraintsInterface::kPayloadPadding[] = "googPayloadPadding";
+const char MediaConstraintsInterface::kOpusFec[] = "googOpusFec";
+
+
// Set |value| to the value associated with the first appearance of |key|, or
// return false if |key| is not found.
bool MediaConstraintsInterface::Constraints::FindFirst(
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h b/chromium/third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h
index ba6b09be910..36257db7157 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h
@@ -60,7 +60,6 @@ class MediaConstraintsInterface {
virtual const Constraints& GetMandatory() const = 0;
virtual const Constraints& GetOptional() const = 0;
-
// Constraint keys used by a local video source.
// Specified by draft-alvestrand-constraints-resolution-00b
static const char kMinAspectRatio[]; // minAspectRatio
@@ -79,6 +78,7 @@ class MediaConstraintsInterface {
static const char kAutoGainControl[]; // googAutoGainControl
static const char kExperimentalAutoGainControl[]; // googAutoGainControl2
static const char kNoiseSuppression[]; // googNoiseSuppression
+ static const char kExperimentalNoiseSuppression[]; // googNoiseSuppression2
static const char kHighpassFilter[]; // googHighpassFilter
static const char kTypingNoiseDetection[]; // googTypingNoiseDetection
static const char kAudioMirroring[]; // googAudioMirroring
@@ -86,9 +86,8 @@ class MediaConstraintsInterface {
// Google-specific constraint keys for a local video source
static const char kNoiseReduction[]; // googNoiseReduction
static const char kLeakyBucket[]; // googLeakyBucket
- // googTemporalLayeredScreencast
static const char kTemporalLayeredScreencast[];
- static const char kCpuOveruseDetection[];
+ // googTemporalLayeredScreencast
// Constraint keys for CreateOffer / CreateAnswer
// Specified by the W3C PeerConnection spec
@@ -103,27 +102,47 @@ class MediaConstraintsInterface {
static const char kValueTrue[]; // true
static const char kValueFalse[]; // false
+ // PeerConnection constraint keys.
// Temporary pseudo-constraints used to enable DTLS-SRTP
static const char kEnableDtlsSrtp[]; // Enable DTLS-SRTP
// Temporary pseudo-constraints used to enable DataChannels
static const char kEnableRtpDataChannels[]; // Enable RTP DataChannels
- // TODO(perkj): Remove kEnableSctpDataChannels once Chrome use
- // PeerConnectionFactory::SetOptions.
- static const char kEnableSctpDataChannels[]; // Enable SCTP DataChannels
+ // Google-specific constraint keys.
// Temporary pseudo-constraint for enabling DSCP through JS.
- static const char kEnableDscp[];
+ static const char kEnableDscp[]; // googDscp
+ // Constraint to enable IPv6 through JS.
+ static const char kEnableIPv6[]; // googIPv6
+ // Temporary constraint to enable suspend below min bitrate feature.
+ static const char kEnableVideoSuspendBelowMinBitrate[];
+ // googSuspendBelowMinBitrate
+ static const char kImprovedWifiBwe[]; // googImprovedWifiBwe
+ static const char kScreencastMinBitrate[]; // googScreencastMinBitrate
+ static const char kSkipEncodingUnusedStreams[];
+ // googSkipEncodingUnusedStreams
+ static const char kCpuOveruseDetection[]; // googCpuOveruseDetection
+ static const char kCpuUnderuseThreshold[]; // googCpuUnderuseThreshold
+ static const char kCpuOveruseThreshold[]; // googCpuOveruseThreshold
+ // Low cpu adaptation threshold for relative standard deviation of encode
+ // time.
+ static const char kCpuUnderuseEncodeRsdThreshold[];
+ // High cpu adaptation threshold for relative standard deviation of encode
+ // time.
+ static const char kCpuOveruseEncodeRsdThreshold[];
+ static const char kCpuOveruseEncodeUsage[]; // googCpuOveruseEncodeUsage
+ static const char kHighStartBitrate[]; // googHighStartBitrate
+ static const char kHighBitrate[]; // googHighBitrate
+ static const char kVeryHighBitrate[]; // googVeryHighBitrate
+ static const char kPayloadPadding[]; // googPayloadPadding
+
+ // PeerConnection codec constraint keys. This should be combined with the
+ // values above.
+ // kOpusFec controls whether we ask the other side to turn on FEC for Opus.
+ static const char kOpusFec[]; // googOpusFec
// The prefix of internal-only constraints whose JS set values should be
// stripped by Chrome before passed down to Libjingle.
static const char kInternalConstraintPrefix[];
- // These constraints are for internal use only, representing Chrome command
- // line flags. So they are prefixed with "internal" so JS values will be
- // removed.
- // Used by a local audio source.
- // TODO(perkj): Remove once Chrome use PeerConnectionFactory::SetOptions.
- static const char kInternalAecDump[]; // internalAecDump
-
protected:
// Dtor protected as objects shouldn't be deleted via this interface
virtual ~MediaConstraintsInterface() {}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastream_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastream_unittest.cc
index bb2d50e6ae6..113242faf50 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastream_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastream_unittest.cc
@@ -33,7 +33,8 @@
#include "talk/base/refcount.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/gunit.h"
-#include "testing/base/public/gmock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
static const char kStreamLabel1[] = "local_stream_1";
static const char kVideoTrackId[] = "dummy_video_cam_1";
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler.cc
index b09af7892fb..ca28cf49736 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler.cc
@@ -56,14 +56,42 @@ void TrackHandler::OnChanged() {
}
}
+LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(NULL) {}
+
+LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
+ talk_base::CritScope lock(&lock_);
+ if (sink_)
+ sink_->OnClose();
+}
+
+void LocalAudioSinkAdapter::OnData(const void* audio_data,
+ int bits_per_sample,
+ int sample_rate,
+ int number_of_channels,
+ int number_of_frames) {
+ talk_base::CritScope lock(&lock_);
+ if (sink_) {
+ sink_->OnData(audio_data, bits_per_sample, sample_rate,
+ number_of_channels, number_of_frames);
+ }
+}
+
+void LocalAudioSinkAdapter::SetSink(cricket::AudioRenderer::Sink* sink) {
+ talk_base::CritScope lock(&lock_);
+ ASSERT(!sink || !sink_);
+ sink_ = sink;
+}
+
LocalAudioTrackHandler::LocalAudioTrackHandler(
AudioTrackInterface* track,
uint32 ssrc,
AudioProviderInterface* provider)
: TrackHandler(track, ssrc),
audio_track_(track),
- provider_(provider) {
+ provider_(provider),
+ sink_adapter_(new LocalAudioSinkAdapter()) {
OnEnabledChanged();
+ track->AddSink(sink_adapter_.get());
}
LocalAudioTrackHandler::~LocalAudioTrackHandler() {
@@ -74,6 +102,7 @@ void LocalAudioTrackHandler::OnStateChanged() {
}
void LocalAudioTrackHandler::Stop() {
+ audio_track_->RemoveSink(sink_adapter_.get());
cricket::AudioOptions options;
provider_->SetAudioSend(ssrc(), false, options, NULL);
}
@@ -81,11 +110,18 @@ void LocalAudioTrackHandler::Stop() {
void LocalAudioTrackHandler::OnEnabledChanged() {
cricket::AudioOptions options;
if (audio_track_->enabled() && audio_track_->GetSource()) {
+ // TODO(xians): Remove this static_cast since we should be able to connect
+ // a remote audio track to peer connection.
options = static_cast<LocalAudioSource*>(
audio_track_->GetSource())->options();
}
- provider_->SetAudioSend(ssrc(), audio_track_->enabled(), options,
- audio_track_->GetRenderer());
+
+ // Use the renderer if the audio track has one, otherwise use the sink
+ // adapter owned by this class.
+ cricket::AudioRenderer* renderer = audio_track_->GetRenderer() ?
+ audio_track_->GetRenderer() : sink_adapter_.get();
+ ASSERT(renderer != NULL);
+ provider_->SetAudioSend(ssrc(), audio_track_->enabled(), options, renderer);
}
RemoteAudioTrackHandler::RemoteAudioTrackHandler(
@@ -95,10 +131,12 @@ RemoteAudioTrackHandler::RemoteAudioTrackHandler(
: TrackHandler(track, ssrc),
audio_track_(track),
provider_(provider) {
+ track->GetSource()->RegisterAudioObserver(this);
OnEnabledChanged();
}
RemoteAudioTrackHandler::~RemoteAudioTrackHandler() {
+ audio_track_->GetSource()->UnregisterAudioObserver(this);
}
void RemoteAudioTrackHandler::Stop() {
@@ -113,6 +151,14 @@ void RemoteAudioTrackHandler::OnEnabledChanged() {
audio_track_->GetRenderer());
}
+void RemoteAudioTrackHandler::OnSetVolume(double volume) {
+ // When the track is disabled, the volume of the source, which is the
+ // corresponding WebRtc Voice Engine channel will be 0. So we do not allow
+ // setting the volume to the source when the track is disabled.
+ if (audio_track_->enabled())
+ provider_->SetAudioPlayoutVolume(ssrc(), volume);
+}
+
LocalVideoTrackHandler::LocalVideoTrackHandler(
VideoTrackInterface* track,
uint32 ssrc,
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler.h b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler.h
index 0cd34d615a4..53afd556285 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler.h
@@ -40,6 +40,7 @@
#include "talk/app/webrtc/mediastreamprovider.h"
#include "talk/app/webrtc/peerconnectioninterface.h"
#include "talk/base/thread.h"
+#include "talk/media/base/audiorenderer.h"
namespace webrtc {
@@ -67,6 +68,28 @@ class TrackHandler : public ObserverInterface {
bool enabled_;
};
+// LocalAudioSinkAdapter receives data callback as a sink to the local
+// AudioTrack, and passes the data to the sink of AudioRenderer.
+class LocalAudioSinkAdapter : public AudioTrackSinkInterface,
+ public cricket::AudioRenderer {
+ public:
+ LocalAudioSinkAdapter();
+ virtual ~LocalAudioSinkAdapter();
+
+ private:
+ // AudioSinkInterface implementation.
+ virtual void OnData(const void* audio_data, int bits_per_sample,
+ int sample_rate, int number_of_channels,
+ int number_of_frames) OVERRIDE;
+
+ // cricket::AudioRenderer implementation.
+ virtual void SetSink(cricket::AudioRenderer::Sink* sink) OVERRIDE;
+
+ cricket::AudioRenderer::Sink* sink_;
+ // Critical section protecting |sink_|.
+ talk_base::CriticalSection lock_;
+};
+
// LocalAudioTrackHandler listen to events on a local AudioTrack instance
// connected to a PeerConnection and orders the |provider| to executes the
// requested change.
@@ -86,12 +109,17 @@ class LocalAudioTrackHandler : public TrackHandler {
private:
AudioTrackInterface* audio_track_;
AudioProviderInterface* provider_;
+
+ // Used to pass the data callback from the |audio_track_| to the other
+ // end of cricket::AudioRenderer.
+ talk_base::scoped_ptr<LocalAudioSinkAdapter> sink_adapter_;
};
// RemoteAudioTrackHandler listen to events on a remote AudioTrack instance
// connected to a PeerConnection and orders the |provider| to executes the
// requested change.
-class RemoteAudioTrackHandler : public TrackHandler {
+class RemoteAudioTrackHandler : public AudioSourceInterface::AudioObserver,
+ public TrackHandler {
public:
RemoteAudioTrackHandler(AudioTrackInterface* track,
uint32 ssrc,
@@ -104,6 +132,9 @@ class RemoteAudioTrackHandler : public TrackHandler {
virtual void OnEnabledChanged() OVERRIDE;
private:
+ // AudioSourceInterface::AudioObserver implementation.
+ virtual void OnSetVolume(double volume) OVERRIDE;
+
AudioTrackInterface* audio_track_;
AudioProviderInterface* provider_;
};
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler_unittest.cc
index 475258e9b98..9a53f355619 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamhandler_unittest.cc
@@ -31,13 +31,15 @@
#include "talk/app/webrtc/audiotrack.h"
#include "talk/app/webrtc/mediastream.h"
+#include "talk/app/webrtc/remoteaudiosource.h"
#include "talk/app/webrtc/streamcollection.h"
#include "talk/app/webrtc/videosource.h"
#include "talk/app/webrtc/videotrack.h"
#include "talk/base/gunit.h"
#include "talk/media/base/fakevideocapturer.h"
#include "talk/media/base/mediachannel.h"
-#include "testing/base/public/gmock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::Exactly;
@@ -59,6 +61,7 @@ class MockAudioProvider : public AudioProviderInterface {
MOCK_METHOD4(SetAudioSend, void(uint32 ssrc, bool enable,
const cricket::AudioOptions& options,
cricket::AudioRenderer* renderer));
+ MOCK_METHOD2(SetAudioPlayoutVolume, void(uint32 ssrc, double volume));
};
// Helper class to test MediaStreamHandler.
@@ -110,12 +113,11 @@ class MediaStreamHandlerTest : public testing::Test {
FakeVideoSource::Create());
video_track_ = VideoTrack::Create(kVideoTrackId, source);
EXPECT_TRUE(stream_->AddTrack(video_track_));
- audio_track_ = AudioTrack::Create(kAudioTrackId,
- NULL);
- EXPECT_TRUE(stream_->AddTrack(audio_track_));
}
void AddLocalAudioTrack() {
+ audio_track_ = AudioTrack::Create(kAudioTrackId, NULL);
+ EXPECT_TRUE(stream_->AddTrack(audio_track_));
EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, true, _, _));
handlers_.AddLocalAudioTrack(stream_, stream_->GetAudioTracks()[0],
kAudioSsrc);
@@ -144,6 +146,9 @@ class MediaStreamHandlerTest : public testing::Test {
}
void AddRemoteAudioTrack() {
+ audio_track_ = AudioTrack::Create(kAudioTrackId,
+ RemoteAudioSource::Create().get());
+ EXPECT_TRUE(stream_->AddTrack(audio_track_));
EXPECT_CALL(audio_provider_, SetAudioPlayout(kAudioSsrc, true, _));
handlers_.AddRemoteAudioTrack(stream_, stream_->GetAudioTracks()[0],
kAudioSsrc);
@@ -292,4 +297,27 @@ TEST_F(MediaStreamHandlerTest, RemoteVideoTrackDisable) {
handlers_.TearDown();
}
+TEST_F(MediaStreamHandlerTest, RemoteAudioTrackSetVolume) {
+ AddRemoteAudioTrack();
+
+ double volume = 0.5;
+ EXPECT_CALL(audio_provider_, SetAudioPlayoutVolume(kAudioSsrc, volume));
+ audio_track_->GetSource()->SetVolume(volume);
+
+ // Disable the audio track, this should prevent setting the volume.
+ EXPECT_CALL(audio_provider_, SetAudioPlayout(kAudioSsrc, false, _));
+ audio_track_->set_enabled(false);
+ audio_track_->GetSource()->SetVolume(1.0);
+
+ EXPECT_CALL(audio_provider_, SetAudioPlayout(kAudioSsrc, true, _));
+ audio_track_->set_enabled(true);
+
+ double new_volume = 0.8;
+ EXPECT_CALL(audio_provider_, SetAudioPlayoutVolume(kAudioSsrc, new_volume));
+ audio_track_->GetSource()->SetVolume(new_volume);
+
+ RemoveRemoteAudioTrack();
+ handlers_.TearDown();
+}
+
} // namespace webrtc
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h
index b2c4468fb99..a3439c59c43 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h
@@ -142,9 +142,64 @@ class VideoTrackInterface : public MediaStreamTrackInterface {
// AudioSourceInterface is a reference counted source used for AudioTracks.
// The same source can be used in multiple AudioTracks.
-// TODO(perkj): Extend this class with necessary methods to allow separate
-// sources for each audio track.
class AudioSourceInterface : public MediaSourceInterface {
+ public:
+ class AudioObserver {
+ public:
+ virtual void OnSetVolume(double volume) = 0;
+
+ protected:
+ virtual ~AudioObserver() {}
+ };
+
+ // TODO(xians): Makes all the interface pure virtual after Chrome has their
+ // implementations.
+ // Sets the volume to the source. |volume| is in the range of [0, 10].
+ virtual void SetVolume(double volume) {}
+
+ // Registers/unregisters observer to the audio source.
+ virtual void RegisterAudioObserver(AudioObserver* observer) {}
+ virtual void UnregisterAudioObserver(AudioObserver* observer) {}
+};
+
+// Interface for receiving audio data from a AudioTrack.
+class AudioTrackSinkInterface {
+ public:
+ virtual void OnData(const void* audio_data,
+ int bits_per_sample,
+ int sample_rate,
+ int number_of_channels,
+ int number_of_frames) = 0;
+ protected:
+ virtual ~AudioTrackSinkInterface() {}
+};
+
+// Interface of the audio processor used by the audio track to collect
+// statistics.
+class AudioProcessorInterface : public talk_base::RefCountInterface {
+ public:
+ struct AudioProcessorStats {
+ AudioProcessorStats() : typing_noise_detected(false),
+ echo_return_loss(0),
+ echo_return_loss_enhancement(0),
+ echo_delay_median_ms(0),
+ aec_quality_min(0.0),
+ echo_delay_std_ms(0) {}
+ ~AudioProcessorStats() {}
+
+ bool typing_noise_detected;
+ int echo_return_loss;
+ int echo_return_loss_enhancement;
+ int echo_delay_median_ms;
+ float aec_quality_min;
+ int echo_delay_std_ms;
+ };
+
+ // Get audio processor statistics.
+ virtual void GetStats(AudioProcessorStats* stats) = 0;
+
+ protected:
+ virtual ~AudioProcessorInterface() {}
};
class AudioTrackInterface : public MediaStreamTrackInterface {
@@ -152,10 +207,26 @@ class AudioTrackInterface : public MediaStreamTrackInterface {
// TODO(xians): Figure out if the following interface should be const or not.
virtual AudioSourceInterface* GetSource() const = 0;
- // Gets a pointer to the audio renderer of this AudioTrack.
+ // Add/Remove a sink that will receive the audio data from the track.
+ virtual void AddSink(AudioTrackSinkInterface* sink) = 0;
+ virtual void RemoveSink(AudioTrackSinkInterface* sink) = 0;
+
+ // Get the signal level from the audio track.
+ // Return true on success, otherwise false.
+ // TODO(xians): Change the interface to int GetSignalLevel() and pure virtual
+ // after Chrome has the correct implementation of the interface.
+ virtual bool GetSignalLevel(int* level) { return false; }
+
+ // Get the audio processor used by the audio track. Return NULL if the track
+ // does not have any processor.
+ // TODO(xians): Make the interface pure virtual.
+ virtual talk_base::scoped_refptr<AudioProcessorInterface>
+ GetAudioProcessor() { return NULL; }
+
+ // Get a pointer to the audio renderer of this AudioTrack.
// The pointer is valid for the lifetime of this AudioTrack.
- // TODO(xians): Make the following interface pure virtual once Chrome has its
- // implementation.
+ // TODO(xians): Remove the following interface after Chrome switches to
+ // AddSink() and RemoveSink() interfaces.
virtual cricket::AudioRenderer* GetRenderer() { return NULL; }
protected:
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamprovider.h b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamprovider.h
index ae00b1de751..5cf0e271695 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamprovider.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamprovider.h
@@ -53,6 +53,10 @@ class AudioProviderInterface {
const cricket::AudioOptions& options,
cricket::AudioRenderer* renderer) = 0;
+ // Sets the audio playout volume of a remote audio track with |ssrc|.
+ // |volume| is in the range of [0, 10].
+ virtual void SetAudioPlayoutVolume(uint32 ssrc, double volume) = 0;
+
protected:
virtual ~AudioProviderInterface() {}
};
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling.cc
index 7586938ce60..99f627a1d39 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling.cc
@@ -33,7 +33,9 @@
#include "talk/app/webrtc/mediastreamproxy.h"
#include "talk/app/webrtc/mediaconstraintsinterface.h"
#include "talk/app/webrtc/mediastreamtrackproxy.h"
+#include "talk/app/webrtc/remoteaudiosource.h"
#include "talk/app/webrtc/remotevideocapturer.h"
+#include "talk/app/webrtc/sctputils.h"
#include "talk/app/webrtc/videosource.h"
#include "talk/app/webrtc/videotrack.h"
#include "talk/base/bytebuffer.h"
@@ -49,18 +51,6 @@ namespace webrtc {
using talk_base::scoped_ptr;
using talk_base::scoped_refptr;
-// Supported MediaConstraints.
-const char MediaConstraintsInterface::kOfferToReceiveAudio[] =
- "OfferToReceiveAudio";
-const char MediaConstraintsInterface::kOfferToReceiveVideo[] =
- "OfferToReceiveVideo";
-const char MediaConstraintsInterface::kIceRestart[] =
- "IceRestart";
-const char MediaConstraintsInterface::kUseRtpMux[] =
- "googUseRtpMUX";
-const char MediaConstraintsInterface::kVoiceActivityDetection[] =
- "VoiceActivityDetection";
-
static bool ParseConstraints(
const MediaConstraintsInterface* constraints,
cricket::MediaSessionOptions* options, bool is_answer) {
@@ -151,7 +141,7 @@ class RemoteMediaStreamFactory {
AudioTrackInterface* AddAudioTrack(webrtc::MediaStreamInterface* stream,
const std::string& track_id) {
return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
- stream, track_id, static_cast<AudioSourceInterface*>(NULL));
+ stream, track_id, RemoteAudioSource::Create().get());
}
VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
@@ -208,14 +198,8 @@ void MediaStreamSignaling::TearDown() {
bool MediaStreamSignaling::IsSctpSidAvailable(int sid) const {
if (sid < 0 || sid > static_cast<int>(cricket::kMaxSctpSid))
return false;
- for (SctpDataChannels::const_iterator iter = sctp_data_channels_.begin();
- iter != sctp_data_channels_.end();
- ++iter) {
- if ((*iter)->id() == sid) {
- return false;
- }
- }
- return true;
+
+ return FindDataChannelBySid(sid) < 0;
}
// Gets the first unused odd/even id based on the DTLS role. If |role| is
@@ -261,13 +245,24 @@ bool MediaStreamSignaling::AddDataChannel(DataChannel* data_channel) {
}
bool MediaStreamSignaling::AddDataChannelFromOpenMessage(
- const std::string& label,
- const DataChannelInit& config) {
+ const cricket::ReceiveDataParams& params,
+ const talk_base::Buffer& payload) {
if (!data_channel_factory_) {
LOG(LS_WARNING) << "Remote peer requested a DataChannel but DataChannels "
<< "are not supported.";
return false;
}
+
+ std::string label;
+ InternalDataChannelInit config;
+ config.id = params.ssrc;
+ if (!ParseDataChannelOpenMessage(payload, &label, &config)) {
+ LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
+ << params.ssrc;
+ return false;
+ }
+ config.open_handshake_role = InternalDataChannelInit::kAcker;
+
scoped_refptr<DataChannel> channel(
data_channel_factory_->CreateDataChannel(label, &config));
if (!channel.get()) {
@@ -279,6 +274,23 @@ bool MediaStreamSignaling::AddDataChannelFromOpenMessage(
return true;
}
+void MediaStreamSignaling::RemoveSctpDataChannel(int sid) {
+ for (SctpDataChannels::iterator iter = sctp_data_channels_.begin();
+ iter != sctp_data_channels_.end();
+ ++iter) {
+ if ((*iter)->id() == sid) {
+ sctp_data_channels_.erase(iter);
+
+ if (talk_base::IsEven(sid) && sid <= last_allocated_sctp_even_sid_) {
+ last_allocated_sctp_even_sid_ = sid - 2;
+ } else if (talk_base::IsOdd(sid) && sid <= last_allocated_sctp_odd_sid_) {
+ last_allocated_sctp_odd_sid_ = sid - 2;
+ }
+ return;
+ }
+ }
+}
+
bool MediaStreamSignaling::AddLocalStream(MediaStreamInterface* local_stream) {
if (local_streams_->find(local_stream->label()) != NULL) {
LOG(LS_WARNING) << "MediaStream with label " << local_stream->label()
@@ -295,24 +307,24 @@ bool MediaStreamSignaling::AddLocalStream(MediaStreamInterface* local_stream) {
AudioTrackVector audio_tracks = local_stream->GetAudioTracks();
for (AudioTrackVector::const_iterator it = audio_tracks.begin();
it != audio_tracks.end(); ++it) {
- TrackInfos::const_iterator track_info_it =
- local_audio_tracks_.find((*it)->id());
- if (track_info_it != local_audio_tracks_.end()) {
- const TrackInfo& info = track_info_it->second;
- OnLocalTrackSeen(info.stream_label, info.track_id, info.ssrc,
- cricket::MEDIA_TYPE_AUDIO);
+ const TrackInfo* track_info = FindTrackInfo(local_audio_tracks_,
+ local_stream->label(),
+ (*it)->id());
+ if (track_info) {
+ OnLocalTrackSeen(track_info->stream_label, track_info->track_id,
+ track_info->ssrc, cricket::MEDIA_TYPE_AUDIO);
}
}
VideoTrackVector video_tracks = local_stream->GetVideoTracks();
for (VideoTrackVector::const_iterator it = video_tracks.begin();
it != video_tracks.end(); ++it) {
- TrackInfos::const_iterator track_info_it =
- local_video_tracks_.find((*it)->id());
- if (track_info_it != local_video_tracks_.end()) {
- const TrackInfo& info = track_info_it->second;
- OnLocalTrackSeen(info.stream_label, info.track_id, info.ssrc,
- cricket::MEDIA_TYPE_VIDEO);
+ const TrackInfo* track_info = FindTrackInfo(local_video_tracks_,
+ local_stream->label(),
+ (*it)->id());
+ if (track_info) {
+ OnLocalTrackSeen(track_info->stream_label, track_info->track_id,
+ track_info->ssrc, cricket::MEDIA_TYPE_VIDEO);
}
}
return true;
@@ -320,6 +332,28 @@ bool MediaStreamSignaling::AddLocalStream(MediaStreamInterface* local_stream) {
void MediaStreamSignaling::RemoveLocalStream(
MediaStreamInterface* local_stream) {
+ AudioTrackVector audio_tracks = local_stream->GetAudioTracks();
+ for (AudioTrackVector::const_iterator it = audio_tracks.begin();
+ it != audio_tracks.end(); ++it) {
+ const TrackInfo* track_info = FindTrackInfo(local_audio_tracks_,
+ local_stream->label(),
+ (*it)->id());
+ if (track_info) {
+ stream_observer_->OnRemoveLocalAudioTrack(local_stream, *it,
+ track_info->ssrc);
+ }
+ }
+ VideoTrackVector video_tracks = local_stream->GetVideoTracks();
+ for (VideoTrackVector::const_iterator it = video_tracks.begin();
+ it != video_tracks.end(); ++it) {
+ const TrackInfo* track_info = FindTrackInfo(local_video_tracks_,
+ local_stream->label(),
+ (*it)->id());
+ if (track_info) {
+ stream_observer_->OnRemoveLocalVideoTrack(local_stream, *it);
+ }
+ }
+
local_streams_->RemoveStream(local_stream);
stream_observer_->OnRemoveLocalStream(local_stream);
}
@@ -464,36 +498,21 @@ void MediaStreamSignaling::OnVideoChannelClose() {
}
void MediaStreamSignaling::OnDataChannelClose() {
- RtpDataChannels::iterator it1 = rtp_data_channels_.begin();
- for (; it1 != rtp_data_channels_.end(); ++it1) {
+ // Use a temporary copy of the RTP/SCTP DataChannel list because the
+ // DataChannel may callback to us and try to modify the list.
+ RtpDataChannels temp_rtp_dcs;
+ temp_rtp_dcs.swap(rtp_data_channels_);
+ RtpDataChannels::iterator it1 = temp_rtp_dcs.begin();
+ for (; it1 != temp_rtp_dcs.end(); ++it1) {
it1->second->OnDataEngineClose();
}
- SctpDataChannels::iterator it2 = sctp_data_channels_.begin();
- for (; it2 != sctp_data_channels_.end(); ++it2) {
- (*it2)->OnDataEngineClose();
- }
-}
-bool MediaStreamSignaling::GetRemoteAudioTrackSsrc(
- const std::string& track_id, uint32* ssrc) const {
- TrackInfos::const_iterator it = remote_audio_tracks_.find(track_id);
- if (it == remote_audio_tracks_.end()) {
- return false;
- }
-
- *ssrc = it->second.ssrc;
- return true;
-}
-
-bool MediaStreamSignaling::GetRemoteVideoTrackSsrc(
- const std::string& track_id, uint32* ssrc) const {
- TrackInfos::const_iterator it = remote_video_tracks_.find(track_id);
- if (it == remote_video_tracks_.end()) {
- return false;
+ SctpDataChannels temp_sctp_dcs;
+ temp_sctp_dcs.swap(sctp_data_channels_);
+ SctpDataChannels::iterator it2 = temp_sctp_dcs.begin();
+ for (; it2 != temp_sctp_dcs.end(); ++it2) {
+ (*it2)->OnDataEngineClose();
}
-
- *ssrc = it->second.ssrc;
- return true;
}
void MediaStreamSignaling::UpdateSessionOptions() {
@@ -554,12 +573,12 @@ void MediaStreamSignaling::UpdateRemoteStreamsList(
// new StreamParam.
TrackInfos::iterator track_it = current_tracks->begin();
while (track_it != current_tracks->end()) {
- TrackInfo info = track_it->second;
+ const TrackInfo& info = *track_it;
cricket::StreamParams params;
if (!cricket::GetStreamBySsrc(streams, info.ssrc, &params) ||
params.id != info.track_id) {
OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
- current_tracks->erase(track_it++);
+ track_it = current_tracks->erase(track_it);
} else {
++track_it;
}
@@ -583,10 +602,10 @@ void MediaStreamSignaling::UpdateRemoteStreamsList(
new_streams->AddStream(stream);
}
- TrackInfos::iterator track_it = current_tracks->find(track_id);
- if (track_it == current_tracks->end()) {
- (*current_tracks)[track_id] =
- TrackInfo(stream_label, track_id, ssrc);
+ const TrackInfo* track_info = FindTrackInfo(*current_tracks, stream_label,
+ track_id);
+ if (!track_info) {
+ current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
OnRemoteTrackSeen(stream_label, track_id, it->first_ssrc(), media_type);
}
}
@@ -642,7 +661,7 @@ void MediaStreamSignaling::RejectRemoteTracks(cricket::MediaType media_type) {
TrackInfos* current_tracks = GetRemoteTracks(media_type);
for (TrackInfos::iterator track_it = current_tracks->begin();
track_it != current_tracks->end(); ++track_it) {
- TrackInfo info = track_it->second;
+ const TrackInfo& info = *track_it;
MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
@@ -695,15 +714,16 @@ void MediaStreamSignaling::MaybeCreateDefaultStream() {
}
if (remote_info_.default_audio_track_needed &&
default_remote_stream->GetAudioTracks().size() == 0) {
- remote_audio_tracks_[kDefaultAudioTrackLabel] =
- TrackInfo(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0);
+ remote_audio_tracks_.push_back(TrackInfo(kDefaultStreamLabel,
+ kDefaultAudioTrackLabel, 0));
+
OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0,
cricket::MEDIA_TYPE_AUDIO);
}
if (remote_info_.default_video_track_needed &&
default_remote_stream->GetVideoTracks().size() == 0) {
- remote_video_tracks_[kDefaultVideoTrackLabel] =
- TrackInfo(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0);
+ remote_video_tracks_.push_back(TrackInfo(kDefaultStreamLabel,
+ kDefaultVideoTrackLabel, 0));
OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0,
cricket::MEDIA_TYPE_VIDEO);
}
@@ -736,16 +756,17 @@ void MediaStreamSignaling::UpdateLocalTracks(
cricket::MediaType media_type) {
TrackInfos* current_tracks = GetLocalTracks(media_type);
- // Find removed tracks. Ie tracks where the track id or ssrc don't match the
- // new StreamParam.
+ // Find removed tracks. Ie tracks where the track id, stream label or ssrc
+ // don't match the new StreamParam.
TrackInfos::iterator track_it = current_tracks->begin();
while (track_it != current_tracks->end()) {
- TrackInfo info = track_it->second;
+ const TrackInfo& info = *track_it;
cricket::StreamParams params;
if (!cricket::GetStreamBySsrc(streams, info.ssrc, &params) ||
- params.id != info.track_id) {
- OnLocalTrackRemoved(info.stream_label, info.track_id, media_type);
- current_tracks->erase(track_it++);
+ params.id != info.track_id || params.sync_label != info.stream_label) {
+ OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
+ media_type);
+ track_it = current_tracks->erase(track_it);
} else {
++track_it;
}
@@ -759,10 +780,11 @@ void MediaStreamSignaling::UpdateLocalTracks(
const std::string& stream_label = it->sync_label;
const std::string& track_id = it->id;
uint32 ssrc = it->first_ssrc();
- TrackInfos::iterator track_it = current_tracks->find(track_id);
- if (track_it == current_tracks->end()) {
- (*current_tracks)[track_id] =
- TrackInfo(stream_label, track_id, ssrc);
+ const TrackInfo* track_info = FindTrackInfo(*current_tracks,
+ stream_label,
+ track_id);
+ if (!track_info) {
+ current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
OnLocalTrackSeen(stream_label, track_id, it->first_ssrc(),
media_type);
}
@@ -805,6 +827,7 @@ void MediaStreamSignaling::OnLocalTrackSeen(
void MediaStreamSignaling::OnLocalTrackRemoved(
const std::string& stream_label,
const std::string& track_id,
+ uint32 ssrc,
cricket::MediaType media_type) {
MediaStreamInterface* stream = local_streams_->find(stream_label);
if (!stream) {
@@ -821,7 +844,7 @@ void MediaStreamSignaling::OnLocalTrackRemoved(
if (!audio_track) {
return;
}
- stream_observer_->OnRemoveLocalAudioTrack(stream, audio_track);
+ stream_observer_->OnRemoveLocalAudioTrack(stream, audio_track, ssrc);
} else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
if (!video_track) {
@@ -948,4 +971,38 @@ void MediaStreamSignaling::OnDtlsRoleReadyForSctp(talk_base::SSLRole role) {
}
}
+
+void MediaStreamSignaling::OnRemoteSctpDataChannelClosed(uint32 sid) {
+ int index = FindDataChannelBySid(sid);
+ if (index < 0) {
+ LOG(LS_WARNING) << "Unexpected sid " << sid
+ << " of the remotely closed DataChannel.";
+ return;
+ }
+ sctp_data_channels_[index]->Close();
+}
+
+const MediaStreamSignaling::TrackInfo*
+MediaStreamSignaling::FindTrackInfo(
+ const MediaStreamSignaling::TrackInfos& infos,
+ const std::string& stream_label,
+ const std::string track_id) const {
+
+ for (TrackInfos::const_iterator it = infos.begin();
+ it != infos.end(); ++it) {
+ if (it->stream_label == stream_label && it->track_id == track_id)
+ return &*it;
+ }
+ return NULL;
+}
+
+int MediaStreamSignaling::FindDataChannelBySid(int sid) const {
+ for (size_t i = 0; i < sctp_data_channels_.size(); ++i) {
+ if (sctp_data_channels_[i]->id() == sid) {
+ return static_cast<int>(i);
+ }
+ }
+ return -1;
+}
+
} // namespace webrtc
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling.h b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling.h
index c600f066285..73781661603 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling.h
@@ -37,6 +37,7 @@
#include "talk/app/webrtc/peerconnectioninterface.h"
#include "talk/app/webrtc/streamcollection.h"
#include "talk/base/scoped_ref_ptr.h"
+#include "talk/base/sigslot.h"
#include "talk/session/media/mediasession.h"
namespace talk_base {
@@ -92,7 +93,8 @@ class MediaStreamSignalingObserver {
// Triggered when the local SessionDescription has removed an audio track.
virtual void OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track) = 0;
+ AudioTrackInterface* audio_track,
+ uint32 ssrc) = 0;
// Triggered when the local SessionDescription has removed a video track.
virtual void OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
@@ -156,7 +158,7 @@ class MediaStreamSignalingObserver {
// DataChannel label or SSRC. The DataChannel SSRC is updated with SSRC=0.
// The DataChannel change state to kClosed.
-class MediaStreamSignaling {
+class MediaStreamSignaling : public sigslot::has_slots<> {
public:
MediaStreamSignaling(talk_base::Thread* signaling_thread,
MediaStreamSignalingObserver* stream_observer,
@@ -194,8 +196,9 @@ class MediaStreamSignaling {
// be offered in a SessionDescription.
bool AddDataChannel(DataChannel* data_channel);
// After we receive an OPEN message, create a data channel and add it.
- bool AddDataChannelFromOpenMessage(
- const std::string& label, const DataChannelInit& config);
+ bool AddDataChannelFromOpenMessage(const cricket::ReceiveDataParams& params,
+ const talk_base::Buffer& payload);
+ void RemoveSctpDataChannel(int sid);
// Returns a MediaSessionOptions struct with options decided by |constraints|,
// the local MediaStreams and DataChannels.
@@ -238,10 +241,6 @@ class MediaStreamSignaling {
// Called when the data channel closes.
void OnDataChannelClose();
- // Returns the SSRC for a given track.
- bool GetRemoteAudioTrackSsrc(const std::string& track_id, uint32* ssrc) const;
- bool GetRemoteVideoTrackSsrc(const std::string& track_id, uint32* ssrc) const;
-
// Returns all current known local MediaStreams.
StreamCollectionInterface* local_streams() const { return local_streams_;}
@@ -251,6 +250,7 @@ class MediaStreamSignaling {
}
void OnDataTransportCreatedForSctp();
void OnDtlsRoleReadyForSctp(talk_base::SSLRole role);
+ void OnRemoteSctpDataChannelClosed(uint32 sid);
private:
struct RemotePeerInfo {
@@ -287,7 +287,7 @@ class MediaStreamSignaling {
std::string track_id;
uint32 ssrc;
};
- typedef std::map<std::string, TrackInfo> TrackInfos;
+ typedef std::vector<TrackInfo> TrackInfos;
void UpdateSessionOptions();
@@ -358,6 +358,7 @@ class MediaStreamSignaling {
// MediaStreamTrack in a MediaStream in |local_streams_|.
void OnLocalTrackRemoved(const std::string& stream_label,
const std::string& track_id,
+ uint32 ssrc,
cricket::MediaType media_type);
void UpdateLocalRtpDataChannels(const cricket::StreamParamsVec& streams);
@@ -366,6 +367,14 @@ class MediaStreamSignaling {
const std::vector<std::string>& active_channels, bool is_local_update);
void CreateRemoteDataChannel(const std::string& label, uint32 remote_ssrc);
+ const TrackInfo* FindTrackInfo(const TrackInfos& infos,
+ const std::string& stream_label,
+ const std::string track_id) const;
+
+ // Returns the index of the specified SCTP DataChannel in sctp_data_channels_,
+ // or -1 if not found.
+ int FindDataChannelBySid(int sid) const;
+
RemotePeerInfo remote_info_;
talk_base::Thread* signaling_thread_;
DataChannelFactory* data_channel_factory_;
@@ -386,6 +395,7 @@ class MediaStreamSignaling {
typedef std::map<std::string, talk_base::scoped_refptr<DataChannel> >
RtpDataChannels;
typedef std::vector<talk_base::scoped_refptr<DataChannel> > SctpDataChannels;
+
RtpDataChannels rtp_data_channels_;
SctpDataChannels sctp_data_channels_;
};
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling_unittest.cc
index 5b88aa0c53f..150058eea06 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamsignaling_unittest.cc
@@ -26,10 +26,12 @@
*/
#include <string>
+#include <vector>
#include "talk/app/webrtc/audiotrack.h"
#include "talk/app/webrtc/mediastream.h"
#include "talk/app/webrtc/mediastreamsignaling.h"
+#include "talk/app/webrtc/sctputils.h"
#include "talk/app/webrtc/streamcollection.h"
#include "talk/app/webrtc/test/fakeconstraints.h"
#include "talk/app/webrtc/test/fakedatachannelprovider.h"
@@ -246,13 +248,19 @@ class FakeDataChannelFactory : public webrtc::DataChannelFactory {
virtual talk_base::scoped_refptr<webrtc::DataChannel> CreateDataChannel(
const std::string& label,
- const webrtc::DataChannelInit* config) {
- return webrtc::DataChannel::Create(provider_, type_, label, config);
+ const webrtc::InternalDataChannelInit* config) {
+ last_init_ = *config;
+ return webrtc::DataChannel::Create(provider_, type_, label, *config);
+ }
+
+ const webrtc::InternalDataChannelInit& last_init() const {
+ return last_init_;
}
private:
FakeDataChannelProvider* provider_;
cricket::DataChannelType type_;
+ webrtc::InternalDataChannelInit last_init_;
};
class MockSignalingObserver : public webrtc::MediaStreamSignalingObserver {
@@ -290,7 +298,8 @@ class MockSignalingObserver : public webrtc::MediaStreamSignalingObserver {
}
virtual void OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track) {
+ AudioTrackInterface* audio_track,
+ uint32 ssrc) {
RemoveTrack(&local_audio_tracks_, stream, audio_track);
}
@@ -376,31 +385,48 @@ class MockSignalingObserver : public webrtc::MediaStreamSignalingObserver {
std::string track_id;
uint32 ssrc;
};
- typedef std::map<std::string, TrackInfo> TrackInfos;
+ typedef std::vector<TrackInfo> TrackInfos;
void AddTrack(TrackInfos* track_infos, MediaStreamInterface* stream,
MediaStreamTrackInterface* track,
uint32 ssrc) {
- (*track_infos)[track->id()] = TrackInfo(stream->label(), track->id(),
- ssrc);
+ (*track_infos).push_back(TrackInfo(stream->label(), track->id(),
+ ssrc));
}
void RemoveTrack(TrackInfos* track_infos, MediaStreamInterface* stream,
MediaStreamTrackInterface* track) {
- TrackInfos::iterator it = track_infos->find(track->id());
- ASSERT_TRUE(it != track_infos->end());
- ASSERT_EQ(it->second.stream_label, stream->label());
- track_infos->erase(it);
+ for (TrackInfos::iterator it = track_infos->begin();
+ it != track_infos->end(); ++it) {
+ if (it->stream_label == stream->label() && it->track_id == track->id()) {
+ track_infos->erase(it);
+ return;
+ }
+ }
+ ADD_FAILURE();
}
+ const TrackInfo* FindTrackInfo(const TrackInfos& infos,
+ const std::string& stream_label,
+ const std::string track_id) const {
+ for (TrackInfos::const_iterator it = infos.begin();
+ it != infos.end(); ++it) {
+ if (it->stream_label == stream_label && it->track_id == track_id)
+ return &*it;
+ }
+ return NULL;
+ }
+
+
void VerifyTrack(const TrackInfos& track_infos,
const std::string& stream_label,
const std::string& track_id,
uint32 ssrc) {
- TrackInfos::const_iterator it = track_infos.find(track_id);
- ASSERT_TRUE(it != track_infos.end());
- EXPECT_EQ(stream_label, it->second.stream_label);
- EXPECT_EQ(ssrc, it->second.ssrc);
+ const TrackInfo* track_info = FindTrackInfo(track_infos,
+ stream_label,
+ track_id);
+ ASSERT_TRUE(track_info != NULL);
+ EXPECT_EQ(ssrc, track_info->ssrc);
}
TrackInfos remote_audio_tracks_;
@@ -528,11 +554,11 @@ class MediaStreamSignalingTest: public testing::Test {
talk_base::scoped_refptr<webrtc::DataChannel> AddDataChannel(
cricket::DataChannelType type, const std::string& label, int id) {
- webrtc::DataChannelInit config;
+ webrtc::InternalDataChannelInit config;
config.id = id;
talk_base::scoped_refptr<webrtc::DataChannel> data_channel(
webrtc::DataChannel::Create(
- data_channel_provider_.get(), type, label, &config));
+ data_channel_provider_.get(), type, label, config));
EXPECT_TRUE(data_channel.get() != NULL);
EXPECT_TRUE(signaling_->AddDataChannel(data_channel.get()));
return data_channel;
@@ -1044,6 +1070,47 @@ TEST_F(MediaStreamSignalingTest, ChangeSsrcOnTrackInLocalSessionDescription) {
observer_->VerifyLocalVideoTrack(kStreams[0], kVideoTracks[0], 98);
}
+// This test that the correct MediaStreamSignalingObserver methods are called
+// if a new session description is set with the same tracks but they are now
+// sent on a another MediaStream.
+TEST_F(MediaStreamSignalingTest, SignalSameTracksInSeparateMediaStream) {
+ talk_base::scoped_ptr<SessionDescriptionInterface> desc;
+ CreateSessionDescriptionAndReference(1, 1, desc.use());
+
+ signaling_->AddLocalStream(reference_collection_->at(0));
+ signaling_->OnLocalDescriptionChanged(desc.get());
+ EXPECT_EQ(1u, observer_->NumberOfLocalAudioTracks());
+ EXPECT_EQ(1u, observer_->NumberOfLocalVideoTracks());
+
+ std::string stream_label_0 = kStreams[0];
+ observer_->VerifyLocalAudioTrack(stream_label_0, kAudioTracks[0], 1);
+ observer_->VerifyLocalVideoTrack(stream_label_0, kVideoTracks[0], 2);
+
+ // Add a new MediaStream but with the same tracks as in the first stream.
+ std::string stream_label_1 = kStreams[1];
+ talk_base::scoped_refptr<webrtc::MediaStreamInterface> stream_1(
+ webrtc::MediaStream::Create(kStreams[1]));
+ stream_1->AddTrack(reference_collection_->at(0)->GetVideoTracks()[0]);
+ stream_1->AddTrack(reference_collection_->at(0)->GetAudioTracks()[0]);
+ signaling_->AddLocalStream(stream_1);
+
+ // Replace msid in the original SDP.
+ std::string sdp;
+ desc->ToString(&sdp);
+ talk_base::replace_substrs(
+ kStreams[0], strlen(kStreams[0]), kStreams[1], strlen(kStreams[1]), &sdp);
+
+ talk_base::scoped_ptr<SessionDescriptionInterface> updated_desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ sdp, NULL));
+
+ signaling_->OnLocalDescriptionChanged(updated_desc.get());
+ observer_->VerifyLocalAudioTrack(kStreams[1], kAudioTracks[0], 1);
+ observer_->VerifyLocalVideoTrack(kStreams[1], kVideoTracks[0], 2);
+ EXPECT_EQ(1u, observer_->NumberOfLocalAudioTracks());
+ EXPECT_EQ(1u, observer_->NumberOfLocalVideoTracks());
+}
+
// Verifies that an even SCTP id is allocated for SSL_CLIENT and an odd id for
// SSL_SERVER.
TEST_F(MediaStreamSignalingTest, SctpIdAllocationBasedOnRole) {
@@ -1074,14 +1141,55 @@ TEST_F(MediaStreamSignalingTest, SctpIdAllocationNoReuse) {
EXPECT_NE(old_id, new_id);
}
+// Verifies that SCTP ids of removed DataChannels can be reused.
+TEST_F(MediaStreamSignalingTest, SctpIdReusedForRemovedDataChannel) {
+ int odd_id = 1;
+ int even_id = 0;
+ AddDataChannel(cricket::DCT_SCTP, "a", odd_id);
+ AddDataChannel(cricket::DCT_SCTP, "a", even_id);
+
+ int allocated_id = -1;
+ ASSERT_TRUE(signaling_->AllocateSctpSid(talk_base::SSL_SERVER,
+ &allocated_id));
+ EXPECT_EQ(odd_id + 2, allocated_id);
+ AddDataChannel(cricket::DCT_SCTP, "a", allocated_id);
+
+ ASSERT_TRUE(signaling_->AllocateSctpSid(talk_base::SSL_CLIENT,
+ &allocated_id));
+ EXPECT_EQ(even_id + 2, allocated_id);
+ AddDataChannel(cricket::DCT_SCTP, "a", allocated_id);
+
+ signaling_->RemoveSctpDataChannel(odd_id);
+ signaling_->RemoveSctpDataChannel(even_id);
+
+ // Verifies that removed DataChannel ids are reused.
+ ASSERT_TRUE(signaling_->AllocateSctpSid(talk_base::SSL_SERVER,
+ &allocated_id));
+ EXPECT_EQ(odd_id, allocated_id);
+
+ ASSERT_TRUE(signaling_->AllocateSctpSid(talk_base::SSL_CLIENT,
+ &allocated_id));
+ EXPECT_EQ(even_id, allocated_id);
+
+ // Verifies that used higher DataChannel ids are not reused.
+ ASSERT_TRUE(signaling_->AllocateSctpSid(talk_base::SSL_SERVER,
+ &allocated_id));
+ EXPECT_NE(odd_id + 2, allocated_id);
+
+ ASSERT_TRUE(signaling_->AllocateSctpSid(talk_base::SSL_CLIENT,
+ &allocated_id));
+ EXPECT_NE(even_id + 2, allocated_id);
+
+}
+
// Verifies that duplicated label is not allowed for RTP data channel.
TEST_F(MediaStreamSignalingTest, RtpDuplicatedLabelNotAllowed) {
AddDataChannel(cricket::DCT_RTP, "a", -1);
- webrtc::DataChannelInit config;
+ webrtc::InternalDataChannelInit config;
talk_base::scoped_refptr<webrtc::DataChannel> data_channel =
webrtc::DataChannel::Create(
- data_channel_provider_.get(), cricket::DCT_RTP, "a", &config);
+ data_channel_provider_.get(), cricket::DCT_RTP, "a", config);
ASSERT_TRUE(data_channel.get() != NULL);
EXPECT_FALSE(signaling_->AddDataChannel(data_channel.get()));
}
@@ -1092,6 +1200,25 @@ TEST_F(MediaStreamSignalingTest, SctpDuplicatedLabelAllowed) {
AddDataChannel(cricket::DCT_SCTP, "a", -1);
}
+// Verifies the correct configuration is used to create DataChannel from an OPEN
+// message.
+TEST_F(MediaStreamSignalingTest, CreateDataChannelFromOpenMessage) {
+ FakeDataChannelFactory fake_factory(data_channel_provider_.get(),
+ cricket::DCT_SCTP);
+ signaling_->SetDataChannelFactory(&fake_factory);
+ webrtc::DataChannelInit config;
+ config.id = 1;
+ talk_base::Buffer payload;
+ webrtc::WriteDataChannelOpenMessage("a", config, &payload);
+ cricket::ReceiveDataParams params;
+ params.ssrc = config.id;
+ EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage(params, payload));
+ EXPECT_EQ(config.id, fake_factory.last_init().id);
+ EXPECT_FALSE(fake_factory.last_init().negotiated);
+ EXPECT_EQ(webrtc::InternalDataChannelInit::kAcker,
+ fake_factory.last_init().open_handshake_role);
+}
+
// Verifies that duplicated label from OPEN message is allowed.
TEST_F(MediaStreamSignalingTest, DuplicatedLabelFromOpenMessageAllowed) {
AddDataChannel(cricket::DCT_SCTP, "a", -1);
@@ -1101,5 +1228,28 @@ TEST_F(MediaStreamSignalingTest, DuplicatedLabelFromOpenMessageAllowed) {
signaling_->SetDataChannelFactory(&fake_factory);
webrtc::DataChannelInit config;
config.id = 0;
- EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage("a", config));
+ talk_base::Buffer payload;
+ webrtc::WriteDataChannelOpenMessage("a", config, &payload);
+ cricket::ReceiveDataParams params;
+ params.ssrc = config.id;
+ EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage(params, payload));
+}
+
+// Verifies that a DataChannel closed remotely is closed locally.
+TEST_F(MediaStreamSignalingTest,
+ SctpDataChannelClosedLocallyWhenClosedRemotely) {
+ webrtc::InternalDataChannelInit config;
+ config.id = 0;
+
+ talk_base::scoped_refptr<webrtc::DataChannel> data_channel =
+ webrtc::DataChannel::Create(
+ data_channel_provider_.get(), cricket::DCT_SCTP, "a", config);
+ ASSERT_TRUE(data_channel.get() != NULL);
+ EXPECT_EQ(webrtc::DataChannelInterface::kConnecting,
+ data_channel->state());
+
+ EXPECT_TRUE(signaling_->AddDataChannel(data_channel.get()));
+
+ signaling_->OnRemoteSctpDataChannelClosed(config.id);
+ EXPECT_EQ(webrtc::DataChannelInterface::kClosed, data_channel->state());
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamtrackproxy.h b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamtrackproxy.h
index 7c622e73332..19750b08acc 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamtrackproxy.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/mediastreamtrackproxy.h
@@ -42,6 +42,11 @@ BEGIN_PROXY_MAP(AudioTrack)
PROXY_CONSTMETHOD0(TrackState, state)
PROXY_CONSTMETHOD0(bool, enabled)
PROXY_CONSTMETHOD0(AudioSourceInterface*, GetSource)
+ PROXY_METHOD1(void, AddSink, AudioTrackSinkInterface*)
+ PROXY_METHOD1(void, RemoveSink, AudioTrackSinkInterface*)
+ PROXY_METHOD1(bool, GetSignalLevel, int*)
+ PROXY_METHOD0(talk_base::scoped_refptr<AudioProcessorInterface>,
+ GetAudioProcessor)
PROXY_METHOD0(cricket::AudioRenderer*, GetRenderer)
PROXY_METHOD1(bool, set_enabled, bool)
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/README b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/README
index 761338fc9c4..692fbbc5643 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/README
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/README
@@ -7,8 +7,6 @@ Prerequisites:
.gclient file should contain a line like:
target_os = ['ios', 'mac']
Make sure to re-run gclient sync after adding this to download the tools.
- Note that until http://crbug.com/248168 is fixed one needs to do a gclient
- sync with just 'mac' and then follow that with a sync with both.
- Set up webrtc-related $GYP_DEFINES; example shell functions that set
up for building for iOS-device, iOS-simulator, and Mac (resp) are:
@@ -47,6 +45,10 @@ Example of building & using the unittest & app:
ninja -C out_mac/Debug libjingle_peerconnection_objc_test && \
./out_mac/Debug/libjingle_peerconnection_objc_test.app/Contents/MacOS/libjingle_peerconnection_objc_test
+- To build & launch the sample app on OSX:
+ wrmac && gclient runhooks && ninja -C out_mac/Debug AppRTCDemo && \
+ ./out_mac/Debug/AppRTCDemo.app/Contents/MacOS/AppRTCDemo
+
- To build & launch the sample app on the iOS simulator:
wrsim && gclient runhooks && ninja -C out_sim/Debug iossim AppRTCDemo && \
./out_sim/Debug/iossim out_sim/Debug/AppRTCDemo.app
@@ -68,14 +70,11 @@ Example of building & using the unittest & app:
the Info.plist file to ensure that the Bundle Identifier matches
your phone provisioning profile, or use a development wildcard
provisioning profile.)
+- Alternately, use ios-deploy:
+ ios-deploy -d -b out_ios/Debug-iphoneos/AppRTCDemo.app
- Once installed:
- Tap AppRTCDemo on the iOS device's home screen (might have to scroll to find it).
- In desktop chrome, navigate to http://apprtc.appspot.com and note
the r=<NNN> room number in the resulting URL; enter that number
into the text field on the phone.
- - Alternatively, background the app and launch Safari. In Safari,
- open the url apprtc://apprtc.appspot.com/?r=<NNN> where <NNN> is
- the room name. Other options are to put the link in an email/chat
- and send it to yourself. Clicking on it will launch AppRTCDemo
- and navigate to the room.
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCAudioTrack.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCAudioTrack.mm
index 8a56986536b..2364c2942c4 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCAudioTrack.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCAudioTrack.mm
@@ -29,9 +29,9 @@
#error "This file requires ARC support."
#endif
-#import "RTCAudioTrack+internal.h"
+#import "RTCAudioTrack+Internal.h"
-#import "RTCMediaStreamTrack+internal.h"
+#import "RTCMediaStreamTrack+Internal.h"
@implementation RTCAudioTrack
@end
@@ -39,7 +39,7 @@
@implementation RTCAudioTrack (Internal)
- (talk_base::scoped_refptr<webrtc::AudioTrackInterface>)audioTrack {
- return static_cast<webrtc::AudioTrackInterface *>(self.mediaTrack.get());
+ return static_cast<webrtc::AudioTrackInterface*>(self.mediaTrack.get());
}
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCDataChannel+Internal.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCDataChannel+Internal.h
new file mode 100644
index 00000000000..a55089193b0
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCDataChannel+Internal.h
@@ -0,0 +1,55 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "RTCDataChannel.h"
+
+#include "talk/app/webrtc/datachannelinterface.h"
+#include "talk/base/scoped_ref_ptr.h"
+
+@interface RTCDataBuffer (Internal)
+
+@property(nonatomic, readonly) const webrtc::DataBuffer* dataBuffer;
+
+- (instancetype)initWithDataBuffer:(const webrtc::DataBuffer&)buffer;
+
+@end
+
+@interface RTCDataChannelInit (Internal)
+
+@property(nonatomic, readonly) const webrtc::DataChannelInit* dataChannelInit;
+
+@end
+
+@interface RTCDataChannel (Internal)
+
+@property(nonatomic, readonly)
+ talk_base::scoped_refptr<webrtc::DataChannelInterface> dataChannel;
+
+- (instancetype)initWithDataChannel:
+ (talk_base::scoped_refptr<webrtc::DataChannelInterface>)dataChannel;
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCDataChannel.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCDataChannel.mm
new file mode 100644
index 00000000000..08379403758
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCDataChannel.mm
@@ -0,0 +1,273 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "RTCDataChannel+Internal.h"
+
+#include "talk/app/webrtc/datachannelinterface.h"
+
+namespace webrtc {
+
+class RTCDataChannelObserver : public DataChannelObserver {
+ public:
+ RTCDataChannelObserver(RTCDataChannel* channel) { _channel = channel; }
+
+ virtual void OnStateChange() OVERRIDE {
+ [_channel.delegate channelDidChangeState:_channel];
+ }
+
+ virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
+ if (!_channel.delegate) {
+ return;
+ }
+ RTCDataBuffer* dataBuffer =
+ [[RTCDataBuffer alloc] initWithDataBuffer:buffer];
+ [_channel.delegate channel:_channel didReceiveMessageWithBuffer:dataBuffer];
+ }
+
+ private:
+ __weak RTCDataChannel* _channel;
+};
+}
+
+// TODO(tkchin): move to shared location
+NSString* NSStringFromStdString(const std::string& stdString) {
+ // std::string may contain null termination character so we construct
+ // using length.
+ return [[NSString alloc] initWithBytes:stdString.data()
+ length:stdString.length()
+ encoding:NSUTF8StringEncoding];
+}
+
+std::string StdStringFromNSString(NSString* nsString) {
+ NSData* charData = [nsString dataUsingEncoding:NSUTF8StringEncoding];
+ return std::string(reinterpret_cast<const char*>([charData bytes]),
+ [charData length]);
+}
+
+@implementation RTCDataChannelInit {
+ webrtc::DataChannelInit _dataChannelInit;
+}
+
+- (BOOL)isOrdered {
+ return _dataChannelInit.ordered;
+}
+
+- (void)setIsOrdered:(BOOL)isOrdered {
+ _dataChannelInit.ordered = isOrdered;
+}
+
+- (NSInteger)maxRetransmitTime {
+ return _dataChannelInit.maxRetransmitTime;
+}
+
+- (void)setMaxRetransmitTime:(NSInteger)maxRetransmitTime {
+ _dataChannelInit.maxRetransmitTime = maxRetransmitTime;
+}
+
+- (NSInteger)maxRetransmits {
+ return _dataChannelInit.maxRetransmits;
+}
+
+- (void)setMaxRetransmits:(NSInteger)maxRetransmits {
+ _dataChannelInit.maxRetransmits = maxRetransmits;
+}
+
+- (NSString*)protocol {
+ return NSStringFromStdString(_dataChannelInit.protocol);
+}
+
+- (void)setProtocol:(NSString*)protocol {
+ _dataChannelInit.protocol = StdStringFromNSString(protocol);
+}
+
+- (BOOL)isNegotiated {
+ return _dataChannelInit.negotiated;
+}
+
+- (void)setIsNegotiated:(BOOL)isNegotiated {
+ _dataChannelInit.negotiated = isNegotiated;
+}
+
+- (NSInteger)streamId {
+ return _dataChannelInit.id;
+}
+
+- (void)setStreamId:(NSInteger)streamId {
+ _dataChannelInit.id = streamId;
+}
+
+@end
+
+@implementation RTCDataChannelInit (Internal)
+
+- (const webrtc::DataChannelInit*)dataChannelInit {
+ return &_dataChannelInit;
+}
+
+@end
+
+@implementation RTCDataBuffer {
+ talk_base::scoped_ptr<webrtc::DataBuffer> _dataBuffer;
+}
+
+- (instancetype)initWithData:(NSData*)data isBinary:(BOOL)isBinary {
+ NSAssert(data, @"data cannot be nil");
+ if (self = [super init]) {
+ talk_base::Buffer buffer([data bytes], [data length]);
+ _dataBuffer.reset(new webrtc::DataBuffer(buffer, isBinary));
+ }
+ return self;
+}
+
+- (NSData*)data {
+ return [NSData dataWithBytes:_dataBuffer->data.data()
+ length:_dataBuffer->data.length()];
+}
+
+- (BOOL)isBinary {
+ return _dataBuffer->binary;
+}
+
+@end
+
+@implementation RTCDataBuffer (Internal)
+
+- (instancetype)initWithDataBuffer:(const webrtc::DataBuffer&)buffer {
+ if (self = [super init]) {
+ _dataBuffer.reset(new webrtc::DataBuffer(buffer));
+ }
+ return self;
+}
+
+- (const webrtc::DataBuffer*)dataBuffer {
+ return _dataBuffer.get();
+}
+
+@end
+
+@implementation RTCDataChannel {
+ talk_base::scoped_refptr<webrtc::DataChannelInterface> _dataChannel;
+ talk_base::scoped_ptr<webrtc::RTCDataChannelObserver> _observer;
+ BOOL _isObserverRegistered;
+}
+
+- (NSString*)label {
+ return NSStringFromStdString(_dataChannel->label());
+}
+
+- (BOOL)isReliable {
+ return _dataChannel->reliable();
+}
+
+- (BOOL)isOrdered {
+ return _dataChannel->ordered();
+}
+
+- (NSUInteger)maxRetransmitTimeMs {
+ return _dataChannel->maxRetransmitTime();
+}
+
+- (NSUInteger)maxRetransmits {
+ return _dataChannel->maxRetransmits();
+}
+
+- (NSString*)protocol {
+ return NSStringFromStdString(_dataChannel->protocol());
+}
+
+- (BOOL)isNegotiated {
+ return _dataChannel->negotiated();
+}
+
+- (NSInteger)streamId {
+ return _dataChannel->id();
+}
+
+- (RTCDataChannelState)state {
+ switch (_dataChannel->state()) {
+ case webrtc::DataChannelInterface::DataState::kConnecting:
+ return kRTCDataChannelStateConnecting;
+ case webrtc::DataChannelInterface::DataState::kOpen:
+ return kRTCDataChannelStateOpen;
+ case webrtc::DataChannelInterface::DataState::kClosing:
+ return kRTCDataChannelStateClosing;
+ case webrtc::DataChannelInterface::DataState::kClosed:
+ return kRTCDataChannelStateClosed;
+ }
+}
+
+- (NSUInteger)bufferedAmount {
+ return _dataChannel->buffered_amount();
+}
+
+- (void)setDelegate:(id<RTCDataChannelDelegate>)delegate {
+ if (_delegate == delegate) {
+ return;
+ }
+ if (_isObserverRegistered) {
+ _dataChannel->UnregisterObserver();
+ _isObserverRegistered = NO;
+ }
+ _delegate = delegate;
+ if (_delegate) {
+ _dataChannel->RegisterObserver(_observer.get());
+ _isObserverRegistered = YES;
+ }
+}
+
+- (void)close {
+ _dataChannel->Close();
+}
+
+- (BOOL)sendData:(RTCDataBuffer*)data {
+ return _dataChannel->Send(*data.dataBuffer);
+}
+
+@end
+
+@implementation RTCDataChannel (Internal)
+
+- (instancetype)initWithDataChannel:
+ (talk_base::scoped_refptr<webrtc::DataChannelInterface>)
+ dataChannel {
+ NSAssert(dataChannel != NULL, @"dataChannel cannot be NULL");
+ if (self = [super init]) {
+ _dataChannel = dataChannel;
+ _observer.reset(new webrtc::RTCDataChannelObserver(self));
+ }
+ return self;
+}
+
+- (talk_base::scoped_refptr<webrtc::DataChannelInterface>)dataChannel {
+ return _dataChannel;
+}
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEAGLVideoView+Internal.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEAGLVideoView+Internal.h
new file mode 100644
index 00000000000..10df2e33594
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEAGLVideoView+Internal.h
@@ -0,0 +1,36 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCEAGLVideoView.h"
+#import "RTCVideoRenderer.h"
+
+// TODO(tkchin): Move declaration to implementation file. Exposed here in order
+// to support deprecated methods in RTCVideoRenderer.
+@interface RTCEAGLVideoView (Internal) <RTCVideoRendererDelegate>
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEAGLVideoView.m b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEAGLVideoView.m
new file mode 100644
index 00000000000..5365d9821df
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEAGLVideoView.m
@@ -0,0 +1,244 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "RTCEAGLVideoView+Internal.h"
+
+#import <GLKit/GLKit.h>
+
+#import "RTCOpenGLVideoRenderer.h"
+#import "RTCVideoRenderer.h"
+#import "RTCVideoTrack.h"
+
+// RTCDisplayLinkTimer wraps a CADisplayLink and is set to fire every two screen
+// refreshes, which should be 30fps. We wrap the display link in order to avoid
+// a retain cycle since CADisplayLink takes a strong reference onto its target.
+// The timer is paused by default.
+@interface RTCDisplayLinkTimer : NSObject
+
+@property(nonatomic) BOOL isPaused;
+
+- (instancetype)initWithTimerHandler:(void (^)(void))timerHandler;
+- (void)invalidate;
+
+@end
+
+@implementation RTCDisplayLinkTimer {
+ CADisplayLink* _displayLink;
+ void (^_timerHandler)(void);
+}
+
+- (instancetype)initWithTimerHandler:(void (^)(void))timerHandler {
+ NSParameterAssert(timerHandler);
+ if (self = [super init]) {
+ _timerHandler = timerHandler;
+ _displayLink =
+ [CADisplayLink displayLinkWithTarget:self
+ selector:@selector(displayLinkDidFire:)];
+ _displayLink.paused = YES;
+ // Set to half of screen refresh, which should be 30fps.
+ [_displayLink setFrameInterval:2];
+ [_displayLink addToRunLoop:[NSRunLoop currentRunLoop]
+ forMode:NSRunLoopCommonModes];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self invalidate];
+}
+
+- (BOOL)isPaused {
+ return _displayLink.paused;
+}
+
+- (void)setIsPaused:(BOOL)isPaused {
+ _displayLink.paused = isPaused;
+}
+
+- (void)invalidate {
+ [_displayLink invalidate];
+}
+
+- (void)displayLinkDidFire:(CADisplayLink*)displayLink {
+ _timerHandler();
+}
+
+@end
+
+@interface RTCEAGLVideoView () <GLKViewDelegate>
+// |i420Frame| is set when we receive a frame from a worker thread and is read
+// from the display link callback so atomicity is required.
+@property(atomic, strong) RTCI420Frame* i420Frame;
+@property(nonatomic, readonly) GLKView* glkView;
+@property(nonatomic, readonly) RTCOpenGLVideoRenderer* glRenderer;
+@end
+
+@implementation RTCEAGLVideoView {
+ RTCDisplayLinkTimer* _timer;
+ GLKView* _glkView;
+ RTCOpenGLVideoRenderer* _glRenderer;
+ RTCVideoRenderer* _videoRenderer;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+ if (self = [super initWithFrame:frame]) {
+ EAGLContext* glContext =
+ [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+ _glRenderer = [[RTCOpenGLVideoRenderer alloc] initWithContext:glContext];
+
+ // GLKView manages a framebuffer for us.
+ _glkView = [[GLKView alloc] initWithFrame:CGRectZero
+ context:glContext];
+ _glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
+ _glkView.drawableDepthFormat = GLKViewDrawableDepthFormatNone;
+ _glkView.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
+ _glkView.drawableMultisample = GLKViewDrawableMultisampleNone;
+ _glkView.delegate = self;
+ _glkView.layer.masksToBounds = YES;
+ [self addSubview:_glkView];
+
+ // Listen to application state in order to clean up OpenGL before app goes
+ // away.
+ NSNotificationCenter* notificationCenter =
+ [NSNotificationCenter defaultCenter];
+ [notificationCenter addObserver:self
+ selector:@selector(willResignActive)
+ name:UIApplicationWillResignActiveNotification
+ object:nil];
+ [notificationCenter addObserver:self
+ selector:@selector(didBecomeActive)
+ name:UIApplicationDidBecomeActiveNotification
+ object:nil];
+
+ // Frames are received on a separate thread, so we poll for current frame
+ // using a refresh rate proportional to screen refresh frequency. This
+ // occurs on the main thread.
+ __weak RTCEAGLVideoView* weakSelf = self;
+ _timer = [[RTCDisplayLinkTimer alloc] initWithTimerHandler:^{
+ RTCEAGLVideoView* strongSelf = weakSelf;
+ // Don't render if frame hasn't changed.
+ if (strongSelf.glRenderer.lastDrawnFrame == strongSelf.i420Frame) {
+ return;
+ }
+ // This tells the GLKView that it's dirty, which will then call the
+ // GLKViewDelegate method implemented below.
+ [strongSelf.glkView setNeedsDisplay];
+ }];
+ _videoRenderer = [[RTCVideoRenderer alloc] initWithDelegate:self];
+ [self setupGL];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ UIApplicationState appState =
+ [UIApplication sharedApplication].applicationState;
+ if (appState == UIApplicationStateActive) {
+ [self teardownGL];
+ }
+ [_timer invalidate];
+}
+
+- (void)setVideoTrack:(RTCVideoTrack*)videoTrack {
+ if (_videoTrack == videoTrack) {
+ return;
+ }
+ [_videoTrack removeRenderer:_videoRenderer];
+ _videoTrack = videoTrack;
+ [_videoTrack addRenderer:_videoRenderer];
+ // TODO(tkchin): potentially handle changes in track state - e.g. render
+ // black if track fails.
+}
+
+#pragma mark - UIView
+
+- (void)layoutSubviews {
+ [super layoutSubviews];
+ _glkView.frame = self.bounds;
+}
+
+#pragma mark - GLKViewDelegate
+
+// This method is called when the GLKView's content is dirty and needs to be
+// redrawn. This occurs on main thread.
+- (void)glkView:(GLKView*)view drawInRect:(CGRect)rect {
+ if (self.i420Frame) {
+ // The renderer will draw the frame to the framebuffer corresponding to the
+ // one used by |view|.
+ [_glRenderer drawFrame:self.i420Frame];
+ }
+}
+
+#pragma mark - Private
+
+- (void)setupGL {
+ [_glRenderer setupGL];
+ _timer.isPaused = NO;
+}
+
+- (void)teardownGL {
+ _timer.isPaused = YES;
+ [_glkView deleteDrawable];
+ [_glRenderer teardownGL];
+}
+
+- (void)didBecomeActive {
+ [self setupGL];
+}
+
+- (void)willResignActive {
+ [self teardownGL];
+}
+
+@end
+
+@implementation RTCEAGLVideoView (Internal)
+
+#pragma mark - RTCVideoRendererDelegate
+
+// These methods are called when the video track has frame information to
+// provide. This occurs on non-main thread.
+- (void)renderer:(RTCVideoRenderer*)renderer
+ didSetSize:(CGSize)size {
+ __weak RTCEAGLVideoView* weakSelf = self;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ RTCEAGLVideoView* strongSelf = weakSelf;
+ [strongSelf.delegate videoView:strongSelf didChangeVideoSize:size];
+ });
+}
+
+- (void)renderer:(RTCVideoRenderer*)renderer
+ didReceiveFrame:(RTCI420Frame*)frame {
+ self.i420Frame = frame;
+}
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEnumConverter.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEnumConverter.h
index 0e83719d56b..d33709d3006 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEnumConverter.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEnumConverter.h
@@ -42,6 +42,9 @@
+ (RTCSignalingState)convertSignalingStateToObjC:
(webrtc::PeerConnectionInterface::SignalingState)nativeState;
++ (webrtc::PeerConnectionInterface::StatsOutputLevel)
+ convertStatsOutputLevelToNative:(RTCStatsOutputLevel)statsOutputLevel;
+
+ (RTCSourceState)convertSourceStateToObjC:
(webrtc::MediaSourceInterface::SourceState)nativeState;
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEnumConverter.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEnumConverter.mm
index 7c81c8d854d..9d019419c6e 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEnumConverter.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCEnumConverter.mm
@@ -81,6 +81,16 @@
}
}
++ (webrtc::PeerConnectionInterface::StatsOutputLevel)
+ convertStatsOutputLevelToNative:(RTCStatsOutputLevel)statsOutputLevel {
+ switch (statsOutputLevel) {
+ case RTCStatsOutputLevelStandard:
+ return webrtc::PeerConnectionInterface::kStatsOutputLevelStandard;
+ case RTCStatsOutputLevelDebug:
+ return webrtc::PeerConnectionInterface::kStatsOutputLevelDebug;
+ }
+}
+
+ (RTCSourceState)convertSourceStateToObjC:
(webrtc::MediaSourceInterface::SourceState)nativeState {
switch (nativeState) {
diff --git a/chromium/third_party/libjingle/source/talk/media/devices/iosdeviceinfo.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCI420Frame+Internal.h
index 8b65c14283c..622c0b31efe 100644
--- a/chromium/third_party/libjingle/source/talk/media/devices/iosdeviceinfo.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCI420Frame+Internal.h
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2012 Google Inc.
+ * Copyright 2014, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,16 +25,12 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "talk/media/devices/deviceinfo.h"
+#import "RTCI420Frame.h"
-namespace cricket {
+#include "talk/media/base/videoframe.h"
-bool GetUsbId(const Device& device, std::string* usb_id) {
- return false;
-}
+@interface RTCI420Frame (Internal)
-bool GetUsbVersion(const Device& device, std::string* usb_version) {
- return false;
-}
+- (instancetype)initWithVideoFrame:(const cricket::VideoFrame*)videoFrame;
-} // namespace cricket
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCI420Frame.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCI420Frame.mm
index df84fc15e1e..eff3102e262 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCI420Frame.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCI420Frame.mm
@@ -27,8 +27,68 @@
#import "RTCI420Frame.h"
-@implementation RTCI420Frame
+#include "talk/base/scoped_ptr.h"
+#include "talk/media/base/videoframe.h"
-// TODO(hughv): Should this just be a cricket::VideoFrame wrapper object?
+@implementation RTCI420Frame {
+ talk_base::scoped_ptr<cricket::VideoFrame> _videoFrame;
+}
+
+- (NSUInteger)width {
+ return _videoFrame->GetWidth();
+}
+
+- (NSUInteger)height {
+ return _videoFrame->GetHeight();
+}
+
+- (NSUInteger)chromaWidth {
+ return _videoFrame->GetChromaWidth();
+}
+
+- (NSUInteger)chromaHeight {
+ return _videoFrame->GetChromaHeight();
+}
+
+- (NSUInteger)chromaSize {
+ return _videoFrame->GetChromaSize();
+}
+
+- (const uint8_t*)yPlane {
+ return _videoFrame->GetYPlane();
+}
+
+- (const uint8_t*)uPlane {
+ return _videoFrame->GetUPlane();
+}
+
+- (const uint8_t*)vPlane {
+ return _videoFrame->GetVPlane();
+}
+
+- (NSInteger)yPitch {
+ return _videoFrame->GetYPitch();
+}
+
+- (NSInteger)uPitch {
+ return _videoFrame->GetUPitch();
+}
+
+- (NSInteger)vPitch {
+ return _videoFrame->GetVPitch();
+}
+
+@end
+
+@implementation RTCI420Frame (Internal)
+
+- (instancetype)initWithVideoFrame:(cricket::VideoFrame*)videoFrame {
+ if (self = [super init]) {
+ // Keep a shallow copy of the video frame. The underlying frame buffer is
+ // not copied.
+ _videoFrame.reset(videoFrame->Copy());
+ }
+ return self;
+}
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCICECandidate.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCICECandidate.mm
index 07a29ee4565..4b5b0ed4457 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCICECandidate.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCICECandidate.mm
@@ -29,7 +29,7 @@
#error "This file requires ARC support."
#endif
-#import "RTCICECandidate+internal.h"
+#import "RTCICECandidate+Internal.h"
@implementation RTCICECandidate
@@ -37,9 +37,9 @@
@synthesize sdpMLineIndex = _sdpMLineIndex;
@synthesize sdp = _sdp;
-- (id)initWithMid:(NSString *)sdpMid
+- (id)initWithMid:(NSString*)sdpMid
index:(NSInteger)sdpMLineIndex
- sdp:(NSString *)sdp {
+ sdp:(NSString*)sdp {
if (!sdpMid || !sdp) {
NSAssert(NO, @"nil arguments not allowed");
return nil;
@@ -52,18 +52,18 @@
return self;
}
-- (NSString *)description {
+- (NSString*)description {
return [NSString stringWithFormat:@"%@:%ld:%@",
- self.sdpMid,
- (long)self.sdpMLineIndex,
- self.sdp];
+ self.sdpMid,
+ (long)self.sdpMLineIndex,
+ self.sdp];
}
@end
@implementation RTCICECandidate (Internal)
-- (id)initWithCandidate:(const webrtc::IceCandidateInterface *)candidate {
+- (id)initWithCandidate:(const webrtc::IceCandidateInterface*)candidate {
if ((self = [super init])) {
std::string sdp;
if (candidate->ToString(&sdp)) {
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCICEServer.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCICEServer.mm
index f01ed32358e..9f6ecb618f5 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCICEServer.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCICEServer.mm
@@ -29,7 +29,7 @@
#error "This file requires ARC support."
#endif
-#import "RTCICEServer+internal.h"
+#import "RTCICEServer+Internal.h"
@implementation RTCICEServer
@@ -37,9 +37,9 @@
@synthesize username = _username;
@synthesize password = _password;
-- (id)initWithURI:(NSURL *)URI
- username:(NSString *)username
- password:(NSString *)password {
+- (id)initWithURI:(NSURL*)URI
+ username:(NSString*)username
+ password:(NSString*)password {
if (!URI || !username || !password) {
NSAssert(NO, @"nil arguments not allowed");
self = nil;
@@ -53,9 +53,11 @@
return self;
}
-- (NSString *)description {
+- (NSString*)description {
return [NSString stringWithFormat:@"RTCICEServer: [%@:%@:%@]",
- [self.URI absoluteString], self.username, self.password];
+ [self.URI absoluteString],
+ self.username,
+ self.password];
}
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaConstraints.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaConstraints.mm
index fcb3b52dcfe..a1cc5a564e2 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaConstraints.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaConstraints.mm
@@ -29,7 +29,7 @@
#error "This file requires ARC support."
#endif
-#import "RTCMediaConstraints+internal.h"
+#import "RTCMediaConstraints+Internal.h"
#import "RTCPair.h"
@@ -44,8 +44,8 @@
webrtc::MediaConstraintsInterface::Constraints _optional;
}
-- (id)initWithMandatoryConstraints:(NSArray *)mandatory
- optionalConstraints:(NSArray *)optional {
+- (id)initWithMandatoryConstraints:(NSArray*)mandatory
+ optionalConstraints:(NSArray*)optional {
if ((self = [super init])) {
_mandatory = [[self class] constraintsFromArray:mandatory];
_optional = [[self class] constraintsFromArray:optional];
@@ -55,10 +55,10 @@
return self;
}
-+ (webrtc::MediaConstraintsInterface::Constraints)
- constraintsFromArray:(NSArray *)array {
++ (webrtc::MediaConstraintsInterface::Constraints)constraintsFromArray:
+ (NSArray*)array {
webrtc::MediaConstraintsInterface::Constraints constraints;
- for (RTCPair *pair in array) {
+ for (RTCPair* pair in array) {
constraints.push_back(webrtc::MediaConstraintsInterface::Constraint(
[pair.key UTF8String], [pair.value UTF8String]));
}
@@ -69,7 +69,7 @@
@implementation RTCMediaConstraints (internal)
-- (const webrtc::RTCMediaConstraintsNative *)constraints {
+- (const webrtc::RTCMediaConstraintsNative*)constraints {
return _constraints.get();
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaSource.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaSource.mm
index 9331fd7290c..28af3ad2e3f 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaSource.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaSource.mm
@@ -29,7 +29,7 @@
#error "This file requires ARC support."
#endif
-#import "RTCMediaSource+internal.h"
+#import "RTCMediaSource+Internal.h"
#import "RTCEnumConverter.h"
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaStream.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaStream.mm
index dd4aab690d3..94e14fc57ca 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaStream.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaStream.mm
@@ -29,40 +29,40 @@
#error "This file requires ARC support."
#endif
-#import "RTCMediaStream+internal.h"
+#import "RTCMediaStream+Internal.h"
-#import "RTCAudioTrack+internal.h"
-#import "RTCMediaStreamTrack+internal.h"
-#import "RTCVideoTrack+internal.h"
+#import "RTCAudioTrack+Internal.h"
+#import "RTCMediaStreamTrack+Internal.h"
+#import "RTCVideoTrack+Internal.h"
#include "talk/app/webrtc/mediastreaminterface.h"
@implementation RTCMediaStream {
- NSMutableArray *_audioTracks;
- NSMutableArray *_videoTracks;
+ NSMutableArray* _audioTracks;
+ NSMutableArray* _videoTracks;
talk_base::scoped_refptr<webrtc::MediaStreamInterface> _mediaStream;
}
-- (NSString *)description {
+- (NSString*)description {
return [NSString stringWithFormat:@"[%@:A=%lu:V=%lu]",
- [self label],
- (unsigned long)[self.audioTracks count],
- (unsigned long)[self.videoTracks count]];
+ [self label],
+ (unsigned long)[self.audioTracks count],
+ (unsigned long)[self.videoTracks count]];
}
-- (NSArray *)audioTracks {
+- (NSArray*)audioTracks {
return [_audioTracks copy];
}
-- (NSArray *)videoTracks {
+- (NSArray*)videoTracks {
return [_videoTracks copy];
}
-- (NSString *)label {
+- (NSString*)label {
return @(self.mediaStream->label().c_str());
}
-- (BOOL)addAudioTrack:(RTCAudioTrack *)track {
+- (BOOL)addAudioTrack:(RTCAudioTrack*)track {
if (self.mediaStream->AddTrack(track.audioTrack)) {
[_audioTracks addObject:track];
return YES;
@@ -70,7 +70,7 @@
return NO;
}
-- (BOOL)addVideoTrack:(RTCVideoTrack *)track {
+- (BOOL)addVideoTrack:(RTCVideoTrack*)track {
if (self.mediaStream->AddTrack(track.videoTrack)) {
[_videoTracks addObject:track];
return YES;
@@ -78,7 +78,7 @@
return NO;
}
-- (BOOL)removeAudioTrack:(RTCAudioTrack *)track {
+- (BOOL)removeAudioTrack:(RTCAudioTrack*)track {
NSUInteger index = [_audioTracks indexOfObjectIdenticalTo:track];
NSAssert(index != NSNotFound,
@"|removeAudioTrack| called on unexpected RTCAudioTrack");
@@ -89,7 +89,7 @@
return NO;
}
-- (BOOL)removeVideoTrack:(RTCVideoTrack *)track {
+- (BOOL)removeVideoTrack:(RTCVideoTrack*)track {
NSUInteger index = [_videoTracks indexOfObjectIdenticalTo:track];
NSAssert(index != NSNotFound,
@"|removeAudioTrack| called on unexpected RTCVideoTrack");
@@ -105,7 +105,7 @@
@implementation RTCMediaStream (Internal)
- (id)initWithMediaStream:
- (talk_base::scoped_refptr<webrtc::MediaStreamInterface>)mediaStream {
+ (talk_base::scoped_refptr<webrtc::MediaStreamInterface>)mediaStream {
if (!mediaStream) {
NSAssert(NO, @"nil arguments not allowed");
self = nil;
@@ -122,18 +122,18 @@
for (size_t i = 0; i < audio_tracks.size(); ++i) {
talk_base::scoped_refptr<webrtc::AudioTrackInterface> track =
audio_tracks[i];
- RTCAudioTrack *audioTrack =
+ RTCAudioTrack* audioTrack =
[[RTCAudioTrack alloc] initWithMediaTrack:track];
[_audioTracks addObject:audioTrack];
}
- // TODO(hughv): Add video.
-// for (size_t i = 0; i < video_tracks.size(); ++i) {
-// talk_base::scoped_refptr<webrtc::VideoTrackInterface> track =
-// video_tracks[i];
-// RTCVideoTrack *videoTrack =
-// [[RTCVideoTrack alloc] initWithMediaTrack:track];
-// [_videoTracks addObject:videoTrack];
-// }
+
+ for (size_t i = 0; i < video_tracks.size(); ++i) {
+ talk_base::scoped_refptr<webrtc::VideoTrackInterface> track =
+ video_tracks[i];
+ RTCVideoTrack* videoTrack =
+ [[RTCVideoTrack alloc] initWithMediaTrack:track];
+ [_videoTracks addObject:videoTrack];
+ }
}
return self;
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaStreamTrack.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaStreamTrack.mm
index 6c8f7154292..59313120029 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaStreamTrack.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCMediaStreamTrack.mm
@@ -29,23 +29,40 @@
#error "This file requires ARC support."
#endif
-#import "RTCMediaStreamTrack+internal.h"
+#import "RTCMediaStreamTrack+Internal.h"
#import "RTCEnumConverter.h"
+namespace webrtc {
+
+class RTCMediaStreamTrackObserver : public ObserverInterface {
+ public:
+ RTCMediaStreamTrackObserver(RTCMediaStreamTrack* track) { _track = track; }
+
+ virtual void OnChanged() OVERRIDE {
+ [_track.delegate mediaStreamTrackDidChange:_track];
+ }
+
+ private:
+ __weak RTCMediaStreamTrack* _track;
+};
+}
+
@implementation RTCMediaStreamTrack {
talk_base::scoped_refptr<webrtc::MediaStreamTrackInterface> _mediaTrack;
+ talk_base::scoped_ptr<webrtc::RTCMediaStreamTrackObserver> _observer;
}
@synthesize label;
- (BOOL)isEqual:(id)other {
// Equality is purely based on the label just like the C++ implementation.
- if (self == other) return YES;
+ if (self == other)
+ return YES;
if (![other isKindOfClass:[self class]] ||
![self isKindOfClass:[other class]]) {
return NO;
}
- RTCMediaStreamTrack *otherMediaStream = (RTCMediaStreamTrack *)other;
+ RTCMediaStreamTrack* otherMediaStream = (RTCMediaStreamTrack*)other;
return [self.label isEqual:otherMediaStream.label];
}
@@ -53,11 +70,11 @@
return [self.label hash];
}
-- (NSString *)kind {
+- (NSString*)kind {
return @(self.mediaTrack->kind().c_str());
}
-- (NSString *)label {
+- (NSString*)label {
return @(self.mediaTrack->id().c_str());
}
@@ -82,20 +99,27 @@
@implementation RTCMediaStreamTrack (Internal)
-- (id)initWithMediaTrack:(
- talk_base::scoped_refptr<webrtc::MediaStreamTrackInterface>)mediaTrack {
+- (id)initWithMediaTrack:
+ (talk_base::scoped_refptr<webrtc::MediaStreamTrackInterface>)
+ mediaTrack {
if (!mediaTrack) {
NSAssert(NO, @"nil arguments not allowed");
self = nil;
return nil;
}
- if ((self = [super init])) {
+ if (self = [super init]) {
_mediaTrack = mediaTrack;
label = @(mediaTrack->id().c_str());
+ _observer.reset(new webrtc::RTCMediaStreamTrackObserver(self));
+ _mediaTrack->RegisterObserver(_observer.get());
}
return self;
}
+- (void)dealloc {
+ _mediaTrack->UnregisterObserver(_observer.get());
+}
+
- (talk_base::scoped_refptr<webrtc::MediaStreamTrackInterface>)mediaTrack {
return _mediaTrack;
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCNSGLVideoView.m b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCNSGLVideoView.m
new file mode 100644
index 00000000000..39f3678bfad
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCNSGLVideoView.m
@@ -0,0 +1,187 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "RTCNSGLVideoView.h"
+
+#import <CoreVideo/CVDisplayLink.h>
+#import <OpenGL/gl3.h>
+#import "RTCOpenGLVideoRenderer.h"
+#import "RTCVideoRenderer.h"
+
+@interface RTCNSGLVideoView () <RTCVideoRendererDelegate>
+// |i420Frame| is set when we receive a frame from a worker thread and is read
+// from the display link callback so atomicity is required.
+@property(atomic, strong) RTCI420Frame* i420Frame;
+@property(atomic, strong) RTCOpenGLVideoRenderer* glRenderer;
+- (void)drawFrame;
+@end
+
+static CVReturn OnDisplayLinkFired(CVDisplayLinkRef displayLink,
+ const CVTimeStamp* now,
+ const CVTimeStamp* outputTime,
+ CVOptionFlags flagsIn,
+ CVOptionFlags* flagsOut,
+ void* displayLinkContext) {
+ RTCNSGLVideoView* view = (__bridge RTCNSGLVideoView*)displayLinkContext;
+ [view drawFrame];
+ return kCVReturnSuccess;
+}
+
+@implementation RTCNSGLVideoView {
+ CVDisplayLinkRef _displayLink;
+ RTCVideoRenderer* _videoRenderer;
+}
+
+- (instancetype)initWithFrame:(NSRect)frame
+ pixelFormat:(NSOpenGLPixelFormat*)format {
+ if (self = [super initWithFrame:frame pixelFormat:format]) {
+ _videoRenderer = [[RTCVideoRenderer alloc] initWithDelegate:self];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self teardownDisplayLink];
+}
+
+- (void)drawRect:(NSRect)rect {
+ [self drawFrame];
+}
+
+- (void)reshape {
+ [super reshape];
+ NSRect frame = [self frame];
+ CGLLockContext([[self openGLContext] CGLContextObj]);
+ glViewport(0, 0, frame.size.width, frame.size.height);
+ CGLUnlockContext([[self openGLContext] CGLContextObj]);
+}
+
+- (void)lockFocus {
+ NSOpenGLContext* context = [self openGLContext];
+ [super lockFocus];
+ if ([context view] != self) {
+ [context setView:self];
+ }
+ [context makeCurrentContext];
+}
+
+- (void)prepareOpenGL {
+ [super prepareOpenGL];
+ if (!self.glRenderer) {
+ self.glRenderer =
+ [[RTCOpenGLVideoRenderer alloc] initWithContext:[self openGLContext]];
+ }
+ [self.glRenderer setupGL];
+ [self setupDisplayLink];
+}
+
+- (void)clearGLContext {
+ [self.glRenderer teardownGL];
+ self.glRenderer = nil;
+ [super clearGLContext];
+}
+
+- (void)setVideoTrack:(RTCVideoTrack*)videoTrack {
+ if (_videoTrack == videoTrack) {
+ return;
+ }
+ if (_videoTrack) {
+ [_videoTrack removeRenderer:_videoRenderer];
+ CVDisplayLinkStop(_displayLink);
+ }
+ _videoTrack = videoTrack;
+ if (_videoTrack) {
+ [_videoTrack addRenderer:_videoRenderer];
+ CVDisplayLinkStart(_displayLink);
+ }
+}
+
+#pragma mark - RTCVideoRendererDelegate
+
+// These methods are called when the video track has frame information to
+// provide. This occurs on non-main thread.
+- (void)renderer:(RTCVideoRenderer*)renderer
+ didSetSize:(CGSize)size {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self.delegate videoView:self didChangeVideoSize:size];
+ });
+}
+
+- (void)renderer:(RTCVideoRenderer*)renderer
+ didReceiveFrame:(RTCI420Frame*)frame {
+ self.i420Frame = frame;
+}
+
+#pragma mark - Private
+
+- (void)drawFrame {
+ RTCI420Frame* i420Frame = self.i420Frame;
+ if (i420Frame && self.glRenderer.lastDrawnFrame != i420Frame) {
+ // This method may be called from CVDisplayLink callback which isn't on the
+ // main thread so we have to lock the GL context before drawing.
+ CGLLockContext([[self openGLContext] CGLContextObj]);
+ [self.glRenderer drawFrame:i420Frame];
+ CGLUnlockContext([[self openGLContext] CGLContextObj]);
+ }
+}
+
+- (void)setupDisplayLink {
+ if (_displayLink) {
+ return;
+ }
+ // Synchronize buffer swaps with vertical refresh rate.
+ GLint swapInt = 1;
+ [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
+
+ // Create display link.
+ CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
+ CVDisplayLinkSetOutputCallback(_displayLink,
+ &OnDisplayLinkFired,
+ (__bridge void*)self);
+ // Set the display link for the current renderer.
+ CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
+ CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
+ CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
+ _displayLink, cglContext, cglPixelFormat);
+ if (_videoTrack) {
+ CVDisplayLinkStart(_displayLink);
+ }
+}
+
+- (void)teardownDisplayLink {
+ if (!_displayLink) {
+ return;
+ }
+ CVDisplayLinkRelease(_displayLink);
+ _displayLink = NULL;
+}
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCOpenGLVideoRenderer.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCOpenGLVideoRenderer.mm
new file mode 100644
index 00000000000..9ee0216cb85
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCOpenGLVideoRenderer.mm
@@ -0,0 +1,457 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "RTCOpenGLVideoRenderer.h"
+
+#if TARGET_OS_IPHONE
+#import <OpenGLES/ES2/gl.h>
+#else
+#import <OpenGL/gl3.h>
+#endif
+
+#import "RTCI420Frame.h"
+
+// TODO(tkchin): check and log openGL errors. Methods here return BOOLs in
+// anticipation of that happening in the future.
+
+#if TARGET_OS_IPHONE
+#define RTC_PIXEL_FORMAT GL_LUMINANCE
+#define SHADER_VERSION
+#define VERTEX_SHADER_IN "attribute"
+#define VERTEX_SHADER_OUT "varying"
+#define FRAGMENT_SHADER_IN "varying"
+#define FRAGMENT_SHADER_OUT
+#define FRAGMENT_SHADER_COLOR "gl_FragColor"
+#define FRAGMENT_SHADER_TEXTURE "texture2D"
+#else
+#define RTC_PIXEL_FORMAT GL_RED
+#define SHADER_VERSION "#version 150\n"
+#define VERTEX_SHADER_IN "in"
+#define VERTEX_SHADER_OUT "out"
+#define FRAGMENT_SHADER_IN "in"
+#define FRAGMENT_SHADER_OUT "out vec4 fragColor;\n"
+#define FRAGMENT_SHADER_COLOR "fragColor"
+#define FRAGMENT_SHADER_TEXTURE "texture"
+#endif
+
+// Vertex shader doesn't do anything except pass coordinates through.
+static const char kVertexShaderSource[] =
+ SHADER_VERSION
+ VERTEX_SHADER_IN " vec2 position;\n"
+ VERTEX_SHADER_IN " vec2 texcoord;\n"
+ VERTEX_SHADER_OUT " vec2 v_texcoord;\n"
+ "void main() {\n"
+ " gl_Position = vec4(position.x, position.y, 0.0, 1.0);\n"
+ " v_texcoord = texcoord;\n"
+ "}\n";
+
+// Fragment shader converts YUV values from input textures into a final RGB
+// pixel. The conversion formula is from http://www.fourcc.org/fccyvrgb.php.
+static const char kFragmentShaderSource[] =
+ SHADER_VERSION
+ "precision highp float;"
+ FRAGMENT_SHADER_IN " vec2 v_texcoord;\n"
+ "uniform lowp sampler2D s_textureY;\n"
+ "uniform lowp sampler2D s_textureU;\n"
+ "uniform lowp sampler2D s_textureV;\n"
+ FRAGMENT_SHADER_OUT
+ "void main() {\n"
+ " float y, u, v, r, g, b;\n"
+ " y = " FRAGMENT_SHADER_TEXTURE "(s_textureY, v_texcoord).r;\n"
+ " u = " FRAGMENT_SHADER_TEXTURE "(s_textureU, v_texcoord).r;\n"
+ " v = " FRAGMENT_SHADER_TEXTURE "(s_textureV, v_texcoord).r;\n"
+ " u = u - 0.5;\n"
+ " v = v - 0.5;\n"
+ " r = y + 1.403 * v;\n"
+ " g = y - 0.344 * u - 0.714 * v;\n"
+ " b = y + 1.770 * u;\n"
+ " " FRAGMENT_SHADER_COLOR " = vec4(r, g, b, 1.0);\n"
+ " }\n";
+
+// Compiles a shader of the given |type| with GLSL source |source| and returns
+// the shader handle or 0 on error.
+GLuint CreateShader(GLenum type, const GLchar* source) {
+ GLuint shader = glCreateShader(type);
+ if (!shader) {
+ return 0;
+ }
+ glShaderSource(shader, 1, &source, NULL);
+ glCompileShader(shader);
+ GLint compileStatus = GL_FALSE;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
+ if (compileStatus == GL_FALSE) {
+ glDeleteShader(shader);
+ shader = 0;
+ }
+ return shader;
+}
+
+// Links a shader program with the given vertex and fragment shaders and
+// returns the program handle or 0 on error.
+GLuint CreateProgram(GLuint vertexShader, GLuint fragmentShader) {
+ if (vertexShader == 0 || fragmentShader == 0) {
+ return 0;
+ }
+ GLuint program = glCreateProgram();
+ if (!program) {
+ return 0;
+ }
+ glAttachShader(program, vertexShader);
+ glAttachShader(program, fragmentShader);
+ glLinkProgram(program);
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus == GL_FALSE) {
+ glDeleteProgram(program);
+ program = 0;
+ }
+ return program;
+}
+
+// When modelview and projection matrices are identity (default) the world is
+// contained in the square around origin with unit size 2. Drawing to these
+// coordinates is equivalent to drawing to the entire screen. The texture is
+// stretched over that square using texture coordinates (u, v) that range
+// from (0, 0) to (1, 1) inclusive. Texture coordinates are flipped vertically
+// here because the incoming frame has origin in upper left hand corner but
+// OpenGL expects origin in bottom left corner.
+const GLfloat gVertices[] = {
+ // X, Y, U, V.
+ -1, -1, 0, 1, // Bottom left.
+ 1, -1, 1, 1, // Bottom right.
+ 1, 1, 1, 0, // Top right.
+ -1, 1, 0, 0, // Top left.
+};
+
+// |kNumTextures| must not exceed 8, which is the limit in OpenGLES2. Two sets
+// of 3 textures are used here, one for each of the Y, U and V planes. Having
+// two sets alleviates CPU blockage in the event that the GPU is asked to render
+// to a texture that is already in use.
+static const GLsizei kNumTextureSets = 2;
+static const GLsizei kNumTextures = 3 * kNumTextureSets;
+
+@implementation RTCOpenGLVideoRenderer {
+#if TARGET_OS_IPHONE
+ EAGLContext* _context;
+#else
+ NSOpenGLContext* _context;
+#endif
+ BOOL _isInitialized;
+ NSUInteger _currentTextureSet;
+ // Handles for OpenGL constructs.
+ GLuint _textures[kNumTextures];
+ GLuint _program;
+#if !TARGET_OS_IPHONE
+ GLuint _vertexArray;
+#endif
+ GLuint _vertexBuffer;
+ GLint _position;
+ GLint _texcoord;
+ GLint _ySampler;
+ GLint _uSampler;
+ GLint _vSampler;
+}
+
++ (void)initialize {
+ // Disable dithering for performance.
+ glDisable(GL_DITHER);
+}
+
+#if TARGET_OS_IPHONE
+- (instancetype)initWithContext:(EAGLContext*)context {
+#else
+- (instancetype)initWithContext:(NSOpenGLContext*)context {
+#endif
+ NSAssert(context != nil, @"context cannot be nil");
+ if (self = [super init]) {
+ _context = context;
+ }
+ return self;
+}
+
+- (BOOL)drawFrame:(RTCI420Frame*)frame {
+ if (!_isInitialized) {
+ return NO;
+ }
+ if (_lastDrawnFrame == frame) {
+ return NO;
+ }
+ [self ensureGLContext];
+ if (![self updateTextureSizesForFrame:frame] ||
+ ![self updateTextureDataForFrame:frame]) {
+ return NO;
+ }
+ glClear(GL_COLOR_BUFFER_BIT);
+#if !TARGET_OS_IPHONE
+ glBindVertexArray(_vertexArray);
+#endif
+ glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+#if !TARGET_OS_IPHONE
+ [_context flushBuffer];
+#endif
+ _lastDrawnFrame = frame;
+ return YES;
+}
+
+- (void)setupGL {
+ if (_isInitialized) {
+ return;
+ }
+ [self ensureGLContext];
+ if (![self setupProgram]) {
+ return;
+ }
+ if (![self setupTextures]) {
+ return;
+ }
+ if (![self setupVertices]) {
+ return;
+ }
+ glUseProgram(_program);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glClearColor(0, 0, 0, 1);
+ _isInitialized = YES;
+}
+
+- (void)teardownGL {
+ if (!_isInitialized) {
+ return;
+ }
+ [self ensureGLContext];
+ glDeleteProgram(_program);
+ _program = 0;
+ glDeleteTextures(kNumTextures, _textures);
+ glDeleteBuffers(1, &_vertexBuffer);
+ _vertexBuffer = 0;
+#if !TARGET_OS_IPHONE
+ glDeleteVertexArrays(1, &_vertexArray);
+#endif
+ _isInitialized = NO;
+}
+
+#pragma mark - Private
+
+- (void)ensureGLContext {
+ NSAssert(_context, @"context shouldn't be nil");
+#if TARGET_OS_IPHONE
+ if ([EAGLContext currentContext] != _context) {
+ [EAGLContext setCurrentContext:_context];
+ }
+#else
+ if ([NSOpenGLContext currentContext] != _context) {
+ [_context makeCurrentContext];
+ }
+#endif
+}
+
+- (BOOL)setupProgram {
+ NSAssert(!_program, @"program already set up");
+ GLuint vertexShader = CreateShader(GL_VERTEX_SHADER, kVertexShaderSource);
+ NSAssert(vertexShader, @"failed to create vertex shader");
+ GLuint fragmentShader =
+ CreateShader(GL_FRAGMENT_SHADER, kFragmentShaderSource);
+ NSAssert(fragmentShader, @"failed to create fragment shader");
+ _program = CreateProgram(vertexShader, fragmentShader);
+ // Shaders are created only to generate program.
+ if (vertexShader) {
+ glDeleteShader(vertexShader);
+ }
+ if (fragmentShader) {
+ glDeleteShader(fragmentShader);
+ }
+ if (!_program) {
+ return NO;
+ }
+ _position = glGetAttribLocation(_program, "position");
+ _texcoord = glGetAttribLocation(_program, "texcoord");
+ _ySampler = glGetUniformLocation(_program, "s_textureY");
+ _uSampler = glGetUniformLocation(_program, "s_textureU");
+ _vSampler = glGetUniformLocation(_program, "s_textureV");
+ if (_position < 0 || _texcoord < 0 || _ySampler < 0 || _uSampler < 0 ||
+ _vSampler < 0) {
+ return NO;
+ }
+ return YES;
+}
+
+- (BOOL)setupTextures {
+ glGenTextures(kNumTextures, _textures);
+ // Set parameters for each of the textures we created.
+ for (GLsizei i = 0; i < kNumTextures; i++) {
+ glActiveTexture(GL_TEXTURE0 + i);
+ glBindTexture(GL_TEXTURE_2D, _textures[i]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+ return YES;
+}
+
+- (BOOL)updateTextureSizesForFrame:(RTCI420Frame*)frame {
+ if (frame.height == _lastDrawnFrame.height &&
+ frame.width == _lastDrawnFrame.width &&
+ frame.chromaWidth == _lastDrawnFrame.chromaWidth &&
+ frame.chromaHeight == _lastDrawnFrame.chromaHeight) {
+ return YES;
+ }
+ GLsizei lumaWidth = frame.width;
+ GLsizei lumaHeight = frame.height;
+ GLsizei chromaWidth = frame.chromaWidth;
+ GLsizei chromaHeight = frame.chromaHeight;
+ for (GLint i = 0; i < kNumTextureSets; i++) {
+ glActiveTexture(GL_TEXTURE0 + i * 3);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ RTC_PIXEL_FORMAT,
+ lumaWidth,
+ lumaHeight,
+ 0,
+ RTC_PIXEL_FORMAT,
+ GL_UNSIGNED_BYTE,
+ 0);
+ glActiveTexture(GL_TEXTURE0 + i * 3 + 1);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ RTC_PIXEL_FORMAT,
+ chromaWidth,
+ chromaHeight,
+ 0,
+ RTC_PIXEL_FORMAT,
+ GL_UNSIGNED_BYTE,
+ 0);
+ glActiveTexture(GL_TEXTURE0 + i * 3 + 2);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ RTC_PIXEL_FORMAT,
+ chromaWidth,
+ chromaHeight,
+ 0,
+ RTC_PIXEL_FORMAT,
+ GL_UNSIGNED_BYTE,
+ 0);
+ }
+ return YES;
+}
+
+- (BOOL)updateTextureDataForFrame:(RTCI420Frame*)frame {
+ NSUInteger textureOffset = _currentTextureSet * 3;
+ NSAssert(textureOffset + 3 <= kNumTextures, @"invalid offset");
+ NSParameterAssert(frame.yPitch == frame.width);
+ NSParameterAssert(frame.uPitch == frame.chromaWidth);
+ NSParameterAssert(frame.vPitch == frame.chromaWidth);
+
+ glActiveTexture(GL_TEXTURE0 + textureOffset);
+ // When setting texture sampler uniforms, the texture index is used not
+ // the texture handle.
+ glUniform1i(_ySampler, textureOffset);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ RTC_PIXEL_FORMAT,
+ frame.width,
+ frame.height,
+ 0,
+ RTC_PIXEL_FORMAT,
+ GL_UNSIGNED_BYTE,
+ frame.yPlane);
+
+ glActiveTexture(GL_TEXTURE0 + textureOffset + 1);
+ glUniform1i(_uSampler, textureOffset + 1);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ RTC_PIXEL_FORMAT,
+ frame.chromaWidth,
+ frame.chromaHeight,
+ 0,
+ RTC_PIXEL_FORMAT,
+ GL_UNSIGNED_BYTE,
+ frame.uPlane);
+
+ glActiveTexture(GL_TEXTURE0 + textureOffset + 2);
+ glUniform1i(_vSampler, textureOffset + 2);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ RTC_PIXEL_FORMAT,
+ frame.chromaWidth,
+ frame.chromaHeight,
+ 0,
+ RTC_PIXEL_FORMAT,
+ GL_UNSIGNED_BYTE,
+ frame.vPlane);
+
+ _currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
+ return YES;
+}
+
+- (BOOL)setupVertices {
+#if !TARGET_OS_IPHONE
+ NSAssert(!_vertexArray, @"vertex array already set up");
+ glGenVertexArrays(1, &_vertexArray);
+ if (!_vertexArray) {
+ return NO;
+ }
+ glBindVertexArray(_vertexArray);
+#endif
+ NSAssert(!_vertexBuffer, @"vertex buffer already set up");
+ glGenBuffers(1, &_vertexBuffer);
+ if (!_vertexBuffer) {
+#if !TARGET_OS_IPHONE
+ glDeleteVertexArrays(1, &_vertexArray);
+ _vertexArray = 0;
+#endif
+ return NO;
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(gVertices), gVertices, GL_DYNAMIC_DRAW);
+
+ // Read position attribute from |gVertices| with size of 2 and stride of 4
+ // beginning at the start of the array. The last argument indicates offset
+ // of data within |gVertices| as supplied to the vertex buffer.
+ glVertexAttribPointer(
+ _position, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)0);
+ glEnableVertexAttribArray(_position);
+
+ // Read texcoord attribute from |gVertices| with size of 2 and stride of 4
+ // beginning at the first texcoord in the array. The last argument indicates
+ // offset of data within |gVertices| as supplied to the vertex buffer.
+ glVertexAttribPointer(_texcoord,
+ 2,
+ GL_FLOAT,
+ GL_FALSE,
+ 4 * sizeof(GLfloat),
+ (void*)(2 * sizeof(GLfloat)));
+ glEnableVertexAttribArray(_texcoord);
+
+ return YES;
+}
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPair.m b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPair.m
index 31ac53ac105..2b289f5ccfd 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPair.m
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPair.m
@@ -32,7 +32,7 @@
@synthesize key = _key;
@synthesize value = _value;
-- (id)initWithKey:(NSString *)key value:(NSString *)value {
+- (id)initWithKey:(NSString*)key value:(NSString*)value {
if ((self = [super init])) {
_key = [key copy];
_value = [value copy];
@@ -40,4 +40,8 @@
return self;
}
+- (NSString*)description {
+ return [NSString stringWithFormat:@"%@: %@", _key, _value];
+}
+
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnection+Internal.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnection+Internal.h
index d1b4639f8af..ad1c334a2a2 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnection+Internal.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnection+Internal.h
@@ -28,7 +28,6 @@
#import "RTCPeerConnection.h"
#import "RTCPeerConnectionDelegate.h"
-#import "RTCPeerConnectionObserver.h"
#include "talk/app/webrtc/peerconnectioninterface.h"
@@ -37,8 +36,8 @@
@property(nonatomic, assign, readonly)
talk_base::scoped_refptr<webrtc::PeerConnectionInterface> peerConnection;
-- (id)initWithPeerConnection:(
- talk_base::scoped_refptr<webrtc::PeerConnectionInterface>)peerConnection
- observer:(webrtc::RTCPeerConnectionObserver *)observer;
+- (instancetype)initWithFactory:(webrtc::PeerConnectionFactoryInterface*)factory
+ iceServers:(const webrtc::PeerConnectionInterface::IceServers&)iceServers
+ constraints:(const webrtc::MediaConstraintsInterface*)constraints;
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnection.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnection.mm
index ae9d1583dc7..738fb313f48 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnection.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnection.mm
@@ -29,16 +29,21 @@
#error "This file requires ARC support."
#endif
-#import "RTCPeerConnection+internal.h"
+#import "RTCPeerConnection+Internal.h"
+#import "RTCDataChannel+Internal.h"
#import "RTCEnumConverter.h"
-#import "RTCICECandidate+internal.h"
-#import "RTCICEServer+internal.h"
-#import "RTCMediaConstraints+internal.h"
-#import "RTCMediaStream+internal.h"
-#import "RTCSessionDescription+internal.h"
-#import "RTCSessionDescriptonDelegate.h"
+#import "RTCICECandidate+Internal.h"
+#import "RTCICEServer+Internal.h"
+#import "RTCMediaConstraints+Internal.h"
+#import "RTCMediaStream+Internal.h"
+#import "RTCMediaStreamTrack+Internal.h"
+#import "RTCPeerConnectionObserver.h"
+#import "RTCSessionDescription+Internal.h"
+#import "RTCSessionDescriptionDelegate.h"
#import "RTCSessionDescription.h"
+#import "RTCStatsDelegate.h"
+#import "RTCStatsReport+Internal.h"
#include "talk/app/webrtc/jsep.h"
@@ -50,40 +55,41 @@ namespace webrtc {
class RTCCreateSessionDescriptionObserver
: public CreateSessionDescriptionObserver {
public:
- RTCCreateSessionDescriptionObserver(id<RTCSessionDescriptonDelegate> delegate,
- RTCPeerConnection *peerConnection) {
+ RTCCreateSessionDescriptionObserver(
+ id<RTCSessionDescriptionDelegate> delegate,
+ RTCPeerConnection* peerConnection) {
_delegate = delegate;
_peerConnection = peerConnection;
}
- virtual void OnSuccess(SessionDescriptionInterface *desc) OVERRIDE {
- RTCSessionDescription *session =
+ virtual void OnSuccess(SessionDescriptionInterface* desc) OVERRIDE {
+ RTCSessionDescription* session =
[[RTCSessionDescription alloc] initWithSessionDescription:desc];
[_delegate peerConnection:_peerConnection
didCreateSessionDescription:session
- error:nil];
+ error:nil];
}
- virtual void OnFailure(const std::string &error) OVERRIDE {
- NSString *str = @(error.c_str());
- NSError *err =
+ virtual void OnFailure(const std::string& error) OVERRIDE {
+ NSString* str = @(error.c_str());
+ NSError* err =
[NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain
code:kRTCSessionDescriptionDelegateErrorCode
- userInfo:@{ @"error" : str }];
+ userInfo:@{@"error" : str}];
[_delegate peerConnection:_peerConnection
didCreateSessionDescription:nil
- error:err];
+ error:err];
}
private:
- id<RTCSessionDescriptonDelegate> _delegate;
- RTCPeerConnection *_peerConnection;
+ id<RTCSessionDescriptionDelegate> _delegate;
+ RTCPeerConnection* _peerConnection;
};
class RTCSetSessionDescriptionObserver : public SetSessionDescriptionObserver {
public:
- RTCSetSessionDescriptionObserver(id<RTCSessionDescriptonDelegate> delegate,
- RTCPeerConnection *peerConnection) {
+ RTCSetSessionDescriptionObserver(id<RTCSessionDescriptionDelegate> delegate,
+ RTCPeerConnection* peerConnection) {
_delegate = delegate;
_peerConnection = peerConnection;
}
@@ -93,37 +99,60 @@ class RTCSetSessionDescriptionObserver : public SetSessionDescriptionObserver {
didSetSessionDescriptionWithError:nil];
}
- virtual void OnFailure(const std::string &error) OVERRIDE {
- NSString *str = @(error.c_str());
- NSError *err =
+ virtual void OnFailure(const std::string& error) OVERRIDE {
+ NSString* str = @(error.c_str());
+ NSError* err =
[NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain
code:kRTCSessionDescriptionDelegateErrorCode
- userInfo:@{ @"error" : str }];
+ userInfo:@{@"error" : str}];
[_delegate peerConnection:_peerConnection
didSetSessionDescriptionWithError:err];
}
private:
- id<RTCSessionDescriptonDelegate> _delegate;
- RTCPeerConnection *_peerConnection;
+ id<RTCSessionDescriptionDelegate> _delegate;
+ RTCPeerConnection* _peerConnection;
};
+class RTCStatsObserver : public StatsObserver {
+ public:
+ RTCStatsObserver(id<RTCStatsDelegate> delegate,
+ RTCPeerConnection* peerConnection) {
+ _delegate = delegate;
+ _peerConnection = peerConnection;
+ }
+
+ virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
+ NSMutableArray* stats = [NSMutableArray arrayWithCapacity:reports.size()];
+ std::vector<StatsReport>::const_iterator it = reports.begin();
+ for (; it != reports.end(); ++it) {
+ RTCStatsReport* statsReport =
+ [[RTCStatsReport alloc] initWithStatsReport:*it];
+ [stats addObject:statsReport];
+ }
+ [_delegate peerConnection:_peerConnection didGetStats:stats];
+ }
+
+ private:
+ id<RTCStatsDelegate> _delegate;
+ RTCPeerConnection* _peerConnection;
+};
}
@implementation RTCPeerConnection {
- NSMutableArray *_localStreams;
- talk_base::scoped_ptr<webrtc::RTCPeerConnectionObserver>_observer;
+ NSMutableArray* _localStreams;
+ talk_base::scoped_ptr<webrtc::RTCPeerConnectionObserver> _observer;
talk_base::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection;
}
-- (BOOL)addICECandidate:(RTCICECandidate *)candidate {
+- (BOOL)addICECandidate:(RTCICECandidate*)candidate {
talk_base::scoped_ptr<const webrtc::IceCandidateInterface> iceCandidate(
candidate.candidate);
return self.peerConnection->AddIceCandidate(iceCandidate.get());
}
-- (BOOL)addStream:(RTCMediaStream *)stream
- constraints:(RTCMediaConstraints *)constraints {
+- (BOOL)addStream:(RTCMediaStream*)stream
+ constraints:(RTCMediaConstraints*)constraints {
BOOL ret = self.peerConnection->AddStream(stream.mediaStream,
constraints.constraints);
if (!ret) {
@@ -133,82 +162,91 @@ class RTCSetSessionDescriptionObserver : public SetSessionDescriptionObserver {
return YES;
}
-- (void)createAnswerWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
- constraints:(RTCMediaConstraints *)constraints {
+- (RTCDataChannel*)createDataChannelWithLabel:(NSString*)label
+ config:(RTCDataChannelInit*)config {
+ std::string labelString([label UTF8String]);
+ talk_base::scoped_refptr<webrtc::DataChannelInterface> dataChannel =
+ self.peerConnection->CreateDataChannel(labelString,
+ config.dataChannelInit);
+ return [[RTCDataChannel alloc] initWithDataChannel:dataChannel];
+}
+
+- (void)createAnswerWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
+ constraints:(RTCMediaConstraints*)constraints {
talk_base::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>
observer(new talk_base::RefCountedObject<
webrtc::RTCCreateSessionDescriptionObserver>(delegate, self));
self.peerConnection->CreateAnswer(observer, constraints.constraints);
}
-- (void)createOfferWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
- constraints:(RTCMediaConstraints *)constraints {
+- (void)createOfferWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
+ constraints:(RTCMediaConstraints*)constraints {
talk_base::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>
observer(new talk_base::RefCountedObject<
webrtc::RTCCreateSessionDescriptionObserver>(delegate, self));
self.peerConnection->CreateOffer(observer, constraints.constraints);
}
-- (void)removeStream:(RTCMediaStream *)stream {
+- (void)removeStream:(RTCMediaStream*)stream {
self.peerConnection->RemoveStream(stream.mediaStream);
[_localStreams removeObject:stream];
}
-- (void)
- setLocalDescriptionWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
- sessionDescription:(RTCSessionDescription *)sdp {
+- (void)setLocalDescriptionWithDelegate:
+ (id<RTCSessionDescriptionDelegate>)delegate
+ sessionDescription:(RTCSessionDescription*)sdp {
talk_base::scoped_refptr<webrtc::RTCSetSessionDescriptionObserver> observer(
new talk_base::RefCountedObject<webrtc::RTCSetSessionDescriptionObserver>(
delegate, self));
self.peerConnection->SetLocalDescription(observer, sdp.sessionDescription);
}
-- (void)
- setRemoteDescriptionWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
- sessionDescription:(RTCSessionDescription *)sdp {
+- (void)setRemoteDescriptionWithDelegate:
+ (id<RTCSessionDescriptionDelegate>)delegate
+ sessionDescription:(RTCSessionDescription*)sdp {
talk_base::scoped_refptr<webrtc::RTCSetSessionDescriptionObserver> observer(
new talk_base::RefCountedObject<webrtc::RTCSetSessionDescriptionObserver>(
delegate, self));
self.peerConnection->SetRemoteDescription(observer, sdp.sessionDescription);
}
-- (BOOL)updateICEServers:(NSArray *)servers
- constraints:(RTCMediaConstraints *)constraints {
+- (BOOL)updateICEServers:(NSArray*)servers
+ constraints:(RTCMediaConstraints*)constraints {
webrtc::PeerConnectionInterface::IceServers iceServers;
- for (RTCICEServer *server in servers) {
+ for (RTCICEServer* server in servers) {
iceServers.push_back(server.iceServer);
}
return self.peerConnection->UpdateIce(iceServers, constraints.constraints);
}
-- (RTCSessionDescription *)localDescription {
- const webrtc::SessionDescriptionInterface *sdi =
+- (RTCSessionDescription*)localDescription {
+ const webrtc::SessionDescriptionInterface* sdi =
self.peerConnection->local_description();
- return sdi ?
- [[RTCSessionDescription alloc] initWithSessionDescription:sdi] :
- nil;
+ return sdi ? [[RTCSessionDescription alloc] initWithSessionDescription:sdi]
+ : nil;
}
-- (NSArray *)localStreams {
+- (NSArray*)localStreams {
return [_localStreams copy];
}
-- (RTCSessionDescription *)remoteDescription {
- const webrtc::SessionDescriptionInterface *sdi =
+- (RTCSessionDescription*)remoteDescription {
+ const webrtc::SessionDescriptionInterface* sdi =
self.peerConnection->remote_description();
- return sdi ?
- [[RTCSessionDescription alloc] initWithSessionDescription:sdi] :
- nil;
+ return sdi ? [[RTCSessionDescription alloc] initWithSessionDescription:sdi]
+ : nil;
}
- (RTCICEConnectionState)iceConnectionState {
- return [RTCEnumConverter convertIceConnectionStateToObjC:
- self.peerConnection->ice_connection_state()];
+ return [RTCEnumConverter
+ convertIceConnectionStateToObjC:self.peerConnection
+ ->ice_connection_state()];
}
- (RTCICEGatheringState)iceGatheringState {
- return [RTCEnumConverter convertIceGatheringStateToObjC:
- self.peerConnection->ice_gathering_state()];
+ return [RTCEnumConverter
+ convertIceGatheringStateToObjC:self.peerConnection
+ ->ice_gathering_state()];
}
- (RTCSignalingState)signalingState {
@@ -220,22 +258,31 @@ class RTCSetSessionDescriptionObserver : public SetSessionDescriptionObserver {
self.peerConnection->Close();
}
+- (BOOL)getStatsWithDelegate:(id<RTCStatsDelegate>)delegate
+ mediaStreamTrack:(RTCMediaStreamTrack*)mediaStreamTrack
+ statsOutputLevel:(RTCStatsOutputLevel)statsOutputLevel {
+ talk_base::scoped_refptr<webrtc::RTCStatsObserver> observer(
+ new talk_base::RefCountedObject<webrtc::RTCStatsObserver>(delegate,
+ self));
+ webrtc::PeerConnectionInterface::StatsOutputLevel nativeOutputLevel =
+ [RTCEnumConverter convertStatsOutputLevelToNative:statsOutputLevel];
+ return self.peerConnection->GetStats(
+ observer, mediaStreamTrack.mediaTrack, nativeOutputLevel);
+}
+
@end
@implementation RTCPeerConnection (Internal)
-- (id)initWithPeerConnection:(
- talk_base::scoped_refptr<webrtc::PeerConnectionInterface>)peerConnection
- observer:(webrtc::RTCPeerConnectionObserver *)observer {
- if (!peerConnection || !observer) {
- NSAssert(NO, @"nil arguments not allowed");
- self = nil;
- return nil;
- }
- if ((self = [super init])) {
- _peerConnection = peerConnection;
+- (instancetype)initWithFactory:(webrtc::PeerConnectionFactoryInterface*)factory
+ iceServers:(const webrtc::PeerConnectionInterface::IceServers&)iceServers
+ constraints:(const webrtc::MediaConstraintsInterface*)constraints {
+ NSParameterAssert(factory != NULL);
+ if (self = [super init]) {
+ _observer.reset(new webrtc::RTCPeerConnectionObserver(self));
+ _peerConnection = factory->CreatePeerConnection(
+ iceServers, constraints, NULL, NULL, _observer.get());
_localStreams = [[NSMutableArray alloc] init];
- _observer.reset(observer);
}
return self;
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionFactory.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionFactory.mm
index 325110fb36a..8ada166d6be 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionFactory.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionFactory.mm
@@ -33,18 +33,17 @@
#include <vector>
-#import "RTCAudioTrack+internal.h"
-#import "RTCICEServer+internal.h"
-#import "RTCMediaConstraints+internal.h"
-#import "RTCMediaSource+internal.h"
-#import "RTCMediaStream+internal.h"
-#import "RTCMediaStreamTrack+internal.h"
-#import "RTCPeerConnection+internal.h"
+#import "RTCAudioTrack+Internal.h"
+#import "RTCICEServer+Internal.h"
+#import "RTCMediaConstraints+Internal.h"
+#import "RTCMediaSource+Internal.h"
+#import "RTCMediaStream+Internal.h"
+#import "RTCMediaStreamTrack+Internal.h"
+#import "RTCPeerConnection+Internal.h"
#import "RTCPeerConnectionDelegate.h"
-#import "RTCPeerConnectionObserver.h"
-#import "RTCVideoCapturer+internal.h"
-#import "RTCVideoSource+internal.h"
-#import "RTCVideoTrack+internal.h"
+#import "RTCVideoCapturer+Internal.h"
+#import "RTCVideoSource+Internal.h"
+#import "RTCVideoTrack+Internal.h"
#include "talk/app/webrtc/audiotrack.h"
#include "talk/app/webrtc/mediastreaminterface.h"
@@ -86,54 +85,48 @@
return self;
}
-- (RTCPeerConnection *)
- peerConnectionWithICEServers:(NSArray *)servers
- constraints:(RTCMediaConstraints *)constraints
+- (RTCPeerConnection*)
+ peerConnectionWithICEServers:(NSArray*)servers
+ constraints:(RTCMediaConstraints*)constraints
delegate:(id<RTCPeerConnectionDelegate>)delegate {
webrtc::PeerConnectionInterface::IceServers iceServers;
- for (RTCICEServer *server in servers) {
+ for (RTCICEServer* server in servers) {
iceServers.push_back(server.iceServer);
}
- webrtc::RTCPeerConnectionObserver *observer =
- new webrtc::RTCPeerConnectionObserver(delegate);
- webrtc::DTLSIdentityServiceInterface* dummy_dtls_identity_service = NULL;
- talk_base::scoped_refptr<webrtc::PeerConnectionInterface> peerConnection =
- self.nativeFactory->CreatePeerConnection(
- iceServers, constraints.constraints, dummy_dtls_identity_service,
- observer);
- RTCPeerConnection *pc =
- [[RTCPeerConnection alloc] initWithPeerConnection:peerConnection
- observer:observer];
- observer->SetPeerConnection(pc);
+ RTCPeerConnection* pc =
+ [[RTCPeerConnection alloc] initWithFactory:self.nativeFactory.get()
+ iceServers:iceServers
+ constraints:constraints.constraints];
+ pc.delegate = delegate;
return pc;
}
-- (RTCMediaStream *)mediaStreamWithLabel:(NSString *)label {
+- (RTCMediaStream*)mediaStreamWithLabel:(NSString*)label {
talk_base::scoped_refptr<webrtc::MediaStreamInterface> nativeMediaStream =
self.nativeFactory->CreateLocalMediaStream([label UTF8String]);
return [[RTCMediaStream alloc] initWithMediaStream:nativeMediaStream];
}
-- (RTCVideoSource *)videoSourceWithCapturer:(RTCVideoCapturer *)capturer
- constraints:(RTCMediaConstraints *)constraints {
+- (RTCVideoSource*)videoSourceWithCapturer:(RTCVideoCapturer*)capturer
+ constraints:(RTCMediaConstraints*)constraints {
if (!capturer) {
return nil;
}
talk_base::scoped_refptr<webrtc::VideoSourceInterface> source =
- self.nativeFactory->CreateVideoSource(capturer.capturer.get(),
+ self.nativeFactory->CreateVideoSource([capturer takeNativeCapturer],
constraints.constraints);
return [[RTCVideoSource alloc] initWithMediaSource:source];
}
-- (RTCVideoTrack *)videoTrackWithID:(NSString *)videoId
- source:(RTCVideoSource *)source {
+- (RTCVideoTrack*)videoTrackWithID:(NSString*)videoId
+ source:(RTCVideoSource*)source {
talk_base::scoped_refptr<webrtc::VideoTrackInterface> track =
self.nativeFactory->CreateVideoTrack([videoId UTF8String],
source.videoSource);
return [[RTCVideoTrack alloc] initWithMediaTrack:track];
}
-- (RTCAudioTrack *)audioTrackWithID:(NSString *)audioId {
+- (RTCAudioTrack*)audioTrackWithID:(NSString*)audioId {
talk_base::scoped_refptr<webrtc::AudioTrackInterface> track =
self.nativeFactory->CreateAudioTrack([audioId UTF8String], NULL);
return [[RTCAudioTrack alloc] initWithMediaTrack:track];
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionObserver.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionObserver.h
index c7d1ef8b8c4..f66b5672ef7 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionObserver.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionObserver.h
@@ -38,9 +38,8 @@ namespace webrtc {
class RTCPeerConnectionObserver : public PeerConnectionObserver {
public:
- explicit RTCPeerConnectionObserver(id<RTCPeerConnectionDelegate> delegate);
-
- void SetPeerConnection(RTCPeerConnection *peerConnection);
+ RTCPeerConnectionObserver(RTCPeerConnection* peerConnection);
+ virtual ~RTCPeerConnectionObserver();
virtual void OnError() OVERRIDE;
@@ -57,7 +56,7 @@ class RTCPeerConnectionObserver : public PeerConnectionObserver {
// Triggered when a remote peer open a data channel.
virtual void OnDataChannel(DataChannelInterface* data_channel) OVERRIDE;
- // Triggered when renegotation is needed, for example the ICE has restarted.
+ // Triggered when renegotiation is needed, for example the ICE has restarted.
virtual void OnRenegotiationNeeded() OVERRIDE;
// Called any time the ICEConnectionState changes
@@ -72,8 +71,7 @@ class RTCPeerConnectionObserver : public PeerConnectionObserver {
virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE;
private:
- id<RTCPeerConnectionDelegate> _delegate;
- RTCPeerConnection *_peerConnection;
+ __weak RTCPeerConnection* _peerConnection;
};
} // namespace webrtc
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionObserver.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionObserver.mm
index e102bb974fb..061ccf0a92d 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionObserver.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCPeerConnectionObserver.mm
@@ -31,73 +31,82 @@
#import "RTCPeerConnectionObserver.h"
-#import "RTCICECandidate+internal.h"
-#import "RTCMediaStream+internal.h"
+#import "RTCDataChannel+Internal.h"
+#import "RTCICECandidate+Internal.h"
+#import "RTCMediaStream+Internal.h"
#import "RTCEnumConverter.h"
namespace webrtc {
RTCPeerConnectionObserver::RTCPeerConnectionObserver(
- id<RTCPeerConnectionDelegate> delegate) {
- _delegate = delegate;
+ RTCPeerConnection* peerConnection) {
+ _peerConnection = peerConnection;
}
-void RTCPeerConnectionObserver::SetPeerConnection(
- RTCPeerConnection *peerConnection) {
- _peerConnection = peerConnection;
+RTCPeerConnectionObserver::~RTCPeerConnectionObserver() {
}
void RTCPeerConnectionObserver::OnError() {
- [_delegate peerConnectionOnError:_peerConnection];
+ [_peerConnection.delegate peerConnectionOnError:_peerConnection];
}
void RTCPeerConnectionObserver::OnSignalingChange(
PeerConnectionInterface::SignalingState new_state) {
- [_delegate peerConnection:_peerConnection
- signalingStateChanged:
- [RTCEnumConverter convertSignalingStateToObjC:new_state]];
+ RTCSignalingState state =
+ [RTCEnumConverter convertSignalingStateToObjC:new_state];
+ [_peerConnection.delegate peerConnection:_peerConnection
+ signalingStateChanged:state];
}
void RTCPeerConnectionObserver::OnAddStream(MediaStreamInterface* stream) {
RTCMediaStream* mediaStream =
[[RTCMediaStream alloc] initWithMediaStream:stream];
- [_delegate peerConnection:_peerConnection addedStream:mediaStream];
+ [_peerConnection.delegate peerConnection:_peerConnection
+ addedStream:mediaStream];
}
void RTCPeerConnectionObserver::OnRemoveStream(MediaStreamInterface* stream) {
RTCMediaStream* mediaStream =
[[RTCMediaStream alloc] initWithMediaStream:stream];
- [_delegate peerConnection:_peerConnection removedStream:mediaStream];
+ [_peerConnection.delegate peerConnection:_peerConnection
+ removedStream:mediaStream];
}
void RTCPeerConnectionObserver::OnDataChannel(
DataChannelInterface* data_channel) {
- // TODO(hughv): Implement for future version.
+ RTCDataChannel* dataChannel =
+ [[RTCDataChannel alloc] initWithDataChannel:data_channel];
+ [_peerConnection.delegate peerConnection:_peerConnection
+ didOpenDataChannel:dataChannel];
}
void RTCPeerConnectionObserver::OnRenegotiationNeeded() {
- [_delegate peerConnectionOnRenegotiationNeeded:_peerConnection];
+ id<RTCPeerConnectionDelegate> delegate = _peerConnection.delegate;
+ [delegate peerConnectionOnRenegotiationNeeded:_peerConnection];
}
void RTCPeerConnectionObserver::OnIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) {
- [_delegate peerConnection:_peerConnection
- iceConnectionChanged:
- [RTCEnumConverter convertIceConnectionStateToObjC:new_state]];
+ RTCICEConnectionState state =
+ [RTCEnumConverter convertIceConnectionStateToObjC:new_state];
+ [_peerConnection.delegate peerConnection:_peerConnection
+ iceConnectionChanged:state];
}
void RTCPeerConnectionObserver::OnIceGatheringChange(
PeerConnectionInterface::IceGatheringState new_state) {
- [_delegate peerConnection:_peerConnection
- iceGatheringChanged:
- [RTCEnumConverter convertIceGatheringStateToObjC:new_state]];
+ RTCICEGatheringState state =
+ [RTCEnumConverter convertIceGatheringStateToObjC:new_state];
+ [_peerConnection.delegate peerConnection:_peerConnection
+ iceGatheringChanged:state];
}
void RTCPeerConnectionObserver::OnIceCandidate(
const IceCandidateInterface* candidate) {
RTCICECandidate* iceCandidate =
[[RTCICECandidate alloc] initWithCandidate:candidate];
- [_delegate peerConnection:_peerConnection gotICECandidate:iceCandidate];
+ [_peerConnection.delegate peerConnection:_peerConnection
+ gotICECandidate:iceCandidate];
}
-} // namespace webrtc
+} // namespace webrtc
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCSessionDescription.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCSessionDescription.mm
index dd2bbdc1410..49dfa2d9cb5 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCSessionDescription.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCSessionDescription.mm
@@ -29,14 +29,14 @@
#error "This file requires ARC support."
#endif
-#import "RTCSessionDescription+internal.h"
+#import "RTCSessionDescription+Internal.h"
@implementation RTCSessionDescription
@synthesize description = _description;
@synthesize type = _type;
-- (id)initWithType:(NSString *)type sdp:(NSString *)sdp {
+- (id)initWithType:(NSString*)type sdp:(NSString*)sdp {
if (!type || !sdp) {
NSAssert(NO, @"nil arguments not allowed");
return nil;
@@ -53,14 +53,14 @@
@implementation RTCSessionDescription (Internal)
- (id)initWithSessionDescription:
- (const webrtc::SessionDescriptionInterface *)sessionDescription {
+ (const webrtc::SessionDescriptionInterface*)sessionDescription {
if (!sessionDescription) {
NSAssert(NO, @"nil arguments not allowed");
self = nil;
return nil;
}
if ((self = [super init])) {
- const std::string &type = sessionDescription->type();
+ const std::string& type = sessionDescription->type();
std::string sdp;
if (!sessionDescription->ToString(&sdp)) {
NSAssert(NO, @"Invalid SessionDescriptionInterface.");
@@ -73,7 +73,7 @@
return self;
}
-- (webrtc::SessionDescriptionInterface *)sessionDescription {
+- (webrtc::SessionDescriptionInterface*)sessionDescription {
return webrtc::CreateSessionDescription(
[self.type UTF8String], [self.description UTF8String], NULL);
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCStatsReport+Internal.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCStatsReport+Internal.h
new file mode 100644
index 00000000000..b17b01a2fbb
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCStatsReport+Internal.h
@@ -0,0 +1,36 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "RTCStatsReport.h"
+
+#include "talk/app/webrtc/statstypes.h"
+
+@interface RTCStatsReport (Internal)
+
+- (instancetype)initWithStatsReport:(const webrtc::StatsReport&)statsReport;
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCStatsReport.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCStatsReport.mm
new file mode 100644
index 00000000000..8da4b469a0f
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCStatsReport.mm
@@ -0,0 +1,69 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "RTCStatsReport+Internal.h"
+
+#import "RTCPair.h"
+
+@implementation RTCStatsReport
+
+- (NSString*)description {
+ NSString* format = @"id: %@, type: %@, timestamp: %f, values: %@";
+ return [NSString stringWithFormat:format,
+ self.reportId,
+ self.type,
+ self.timestamp,
+ self.values];
+}
+
+@end
+
+@implementation RTCStatsReport (Internal)
+
+- (instancetype)initWithStatsReport:(const webrtc::StatsReport&)statsReport {
+ if (self = [super init]) {
+ _reportId = @(statsReport.id.c_str());
+ _type = @(statsReport.type.c_str());
+ _timestamp = statsReport.timestamp;
+ NSMutableArray* values =
+ [NSMutableArray arrayWithCapacity:statsReport.values.size()];
+ webrtc::StatsReport::Values::const_iterator it = statsReport.values.begin();
+ for (; it != statsReport.values.end(); ++it) {
+ RTCPair* pair = [[RTCPair alloc] initWithKey:@(it->name.c_str())
+ value:@(it->value.c_str())];
+ [values addObject:pair];
+ }
+ _values = values;
+ }
+ return self;
+}
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoCapturer+Internal.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoCapturer+Internal.h
index d0d685b2c9f..4a4810b471a 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoCapturer+Internal.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoCapturer+Internal.h
@@ -31,7 +31,7 @@
@interface RTCVideoCapturer (Internal)
-@property(nonatomic, assign, readonly) const talk_base::scoped_ptr<cricket::VideoCapturer> &capturer;
+- (cricket::VideoCapturer*)takeNativeCapturer;
- (id)initWithCapturer:(cricket::VideoCapturer*)capturer;
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoCapturer.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoCapturer.mm
index f7282c55d87..d947f02adec 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoCapturer.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoCapturer.mm
@@ -29,17 +29,17 @@
#error "This file requires ARC support."
#endif
-#import "RTCVideoCapturer+internal.h"
+#import "RTCVideoCapturer+Internal.h"
#include "talk/media/base/videocapturer.h"
#include "talk/media/devices/devicemanager.h"
@implementation RTCVideoCapturer {
- talk_base::scoped_ptr<cricket::VideoCapturer>_capturer;
+ talk_base::scoped_ptr<cricket::VideoCapturer> _capturer;
}
-+ (RTCVideoCapturer *)capturerWithDeviceName:(NSString *)deviceName {
- const std::string &device_name = std::string([deviceName UTF8String]);
++ (RTCVideoCapturer*)capturerWithDeviceName:(NSString*)deviceName {
+ const std::string& device_name = std::string([deviceName UTF8String]);
talk_base::scoped_ptr<cricket::DeviceManagerInterface> device_manager(
cricket::DeviceManagerFactory::Create());
bool initialized = device_manager->Init();
@@ -51,7 +51,7 @@
}
talk_base::scoped_ptr<cricket::VideoCapturer> capturer(
device_manager->CreateVideoCapturer(device));
- RTCVideoCapturer *rtcCapturer =
+ RTCVideoCapturer* rtcCapturer =
[[RTCVideoCapturer alloc] initWithCapturer:capturer.release()];
return rtcCapturer;
}
@@ -60,17 +60,15 @@
@implementation RTCVideoCapturer (Internal)
-- (id)initWithCapturer:(cricket::VideoCapturer *)capturer {
+- (id)initWithCapturer:(cricket::VideoCapturer*)capturer {
if ((self = [super init])) {
_capturer.reset(capturer);
}
return self;
}
-// TODO(hughv): When capturer is implemented, this needs to return
-// _capturer.release() instead. For now, this isn't used.
-- (const talk_base::scoped_ptr<cricket::VideoCapturer> &)capturer {
- return _capturer;
+- (cricket::VideoCapturer*)takeNativeCapturer {
+ return _capturer.release();
}
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoRenderer+Internal.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoRenderer+Internal.h
index 8854ed71ff4..22e445ccc9d 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoRenderer+Internal.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoRenderer+Internal.h
@@ -31,10 +31,6 @@
@interface RTCVideoRenderer (Internal)
-// TODO(hughv): Use smart pointer.
-@property(nonatomic, assign, readonly)
- webrtc::VideoRendererInterface *videoRenderer;
-
-- (id)initWithVideoRenderer:(webrtc::VideoRendererInterface *)videoRenderer;
+@property(nonatomic, readonly) webrtc::VideoRendererInterface* videoRenderer;
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoRenderer.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoRenderer.mm
index 23136152109..07041819f65 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoRenderer.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoRenderer.mm
@@ -29,46 +29,74 @@
#error "This file requires ARC support."
#endif
-#import "RTCVideoRenderer+internal.h"
+#import "RTCVideoRenderer+Internal.h"
#if TARGET_OS_IPHONE
-#import <UIKit/UIKit.h>
+#import "RTCEAGLVideoView+Internal.h"
#endif
+#import "RTCI420Frame+Internal.h"
-#import "RTCI420Frame.h"
-#import "RTCVideoRendererDelegate.h"
+namespace webrtc {
-@implementation RTCVideoRenderer
+class RTCVideoRendererAdapter : public VideoRendererInterface {
+ public:
+ RTCVideoRendererAdapter(RTCVideoRenderer* renderer) { _renderer = renderer; }
-@synthesize delegate = _delegate;
+ virtual void SetSize(int width, int height) OVERRIDE {
+ [_renderer.delegate renderer:_renderer
+ didSetSize:CGSizeMake(width, height)];
+ }
+
+ virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
+ if (!_renderer.delegate) {
+ return;
+ }
+ RTCI420Frame* i420Frame = [[RTCI420Frame alloc] initWithVideoFrame:frame];
+ [_renderer.delegate renderer:_renderer didReceiveFrame:i420Frame];
+ }
-+ (RTCVideoRenderer *)videoRenderGUIWithFrame:(CGRect)frame {
- // TODO (hughv): Implement.
- return nil;
+ private:
+ __weak RTCVideoRenderer* _renderer;
+};
}
-- (id)initWithDelegate:(id<RTCVideoRendererDelegate>)delegate {
- if ((self = [super init])) {
+@implementation RTCVideoRenderer {
+ talk_base::scoped_ptr<webrtc::RTCVideoRendererAdapter> _adapter;
+#if TARGET_OS_IPHONE
+ RTCEAGLVideoView* _videoView;
+#endif
+}
+
+- (instancetype)initWithDelegate:(id<RTCVideoRendererDelegate>)delegate {
+ if (self = [super init]) {
_delegate = delegate;
- // TODO (hughv): Create video renderer.
+ _adapter.reset(new webrtc::RTCVideoRendererAdapter(self));
}
return self;
}
-@end
-
-@implementation RTCVideoRenderer (Internal)
-
-- (id)initWithVideoRenderer:(webrtc::VideoRendererInterface *)videoRenderer {
- if ((self = [super init])) {
- // TODO (hughv): Implement.
+#if TARGET_OS_IPHONE
+// TODO(tkchin): remove shim for deprecated method.
+- (instancetype)initWithView:(UIView*)view {
+ if (self = [super init]) {
+ _videoView = [[RTCEAGLVideoView alloc] initWithFrame:view.bounds];
+ _videoView.autoresizingMask =
+ UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
+ _videoView.translatesAutoresizingMaskIntoConstraints = YES;
+ [view addSubview:_videoView];
+ self.delegate = _videoView;
+ _adapter.reset(new webrtc::RTCVideoRendererAdapter(self));
}
return self;
}
+#endif
+
+@end
+
+@implementation RTCVideoRenderer (Internal)
-- (webrtc::VideoRendererInterface *)videoRenderer {
- // TODO (hughv): Implement.
- return NULL;
+- (webrtc::VideoRendererInterface*)videoRenderer {
+ return _adapter.get();
}
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoSource.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoSource.mm
index c28fa9bcfcd..b4554e08d22 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoSource.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoSource.mm
@@ -29,8 +29,8 @@
#error "This file requires ARC support."
#endif
-#import "RTCVideoSource+internal.h"
-#import "RTCMediaSource+internal.h"
+#import "RTCVideoSource+Internal.h"
+#import "RTCMediaSource+Internal.h"
@implementation RTCVideoSource
@end
@@ -38,7 +38,7 @@
@implementation RTCVideoSource (Internal)
- (talk_base::scoped_refptr<webrtc::VideoSourceInterface>)videoSource {
- return static_cast<webrtc::VideoSourceInterface *>(self.mediaSource.get());
+ return static_cast<webrtc::VideoSourceInterface*>(self.mediaSource.get());
}
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoTrack.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoTrack.mm
index 88f7226a11e..d6c8ed8a4f5 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoTrack.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/RTCVideoTrack.mm
@@ -29,24 +29,25 @@
#error "This file requires ARC support."
#endif
-#import "RTCVideoTrack+internal.h"
+#import "RTCVideoTrack+Internal.h"
-#import "RTCMediaStreamTrack+internal.h"
-#import "RTCVideoRenderer+internal.h"
+#import "RTCMediaStreamTrack+Internal.h"
+#import "RTCVideoRenderer+Internal.h"
@implementation RTCVideoTrack {
- NSMutableArray *_rendererArray;
+ NSMutableArray* _rendererArray;
}
-- (id)initWithMediaTrack:(
- talk_base::scoped_refptr<webrtc::MediaStreamTrackInterface>)mediaTrack {
+- (id)initWithMediaTrack:
+ (talk_base::scoped_refptr<webrtc::MediaStreamTrackInterface>)
+ mediaTrack {
if (self = [super initWithMediaTrack:mediaTrack]) {
_rendererArray = [NSMutableArray array];
}
return self;
}
-- (void)addRenderer:(RTCVideoRenderer *)renderer {
+- (void)addRenderer:(RTCVideoRenderer*)renderer {
NSAssert1(![self.renderers containsObject:renderer],
@"renderers already contains object [%@]",
[renderer description]);
@@ -54,7 +55,7 @@
self.videoTrack->AddRenderer(renderer.videoRenderer);
}
-- (void)removeRenderer:(RTCVideoRenderer *)renderer {
+- (void)removeRenderer:(RTCVideoRenderer*)renderer {
NSUInteger index = [self.renderers indexOfObjectIdenticalTo:renderer];
if (index != NSNotFound) {
[_rendererArray removeObjectAtIndex:index];
@@ -62,7 +63,7 @@
}
}
-- (NSArray *)renderers {
+- (NSArray*)renderers {
return [_rendererArray copy];
}
@@ -71,7 +72,7 @@
@implementation RTCVideoTrack (Internal)
- (talk_base::scoped_refptr<webrtc::VideoTrackInterface>)videoTrack {
- return static_cast<webrtc::VideoTrackInterface *>(self.mediaTrack.get());
+ return static_cast<webrtc::VideoTrackInterface*>(self.mediaTrack.get());
}
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCDataChannel.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCDataChannel.h
new file mode 100644
index 00000000000..762bd662e8a
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCDataChannel.h
@@ -0,0 +1,112 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Foundation/Foundation.h>
+
+// ObjectiveC wrapper for a DataChannelInit object.
+@interface RTCDataChannelInit : NSObject
+
+// Set to YES if ordered delivery is required
+@property(nonatomic) BOOL isOrdered;
+// Max period in milliseconds in which retransmissions will be sent. After this
+// time, no more retransmissions will be sent. -1 if unset.
+@property(nonatomic) NSInteger maxRetransmitTimeMs;
+// The max number of retransmissions. -1 if unset.
+@property(nonatomic) NSInteger maxRetransmits;
+// Set to YES if the channel has been externally negotiated and we do not send
+// an in-band signalling in the form of an "open" message
+@property(nonatomic) BOOL isNegotiated;
+// The stream id, or SID, for SCTP data channels. -1 if unset.
+@property(nonatomic) NSInteger streamId;
+// Set by the application and opaque to the WebRTC implementation.
+@property(nonatomic) NSString* protocol;
+
+@end
+
+// ObjectiveC wrapper for a DataBuffer object.
+@interface RTCDataBuffer : NSObject
+
+@property(nonatomic, readonly) NSData* data;
+@property(nonatomic, readonly) BOOL isBinary;
+
+- (instancetype)initWithData:(NSData*)data isBinary:(BOOL)isBinary;
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+// Disallow init and don't add to documentation
+- (id)init __attribute__((
+ unavailable("init is not a supported initializer for this class.")));
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+@end
+
+// Keep in sync with webrtc::DataChannelInterface::DataState
+typedef enum {
+ kRTCDataChannelStateConnecting,
+ kRTCDataChannelStateOpen,
+ kRTCDataChannelStateClosing,
+ kRTCDataChannelStateClosed
+} RTCDataChannelState;
+
+@class RTCDataChannel;
+// Protocol for receving data channel state and message events.
+@protocol RTCDataChannelDelegate<NSObject>
+
+// Called when the data channel state has changed.
+- (void)channelDidChangeState:(RTCDataChannel*)channel;
+
+// Called when a data buffer was successfully received.
+- (void)channel:(RTCDataChannel*)channel
+ didReceiveMessageWithBuffer:(RTCDataBuffer*)buffer;
+
+@end
+
+// ObjectiveC wrapper for a DataChannel object.
+// See talk/app/webrtc/datachannelinterface.h
+@interface RTCDataChannel : NSObject
+
+@property(nonatomic, readonly) NSString* label;
+@property(nonatomic, readonly) BOOL isReliable;
+@property(nonatomic, readonly) BOOL isOrdered;
+@property(nonatomic, readonly) NSUInteger maxRetransmitTime;
+@property(nonatomic, readonly) NSUInteger maxRetransmits;
+@property(nonatomic, readonly) NSString* protocol;
+@property(nonatomic, readonly) BOOL isNegotiated;
+@property(nonatomic, readonly) NSInteger streamId;
+@property(nonatomic, readonly) RTCDataChannelState state;
+@property(nonatomic, readonly) NSUInteger bufferedAmount;
+@property(nonatomic, weak) id<RTCDataChannelDelegate> delegate;
+
+- (void)close;
+- (BOOL)sendData:(RTCDataBuffer*)data;
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+// Disallow init and don't add to documentation
+- (id)init __attribute__((
+ unavailable("init is not a supported initializer for this class.")));
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCVideoRendererDelegate.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCEAGLVideoView.h
index af72bdeb9a1..c38799e86f9 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCVideoRendererDelegate.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCEAGLVideoView.h
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2013, Google Inc.
+ * Copyright 2014, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,19 +26,22 @@
*/
#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
-@class RTCI420Frame;
-@class RTCVideoRenderer;
+#import "RTCVideoRenderer.h"
-// RTCVideoRendererDelegate is a protocol for an object that must be
-// implemented to get messages when rendering.
-@protocol RTCVideoRendererDelegate<NSObject>
+@class RTCEAGLVideoView;
+@protocol RTCEAGLVideoViewDelegate
-// The size of the frame.
-- (void)videoRenderer:(RTCVideoRenderer *)videoRenderer setSize:(CGSize)size;
+- (void)videoView:(RTCEAGLVideoView*)videoView didChangeVideoSize:(CGSize)size;
-// The frame to be displayed.
-- (void)videoRenderer:(RTCVideoRenderer *)videoRenderer
- renderFrame:(RTCI420Frame *)frame;
+@end
+
+@class RTCVideoTrack;
+// RTCEAGLVideoView renders |videoTrack| onto itself using OpenGLES.
+@interface RTCEAGLVideoView : UIView
+
+@property(nonatomic, strong) RTCVideoTrack* videoTrack;
+@property(nonatomic, weak) id<RTCEAGLVideoViewDelegate> delegate;
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCI420Frame.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCI420Frame.h
index bf58085da06..737968c123d 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCI420Frame.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCI420Frame.h
@@ -30,7 +30,24 @@
// RTCI420Frame is an ObjectiveC version of cricket::VideoFrame.
@interface RTCI420Frame : NSObject
-// TODO(hughv): Implement this when iOS VP8 is ready.
+@property(nonatomic, readonly) NSUInteger width;
+@property(nonatomic, readonly) NSUInteger height;
+@property(nonatomic, readonly) NSUInteger chromaWidth;
+@property(nonatomic, readonly) NSUInteger chromaHeight;
+@property(nonatomic, readonly) NSUInteger chromaSize;
+// These can return NULL if the object is not backed by a buffer.
+@property(nonatomic, readonly) const uint8_t* yPlane;
+@property(nonatomic, readonly) const uint8_t* uPlane;
+@property(nonatomic, readonly) const uint8_t* vPlane;
+@property(nonatomic, readonly) NSInteger yPitch;
+@property(nonatomic, readonly) NSInteger uPitch;
+@property(nonatomic, readonly) NSInteger vPitch;
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+// Disallow init and don't add to documentation
+- (id)init __attribute__((
+ unavailable("init is not a supported initializer for this class.")));
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCICEServer.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCICEServer.h
index 63c14efaaf4..b0adbf1ed08 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCICEServer.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCICEServer.h
@@ -35,8 +35,8 @@
@property(nonatomic, copy, readonly) NSString* username;
@property(nonatomic, copy, readonly) NSString* password;
-// Initializer for RTCICEServer taking uri and password.
-- (id)initWithURI:(NSString*)URI
+// Initializer for RTCICEServer taking uri, username, and password.
+- (id)initWithURI:(NSURL*)URI
username:(NSString*)username
password:(NSString*)password;
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCMediaSource.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCMediaSource.h
index be3ad329186..e31817f3f7f 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCMediaSource.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCMediaSource.h
@@ -33,12 +33,12 @@
@interface RTCMediaSource : NSObject
// The current state of the RTCMediaSource.
-@property (nonatomic, assign, readonly)RTCSourceState state;
+@property(nonatomic, assign, readonly) RTCSourceState state;
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// Disallow init and don't add to documentation
-- (id)init __attribute__(
- (unavailable("init is not a supported initializer for this class.")));
+- (id)init __attribute__((
+ unavailable("init is not a supported initializer for this class.")));
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCMediaStreamTrack.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCMediaStreamTrack.h
index f8f9369b5ca..1b9339d76b2 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCMediaStreamTrack.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCMediaStreamTrack.h
@@ -29,13 +29,21 @@
#import "RTCTypes.h"
+@class RTCMediaStreamTrack;
+@protocol RTCMediaStreamTrackDelegate<NSObject>
+
+- (void)mediaStreamTrackDidChange:(RTCMediaStreamTrack*)mediaStreamTrack;
+
+@end
+
// RTCMediaStreamTrack implements the interface common to RTCAudioTrack and
// RTCVideoTrack. Do not create an instance of this class, rather create one
// of the derived classes.
@interface RTCMediaStreamTrack : NSObject
-@property(nonatomic, assign, readonly) NSString *kind;
-@property(nonatomic, assign, readonly) NSString *label;
+@property(nonatomic, readonly) NSString* kind;
+@property(nonatomic, readonly) NSString* label;
+@property(nonatomic, weak) id<RTCMediaStreamTrackDelegate> delegate;
- (BOOL)isEnabled;
- (BOOL)setEnabled:(BOOL)enabled;
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCNSGLVideoView.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCNSGLVideoView.h
new file mode 100644
index 00000000000..fd757cb43c5
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCNSGLVideoView.h
@@ -0,0 +1,48 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if TARGET_OS_IPHONE
+#error "This file targets OSX."
+#endif
+
+#import <AppKit/NSOpenGLView.h>
+
+#import "RTCVideoTrack.h"
+
+@class RTCNSGLVideoView;
+@protocol RTCNSGLVideoViewDelegate
+
+- (void)videoView:(RTCNSGLVideoView*)videoView didChangeVideoSize:(CGSize)size;
+
+@end
+
+@interface RTCNSGLVideoView : NSOpenGLView
+
+@property(nonatomic, strong) RTCVideoTrack* videoTrack;
+@property(nonatomic, weak) id<RTCNSGLVideoViewDelegate> delegate;
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCOpenGLVideoRenderer.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCOpenGLVideoRenderer.h
new file mode 100644
index 00000000000..d6744b23fa9
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCOpenGLVideoRenderer.h
@@ -0,0 +1,73 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Foundation/Foundation.h>
+#if TARGET_OS_IPHONE
+#import <GLKit/GLKit.h>
+#else
+#import <AppKit/NSOpenGL.h>
+#endif
+
+@class RTCI420Frame;
+
+// RTCOpenGLVideoRenderer issues appropriate OpenGL commands to draw a frame to
+// the currently bound framebuffer. Supports OpenGL 3.2 and OpenGLES 2.0. OpenGL
+// framebuffer creation and management should be handled elsewhere using the
+// same context used to initialize this class.
+@interface RTCOpenGLVideoRenderer : NSObject
+
+// The last successfully drawn frame. Used to avoid drawing frames unnecessarily
+// hence saving battery life by reducing load.
+@property(nonatomic, readonly) RTCI420Frame* lastDrawnFrame;
+
+#if TARGET_OS_IPHONE
+- (instancetype)initWithContext:(EAGLContext*)context;
+#else
+- (instancetype)initWithContext:(NSOpenGLContext*)context;
+#endif
+
+// Draws |frame| onto the currently bound OpenGL framebuffer. |setupGL| must be
+// called before this function will succeed.
+- (BOOL)drawFrame:(RTCI420Frame*)frame;
+
+// The following methods are used to manage OpenGL resources. On iOS
+// applications should release resources when placed in background for use in
+// the foreground application. In fact, attempting to call OpenGLES commands
+// while in background will result in application termination.
+
+// Sets up the OpenGL state needed for rendering.
+- (void)setupGL;
+// Tears down the OpenGL state created by |setupGL|.
+- (void)teardownGL;
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+// Disallow init and don't add to documentation
+- (id)init __attribute__((
+ unavailable("init is not a supported initializer for this class.")));
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCPeerConnection.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCPeerConnection.h
index c66bac8b4cb..32a98306ef6 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCPeerConnection.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCPeerConnection.h
@@ -27,12 +27,16 @@
#import "RTCPeerConnectionDelegate.h"
+@class RTCDataChannel;
+@class RTCDataChannelInit;
@class RTCICECandidate;
@class RTCICEServers;
@class RTCMediaConstraints;
@class RTCMediaStream;
+@class RTCMediaStreamTrack;
@class RTCSessionDescription;
-@protocol RTCSessionDescriptonDelegate;
+@protocol RTCSessionDescriptionDelegate;
+@protocol RTCStatsDelegate;
// RTCPeerConnection is an ObjectiveC friendly wrapper around a PeerConnection
// object. See the documentation in talk/app/webrtc/peerconnectioninterface.h.
@@ -41,6 +45,8 @@
// http://www.w3.org/TR/mediacapture-streams/
@interface RTCPeerConnection : NSObject
+@property(nonatomic, weak) id<RTCPeerConnectionDelegate> delegate;
+
// Accessor methods to active local streams.
@property(nonatomic, strong, readonly) NSArray *localStreams;
@@ -66,26 +72,30 @@
// remote peer is notified.
- (void)removeStream:(RTCMediaStream *)stream;
+// Create a data channel.
+- (RTCDataChannel*)createDataChannelWithLabel:(NSString*)label
+ config:(RTCDataChannelInit*)config;
+
// Create a new offer.
-// Success or failure will be reported via RTCSessionDescriptonDelegate.
-- (void)createOfferWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
+// Success or failure will be reported via RTCSessionDescriptionDelegate.
+- (void)createOfferWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
constraints:(RTCMediaConstraints *)constraints;
// Create an answer to an offer.
-// Success or failure will be reported via RTCSessionDescriptonDelegate.
-- (void)createAnswerWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
+// Success or failure will be reported via RTCSessionDescriptionDelegate.
+- (void)createAnswerWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
constraints:(RTCMediaConstraints *)constraints;
// Sets the local session description.
-// Success or failure will be reported via RTCSessionDescriptonDelegate.
+// Success or failure will be reported via RTCSessionDescriptionDelegate.
- (void)
- setLocalDescriptionWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
+ setLocalDescriptionWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
sessionDescription:(RTCSessionDescription *)sdp;
// Sets the remote session description.
-// Success or failure will be reported via RTCSessionDescriptonDelegate.
+// Success or failure will be reported via RTCSessionDescriptionDelegate.
- (void)
- setRemoteDescriptionWithDelegate:(id<RTCSessionDescriptonDelegate>)delegate
+ setRemoteDescriptionWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
sessionDescription:(RTCSessionDescription *)sdp;
// Restarts or updates the ICE Agent process of gathering local candidates
@@ -99,7 +109,12 @@
// Terminates all media and closes the transport.
- (void)close;
-// TODO(hughv): Implement GetStats.
+// Gets statistics for the media track. If |mediaStreamTrack| is nil statistics
+// are gathered for all tracks.
+// Statistics information will be reported via RTCStatsDelegate.
+- (BOOL)getStatsWithDelegate:(id<RTCStatsDelegate>)delegate
+ mediaStreamTrack:(RTCMediaStreamTrack*)mediaStreamTrack
+ statsOutputLevel:(RTCStatsOutputLevel)statsOutputLevel;
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// Disallow init and don't add to documentation
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCPeerConnectionDelegate.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCPeerConnectionDelegate.h
index b3bb881da68..4b177d504fb 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCPeerConnectionDelegate.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCPeerConnectionDelegate.h
@@ -29,6 +29,7 @@
#import "RTCTypes.h"
+@class RTCDataChannel;
@class RTCICECandidate;
@class RTCMediaStream;
@class RTCPeerConnection;
@@ -52,7 +53,7 @@
- (void)peerConnection:(RTCPeerConnection *)peerConnection
removedStream:(RTCMediaStream *)stream;
-// Triggered when renegotation is needed, for example the ICE has restarted.
+// Triggered when renegotiation is needed, for example the ICE has restarted.
- (void)peerConnectionOnRenegotiationNeeded:(RTCPeerConnection *)peerConnection;
// Called any time the ICEConnectionState changes.
@@ -67,4 +68,8 @@
- (void)peerConnection:(RTCPeerConnection *)peerConnection
gotICECandidate:(RTCICECandidate *)candidate;
+// New data channel has been opened.
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ didOpenDataChannel:(RTCDataChannel*)dataChannel;
+
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCSessionDescriptonDelegate.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCSessionDescriptionDelegate.h
index 409aaee5d63..ecdc581f5e4 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCSessionDescriptonDelegate.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCSessionDescriptionDelegate.h
@@ -33,9 +33,9 @@
extern NSString* const kRTCSessionDescriptionDelegateErrorDomain;
extern int const kRTCSessionDescriptionDelegateErrorCode;
-// RTCSessionDescriptonDelegate is a protocol for listening to callback messages
-// when RTCSessionDescriptions are created or set.
-@protocol RTCSessionDescriptonDelegate<NSObject>
+// RTCSessionDescriptionDelegate is a protocol for listening to callback
+// messages when RTCSessionDescriptions are created or set.
+@protocol RTCSessionDescriptionDelegate<NSObject>
// Called when creating a session.
- (void)peerConnection:(RTCPeerConnection *)peerConnection
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCStatsDelegate.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCStatsDelegate.h
new file mode 100644
index 00000000000..3de3dfe9618
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCStatsDelegate.h
@@ -0,0 +1,39 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class RTCPeerConnection;
+
+// RTCSessionDescriptionDelegate is a protocol for receiving statistic
+// reports from RTCPeerConnection.
+@protocol RTCStatsDelegate<NSObject>
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ didGetStats:(NSArray*)stats; // NSArray of RTCStatsReport*.
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/plus/presencepushtask.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCStatsReport.h
index b9c8038b36a..784ce67410a 100644
--- a/chromium/third_party/libjingle/source/talk/examples/plus/presencepushtask.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCStatsReport.h
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2005, Google Inc.
+ * Copyright 2014, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,29 +25,21 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef _PRESENCEPUSHTASK_H_
-#define _PRESENCEPUSHTASK_H_
+#import <Foundation/Foundation.h>
-#include "talk/xmpp/xmppengine.h"
-#include "talk/xmpp/xmpptask.h"
-#include "talk/base/sigslot.h"
-#include "talk/app/status.h"
+// ObjectiveC friendly wrapper around a StatsReport object.
+// See talk/app/webrtc/statsypes.h
+@interface RTCStatsReport : NSObject
-namespace buzz {
+@property(nonatomic, readonly) NSString* reportId;
+@property(nonatomic, readonly) NSString* type;
+@property(nonatomic, readonly) CFTimeInterval timestamp;
+@property(nonatomic, readonly) NSArray* values; // NSArray of RTCPair*.
-class PresencePushTask : public XmppTask {
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+// Disallow init and don't add to documentation
+- (id)init __attribute__((
+ unavailable("init is not a supported initializer for this class.")));
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
-public:
- PresencePushTask(Task * parent) : XmppTask(parent, XmppEngine::HL_TYPE) {}
- virtual int ProcessStart();
- sigslot::signal1<const Status &>SignalStatusUpdate;
- sigslot::signal1<const XmlElement &> SignalStatusError;
-
-protected:
- virtual bool HandleStanza(const XmlElement * stanza);
-};
-
-
-}
-
-#endif
+@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCTypes.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCTypes.h
index 8ff8bf48593..2a55200a6ed 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCTypes.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCTypes.h
@@ -55,6 +55,12 @@ typedef enum {
RTCSignalingClosed,
} RTCSignalingState;
+// RTCStatsOutputLevel correspond to webrtc::StatsOutputLevel
+typedef enum {
+ RTCStatsOutputLevelStandard,
+ RTCStatsOutputLevelDebug,
+} RTCStatsOutputLevel;
+
// RTCSourceState corresponds to the states in webrtc::SourceState.
typedef enum {
RTCSourceStateInitializing,
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCVideoRenderer.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCVideoRenderer.h
index cc7ba718476..f78746c2fe8 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCVideoRenderer.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objc/public/RTCVideoRenderer.h
@@ -26,27 +26,45 @@
*/
#import <Foundation/Foundation.h>
+#if TARGET_OS_IPHONE
+#import <UIKit/UIKit.h>
+#endif
-@protocol RTCVideoRendererDelegate;
-struct CGRect;
+@class RTCI420Frame;
+@class RTCVideoRenderer;
+
+// RTCVideoRendererDelegate is a protocol for an object that must be
+// implemented to get messages when rendering.
+@protocol RTCVideoRendererDelegate<NSObject>
+
+// The size of the frame.
+- (void)renderer:(RTCVideoRenderer*)renderer didSetSize:(CGSize)size;
+
+// The frame to be displayed.
+- (void)renderer:(RTCVideoRenderer*)renderer
+ didReceiveFrame:(RTCI420Frame*)frame;
+
+@end
// Interface for rendering VideoFrames from a VideoTrack
@interface RTCVideoRenderer : NSObject
-@property(nonatomic, strong) id<RTCVideoRendererDelegate> delegate;
-
-// A convenience method to create a renderer and window and render frames into
-// that window.
-+ (RTCVideoRenderer *)videoRenderGUIWithFrame:(CGRect)frame;
+@property(nonatomic, weak) id<RTCVideoRendererDelegate> delegate;
// Initialize the renderer. Requires a delegate which does the actual drawing
// of frames.
-- (id)initWithDelegate:(id<RTCVideoRendererDelegate>)delegate;
+- (instancetype)initWithDelegate:(id<RTCVideoRendererDelegate>)delegate;
+
+#if TARGET_OS_IPHONE
+// DEPRECATED. See https://code.google.com/p/webrtc/issues/detail?id=3341 for
+// details.
+- (instancetype)initWithView:(UIView*)view;
+#endif
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// Disallow init and don't add to documentation
-- (id)init __attribute__(
- (unavailable("init is not a supported initializer for this class.")));
+- (id)init __attribute__((
+ unavailable("init is not a supported initializer for this class.")));
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/Info.plist b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/Info.plist
index 0b1583e6ea5..c2fb0617f33 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/Info.plist
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/Info.plist
@@ -18,21 +18,7 @@
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
- <key>CFBundleSignature</key>
- <string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
- <key>LSRequiresIPhoneOS</key>
- <true/>
- <key>UIRequiredDeviceCapabilities</key>
- <array>
- <string>armv7</string>
- </array>
- <key>UISupportedInterfaceOrientations</key>
- <array>
- <string>UIInterfaceOrientationPortrait</string>
- <string>UIInterfaceOrientationLandscapeLeft</string>
- <string>UIInterfaceOrientationLandscapeRight</string>
- </array>
</dict>
</plist>
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.h
index db97816fc90..8bbf9825115 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.h
@@ -27,11 +27,14 @@
#import <Foundation/Foundation.h>
+#import "RTCDataChannel.h"
#import "RTCPeerConnectionDelegate.h"
// Observer of PeerConnection events, used by RTCPeerConnectionTest to check
// expectations.
-@interface RTCPeerConnectionSyncObserver : NSObject<RTCPeerConnectionDelegate>
+@interface RTCPeerConnectionSyncObserver
+ : NSObject<RTCPeerConnectionDelegate, RTCDataChannelDelegate>
+@property(nonatomic) RTCDataChannel* dataChannel;
// TODO(hughv): Add support for RTCVideoRendererDelegate when Video is enabled.
// Transfer received ICE candidates to the caller.
@@ -46,6 +49,9 @@
- (void)expectICECandidates:(int)count;
- (void)expectICEConnectionChange:(RTCICEConnectionState)state;
- (void)expectICEGatheringChange:(RTCICEGatheringState)state;
+- (void)expectDataChannel:(NSString*)label;
+- (void)expectStateChange:(RTCDataChannelState)state;
+- (void)expectMessage:(NSData*)message isBinary:(BOOL)isBinary;
// Wait until all registered expectations above have been observed.
- (void)waitForAllExpectationsToBeSatisfied;
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m
index 0f33bac5cc6..c3f898a2945 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m
@@ -35,13 +35,16 @@
@implementation RTCPeerConnectionSyncObserver {
int _expectedErrors;
- NSMutableArray *_expectedSignalingChanges;
- NSMutableArray *_expectedAddStreamLabels;
- NSMutableArray *_expectedRemoveStreamLabels;
+ NSMutableArray* _expectedSignalingChanges;
+ NSMutableArray* _expectedAddStreamLabels;
+ NSMutableArray* _expectedRemoveStreamLabels;
int _expectedICECandidates;
- NSMutableArray *_receivedICECandidates;
- NSMutableArray *_expectedICEConnectionChanges;
- NSMutableArray *_expectedICEGatheringChanges;
+ NSMutableArray* _receivedICECandidates;
+ NSMutableArray* _expectedICEConnectionChanges;
+ NSMutableArray* _expectedICEGatheringChanges;
+ NSMutableArray* _expectedDataChannels;
+ NSMutableArray* _expectedStateChanges;
+ NSMutableArray* _expectedMessages;
}
- (id)init {
@@ -54,36 +57,41 @@
_receivedICECandidates = [NSMutableArray array];
_expectedICEConnectionChanges = [NSMutableArray array];
_expectedICEGatheringChanges = [NSMutableArray array];
+ _expectedDataChannels = [NSMutableArray array];
+ _expectedMessages = [NSMutableArray array];
+ _expectedStateChanges = [NSMutableArray array];
}
return self;
}
-- (int)popFirstElementAsInt:(NSMutableArray *)array {
+- (int)popFirstElementAsInt:(NSMutableArray*)array {
NSAssert([array count] > 0, @"Empty array");
- NSNumber *boxedState = [array objectAtIndex:0];
+ NSNumber* boxedState = [array objectAtIndex:0];
[array removeObjectAtIndex:0];
return [boxedState intValue];
}
-- (NSString *)popFirstElementAsNSString:(NSMutableArray *)array {
+- (NSString*)popFirstElementAsNSString:(NSMutableArray*)array {
NSAssert([array count] > 0, @"Empty expectation array");
- NSString *string = [array objectAtIndex:0];
+ NSString* string = [array objectAtIndex:0];
[array removeObjectAtIndex:0];
return string;
}
- (BOOL)areAllExpectationsSatisfied {
return _expectedICECandidates <= 0 && // See comment in gotICECandidate.
- _expectedErrors == 0 &&
- [_expectedSignalingChanges count] == 0 &&
+ _expectedErrors == 0 && [_expectedSignalingChanges count] == 0 &&
[_expectedICEConnectionChanges count] == 0 &&
[_expectedICEGatheringChanges count] == 0 &&
[_expectedAddStreamLabels count] == 0 &&
- [_expectedRemoveStreamLabels count] == 0;
+ [_expectedRemoveStreamLabels count] == 0 &&
+ [_expectedDataChannels count] == 0 &&
+ [_expectedStateChanges count] == 0 &&
+ [_expectedMessages count] == 0;
// TODO(hughv): Test video state here too.
}
-- (NSArray *)releaseReceivedICECandidates {
+- (NSArray*)releaseReceivedICECandidates {
NSArray* ret = _receivedICECandidates;
_receivedICECandidates = [NSMutableArray array];
return ret;
@@ -97,11 +105,11 @@
[_expectedSignalingChanges addObject:@((int)state)];
}
-- (void)expectAddStream:(NSString *)label {
+- (void)expectAddStream:(NSString*)label {
[_expectedAddStreamLabels addObject:label];
}
-- (void)expectRemoveStream:(NSString *)label {
+- (void)expectRemoveStream:(NSString*)label {
[_expectedRemoveStreamLabels addObject:label];
}
@@ -117,6 +125,20 @@
[_expectedICEGatheringChanges addObject:@((int)state)];
}
+- (void)expectDataChannel:(NSString*)label {
+ [_expectedDataChannels addObject:label];
+}
+
+- (void)expectStateChange:(RTCDataChannelState)state {
+ [_expectedStateChanges addObject:@(state)];
+}
+
+- (void)expectMessage:(NSData*)message isBinary:(BOOL)isBinary {
+ RTCDataBuffer* buffer = [[RTCDataBuffer alloc] initWithData:message
+ isBinary:isBinary];
+ [_expectedMessages addObject:buffer];
+}
+
- (void)waitForAllExpectationsToBeSatisfied {
// TODO (fischman): Revisit. Keeping in sync with the Java version, but
// polling is not optimal.
@@ -129,39 +151,41 @@
#pragma mark - RTCPeerConnectionDelegate methods
-- (void)peerConnectionOnError:(RTCPeerConnection *)peerConnection {
+- (void)peerConnectionOnError:(RTCPeerConnection*)peerConnection {
NSLog(@"RTCPeerConnectionDelegate::onError");
NSAssert(--_expectedErrors >= 0, @"Unexpected error");
}
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
signalingStateChanged:(RTCSignalingState)stateChanged {
int expectedState = [self popFirstElementAsInt:_expectedSignalingChanges];
- NSString *message = [NSString stringWithFormat: @"RTCPeerConnectionDelegate::"
- @"onSignalingStateChange [%d] expected[%d]", stateChanged, expectedState];
- NSAssert(expectedState == (int) stateChanged, message);
+ NSString* message =
+ [NSString stringWithFormat:@"RTCPeerConnectionDelegate::"
+ @"onSignalingStateChange [%d] expected[%d]",
+ stateChanged,
+ expectedState];
+ NSAssert(expectedState == (int)stateChanged, message);
}
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- addedStream:(RTCMediaStream *)stream {
- NSString *expectedLabel =
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ addedStream:(RTCMediaStream*)stream {
+ NSString* expectedLabel =
[self popFirstElementAsNSString:_expectedAddStreamLabels];
NSAssert([expectedLabel isEqual:stream.label], @"Stream not expected");
}
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- removedStream:(RTCMediaStream *)stream {
- NSString *expectedLabel =
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ removedStream:(RTCMediaStream*)stream {
+ NSString* expectedLabel =
[self popFirstElementAsNSString:_expectedRemoveStreamLabels];
NSAssert([expectedLabel isEqual:stream.label], @"Stream not expected");
}
-- (void)peerConnectionOnRenegotiationNeeded:
- (RTCPeerConnection *)peerConnection {
+- (void)peerConnectionOnRenegotiationNeeded:(RTCPeerConnection*)peerConnection {
}
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- gotICECandidate:(RTCICECandidate *)candidate {
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ gotICECandidate:(RTCICECandidate*)candidate {
--_expectedICECandidates;
// We don't assert expectedICECandidates >= 0 because it's hard to know
// how many to expect, in general. We only use expectICECandidates to
@@ -169,7 +193,7 @@
[_receivedICECandidates addObject:candidate];
}
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
iceGatheringChanged:(RTCICEGatheringState)newState {
// It's fine to get a variable number of GATHERING messages before
// COMPLETE fires (depending on how long the test runs) so we don't assert
@@ -181,10 +205,46 @@
NSAssert(expectedState == (int)newState, @"Empty expectation array");
}
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- iceConnectionChanged:(RTCICEConnectionState)newState {
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ iceConnectionChanged:(RTCICEConnectionState)newState {
+ // See TODO(fischman) in RTCPeerConnectionTest.mm about Completed.
+ if (newState == RTCICEConnectionCompleted)
+ return;
int expectedState = [self popFirstElementAsInt:_expectedICEConnectionChanges];
NSAssert(expectedState == (int)newState, @"Empty expectation array");
}
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ didOpenDataChannel:(RTCDataChannel*)dataChannel {
+ NSString* expectedLabel =
+ [self popFirstElementAsNSString:_expectedDataChannels];
+ NSAssert([expectedLabel isEqual:dataChannel.label],
+ @"Data channel not expected");
+ self.dataChannel = dataChannel;
+ dataChannel.delegate = self;
+ NSAssert(kRTCDataChannelStateConnecting == dataChannel.state,
+ @"Unexpected state");
+}
+
+#pragma mark - RTCDataChannelDelegate
+
+- (void)channelDidChangeState:(RTCDataChannel*)channel {
+ NSAssert([_expectedStateChanges count] > 0,
+ @"Unexpected state change");
+ int expectedState = [self popFirstElementAsInt:_expectedStateChanges];
+ NSAssert(expectedState == channel.state, @"Channel state should match");
+}
+
+- (void)channel:(RTCDataChannel*)channel
+ didReceiveMessageWithBuffer:(RTCDataBuffer*)buffer {
+ NSAssert([_expectedMessages count] > 0,
+ @"Unexpected message received");
+ RTCDataBuffer* expectedBuffer = [_expectedMessages objectAtIndex:0];
+ NSAssert(expectedBuffer.isBinary == buffer.isBinary,
+ @"Buffer isBinary should match");
+ NSAssert([expectedBuffer.data isEqual:buffer.data],
+ @"Buffer data should match");
+ [_expectedMessages removeObjectAtIndex:0];
+}
+
@end
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm
index 0ce8822fd1e..7a178f39fcd 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm
@@ -30,6 +30,7 @@
#import "RTCICEServer.h"
#import "RTCMediaConstraints.h"
#import "RTCMediaStream.h"
+#import "RTCPair.h"
#import "RTCPeerConnection.h"
#import "RTCPeerConnectionFactory.h"
#import "RTCPeerConnectionSyncObserver.h"
@@ -39,6 +40,7 @@
#import "RTCVideoTrack.h"
#include "talk/base/gunit.h"
+#include "talk/base/ssladapter.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
@@ -47,123 +49,126 @@
@interface RTCPeerConnectionTest : NSObject
// Returns whether the two sessions are of the same type.
-+ (BOOL)isSession:(RTCSessionDescription *)session1
- ofSameTypeAsSession:(RTCSessionDescription *)session2;
++ (BOOL)isSession:(RTCSessionDescription*)session1
+ ofSameTypeAsSession:(RTCSessionDescription*)session2;
// Create and add tracks to pc, with the given source, label, and IDs
-- (RTCMediaStream *)
- addTracksToPeerConnection:(RTCPeerConnection *)pc
- withFactory:(RTCPeerConnectionFactory *)factory
- videoSource:(RTCVideoSource *)videoSource
- streamLabel:(NSString *)streamLabel
- videoTrackID:(NSString *)videoTrackID
- audioTrackID:(NSString *)audioTrackID;
+- (RTCMediaStream*)addTracksToPeerConnection:(RTCPeerConnection*)pc
+ withFactory:(RTCPeerConnectionFactory*)factory
+ videoSource:(RTCVideoSource*)videoSource
+ streamLabel:(NSString*)streamLabel
+ videoTrackID:(NSString*)videoTrackID
+ audioTrackID:(NSString*)audioTrackID;
-- (void)testCompleteSession;
+- (void)testCompleteSessionWithFactory:(RTCPeerConnectionFactory*)factory;
@end
@implementation RTCPeerConnectionTest
-+ (BOOL)isSession:(RTCSessionDescription *)session1
- ofSameTypeAsSession:(RTCSessionDescription *)session2 {
++ (BOOL)isSession:(RTCSessionDescription*)session1
+ ofSameTypeAsSession:(RTCSessionDescription*)session2 {
return [session1.type isEqual:session2.type];
}
-- (RTCMediaStream *)
- addTracksToPeerConnection:(RTCPeerConnection *)pc
- withFactory:(RTCPeerConnectionFactory *)factory
- videoSource:(RTCVideoSource *)videoSource
- streamLabel:(NSString *)streamLabel
- videoTrackID:(NSString *)videoTrackID
- audioTrackID:(NSString *)audioTrackID {
- RTCMediaStream *localMediaStream = [factory mediaStreamWithLabel:streamLabel];
- RTCVideoTrack *videoTrack =
+- (RTCMediaStream*)addTracksToPeerConnection:(RTCPeerConnection*)pc
+ withFactory:(RTCPeerConnectionFactory*)factory
+ videoSource:(RTCVideoSource*)videoSource
+ streamLabel:(NSString*)streamLabel
+ videoTrackID:(NSString*)videoTrackID
+ audioTrackID:(NSString*)audioTrackID {
+ RTCMediaStream* localMediaStream = [factory mediaStreamWithLabel:streamLabel];
+ RTCVideoTrack* videoTrack =
[factory videoTrackWithID:videoTrackID source:videoSource];
- RTCVideoRenderer *videoRenderer =
+ RTCVideoRenderer* videoRenderer =
[[RTCVideoRenderer alloc] initWithDelegate:nil];
[videoTrack addRenderer:videoRenderer];
[localMediaStream addVideoTrack:videoTrack];
// Test that removal/re-add works.
[localMediaStream removeVideoTrack:videoTrack];
[localMediaStream addVideoTrack:videoTrack];
- RTCAudioTrack *audioTrack = [factory audioTrackWithID:audioTrackID];
+ RTCAudioTrack* audioTrack = [factory audioTrackWithID:audioTrackID];
[localMediaStream addAudioTrack:audioTrack];
- RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] init];
+ RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc] init];
[pc addStream:localMediaStream constraints:constraints];
return localMediaStream;
}
-- (void)testCompleteSession {
- RTCPeerConnectionFactory *factory = [[RTCPeerConnectionFactory alloc] init];
- NSString *stunURL = @"stun:stun.l.google.com:19302";
- RTCICEServer *stunServer =
- [[RTCICEServer alloc] initWithURI:[NSURL URLWithString:stunURL]
- username:@""
- password:@""];
- NSArray *iceServers = @[stunServer];
-
- RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] init];
- RTCPeerConnectionSyncObserver *offeringExpectations =
+- (void)testCompleteSessionWithFactory:(RTCPeerConnectionFactory*)factory {
+ NSArray* mandatory = @[
+ [[RTCPair alloc] initWithKey:@"DtlsSrtpKeyAgreement" value:@"true"],
+ [[RTCPair alloc] initWithKey:@"internalSctpDataChannels" value:@"true"],
+ ];
+ RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc] init];
+ RTCMediaConstraints* pcConstraints =
+ [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatory
+ optionalConstraints:nil];
+
+ RTCPeerConnectionSyncObserver* offeringExpectations =
[[RTCPeerConnectionSyncObserver alloc] init];
- RTCPeerConnection *pcOffer =
- [factory peerConnectionWithICEServers:iceServers
- constraints:constraints
+ RTCPeerConnection* pcOffer =
+ [factory peerConnectionWithICEServers:nil
+ constraints:pcConstraints
delegate:offeringExpectations];
- RTCPeerConnectionSyncObserver *answeringExpectations =
+ RTCPeerConnectionSyncObserver* answeringExpectations =
[[RTCPeerConnectionSyncObserver alloc] init];
- RTCPeerConnection *pcAnswer =
- [factory peerConnectionWithICEServers:iceServers
- constraints:constraints
- delegate:answeringExpectations];
+ RTCPeerConnection* pcAnswer =
+ [factory peerConnectionWithICEServers:nil
+ constraints:pcConstraints
+ delegate:answeringExpectations];
// TODO(hughv): Create video capturer
- RTCVideoCapturer *capturer = nil;
- RTCVideoSource *videoSource =
+ RTCVideoCapturer* capturer = nil;
+ RTCVideoSource* videoSource =
[factory videoSourceWithCapturer:capturer constraints:constraints];
// Here and below, "oLMS" refers to offerer's local media stream, and "aLMS"
// refers to the answerer's local media stream, with suffixes of "a0" and "v0"
// for audio and video tracks, resp. These mirror chrome historical naming.
- RTCMediaStream *oLMSUnused =
- [self addTracksToPeerConnection:pcOffer
- withFactory:factory
- videoSource:videoSource
- streamLabel:@"oLMS"
- videoTrackID:@"oLMSv0"
- audioTrackID:@"oLMSa0"];
- RTCSessionDescriptionSyncObserver *sdpObserver =
+ RTCMediaStream* oLMSUnused = [self addTracksToPeerConnection:pcOffer
+ withFactory:factory
+ videoSource:videoSource
+ streamLabel:@"oLMS"
+ videoTrackID:@"oLMSv0"
+ audioTrackID:@"oLMSa0"];
+
+ RTCDataChannel* offerDC =
+ [pcOffer createDataChannelWithLabel:@"offerDC"
+ config:[[RTCDataChannelInit alloc] init]];
+ EXPECT_TRUE([offerDC.label isEqual:@"offerDC"]);
+ offerDC.delegate = offeringExpectations;
+ offeringExpectations.dataChannel = offerDC;
+
+ RTCSessionDescriptionSyncObserver* sdpObserver =
[[RTCSessionDescriptionSyncObserver alloc] init];
[pcOffer createOfferWithDelegate:sdpObserver constraints:constraints];
[sdpObserver wait];
EXPECT_TRUE(sdpObserver.success);
- RTCSessionDescription *offerSDP = sdpObserver.sessionDescription;
+ RTCSessionDescription* offerSDP = sdpObserver.sessionDescription;
EXPECT_EQ([@"offer" compare:offerSDP.type options:NSCaseInsensitiveSearch],
NSOrderedSame);
EXPECT_GT([offerSDP.description length], 0);
sdpObserver = [[RTCSessionDescriptionSyncObserver alloc] init];
- [answeringExpectations
- expectSignalingChange:RTCSignalingHaveRemoteOffer];
+ [answeringExpectations expectSignalingChange:RTCSignalingHaveRemoteOffer];
[answeringExpectations expectAddStream:@"oLMS"];
[pcAnswer setRemoteDescriptionWithDelegate:sdpObserver
sessionDescription:offerSDP];
[sdpObserver wait];
- RTCMediaStream *aLMSUnused =
- [self addTracksToPeerConnection:pcAnswer
- withFactory:factory
- videoSource:videoSource
- streamLabel:@"aLMS"
- videoTrackID:@"aLMSv0"
- audioTrackID:@"aLMSa0"];
+ RTCMediaStream* aLMSUnused = [self addTracksToPeerConnection:pcAnswer
+ withFactory:factory
+ videoSource:videoSource
+ streamLabel:@"aLMS"
+ videoTrackID:@"aLMSv0"
+ audioTrackID:@"aLMSa0"];
sdpObserver = [[RTCSessionDescriptionSyncObserver alloc] init];
[pcAnswer createAnswerWithDelegate:sdpObserver constraints:constraints];
[sdpObserver wait];
EXPECT_TRUE(sdpObserver.success);
- RTCSessionDescription *answerSDP = sdpObserver.sessionDescription;
+ RTCSessionDescription* answerSDP = sdpObserver.sessionDescription;
EXPECT_EQ([@"answer" compare:answerSDP.type options:NSCaseInsensitiveSearch],
NSOrderedSame);
EXPECT_GT([answerSDP.description length], 0);
@@ -187,9 +192,16 @@
[offeringExpectations expectICEConnectionChange:RTCICEConnectionChecking];
[offeringExpectations expectICEConnectionChange:RTCICEConnectionConnected];
+ // TODO(fischman): figure out why this is flaky and re-introduce (and remove
+ // special-casing from the observer!).
+ // [offeringExpectations expectICEConnectionChange:RTCICEConnectionCompleted];
[answeringExpectations expectICEConnectionChange:RTCICEConnectionChecking];
[answeringExpectations expectICEConnectionChange:RTCICEConnectionConnected];
+ [offeringExpectations expectStateChange:kRTCDataChannelStateOpen];
+ [answeringExpectations expectDataChannel:@"offerDC"];
+ [answeringExpectations expectStateChange:kRTCDataChannelStateOpen];
+
[offeringExpectations expectICEGatheringChange:RTCICEGatheringComplete];
[answeringExpectations expectICEGatheringChange:RTCICEGatheringComplete];
@@ -206,31 +218,100 @@
EXPECT_TRUE([offerSDP.type isEqual:pcAnswer.remoteDescription.type]);
EXPECT_TRUE([answerSDP.type isEqual:pcAnswer.localDescription.type]);
- for (RTCICECandidate *candidate in
- offeringExpectations.releaseReceivedICECandidates) {
+ for (RTCICECandidate* candidate in offeringExpectations
+ .releaseReceivedICECandidates) {
[pcAnswer addICECandidate:candidate];
}
- for (RTCICECandidate *candidate in
- answeringExpectations.releaseReceivedICECandidates) {
+ for (RTCICECandidate* candidate in answeringExpectations
+ .releaseReceivedICECandidates) {
[pcOffer addICECandidate:candidate];
}
[offeringExpectations waitForAllExpectationsToBeSatisfied];
[answeringExpectations waitForAllExpectationsToBeSatisfied];
- // Let the audio feedback run for 10s to allow human testing and to ensure
+ EXPECT_EQ(pcOffer.signalingState, RTCSignalingStable);
+ EXPECT_EQ(pcAnswer.signalingState, RTCSignalingStable);
+
+ // Test send and receive UTF-8 text
+ NSString* text = @"你好";
+ NSData* textData = [text dataUsingEncoding:NSUTF8StringEncoding];
+ RTCDataBuffer* buffer =
+ [[RTCDataBuffer alloc] initWithData:textData isBinary:NO];
+ [answeringExpectations expectMessage:[textData copy] isBinary:NO];
+ EXPECT_TRUE([offeringExpectations.dataChannel sendData:buffer]);
+ [answeringExpectations waitForAllExpectationsToBeSatisfied];
+
+ // Test send and receive binary data
+ const size_t byteLength = 5;
+ char bytes[byteLength] = {1, 2, 3, 4, 5};
+ NSData* byteData = [NSData dataWithBytes:bytes length:byteLength];
+ buffer = [[RTCDataBuffer alloc] initWithData:byteData isBinary:YES];
+ [answeringExpectations expectMessage:[byteData copy] isBinary:YES];
+ EXPECT_TRUE([offeringExpectations.dataChannel sendData:buffer]);
+ [answeringExpectations waitForAllExpectationsToBeSatisfied];
+
+ [offeringExpectations expectStateChange:kRTCDataChannelStateClosing];
+ [answeringExpectations expectStateChange:kRTCDataChannelStateClosing];
+ [offeringExpectations expectStateChange:kRTCDataChannelStateClosed];
+ [answeringExpectations expectStateChange:kRTCDataChannelStateClosed];
+
+ [answeringExpectations.dataChannel close];
+ [offeringExpectations.dataChannel close];
+
+ [offeringExpectations waitForAllExpectationsToBeSatisfied];
+ [answeringExpectations waitForAllExpectationsToBeSatisfied];
+ // Don't need to listen to further state changes.
+ // TODO(tkchin): figure out why Closed->Closing without this.
+ offeringExpectations.dataChannel.delegate = nil;
+ answeringExpectations.dataChannel.delegate = nil;
+
+ // Let the audio feedback run for 2s to allow human testing and to ensure
// things stabilize. TODO(fischman): replace seconds with # of video frames,
// when we have video flowing.
[[NSRunLoop currentRunLoop]
- runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
+ runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
+
+ [offeringExpectations expectICEConnectionChange:RTCICEConnectionClosed];
+ [answeringExpectations expectICEConnectionChange:RTCICEConnectionClosed];
+ [offeringExpectations expectSignalingChange:RTCSignalingClosed];
+ [answeringExpectations expectSignalingChange:RTCSignalingClosed];
+
+ [pcOffer close];
+ [pcAnswer close];
- // TODO(hughv): Implement orderly shutdown.
+ [offeringExpectations waitForAllExpectationsToBeSatisfied];
+ [answeringExpectations waitForAllExpectationsToBeSatisfied];
+
+ capturer = nil;
+ videoSource = nil;
+ pcOffer = nil;
+ pcAnswer = nil;
+ // TODO(fischman): be stricter about shutdown checks; ensure thread
+ // counts return to where they were before the test kicked off, and
+ // that all objects have in fact shut down.
}
@end
-
+// TODO(fischman): move {Initialize,Cleanup}SSL into alloc/dealloc of
+// RTCPeerConnectionTest and avoid the appearance of RTCPeerConnectionTest being
+// a TestBase since it's not.
TEST(RTCPeerConnectionTest, SessionTest) {
- RTCPeerConnectionTest *pcTest = [[RTCPeerConnectionTest alloc] init];
- [pcTest testCompleteSession];
+ @autoreleasepool {
+ talk_base::InitializeSSL();
+ // Since |factory| will own the signaling & worker threads, it's important
+ // that it outlive the created PeerConnections since they self-delete on the
+ // signaling thread, and if |factory| is freed first then a last refcount on
+ // the factory will expire during this teardown, causing the signaling
+ // thread to try to Join() with itself. This is a hack to ensure that the
+ // factory outlives RTCPeerConnection:dealloc.
+ // See https://code.google.com/p/webrtc/issues/detail?id=3100.
+ RTCPeerConnectionFactory* factory = [[RTCPeerConnectionFactory alloc] init];
+ @autoreleasepool {
+ RTCPeerConnectionTest* pcTest = [[RTCPeerConnectionTest alloc] init];
+ [pcTest testCompleteSessionWithFactory:factory];
+ }
+ talk_base::CleanupSSL();
+ }
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCSessionDescriptionSyncObserver.h b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCSessionDescriptionSyncObserver.h
index 18d7902886b..8631f017047 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCSessionDescriptionSyncObserver.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCSessionDescriptionSyncObserver.h
@@ -27,14 +27,14 @@
#import <Foundation/Foundation.h>
-#import "RTCSessionDescriptonDelegate.h"
+#import "RTCSessionDescriptionDelegate.h"
@class RTCSessionDescription;
// Observer of SDP-related events, used by RTCPeerConnectionTest to check
// expectations.
@interface RTCSessionDescriptionSyncObserver : NSObject<
- RTCSessionDescriptonDelegate>
+ RTCSessionDescriptionDelegate>
// Error string. May be nil.
@property(atomic, copy) NSString *error;
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCSessionDescriptionSyncObserver.m b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCSessionDescriptionSyncObserver.m
index 85a4482b89e..6d782536c6c 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCSessionDescriptionSyncObserver.m
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCSessionDescriptionSyncObserver.m
@@ -33,10 +33,10 @@
#import "RTCSessionDescription.h"
-@interface RTCSessionDescriptionSyncObserver()
+@interface RTCSessionDescriptionSyncObserver ()
// CondVar used to wait for, and signal arrival of, an SDP-related callback.
-@property(nonatomic, strong) NSCondition *condition;
+@property(nonatomic, strong) NSCondition* condition;
// Whether an SDP-related callback has fired; cleared before wait returns.
@property(atomic, assign) BOOL signaled;
@@ -71,10 +71,10 @@
[self.condition unlock];
}
-#pragma mark - RTCSessionDescriptonDelegate methods
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- didCreateSessionDescription:(RTCSessionDescription *)sdp
- error:(NSError *)error {
+#pragma mark - RTCSessionDescriptionDelegate methods
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ didCreateSessionDescription:(RTCSessionDescription*)sdp
+ error:(NSError*)error {
[self.condition lock];
if (error) {
self.success = NO;
@@ -87,8 +87,8 @@
[self.condition unlock];
}
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- didSetSessionDescriptionWithError:(NSError *)error {
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ didSetSessionDescriptionWithError:(NSError*)error {
[self.condition lock];
if (error) {
self.success = NO;
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/mac/main.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/mac/main.mm
index 3fb24f37b23..4995b7f3ac2 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/mac/main.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/mac/main.mm
@@ -27,7 +27,11 @@
#include "talk/base/gunit.h"
-int main(int argc, char *argv[]) {
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection.cc
index e10e8fc953a..0839977f17a 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection.cc
@@ -32,10 +32,12 @@
#include "talk/app/webrtc/dtmfsender.h"
#include "talk/app/webrtc/jsepicecandidate.h"
#include "talk/app/webrtc/jsepsessiondescription.h"
+#include "talk/app/webrtc/mediaconstraintsinterface.h"
#include "talk/app/webrtc/mediastreamhandler.h"
#include "talk/app/webrtc/streamcollection.h"
#include "talk/base/logging.h"
#include "talk/base/stringencode.h"
+#include "talk/p2p/client/basicportallocator.h"
#include "talk/session/media/channelmanager.h"
namespace {
@@ -70,17 +72,6 @@ enum {
MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
MSG_SET_SESSIONDESCRIPTION_FAILED,
MSG_GETSTATS,
- MSG_ICECONNECTIONCHANGE,
- MSG_ICEGATHERINGCHANGE,
- MSG_ICECANDIDATE,
- MSG_ICECOMPLETE,
-};
-
-struct CandidateMsg : public talk_base::MessageData {
- explicit CandidateMsg(const webrtc::JsepIceCandidate* candidate)
- : candidate(candidate) {
- }
- talk_base::scoped_ptr<const webrtc::JsepIceCandidate> candidate;
};
struct SetSessionDescriptionMsg : public talk_base::MessageData {
@@ -276,13 +267,6 @@ bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
server.password,
turn_transport_type,
secure));
- // STUN functionality is part of TURN.
- // Note: If there is only TURNS is supplied as part of configuration,
- // we will have problem in fetching server reflexive candidate, as
- // currently we don't have support of TCP/TLS in stunport.cc.
- // In that case we should fetch server reflexive addess from
- // TURN allocate response.
- stun_config->push_back(StunConfiguration(address, port));
break;
}
case INVALID:
@@ -317,6 +301,7 @@ namespace webrtc {
PeerConnection::PeerConnection(PeerConnectionFactory* factory)
: factory_(factory),
observer_(NULL),
+ uma_observer_(NULL),
signaling_state_(kStable),
ice_state_(kIceNew),
ice_connection_state_(kIceConnectionNew),
@@ -331,22 +316,23 @@ PeerConnection::~PeerConnection() {
}
bool PeerConnection::Initialize(
- const PeerConnectionInterface::IceServers& configuration,
+ const PeerConnectionInterface::RTCConfiguration& configuration,
const MediaConstraintsInterface* constraints,
PortAllocatorFactoryInterface* allocator_factory,
DTLSIdentityServiceInterface* dtls_identity_service,
PeerConnectionObserver* observer) {
std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
- if (!ParseIceServers(configuration, &stun_config, &turn_config)) {
+ if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
return false;
}
- return DoInitialize(stun_config, turn_config, constraints,
+ return DoInitialize(configuration.type, stun_config, turn_config, constraints,
allocator_factory, dtls_identity_service, observer);
}
bool PeerConnection::DoInitialize(
+ IceTransportsType type,
const StunConfigurations& stun_config,
const TurnConfigurations& turn_config,
const MediaConstraintsInterface* constraints,
@@ -359,11 +345,21 @@ bool PeerConnection::DoInitialize(
observer_ = observer;
port_allocator_.reset(
allocator_factory->CreatePortAllocator(stun_config, turn_config));
+
// To handle both internal and externally created port allocator, we will
- // enable BUNDLE here. Also enabling TURN and disable legacy relay service.
- port_allocator_->set_flags(cricket::PORTALLOCATOR_ENABLE_BUNDLE |
- cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
- cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+ // enable BUNDLE here.
+ int portallocator_flags = cricket::PORTALLOCATOR_ENABLE_BUNDLE |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
+ bool value;
+ if (FindConstraint(
+ constraints,
+ MediaConstraintsInterface::kEnableIPv6,
+ &value, NULL) && value) {
+ portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
+ }
+
+ port_allocator_->set_flags(portallocator_flags);
// No step delay is used while allocating ports.
port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
@@ -381,7 +377,7 @@ bool PeerConnection::DoInitialize(
// Initialize the WebRtcSession. It creates transport channels etc.
if (!session_->Initialize(factory_->options(), constraints,
- dtls_identity_service))
+ dtls_identity_service, type))
return false;
// Register PeerConnection as receiver of local ice candidates.
@@ -448,13 +444,14 @@ talk_base::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
}
bool PeerConnection::GetStats(StatsObserver* observer,
- MediaStreamTrackInterface* track) {
+ MediaStreamTrackInterface* track,
+ StatsOutputLevel level) {
if (!VERIFY(observer != NULL)) {
LOG(LS_ERROR) << "GetStats - observer is NULL.";
return false;
}
- stats_.UpdateStats();
+ stats_.UpdateStats(level);
talk_base::scoped_ptr<GetStatsMsg> msg(new GetStatsMsg(observer));
if (!stats_.GetStats(track, &(msg->reports))) {
return false;
@@ -485,12 +482,22 @@ talk_base::scoped_refptr<DataChannelInterface>
PeerConnection::CreateDataChannel(
const std::string& label,
const DataChannelInit* config) {
+ bool first_datachannel = !mediastream_signaling_->HasDataChannels();
+
+ talk_base::scoped_ptr<InternalDataChannelInit> internal_config;
+ if (config) {
+ internal_config.reset(new InternalDataChannelInit(*config));
+ }
talk_base::scoped_refptr<DataChannelInterface> channel(
- session_->CreateDataChannel(label, config));
+ session_->CreateDataChannel(label, internal_config.get()));
if (!channel.get())
return NULL;
- observer_->OnRenegotiationNeeded();
+ // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
+ // the first SCTP DataChannel.
+ if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
+ observer_->OnRenegotiationNeeded();
+ }
return DataChannelProxy::Create(signaling_thread(), channel.get());
}
@@ -527,7 +534,7 @@ void PeerConnection::SetLocalDescription(
}
// Update stats here so that we have the most recent stats for tracks and
// streams that might be removed by updating the session description.
- stats_.UpdateStats();
+ stats_.UpdateStats(kStatsOutputLevelStandard);
std::string error;
if (!session_->SetLocalDescription(desc, &error)) {
PostSetSessionDescriptionFailure(observer, error);
@@ -550,7 +557,7 @@ void PeerConnection::SetRemoteDescription(
}
// Update stats here so that we have the most recent stats for tracks and
// streams that might be removed by updating the session description.
- stats_.UpdateStats();
+ stats_.UpdateStats(kStatsOutputLevelStandard);
std::string error;
if (!session_->SetRemoteDescription(desc, &error)) {
PostSetSessionDescriptionFailure(observer, error);
@@ -570,16 +577,67 @@ void PeerConnection::PostSetSessionDescriptionFailure(
bool PeerConnection::UpdateIce(const IceServers& configuration,
const MediaConstraintsInterface* constraints) {
- // TODO(ronghuawu): Implement UpdateIce.
- LOG(LS_ERROR) << "UpdateIce is not implemented.";
return false;
}
+bool PeerConnection::UpdateIce(const RTCConfiguration& config) {
+ if (port_allocator_) {
+ std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
+ std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
+ if (!ParseIceServers(config.servers, &stuns, &turns)) {
+ return false;
+ }
+
+ std::vector<talk_base::SocketAddress> stun_hosts;
+ typedef std::vector<StunConfiguration>::const_iterator StunIt;
+ for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
+ stun_hosts.push_back(stun_it->server);
+ }
+
+ talk_base::SocketAddress stun_addr;
+ if (!stun_hosts.empty()) {
+ stun_addr = stun_hosts.front();
+ LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString();
+ }
+
+ for (size_t i = 0; i < turns.size(); ++i) {
+ cricket::RelayCredentials credentials(turns[i].username,
+ turns[i].password);
+ cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
+ cricket::ProtocolType protocol;
+ if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ turns[i].server, protocol, turns[i].secure));
+ relay_server.credentials = credentials;
+ LOG(LS_INFO) << "UpdateIce: TurnServer Address: "
+ << turns[i].server.ToString();
+ } else {
+ LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
+ << "Reason= Incorrect " << turns[i].transport_type
+ << " transport parameter.";
+ }
+ }
+ }
+ return session_->UpdateIce(config.type);
+}
+
bool PeerConnection::AddIceCandidate(
const IceCandidateInterface* ice_candidate) {
return session_->ProcessIceMessage(ice_candidate);
}
+void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
+ uma_observer_ = observer;
+ // Send information about IPv4/IPv6 status.
+ if (uma_observer_ && port_allocator_) {
+ if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
+ uma_observer_->IncrementCounter(kPeerConnection_IPv6);
+ } else {
+ uma_observer_->IncrementCounter(kPeerConnection_IPv4);
+ }
+ }
+}
+
const SessionDescriptionInterface* PeerConnection::local_description() const {
return session_->local_description();
}
@@ -591,7 +649,7 @@ const SessionDescriptionInterface* PeerConnection::remote_description() const {
void PeerConnection::Close() {
// Update stats here so that we have the most recent stats for tracks and
// streams before the channels are closed.
- stats_.UpdateStats();
+ stats_.UpdateStats(kStatsOutputLevelStandard);
session_->Terminate();
}
@@ -648,24 +706,6 @@ void PeerConnection::OnMessage(talk_base::Message* msg) {
delete param;
break;
}
- case MSG_ICECONNECTIONCHANGE: {
- observer_->OnIceConnectionChange(ice_connection_state_);
- break;
- }
- case MSG_ICEGATHERINGCHANGE: {
- observer_->OnIceGatheringChange(ice_gathering_state_);
- break;
- }
- case MSG_ICECANDIDATE: {
- CandidateMsg* data = static_cast<CandidateMsg*>(msg->pdata);
- observer_->OnIceCandidate(data->candidate.get());
- delete data;
- break;
- }
- case MSG_ICECOMPLETE: {
- observer_->OnIceComplete();
- break;
- }
default:
ASSERT(false && "Not implemented");
break;
@@ -714,6 +754,7 @@ void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
AudioTrackInterface* audio_track,
uint32 ssrc) {
stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
+ stats_.AddLocalAudioTrack(audio_track, ssrc);
}
void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
VideoTrackInterface* video_track,
@@ -722,8 +763,10 @@ void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
}
void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track) {
+ AudioTrackInterface* audio_track,
+ uint32 ssrc) {
stream_handler_container_->RemoveLocalTrack(stream, audio_track);
+ stats_.RemoveLocalAudioTrack(audio_track, ssrc);
}
void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
@@ -737,35 +780,29 @@ void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
void PeerConnection::OnIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) {
+ ASSERT(signaling_thread()->IsCurrent());
ice_connection_state_ = new_state;
- signaling_thread()->Post(this, MSG_ICECONNECTIONCHANGE);
+ observer_->OnIceConnectionChange(ice_connection_state_);
}
void PeerConnection::OnIceGatheringChange(
PeerConnectionInterface::IceGatheringState new_state) {
+ ASSERT(signaling_thread()->IsCurrent());
if (IsClosed()) {
return;
}
ice_gathering_state_ = new_state;
- signaling_thread()->Post(this, MSG_ICEGATHERINGCHANGE);
+ observer_->OnIceGatheringChange(ice_gathering_state_);
}
void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
- JsepIceCandidate* candidate_copy = NULL;
- if (candidate) {
- // TODO(ronghuawu): Make IceCandidateInterface reference counted instead
- // of making a copy.
- candidate_copy = new JsepIceCandidate(candidate->sdp_mid(),
- candidate->sdp_mline_index(),
- candidate->candidate());
- }
- // The Post takes the ownership of the |candidate_copy|.
- signaling_thread()->Post(this, MSG_ICECANDIDATE,
- new CandidateMsg(candidate_copy));
+ ASSERT(signaling_thread()->IsCurrent());
+ observer_->OnIceCandidate(candidate);
}
void PeerConnection::OnIceComplete() {
- signaling_thread()->Post(this, MSG_ICECOMPLETE);
+ ASSERT(signaling_thread()->IsCurrent());
+ observer_->OnIceComplete();
}
void PeerConnection::ChangeSignalingState(
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection.h b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection.h
index 9cc9f3868de..4a428efeed5 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection.h
@@ -57,11 +57,12 @@ class PeerConnection : public PeerConnectionInterface,
public:
explicit PeerConnection(PeerConnectionFactory* factory);
- bool Initialize(const PeerConnectionInterface::IceServers& configuration,
- const MediaConstraintsInterface* constraints,
- PortAllocatorFactoryInterface* allocator_factory,
- DTLSIdentityServiceInterface* dtls_identity_service,
- PeerConnectionObserver* observer);
+ bool Initialize(
+ const PeerConnectionInterface::RTCConfiguration& configuration,
+ const MediaConstraintsInterface* constraints,
+ PortAllocatorFactoryInterface* allocator_factory,
+ DTLSIdentityServiceInterface* dtls_identity_service,
+ PeerConnectionObserver* observer);
virtual talk_base::scoped_refptr<StreamCollectionInterface> local_streams();
virtual talk_base::scoped_refptr<StreamCollectionInterface> remote_streams();
virtual bool AddStream(MediaStreamInterface* local_stream,
@@ -75,7 +76,8 @@ class PeerConnection : public PeerConnectionInterface,
const std::string& label,
const DataChannelInit* config);
virtual bool GetStats(StatsObserver* observer,
- webrtc::MediaStreamTrackInterface* track);
+ webrtc::MediaStreamTrackInterface* track,
+ StatsOutputLevel level);
virtual SignalingState signaling_state();
@@ -96,10 +98,15 @@ class PeerConnection : public PeerConnectionInterface,
SessionDescriptionInterface* desc);
virtual void SetRemoteDescription(SetSessionDescriptionObserver* observer,
SessionDescriptionInterface* desc);
+ // TODO(mallinath) : Deprecated version, remove after all clients are updated.
virtual bool UpdateIce(const IceServers& configuration,
const MediaConstraintsInterface* constraints);
+ virtual bool UpdateIce(
+ const PeerConnectionInterface::RTCConfiguration& config);
virtual bool AddIceCandidate(const IceCandidateInterface* candidate);
+ virtual void RegisterUMAObserver(UMAObserver* observer);
+
virtual void Close();
protected:
@@ -133,7 +140,8 @@ class PeerConnection : public PeerConnectionInterface,
uint32 ssrc) OVERRIDE;
virtual void OnRemoveLocalAudioTrack(
MediaStreamInterface* stream,
- AudioTrackInterface* audio_track) OVERRIDE;
+ AudioTrackInterface* audio_track,
+ uint32 ssrc) OVERRIDE;
virtual void OnRemoveLocalVideoTrack(
MediaStreamInterface* stream,
VideoTrackInterface* video_track) OVERRIDE;
@@ -150,7 +158,8 @@ class PeerConnection : public PeerConnectionInterface,
cricket::BaseSession::State state);
void ChangeSignalingState(SignalingState signaling_state);
- bool DoInitialize(const StunConfigurations& stun_config,
+ bool DoInitialize(IceTransportsType type,
+ const StunConfigurations& stun_config,
const TurnConfigurations& turn_config,
const MediaConstraintsInterface* constraints,
PortAllocatorFactoryInterface* allocator_factory,
@@ -176,6 +185,7 @@ class PeerConnection : public PeerConnectionInterface,
// will refer to the same reference count.
talk_base::scoped_refptr<PeerConnectionFactory> factory_;
PeerConnectionObserver* observer_;
+ UMAObserver* uma_observer_;
SignalingState signaling_state_;
// TODO(bemasc): Remove ice_state_.
IceState ice_state_;
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection_unittest.cc
index 76d9cd73cf0..0c39297ab23 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnection_unittest.cc
@@ -40,6 +40,7 @@
#include "talk/app/webrtc/peerconnectioninterface.h"
#include "talk/app/webrtc/test/fakeaudiocapturemodule.h"
#include "talk/app/webrtc/test/fakeconstraints.h"
+#include "talk/app/webrtc/test/fakedtlsidentityservice.h"
#include "talk/app/webrtc/test/fakevideotrackrenderer.h"
#include "talk/app/webrtc/test/fakeperiodicvideocapturer.h"
#include "talk/app/webrtc/test/mockpeerconnectionobservers.h"
@@ -78,12 +79,19 @@ using webrtc::MockCreateSessionDescriptionObserver;
using webrtc::MockDataChannelObserver;
using webrtc::MockSetSessionDescriptionObserver;
using webrtc::MockStatsObserver;
+using webrtc::PeerConnectionInterface;
using webrtc::SessionDescriptionInterface;
using webrtc::StreamCollectionInterface;
-static const int kMaxWaitMs = 1000;
+static const int kMaxWaitMs = 2000;
+// Disable for TSan v2, see
+// https://code.google.com/p/webrtc/issues/detail?id=1205 for details.
+// This declaration is also #ifdef'd as it causes uninitialized-variable
+// warnings.
+#if !defined(THREAD_SANITIZER)
static const int kMaxWaitForStatsMs = 3000;
-static const int kMaxWaitForFramesMs = 5000;
+#endif
+static const int kMaxWaitForFramesMs = 10000;
static const int kEndAudioFrameCount = 3;
static const int kEndVideoFrameCount = 3;
@@ -327,7 +335,8 @@ class PeerConnectionTestClientBase
int GetAudioOutputLevelStats(webrtc::MediaStreamTrackInterface* track) {
talk_base::scoped_refptr<MockStatsObserver>
observer(new talk_base::RefCountedObject<MockStatsObserver>());
- EXPECT_TRUE(peer_connection_->GetStats(observer, track));
+ EXPECT_TRUE(peer_connection_->GetStats(
+ observer, track, PeerConnectionInterface::kStatsOutputLevelStandard));
EXPECT_TRUE_WAIT(observer->called(), kMaxWaitMs);
return observer->AudioOutputLevel();
}
@@ -335,7 +344,8 @@ class PeerConnectionTestClientBase
int GetAudioInputLevelStats() {
talk_base::scoped_refptr<MockStatsObserver>
observer(new talk_base::RefCountedObject<MockStatsObserver>());
- EXPECT_TRUE(peer_connection_->GetStats(observer, NULL));
+ EXPECT_TRUE(peer_connection_->GetStats(
+ observer, NULL, PeerConnectionInterface::kStatsOutputLevelStandard));
EXPECT_TRUE_WAIT(observer->called(), kMaxWaitMs);
return observer->AudioInputLevel();
}
@@ -343,7 +353,8 @@ class PeerConnectionTestClientBase
int GetBytesReceivedStats(webrtc::MediaStreamTrackInterface* track) {
talk_base::scoped_refptr<MockStatsObserver>
observer(new talk_base::RefCountedObject<MockStatsObserver>());
- EXPECT_TRUE(peer_connection_->GetStats(observer, track));
+ EXPECT_TRUE(peer_connection_->GetStats(
+ observer, track, PeerConnectionInterface::kStatsOutputLevelStandard));
EXPECT_TRUE_WAIT(observer->called(), kMaxWaitMs);
return observer->BytesReceived();
}
@@ -351,7 +362,8 @@ class PeerConnectionTestClientBase
int GetBytesSentStats(webrtc::MediaStreamTrackInterface* track) {
talk_base::scoped_refptr<MockStatsObserver>
observer(new talk_base::RefCountedObject<MockStatsObserver>());
- EXPECT_TRUE(peer_connection_->GetStats(observer, track));
+ EXPECT_TRUE(peer_connection_->GetStats(
+ observer, track, PeerConnectionInterface::kStatsOutputLevelStandard));
EXPECT_TRUE_WAIT(observer->called(), kMaxWaitMs);
return observer->BytesSent();
}
@@ -719,8 +731,12 @@ class JsepTestClient
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.uri = "stun:stun.l.google.com:19302";
ice_servers.push_back(ice_server);
+
+ FakeIdentityService* dtls_service =
+ talk_base::SSLStreamAdapter::HaveDtlsSrtp() ?
+ new FakeIdentityService() : NULL;
return peer_connection_factory()->CreatePeerConnection(
- ice_servers, constraints, factory, NULL, this);
+ ice_servers, constraints, factory, dtls_service, this);
}
void HandleIncomingOffer(const std::string& msg) {
@@ -957,12 +973,13 @@ class P2PTestConductor : public testing::Test {
}
if (audio_frame_count != -1 || video_frame_count != -1) {
- // Audio or video is expected to flow, so both sides should get to the
- // Connected state.
+ // Audio or video is expected to flow, so both clients should reach the
+ // Connected state, and the offerer (ICE controller) should proceed to
+ // Completed.
// Note: These tests have been observed to fail under heavy load at
// shorter timeouts, so they may be flaky.
EXPECT_EQ_WAIT(
- webrtc::PeerConnectionInterface::kIceConnectionConnected,
+ webrtc::PeerConnectionInterface::kIceConnectionCompleted,
initiating_client_->ice_connection_state(),
kMaxWaitForFramesMs);
EXPECT_EQ_WAIT(
@@ -992,6 +1009,16 @@ class P2PTestConductor : public testing::Test {
kMaxWaitForFramesMs);
}
+ void SendRtpData(webrtc::DataChannelInterface* dc, const std::string& data) {
+ // Messages may get lost on the unreliable DataChannel, so we send multiple
+ // times to avoid test flakiness.
+ static const size_t kSendAttempts = 5;
+
+ for (size_t i = 0; i < kSendAttempts; ++i) {
+ dc->Send(DataBuffer(data));
+ }
+ }
+
SignalingClass* initializing_client() { return initiating_client_.get(); }
SignalingClass* receiving_client() { return receiving_client_.get(); }
@@ -1077,32 +1104,6 @@ TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDtlsRenegotiate) {
receiving_client()->Negotiate();
}
-// This test sets up a call between an endpoint configured to use either SDES or
-// DTLS (the offerer) and just SDES (the answerer). As a result, SDES is used
-// instead of DTLS.
-TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestOfferDtlsToSdes) {
- MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
- FakeConstraints setup_constraints;
- setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- ASSERT_TRUE(CreateTestClients(&setup_constraints, NULL));
- LocalP2PTest();
- VerifyRenderedSize(640, 480);
-}
-
-// This test sets up a call between an endpoint configured to use SDES
-// (the offerer) and either SDES or DTLS (the answerer). As a result, SDES is
-// used instead of DTLS.
-TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestOfferSdesToDtls) {
- MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
- FakeConstraints setup_constraints;
- setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- ASSERT_TRUE(CreateTestClients(NULL, &setup_constraints));
- LocalP2PTest();
- VerifyRenderedSize(640, 480);
-}
-
// This test sets up a call between two endpoints that are configured to use
// DTLS key agreement. The offerer don't support SDES. As a result, DTLS is
// negotiated and used for transport.
@@ -1146,7 +1147,9 @@ TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestAnswerNone) {
// runs for a while (10 frames), the caller sends an update offer with video
// being rejected. Once the re-negotiation is done, the video flow should stop
// and the audio flow should continue.
-TEST_F(JsepPeerConnectionP2PTestClient, UpdateOfferWithRejectedContent) {
+// Disabled due to b/14955157.
+TEST_F(JsepPeerConnectionP2PTestClient,
+ DISABLED_UpdateOfferWithRejectedContent) {
ASSERT_TRUE(CreateTestClients());
LocalP2PTest();
TestUpdateOfferWithRejectedContent();
@@ -1154,7 +1157,8 @@ TEST_F(JsepPeerConnectionP2PTestClient, UpdateOfferWithRejectedContent) {
// This test sets up a Jsep call between two parties. The MSID is removed from
// the SDP strings from the caller.
-TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestWithoutMsid) {
+// Disabled due to b/14955157.
+TEST_F(JsepPeerConnectionP2PTestClient, DISABLED_LocalP2PTestWithoutMsid) {
ASSERT_TRUE(CreateTestClients());
receiving_client()->RemoveMsidFromReceivedSdp(true);
// TODO(perkj): Currently there is a bug that cause audio to stop playing if
@@ -1271,10 +1275,12 @@ TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDataChannel) {
kMaxWaitMs);
std::string data = "hello world";
- initializing_client()->data_channel()->Send(DataBuffer(data));
+
+ SendRtpData(initializing_client()->data_channel(), data);
EXPECT_EQ_WAIT(data, receiving_client()->data_observer()->last_message(),
kMaxWaitMs);
- receiving_client()->data_channel()->Send(DataBuffer(data));
+
+ SendRtpData(receiving_client()->data_channel(), data);
EXPECT_EQ_WAIT(data, initializing_client()->data_observer()->last_message(),
kMaxWaitMs);
@@ -1308,8 +1314,10 @@ TEST_F(JsepPeerConnectionP2PTestClient, RegisterDataChannelObserver) {
// Unregister the existing observer.
receiving_client()->data_channel()->UnregisterObserver();
+
std::string data = "hello world";
- initializing_client()->data_channel()->Send(DataBuffer(data));
+ SendRtpData(initializing_client()->data_channel(), data);
+
// Wait a while to allow the sent data to arrive before an observer is
// registered..
talk_base::Thread::Current()->ProcessMessages(100);
@@ -1321,9 +1329,15 @@ TEST_F(JsepPeerConnectionP2PTestClient, RegisterDataChannelObserver) {
// This test sets up a call between two parties with audio, video and but only
// the initiating client support data.
TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestReceiverDoesntSupportData) {
- FakeConstraints setup_constraints;
- setup_constraints.SetAllowRtpDataChannels();
- ASSERT_TRUE(CreateTestClients(&setup_constraints, NULL));
+ FakeConstraints setup_constraints_1;
+ setup_constraints_1.SetAllowRtpDataChannels();
+ // Must disable DTLS to make negotiation succeed.
+ setup_constraints_1.SetMandatory(
+ MediaConstraintsInterface::kEnableDtlsSrtp, false);
+ FakeConstraints setup_constraints_2;
+ setup_constraints_2.SetMandatory(
+ MediaConstraintsInterface::kEnableDtlsSrtp, false);
+ ASSERT_TRUE(CreateTestClients(&setup_constraints_1, &setup_constraints_2));
initializing_client()->CreateDataChannel();
LocalP2PTest();
EXPECT_TRUE(initializing_client()->data_channel() != NULL);
@@ -1349,6 +1363,20 @@ TEST_F(JsepPeerConnectionP2PTestClient, AddDataChannelAfterRenegotiation) {
kMaxWaitMs);
}
+// This test sets up a Jsep call with SCTP DataChannel and verifies the
+// negotiation is completed without error.
+#ifdef HAVE_SCTP
+TEST_F(JsepPeerConnectionP2PTestClient, CreateOfferWithSctpDataChannel) {
+ MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+ FakeConstraints constraints;
+ constraints.SetMandatory(
+ MediaConstraintsInterface::kEnableDtlsSrtp, true);
+ ASSERT_TRUE(CreateTestClients(&constraints, &constraints));
+ initializing_client()->CreateDataChannel();
+ initializing_client()->Negotiate(false, false);
+}
+#endif
+
// This test sets up a call between two parties with audio, and video.
// During the call, the initializing side restart ice and the test verifies that
// new ice candidates are generated and audio and video still can flow.
@@ -1410,6 +1438,4 @@ TEST_F(JsepPeerConnectionP2PTestClient,
EnableVideoDecoderFactory();
LocalP2PTest();
}
-
#endif // if !defined(THREAD_SANITIZER)
-
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionendtoend_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionendtoend_unittest.cc
index da3c03da4eb..f701e0635f0 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionendtoend_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionendtoend_unittest.cc
@@ -26,6 +26,7 @@
*/
#include "talk/app/webrtc/test/peerconnectiontestwrapper.h"
+#include "talk/app/webrtc/test/mockpeerconnectionobservers.h"
#include "talk/base/gunit.h"
#include "talk/base/logging.h"
#include "talk/base/ssladapter.h"
@@ -33,6 +34,13 @@
#include "talk/base/stringencode.h"
#include "talk/base/stringutils.h"
+#define MAYBE_SKIP_TEST(feature) \
+ if (!(feature())) { \
+ LOG(LS_INFO) << "Feature disabled... skipping"; \
+ return; \
+ }
+
+using webrtc::DataChannelInterface;
using webrtc::FakeConstraints;
using webrtc::MediaConstraintsInterface;
using webrtc::MediaStreamInterface;
@@ -42,6 +50,7 @@ namespace {
const char kExternalGiceUfrag[] = "1234567890123456";
const char kExternalGicePwd[] = "123456789012345678901234";
+const size_t kMaxWait = 10000;
void RemoveLinesFromSdp(const std::string& line_start,
std::string* sdp) {
@@ -117,6 +126,9 @@ class PeerConnectionEndToEndTest
: public sigslot::has_slots<>,
public testing::Test {
public:
+ typedef std::vector<talk_base::scoped_refptr<DataChannelInterface> >
+ DataChannelList;
+
PeerConnectionEndToEndTest()
: caller_(new talk_base::RefCountedObject<PeerConnectionTestWrapper>(
"caller")),
@@ -133,6 +145,11 @@ class PeerConnectionEndToEndTest
EXPECT_TRUE(caller_->CreatePc(pc_constraints));
EXPECT_TRUE(callee_->CreatePc(pc_constraints));
PeerConnectionTestWrapper::Connect(caller_.get(), callee_.get());
+
+ caller_->SignalOnDataChannel.connect(
+ this, &PeerConnectionEndToEndTest::OnCallerAddedDataChanel);
+ callee_->SignalOnDataChannel.connect(
+ this, &PeerConnectionEndToEndTest::OnCalleeAddedDataChannel);
}
void GetAndAddUserMedia() {
@@ -158,6 +175,11 @@ class PeerConnectionEndToEndTest
callee_->WaitForCallEstablished();
}
+ void WaitForConnection() {
+ caller_->WaitForConnection();
+ callee_->WaitForConnection();
+ }
+
void SetupLegacySdpConverter() {
caller_->SignalOnSdpCreated.connect(
this, &PeerConnectionEndToEndTest::ConvertToLegacySdp);
@@ -189,6 +211,57 @@ class PeerConnectionEndToEndTest
LOG(LS_INFO) << "AddGiceCredsToCandidate: " << *sdp;
}
+ void OnCallerAddedDataChanel(DataChannelInterface* dc) {
+ caller_signaled_data_channels_.push_back(dc);
+ }
+
+ void OnCalleeAddedDataChannel(DataChannelInterface* dc) {
+ callee_signaled_data_channels_.push_back(dc);
+ }
+
+ // Tests that |dc1| and |dc2| can send to and receive from each other.
+ void TestDataChannelSendAndReceive(
+ DataChannelInterface* dc1, DataChannelInterface* dc2) {
+ talk_base::scoped_ptr<webrtc::MockDataChannelObserver> dc1_observer(
+ new webrtc::MockDataChannelObserver(dc1));
+
+ talk_base::scoped_ptr<webrtc::MockDataChannelObserver> dc2_observer(
+ new webrtc::MockDataChannelObserver(dc2));
+
+ static const std::string kDummyData = "abcdefg";
+ webrtc::DataBuffer buffer(kDummyData);
+ EXPECT_TRUE(dc1->Send(buffer));
+ EXPECT_EQ_WAIT(kDummyData, dc2_observer->last_message(), kMaxWait);
+
+ EXPECT_TRUE(dc2->Send(buffer));
+ EXPECT_EQ_WAIT(kDummyData, dc1_observer->last_message(), kMaxWait);
+
+ EXPECT_EQ(1U, dc1_observer->received_message_count());
+ EXPECT_EQ(1U, dc2_observer->received_message_count());
+ }
+
+ void WaitForDataChannelsToOpen(DataChannelInterface* local_dc,
+ const DataChannelList& remote_dc_list,
+ size_t remote_dc_index) {
+ EXPECT_EQ_WAIT(DataChannelInterface::kOpen, local_dc->state(), kMaxWait);
+
+ EXPECT_TRUE_WAIT(remote_dc_list.size() > remote_dc_index, kMaxWait);
+ EXPECT_EQ_WAIT(DataChannelInterface::kOpen,
+ remote_dc_list[remote_dc_index]->state(),
+ kMaxWait);
+ EXPECT_EQ(local_dc->id(), remote_dc_list[remote_dc_index]->id());
+ }
+
+ void CloseDataChannels(DataChannelInterface* local_dc,
+ const DataChannelList& remote_dc_list,
+ size_t remote_dc_index) {
+ local_dc->Close();
+ EXPECT_EQ_WAIT(DataChannelInterface::kClosed, local_dc->state(), kMaxWait);
+ EXPECT_EQ_WAIT(DataChannelInterface::kClosed,
+ remote_dc_list[remote_dc_index]->state(),
+ kMaxWait);
+ }
+
~PeerConnectionEndToEndTest() {
talk_base::CleanupSSL();
}
@@ -196,6 +269,8 @@ class PeerConnectionEndToEndTest
protected:
talk_base::scoped_refptr<PeerConnectionTestWrapper> caller_;
talk_base::scoped_refptr<PeerConnectionTestWrapper> callee_;
+ DataChannelList caller_signaled_data_channels_;
+ DataChannelList callee_signaled_data_channels_;
};
// Disable for TSan v2, see
@@ -209,7 +284,8 @@ TEST_F(PeerConnectionEndToEndTest, Call) {
WaitForCallEstablished();
}
-TEST_F(PeerConnectionEndToEndTest, CallWithLegacySdp) {
+// Disabled per b/14899892
+TEST_F(PeerConnectionEndToEndTest, DISABLED_CallWithLegacySdp) {
FakeConstraints pc_constraints;
pc_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp,
false);
@@ -221,4 +297,126 @@ TEST_F(PeerConnectionEndToEndTest, CallWithLegacySdp) {
WaitForCallEstablished();
}
+// Verifies that a DataChannel created before the negotiation can transition to
+// "OPEN" and transfer data.
+TEST_F(PeerConnectionEndToEndTest, CreateDataChannelBeforeNegotiate) {
+ MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+
+ CreatePcs();
+
+ webrtc::DataChannelInit init;
+ talk_base::scoped_refptr<DataChannelInterface> caller_dc(
+ caller_->CreateDataChannel("data", init));
+ talk_base::scoped_refptr<DataChannelInterface> callee_dc(
+ callee_->CreateDataChannel("data", init));
+
+ Negotiate();
+ WaitForConnection();
+
+ WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 0);
+ WaitForDataChannelsToOpen(callee_dc, caller_signaled_data_channels_, 0);
+
+ TestDataChannelSendAndReceive(caller_dc, callee_signaled_data_channels_[0]);
+ TestDataChannelSendAndReceive(callee_dc, caller_signaled_data_channels_[0]);
+
+ CloseDataChannels(caller_dc, callee_signaled_data_channels_, 0);
+ CloseDataChannels(callee_dc, caller_signaled_data_channels_, 0);
+}
+
+// Verifies that a DataChannel created after the negotiation can transition to
+// "OPEN" and transfer data.
+TEST_F(PeerConnectionEndToEndTest, CreateDataChannelAfterNegotiate) {
+ MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+
+ CreatePcs();
+
+ webrtc::DataChannelInit init;
+
+ // This DataChannel is for creating the data content in the negotiation.
+ talk_base::scoped_refptr<DataChannelInterface> dummy(
+ caller_->CreateDataChannel("data", init));
+ Negotiate();
+ WaitForConnection();
+
+ // Creates new DataChannels after the negotiation and verifies their states.
+ talk_base::scoped_refptr<DataChannelInterface> caller_dc(
+ caller_->CreateDataChannel("hello", init));
+ talk_base::scoped_refptr<DataChannelInterface> callee_dc(
+ callee_->CreateDataChannel("hello", init));
+
+ WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 1);
+ WaitForDataChannelsToOpen(callee_dc, caller_signaled_data_channels_, 0);
+
+ TestDataChannelSendAndReceive(caller_dc, callee_signaled_data_channels_[1]);
+ TestDataChannelSendAndReceive(callee_dc, caller_signaled_data_channels_[0]);
+
+ CloseDataChannels(caller_dc, callee_signaled_data_channels_, 1);
+ CloseDataChannels(callee_dc, caller_signaled_data_channels_, 0);
+}
+
+// Verifies that DataChannel IDs are even/odd based on the DTLS roles.
+TEST_F(PeerConnectionEndToEndTest, DataChannelIdAssignment) {
+ MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+
+ CreatePcs();
+
+ webrtc::DataChannelInit init;
+ talk_base::scoped_refptr<DataChannelInterface> caller_dc_1(
+ caller_->CreateDataChannel("data", init));
+ talk_base::scoped_refptr<DataChannelInterface> callee_dc_1(
+ callee_->CreateDataChannel("data", init));
+
+ Negotiate();
+ WaitForConnection();
+
+ EXPECT_EQ(1U, caller_dc_1->id() % 2);
+ EXPECT_EQ(0U, callee_dc_1->id() % 2);
+
+ talk_base::scoped_refptr<DataChannelInterface> caller_dc_2(
+ caller_->CreateDataChannel("data", init));
+ talk_base::scoped_refptr<DataChannelInterface> callee_dc_2(
+ callee_->CreateDataChannel("data", init));
+
+ EXPECT_EQ(1U, caller_dc_2->id() % 2);
+ EXPECT_EQ(0U, callee_dc_2->id() % 2);
+}
+
+// Verifies that the message is received by the right remote DataChannel when
+// there are multiple DataChannels.
+TEST_F(PeerConnectionEndToEndTest,
+ MessageTransferBetweenTwoPairsOfDataChannels) {
+ MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+
+ CreatePcs();
+
+ webrtc::DataChannelInit init;
+
+ talk_base::scoped_refptr<DataChannelInterface> caller_dc_1(
+ caller_->CreateDataChannel("data", init));
+ talk_base::scoped_refptr<DataChannelInterface> caller_dc_2(
+ caller_->CreateDataChannel("data", init));
+
+ Negotiate();
+ WaitForConnection();
+ WaitForDataChannelsToOpen(caller_dc_1, callee_signaled_data_channels_, 0);
+ WaitForDataChannelsToOpen(caller_dc_2, callee_signaled_data_channels_, 1);
+
+ talk_base::scoped_ptr<webrtc::MockDataChannelObserver> dc_1_observer(
+ new webrtc::MockDataChannelObserver(callee_signaled_data_channels_[0]));
+
+ talk_base::scoped_ptr<webrtc::MockDataChannelObserver> dc_2_observer(
+ new webrtc::MockDataChannelObserver(callee_signaled_data_channels_[1]));
+
+ const std::string message_1 = "hello 1";
+ const std::string message_2 = "hello 2";
+
+ caller_dc_1->Send(webrtc::DataBuffer(message_1));
+ EXPECT_EQ_WAIT(message_1, dc_1_observer->last_message(), kMaxWait);
+
+ caller_dc_2->Send(webrtc::DataBuffer(message_2));
+ EXPECT_EQ_WAIT(message_2, dc_2_observer->last_message(), kMaxWait);
+
+ EXPECT_EQ(1U, dc_1_observer->received_message_count());
+ EXPECT_EQ(1U, dc_2_observer->received_message_count());
+}
#endif // if !defined(THREAD_SANITIZER)
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory.cc
index e8b8f63169c..3628c590535 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory.cc
@@ -51,7 +51,7 @@ typedef talk_base::TypedMessageData<bool> InitMessageData;
struct CreatePeerConnectionParams : public talk_base::MessageData {
CreatePeerConnectionParams(
- const webrtc::PeerConnectionInterface::IceServers& configuration,
+ const webrtc::PeerConnectionInterface::RTCConfiguration& configuration,
const webrtc::MediaConstraintsInterface* constraints,
webrtc::PortAllocatorFactoryInterface* allocator_factory,
webrtc::DTLSIdentityServiceInterface* dtls_identity_service,
@@ -63,28 +63,13 @@ struct CreatePeerConnectionParams : public talk_base::MessageData {
observer(observer) {
}
scoped_refptr<webrtc::PeerConnectionInterface> peerconnection;
- const webrtc::PeerConnectionInterface::IceServers& configuration;
+ const webrtc::PeerConnectionInterface::RTCConfiguration& configuration;
const webrtc::MediaConstraintsInterface* constraints;
scoped_refptr<webrtc::PortAllocatorFactoryInterface> allocator_factory;
webrtc::DTLSIdentityServiceInterface* dtls_identity_service;
webrtc::PeerConnectionObserver* observer;
};
-struct CreatePeerConnectionParamsDeprecated : public talk_base::MessageData {
- CreatePeerConnectionParamsDeprecated(
- const std::string& configuration,
- webrtc::PortAllocatorFactoryInterface* allocator_factory,
- webrtc::PeerConnectionObserver* observer)
- : configuration(configuration),
- allocator_factory(allocator_factory),
- observer(observer) {
- }
- scoped_refptr<webrtc::PeerConnectionInterface> peerconnection;
- const std::string& configuration;
- scoped_refptr<webrtc::PortAllocatorFactoryInterface> allocator_factory;
- webrtc::PeerConnectionObserver* observer;
-};
-
struct CreateAudioSourceParams : public talk_base::MessageData {
explicit CreateAudioSourceParams(
const webrtc::MediaConstraintsInterface* constraints)
@@ -105,21 +90,30 @@ struct CreateVideoSourceParams : public talk_base::MessageData {
scoped_refptr<webrtc::VideoSourceInterface> source;
};
+struct StartAecDumpParams : public talk_base::MessageData {
+ explicit StartAecDumpParams(talk_base::PlatformFile aec_dump_file)
+ : aec_dump_file(aec_dump_file) {
+ }
+ talk_base::PlatformFile aec_dump_file;
+ bool result;
+};
+
enum {
MSG_INIT_FACTORY = 1,
MSG_TERMINATE_FACTORY,
MSG_CREATE_PEERCONNECTION,
MSG_CREATE_AUDIOSOURCE,
MSG_CREATE_VIDEOSOURCE,
+ MSG_START_AEC_DUMP,
};
} // namespace
namespace webrtc {
-scoped_refptr<PeerConnectionFactoryInterface>
+talk_base::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory() {
- scoped_refptr<PeerConnectionFactory> pc_factory(
+ talk_base::scoped_refptr<PeerConnectionFactory> pc_factory(
new talk_base::RefCountedObject<PeerConnectionFactory>());
if (!pc_factory->Initialize()) {
@@ -128,17 +122,19 @@ CreatePeerConnectionFactory() {
return pc_factory;
}
-scoped_refptr<PeerConnectionFactoryInterface>
+talk_base::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory(
talk_base::Thread* worker_thread,
talk_base::Thread* signaling_thread,
AudioDeviceModule* default_adm,
cricket::WebRtcVideoEncoderFactory* encoder_factory,
cricket::WebRtcVideoDecoderFactory* decoder_factory) {
- scoped_refptr<PeerConnectionFactory> pc_factory(
- new talk_base::RefCountedObject<PeerConnectionFactory>(
- worker_thread, signaling_thread, default_adm,
- encoder_factory, decoder_factory));
+ talk_base::scoped_refptr<PeerConnectionFactory> pc_factory(
+ new talk_base::RefCountedObject<PeerConnectionFactory>(worker_thread,
+ signaling_thread,
+ default_adm,
+ encoder_factory,
+ decoder_factory));
if (!pc_factory->Initialize()) {
return NULL;
}
@@ -223,6 +219,12 @@ void PeerConnectionFactory::OnMessage(talk_base::Message* msg) {
pdata->source = CreateVideoSource_s(pdata->capturer, pdata->constraints);
break;
}
+ case MSG_START_AEC_DUMP: {
+ StartAecDumpParams* pdata =
+ static_cast<StartAecDumpParams*>(msg->pdata);
+ pdata->result = StartAecDump_s(pdata->aec_dump_file);
+ break;
+ }
}
}
@@ -245,6 +247,7 @@ bool PeerConnectionFactory::Initialize_s() {
channel_manager_.reset(new cricket::ChannelManager(
webrtc_media_engine, device_manager, worker_thread_));
+ channel_manager_->SetVideoRtxEnabled(true);
if (!channel_manager_->Init()) {
return false;
}
@@ -274,9 +277,13 @@ PeerConnectionFactory::CreateVideoSource_s(
return VideoSourceProxy::Create(signaling_thread_, source);
}
-scoped_refptr<PeerConnectionInterface>
+bool PeerConnectionFactory::StartAecDump_s(talk_base::PlatformFile file) {
+ return channel_manager_->StartAecDump(file);
+}
+
+talk_base::scoped_refptr<PeerConnectionInterface>
PeerConnectionFactory::CreatePeerConnection(
- const PeerConnectionInterface::IceServers& configuration,
+ const PeerConnectionInterface::RTCConfiguration& configuration,
const MediaConstraintsInterface* constraints,
PortAllocatorFactoryInterface* allocator_factory,
DTLSIdentityServiceInterface* dtls_identity_service,
@@ -284,23 +291,14 @@ PeerConnectionFactory::CreatePeerConnection(
CreatePeerConnectionParams params(configuration, constraints,
allocator_factory, dtls_identity_service,
observer);
- signaling_thread_->Send(this, MSG_CREATE_PEERCONNECTION, &params);
+ signaling_thread_->Send(
+ this, MSG_CREATE_PEERCONNECTION, &params);
return params.peerconnection;
}
-scoped_refptr<PeerConnectionInterface>
-PeerConnectionFactory::CreatePeerConnection(
- const PeerConnectionInterface::IceServers& configuration,
- const MediaConstraintsInterface* constraints,
- DTLSIdentityServiceInterface* dtls_identity_service,
- PeerConnectionObserver* observer) {
- return CreatePeerConnection(
- configuration, constraints, NULL, dtls_identity_service, observer);
-}
-
talk_base::scoped_refptr<PeerConnectionInterface>
PeerConnectionFactory::CreatePeerConnection_s(
- const PeerConnectionInterface::IceServers& configuration,
+ const PeerConnectionInterface::RTCConfiguration& configuration,
const MediaConstraintsInterface* constraints,
PortAllocatorFactoryInterface* allocator_factory,
DTLSIdentityServiceInterface* dtls_identity_service,
@@ -319,7 +317,7 @@ PeerConnectionFactory::CreatePeerConnection_s(
return PeerConnectionProxy::Create(signaling_thread(), pc);
}
-scoped_refptr<MediaStreamInterface>
+talk_base::scoped_refptr<MediaStreamInterface>
PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) {
return MediaStreamProxy::Create(signaling_thread_,
MediaStream::Create(label));
@@ -353,14 +351,20 @@ PeerConnectionFactory::CreateVideoTrack(
return VideoTrackProxy::Create(signaling_thread_, track);
}
-scoped_refptr<AudioTrackInterface> PeerConnectionFactory::CreateAudioTrack(
- const std::string& id,
- AudioSourceInterface* source) {
+talk_base::scoped_refptr<AudioTrackInterface>
+PeerConnectionFactory::CreateAudioTrack(const std::string& id,
+ AudioSourceInterface* source) {
talk_base::scoped_refptr<AudioTrackInterface> track(
AudioTrack::Create(id, source));
return AudioTrackProxy::Create(signaling_thread_, track);
}
+bool PeerConnectionFactory::StartAecDump(talk_base::PlatformFile file) {
+ StartAecDumpParams params(file);
+ signaling_thread_->Send(this, MSG_START_AEC_DUMP, &params);
+ return params.result;
+}
+
cricket::ChannelManager* PeerConnectionFactory::channel_manager() {
return channel_manager_.get();
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory.h b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory.h
index dff885dfe95..633d2811406 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory.h
@@ -46,18 +46,12 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface,
virtual talk_base::scoped_refptr<PeerConnectionInterface>
CreatePeerConnection(
- const PeerConnectionInterface::IceServers& configuration,
- const MediaConstraintsInterface* constraints,
- DTLSIdentityServiceInterface* dtls_identity_service,
- PeerConnectionObserver* observer);
-
- virtual talk_base::scoped_refptr<PeerConnectionInterface>
- CreatePeerConnection(
- const PeerConnectionInterface::IceServers& configuration,
+ const PeerConnectionInterface::RTCConfiguration& configuration,
const MediaConstraintsInterface* constraints,
PortAllocatorFactoryInterface* allocator_factory,
DTLSIdentityServiceInterface* dtls_identity_service,
PeerConnectionObserver* observer);
+
bool Initialize();
virtual talk_base::scoped_refptr<MediaStreamInterface>
@@ -78,6 +72,8 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface,
CreateAudioTrack(const std::string& id,
AudioSourceInterface* audio_source);
+ virtual bool StartAecDump(talk_base::PlatformFile file);
+
virtual cricket::ChannelManager* channel_manager();
virtual talk_base::Thread* signaling_thread();
virtual talk_base::Thread* worker_thread();
@@ -93,7 +89,6 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface,
cricket::WebRtcVideoDecoderFactory* video_decoder_factory);
virtual ~PeerConnectionFactory();
-
private:
bool Initialize_s();
void Terminate_s();
@@ -102,12 +97,16 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface,
talk_base::scoped_refptr<VideoSourceInterface> CreateVideoSource_s(
cricket::VideoCapturer* capturer,
const MediaConstraintsInterface* constraints);
+
talk_base::scoped_refptr<PeerConnectionInterface> CreatePeerConnection_s(
- const PeerConnectionInterface::IceServers& configuration,
+ const PeerConnectionInterface::RTCConfiguration& configuration,
const MediaConstraintsInterface* constraints,
PortAllocatorFactoryInterface* allocator_factory,
DTLSIdentityServiceInterface* dtls_identity_service,
PeerConnectionObserver* observer);
+
+ bool StartAecDump_s(talk_base::PlatformFile file);
+
// Implements talk_base::MessageHandler.
void OnMessage(talk_base::Message* msg);
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory_unittest.cc
index 4ab9e35c891..01f35d940dc 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionfactory_unittest.cc
@@ -156,7 +156,7 @@ TEST(PeerConnectionFactoryTestInternal, CreatePCUsingInternalModules) {
webrtc::PeerConnectionInterface::IceServers servers;
talk_base::scoped_refptr<PeerConnectionInterface> pc(
- factory->CreatePeerConnection(servers, NULL, NULL, &observer));
+ factory->CreatePeerConnection(servers, NULL, NULL, NULL, &observer));
EXPECT_TRUE(pc.get() != NULL);
}
@@ -164,6 +164,42 @@ TEST(PeerConnectionFactoryTestInternal, CreatePCUsingInternalModules) {
// This test verifies creation of PeerConnection with valid STUN and TURN
// configuration. Also verifies the URL's parsed correctly as expected.
TEST_F(PeerConnectionFactoryTest, CreatePCUsingIceServers) {
+ PeerConnectionInterface::RTCConfiguration config;
+ webrtc::PeerConnectionInterface::IceServer ice_server;
+ ice_server.uri = kStunIceServer;
+ config.servers.push_back(ice_server);
+ ice_server.uri = kTurnIceServer;
+ ice_server.password = kTurnPassword;
+ config.servers.push_back(ice_server);
+ ice_server.uri = kTurnIceServerWithTransport;
+ ice_server.password = kTurnPassword;
+ config.servers.push_back(ice_server);
+ talk_base::scoped_refptr<PeerConnectionInterface> pc(
+ factory_->CreatePeerConnection(config, NULL,
+ allocator_factory_.get(),
+ NULL,
+ &observer_));
+ EXPECT_TRUE(pc.get() != NULL);
+ StunConfigurations stun_configs;
+ webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1(
+ "stun.l.google.com", 19302);
+ stun_configs.push_back(stun1);
+ VerifyStunConfigurations(stun_configs);
+ TurnConfigurations turn_configs;
+ webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1(
+ "test.com", 1234, "test@hello.com", kTurnPassword, "udp", false);
+ turn_configs.push_back(turn1);
+ webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn2(
+ "hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false);
+ turn_configs.push_back(turn2);
+ VerifyTurnConfigurations(turn_configs);
+}
+
+// This test verifies creation of PeerConnection with valid STUN and TURN
+// configuration. Also verifies the URL's parsed correctly as expected.
+// This version doesn't use RTCConfiguration.
+// TODO(mallinath) - Remove this method after clients start using RTCConfig.
+TEST_F(PeerConnectionFactoryTest, CreatePCUsingIceServersOldSignature) {
webrtc::PeerConnectionInterface::IceServers ice_servers;
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.uri = kStunIceServer;
@@ -184,12 +220,6 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingIceServers) {
webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1(
"stun.l.google.com", 19302);
stun_configs.push_back(stun1);
- webrtc::PortAllocatorFactoryInterface::StunConfiguration stun2(
- "test.com", 1234);
- stun_configs.push_back(stun2);
- webrtc::PortAllocatorFactoryInterface::StunConfiguration stun3(
- "hello.com", kDefaultStunPort);
- stun_configs.push_back(stun3);
VerifyStunConfigurations(stun_configs);
TurnConfigurations turn_configs;
webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1(
@@ -202,16 +232,16 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingIceServers) {
}
TEST_F(PeerConnectionFactoryTest, CreatePCUsingNoUsernameInUri) {
- webrtc::PeerConnectionInterface::IceServers ice_servers;
+ PeerConnectionInterface::RTCConfiguration config;
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.uri = kStunIceServer;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
ice_server.uri = kTurnIceServerWithNoUsernameInUri;
ice_server.username = kTurnUsername;
ice_server.password = kTurnPassword;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
talk_base::scoped_refptr<PeerConnectionInterface> pc(
- factory_->CreatePeerConnection(ice_servers, NULL,
+ factory_->CreatePeerConnection(config, NULL,
allocator_factory_.get(),
NULL,
&observer_));
@@ -226,13 +256,13 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingNoUsernameInUri) {
// This test verifies the PeerConnection created properly with TURN url which
// has transport parameter in it.
TEST_F(PeerConnectionFactoryTest, CreatePCUsingTurnUrlWithTransportParam) {
- webrtc::PeerConnectionInterface::IceServers ice_servers;
+ PeerConnectionInterface::RTCConfiguration config;
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.uri = kTurnIceServerWithTransport;
ice_server.password = kTurnPassword;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
talk_base::scoped_refptr<PeerConnectionInterface> pc(
- factory_->CreatePeerConnection(ice_servers, NULL,
+ factory_->CreatePeerConnection(config, NULL,
allocator_factory_.get(),
NULL,
&observer_));
@@ -242,27 +272,22 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingTurnUrlWithTransportParam) {
"hello.com", kDefaultStunPort, "test", kTurnPassword, "tcp", false);
turn_configs.push_back(turn);
VerifyTurnConfigurations(turn_configs);
- StunConfigurations stun_configs;
- webrtc::PortAllocatorFactoryInterface::StunConfiguration stun(
- "hello.com", kDefaultStunPort);
- stun_configs.push_back(stun);
- VerifyStunConfigurations(stun_configs);
}
TEST_F(PeerConnectionFactoryTest, CreatePCUsingSecureTurnUrl) {
- webrtc::PeerConnectionInterface::IceServers ice_servers;
+ PeerConnectionInterface::RTCConfiguration config;
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.uri = kSecureTurnIceServer;
ice_server.password = kTurnPassword;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
ice_server.uri = kSecureTurnIceServerWithoutTransportParam;
ice_server.password = kTurnPassword;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
ice_server.uri = kSecureTurnIceServerWithoutTransportAndPortParam;
ice_server.password = kTurnPassword;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
talk_base::scoped_refptr<PeerConnectionInterface> pc(
- factory_->CreatePeerConnection(ice_servers, NULL,
+ factory_->CreatePeerConnection(config, NULL,
allocator_factory_.get(),
NULL,
&observer_));
@@ -283,23 +308,23 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingSecureTurnUrl) {
}
TEST_F(PeerConnectionFactoryTest, CreatePCUsingIPLiteralAddress) {
- webrtc::PeerConnectionInterface::IceServers ice_servers;
+ PeerConnectionInterface::RTCConfiguration config;
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.uri = kStunIceServerWithIPv4Address;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
ice_server.uri = kStunIceServerWithIPv4AddressWithoutPort;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
ice_server.uri = kStunIceServerWithIPv6Address;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
ice_server.uri = kStunIceServerWithIPv6AddressWithoutPort;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
ice_server.uri = kStunIceServerWithInvalidIPv6Address;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
ice_server.uri = kTurnIceServerWithIPv6Address;
ice_server.password = kTurnPassword;
- ice_servers.push_back(ice_server);
+ config.servers.push_back(ice_server);
talk_base::scoped_refptr<PeerConnectionInterface> pc(
- factory_->CreatePeerConnection(ice_servers, NULL,
+ factory_->CreatePeerConnection(config, NULL,
allocator_factory_.get(),
NULL,
&observer_));
@@ -317,9 +342,8 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingIPLiteralAddress) {
webrtc::PortAllocatorFactoryInterface::StunConfiguration stun4(
"2401:fa00:4::", 3478);
stun_configs.push_back(stun4); // Default port
- // Turn Address has the same host information as |stun3|.
- stun_configs.push_back(stun3);
VerifyStunConfigurations(stun_configs);
+
TurnConfigurations turn_configs;
webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1(
"2401:fa00:4::", 1234, "test", kTurnPassword, "udp", false);
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h
index a127dad3a9d..ed4033c17d6 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h
@@ -76,6 +76,8 @@
#include "talk/app/webrtc/jsep.h"
#include "talk/app/webrtc/mediastreaminterface.h"
#include "talk/app/webrtc/statstypes.h"
+#include "talk/app/webrtc/umametrics.h"
+#include "talk/base/fileutils.h"
#include "talk/base/socketaddress.h"
namespace talk_base {
@@ -117,6 +119,16 @@ class StatsObserver : public talk_base::RefCountInterface {
virtual ~StatsObserver() {}
};
+class UMAObserver : public talk_base::RefCountInterface {
+ public:
+ virtual void IncrementCounter(PeerConnectionUMAMetricsCounter type) = 0;
+ virtual void AddHistogramSample(PeerConnectionUMAMetricsName type,
+ int value) = 0;
+
+ protected:
+ virtual ~UMAObserver() {}
+};
+
class PeerConnectionInterface : public talk_base::RefCountInterface {
public:
// See http://dev.w3.org/2011/webrtc/editor/webrtc.html#state-definitions .
@@ -165,6 +177,30 @@ class PeerConnectionInterface : public talk_base::RefCountInterface {
};
typedef std::vector<IceServer> IceServers;
+ enum IceTransportsType {
+ kNone,
+ kRelay,
+ kNoHost,
+ kAll
+ };
+
+ struct RTCConfiguration {
+ IceTransportsType type;
+ IceServers servers;
+
+ RTCConfiguration() : type(kAll) {}
+ explicit RTCConfiguration(IceTransportsType type) : type(type) {}
+ };
+
+ // Used by GetStats to decide which stats to include in the stats reports.
+ // |kStatsOutputLevelStandard| includes the standard stats for Javascript API;
+ // |kStatsOutputLevelDebug| includes both the standard stats and additional
+ // stats for debugging purposes.
+ enum StatsOutputLevel {
+ kStatsOutputLevelStandard,
+ kStatsOutputLevelDebug,
+ };
+
// Accessor methods to active local streams.
virtual talk_base::scoped_refptr<StreamCollectionInterface>
local_streams() = 0;
@@ -190,7 +226,8 @@ class PeerConnectionInterface : public talk_base::RefCountInterface {
AudioTrackInterface* track) = 0;
virtual bool GetStats(StatsObserver* observer,
- MediaStreamTrackInterface* track) = 0;
+ MediaStreamTrackInterface* track,
+ StatsOutputLevel level) = 0;
virtual talk_base::scoped_refptr<DataChannelInterface> CreateDataChannel(
const std::string& label,
@@ -229,6 +266,8 @@ class PeerConnectionInterface : public talk_base::RefCountInterface {
// take the ownership of the |candidate|.
virtual bool AddIceCandidate(const IceCandidateInterface* candidate) = 0;
+ virtual void RegisterUMAObserver(UMAObserver* observer) = 0;
+
// Returns the current SignalingState.
virtual SignalingState signaling_state() = 0;
@@ -276,8 +315,8 @@ class PeerConnectionObserver {
// TODO(perkj): Make pure virtual.
virtual void OnDataChannel(DataChannelInterface* data_channel) {}
- // Triggered when renegotation is needed, for example the ICE has restarted.
- virtual void OnRenegotiationNeeded() {}
+ // Triggered when renegotiation is needed, for example the ICE has restarted.
+ virtual void OnRenegotiationNeeded() = 0;
// Called any time the IceConnectionState changes
virtual void OnIceConnectionChange(
@@ -393,29 +432,42 @@ class PeerConnectionFactoryInterface : public talk_base::RefCountInterface {
class Options {
public:
Options() :
- enable_aec_dump(false),
disable_encryption(false),
disable_sctp_data_channels(false) {
}
- bool enable_aec_dump;
bool disable_encryption;
bool disable_sctp_data_channels;
};
virtual void SetOptions(const Options& options) = 0;
- virtual talk_base::scoped_refptr<PeerConnectionInterface>
- CreatePeerConnection(
- const PeerConnectionInterface::IceServers& configuration,
- const MediaConstraintsInterface* constraints,
- DTLSIdentityServiceInterface* dtls_identity_service,
- PeerConnectionObserver* observer) = 0;
+
virtual talk_base::scoped_refptr<PeerConnectionInterface>
CreatePeerConnection(
- const PeerConnectionInterface::IceServers& configuration,
+ const PeerConnectionInterface::RTCConfiguration& configuration,
const MediaConstraintsInterface* constraints,
PortAllocatorFactoryInterface* allocator_factory,
DTLSIdentityServiceInterface* dtls_identity_service,
PeerConnectionObserver* observer) = 0;
+
+ // TODO(mallinath) : Remove below versions after clients are updated
+ // to above method.
+ // In latest W3C WebRTC draft, PC constructor will take RTCConfiguration,
+ // and not IceServers. RTCConfiguration is made up of ice servers and
+ // ice transport type.
+ // http://dev.w3.org/2011/webrtc/editor/webrtc.html
+ inline talk_base::scoped_refptr<PeerConnectionInterface>
+ CreatePeerConnection(
+ const PeerConnectionInterface::IceServers& configuration,
+ const MediaConstraintsInterface* constraints,
+ PortAllocatorFactoryInterface* allocator_factory,
+ DTLSIdentityServiceInterface* dtls_identity_service,
+ PeerConnectionObserver* observer) {
+ PeerConnectionInterface::RTCConfiguration rtc_config;
+ rtc_config.servers = configuration;
+ return CreatePeerConnection(rtc_config, constraints, allocator_factory,
+ dtls_identity_service, observer);
+ }
+
virtual talk_base::scoped_refptr<MediaStreamInterface>
CreateLocalMediaStream(const std::string& label) = 0;
@@ -442,6 +494,13 @@ class PeerConnectionFactoryInterface : public talk_base::RefCountInterface {
CreateAudioTrack(const std::string& label,
AudioSourceInterface* source) = 0;
+ // Starts AEC dump using existing file. Takes ownership of |file| and passes
+ // it on to VoiceEngine (via other objects) immediately, which will take
+ // the ownerhip. If the operation fails, the file will be closed.
+ // TODO(grunell): Remove when Chromium has started to use AEC in each source.
+ // http://crbug.com/264611.
+ virtual bool StartAecDump(talk_base::PlatformFile file) = 0;
+
protected:
// Dtor and ctor protected as objects shouldn't be created or deleted via
// this interface.
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface_unittest.cc
index 093b8426856..5c9b826dac0 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface_unittest.cc
@@ -32,6 +32,7 @@
#include "talk/app/webrtc/mediastreaminterface.h"
#include "talk/app/webrtc/peerconnectioninterface.h"
#include "talk/app/webrtc/test/fakeconstraints.h"
+#include "talk/app/webrtc/test/fakedtlsidentityservice.h"
#include "talk/app/webrtc/test/mockpeerconnectionobservers.h"
#include "talk/app/webrtc/test/testsdpstrings.h"
#include "talk/app/webrtc/videosource.h"
@@ -257,9 +258,21 @@ class PeerConnectionInterfaceTest : public testing::Test {
servers.push_back(server);
port_allocator_factory_ = FakePortAllocatorFactory::Create();
+
+ // DTLS does not work in a loopback call, so is disabled for most of the
+ // tests in this file. We only create a FakeIdentityService if the test
+ // explicitly sets the constraint.
+ FakeIdentityService* dtls_service = NULL;
+ bool dtls;
+ if (FindConstraint(constraints,
+ webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
+ &dtls,
+ NULL) && dtls) {
+ dtls_service = new FakeIdentityService();
+ }
pc_ = pc_factory_->CreatePeerConnection(servers, constraints,
port_allocator_factory_.get(),
- NULL,
+ dtls_service,
&observer_);
ASSERT_TRUE(pc_.get() != NULL);
observer_.SetPeerConnectionInterface(pc_.get());
@@ -288,7 +301,7 @@ class PeerConnectionInterfaceTest : public testing::Test {
EXPECT_EQ(0u, port_allocator_factory_->turn_configs().size());
CreatePeerConnection(kTurnIceServerUri, kTurnPassword, NULL);
- EXPECT_EQ(1u, port_allocator_factory_->stun_configs().size());
+ EXPECT_EQ(0u, port_allocator_factory_->stun_configs().size());
EXPECT_EQ(1u, port_allocator_factory_->turn_configs().size());
EXPECT_EQ(kTurnUsername,
port_allocator_factory_->turn_configs()[0].username);
@@ -296,8 +309,6 @@ class PeerConnectionInterfaceTest : public testing::Test {
port_allocator_factory_->turn_configs()[0].password);
EXPECT_EQ(kTurnHostname,
port_allocator_factory_->turn_configs()[0].server.hostname());
- EXPECT_EQ(kTurnHostname,
- port_allocator_factory_->stun_configs()[0].server.hostname());
}
void ReleasePeerConnection() {
@@ -398,7 +409,8 @@ class PeerConnectionInterfaceTest : public testing::Test {
bool DoGetStats(MediaStreamTrackInterface* track) {
talk_base::scoped_refptr<MockStatsObserver> observer(
new talk_base::RefCountedObject<MockStatsObserver>());
- if (!pc_->GetStats(observer, track))
+ if (!pc_->GetStats(
+ observer, track, PeerConnectionInterface::kStatsOutputLevelStandard))
return false;
EXPECT_TRUE_WAIT(observer->called(), kTimeout);
return observer->called();
@@ -496,6 +508,8 @@ class PeerConnectionInterfaceTest : public testing::Test {
EXPECT_TRUE(DoSetLocalDescription(new_offer));
EXPECT_EQ(PeerConnectionInterface::kHaveLocalOffer, observer_.state_);
+ // Wait for the ice_complete message, so that SDP will have candidates.
+ EXPECT_TRUE_WAIT(observer_.ice_complete_, kTimeout);
}
void CreateAnswerAsRemoteDescription(const std::string& offer) {
@@ -766,13 +780,7 @@ TEST_F(PeerConnectionInterfaceTest, GetStatsForInvalidTrack) {
}
// This test setup two RTP data channels in loop back.
-#ifdef WIN32
-// TODO(perkj): Investigate why the transport channel sometimes don't become
-// writable on Windows when we try to connect in loop back.
-TEST_F(PeerConnectionInterfaceTest, DISABLED_TestDataChannel) {
-#else
TEST_F(PeerConnectionInterfaceTest, TestDataChannel) {
-#endif
FakeConstraints constraints;
constraints.SetAllowRtpDataChannels();
CreatePeerConnection(&constraints);
@@ -819,13 +827,7 @@ TEST_F(PeerConnectionInterfaceTest, TestDataChannel) {
// This test verifies that sendnig binary data over RTP data channels should
// fail.
-#ifdef WIN32
-// TODO(perkj): Investigate why the transport channel sometimes don't become
-// writable on Windows when we try to connect in loop back.
-TEST_F(PeerConnectionInterfaceTest, DISABLED_TestSendBinaryOnRtpDataChannel) {
-#else
TEST_F(PeerConnectionInterfaceTest, TestSendBinaryOnRtpDataChannel) {
-#endif
FakeConstraints constraints;
constraints.SetAllowRtpDataChannels();
CreatePeerConnection(&constraints);
@@ -855,13 +857,7 @@ TEST_F(PeerConnectionInterfaceTest, TestSendBinaryOnRtpDataChannel) {
// This test setup a RTP data channels in loop back and test that a channel is
// opened even if the remote end answer with a zero SSRC.
-#ifdef WIN32
-// TODO(perkj): Investigate why the transport channel sometimes don't become
-// writable on Windows when we try to connect in loop back.
-TEST_F(PeerConnectionInterfaceTest, DISABLED_TestSendOnlyDataChannel) {
-#else
TEST_F(PeerConnectionInterfaceTest, TestSendOnlyDataChannel) {
-#endif
FakeConstraints constraints;
constraints.SetAllowRtpDataChannels();
CreatePeerConnection(&constraints);
@@ -950,23 +946,28 @@ TEST_F(PeerConnectionInterfaceTest, CreateSctpDataChannel) {
pc_->CreateDataChannel("1", &config);
EXPECT_TRUE(channel != NULL);
EXPECT_TRUE(channel->reliable());
+ EXPECT_TRUE(observer_.renegotiation_needed_);
+ observer_.renegotiation_needed_ = false;
config.ordered = false;
channel = pc_->CreateDataChannel("2", &config);
EXPECT_TRUE(channel != NULL);
EXPECT_TRUE(channel->reliable());
+ EXPECT_FALSE(observer_.renegotiation_needed_);
config.ordered = true;
config.maxRetransmits = 0;
channel = pc_->CreateDataChannel("3", &config);
EXPECT_TRUE(channel != NULL);
EXPECT_FALSE(channel->reliable());
+ EXPECT_FALSE(observer_.renegotiation_needed_);
config.maxRetransmits = -1;
config.maxRetransmitTime = 0;
channel = pc_->CreateDataChannel("4", &config);
EXPECT_TRUE(channel != NULL);
EXPECT_FALSE(channel->reliable());
+ EXPECT_FALSE(observer_.renegotiation_needed_);
}
// This tests that no data channel is returned if both maxRetransmits and
@@ -1016,15 +1017,25 @@ TEST_F(PeerConnectionInterfaceTest,
EXPECT_TRUE(channel == NULL);
}
+// This test verifies that OnRenegotiationNeeded is fired for every new RTP
+// DataChannel.
+TEST_F(PeerConnectionInterfaceTest, RenegotiationNeededForNewRtpDataChannel) {
+ FakeConstraints constraints;
+ constraints.SetAllowRtpDataChannels();
+ CreatePeerConnection(&constraints);
+
+ scoped_refptr<DataChannelInterface> dc1 =
+ pc_->CreateDataChannel("test1", NULL);
+ EXPECT_TRUE(observer_.renegotiation_needed_);
+ observer_.renegotiation_needed_ = false;
+
+ scoped_refptr<DataChannelInterface> dc2 =
+ pc_->CreateDataChannel("test2", NULL);
+ EXPECT_TRUE(observer_.renegotiation_needed_);
+}
+
// This test that a data channel closes when a PeerConnection is deleted/closed.
-#ifdef WIN32
-// TODO(perkj): Investigate why the transport channel sometimes don't become
-// writable on Windows when we try to connect in loop back.
-TEST_F(PeerConnectionInterfaceTest,
- DISABLED_DataChannelCloseWhenPeerConnectionClose) {
-#else
TEST_F(PeerConnectionInterfaceTest, DataChannelCloseWhenPeerConnectionClose) {
-#endif
FakeConstraints constraints;
constraints.SetAllowRtpDataChannels();
CreatePeerConnection(&constraints);
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionproxy.h b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionproxy.h
index f07416d65c4..74e5012bb14 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionproxy.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/peerconnectionproxy.h
@@ -44,7 +44,9 @@ BEGIN_PROXY_MAP(PeerConnection)
PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*)
PROXY_METHOD1(talk_base::scoped_refptr<DtmfSenderInterface>,
CreateDtmfSender, AudioTrackInterface*)
- PROXY_METHOD2(bool, GetStats, StatsObserver*, MediaStreamTrackInterface*)
+ PROXY_METHOD3(bool, GetStats, StatsObserver*,
+ MediaStreamTrackInterface*,
+ StatsOutputLevel)
PROXY_METHOD2(talk_base::scoped_refptr<DataChannelInterface>,
CreateDataChannel, const std::string&, const DataChannelInit*)
PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description)
@@ -60,6 +62,7 @@ BEGIN_PROXY_MAP(PeerConnection)
PROXY_METHOD2(bool, UpdateIce, const IceServers&,
const MediaConstraintsInterface*)
PROXY_METHOD1(bool, AddIceCandidate, const IceCandidateInterface*)
+ PROXY_METHOD1(void, RegisterUMAObserver, UMAObserver*)
PROXY_METHOD0(SignalingState, signaling_state)
PROXY_METHOD0(IceState, ice_state)
PROXY_METHOD0(IceConnectionState, ice_connection_state)
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/portallocatorfactory.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/portallocatorfactory.cc
index 32008f6b5b0..decd33c7b6e 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/portallocatorfactory.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/portallocatorfactory.cc
@@ -33,8 +33,6 @@
#include "talk/p2p/base/basicpacketsocketfactory.h"
#include "talk/p2p/client/basicportallocator.h"
-static const char kUserAgent[] = "PeerConnection User Agent";
-
namespace webrtc {
using talk_base::scoped_ptr;
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/remoteaudiosource.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/remoteaudiosource.cc
new file mode 100644
index 00000000000..1c275c74c67
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/remoteaudiosource.cc
@@ -0,0 +1,72 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/app/webrtc/remoteaudiosource.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "talk/base/logging.h"
+
+namespace webrtc {
+
+talk_base::scoped_refptr<RemoteAudioSource> RemoteAudioSource::Create() {
+ return new talk_base::RefCountedObject<RemoteAudioSource>();
+}
+
+RemoteAudioSource::RemoteAudioSource() {
+}
+
+RemoteAudioSource::~RemoteAudioSource() {
+ ASSERT(audio_observers_.empty());
+}
+
+MediaSourceInterface::SourceState RemoteAudioSource::state() const {
+ return MediaSourceInterface::kLive;
+}
+
+void RemoteAudioSource::SetVolume(double volume) {
+ ASSERT(volume >= 0 && volume <= 10);
+ for (AudioObserverList::iterator it = audio_observers_.begin();
+ it != audio_observers_.end(); ++it) {
+ (*it)->OnSetVolume(volume);
+ }
+}
+
+void RemoteAudioSource::RegisterAudioObserver(AudioObserver* observer) {
+ ASSERT(observer != NULL);
+ ASSERT(std::find(audio_observers_.begin(), audio_observers_.end(),
+ observer) == audio_observers_.end());
+ audio_observers_.push_back(observer);
+}
+
+void RemoteAudioSource::UnregisterAudioObserver(AudioObserver* observer) {
+ ASSERT(observer != NULL);
+ audio_observers_.remove(observer);
+}
+
+} // namespace webrtc
diff --git a/chromium/third_party/libjingle/source/talk/examples/chat/textchatreceivetask.h b/chromium/third_party/libjingle/source/talk/app/webrtc/remoteaudiosource.h
index e2776927a72..ed2421449af 100644
--- a/chromium/third_party/libjingle/source/talk/examples/chat/textchatreceivetask.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/remoteaudiosource.h
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2013, Google Inc.
+ * Copyright 2014, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,39 +25,42 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TALK_EXAMPLES_CHAT_TEXTCHATRECEIVETASK_H_
-#define TALK_EXAMPLES_CHAT_TEXTCHATRECEIVETASK_H_
+#ifndef TALK_APP_WEBRTC_REMOTEAUDIOSOURCE_H_
+#define TALK_APP_WEBRTC_REMOTEAUDIOSOURCE_H_
-#include "talk/base/sigslot.h"
-#include "talk/xmpp/xmpptask.h"
+#include <list>
-namespace buzz {
+#include "talk/app/webrtc/mediastreaminterface.h"
+#include "talk/app/webrtc/notifier.h"
-// A class to receive chat messages from the XMPP server.
-class TextChatReceiveTask : public XmppTask {
+namespace webrtc {
+
+using webrtc::AudioSourceInterface;
+
+// This class implements the audio source used by the remote audio track.
+class RemoteAudioSource : public Notifier<AudioSourceInterface> {
public:
- // Arguments:
- // parent a reference to task interface associated withe the XMPP client.
- explicit TextChatReceiveTask(XmppTaskParentInterface* parent);
+ // Creates an instance of RemoteAudioSource.
+ static talk_base::scoped_refptr<RemoteAudioSource> Create();
+
+ protected:
+ RemoteAudioSource();
+ virtual ~RemoteAudioSource();
- // Shuts down the thread associated with this task.
- virtual ~TextChatReceiveTask();
+ private:
+ typedef std::list<AudioObserver*> AudioObserverList;
- // Starts pulling queued status messages and dispatching them to the
- // PresenceUpdate() callback.
- virtual int ProcessStart();
+ // MediaSourceInterface implementation.
+ virtual MediaSourceInterface::SourceState state() const OVERRIDE;
- // Slot for chat message callbacks
- sigslot::signal3<const Jid&, const Jid&, const std::string&>
- SignalTextChatReceived;
+ // AudioSourceInterface implementation.
+ virtual void SetVolume(double volume) OVERRIDE;
+ virtual void RegisterAudioObserver(AudioObserver* observer) OVERRIDE;
+ virtual void UnregisterAudioObserver(AudioObserver* observer) OVERRIDE;
- protected:
- // Called by the XMPP client when chat stanzas arrive. We pull out the
- // interesting parts and send them to the SignalTextCharReceived() slot.
- virtual bool HandleStanza(const XmlElement* stanza);
+ AudioObserverList audio_observers_;
};
-} // namespace buzz
-
-#endif // TALK_EXAMPLES_CHAT_TEXTCHATRECEIVETASK_H_
+} // namespace webrtc
+#endif // TALK_APP_WEBRTC_REMOTEAUDIOSOURCE_H_
diff --git a/chromium/third_party/libjingle/source/talk/media/sctp/sctputils.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/sctputils.cc
index 4073905de7e..dcc6ba6eac3 100644
--- a/chromium/third_party/libjingle/source/talk/media/sctp/sctputils.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/sctputils.cc
@@ -25,19 +25,19 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "talk/media/sctp/sctputils.h"
+#include "talk/app/webrtc/sctputils.h"
-#include "talk/app/webrtc/datachannelinterface.h"
#include "talk/base/buffer.h"
#include "talk/base/bytebuffer.h"
#include "talk/base/logging.h"
-namespace cricket {
+namespace webrtc {
// Format defined at
-// http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-00#section-6.1
+// http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-01#section
static const uint8 DATA_CHANNEL_OPEN_MESSAGE_TYPE = 0x03;
+static const uint8 DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE = 0x02;
enum DataChannelOpenMessageChannelType {
DCOMCT_ORDERED_RELIABLE = 0x00,
@@ -48,10 +48,9 @@ enum DataChannelOpenMessageChannelType {
DCOMCT_UNORDERED_PARTIAL_TIME = 0x82,
};
-bool ParseDataChannelOpenMessage(
- const talk_base::Buffer& payload,
- std::string* label,
- webrtc::DataChannelInit* config) {
+bool ParseDataChannelOpenMessage(const talk_base::Buffer& payload,
+ std::string* label,
+ DataChannelInit* config) {
// Format defined at
// http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
@@ -123,14 +122,28 @@ bool ParseDataChannelOpenMessage(
config->maxRetransmitTime = reliability_param;
break;
}
+ return true;
+}
+
+bool ParseDataChannelOpenAckMessage(const talk_base::Buffer& payload) {
+ talk_base::ByteBuffer buffer(payload.data(), payload.length());
+ uint8 message_type;
+ if (!buffer.ReadUInt8(&message_type)) {
+ LOG(LS_WARNING) << "Could not read OPEN_ACK message type.";
+ return false;
+ }
+ if (message_type != DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE) {
+ LOG(LS_WARNING) << "Data Channel OPEN_ACK message of unexpected type: "
+ << message_type;
+ return false;
+ }
return true;
}
-bool WriteDataChannelOpenMessage(
- const std::string& label,
- const webrtc::DataChannelInit& config,
- talk_base::Buffer* payload) {
+bool WriteDataChannelOpenMessage(const std::string& label,
+ const DataChannelInit& config,
+ talk_base::Buffer* payload) {
// Format defined at
// http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-00#section-6.1
uint8 channel_type = 0;
@@ -173,4 +186,9 @@ bool WriteDataChannelOpenMessage(
return true;
}
-} // namespace cricket
+void WriteDataChannelOpenAckMessage(talk_base::Buffer* payload) {
+ talk_base::ByteBuffer buffer(talk_base::ByteBuffer::ORDER_NETWORK);
+ buffer.WriteUInt8(DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE);
+ payload->SetData(buffer.Data(), buffer.Length());
+}
+} // namespace webrtc
diff --git a/chromium/third_party/libjingle/source/talk/media/sctp/sctputils.h b/chromium/third_party/libjingle/source/talk/app/webrtc/sctputils.h
index d349274a9a6..d0b4e9c36b2 100644
--- a/chromium/third_party/libjingle/source/talk/media/sctp/sctputils.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/sctputils.h
@@ -25,29 +25,31 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TALK_MEDIA_BASE_SCTPUTILS_H_
-#define TALK_MEDIA_BASE_SCTPUTILS_H_
+#ifndef TALK_APP_WEBRTC_SCTPUTILS_H_
+#define TALK_APP_WEBRTC_SCTPUTILS_H_
#include <string>
+#include "talk/app/webrtc/datachannelinterface.h"
+
namespace talk_base {
class Buffer;
} // namespace talk_base
namespace webrtc {
struct DataChannelInit;
-} // namespace webrtc
-
-namespace cricket {
bool ParseDataChannelOpenMessage(const talk_base::Buffer& payload,
std::string* label,
- webrtc::DataChannelInit* config);
+ DataChannelInit* config);
+
+bool ParseDataChannelOpenAckMessage(const talk_base::Buffer& payload);
bool WriteDataChannelOpenMessage(const std::string& label,
- const webrtc::DataChannelInit& config,
+ const DataChannelInit& config,
talk_base::Buffer* payload);
-} // namespace cricket
+void WriteDataChannelOpenAckMessage(talk_base::Buffer* payload);
+} // namespace webrtc
-#endif // TALK_MEDIA_BASE_SCTPUTILS_H_
+#endif // TALK_APP_WEBRTC_SCTPUTILS_H_
diff --git a/chromium/third_party/libjingle/source/talk/media/sctp/sctputils_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/sctputils_unittest.cc
index 70f67b8b581..6a139a04c20 100644
--- a/chromium/third_party/libjingle/source/talk/media/sctp/sctputils_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/sctputils_unittest.cc
@@ -25,10 +25,9 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "talk/app/webrtc/datachannelinterface.h"
#include "talk/base/bytebuffer.h"
#include "talk/base/gunit.h"
-#include "talk/media/sctp/sctputils.h"
+#include "talk/app/webrtc/sctputils.h"
class SctpUtilsTest : public testing::Test {
public:
@@ -80,23 +79,22 @@ class SctpUtilsTest : public testing::Test {
}
};
-TEST_F(SctpUtilsTest, WriteParseMessageWithOrderedReliable) {
- std::string input_label = "abc";
+TEST_F(SctpUtilsTest, WriteParseOpenMessageWithOrderedReliable) {
webrtc::DataChannelInit config;
+ std::string label = "abc";
config.protocol = "y";
talk_base::Buffer packet;
- ASSERT_TRUE(
- cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
+ ASSERT_TRUE(webrtc::WriteDataChannelOpenMessage(label, config, &packet));
- VerifyOpenMessageFormat(packet, input_label, config);
+ VerifyOpenMessageFormat(packet, label, config);
std::string output_label;
webrtc::DataChannelInit output_config;
- ASSERT_TRUE(cricket::ParseDataChannelOpenMessage(
+ ASSERT_TRUE(webrtc::ParseDataChannelOpenMessage(
packet, &output_label, &output_config));
- EXPECT_EQ(input_label, output_label);
+ EXPECT_EQ(label, output_label);
EXPECT_EQ(config.protocol, output_config.protocol);
EXPECT_EQ(config.ordered, output_config.ordered);
EXPECT_EQ(config.maxRetransmitTime, output_config.maxRetransmitTime);
@@ -104,24 +102,23 @@ TEST_F(SctpUtilsTest, WriteParseMessageWithOrderedReliable) {
}
TEST_F(SctpUtilsTest, WriteParseOpenMessageWithMaxRetransmitTime) {
- std::string input_label = "abc";
webrtc::DataChannelInit config;
+ std::string label = "abc";
config.ordered = false;
config.maxRetransmitTime = 10;
config.protocol = "y";
talk_base::Buffer packet;
- ASSERT_TRUE(
- cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
+ ASSERT_TRUE(webrtc::WriteDataChannelOpenMessage(label, config, &packet));
- VerifyOpenMessageFormat(packet, input_label, config);
+ VerifyOpenMessageFormat(packet, label, config);
std::string output_label;
webrtc::DataChannelInit output_config;
- ASSERT_TRUE(cricket::ParseDataChannelOpenMessage(
+ ASSERT_TRUE(webrtc::ParseDataChannelOpenMessage(
packet, &output_label, &output_config));
- EXPECT_EQ(input_label, output_label);
+ EXPECT_EQ(label, output_label);
EXPECT_EQ(config.protocol, output_config.protocol);
EXPECT_EQ(config.ordered, output_config.ordered);
EXPECT_EQ(config.maxRetransmitTime, output_config.maxRetransmitTime);
@@ -129,25 +126,36 @@ TEST_F(SctpUtilsTest, WriteParseOpenMessageWithMaxRetransmitTime) {
}
TEST_F(SctpUtilsTest, WriteParseOpenMessageWithMaxRetransmits) {
- std::string input_label = "abc";
webrtc::DataChannelInit config;
+ std::string label = "abc";
config.maxRetransmits = 10;
config.protocol = "y";
talk_base::Buffer packet;
- ASSERT_TRUE(
- cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
+ ASSERT_TRUE(webrtc::WriteDataChannelOpenMessage(label, config, &packet));
- VerifyOpenMessageFormat(packet, input_label, config);
+ VerifyOpenMessageFormat(packet, label, config);
std::string output_label;
webrtc::DataChannelInit output_config;
- ASSERT_TRUE(cricket::ParseDataChannelOpenMessage(
+ ASSERT_TRUE(webrtc::ParseDataChannelOpenMessage(
packet, &output_label, &output_config));
- EXPECT_EQ(input_label, output_label);
+ EXPECT_EQ(label, output_label);
EXPECT_EQ(config.protocol, output_config.protocol);
EXPECT_EQ(config.ordered, output_config.ordered);
EXPECT_EQ(config.maxRetransmits, output_config.maxRetransmits);
EXPECT_EQ(-1, output_config.maxRetransmitTime);
}
+
+TEST_F(SctpUtilsTest, WriteParseAckMessage) {
+ talk_base::Buffer packet;
+ webrtc::WriteDataChannelOpenAckMessage(&packet);
+
+ uint8 message_type;
+ talk_base::ByteBuffer buffer(packet.data(), packet.length());
+ ASSERT_TRUE(buffer.ReadUInt8(&message_type));
+ EXPECT_EQ(0x02, message_type);
+
+ EXPECT_TRUE(webrtc::ParseDataChannelOpenAckMessage(packet));
+}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector.cc
index 7e1e7eec662..67d64fbe8db 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector.cc
@@ -63,6 +63,18 @@ const char StatsReport::kStatsValueNameComponent[] = "googComponent";
const char StatsReport::kStatsValueNameContentName[] = "googContentName";
const char StatsReport::kStatsValueNameCpuLimitedResolution[] =
"googCpuLimitedResolution";
+const char StatsReport::kStatsValueNameDecodingCTSG[] =
+ "googDecodingCTSG";
+const char StatsReport::kStatsValueNameDecodingCTN[] =
+ "googDecodingCTN";
+const char StatsReport::kStatsValueNameDecodingNormal[] =
+ "googDecodingNormal";
+const char StatsReport::kStatsValueNameDecodingPLC[] =
+ "googDecodingPLC";
+const char StatsReport::kStatsValueNameDecodingCNG[] =
+ "googDecodingCNG";
+const char StatsReport::kStatsValueNameDecodingPLCCNG[] =
+ "googDecodingPLCCNG";
const char StatsReport::kStatsValueNameDer[] = "googDerBase64";
// Echo metrics from the audio processing module.
const char StatsReport::kStatsValueNameEchoCancellationQualityMin[] =
@@ -76,13 +88,18 @@ const char StatsReport::kStatsValueNameEchoReturnLoss[] =
const char StatsReport::kStatsValueNameEchoReturnLossEnhancement[] =
"googEchoCancellationReturnLossEnhancement";
+const char StatsReport::kStatsValueNameEncodeRelStdDev[] =
+ "googEncodeRelStdDev";
const char StatsReport::kStatsValueNameEncodeUsagePercent[] =
"googEncodeUsagePercent";
+const char StatsReport::kStatsValueNameExpandRate[] = "googExpandRate";
const char StatsReport::kStatsValueNameFingerprint[] = "googFingerprint";
const char StatsReport::kStatsValueNameFingerprintAlgorithm[] =
"googFingerprintAlgorithm";
const char StatsReport::kStatsValueNameFirsReceived[] = "googFirsReceived";
const char StatsReport::kStatsValueNameFirsSent[] = "googFirsSent";
+const char StatsReport::kStatsValueNameFrameHeightInput[] =
+ "googFrameHeightInput";
const char StatsReport::kStatsValueNameFrameHeightReceived[] =
"googFrameHeightReceived";
const char StatsReport::kStatsValueNameFrameHeightSent[] =
@@ -102,8 +119,13 @@ const char StatsReport::kStatsValueNameMinPlayoutDelayMs[] =
"googMinPlayoutDelayMs";
const char StatsReport::kStatsValueNameRenderDelayMs[] = "googRenderDelayMs";
+const char StatsReport::kStatsValueNameCaptureStartNtpTimeMs[] =
+ "googCaptureStartNtpTimeMs";
+
const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
+const char StatsReport::kStatsValueNameFrameWidthInput[] =
+ "googFrameWidthInput";
const char StatsReport::kStatsValueNameFrameWidthReceived[] =
"googFrameWidthReceived";
const char StatsReport::kStatsValueNameFrameWidthSent[] = "googFrameWidthSent";
@@ -117,10 +139,21 @@ const char StatsReport::kStatsValueNameLocalCertificateId[] =
"googLocalCertificateId";
const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
const char StatsReport::kStatsValueNameNacksSent[] = "googNacksSent";
+const char StatsReport::kStatsValueNamePlisReceived[] = "googPlisReceived";
+const char StatsReport::kStatsValueNamePlisSent[] = "googPlisSent";
const char StatsReport::kStatsValueNamePacketsReceived[] = "packetsReceived";
const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
+const char StatsReport::kStatsValueNamePreferredJitterBufferMs[] =
+ "googPreferredJitterBufferMs";
const char StatsReport::kStatsValueNameReadable[] = "googReadable";
+const char StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug[] =
+ "googReceivedPacketGroupArrivalTimeDebug";
+const char StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug[] =
+ "googReceivedPacketGroupPropagationDeltaDebug";
+const char
+StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug[] =
+ "googReceivedPacketGroupPropagationDeltaSumDebug";
const char StatsReport::kStatsValueNameRemoteAddress[] = "googRemoteAddress";
const char StatsReport::kStatsValueNameRemoteCandidateType[] =
"googRemoteCandidateType";
@@ -156,7 +189,6 @@ const char StatsReport::kStatsReportTypeCertificate[] = "googCertificate";
const char StatsReport::kStatsReportVideoBweId[] = "bweforvideo";
-
// Implementations of functions in statstypes.h
void StatsReport::AddValue(const std::string& name, const std::string& value) {
Value temp;
@@ -169,10 +201,37 @@ void StatsReport::AddValue(const std::string& name, int64 value) {
AddValue(name, talk_base::ToString<int64>(value));
}
+template <typename T>
+void StatsReport::AddValue(const std::string& name,
+ const std::vector<T>& value) {
+ std::ostringstream oss;
+ oss << "[";
+ for (size_t i = 0; i < value.size(); ++i) {
+ oss << talk_base::ToString<T>(value[i]);
+ if (i != value.size() - 1)
+ oss << ", ";
+ }
+ oss << "]";
+ AddValue(name, oss.str());
+}
+
void StatsReport::AddBoolean(const std::string& name, bool value) {
AddValue(name, value ? "true" : "false");
}
+void StatsReport::ReplaceValue(const std::string& name,
+ const std::string& value) {
+ for (Values::iterator it = values.begin(); it != values.end(); ++it) {
+ if ((*it).name == name) {
+ it->value = value;
+ return;
+ }
+ }
+ // It is not reachable here, add an ASSERT to make sure the overwriting is
+ // always a success.
+ ASSERT(false);
+}
+
namespace {
typedef std::map<std::string, StatsReport> StatsMap;
@@ -180,6 +239,20 @@ std::string StatsId(const std::string& type, const std::string& id) {
return type + "_" + id;
}
+std::string StatsId(const std::string& type, const std::string& id,
+ StatsCollector::TrackDirection direction) {
+ ASSERT(direction == StatsCollector::kSending ||
+ direction == StatsCollector::kReceiving);
+
+ // Strings for the direction of the track.
+ const char kSendDirection[] = "send";
+ const char kRecvDirection[] = "recv";
+
+ const std::string direction_id = (direction == StatsCollector::kSending) ?
+ kSendDirection : kRecvDirection;
+ return type + "_" + id + "_" + direction_id;
+}
+
bool ExtractValueFromReport(
const StatsReport& report,
const std::string& name,
@@ -215,10 +288,33 @@ void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
info.bytes_rcvd);
report->AddValue(StatsReport::kStatsValueNameJitterReceived,
info.jitter_ms);
+ report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
+ info.jitter_buffer_ms);
+ report->AddValue(StatsReport::kStatsValueNamePreferredJitterBufferMs,
+ info.jitter_buffer_preferred_ms);
+ report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
+ info.delay_estimate_ms);
+ report->AddValue(StatsReport::kStatsValueNameExpandRate,
+ talk_base::ToString<float>(info.expand_rate));
report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
info.packets_rcvd);
report->AddValue(StatsReport::kStatsValueNamePacketsLost,
info.packets_lost);
+ report->AddValue(StatsReport::kStatsValueNameDecodingCTSG,
+ info.decoding_calls_to_silence_generator);
+ report->AddValue(StatsReport::kStatsValueNameDecodingCTN,
+ info.decoding_calls_to_neteq);
+ report->AddValue(StatsReport::kStatsValueNameDecodingNormal,
+ info.decoding_normal);
+ report->AddValue(StatsReport::kStatsValueNameDecodingPLC,
+ info.decoding_plc);
+ report->AddValue(StatsReport::kStatsValueNameDecodingCNG,
+ info.decoding_cng);
+ report->AddValue(StatsReport::kStatsValueNameDecodingPLCCNG,
+ info.decoding_plc_cng);
+ report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
+ info.capture_start_ntp_time_ms);
+ report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
}
void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
@@ -228,6 +324,8 @@ void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
info.bytes_sent);
report->AddValue(StatsReport::kStatsValueNamePacketsSent,
info.packets_sent);
+ report->AddValue(StatsReport::kStatsValueNamePacketsLost,
+ info.packets_lost);
report->AddValue(StatsReport::kStatsValueNameJitterReceived,
info.jitter_ms);
report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
@@ -256,6 +354,8 @@ void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
report->AddValue(StatsReport::kStatsValueNameFirsSent,
info.firs_sent);
+ report->AddValue(StatsReport::kStatsValueNamePlisSent,
+ info.plis_sent);
report->AddValue(StatsReport::kStatsValueNameNacksSent,
info.nacks_sent);
report->AddValue(StatsReport::kStatsValueNameFrameWidthReceived,
@@ -283,6 +383,9 @@ void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
info.min_playout_delay_ms);
report->AddValue(StatsReport::kStatsValueNameRenderDelayMs,
info.render_delay_ms);
+
+ report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
+ info.capture_start_ntp_time_ms);
}
void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
@@ -290,15 +393,23 @@ void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
info.bytes_sent);
report->AddValue(StatsReport::kStatsValueNamePacketsSent,
info.packets_sent);
+ report->AddValue(StatsReport::kStatsValueNamePacketsLost,
+ info.packets_lost);
report->AddValue(StatsReport::kStatsValueNameFirsReceived,
info.firs_rcvd);
+ report->AddValue(StatsReport::kStatsValueNamePlisReceived,
+ info.plis_rcvd);
report->AddValue(StatsReport::kStatsValueNameNacksReceived,
info.nacks_rcvd);
+ report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
+ info.input_frame_width);
+ report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
+ info.input_frame_height);
report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
- info.frame_width);
+ info.send_frame_width);
report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
- info.frame_height);
+ info.send_frame_height);
report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
info.framerate_input);
report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
@@ -318,10 +429,13 @@ void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
info.capture_queue_delay_ms_per_s);
report->AddValue(StatsReport::kStatsValueNameEncodeUsagePercent,
info.encode_usage_percent);
+ report->AddValue(StatsReport::kStatsValueNameEncodeRelStdDev,
+ info.encode_rsd);
}
void ExtractStats(const cricket::BandwidthEstimationInfo& info,
double stats_gathering_started,
+ PeerConnectionInterface::StatsOutputLevel level,
StatsReport* report) {
report->id = StatsReport::kStatsReportVideoBweId;
report->type = StatsReport::kStatsReportTypeBwe;
@@ -346,6 +460,19 @@ void ExtractStats(const cricket::BandwidthEstimationInfo& info,
info.transmit_bitrate);
report->AddValue(StatsReport::kStatsValueNameBucketDelay,
info.bucket_delay);
+ if (level >= PeerConnectionInterface::kStatsOutputLevelDebug) {
+ report->AddValue(
+ StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug,
+ info.total_received_propagation_delta_ms);
+ if (info.recent_received_propagation_delta_ms.size() > 0) {
+ report->AddValue(
+ StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug,
+ info.recent_received_propagation_delta_ms);
+ report->AddValue(
+ StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug,
+ info.recent_received_packet_group_arrival_time_ms);
+ }
+ }
}
void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
@@ -367,27 +494,29 @@ void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
template<typename T>
void ExtractStatsFromList(const std::vector<T>& data,
const std::string& transport_id,
- StatsCollector* collector) {
+ StatsCollector* collector,
+ StatsCollector::TrackDirection direction) {
typename std::vector<T>::const_iterator it = data.begin();
for (; it != data.end(); ++it) {
std::string id;
uint32 ssrc = it->ssrc();
- // Each object can result in 2 objects, a local and a remote object.
+ // Each track can have stats for both local and remote objects.
// TODO(hta): Handle the case of multiple SSRCs per object.
- StatsReport* report = collector->PrepareLocalReport(ssrc, transport_id);
- if (!report) {
- continue;
- }
- ExtractStats(*it, report);
+ StatsReport* report = collector->PrepareLocalReport(ssrc, transport_id,
+ direction);
+ if (report)
+ ExtractStats(*it, report);
+
if (it->remote_stats.size() > 0) {
- report = collector->PrepareRemoteReport(ssrc, transport_id);
+ report = collector->PrepareRemoteReport(ssrc, transport_id,
+ direction);
if (!report) {
continue;
}
ExtractRemoteStats(*it, report);
}
}
-};
+}
} // namespace
@@ -406,6 +535,32 @@ void StatsCollector::AddStream(MediaStreamInterface* stream) {
&reports_);
}
+void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
+ uint32 ssrc) {
+ ASSERT(audio_track != NULL);
+#ifdef _DEBUG
+ for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
+ it != local_audio_tracks_.end(); ++it) {
+ ASSERT(it->first != audio_track || it->second != ssrc);
+ }
+#endif
+ local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
+}
+
+void StatsCollector::RemoveLocalAudioTrack(AudioTrackInterface* audio_track,
+ uint32 ssrc) {
+ ASSERT(audio_track != NULL);
+ for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
+ it != local_audio_tracks_.end(); ++it) {
+ if (it->first == audio_track && it->second == ssrc) {
+ local_audio_tracks_.erase(it);
+ return;
+ }
+ }
+
+ ASSERT(false);
+}
+
bool StatsCollector::GetStats(MediaStreamTrackInterface* track,
StatsReports* reports) {
ASSERT(reports != NULL);
@@ -451,7 +606,8 @@ bool StatsCollector::GetStats(MediaStreamTrackInterface* track,
return true;
}
-void StatsCollector::UpdateStats() {
+void
+StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
double time_now = GetTimeNow();
// Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
// ms apart will be ignored.
@@ -464,24 +620,22 @@ void StatsCollector::UpdateStats() {
if (session_) {
ExtractSessionInfo();
ExtractVoiceInfo();
- ExtractVideoInfo();
+ ExtractVideoInfo(level);
}
}
StatsReport* StatsCollector::PrepareLocalReport(
uint32 ssrc,
- const std::string& transport_id) {
- std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
+ const std::string& transport_id,
+ TrackDirection direction) {
+ const std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
StatsMap::iterator it = reports_.find(StatsId(
- StatsReport::kStatsReportTypeSsrc, ssrc_id));
+ StatsReport::kStatsReportTypeSsrc, ssrc_id, direction));
std::string track_id;
if (it == reports_.end()) {
- if (!session()->GetTrackIdBySsrc(ssrc, &track_id)) {
- LOG(LS_WARNING) << "The SSRC " << ssrc
- << " is not associated with a track";
+ if (!GetTrackIdBySsrc(ssrc, &track_id, direction))
return NULL;
- }
} else {
// Keeps the old track id since we want to report the stats for inactive
// tracks.
@@ -491,7 +645,7 @@ StatsReport* StatsCollector::PrepareLocalReport(
}
StatsReport* report = GetOrCreateReport(StatsReport::kStatsReportTypeSsrc,
- ssrc_id);
+ ssrc_id, direction);
// Clear out stats from previous GatherStats calls if any.
if (report->timestamp != stats_gathering_started_) {
@@ -509,18 +663,16 @@ StatsReport* StatsCollector::PrepareLocalReport(
StatsReport* StatsCollector::PrepareRemoteReport(
uint32 ssrc,
- const std::string& transport_id) {
- std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
+ const std::string& transport_id,
+ TrackDirection direction) {
+ const std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
StatsMap::iterator it = reports_.find(StatsId(
- StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id));
+ StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id, direction));
std::string track_id;
if (it == reports_.end()) {
- if (!session()->GetTrackIdBySsrc(ssrc, &track_id)) {
- LOG(LS_WARNING) << "The SSRC " << ssrc
- << " is not associated with a track";
+ if (!GetTrackIdBySsrc(ssrc, &track_id, direction))
return NULL;
- }
} else {
// Keeps the old track id since we want to report the stats for inactive
// tracks.
@@ -530,7 +682,7 @@ StatsReport* StatsCollector::PrepareRemoteReport(
}
StatsReport* report = GetOrCreateReport(
- StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id);
+ StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id, direction);
// Clear out stats from previous GatherStats calls if any.
// The timestamp will be added later. Zero it for debugging.
@@ -557,6 +709,14 @@ std::string StatsCollector::AddOneCertificateReport(
talk_base::scoped_ptr<talk_base::SSLFingerprint> ssl_fingerprint(
talk_base::SSLFingerprint::Create(digest_algorithm, cert));
+
+ // SSLFingerprint::Create can fail if the algorithm returned by
+ // SSLCertificate::GetSignatureDigestAlgorithm is not supported by the
+ // implementation of SSLCertificate::ComputeDigest. This currently happens
+ // with MD5- and SHA-224-signed certificates when linked to libNSS.
+ if (!ssl_fingerprint)
+ return std::string();
+
std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
talk_base::Buffer der_buffer;
@@ -721,16 +881,23 @@ void StatsCollector::ExtractVoiceInfo() {
<< session_->voice_channel()->content_name();
return;
}
- ExtractStatsFromList(voice_info.receivers, transport_id, this);
- ExtractStatsFromList(voice_info.senders, transport_id, this);
+ ExtractStatsFromList(voice_info.receivers, transport_id, this, kReceiving);
+ ExtractStatsFromList(voice_info.senders, transport_id, this, kSending);
+
+ UpdateStatsFromExistingLocalAudioTracks();
}
-void StatsCollector::ExtractVideoInfo() {
+void StatsCollector::ExtractVideoInfo(
+ PeerConnectionInterface::StatsOutputLevel level) {
if (!session_->video_channel()) {
return;
}
+ cricket::StatsOptions options;
+ options.include_received_propagation_stats =
+ (level >= PeerConnectionInterface::kStatsOutputLevelDebug) ?
+ true : false;
cricket::VideoMediaInfo video_info;
- if (!session_->video_channel()->GetStats(&video_info)) {
+ if (!session_->video_channel()->GetStats(options, &video_info)) {
LOG(LS_ERROR) << "Failed to get video channel stats.";
return;
}
@@ -741,14 +908,14 @@ void StatsCollector::ExtractVideoInfo() {
<< session_->video_channel()->content_name();
return;
}
- ExtractStatsFromList(video_info.receivers, transport_id, this);
- ExtractStatsFromList(video_info.senders, transport_id, this);
+ ExtractStatsFromList(video_info.receivers, transport_id, this, kReceiving);
+ ExtractStatsFromList(video_info.senders, transport_id, this, kSending);
if (video_info.bw_estimations.size() != 1) {
LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size();
} else {
StatsReport* report = &reports_[StatsReport::kStatsReportVideoBweId];
ExtractStats(
- video_info.bw_estimations[0], stats_gathering_started_, report);
+ video_info.bw_estimations[0], stats_gathering_started_, level, report);
}
}
@@ -774,19 +941,118 @@ bool StatsCollector::GetTransportIdFromProxy(const std::string& proxy,
return true;
}
-StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
- const std::string& id) {
- std::string statsid = StatsId(type, id);
+StatsReport* StatsCollector::GetReport(const std::string& type,
+ const std::string& id,
+ TrackDirection direction) {
+ ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
+ type == StatsReport::kStatsReportTypeRemoteSsrc);
+ std::string statsid = StatsId(type, id, direction);
StatsReport* report = NULL;
std::map<std::string, StatsReport>::iterator it = reports_.find(statsid);
- if (it == reports_.end()) {
+ if (it != reports_.end())
+ report = &(it->second);
+
+ return report;
+}
+
+StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
+ const std::string& id,
+ TrackDirection direction) {
+ ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
+ type == StatsReport::kStatsReportTypeRemoteSsrc);
+ StatsReport* report = GetReport(type, id, direction);
+ if (report == NULL) {
+ std::string statsid = StatsId(type, id, direction);
report = &reports_[statsid]; // Create new element.
report->id = statsid;
report->type = type;
- } else {
- report = &(it->second);
}
+
return report;
}
+void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
+ // Loop through the existing local audio tracks.
+ for (LocalAudioTrackVector::const_iterator it = local_audio_tracks_.begin();
+ it != local_audio_tracks_.end(); ++it) {
+ AudioTrackInterface* track = it->first;
+ uint32 ssrc = it->second;
+ std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
+ StatsReport* report = GetReport(StatsReport::kStatsReportTypeSsrc,
+ ssrc_id,
+ kSending);
+ if (report == NULL) {
+ // This can happen if a local audio track is added to a stream on the
+ // fly and the report has not been set up yet. Do nothing in this case.
+ LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc;
+ continue;
+ }
+
+ // The same ssrc can be used by both local and remote audio tracks.
+ std::string track_id;
+ if (!ExtractValueFromReport(*report,
+ StatsReport::kStatsValueNameTrackId,
+ &track_id) ||
+ track_id != track->id()) {
+ continue;
+ }
+
+ UpdateReportFromAudioTrack(track, report);
+ }
+}
+
+void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
+ StatsReport* report) {
+ ASSERT(track != NULL);
+ if (report == NULL)
+ return;
+
+ int signal_level = 0;
+ if (track->GetSignalLevel(&signal_level)) {
+ report->ReplaceValue(StatsReport::kStatsValueNameAudioInputLevel,
+ talk_base::ToString<int>(signal_level));
+ }
+
+ talk_base::scoped_refptr<AudioProcessorInterface> audio_processor(
+ track->GetAudioProcessor());
+ if (audio_processor.get() == NULL)
+ return;
+
+ AudioProcessorInterface::AudioProcessorStats stats;
+ audio_processor->GetStats(&stats);
+ report->ReplaceValue(StatsReport::kStatsValueNameTypingNoiseState,
+ stats.typing_noise_detected ? "true" : "false");
+ report->ReplaceValue(StatsReport::kStatsValueNameEchoReturnLoss,
+ talk_base::ToString<int>(stats.echo_return_loss));
+ report->ReplaceValue(
+ StatsReport::kStatsValueNameEchoReturnLossEnhancement,
+ talk_base::ToString<int>(stats.echo_return_loss_enhancement));
+ report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayMedian,
+ talk_base::ToString<int>(stats.echo_delay_median_ms));
+ report->ReplaceValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
+ talk_base::ToString<float>(stats.aec_quality_min));
+ report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayStdDev,
+ talk_base::ToString<int>(stats.echo_delay_std_ms));
+}
+
+bool StatsCollector::GetTrackIdBySsrc(uint32 ssrc, std::string* track_id,
+ TrackDirection direction) {
+ if (direction == kSending) {
+ if (!session()->GetLocalTrackIdBySsrc(ssrc, track_id)) {
+ LOG(LS_WARNING) << "The SSRC " << ssrc
+ << " is not associated with a sending track";
+ return false;
+ }
+ } else {
+ ASSERT(direction == kReceiving);
+ if (!session()->GetRemoteTrackIdBySsrc(ssrc, track_id)) {
+ LOG(LS_WARNING) << "The SSRC " << ssrc
+ << " is not associated with a receiving track";
+ return false;
+ }
+ }
+
+ return true;
+}
+
} // namespace webrtc
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector.h b/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector.h
index 01da059b510..77a1ba086df 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector.h
@@ -31,10 +31,12 @@
#ifndef TALK_APP_WEBRTC_STATSCOLLECTOR_H_
#define TALK_APP_WEBRTC_STATSCOLLECTOR_H_
-#include <string>
#include <map>
+#include <string>
+#include <vector>
#include "talk/app/webrtc/mediastreaminterface.h"
+#include "talk/app/webrtc/peerconnectioninterface.h"
#include "talk/app/webrtc/statstypes.h"
#include "talk/app/webrtc/webrtcsession.h"
@@ -44,6 +46,11 @@ namespace webrtc {
class StatsCollector {
public:
+ enum TrackDirection {
+ kSending = 0,
+ kReceiving,
+ };
+
StatsCollector();
// Register the session Stats should operate on.
@@ -56,20 +63,30 @@ class StatsCollector {
// to GetStats.
void AddStream(MediaStreamInterface* stream);
+ // Adds a local audio track that is used for getting some voice statistics.
+ void AddLocalAudioTrack(AudioTrackInterface* audio_track, uint32 ssrc);
+
+ // Removes a local audio tracks that is used for getting some voice
+ // statistics.
+ void RemoveLocalAudioTrack(AudioTrackInterface* audio_track, uint32 ssrc);
+
// Gather statistics from the session and store them for future use.
- void UpdateStats();
+ void UpdateStats(PeerConnectionInterface::StatsOutputLevel level);
// Gets a StatsReports of the last collected stats. Note that UpdateStats must
// be called before this function to get the most recent stats. |selector| is
// a track label or empty string. The most recent reports are stored in
// |reports|.
- bool GetStats(MediaStreamTrackInterface* track, StatsReports* reports);
+ bool GetStats(MediaStreamTrackInterface* track,
+ StatsReports* reports);
// Prepare an SSRC report for the given ssrc. Used internally
// in the ExtractStatsFromList template.
- StatsReport* PrepareLocalReport(uint32 ssrc, const std::string& transport);
+ StatsReport* PrepareLocalReport(uint32 ssrc, const std::string& transport,
+ TrackDirection direction);
// Prepare an SSRC report for the given remote ssrc. Used internally.
- StatsReport* PrepareRemoteReport(uint32 ssrc, const std::string& transport);
+ StatsReport* PrepareRemoteReport(uint32 ssrc, const std::string& transport,
+ TrackDirection direction);
// Extracts the ID of a Transport belonging to an SSRC. Used internally.
bool GetTransportIdFromProxy(const std::string& proxy,
std::string* transport_id);
@@ -87,12 +104,26 @@ class StatsCollector {
void ExtractSessionInfo();
void ExtractVoiceInfo();
- void ExtractVideoInfo();
+ void ExtractVideoInfo(PeerConnectionInterface::StatsOutputLevel level);
double GetTimeNow();
void BuildSsrcToTransportId();
WebRtcSession* session() { return session_; }
webrtc::StatsReport* GetOrCreateReport(const std::string& type,
- const std::string& id);
+ const std::string& id,
+ TrackDirection direction);
+ webrtc::StatsReport* GetReport(const std::string& type,
+ const std::string& id,
+ TrackDirection direction);
+
+ // Helper method to get stats from the local audio tracks.
+ void UpdateStatsFromExistingLocalAudioTracks();
+ void UpdateReportFromAudioTrack(AudioTrackInterface* track,
+ StatsReport* report);
+
+ // Helper method to get the id for the track identified by ssrc.
+ // |direction| tells if the track is for sending or receiving.
+ bool GetTrackIdBySsrc(uint32 ssrc, std::string* track_id,
+ TrackDirection direction);
// A map from the report id to the report.
std::map<std::string, StatsReport> reports_;
@@ -101,6 +132,10 @@ class StatsCollector {
double stats_gathering_started_;
talk_base::Timing timing_;
cricket::ProxyTransportMap proxy_to_transport_;
+
+ typedef std::vector<std::pair<AudioTrackInterface*, uint32> >
+ LocalAudioTrackVector;
+ LocalAudioTrackVector local_audio_tracks_;
};
} // namespace webrtc
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector_unittest.cc
index 1adcb0e20aa..2cd716e0232 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/statscollector_unittest.cc
@@ -1,5 +1,6 @@
/*
* libjingle
+ * Copyright 2014, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,6 +30,8 @@
#include "talk/app/webrtc/statscollector.h"
#include "talk/app/webrtc/mediastream.h"
+#include "talk/app/webrtc/mediastreaminterface.h"
+#include "talk/app/webrtc/mediastreamtrack.h"
#include "talk/app/webrtc/videotrack.h"
#include "talk/base/base64.h"
#include "talk/base/fakesslidentity.h"
@@ -37,13 +40,19 @@
#include "talk/media/devices/fakedevicemanager.h"
#include "talk/p2p/base/fakesession.h"
#include "talk/session/media/channelmanager.h"
-#include "testing/base/public/gmock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+using cricket::StatsOptions;
using testing::_;
using testing::DoAll;
+using testing::Field;
using testing::Return;
using testing::ReturnNull;
using testing::SetArgPointee;
+using webrtc::PeerConnectionInterface;
+using webrtc::StatsReport;
+using webrtc::StatsReports;
namespace cricket {
@@ -59,7 +68,8 @@ const char kNotFound[] = "NOT FOUND";
const char kNoReports[] = "NO REPORTS";
// Constant names for track identification.
-const char kTrackId[] = "somename";
+const char kLocalTrackId[] = "local_track_id";
+const char kRemoteTrackId[] = "remote_track_id";
const uint32 kSsrcOfTrack = 1234;
class MockWebRtcSession : public webrtc::WebRtcSession {
@@ -68,8 +78,12 @@ class MockWebRtcSession : public webrtc::WebRtcSession {
: WebRtcSession(channel_manager, talk_base::Thread::Current(),
talk_base::Thread::Current(), NULL, NULL) {
}
+ MOCK_METHOD0(voice_channel, cricket::VoiceChannel*());
MOCK_METHOD0(video_channel, cricket::VideoChannel*());
- MOCK_METHOD2(GetTrackIdBySsrc, bool(uint32, std::string*));
+ // Libjingle uses "local" for a outgoing track, and "remote" for a incoming
+ // track.
+ MOCK_METHOD2(GetLocalTrackIdBySsrc, bool(uint32, std::string*));
+ MOCK_METHOD2(GetRemoteTrackIdBySsrc, bool(uint32, std::string*));
MOCK_METHOD1(GetStats, bool(cricket::SessionStats*));
MOCK_METHOD1(GetTransport, cricket::Transport*(const std::string&));
};
@@ -80,13 +94,64 @@ class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
: cricket::FakeVideoMediaChannel(NULL) {
}
// MOCK_METHOD0(transport_channel, cricket::TransportChannel*());
- MOCK_METHOD1(GetStats, bool(cricket::VideoMediaInfo*));
+ MOCK_METHOD2(GetStats, bool(const StatsOptions&, cricket::VideoMediaInfo*));
};
-bool GetValue(const webrtc::StatsReport* report,
+class MockVoiceMediaChannel : public cricket::FakeVoiceMediaChannel {
+ public:
+ MockVoiceMediaChannel() : cricket::FakeVoiceMediaChannel(NULL) {
+ }
+ MOCK_METHOD1(GetStats, bool(cricket::VoiceMediaInfo*));
+};
+
+class FakeAudioProcessor : public webrtc::AudioProcessorInterface {
+ public:
+ FakeAudioProcessor() {}
+ ~FakeAudioProcessor() {}
+
+ private:
+ virtual void GetStats(
+ AudioProcessorInterface::AudioProcessorStats* stats) OVERRIDE {
+ stats->typing_noise_detected = true;
+ stats->echo_return_loss = 2;
+ stats->echo_return_loss_enhancement = 3;
+ stats->echo_delay_median_ms = 4;
+ stats->aec_quality_min = 5.1f;
+ stats->echo_delay_std_ms = 6;
+ }
+};
+
+class FakeAudioTrack
+ : public webrtc::MediaStreamTrack<webrtc::AudioTrackInterface> {
+ public:
+ explicit FakeAudioTrack(const std::string& id)
+ : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(id),
+ processor_(new talk_base::RefCountedObject<FakeAudioProcessor>()) {}
+ std::string kind() const OVERRIDE {
+ return "audio";
+ }
+ virtual webrtc::AudioSourceInterface* GetSource() const OVERRIDE {
+ return NULL;
+ }
+ virtual void AddSink(webrtc::AudioTrackSinkInterface* sink) OVERRIDE {}
+ virtual void RemoveSink(webrtc::AudioTrackSinkInterface* sink) OVERRIDE {}
+ virtual bool GetSignalLevel(int* level) OVERRIDE {
+ *level = 1;
+ return true;
+ }
+ virtual talk_base::scoped_refptr<webrtc::AudioProcessorInterface>
+ GetAudioProcessor() OVERRIDE {
+ return processor_;
+ }
+
+ private:
+ talk_base::scoped_refptr<FakeAudioProcessor> processor_;
+};
+
+bool GetValue(const StatsReport* report,
const std::string& name,
std::string* value) {
- webrtc::StatsReport::Values::const_iterator it = report->values.begin();
+ StatsReport::Values::const_iterator it = report->values.begin();
for (; it != report->values.end(); ++it) {
if (it->name == name) {
*value = it->value;
@@ -97,7 +162,7 @@ bool GetValue(const webrtc::StatsReport* report,
}
std::string ExtractStatsValue(const std::string& type,
- const webrtc::StatsReports& reports,
+ const StatsReports& reports,
const std::string name) {
if (reports.empty()) {
return kNoReports;
@@ -116,8 +181,8 @@ std::string ExtractStatsValue(const std::string& type,
// Finds the |n|-th report of type |type| in |reports|.
// |n| starts from 1 for finding the first report.
-const webrtc::StatsReport* FindNthReportByType(
- const webrtc::StatsReports& reports, const std::string& type, int n) {
+const StatsReport* FindNthReportByType(
+ const StatsReports& reports, const std::string& type, int n) {
for (size_t i = 0; i < reports.size(); ++i) {
if (reports[i].type == type) {
n--;
@@ -128,8 +193,8 @@ const webrtc::StatsReport* FindNthReportByType(
return NULL;
}
-const webrtc::StatsReport* FindReportById(const webrtc::StatsReports& reports,
- const std::string& id) {
+const StatsReport* FindReportById(const StatsReports& reports,
+ const std::string& id) {
for (size_t i = 0; i < reports.size(); ++i) {
if (reports[i].id == id) {
return &reports[i];
@@ -138,16 +203,16 @@ const webrtc::StatsReport* FindReportById(const webrtc::StatsReports& reports,
return NULL;
}
-std::string ExtractSsrcStatsValue(webrtc::StatsReports reports,
+std::string ExtractSsrcStatsValue(StatsReports reports,
const std::string& name) {
return ExtractStatsValue(
- webrtc::StatsReport::kStatsReportTypeSsrc, reports, name);
+ StatsReport::kStatsReportTypeSsrc, reports, name);
}
-std::string ExtractBweStatsValue(webrtc::StatsReports reports,
+std::string ExtractBweStatsValue(StatsReports reports,
const std::string& name) {
return ExtractStatsValue(
- webrtc::StatsReport::kStatsReportTypeBwe, reports, name);
+ StatsReport::kStatsReportTypeBwe, reports, name);
}
std::string DerToPem(const std::string& der) {
@@ -164,18 +229,18 @@ std::vector<std::string> DersToPems(
return pems;
}
-void CheckCertChainReports(const webrtc::StatsReports& reports,
+void CheckCertChainReports(const StatsReports& reports,
const std::vector<std::string>& ders,
const std::string& start_id) {
std::string certificate_id = start_id;
size_t i = 0;
while (true) {
- const webrtc::StatsReport* report = FindReportById(reports, certificate_id);
+ const StatsReport* report = FindReportById(reports, certificate_id);
ASSERT_TRUE(report != NULL);
std::string der_base64;
EXPECT_TRUE(GetValue(
- report, webrtc::StatsReport::kStatsValueNameDer, &der_base64));
+ report, StatsReport::kStatsValueNameDer, &der_base64));
std::string der = talk_base::Base64::Decode(der_base64,
talk_base::Base64::DO_STRICT);
EXPECT_EQ(ders[i], der);
@@ -183,7 +248,7 @@ void CheckCertChainReports(const webrtc::StatsReports& reports,
std::string fingerprint_algorithm;
EXPECT_TRUE(GetValue(
report,
- webrtc::StatsReport::kStatsValueNameFingerprintAlgorithm,
+ StatsReport::kStatsValueNameFingerprintAlgorithm,
&fingerprint_algorithm));
// The digest algorithm for a FakeSSLCertificate is always SHA-1.
std::string sha_1_str = talk_base::DIGEST_SHA_1;
@@ -192,17 +257,179 @@ void CheckCertChainReports(const webrtc::StatsReports& reports,
std::string dummy_fingerprint; // Value is not checked.
EXPECT_TRUE(GetValue(
report,
- webrtc::StatsReport::kStatsValueNameFingerprint,
+ StatsReport::kStatsValueNameFingerprint,
&dummy_fingerprint));
++i;
if (!GetValue(
- report, webrtc::StatsReport::kStatsValueNameIssuerId, &certificate_id))
+ report, StatsReport::kStatsValueNameIssuerId, &certificate_id))
break;
}
EXPECT_EQ(ders.size(), i);
}
+void VerifyVoiceReceiverInfoReport(
+ const StatsReport* report,
+ const cricket::VoiceReceiverInfo& info) {
+ std::string value_in_report;
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameAudioOutputLevel, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.audio_level), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameBytesReceived, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int64>(info.bytes_rcvd), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameJitterReceived, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.jitter_ms), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameJitterBufferMs, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.jitter_buffer_ms), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNamePreferredJitterBufferMs,
+ &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.jitter_buffer_preferred_ms),
+ value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameCurrentDelayMs, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.delay_estimate_ms), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameExpandRate, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<float>(info.expand_rate), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNamePacketsReceived, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.packets_rcvd), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameDecodingCTSG, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.decoding_calls_to_silence_generator),
+ value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameDecodingCTN, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.decoding_calls_to_neteq),
+ value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameDecodingNormal, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.decoding_normal), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameDecodingPLC, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.decoding_plc), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameDecodingCNG, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.decoding_cng), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameDecodingPLCCNG, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(info.decoding_plc_cng), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameCodecName, &value_in_report));
+}
+
+
+void VerifyVoiceSenderInfoReport(const StatsReport* report,
+ const cricket::VoiceSenderInfo& sinfo) {
+ std::string value_in_report;
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameCodecName, &value_in_report));
+ EXPECT_EQ(sinfo.codec_name, value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameBytesSent, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int64>(sinfo.bytes_sent), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNamePacketsSent, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(sinfo.packets_sent), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNamePacketsLost, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(sinfo.packets_lost), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameRtt, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(sinfo.rtt_ms), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameRtt, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(sinfo.rtt_ms), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameJitterReceived, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(sinfo.jitter_ms), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameEchoCancellationQualityMin,
+ &value_in_report));
+ EXPECT_EQ(talk_base::ToString<float>(sinfo.aec_quality_min), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameEchoDelayMedian, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(sinfo.echo_delay_median_ms),
+ value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameEchoDelayStdDev, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(sinfo.echo_delay_std_ms),
+ value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameEchoReturnLoss, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(sinfo.echo_return_loss),
+ value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameEchoReturnLossEnhancement,
+ &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(sinfo.echo_return_loss_enhancement),
+ value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameAudioInputLevel, &value_in_report));
+ EXPECT_EQ(talk_base::ToString<int>(sinfo.audio_level), value_in_report);
+ EXPECT_TRUE(GetValue(
+ report, StatsReport::kStatsValueNameTypingNoiseState, &value_in_report));
+ std::string typing_detected = sinfo.typing_noise_detected ? "true" : "false";
+ EXPECT_EQ(typing_detected, value_in_report);
+}
+
+// Helper methods to avoid duplication of code.
+void InitVoiceSenderInfo(cricket::VoiceSenderInfo* voice_sender_info) {
+ voice_sender_info->add_ssrc(kSsrcOfTrack);
+ voice_sender_info->codec_name = "fake_codec";
+ voice_sender_info->bytes_sent = 100;
+ voice_sender_info->packets_sent = 101;
+ voice_sender_info->rtt_ms = 102;
+ voice_sender_info->fraction_lost = 103;
+ voice_sender_info->jitter_ms = 104;
+ voice_sender_info->packets_lost = 105;
+ voice_sender_info->ext_seqnum = 106;
+ voice_sender_info->audio_level = 107;
+ voice_sender_info->echo_return_loss = 108;
+ voice_sender_info->echo_return_loss_enhancement = 109;
+ voice_sender_info->echo_delay_median_ms = 110;
+ voice_sender_info->echo_delay_std_ms = 111;
+ voice_sender_info->aec_quality_min = 112.0f;
+ voice_sender_info->typing_noise_detected = false;
+}
+
+void UpdateVoiceSenderInfoFromAudioTrack(
+ FakeAudioTrack* audio_track, cricket::VoiceSenderInfo* voice_sender_info) {
+ audio_track->GetSignalLevel(&voice_sender_info->audio_level);
+ webrtc::AudioProcessorInterface::AudioProcessorStats audio_processor_stats;
+ audio_track->GetAudioProcessor()->GetStats(&audio_processor_stats);
+ voice_sender_info->typing_noise_detected =
+ audio_processor_stats.typing_noise_detected;
+ voice_sender_info->echo_return_loss = audio_processor_stats.echo_return_loss;
+ voice_sender_info->echo_return_loss_enhancement =
+ audio_processor_stats.echo_return_loss_enhancement;
+ voice_sender_info->echo_delay_median_ms =
+ audio_processor_stats.echo_delay_median_ms;
+ voice_sender_info->aec_quality_min = audio_processor_stats.aec_quality_min;
+ voice_sender_info->echo_delay_std_ms =
+ audio_processor_stats.echo_delay_std_ms;
+}
+
+void InitVoiceReceiverInfo(cricket::VoiceReceiverInfo* voice_receiver_info) {
+ voice_receiver_info->add_ssrc(kSsrcOfTrack);
+ voice_receiver_info->bytes_rcvd = 110;
+ voice_receiver_info->packets_rcvd = 111;
+ voice_receiver_info->packets_lost = 112;
+ voice_receiver_info->fraction_lost = 113;
+ voice_receiver_info->packets_lost = 114;
+ voice_receiver_info->ext_seqnum = 115;
+ voice_receiver_info->jitter_ms = 116;
+ voice_receiver_info->jitter_buffer_ms = 117;
+ voice_receiver_info->jitter_buffer_preferred_ms = 118;
+ voice_receiver_info->delay_estimate_ms = 119;
+ voice_receiver_info->audio_level = 120;
+ voice_receiver_info->expand_rate = 121;
+}
+
class StatsCollectorTest : public testing::Test {
protected:
StatsCollectorTest()
@@ -211,8 +438,7 @@ class StatsCollectorTest : public testing::Test {
new cricket::ChannelManager(media_engine_,
new cricket::FakeDeviceManager(),
talk_base::Thread::Current())),
- session_(channel_manager_.get()),
- track_id_(kTrackId) {
+ session_(channel_manager_.get()) {
// By default, we ignore session GetStats calls.
EXPECT_CALL(session_, GetStats(_)).WillRepeatedly(Return(false));
}
@@ -232,14 +458,56 @@ class StatsCollectorTest : public testing::Test {
session_stats_.proxy_to_transport[vc_name] = kTransportName;
}
- // Adds a track with a given SSRC into the stats.
- void AddVideoTrackStats() {
+ // Adds a outgoing video track with a given SSRC into the stats.
+ void AddOutgoingVideoTrackStats() {
stream_ = webrtc::MediaStream::Create("streamlabel");
- track_= webrtc::VideoTrack::Create(kTrackId, NULL);
+ track_= webrtc::VideoTrack::Create(kLocalTrackId, NULL);
stream_->AddTrack(track_);
- EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(track_id_),
- Return(true)));
+ EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(kLocalTrackId), Return(true)));
+ EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _))
+ .WillRepeatedly(Return(false));
+ }
+
+ // Adds a incoming video track with a given SSRC into the stats.
+ void AddIncomingVideoTrackStats() {
+ stream_ = webrtc::MediaStream::Create("streamlabel");
+ track_= webrtc::VideoTrack::Create(kRemoteTrackId, NULL);
+ stream_->AddTrack(track_);
+ EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(kRemoteTrackId),
+ Return(true)));
+ }
+
+ // Adds a outgoing audio track with a given SSRC into the stats.
+ void AddOutgoingAudioTrackStats() {
+ if (stream_ == NULL)
+ stream_ = webrtc::MediaStream::Create("streamlabel");
+
+ audio_track_ = new talk_base::RefCountedObject<FakeAudioTrack>(
+ kLocalTrackId);
+ stream_->AddTrack(audio_track_);
+ EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(kLocalTrackId),
+ Return(true)));
+ EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _))
+ .WillRepeatedly(Return(false));
+ }
+
+ // Adds a incoming audio track with a given SSRC into the stats.
+ void AddIncomingAudioTrackStats() {
+ if (stream_ == NULL)
+ stream_ = webrtc::MediaStream::Create("streamlabel");
+
+ audio_track_ = new talk_base::RefCountedObject<FakeAudioTrack>(
+ kRemoteTrackId);
+ stream_->AddTrack(audio_track_);
+ EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true)));
}
void TestCertificateReports(const talk_base::FakeSSLCertificate& local_cert,
@@ -247,7 +515,7 @@ class StatsCollectorTest : public testing::Test {
const talk_base::FakeSSLCertificate& remote_cert,
const std::vector<std::string>& remote_ders) {
webrtc::StatsCollector stats; // Implementation under test.
- webrtc::StatsReports reports; // returned values.
+ StatsReports reports; // returned values.
stats.set_session(&session_);
// Fake stats to process.
@@ -286,32 +554,40 @@ class StatsCollectorTest : public testing::Test {
EXPECT_CALL(session_, GetStats(_))
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
- const webrtc::StatsReport* channel_report = FindNthReportByType(
- reports, webrtc::StatsReport::kStatsReportTypeComponent, 1);
+ const StatsReport* channel_report = FindNthReportByType(
+ reports, StatsReport::kStatsReportTypeComponent, 1);
EXPECT_TRUE(channel_report != NULL);
// Check local certificate chain.
std::string local_certificate_id = ExtractStatsValue(
- webrtc::StatsReport::kStatsReportTypeComponent,
+ StatsReport::kStatsReportTypeComponent,
reports,
- webrtc::StatsReport::kStatsValueNameLocalCertificateId);
- EXPECT_NE(kNotFound, local_certificate_id);
- CheckCertChainReports(reports, local_ders, local_certificate_id);
+ StatsReport::kStatsValueNameLocalCertificateId);
+ if (local_ders.size() > 0) {
+ EXPECT_NE(kNotFound, local_certificate_id);
+ CheckCertChainReports(reports, local_ders, local_certificate_id);
+ } else {
+ EXPECT_EQ(kNotFound, local_certificate_id);
+ }
// Check remote certificate chain.
std::string remote_certificate_id = ExtractStatsValue(
- webrtc::StatsReport::kStatsReportTypeComponent,
+ StatsReport::kStatsReportTypeComponent,
reports,
- webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
- EXPECT_NE(kNotFound, remote_certificate_id);
- CheckCertChainReports(reports, remote_ders, remote_certificate_id);
+ StatsReport::kStatsValueNameRemoteCertificateId);
+ if (remote_ders.size() > 0) {
+ EXPECT_NE(kNotFound, remote_certificate_id);
+ CheckCertChainReports(reports, remote_ders, remote_certificate_id);
+ } else {
+ EXPECT_EQ(kNotFound, remote_certificate_id);
+ }
}
cricket::FakeMediaEngine* media_engine_;
@@ -320,16 +596,16 @@ class StatsCollectorTest : public testing::Test {
cricket::SessionStats session_stats_;
talk_base::scoped_refptr<webrtc::MediaStream> stream_;
talk_base::scoped_refptr<webrtc::VideoTrack> track_;
- std::string track_id_;
+ talk_base::scoped_refptr<FakeAudioTrack> audio_track_;
};
// This test verifies that 64-bit counters are passed successfully.
TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
webrtc::StatsCollector stats; // Implementation under test.
- MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, "", false, NULL);
- webrtc::StatsReports reports; // returned values.
+ StatsReports reports; // returned values.
cricket::VideoSenderInfo video_sender_info;
cricket::VideoMediaInfo stats_read;
// The number of bytes must be larger than 0xFFFFFFFF for this test.
@@ -337,7 +613,7 @@ TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
const std::string kBytesSentString("12345678901234");
stats.set_session(&session_);
- AddVideoTrackStats();
+ AddOutgoingVideoTrackStats();
stats.AddStream(stream_);
// Construct a stats value to read.
@@ -345,12 +621,12 @@ TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
video_sender_info.bytes_sent = kBytesSent;
stats_read.senders.push_back(video_sender_info);
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(Return(&video_channel));
- EXPECT_CALL(*media_channel, GetStats(_))
- .WillOnce(DoAll(SetArgPointee<0>(stats_read),
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
EXPECT_EQ(kBytesSentString, result);
@@ -359,10 +635,10 @@ TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
// Test that BWE information is reported via stats.
TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
webrtc::StatsCollector stats; // Implementation under test.
- MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, "", false, NULL);
- webrtc::StatsReports reports; // returned values.
+ StatsReports reports; // returned values.
cricket::VideoSenderInfo video_sender_info;
cricket::VideoMediaInfo stats_read;
// Set up an SSRC just to test that we get both kinds of stats back: SSRC and
@@ -371,7 +647,7 @@ TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
const std::string kBytesSentString("12345678901234");
stats.set_session(&session_);
- AddVideoTrackStats();
+ AddOutgoingVideoTrackStats();
stats.AddStream(stream_);
// Construct a stats value to read.
@@ -384,13 +660,13 @@ TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
bwe.target_enc_bitrate = kTargetEncBitrate;
stats_read.bw_estimations.push_back(bwe);
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(Return(&video_channel));
- EXPECT_CALL(*media_channel, GetStats(_))
- .WillOnce(DoAll(SetArgPointee<0>(stats_read),
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
EXPECT_EQ(kBytesSentString, result);
@@ -402,14 +678,14 @@ TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
// exists in the returned stats.
TEST_F(StatsCollectorTest, SessionObjectExists) {
webrtc::StatsCollector stats; // Implementation under test.
- webrtc::StatsReports reports; // returned values.
+ StatsReports reports; // returned values.
stats.set_session(&session_);
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(ReturnNull());
- stats.UpdateStats();
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
- const webrtc::StatsReport* session_report = FindNthReportByType(
- reports, webrtc::StatsReport::kStatsReportTypeSession, 1);
+ const StatsReport* session_report = FindNthReportByType(
+ reports, StatsReport::kStatsReportTypeSession, 1);
EXPECT_FALSE(session_report == NULL);
}
@@ -417,18 +693,18 @@ TEST_F(StatsCollectorTest, SessionObjectExists) {
// in the returned stats.
TEST_F(StatsCollectorTest, OnlyOneSessionObjectExists) {
webrtc::StatsCollector stats; // Implementation under test.
- webrtc::StatsReports reports; // returned values.
+ StatsReports reports; // returned values.
stats.set_session(&session_);
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(ReturnNull());
- stats.UpdateStats();
- stats.UpdateStats();
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
- const webrtc::StatsReport* session_report = FindNthReportByType(
- reports, webrtc::StatsReport::kStatsReportTypeSession, 1);
+ const StatsReport* session_report = FindNthReportByType(
+ reports, StatsReport::kStatsReportTypeSession, 1);
EXPECT_FALSE(session_report == NULL);
session_report = FindNthReportByType(
- reports, webrtc::StatsReport::kStatsReportTypeSession, 2);
+ reports, StatsReport::kStatsReportTypeSession, 2);
EXPECT_EQ(NULL, session_report);
}
@@ -436,42 +712,42 @@ TEST_F(StatsCollectorTest, OnlyOneSessionObjectExists) {
// without calling StatsCollector::UpdateStats.
TEST_F(StatsCollectorTest, TrackObjectExistsWithoutUpdateStats) {
webrtc::StatsCollector stats; // Implementation under test.
- MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, "", false, NULL);
- AddVideoTrackStats();
+ AddOutgoingVideoTrackStats();
stats.AddStream(stream_);
stats.set_session(&session_);
- webrtc::StatsReports reports;
+ StatsReports reports;
// Verfies the existence of the track report.
stats.GetStats(NULL, &reports);
EXPECT_EQ((size_t)1, reports.size());
- EXPECT_EQ(std::string(webrtc::StatsReport::kStatsReportTypeTrack),
+ EXPECT_EQ(std::string(StatsReport::kStatsReportTypeTrack),
reports[0].type);
std::string trackValue =
- ExtractStatsValue(webrtc::StatsReport::kStatsReportTypeTrack,
+ ExtractStatsValue(StatsReport::kStatsReportTypeTrack,
reports,
- webrtc::StatsReport::kStatsValueNameTrackId);
- EXPECT_EQ(kTrackId, trackValue);
+ StatsReport::kStatsValueNameTrackId);
+ EXPECT_EQ(kLocalTrackId, trackValue);
}
// This test verifies that the empty track report exists in the returned stats
// when StatsCollector::UpdateStats is called with ssrc stats.
TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
webrtc::StatsCollector stats; // Implementation under test.
- MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, "", false, NULL);
- AddVideoTrackStats();
+ AddOutgoingVideoTrackStats();
stats.AddStream(stream_);
stats.set_session(&session_);
- webrtc::StatsReports reports;
+ StatsReports reports;
// Constructs an ssrc stats update.
cricket::VideoSenderInfo video_sender_info;
@@ -483,53 +759,54 @@ TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
video_sender_info.bytes_sent = kBytesSent;
stats_read.senders.push_back(video_sender_info);
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(Return(&video_channel));
- EXPECT_CALL(*media_channel, GetStats(_))
- .WillOnce(DoAll(SetArgPointee<0>(stats_read),
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
// |reports| should contain at least one session report, one track report,
// and one ssrc report.
EXPECT_LE((size_t)3, reports.size());
- const webrtc::StatsReport* track_report = FindNthReportByType(
- reports, webrtc::StatsReport::kStatsReportTypeTrack, 1);
- EXPECT_FALSE(track_report == NULL);
+ const StatsReport* track_report = FindNthReportByType(
+ reports, StatsReport::kStatsReportTypeTrack, 1);
+ EXPECT_TRUE(track_report);
+ // Get report for the specific |track|.
stats.GetStats(track_, &reports);
// |reports| should contain at least one session report, one track report,
// and one ssrc report.
EXPECT_LE((size_t)3, reports.size());
track_report = FindNthReportByType(
- reports, webrtc::StatsReport::kStatsReportTypeTrack, 1);
- EXPECT_FALSE(track_report == NULL);
+ reports, StatsReport::kStatsReportTypeTrack, 1);
+ EXPECT_TRUE(track_report);
std::string ssrc_id = ExtractSsrcStatsValue(
- reports, webrtc::StatsReport::kStatsValueNameSsrc);
+ reports, StatsReport::kStatsValueNameSsrc);
EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
std::string track_id = ExtractSsrcStatsValue(
- reports, webrtc::StatsReport::kStatsValueNameTrackId);
- EXPECT_EQ(kTrackId, track_id);
+ reports, StatsReport::kStatsValueNameTrackId);
+ EXPECT_EQ(kLocalTrackId, track_id);
}
// This test verifies that an SSRC object has the identifier of a Transport
// stats object, and that this transport stats object exists in stats.
TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
webrtc::StatsCollector stats; // Implementation under test.
- MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
// The content_name known by the video channel.
const std::string kVcName("vcname");
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, kVcName, false, NULL);
- AddVideoTrackStats();
+ AddOutgoingVideoTrackStats();
stats.AddStream(stream_);
stats.set_session(&session_);
- webrtc::StatsReports reports;
+ StatsReports reports;
// Constructs an ssrc stats update.
cricket::VideoSenderInfo video_sender_info;
@@ -541,26 +818,26 @@ TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
video_sender_info.bytes_sent = kBytesSent;
stats_read.senders.push_back(video_sender_info);
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(Return(&video_channel));
- EXPECT_CALL(*media_channel, GetStats(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
InitSessionStats(kVcName);
EXPECT_CALL(session_, GetStats(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
- Return(true)));
+ .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
+ Return(true)));
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
std::string transport_id = ExtractStatsValue(
- webrtc::StatsReport::kStatsReportTypeSsrc,
+ StatsReport::kStatsReportTypeSsrc,
reports,
- webrtc::StatsReport::kStatsValueNameTransportId);
+ StatsReport::kStatsValueNameTransportId);
ASSERT_NE(kNotFound, transport_id);
- const webrtc::StatsReport* transport_report = FindReportById(reports,
- transport_id);
+ const StatsReport* transport_report = FindReportById(reports,
+ transport_id);
ASSERT_FALSE(transport_report == NULL);
}
@@ -568,24 +845,24 @@ TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
// an outgoing SSRC where remote stats are not returned.
TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) {
webrtc::StatsCollector stats; // Implementation under test.
- MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
// The content_name known by the video channel.
const std::string kVcName("vcname");
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, kVcName, false, NULL);
- AddVideoTrackStats();
+ AddOutgoingVideoTrackStats();
stats.AddStream(stream_);
stats.set_session(&session_);
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
- stats.UpdateStats();
- webrtc::StatsReports reports;
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
+ StatsReports reports;
stats.GetStats(NULL, &reports);
- const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
- webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
+ const StatsReport* remote_report = FindNthReportByType(reports,
+ StatsReport::kStatsReportTypeRemoteSsrc, 1);
EXPECT_TRUE(remote_report == NULL);
}
@@ -593,23 +870,23 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) {
// an outgoing SSRC where stats are returned.
TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
webrtc::StatsCollector stats; // Implementation under test.
- MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
// The content_name known by the video channel.
const std::string kVcName("vcname");
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, kVcName, false, NULL);
- AddVideoTrackStats();
+ AddOutgoingVideoTrackStats();
stats.AddStream(stream_);
stats.set_session(&session_);
- webrtc::StatsReports reports;
+ StatsReports reports;
// Instruct the session to return stats containing the transport channel.
InitSessionStats(kVcName);
EXPECT_CALL(session_, GetStats(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
- Return(true)));
+ .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
+ Return(true)));
// Constructs an ssrc stats update.
cricket::VideoMediaInfo stats_read;
@@ -622,20 +899,69 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
video_sender_info.remote_stats.push_back(remote_ssrc_stats);
stats_read.senders.push_back(video_sender_info);
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(Return(&video_channel));
- EXPECT_CALL(*media_channel, GetStats(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
- const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
- webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
+
+ const StatsReport* remote_report = FindNthReportByType(reports,
+ StatsReport::kStatsReportTypeRemoteSsrc, 1);
EXPECT_FALSE(remote_report == NULL);
EXPECT_NE(0, remote_report->timestamp);
}
+// This test verifies that the empty track report exists in the returned stats
+// when StatsCollector::UpdateStats is called with ssrc stats.
+TEST_F(StatsCollectorTest, ReportsFromRemoteTrack) {
+ webrtc::StatsCollector stats; // Implementation under test.
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
+ cricket::VideoChannel video_channel(talk_base::Thread::Current(),
+ media_engine_, media_channel, &session_, "", false, NULL);
+ AddIncomingVideoTrackStats();
+ stats.AddStream(stream_);
+
+ stats.set_session(&session_);
+
+ StatsReports reports;
+
+ // Constructs an ssrc stats update.
+ cricket::VideoReceiverInfo video_receiver_info;
+ cricket::VideoMediaInfo stats_read;
+ const int64 kNumOfPacketsConcealed = 54321;
+
+ // Construct a stats value to read.
+ video_receiver_info.add_ssrc(1234);
+ video_receiver_info.packets_concealed = kNumOfPacketsConcealed;
+ stats_read.receivers.push_back(video_receiver_info);
+
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(stats_read),
+ Return(true)));
+
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
+ stats.GetStats(NULL, &reports);
+ // |reports| should contain at least one session report, one track report,
+ // and one ssrc report.
+ EXPECT_LE(static_cast<size_t>(3), reports.size());
+ const StatsReport* track_report = FindNthReportByType(
+ reports, StatsReport::kStatsReportTypeTrack, 1);
+ EXPECT_TRUE(track_report);
+
+ std::string ssrc_id = ExtractSsrcStatsValue(
+ reports, StatsReport::kStatsValueNameSsrc);
+ EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
+
+ std::string track_id = ExtractSsrcStatsValue(
+ reports, StatsReport::kStatsValueNameTrackId);
+ EXPECT_EQ(kRemoteTrackId, track_id);
+}
+
// This test verifies that all chained certificates are correctly
// reported
TEST_F(StatsCollectorTest, ChainedCertificateReportsCreated) {
@@ -678,7 +1004,7 @@ TEST_F(StatsCollectorTest, ChainlessCertificateReportsCreated) {
// transport is present.
TEST_F(StatsCollectorTest, NoTransport) {
webrtc::StatsCollector stats; // Implementation under test.
- webrtc::StatsReports reports; // returned values.
+ StatsReports reports; // returned values.
stats.set_session(&session_);
// Fake stats to process.
@@ -700,24 +1026,24 @@ TEST_F(StatsCollectorTest, NoTransport) {
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
// Check that the local certificate is absent.
std::string local_certificate_id = ExtractStatsValue(
- webrtc::StatsReport::kStatsReportTypeComponent,
+ StatsReport::kStatsReportTypeComponent,
reports,
- webrtc::StatsReport::kStatsValueNameLocalCertificateId);
+ StatsReport::kStatsValueNameLocalCertificateId);
ASSERT_EQ(kNotFound, local_certificate_id);
// Check that the remote certificate is absent.
std::string remote_certificate_id = ExtractStatsValue(
- webrtc::StatsReport::kStatsReportTypeComponent,
+ StatsReport::kStatsReportTypeComponent,
reports,
- webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
+ StatsReport::kStatsValueNameRemoteCertificateId);
ASSERT_EQ(kNotFound, remote_certificate_id);
}
@@ -725,7 +1051,7 @@ TEST_F(StatsCollectorTest, NoTransport) {
// does not have any certificates.
TEST_F(StatsCollectorTest, NoCertificates) {
webrtc::StatsCollector stats; // Implementation under test.
- webrtc::StatsReports reports; // returned values.
+ StatsReports reports; // returned values.
stats.set_session(&session_);
// Fake stats to process.
@@ -753,25 +1079,343 @@ TEST_F(StatsCollectorTest, NoCertificates) {
EXPECT_CALL(session_, GetStats(_))
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
- EXPECT_CALL(session_, video_channel())
- .WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
// Check that the local certificate is absent.
std::string local_certificate_id = ExtractStatsValue(
- webrtc::StatsReport::kStatsReportTypeComponent,
+ StatsReport::kStatsReportTypeComponent,
reports,
- webrtc::StatsReport::kStatsValueNameLocalCertificateId);
+ StatsReport::kStatsValueNameLocalCertificateId);
ASSERT_EQ(kNotFound, local_certificate_id);
// Check that the remote certificate is absent.
std::string remote_certificate_id = ExtractStatsValue(
- webrtc::StatsReport::kStatsReportTypeComponent,
+ StatsReport::kStatsReportTypeComponent,
reports,
- webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
+ StatsReport::kStatsValueNameRemoteCertificateId);
ASSERT_EQ(kNotFound, remote_certificate_id);
}
+// This test verifies that a remote certificate with an unsupported digest
+// algorithm is correctly ignored.
+TEST_F(StatsCollectorTest, UnsupportedDigestIgnored) {
+ // Build a local certificate.
+ std::string local_der = "This is the local der.";
+ talk_base::FakeSSLCertificate local_cert(DerToPem(local_der));
+
+ // Build a remote certificate with an unsupported digest algorithm.
+ std::string remote_der = "This is somebody else's der.";
+ talk_base::FakeSSLCertificate remote_cert(DerToPem(remote_der));
+ remote_cert.set_digest_algorithm("foobar");
+
+ TestCertificateReports(local_cert, std::vector<std::string>(1, local_der),
+ remote_cert, std::vector<std::string>());
+}
+
+// Verifies the correct optons are passed to the VideoMediaChannel when using
+// verbose output level.
+TEST_F(StatsCollectorTest, StatsOutputLevelVerbose) {
+ webrtc::StatsCollector stats; // Implementation under test.
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
+ cricket::VideoChannel video_channel(talk_base::Thread::Current(),
+ media_engine_, media_channel, &session_, "", false, NULL);
+ stats.set_session(&session_);
+
+ StatsReports reports; // returned values.
+ cricket::VideoMediaInfo stats_read;
+ cricket::BandwidthEstimationInfo bwe;
+ bwe.total_received_propagation_delta_ms = 10;
+ bwe.recent_received_propagation_delta_ms.push_back(100);
+ bwe.recent_received_propagation_delta_ms.push_back(200);
+ bwe.recent_received_packet_group_arrival_time_ms.push_back(1000);
+ bwe.recent_received_packet_group_arrival_time_ms.push_back(2000);
+ stats_read.bw_estimations.push_back(bwe);
+
+ EXPECT_CALL(session_, video_channel())
+ .WillRepeatedly(Return(&video_channel));
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+
+ StatsOptions options;
+ options.include_received_propagation_stats = true;
+ EXPECT_CALL(*media_channel, GetStats(
+ Field(&StatsOptions::include_received_propagation_stats, true),
+ _))
+ .WillOnce(DoAll(SetArgPointee<1>(stats_read),
+ Return(true)));
+
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelDebug);
+ stats.GetStats(NULL, &reports);
+ std::string result = ExtractBweStatsValue(
+ reports, "googReceivedPacketGroupPropagationDeltaSumDebug");
+ EXPECT_EQ("10", result);
+ result = ExtractBweStatsValue(
+ reports, "googReceivedPacketGroupPropagationDeltaDebug");
+ EXPECT_EQ("[100, 200]", result);
+ result = ExtractBweStatsValue(
+ reports, "googReceivedPacketGroupArrivalTimeDebug");
+ EXPECT_EQ("[1000, 2000]", result);
+}
+
+// This test verifies that a local stats object can get statistics via
+// AudioTrackInterface::GetStats() method.
+TEST_F(StatsCollectorTest, GetStatsFromLocalAudioTrack) {
+ webrtc::StatsCollector stats; // Implementation under test.
+ MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
+ // The content_name known by the voice channel.
+ const std::string kVcName("vcname");
+ cricket::VoiceChannel voice_channel(talk_base::Thread::Current(),
+ media_engine_, media_channel, &session_, kVcName, false);
+ AddOutgoingAudioTrackStats();
+ stats.AddStream(stream_);
+ stats.AddLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
+
+ stats.set_session(&session_);
+
+ // Instruct the session to return stats containing the transport channel.
+ InitSessionStats(kVcName);
+ EXPECT_CALL(session_, GetStats(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
+ Return(true)));
+
+ cricket::VoiceSenderInfo voice_sender_info;
+ InitVoiceSenderInfo(&voice_sender_info);
+
+ // Constructs an ssrc stats update.
+ cricket::VoiceMediaInfo stats_read;
+ stats_read.senders.push_back(voice_sender_info);
+
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(Return(&voice_channel));
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(*media_channel, GetStats(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
+ Return(true)));
+
+ StatsReports reports; // returned values.
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
+ stats.GetStats(NULL, &reports);
+
+ // Verfy the existence of the track report.
+ const StatsReport* report = FindNthReportByType(
+ reports, StatsReport::kStatsReportTypeSsrc, 1);
+ EXPECT_FALSE(report == NULL);
+ std::string track_id = ExtractSsrcStatsValue(
+ reports, StatsReport::kStatsValueNameTrackId);
+ EXPECT_EQ(kLocalTrackId, track_id);
+ std::string ssrc_id = ExtractSsrcStatsValue(
+ reports, StatsReport::kStatsValueNameSsrc);
+ EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
+
+ // Verifies the values in the track report.
+ UpdateVoiceSenderInfoFromAudioTrack(audio_track_.get(), &voice_sender_info);
+ VerifyVoiceSenderInfoReport(report, voice_sender_info);
+
+ // Verify we get the same result by passing a track to GetStats().
+ StatsReports track_reports; // returned values.
+ stats.GetStats(audio_track_.get(), &track_reports);
+ const StatsReport* track_report = FindNthReportByType(
+ track_reports, StatsReport::kStatsReportTypeSsrc, 1);
+ EXPECT_TRUE(track_report);
+ track_id = ExtractSsrcStatsValue(track_reports,
+ StatsReport::kStatsValueNameTrackId);
+ EXPECT_EQ(kLocalTrackId, track_id);
+ ssrc_id = ExtractSsrcStatsValue(track_reports,
+ StatsReport::kStatsValueNameSsrc);
+ EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
+ VerifyVoiceSenderInfoReport(track_report, voice_sender_info);
+
+ // Verify that there is no remote report for the local audio track because
+ // we did not set it up.
+ const StatsReport* remote_report = FindNthReportByType(reports,
+ StatsReport::kStatsReportTypeRemoteSsrc, 1);
+ EXPECT_TRUE(remote_report == NULL);
+}
+
+// This test verifies that audio receive streams populate stats reports
+// correctly.
+TEST_F(StatsCollectorTest, GetStatsFromRemoteStream) {
+ webrtc::StatsCollector stats; // Implementation under test.
+ MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
+ // The content_name known by the voice channel.
+ const std::string kVcName("vcname");
+ cricket::VoiceChannel voice_channel(talk_base::Thread::Current(),
+ media_engine_, media_channel, &session_, kVcName, false);
+ AddIncomingAudioTrackStats();
+ stats.AddStream(stream_);
+
+ stats.set_session(&session_);
+
+ // Instruct the session to return stats containing the transport channel.
+ InitSessionStats(kVcName);
+ EXPECT_CALL(session_, GetStats(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
+ Return(true)));
+
+ cricket::VoiceReceiverInfo voice_receiver_info;
+ InitVoiceReceiverInfo(&voice_receiver_info);
+ voice_receiver_info.codec_name = "fake_codec";
+
+ // Constructs an ssrc stats update.
+ cricket::VoiceMediaInfo stats_read;
+ stats_read.receivers.push_back(voice_receiver_info);
+
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(Return(&voice_channel));
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(*media_channel, GetStats(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
+ Return(true)));
+
+ StatsReports reports; // returned values.
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
+ stats.GetStats(NULL, &reports);
+
+ // Verify the track id is |kRemoteTrackId|.
+ const std::string track_id = ExtractSsrcStatsValue(
+ reports, StatsReport::kStatsValueNameTrackId);
+ EXPECT_EQ(kRemoteTrackId, track_id);
+
+ // Verify the report for this remote track.
+ const StatsReport* report = FindNthReportByType(
+ reports, StatsReport::kStatsReportTypeSsrc, 1);
+ EXPECT_FALSE(report == NULL);
+ VerifyVoiceReceiverInfoReport(report, voice_receiver_info);
+}
+
+// This test verifies that a local stats object won't update its statistics
+// after a RemoveLocalAudioTrack() call.
+TEST_F(StatsCollectorTest, GetStatsAfterRemoveAudioStream) {
+ webrtc::StatsCollector stats; // Implementation under test.
+ MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
+ // The content_name known by the voice channel.
+ const std::string kVcName("vcname");
+ cricket::VoiceChannel voice_channel(talk_base::Thread::Current(),
+ media_engine_, media_channel, &session_, kVcName, false);
+ AddOutgoingAudioTrackStats();
+ stats.AddStream(stream_);
+ stats.AddLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
+
+ stats.set_session(&session_);
+
+ // Instruct the session to return stats containing the transport channel.
+ InitSessionStats(kVcName);
+ EXPECT_CALL(session_, GetStats(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
+ Return(true)));
+
+ stats.RemoveLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
+ cricket::VoiceSenderInfo voice_sender_info;
+ InitVoiceSenderInfo(&voice_sender_info);
+
+ // Constructs an ssrc stats update.
+ cricket::VoiceMediaInfo stats_read;
+ stats_read.senders.push_back(voice_sender_info);
+
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(Return(&voice_channel));
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(*media_channel, GetStats(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
+ Return(true)));
+
+ StatsReports reports; // returned values.
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
+ stats.GetStats(NULL, &reports);
+
+ // The report will exist since we don't remove them in RemoveStream().
+ const StatsReport* report = FindNthReportByType(
+ reports, StatsReport::kStatsReportTypeSsrc, 1);
+ EXPECT_FALSE(report == NULL);
+ std::string track_id = ExtractSsrcStatsValue(
+ reports, StatsReport::kStatsValueNameTrackId);
+ EXPECT_EQ(kLocalTrackId, track_id);
+ std::string ssrc_id = ExtractSsrcStatsValue(
+ reports, StatsReport::kStatsValueNameSsrc);
+ EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
+
+ // Verifies the values in the track report, no value will be changed by the
+ // AudioTrackInterface::GetSignalValue() and
+ // AudioProcessorInterface::AudioProcessorStats::GetStats();
+ VerifyVoiceSenderInfoReport(report, voice_sender_info);
+}
+
+// This test verifies that when ongoing and incoming audio tracks are using
+// the same ssrc, they populate stats reports correctly.
+TEST_F(StatsCollectorTest, LocalAndRemoteTracksWithSameSsrc) {
+ webrtc::StatsCollector stats; // Implementation under test.
+ MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
+ // The content_name known by the voice channel.
+ const std::string kVcName("vcname");
+ cricket::VoiceChannel voice_channel(talk_base::Thread::Current(),
+ media_engine_, media_channel, &session_, kVcName, false);
+
+ // Create a local stream with a local audio track and adds it to the stats.
+ AddOutgoingAudioTrackStats();
+ stats.AddStream(stream_);
+ stats.AddLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
+
+ // Create a remote stream with a remote audio track and adds it to the stats.
+ talk_base::scoped_refptr<webrtc::MediaStream> remote_stream(
+ webrtc::MediaStream::Create("remotestreamlabel"));
+ talk_base::scoped_refptr<FakeAudioTrack> remote_track(
+ new talk_base::RefCountedObject<FakeAudioTrack>(kRemoteTrackId));
+ EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true)));
+ remote_stream->AddTrack(remote_track);
+ stats.AddStream(remote_stream);
+
+ stats.set_session(&session_);
+
+ // Instruct the session to return stats containing the transport channel.
+ InitSessionStats(kVcName);
+ EXPECT_CALL(session_, GetStats(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
+ Return(true)));
+
+ cricket::VoiceSenderInfo voice_sender_info;
+ InitVoiceSenderInfo(&voice_sender_info);
+
+ // Some of the contents in |voice_sender_info| needs to be updated from the
+ // |audio_track_|.
+ UpdateVoiceSenderInfoFromAudioTrack(audio_track_.get(), &voice_sender_info);
+
+ cricket::VoiceReceiverInfo voice_receiver_info;
+ InitVoiceReceiverInfo(&voice_receiver_info);
+
+ // Constructs an ssrc stats update.
+ cricket::VoiceMediaInfo stats_read;
+ stats_read.senders.push_back(voice_sender_info);
+ stats_read.receivers.push_back(voice_receiver_info);
+
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(Return(&voice_channel));
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(*media_channel, GetStats(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
+ Return(true)));
+
+ StatsReports reports; // returned values.
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
+
+ // Get stats for the local track.
+ stats.GetStats(audio_track_.get(), &reports);
+ const StatsReport* track_report = FindNthReportByType(
+ reports, StatsReport::kStatsReportTypeSsrc, 1);
+ EXPECT_TRUE(track_report);
+ std::string track_id = ExtractSsrcStatsValue(
+ reports, StatsReport::kStatsValueNameTrackId);
+ EXPECT_EQ(kLocalTrackId, track_id);
+ VerifyVoiceSenderInfoReport(track_report, voice_sender_info);
+
+ // Get stats for the remote track.
+ stats.GetStats(remote_track.get(), &reports);
+ track_report = FindNthReportByType(reports,
+ StatsReport::kStatsReportTypeSsrc, 1);
+ EXPECT_TRUE(track_report);
+ track_id = ExtractSsrcStatsValue(reports,
+ StatsReport::kStatsValueNameTrackId);
+ EXPECT_EQ(kRemoteTrackId, track_id);
+ VerifyVoiceReceiverInfoReport(track_report, voice_receiver_info);
+}
+
} // namespace
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/statstypes.h b/chromium/third_party/libjingle/source/talk/app/webrtc/statstypes.h
index 6890f9e017a..22e281cf71c 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/statstypes.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/statstypes.h
@@ -53,8 +53,12 @@ class StatsReport {
void AddValue(const std::string& name, const std::string& value);
void AddValue(const std::string& name, int64 value);
+ template <typename T>
+ void AddValue(const std::string& name, const std::vector<T>& value);
void AddBoolean(const std::string& name, bool value);
+ void ReplaceValue(const std::string& name, const std::string& value);
+
double timestamp; // Time since 1970-01-01T00:00:00Z in milliseconds.
typedef std::vector<Value> Values;
Values values;
@@ -129,6 +133,7 @@ class StatsReport {
// Internal StatsValue names
static const char kStatsValueNameAvgEncodeMs[];
+ static const char kStatsValueNameEncodeRelStdDev[];
static const char kStatsValueNameEncodeUsagePercent[];
static const char kStatsValueNameCaptureJitterMs[];
static const char kStatsValueNameCaptureQueueDelayMsPerS[];
@@ -141,8 +146,10 @@ class StatsReport {
static const char kStatsValueNameEchoDelayStdDev[];
static const char kStatsValueNameEchoReturnLoss[];
static const char kStatsValueNameEchoReturnLossEnhancement[];
+ static const char kStatsValueNameExpandRate[];
static const char kStatsValueNameFirsReceived[];
static const char kStatsValueNameFirsSent[];
+ static const char kStatsValueNameFrameHeightInput[];
static const char kStatsValueNameFrameHeightReceived[];
static const char kStatsValueNameFrameHeightSent[];
static const char kStatsValueNameFrameRateReceived[];
@@ -155,13 +162,18 @@ class StatsReport {
static const char kStatsValueNameJitterBufferMs[];
static const char kStatsValueNameMinPlayoutDelayMs[];
static const char kStatsValueNameRenderDelayMs[];
+ static const char kStatsValueNameCaptureStartNtpTimeMs[];
static const char kStatsValueNameFrameRateInput[];
static const char kStatsValueNameFrameRateSent[];
+ static const char kStatsValueNameFrameWidthInput[];
static const char kStatsValueNameFrameWidthReceived[];
static const char kStatsValueNameFrameWidthSent[];
static const char kStatsValueNameJitterReceived[];
static const char kStatsValueNameNacksReceived[];
static const char kStatsValueNameNacksSent[];
+ static const char kStatsValueNamePlisReceived[];
+ static const char kStatsValueNamePlisSent[];
+ static const char kStatsValueNamePreferredJitterBufferMs[];
static const char kStatsValueNameRtt[];
static const char kStatsValueNameAvailableSendBandwidth[];
static const char kStatsValueNameAvailableReceiveBandwidth[];
@@ -186,6 +198,15 @@ class StatsReport {
static const char kStatsValueNameRemoteCertificateId[];
static const char kStatsValueNameLocalCandidateType[];
static const char kStatsValueNameRemoteCandidateType[];
+ static const char kStatsValueNameRecvPacketGroupArrivalTimeDebug[];
+ static const char kStatsValueNameRecvPacketGroupPropagationDeltaDebug[];
+ static const char kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug[];
+ static const char kStatsValueNameDecodingCTSG[];
+ static const char kStatsValueNameDecodingCTN[];
+ static const char kStatsValueNameDecodingNormal[];
+ static const char kStatsValueNameDecodingPLC[];
+ static const char kStatsValueNameDecodingCNG[];
+ static const char kStatsValueNameDecodingPLCCNG[];
};
typedef std::vector<StatsReport> StatsReports;
diff --git a/chromium/third_party/libjingle/source/talk/examples/chat/textchatsendtask.h b/chromium/third_party/libjingle/source/talk/app/webrtc/umametrics.h
index 9b18923d2bf..81f7bac400d 100644..100755
--- a/chromium/third_party/libjingle/source/talk/examples/chat/textchatsendtask.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/umametrics.h
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2013, Google Inc.
+ * Copyright 2014, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,32 +25,35 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TALK_EXAMPLES_CHAT_TEXTCHATSENDTASK_H_
-#define TALK_EXAMPLES_CHAT_TEXTCHATSENDTASK_H_
+// This file contains enums related to IPv4/IPv6 metrics.
-#include "talk/xmpp/xmpptask.h"
+#ifndef TALK_APP_WEBRTC_UMAMETRICS_H_
+#define TALK_APP_WEBRTC_UMAMETRICS_H_
-namespace buzz {
+namespace webrtc {
-// A class to send chat messages to the XMPP server.
-class TextChatSendTask : public XmppTask {
- public:
- // Arguments:
- // parent a reference to task interface associated withe the XMPP client.
- explicit TextChatSendTask(XmppTaskParentInterface* parent);
+// Currently this contains information related to WebRTC network/transport
+// information.
- // Shuts down the thread associated with this task.
- virtual ~TextChatSendTask();
-
- // Forms the XMPP "chat" stanza with the specified receipient and message
- // and queues it up.
- XmppReturnStatus Send(const Jid& to, const std::string& message);
-
- // Picks up any "chat" stanzas from our queue and sends them to the server.
- virtual int ProcessStart();
+// This enum is backed by Chromium's histograms.xml,
+// chromium/src/tools/metrics/histograms/histograms.xml
+// Existing values cannot be re-ordered and new enums must be added
+// before kBoundary.
+enum PeerConnectionUMAMetricsCounter {
+ kPeerConnection_IPv4,
+ kPeerConnection_IPv6,
+ kBestConnections_IPv4,
+ kBestConnections_IPv6,
+ kBoundary,
};
-} // namespace buzz
+// This enum defines types for UMA samples, which will have a range.
+enum PeerConnectionUMAMetricsName {
+ kNetworkInterfaces_IPv4, // Number of IPv4 interfaces.
+ kNetworkInterfaces_IPv6, // Number of IPv6 interfaces.
+ kTimeToConnect, // In milliseconds.
+};
-#endif // TALK_EXAMPLES_CHAT_TEXTCHATSENDTASK_H_
+} // namespace webrtc
+#endif // TALK_APP_WEBRTC_UMA6METRICS_H_
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/videosource.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/videosource.cc
index f0182f4fb18..eb4ab97ea93 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/videosource.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/videosource.cc
@@ -36,30 +36,6 @@ using cricket::CaptureState;
using webrtc::MediaConstraintsInterface;
using webrtc::MediaSourceInterface;
-namespace webrtc {
-
-// Constraint keys. Specified by draft-alvestrand-constraints-resolution-00b
-// They are declared as static members in mediastreaminterface.h
-const char MediaConstraintsInterface::kMinAspectRatio[] = "minAspectRatio";
-const char MediaConstraintsInterface::kMaxAspectRatio[] = "maxAspectRatio";
-const char MediaConstraintsInterface::kMaxWidth[] = "maxWidth";
-const char MediaConstraintsInterface::kMinWidth[] = "minWidth";
-const char MediaConstraintsInterface::kMaxHeight[] = "maxHeight";
-const char MediaConstraintsInterface::kMinHeight[] = "minHeight";
-const char MediaConstraintsInterface::kMaxFrameRate[] = "maxFrameRate";
-const char MediaConstraintsInterface::kMinFrameRate[] = "minFrameRate";
-
-// Google-specific keys
-const char MediaConstraintsInterface::kNoiseReduction[] = "googNoiseReduction";
-const char MediaConstraintsInterface::kLeakyBucket[] = "googLeakyBucket";
-const char MediaConstraintsInterface::kTemporalLayeredScreencast[] =
- "googTemporalLayeredScreencast";
-// TODO(ronghuawu): Remove once cpu overuse detection is stable.
-const char MediaConstraintsInterface::kCpuOveruseDetection[] =
- "googCpuOveruseDetection";
-
-} // namespace webrtc
-
namespace {
const double kRoundingTruncation = 0.0005;
@@ -205,9 +181,7 @@ bool NewFormatWithConstraints(
} else if (constraint.key == MediaConstraintsInterface::kNoiseReduction ||
constraint.key == MediaConstraintsInterface::kLeakyBucket ||
constraint.key ==
- MediaConstraintsInterface::kTemporalLayeredScreencast ||
- constraint.key ==
- MediaConstraintsInterface::kCpuOveruseDetection) {
+ MediaConstraintsInterface::kTemporalLayeredScreencast) {
// These are actually options, not constraints, so they can be satisfied
// regardless of the format.
return true;
@@ -321,9 +295,6 @@ bool ExtractVideoOptions(const MediaConstraintsInterface* all_constraints,
all_valid &= ExtractOption(all_constraints,
MediaConstraintsInterface::kTemporalLayeredScreencast,
&(options->video_temporal_layer_screencast));
- all_valid &= ExtractOption(all_constraints,
- MediaConstraintsInterface::kCpuOveruseDetection,
- &(options->cpu_overuse_detection));
return all_valid;
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/videosource_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/videosource_unittest.cc
index 69e9b3f0f74..43811760c43 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/videosource_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/videosource_unittest.cc
@@ -238,7 +238,7 @@ TEST_F(VideoSourceTest, MandatoryConstraintCif5Fps) {
ASSERT_TRUE(format != NULL);
EXPECT_EQ(352, format->width);
EXPECT_EQ(288, format->height);
- EXPECT_EQ(5, format->framerate());
+ EXPECT_EQ(30, format->framerate());
}
// Test that the capture output is 720P if the camera support it and the
@@ -370,8 +370,6 @@ TEST_F(VideoSourceTest, SetValidOptionValues) {
MediaConstraintsInterface::kTemporalLayeredScreencast, "false");
constraints.AddOptional(
MediaConstraintsInterface::kLeakyBucket, "true");
- constraints.AddOptional(
- MediaConstraintsInterface::kCpuOveruseDetection, "true");
CreateVideoSource(&constraints);
@@ -383,8 +381,6 @@ TEST_F(VideoSourceTest, SetValidOptionValues) {
EXPECT_FALSE(value);
EXPECT_TRUE(source_->options()->video_leaky_bucket.Get(&value));
EXPECT_TRUE(value);
- EXPECT_TRUE(source_->options()->
- cpu_overuse_detection.GetWithDefaultIfUnset(false));
}
TEST_F(VideoSourceTest, OptionNotSet) {
@@ -392,7 +388,6 @@ TEST_F(VideoSourceTest, OptionNotSet) {
CreateVideoSource(&constraints);
bool value;
EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value));
- EXPECT_FALSE(source_->options()->cpu_overuse_detection.Get(&value));
}
TEST_F(VideoSourceTest, MandatoryOptionOverridesOptional) {
@@ -491,7 +486,7 @@ TEST_F(VideoSourceTest, MixedOptionsAndConstraints) {
ASSERT_TRUE(format != NULL);
EXPECT_EQ(352, format->width);
EXPECT_EQ(288, format->height);
- EXPECT_EQ(5, format->framerate());
+ EXPECT_EQ(30, format->framerate());
bool value = true;
EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value));
@@ -554,6 +549,6 @@ TEST_F(VideoSourceTest, OptionalSubOneFpsConstraints) {
kMaxWaitMs);
const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
ASSERT_TRUE(format != NULL);
- EXPECT_EQ(1, format->framerate());
+ EXPECT_EQ(30, format->framerate());
}
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtc.scons b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtc.scons
deleted file mode 100644
index 9b1af3cead8..00000000000
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtc.scons
+++ /dev/null
@@ -1,89 +0,0 @@
-# -*- Python -*-
-import talk
-
-Import('env')
-
-# For peerconnection, we need additional flags only for GCC 4.6+.
-peerconnection_lin_ccflags = []
-
-if env.Bit('linux'):
- # Detect the GCC version and update peerconnection flags.
- (major, minor, rev) = env.GetGccVersion()
- if major > 4 or (major == 4 and minor >= 6):
- peerconnection_lin_ccflags = ['-Wno-error=unused-but-set-variable']
-
-
-if env.Bit('have_webrtc_voice') and env.Bit('have_webrtc_video'):
- # local sources
- talk.Library(
- env,
- name = 'peerconnection',
- srcs = [
- 'audiotrack.cc',
- 'jsepicecandidate.cc',
- 'jsepsessiondescription.cc',
- 'mediaconstraintsinterface.cc',
- 'mediastream.cc',
- 'mediastreamhandler.cc',
- 'mediastreamproxy.cc',
- 'mediastreamsignaling.cc',
- 'mediastreamtrackproxy.cc',
- 'peerconnectionfactory.cc',
- 'peerconnection.cc',
- 'portallocatorfactory.cc',
- 'roapmessages.cc',
- 'roapsession.cc',
- 'roapsignaling.cc',
- 'videorendererimpl.cc',
- 'videotrack.cc',
- 'webrtcsdp.cc',
- 'webrtcsession.cc',
- 'webrtcsessiondescriptionfactory.cc',
- ],
- lin_ccflags = peerconnection_lin_ccflags
- )
-
- talk.Unittest(
- env,
- name = 'peerconnection',
- srcs = [
- 'test/fakeaudiocapturemodule.cc',
- 'test/fakeaudiocapturemodule_unittest.cc',
- 'test/fakevideocapturemodule.cc',
- 'test/fileframesource.cc',
- 'test/i420framesource.cc',
- 'test/staticframesource.cc',
- 'jsepsessiondescription_unittest.cc',
- 'mediastream_unittest.cc',
- 'mediastreamhandler_unittest.cc',
- 'mediastreamsignaling_unittest.cc',
- 'peerconnectioninterface_unittest.cc',
- 'peerconnection_unittest.cc',
- 'peerconnectionfactory_unittest.cc',
- 'roapmessages_unittest.cc',
- 'roapsession_unittest.cc',
- 'roapsignaling_unittest.cc',
- 'webrtcsdp_unittest.cc',
- 'webrtcsession_unittest.cc',
- ],
- libs = [
- 'base',
- 'expat',
- 'json',
- 'p2p',
- 'phone',
- 'srtp',
- 'xmllite',
- 'xmpp',
- 'yuvscaler',
- 'peerconnection',
- ],
- win_link_flags = [('', '/nodefaultlib:libcmt')[env.Bit('debug')]],
- lin_libs = [
- 'sound',
- ],
- mac_libs = [
- 'crypto',
- 'ssl',
- ],
- )
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsdp.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsdp.cc
index 79f94fe3b4e..b2d8a30ec52 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsdp.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsdp.cc
@@ -65,11 +65,13 @@ using cricket::kCodecParamMinBitrate;
using cricket::kCodecParamMinPTime;
using cricket::kCodecParamPTime;
using cricket::kCodecParamSPropStereo;
+using cricket::kCodecParamStartBitrate;
using cricket::kCodecParamStereo;
using cricket::kCodecParamUseInbandFec;
using cricket::kCodecParamSctpProtocol;
using cricket::kCodecParamSctpStreams;
using cricket::kCodecParamMaxAverageBitrate;
+using cricket::kCodecParamAssociatedPayloadType;
using cricket::kWildcardPayloadType;
using cricket::MediaContentDescription;
using cricket::MediaType;
@@ -127,9 +129,6 @@ static const char kAttributeMsidSemantics[] = "msid-semantic";
static const char kMediaStreamSemantic[] = "WMS";
static const char kSsrcAttributeMsid[] = "msid";
static const char kDefaultMsid[] = "default";
-static const char kMsidAppdataAudio[] = "a";
-static const char kMsidAppdataVideo[] = "v";
-static const char kMsidAppdataData[] = "d";
static const char kSsrcAttributeMslabel[] = "mslabel";
static const char kSSrcAttributeLabel[] = "label";
static const char kAttributeSsrcGroup[] = "ssrc-group";
@@ -210,7 +209,6 @@ static const char kIsacCodecName[] = "ISAC"; // From webrtcvoiceengine.cc
static const int kIsacWbDefaultRate = 32000; // From acm_common_defs.h
static const int kIsacSwbDefaultRate = 56000; // From acm_common_defs.h
-static const int kDefaultSctpFmt = 5000;
static const char kDefaultSctpmapProtocol[] = "webrtc-datachannel";
struct SsrcInfo {
@@ -243,7 +241,7 @@ static void BuildMediaDescription(const ContentInfo* content_info,
const TransportInfo* transport_info,
const MediaType media_type,
std::string* message);
-static void BuildSctpContentAttributes(std::string* message);
+static void BuildSctpContentAttributes(std::string* message, int sctp_port);
static void BuildRtpContentAttributes(
const MediaContentDescription* media_desc,
const MediaType media_type,
@@ -591,6 +589,19 @@ static bool CaseInsensitiveFind(std::string str1, std::string str2) {
return str1.find(str2) != std::string::npos;
}
+template <class T>
+static bool GetValueFromString(const std::string& line,
+ const std::string& s,
+ T* t,
+ SdpParseError* error) {
+ if (!talk_base::FromString(s, t)) {
+ std::ostringstream description;
+ description << "Invalid value: " << s << ".";
+ return ParseFailed(line, description.str(), error);
+ }
+ return true;
+}
+
void CreateTracksFromSsrcInfos(const SsrcInfoVec& ssrc_infos,
StreamParamsVec* tracks) {
ASSERT(tracks != NULL);
@@ -1006,11 +1017,20 @@ bool ParseCandidate(const std::string& message, Candidate* candidate,
if (!GetValue(fields[0], kAttributeCandidate, &foundation, error)) {
return false;
}
- const int component_id = talk_base::FromString<int>(fields[1]);
+ int component_id = 0;
+ if (!GetValueFromString(first_line, fields[1], &component_id, error)) {
+ return false;
+ }
const std::string transport = fields[2];
- const uint32 priority = talk_base::FromString<uint32>(fields[3]);
+ uint32 priority = 0;
+ if (!GetValueFromString(first_line, fields[3], &priority, error)) {
+ return false;
+ }
const std::string connection_address = fields[4];
- const int port = talk_base::FromString<int>(fields[5]);
+ int port = 0;
+ if (!GetValueFromString(first_line, fields[5], &port, error)) {
+ return false;
+ }
SocketAddress address(connection_address, port);
cricket::ProtocolType protocol;
@@ -1041,8 +1061,12 @@ bool ParseCandidate(const std::string& message, Candidate* candidate,
}
if (fields.size() >= (current_position + 2) &&
fields[current_position] == kAttributeCandidateRport) {
- related_address.SetPort(
- talk_base::FromString<int>(fields[++current_position]));
+ int port = 0;
+ if (!GetValueFromString(
+ first_line, fields[++current_position], &port, error)) {
+ return false;
+ }
+ related_address.SetPort(port);
++current_position;
}
@@ -1058,7 +1082,9 @@ bool ParseCandidate(const std::string& message, Candidate* candidate,
// RFC 5245
// *(SP extension-att-name SP extension-att-value)
if (fields[i] == kAttributeCandidateGeneration) {
- generation = talk_base::FromString<uint32>(fields[++i]);
+ if (!GetValueFromString(first_line, fields[++i], &generation, error)) {
+ return false;
+ }
} else if (fields[i] == kAttributeCandidateUsername) {
username = fields[++i];
} else if (fields[i] == kAttributeCandidatePassword) {
@@ -1113,7 +1139,10 @@ bool ParseExtmap(const std::string& line, RtpHeaderExtension* extmap,
}
std::vector<std::string> sub_fields;
talk_base::split(value_direction, kSdpDelimiterSlash, &sub_fields);
- int value = talk_base::FromString<int>(sub_fields[0]);
+ int value = 0;
+ if (!GetValueFromString(line, sub_fields[0], &value, error)) {
+ return false;
+ }
*extmap = RtpHeaderExtension(uri, value);
return true;
@@ -1138,6 +1167,7 @@ void BuildMediaDescription(const ContentInfo* content_info,
ASSERT(media_desc != NULL);
bool is_sctp = (media_desc->protocol() == cricket::kMediaProtocolDtlsSctp);
+ int sctp_port = cricket::kSctpDefaultPort;
// RFC 4566
// m=<media> <port> <proto> <fmt>
@@ -1172,14 +1202,22 @@ void BuildMediaDescription(const ContentInfo* content_info,
fmt.append(talk_base::ToString<int>(it->id));
}
} else if (media_type == cricket::MEDIA_TYPE_DATA) {
+ const DataContentDescription* data_desc =
+ static_cast<const DataContentDescription*>(media_desc);
if (is_sctp) {
fmt.append(" ");
- // TODO(jiayl): Replace the hard-coded string with the fmt read out of the
- // ContentDescription.
- fmt.append(talk_base::ToString<int>(kDefaultSctpFmt));
+
+ for (std::vector<cricket::DataCodec>::const_iterator it =
+ data_desc->codecs().begin();
+ it != data_desc->codecs().end(); ++it) {
+ if (it->id == cricket::kGoogleSctpDataCodecId &&
+ it->GetParam(cricket::kCodecParamPort, &sctp_port)) {
+ break;
+ }
+ }
+
+ fmt.append(talk_base::ToString<int>(sctp_port));
} else {
- const DataContentDescription* data_desc =
- static_cast<const DataContentDescription*>(media_desc);
for (std::vector<cricket::DataCodec>::const_iterator it =
data_desc->codecs().begin();
it != data_desc->codecs().end(); ++it) {
@@ -1261,18 +1299,18 @@ void BuildMediaDescription(const ContentInfo* content_info,
AddLine(os.str(), message);
if (is_sctp) {
- BuildSctpContentAttributes(message);
+ BuildSctpContentAttributes(message, sctp_port);
} else {
BuildRtpContentAttributes(media_desc, media_type, message);
}
}
-void BuildSctpContentAttributes(std::string* message) {
+void BuildSctpContentAttributes(std::string* message, int sctp_port) {
// draft-ietf-mmusic-sctp-sdp-04
// a=sctpmap:sctpmap-number protocol [streams]
std::ostringstream os;
InitAttrLine(kAttributeSctpmap, &os);
- os << kSdpDelimiterColon << kDefaultSctpFmt << kSdpDelimiterSpace
+ os << kSdpDelimiterColon << sctp_port << kSdpDelimiterSpace
<< kDefaultSctpmapProtocol << kSdpDelimiterSpace
<< (cricket::kMaxSctpSid + 1);
AddLine(os.str(), message);
@@ -1472,10 +1510,10 @@ void WriteFmtpParameters(const cricket::CodecParameterMap& parameters,
bool IsFmtpParam(const std::string& name) {
const char* kFmtpParams[] = {
kCodecParamMinPTime, kCodecParamSPropStereo,
- kCodecParamStereo, kCodecParamUseInbandFec,
+ kCodecParamStereo, kCodecParamUseInbandFec, kCodecParamStartBitrate,
kCodecParamMaxBitrate, kCodecParamMinBitrate, kCodecParamMaxQuantization,
kCodecParamSctpProtocol, kCodecParamSctpStreams,
- kCodecParamMaxAverageBitrate
+ kCodecParamMaxAverageBitrate, kCodecParamAssociatedPayloadType
};
for (size_t i = 0; i < ARRAY_SIZE(kFmtpParams); ++i) {
if (_stricmp(name.c_str(), kFmtpParams[i]) == 0) {
@@ -1544,7 +1582,9 @@ bool GetParameter(const std::string& name,
if (found == params.end()) {
return false;
}
- *value = talk_base::FromString<int>(found->second);
+ if (!talk_base::FromString(found->second, value)) {
+ return false;
+ }
return true;
}
@@ -2085,7 +2125,17 @@ bool ParseMediaDescription(const std::string& message,
// <fmt>
std::vector<int> codec_preference;
for (size_t j = 3 ; j < fields.size(); ++j) {
- codec_preference.push_back(talk_base::FromString<int>(fields[j]));
+ // TODO(wu): Remove when below bug is fixed.
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=996329
+ if (fields[j] == "" && j == fields.size() - 1) {
+ continue;
+ }
+
+ int pl = 0;
+ if (!GetValueFromString(line, fields[j], &pl, error)) {
+ return false;
+ }
+ codec_preference.push_back(pl);
}
// Make a temporary TransportDescription based on |session_td|.
@@ -2111,9 +2161,6 @@ bool ParseMediaDescription(const std::string& message,
message, cricket::MEDIA_TYPE_AUDIO, mline_index, protocol,
codec_preference, pos, &content_name,
&transport, candidates, error));
- MaybeCreateStaticPayloadAudioCodecs(
- codec_preference,
- static_cast<AudioContentDescription*>(content.get()));
} else if (HasAttribute(line, kMediaTypeData)) {
DataContentDescription* desc =
ParseContentDescription<DataContentDescription>(
@@ -2121,7 +2168,7 @@ bool ParseMediaDescription(const std::string& message,
codec_preference, pos, &content_name,
&transport, candidates, error);
- if (protocol == cricket::kMediaProtocolDtlsSctp) {
+ if (desc && protocol == cricket::kMediaProtocolDtlsSctp) {
// Add the SCTP Port number as a pseudo-codec "port" parameter
cricket::DataCodec codec_port(
cricket::kGoogleSctpDataCodecId, cricket::kGoogleSctpDataCodecName,
@@ -2129,6 +2176,7 @@ bool ParseMediaDescription(const std::string& message,
codec_port.SetParam(cricket::kCodecParamPort, fields[3]);
LOG(INFO) << "ParseMediaDescription: Got SCTP Port Number "
<< fields[3];
+ ASSERT(!desc->HasCodec(cricket::kGoogleSctpDataCodecId));
desc->AddCodec(codec_port);
}
@@ -2366,6 +2414,11 @@ bool ParseContent(const std::string& message,
ASSERT(content_name != NULL);
ASSERT(transport != NULL);
+ if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+ MaybeCreateStaticPayloadAudioCodecs(
+ codec_preference, static_cast<AudioContentDescription*>(media_desc));
+ }
+
// The media level "ice-ufrag" and "ice-pwd".
// The candidates before update the media level "ice-pwd" and "ice-ufrag".
Candidates candidates_orig;
@@ -2393,19 +2446,6 @@ bool ParseContent(const std::string& message,
}
}
- if (IsLineType(line, kLineTypeSessionBandwidth)) {
- std::string bandwidth;
- if (HasAttribute(line, kApplicationSpecificMaximum)) {
- if (!GetValue(line, kApplicationSpecificMaximum, &bandwidth, error)) {
- return false;
- } else {
- media_desc->set_bandwidth(
- talk_base::FromString<int>(bandwidth) * 1000);
- }
- }
- continue;
- }
-
// RFC 4566
// b=* (zero or more bandwidth information lines)
if (IsLineType(line, kLineTypeSessionBandwidth)) {
@@ -2414,8 +2454,11 @@ bool ParseContent(const std::string& message,
if (!GetValue(line, kApplicationSpecificMaximum, &bandwidth, error)) {
return false;
} else {
- media_desc->set_bandwidth(
- talk_base::FromString<int>(bandwidth) * 1000);
+ int b = 0;
+ if (!GetValueFromString(line, bandwidth, &b, error)) {
+ return false;
+ }
+ media_desc->set_bandwidth(b * 1000);
}
}
continue;
@@ -2538,9 +2581,11 @@ bool ParseContent(const std::string& message,
return false;
}
int buffer_latency = 0;
- if (!talk_base::FromString(flag_value, &buffer_latency) ||
- buffer_latency < 0) {
- return ParseFailed(message, "Invalid buffer latency.", error);
+ if (!GetValueFromString(line, flag_value, &buffer_latency, error)) {
+ return false;
+ }
+ if (buffer_latency < 0) {
+ return ParseFailed(line, "Buffer latency less than 0.", error);
}
media_desc->set_buffered_mode_latency(buffer_latency);
}
@@ -2632,7 +2677,10 @@ bool ParseSsrcAttribute(const std::string& line, SsrcInfoVec* ssrc_infos,
if (!GetValue(field1, kAttributeSsrc, &ssrc_id_s, error)) {
return false;
}
- uint32 ssrc_id = talk_base::FromString<uint32>(ssrc_id_s);
+ uint32 ssrc_id = 0;
+ if (!GetValueFromString(line, ssrc_id_s, &ssrc_id, error)) {
+ return false;
+ }
std::string attribute;
std::string value;
@@ -2709,7 +2757,10 @@ bool ParseSsrcGroupAttribute(const std::string& line,
}
std::vector<uint32> ssrcs;
for (size_t i = 1; i < fields.size(); ++i) {
- uint32 ssrc = talk_base::FromString<uint32>(fields[i]);
+ uint32 ssrc = 0;
+ if (!GetValueFromString(line, fields[i], &ssrc, error)) {
+ return false;
+ }
ssrcs.push_back(ssrc);
}
ssrc_groups->push_back(SsrcGroup(semantics, ssrcs));
@@ -2732,7 +2783,10 @@ bool ParseCryptoAttribute(const std::string& line,
if (!GetValue(fields[0], kAttributeCrypto, &tag_value, error)) {
return false;
}
- int tag = talk_base::FromString<int>(tag_value);
+ int tag = 0;
+ if (!GetValueFromString(line, tag_value, &tag, error)) {
+ return false;
+ }
const std::string crypto_suite = fields[1];
const std::string key_params = fields[2];
std::string session_params;
@@ -2796,7 +2850,10 @@ bool ParseRtpmapAttribute(const std::string& line,
if (!GetValue(fields[0], kAttributeRtpmap, &payload_type_value, error)) {
return false;
}
- const int payload_type = talk_base::FromString<int>(payload_type_value);
+ int payload_type = 0;
+ if (!GetValueFromString(line, payload_type_value, &payload_type, error)) {
+ return false;
+ }
// Set the preference order depending on the order of the pl type in the
// <fmt> of the m-line.
@@ -2820,7 +2877,10 @@ bool ParseRtpmapAttribute(const std::string& line,
error);
}
const std::string encoding_name = codec_params[0];
- const int clock_rate = talk_base::FromString<int>(codec_params[1]);
+ int clock_rate = 0;
+ if (!GetValueFromString(line, codec_params[1], &clock_rate, error)) {
+ return false;
+ }
if (media_type == cricket::MEDIA_TYPE_VIDEO) {
VideoContentDescription* video_desc =
static_cast<VideoContentDescription*>(media_desc);
@@ -2839,7 +2899,9 @@ bool ParseRtpmapAttribute(const std::string& line,
// additional parameters are needed.
int channels = 1;
if (codec_params.size() == 3) {
- channels = talk_base::FromString<int>(codec_params[2]);
+ if (!GetValueFromString(line, codec_params[2], &channels, error)) {
+ return false;
+ }
}
int bitrate = 0;
// The default behavior for ISAC (bitrate == 0) in webrtcvoiceengine.cc
@@ -2926,7 +2988,10 @@ bool ParseFmtpAttributes(const std::string& line, const MediaType media_type,
codec_params[name] = value;
}
- int int_payload_type = talk_base::FromString<int>(payload_type);
+ int int_payload_type = 0;
+ if (!GetValueFromString(line, payload_type, &int_payload_type, error)) {
+ return false;
+ }
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
UpdateCodec<AudioContentDescription, cricket::AudioCodec>(
media_desc, int_payload_type, codec_params);
@@ -2954,8 +3019,12 @@ bool ParseRtcpFbAttribute(const std::string& line, const MediaType media_type,
error)) {
return false;
}
- int payload_type = (payload_type_string == "*") ?
- kWildcardPayloadType : talk_base::FromString<int>(payload_type_string);
+ int payload_type = kWildcardPayloadType;
+ if (payload_type_string != "*") {
+ if (!GetValueFromString(line, payload_type_string, &payload_type, error)) {
+ return false;
+ }
+ }
std::string id = rtcp_fb_fields[1];
std::string param = "";
for (std::vector<std::string>::iterator iter = rtcp_fb_fields.begin() + 2;
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsdp_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsdp_unittest.cc
index 541868314c7..64776e29e1c 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsdp_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsdp_unittest.cc
@@ -299,6 +299,19 @@ static const char kSdpSctpDataChannelWithCandidatesString[] =
"a=mid:data_content_name\r\n"
"a=sctpmap:5000 webrtc-datachannel 1024\r\n";
+static const char kSdpConferenceString[] =
+ "v=0\r\n"
+ "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=msid-semantic: WMS\r\n"
+ "m=audio 1 RTP/SAVPF 111 103 104\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=x-google-flag:conference\r\n"
+ "m=video 1 RTP/SAVPF 120\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=x-google-flag:conference\r\n";
+
// One candidate reference string as per W3c spec.
// candidate:<blah> not a=candidate:<blah>CRLF
@@ -388,14 +401,31 @@ static void Replace(const std::string& line,
newlines.c_str(), newlines.length(), message);
}
-static void ReplaceAndTryToParse(const char* search, const char* replace) {
+// Expect fail to parase |bad_sdp| and expect |bad_part| be part of the error
+// message.
+static void ExpectParseFailure(const std::string& bad_sdp,
+ const std::string& bad_part) {
JsepSessionDescription desc(kDummyString);
- std::string sdp = kSdpFullString;
- Replace(search, replace, &sdp);
SdpParseError error;
- bool ret = webrtc::SdpDeserialize(sdp, &desc, &error);
+ bool ret = webrtc::SdpDeserialize(bad_sdp, &desc, &error);
EXPECT_FALSE(ret);
- EXPECT_NE(std::string::npos, error.line.find(replace));
+ EXPECT_NE(std::string::npos, error.line.find(bad_part.c_str()));
+}
+
+// Expect fail to parse kSdpFullString if replace |good_part| with |bad_part|.
+static void ExpectParseFailure(const char* good_part, const char* bad_part) {
+ std::string bad_sdp = kSdpFullString;
+ Replace(good_part, bad_part, &bad_sdp);
+ ExpectParseFailure(bad_sdp, bad_part);
+}
+
+// Expect fail to parse kSdpFullString if add |newlines| after |injectpoint|.
+static void ExpectParseFailureWithNewLines(const std::string& injectpoint,
+ const std::string& newlines,
+ const std::string& bad_part) {
+ std::string bad_sdp = kSdpFullString;
+ InjectAfter(injectpoint, newlines, &bad_sdp);
+ ExpectParseFailure(bad_sdp, bad_part);
}
static void ReplaceDirection(cricket::MediaContentDirection direction,
@@ -1123,6 +1153,15 @@ class WebRtcSdpTest : public testing::Test {
<< "a=maxptime:" << params.max_ptime << "\r\n";
sdp += os.str();
+ os.clear();
+ os.str("");
+ // Pl type 100 preferred.
+ os << "m=video 1 RTP/SAVPF 99 95\r\n"
+ << "a=rtpmap:99 VP8/90000\r\n"
+ << "a=rtpmap:95 RTX/90000\r\n"
+ << "a=fmtp:95 apt=99;rtx-time=1000\r\n";
+ sdp += os.str();
+
// Deserialize
SdpParseError error;
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
@@ -1153,6 +1192,19 @@ class WebRtcSdpTest : public testing::Test {
}
}
}
+
+ const ContentInfo* vc = GetFirstVideoContent(jdesc_output->description());
+ ASSERT_TRUE(vc != NULL);
+ const VideoContentDescription* vcd =
+ static_cast<const VideoContentDescription*>(vc->description);
+ ASSERT_FALSE(vcd->codecs().empty());
+ cricket::VideoCodec vp8 = vcd->codecs()[0];
+ EXPECT_EQ("VP8", vp8.name);
+ EXPECT_EQ(99, vp8.id);
+ cricket::VideoCodec rtx = vcd->codecs()[1];
+ EXPECT_EQ("RTX", rtx.name);
+ EXPECT_EQ(95, rtx.id);
+ VerifyCodecParameter(rtx.params, "apt", vp8.id);
}
void TestDeserializeRtcpFb(JsepSessionDescription* jdesc_output,
@@ -1172,6 +1224,7 @@ class WebRtcSdpTest : public testing::Test {
"m=video 3457 RTP/SAVPF 101\r\n"
"a=rtpmap:101 VP8/90000\r\n"
"a=rtcp-fb:101 nack\r\n"
+ "a=rtcp-fb:101 nack pli\r\n"
"a=rtcp-fb:101 goog-remb\r\n"
"a=rtcp-fb:101 ccm fir\r\n";
std::ostringstream os;
@@ -1204,6 +1257,9 @@ class WebRtcSdpTest : public testing::Test {
cricket::FeedbackParam(cricket::kRtcpFbParamNack,
cricket::kParamValueEmpty)));
EXPECT_TRUE(vp8.HasFeedbackParam(
+ cricket::FeedbackParam(cricket::kRtcpFbParamNack,
+ cricket::kRtcpFbNackParamPli)));
+ EXPECT_TRUE(vp8.HasFeedbackParam(
cricket::FeedbackParam(cricket::kRtcpFbParamRemb,
cricket::kParamValueEmpty)));
EXPECT_TRUE(vp8.HasFeedbackParam(
@@ -1432,6 +1488,37 @@ TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
EXPECT_EQ(message, expected_sdp);
}
+TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) {
+ AddSctpDataChannel();
+ JsepSessionDescription jsep_desc(kDummyString);
+
+ ASSERT_TRUE(jsep_desc.Initialize(desc_.Copy(), kSessionId, kSessionVersion));
+ DataContentDescription* dcdesc = static_cast<DataContentDescription*>(
+ jsep_desc.description()->GetContentDescriptionByName(kDataContentName));
+
+ const int kNewPort = 1234;
+ cricket::DataCodec codec(
+ cricket::kGoogleSctpDataCodecId, cricket::kGoogleSctpDataCodecName, 0);
+ codec.SetParam(cricket::kCodecParamPort, kNewPort);
+ dcdesc->AddOrReplaceCodec(codec);
+
+ std::string message = webrtc::SdpSerialize(jsep_desc);
+
+ std::string expected_sdp = kSdpString;
+ expected_sdp.append(kSdpSctpDataChannelString);
+
+ char default_portstr[16];
+ char new_portstr[16];
+ talk_base::sprintfn(default_portstr, sizeof(default_portstr), "%d",
+ kDefaultSctpPort);
+ talk_base::sprintfn(new_portstr, sizeof(new_portstr), "%d", kNewPort);
+ talk_base::replace_substrs(default_portstr, strlen(default_portstr),
+ new_portstr, strlen(new_portstr),
+ &expected_sdp);
+
+ EXPECT_EQ(expected_sdp, message);
+}
+
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithDataChannelAndBandwidth) {
AddRtpDataChannel();
data_desc_->set_bandwidth(100*1000);
@@ -1470,6 +1557,21 @@ TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmap) {
EXPECT_EQ(sdp_with_extmap, message);
}
+TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBufferLatency) {
+ VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
+ GetFirstVideoContent(&desc_)->description);
+ vcd->set_buffered_mode_latency(128);
+
+ ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
+ jdesc_.session_id(),
+ jdesc_.session_version()));
+ std::string message = webrtc::SdpSerialize(jdesc_);
+ std::string sdp_with_buffer_latency = kSdpFullString;
+ InjectAfter("a=rtpmap:120 VP8/90000\r\n",
+ "a=x-google-buffer-latency:128\r\n",
+ &sdp_with_buffer_latency);
+ EXPECT_EQ(sdp_with_buffer_latency, message);
+}
TEST_F(WebRtcSdpTest, SerializeCandidates) {
std::string message = webrtc::SdpSerializeCandidate(*jcandidate_);
@@ -1543,6 +1645,37 @@ TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) {
EXPECT_EQ(ref_codecs, audio->codecs());
}
+TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) {
+ static const char kSdpNoRtpmapString[] =
+ "v=0\r\n"
+ "o=- 11 22 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "m=audio 49232 RTP/AVP 18 103\r\n"
+ "a=fmtp:18 annexb=yes\r\n"
+ "a=rtpmap:103 ISAC/16000\r\n";
+
+ JsepSessionDescription jdesc(kDummyString);
+ EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
+ cricket::AudioContentDescription* audio =
+ static_cast<AudioContentDescription*>(
+ jdesc.description()->GetContentDescriptionByName(cricket::CN_AUDIO));
+
+ cricket::AudioCodec g729 = audio->codecs()[0];
+ EXPECT_EQ("G729", g729.name);
+ EXPECT_EQ(8000, g729.clockrate);
+ EXPECT_EQ(18, g729.id);
+ cricket::CodecParameterMap::iterator found =
+ g729.params.find("annexb");
+ ASSERT_TRUE(found != g729.params.end());
+ EXPECT_EQ(found->second, "yes");
+
+ cricket::AudioCodec isac = audio->codecs()[1];
+ EXPECT_EQ("ISAC", isac.name);
+ EXPECT_EQ(103, isac.id);
+ EXPECT_EQ(16000, isac.clockrate);
+}
+
// Ensure that we can deserialize SDP with a=fingerprint properly.
TEST_F(WebRtcSdpTest, DeserializeJsepSessionDescriptionWithFingerprint) {
// Add a DTLS a=fingerprint attribute to our session description.
@@ -1650,6 +1783,23 @@ TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithUfragPwd) {
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ufrag_pwd));
}
+TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBufferLatency) {
+ JsepSessionDescription jdesc_with_buffer_latency(kDummyString);
+ std::string sdp_with_buffer_latency = kSdpFullString;
+ InjectAfter("a=rtpmap:120 VP8/90000\r\n",
+ "a=x-google-buffer-latency:128\r\n",
+ &sdp_with_buffer_latency);
+
+ EXPECT_TRUE(
+ SdpDeserialize(sdp_with_buffer_latency, &jdesc_with_buffer_latency));
+ VideoContentDescription* vcd = static_cast<VideoContentDescription*>(
+ GetFirstVideoContent(&desc_)->description);
+ vcd->set_buffered_mode_latency(128);
+ ASSERT_TRUE(jdesc_.Initialize(desc_.Copy(),
+ jdesc_.session_id(),
+ jdesc_.session_version()));
+ EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_buffer_latency));
+}
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRecvOnlyContent) {
EXPECT_TRUE(TestDeserializeDirection(cricket::MD_RECVONLY));
@@ -1779,6 +1929,18 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
}
+// For crbug/344475.
+TEST_F(WebRtcSdpTest, DeserializeSdpWithCorruptedSctpDataChannels) {
+ std::string sdp_with_data = kSdpString;
+ sdp_with_data.append(kSdpSctpDataChannelString);
+ // Remove the "\n" at the end.
+ sdp_with_data = sdp_with_data.substr(0, sdp_with_data.size() - 1);
+ JsepSessionDescription jdesc_output(kDummyString);
+
+ EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
+ // No crash is a pass.
+}
+
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndNewPort) {
AddSctpDataChannel();
const uint16 kUnusualSctpPort = 9556;
@@ -1789,6 +1951,7 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndNewPort) {
talk_base::sprintfn(unusual_portstr, sizeof(unusual_portstr), "%d",
kUnusualSctpPort);
+ // First setup the expected JsepSessionDescription.
JsepSessionDescription jdesc(kDummyString);
// take our pre-built session description and change the SCTP port.
cricket::SessionDescription* mutant = desc_.Copy();
@@ -1798,11 +1961,13 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndNewPort) {
EXPECT_EQ(codecs.size(), 1UL);
EXPECT_EQ(codecs[0].id, cricket::kGoogleSctpDataCodecId);
codecs[0].SetParam(cricket::kCodecParamPort, kUnusualSctpPort);
+ dcdesc->set_codecs(codecs);
// note: mutant's owned by jdesc now.
ASSERT_TRUE(jdesc.Initialize(mutant, kSessionId, kSessionVersion));
mutant = NULL;
+ // Then get the deserialized JsepSessionDescription.
std::string sdp_with_data = kSdpString;
sdp_with_data.append(kSdpSctpDataChannelString);
talk_base::replace_substrs(default_portstr, strlen(default_portstr),
@@ -1888,6 +2053,24 @@ TEST_F(WebRtcSdpTest, DeserializeCandidateOldFormat) {
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(ref_candidate));
}
+TEST_F(WebRtcSdpTest, DeserializeSdpWithConferenceFlag) {
+ JsepSessionDescription jdesc(kDummyString);
+
+ // Deserialize
+ EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
+
+ // Verify
+ cricket::AudioContentDescription* audio =
+ static_cast<AudioContentDescription*>(
+ jdesc.description()->GetContentDescriptionByName(cricket::CN_AUDIO));
+ EXPECT_TRUE(audio->conference_mode());
+
+ cricket::VideoContentDescription* video =
+ static_cast<VideoContentDescription*>(
+ jdesc.description()->GetContentDescriptionByName(cricket::CN_VIDEO));
+ EXPECT_TRUE(video->conference_mode());
+}
+
TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
const char kSdpDestroyer[] = "!@#$%^&";
const char kSdpInvalidLine1[] = " =candidate";
@@ -1902,29 +2085,72 @@ TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
// Missing space.
const char kSdpInvalidLine6[] = "a=fingerprint:sha-1"
"4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB";
+ // MD5 is not allowed in fingerprints.
+ const char kSdpInvalidLine7[] = "a=fingerprint:md5 "
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B";
// Broken session description
- ReplaceAndTryToParse("v=", kSdpDestroyer);
- ReplaceAndTryToParse("o=", kSdpDestroyer);
- ReplaceAndTryToParse("s=-", kSdpDestroyer);
+ ExpectParseFailure("v=", kSdpDestroyer);
+ ExpectParseFailure("o=", kSdpDestroyer);
+ ExpectParseFailure("s=-", kSdpDestroyer);
// Broken time description
- ReplaceAndTryToParse("t=", kSdpDestroyer);
+ ExpectParseFailure("t=", kSdpDestroyer);
// Broken media description
- ReplaceAndTryToParse("m=audio", "c=IN IP4 74.125.224.39");
- ReplaceAndTryToParse("m=video", kSdpDestroyer);
+ ExpectParseFailure("m=audio", "c=IN IP4 74.125.224.39");
+ ExpectParseFailure("m=video", kSdpDestroyer);
// Invalid lines
- ReplaceAndTryToParse("a=candidate", kSdpInvalidLine1);
- ReplaceAndTryToParse("a=candidate", kSdpInvalidLine2);
- ReplaceAndTryToParse("a=candidate", kSdpInvalidLine3);
+ ExpectParseFailure("a=candidate", kSdpInvalidLine1);
+ ExpectParseFailure("a=candidate", kSdpInvalidLine2);
+ ExpectParseFailure("a=candidate", kSdpInvalidLine3);
// Bogus fingerprint replacing a=sendrev. We selected this attribute
// because it's orthogonal to what we are replacing and hence
// safe.
- ReplaceAndTryToParse("a=sendrecv", kSdpInvalidLine4);
- ReplaceAndTryToParse("a=sendrecv", kSdpInvalidLine5);
- ReplaceAndTryToParse("a=sendrecv", kSdpInvalidLine6);
+ ExpectParseFailure("a=sendrecv", kSdpInvalidLine4);
+ ExpectParseFailure("a=sendrecv", kSdpInvalidLine5);
+ ExpectParseFailure("a=sendrecv", kSdpInvalidLine6);
+ ExpectParseFailure("a=sendrecv", kSdpInvalidLine7);
+}
+
+TEST_F(WebRtcSdpTest, DeserializeSdpWithInvalidAttributeValue) {
+ // ssrc
+ ExpectParseFailure("a=ssrc:1", "a=ssrc:badvalue");
+ ExpectParseFailure("a=ssrc-group:FEC 5 6", "a=ssrc-group:FEC badvalue 6");
+ // crypto
+ ExpectParseFailure("a=crypto:1 ", "a=crypto:badvalue ");
+ // rtpmap
+ ExpectParseFailure("a=rtpmap:111 ", "a=rtpmap:badvalue ");
+ ExpectParseFailure("opus/48000/2", "opus/badvalue/2");
+ ExpectParseFailure("opus/48000/2", "opus/48000/badvalue");
+ // candidate
+ ExpectParseFailure("1 udp 2130706432", "badvalue udp 2130706432");
+ ExpectParseFailure("1 udp 2130706432", "1 udp badvalue");
+ ExpectParseFailure("192.168.1.5 1234", "192.168.1.5 badvalue");
+ ExpectParseFailure("rport 2346", "rport badvalue");
+ ExpectParseFailure("rport 2346 generation 2",
+ "rport 2346 generation badvalue");
+ // m line
+ ExpectParseFailure("m=audio 2345 RTP/SAVPF 111 103 104",
+ "m=audio 2345 RTP/SAVPF 111 badvalue 104");
+
+ // bandwidth
+ ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
+ "b=AS:badvalue\r\n",
+ "b=AS:badvalue");
+ // rtcp-fb
+ ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
+ "a=rtcp-fb:badvalue nack\r\n",
+ "a=rtcp-fb:badvalue nack");
+ // extmap
+ ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
+ "a=extmap:badvalue http://example.com\r\n",
+ "a=extmap:badvalue http://example.com");
+ // x-google-buffer-latency
+ ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
+ "a=x-google-buffer-latency:badvalue\r\n",
+ "a=x-google-buffer-latency:badvalue");
}
TEST_F(WebRtcSdpTest, DeserializeSdpWithReorderedPltypes) {
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession.cc
index 7e153b3ffd1..1b1c287817d 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession.cc
@@ -27,8 +27,9 @@
#include "talk/app/webrtc/webrtcsession.h"
+#include <limits.h>
+
#include <algorithm>
-#include <climits>
#include <vector>
#include "talk/app/webrtc/jsepicecandidate.h"
@@ -40,6 +41,7 @@
#include "talk/base/helpers.h"
#include "talk/base/logging.h"
#include "talk/base/stringencode.h"
+#include "talk/base/stringutils.h"
#include "talk/media/base/constants.h"
#include "talk/media/base/videocapturer.h"
#include "talk/session/media/channel.h"
@@ -54,47 +56,24 @@ using cricket::TransportInfo;
namespace webrtc {
-const char MediaConstraintsInterface::kInternalConstraintPrefix[] = "internal";
-
-// Supported MediaConstraints.
-// DSCP constraints.
-const char MediaConstraintsInterface::kEnableDscp[] = "googDscp";
-// DTLS-SRTP pseudo-constraints.
-const char MediaConstraintsInterface::kEnableDtlsSrtp[] =
- "DtlsSrtpKeyAgreement";
-// DataChannel pseudo constraints.
-const char MediaConstraintsInterface::kEnableRtpDataChannels[] =
- "RtpDataChannels";
-// This constraint is for internal use only, representing the Chrome command
-// line flag. So it is prefixed with kInternalConstraintPrefix so JS values
-// will be removed.
-const char MediaConstraintsInterface::kEnableSctpDataChannels[] =
- "deprecatedSctpDataChannels";
-
// Error messages
-const char kSetLocalSdpFailed[] = "SetLocalDescription failed: ";
-const char kSetRemoteSdpFailed[] = "SetRemoteDescription failed: ";
-const char kCreateChannelFailed[] = "Failed to create channels.";
const char kBundleWithoutRtcpMux[] = "RTCP-MUX must be enabled when BUNDLE "
"is enabled.";
+const char kCreateChannelFailed[] = "Failed to create channels.";
const char kInvalidCandidates[] = "Description contains invalid candidates.";
const char kInvalidSdp[] = "Invalid session description.";
const char kMlineMismatch[] =
- "Offer and answer descriptions m-lines are not matching. "
- "Rejecting answer.";
-const char kSdpWithoutCrypto[] = "Called with a SDP without crypto enabled.";
-const char kSdpWithoutSdesAndDtlsDisabled[] =
- "Called with an SDP without SDES crypto and DTLS disabled locally.";
+ "Offer and answer descriptions m-lines are not matching. Rejecting answer.";
+const char kPushDownTDFailed[] =
+ "Failed to push down transport description:";
+const char kSdpWithoutDtlsFingerprint[] =
+ "Called with SDP without DTLS fingerprint.";
+const char kSdpWithoutSdesCrypto[] =
+ "Called with SDP without SDES crypto.";
const char kSdpWithoutIceUfragPwd[] =
- "Called with an SDP without ice-ufrag and ice-pwd.";
+ "Called with SDP without ice-ufrag and ice-pwd.";
const char kSessionError[] = "Session error code: ";
-const char kUpdateStateFailed[] = "Failed to update session state: ";
-const char kPushDownOfferTDFailed[] =
- "Failed to push down offer transport description.";
-const char kPushDownPranswerTDFailed[] =
- "Failed to push down pranswer transport description.";
-const char kPushDownAnswerTDFailed[] =
- "Failed to push down answer transport description.";
+const char kSessionErrorDesc[] = "Session error description: ";
// Compares |answer| against |offer|. Comparision is done
// for number of m-lines in answer against offer. If matches true will be
@@ -108,6 +87,15 @@ static bool VerifyMediaDescriptions(
if ((offer->contents()[i].name) != answer->contents()[i].name) {
return false;
}
+ const MediaContentDescription* offer_mdesc =
+ static_cast<const MediaContentDescription*>(
+ offer->contents()[i].description);
+ const MediaContentDescription* answer_mdesc =
+ static_cast<const MediaContentDescription*>(
+ answer->contents()[i].description);
+ if (offer_mdesc->type() != answer_mdesc->type()) {
+ return false;
+ }
}
return true;
}
@@ -136,17 +124,18 @@ static bool VerifyCrypto(const SessionDescription* desc,
*error = kInvalidSdp;
return false;
}
- if (media->cryptos().empty()) {
+ if (dtls_enabled) {
if (!tinfo->description.identity_fingerprint) {
- // Crypto must be supplied.
- LOG(LS_WARNING) << "Session description must have SDES or DTLS-SRTP.";
- *error = kSdpWithoutCrypto;
+ LOG(LS_WARNING) <<
+ "Session description must have DTLS fingerprint if DTLS enabled.";
+ *error = kSdpWithoutDtlsFingerprint;
return false;
}
- if (!dtls_enabled) {
+ } else {
+ if (media->cryptos().empty()) {
LOG(LS_WARNING) <<
"Session description must have SDES when DTLS disabled.";
- *error = kSdpWithoutSdesAndDtlsDisabled;
+ *error = kSdpWithoutSdesCrypto;
return false;
}
}
@@ -184,9 +173,8 @@ static bool VerifyIceUfragPwdPresent(const SessionDescription* desc) {
// current security policy, to ensure a failure occurs if there is an error
// in crypto negotiation.
// Called when processing the local session description.
-static void UpdateSessionDescriptionSecurePolicy(
- cricket::SecureMediaPolicy secure_policy,
- SessionDescription* sdesc) {
+static void UpdateSessionDescriptionSecurePolicy(cricket::CryptoType type,
+ SessionDescription* sdesc) {
if (!sdesc) {
return;
}
@@ -199,7 +187,7 @@ static void UpdateSessionDescriptionSecurePolicy(
MediaContentDescription* mdesc =
static_cast<MediaContentDescription*> (iter->description);
if (mdesc) {
- mdesc->set_crypto_required(secure_policy == cricket::SEC_REQUIRED);
+ mdesc->set_crypto_required(type);
}
}
}
@@ -262,39 +250,60 @@ static bool GetTrackIdBySsrc(const SessionDescription* session_description,
return false;
}
-static bool BadSdp(const std::string& desc, std::string* err_desc) {
+static bool BadSdp(const std::string& source,
+ const std::string& type,
+ const std::string& reason,
+ std::string* err_desc) {
+ std::ostringstream desc;
+ desc << "Failed to set " << source << " " << type << " sdp: " << reason;
+
if (err_desc) {
- *err_desc = desc;
+ *err_desc = desc.str();
}
- LOG(LS_ERROR) << desc;
+ LOG(LS_ERROR) << desc.str();
return false;
}
-static bool BadLocalSdp(const std::string& desc, std::string* err_desc) {
- std::string set_local_sdp_failed = kSetLocalSdpFailed;
- set_local_sdp_failed.append(desc);
- return BadSdp(set_local_sdp_failed, err_desc);
-}
-
-static bool BadRemoteSdp(const std::string& desc, std::string* err_desc) {
- std::string set_remote_sdp_failed = kSetRemoteSdpFailed;
- set_remote_sdp_failed.append(desc);
- return BadSdp(set_remote_sdp_failed, err_desc);
-}
-
static bool BadSdp(cricket::ContentSource source,
- const std::string& desc, std::string* err_desc) {
+ const std::string& type,
+ const std::string& reason,
+ std::string* err_desc) {
if (source == cricket::CS_LOCAL) {
- return BadLocalSdp(desc, err_desc);
+ return BadSdp("local", type, reason, err_desc);
} else {
- return BadRemoteSdp(desc, err_desc);
+ return BadSdp("remote", type, reason, err_desc);
}
}
-static std::string SessionErrorMsg(cricket::BaseSession::Error error) {
- std::ostringstream desc;
- desc << kSessionError << error;
- return desc.str();
+static bool BadLocalSdp(const std::string& type,
+ const std::string& reason,
+ std::string* err_desc) {
+ return BadSdp(cricket::CS_LOCAL, type, reason, err_desc);
+}
+
+static bool BadRemoteSdp(const std::string& type,
+ const std::string& reason,
+ std::string* err_desc) {
+ return BadSdp(cricket::CS_REMOTE, type, reason, err_desc);
+}
+
+static bool BadOfferSdp(cricket::ContentSource source,
+ const std::string& reason,
+ std::string* err_desc) {
+ return BadSdp(source, SessionDescriptionInterface::kOffer, reason, err_desc);
+}
+
+static bool BadPranswerSdp(cricket::ContentSource source,
+ const std::string& reason,
+ std::string* err_desc) {
+ return BadSdp(source, SessionDescriptionInterface::kPrAnswer,
+ reason, err_desc);
+}
+
+static bool BadAnswerSdp(cricket::ContentSource source,
+ const std::string& reason,
+ std::string* err_desc) {
+ return BadSdp(source, SessionDescriptionInterface::kAnswer, reason, err_desc);
}
#define GET_STRING_OF_STATE(state) \
@@ -328,20 +337,20 @@ static std::string GetStateString(cricket::BaseSession::State state) {
return result;
}
-#define GET_STRING_OF_ERROR(err) \
+#define GET_STRING_OF_ERROR_CODE(err) \
case cricket::BaseSession::err: \
result = #err; \
break;
-static std::string GetErrorString(cricket::BaseSession::Error err) {
+static std::string GetErrorCodeString(cricket::BaseSession::Error err) {
std::string result;
switch (err) {
- GET_STRING_OF_ERROR(ERROR_NONE)
- GET_STRING_OF_ERROR(ERROR_TIME)
- GET_STRING_OF_ERROR(ERROR_RESPONSE)
- GET_STRING_OF_ERROR(ERROR_NETWORK)
- GET_STRING_OF_ERROR(ERROR_CONTENT)
- GET_STRING_OF_ERROR(ERROR_TRANSPORT)
+ GET_STRING_OF_ERROR_CODE(ERROR_NONE)
+ GET_STRING_OF_ERROR_CODE(ERROR_TIME)
+ GET_STRING_OF_ERROR_CODE(ERROR_RESPONSE)
+ GET_STRING_OF_ERROR_CODE(ERROR_NETWORK)
+ GET_STRING_OF_ERROR_CODE(ERROR_CONTENT)
+ GET_STRING_OF_ERROR_CODE(ERROR_TRANSPORT)
default:
ASSERT(false);
break;
@@ -349,12 +358,33 @@ static std::string GetErrorString(cricket::BaseSession::Error err) {
return result;
}
-static bool SetSessionStateFailed(cricket::ContentSource source,
- cricket::BaseSession::Error err,
- std::string* err_desc) {
- std::string set_state_err = kUpdateStateFailed;
- set_state_err.append(GetErrorString(err));
- return BadSdp(source, set_state_err, err_desc);
+static std::string MakeErrorString(const std::string& error,
+ const std::string& desc) {
+ std::ostringstream ret;
+ ret << error << " " << desc;
+ return ret.str();
+}
+
+static std::string MakeTdErrorString(const std::string& desc) {
+ return MakeErrorString(kPushDownTDFailed, desc);
+}
+
+// Set |option| to the highest-priority value of |key| in the optional
+// constraints if the key is found and has a valid value.
+template<typename T>
+static void SetOptionFromOptionalConstraint(
+ const MediaConstraintsInterface* constraints,
+ const std::string& key, cricket::Settable<T>* option) {
+ if (!constraints) {
+ return;
+ }
+ std::string string_value;
+ T value;
+ if (constraints->GetOptional().FindFirst(key, &string_value)) {
+ if (talk_base::FromString(string_value, &value)) {
+ option->Set(value);
+ }
+ }
}
// Help class used to remember if a a remote peer has requested ice restart by
@@ -432,7 +462,6 @@ WebRtcSession::WebRtcSession(
ice_connection_state_(PeerConnectionInterface::kIceConnectionNew),
older_version_remote_peer_(false),
dtls_enabled_(false),
- dscp_enabled_(false),
data_channel_type_(cricket::DCT_NONE),
ice_restart_latch_(new IceRestartAnswerLatch) {
}
@@ -458,21 +487,26 @@ WebRtcSession::~WebRtcSession() {
bool WebRtcSession::Initialize(
const PeerConnectionFactoryInterface::Options& options,
- const MediaConstraintsInterface* constraints,
- DTLSIdentityServiceInterface* dtls_identity_service) {
+ const MediaConstraintsInterface* constraints,
+ DTLSIdentityServiceInterface* dtls_identity_service,
+ PeerConnectionInterface::IceTransportsType ice_transport) {
// TODO(perkj): Take |constraints| into consideration. Return false if not all
// mandatory constraints can be fulfilled. Note that |constraints|
// can be null.
bool value;
- // Enable DTLS by default if |dtls_identity_service| is valid.
- dtls_enabled_ = (dtls_identity_service != NULL);
- // |constraints| can override the default |dtls_enabled_| value.
- if (FindConstraint(
- constraints,
- MediaConstraintsInterface::kEnableDtlsSrtp,
- &value, NULL)) {
- dtls_enabled_ = value;
+ if (options.disable_encryption) {
+ dtls_enabled_ = false;
+ } else {
+ // Enable DTLS by default if |dtls_identity_service| is valid.
+ dtls_enabled_ = (dtls_identity_service != NULL);
+ // |constraints| can override the default |dtls_enabled_| value.
+ if (FindConstraint(
+ constraints,
+ MediaConstraintsInterface::kEnableDtlsSrtp,
+ &value, NULL)) {
+ dtls_enabled_ = value;
+ }
}
// Enable creation of RTP data channels if the kEnableRtpDataChannels is set.
@@ -499,9 +533,92 @@ bool WebRtcSession::Initialize(
constraints,
MediaConstraintsInterface::kEnableDscp,
&value, NULL)) {
- dscp_enabled_ = value;
+ audio_options_.dscp.Set(value);
+ video_options_.dscp.Set(value);
+ }
+
+ // Find Suspend Below Min Bitrate constraint.
+ if (FindConstraint(
+ constraints,
+ MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate,
+ &value,
+ NULL)) {
+ video_options_.suspend_below_min_bitrate.Set(value);
}
+ if (FindConstraint(
+ constraints,
+ MediaConstraintsInterface::kSkipEncodingUnusedStreams,
+ &value,
+ NULL)) {
+ video_options_.skip_encoding_unused_streams.Set(value);
+ }
+
+ SetOptionFromOptionalConstraint(constraints,
+ MediaConstraintsInterface::kScreencastMinBitrate,
+ &video_options_.screencast_min_bitrate);
+
+ // Find constraints for cpu overuse detection.
+ SetOptionFromOptionalConstraint(constraints,
+ MediaConstraintsInterface::kCpuUnderuseThreshold,
+ &video_options_.cpu_underuse_threshold);
+ SetOptionFromOptionalConstraint(constraints,
+ MediaConstraintsInterface::kCpuOveruseThreshold,
+ &video_options_.cpu_overuse_threshold);
+ SetOptionFromOptionalConstraint(constraints,
+ MediaConstraintsInterface::kCpuOveruseDetection,
+ &video_options_.cpu_overuse_detection);
+ SetOptionFromOptionalConstraint(constraints,
+ MediaConstraintsInterface::kCpuOveruseEncodeUsage,
+ &video_options_.cpu_overuse_encode_usage);
+ SetOptionFromOptionalConstraint(constraints,
+ MediaConstraintsInterface::kCpuUnderuseEncodeRsdThreshold,
+ &video_options_.cpu_underuse_encode_rsd_threshold);
+ SetOptionFromOptionalConstraint(constraints,
+ MediaConstraintsInterface::kCpuOveruseEncodeRsdThreshold,
+ &video_options_.cpu_overuse_encode_rsd_threshold);
+
+ // Find payload padding constraint.
+ SetOptionFromOptionalConstraint(constraints,
+ MediaConstraintsInterface::kPayloadPadding,
+ &video_options_.use_payload_padding);
+
+ // Find improved wifi bwe constraint.
+ if (FindConstraint(
+ constraints,
+ MediaConstraintsInterface::kImprovedWifiBwe,
+ &value,
+ NULL)) {
+ video_options_.use_improved_wifi_bandwidth_estimator.Set(value);
+ } else {
+ // Enable by default if the constraint is not set.
+ video_options_.use_improved_wifi_bandwidth_estimator.Set(true);
+ }
+
+ SetOptionFromOptionalConstraint(constraints,
+ MediaConstraintsInterface::kHighStartBitrate,
+ &video_options_.video_start_bitrate);
+
+ if (FindConstraint(
+ constraints,
+ MediaConstraintsInterface::kVeryHighBitrate,
+ &value,
+ NULL)) {
+ video_options_.video_highest_bitrate.Set(
+ cricket::VideoOptions::VERY_HIGH);
+ } else if (FindConstraint(
+ constraints,
+ MediaConstraintsInterface::kHighBitrate,
+ &value,
+ NULL)) {
+ video_options_.video_highest_bitrate.Set(
+ cricket::VideoOptions::HIGH);
+ }
+
+ SetOptionFromOptionalConstraint(constraints,
+ MediaConstraintsInterface::kOpusFec,
+ &audio_options_.opus_fec);
+
const cricket::VideoCodec default_codec(
JsepSessionDescription::kDefaultVideoCodecId,
JsepSessionDescription::kDefaultVideoCodecName,
@@ -526,7 +643,7 @@ bool WebRtcSession::Initialize(
this, &WebRtcSession::OnIdentityReady);
if (options.disable_encryption) {
- webrtc_session_desc_factory_->SetSecure(cricket::SEC_DISABLED);
+ webrtc_session_desc_factory_->SetSdesPolicy(cricket::SEC_DISABLED);
}
return true;
@@ -554,13 +671,12 @@ bool WebRtcSession::StartCandidatesAllocation() {
return true;
}
-void WebRtcSession::SetSecurePolicy(
- cricket::SecureMediaPolicy secure_policy) {
- webrtc_session_desc_factory_->SetSecure(secure_policy);
+void WebRtcSession::SetSdesPolicy(cricket::SecurePolicy secure_policy) {
+ webrtc_session_desc_factory_->SetSdesPolicy(secure_policy);
}
-cricket::SecureMediaPolicy WebRtcSession::SecurePolicy() const {
- return webrtc_session_desc_factory_->Secure();
+cricket::SecurePolicy WebRtcSession::SdesPolicy() const {
+ return webrtc_session_desc_factory_->SdesPolicy();
}
bool WebRtcSession::GetSslRole(talk_base::SSLRole* role) {
@@ -609,10 +725,13 @@ bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc,
set_initiator(true);
}
- cricket::SecureMediaPolicy secure_policy =
- webrtc_session_desc_factory_->Secure();
+ cricket::SecurePolicy sdes_policy =
+ webrtc_session_desc_factory_->SdesPolicy();
+ cricket::CryptoType crypto_required = dtls_enabled_ ?
+ cricket::CT_DTLS : (sdes_policy == cricket::SEC_REQUIRED ?
+ cricket::CT_SDES : cricket::CT_NONE);
// Update the MediaContentDescription crypto settings as per the policy set.
- UpdateSessionDescriptionSecurePolicy(secure_policy, desc->description());
+ UpdateSessionDescriptionSecurePolicy(crypto_required, desc->description());
set_local_description(desc->description()->Copy());
local_desc_.reset(desc_temp.release());
@@ -621,15 +740,14 @@ bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc,
if (action == kOffer && !CreateChannels(local_desc_->description())) {
// TODO(mallinath) - Handle CreateChannel failure, as new local description
// is applied. Restore back to old description.
- return BadLocalSdp(kCreateChannelFailed, err_desc);
+ return BadLocalSdp(desc->type(), kCreateChannelFailed, err_desc);
}
// Remove channel and transport proxies, if MediaContentDescription is
// rejected.
RemoveUnusedChannelsAndTransports(local_desc_->description());
- if (!UpdateSessionState(action, cricket::CS_LOCAL,
- local_desc_->description(), err_desc)) {
+ if (!UpdateSessionState(action, cricket::CS_LOCAL, err_desc)) {
return false;
}
// Kick starting the ice candidates allocation.
@@ -644,7 +762,7 @@ bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc,
mediastream_signaling_->OnDtlsRoleReadyForSctp(role);
}
if (error() != cricket::BaseSession::ERROR_NONE) {
- return BadLocalSdp(SessionErrorMsg(error()), err_desc);
+ return BadLocalSdp(desc->type(), GetSessionErrorMsg(), err_desc);
}
return true;
}
@@ -664,7 +782,7 @@ bool WebRtcSession::SetRemoteDescription(SessionDescriptionInterface* desc,
if (action == kOffer && !CreateChannels(desc->description())) {
// TODO(mallinath) - Handle CreateChannel failure, as new local description
// is applied. Restore back to old description.
- return BadRemoteSdp(kCreateChannelFailed, err_desc);
+ return BadRemoteSdp(desc->type(), kCreateChannelFailed, err_desc);
}
// Remove channel and transport proxies, if MediaContentDescription is
@@ -674,15 +792,14 @@ bool WebRtcSession::SetRemoteDescription(SessionDescriptionInterface* desc,
// NOTE: Candidates allocation will be initiated only when SetLocalDescription
// is called.
set_remote_description(desc->description()->Copy());
- if (!UpdateSessionState(action, cricket::CS_REMOTE,
- desc->description(), err_desc)) {
+ if (!UpdateSessionState(action, cricket::CS_REMOTE, err_desc)) {
return false;
}
// Update remote MediaStreams.
mediastream_signaling_->OnRemoteDescriptionChanged(desc);
if (local_description() && !UseCandidatesInSessionDescription(desc)) {
- return BadRemoteSdp(kInvalidCandidates, err_desc);
+ return BadRemoteSdp(desc->type(), kInvalidCandidates, err_desc);
}
// Copy all saved candidates.
@@ -702,47 +819,47 @@ bool WebRtcSession::SetRemoteDescription(SessionDescriptionInterface* desc,
}
if (error() != cricket::BaseSession::ERROR_NONE) {
- return BadRemoteSdp(SessionErrorMsg(error()), err_desc);
+ return BadRemoteSdp(desc->type(), GetSessionErrorMsg(), err_desc);
}
return true;
}
bool WebRtcSession::UpdateSessionState(
Action action, cricket::ContentSource source,
- const cricket::SessionDescription* desc,
std::string* err_desc) {
// If there's already a pending error then no state transition should happen.
// But all call-sites should be verifying this before calling us!
ASSERT(error() == cricket::BaseSession::ERROR_NONE);
+ std::string td_err;
if (action == kOffer) {
- if (!PushdownTransportDescription(source, cricket::CA_OFFER)) {
- return BadSdp(source, kPushDownOfferTDFailed, err_desc);
+ if (!PushdownTransportDescription(source, cricket::CA_OFFER, &td_err)) {
+ return BadOfferSdp(source, MakeTdErrorString(td_err), err_desc);
}
SetState(source == cricket::CS_LOCAL ?
STATE_SENTINITIATE : STATE_RECEIVEDINITIATE);
if (error() != cricket::BaseSession::ERROR_NONE) {
- return SetSessionStateFailed(source, error(), err_desc);
+ return BadOfferSdp(source, GetSessionErrorMsg(), err_desc);
}
} else if (action == kPrAnswer) {
- if (!PushdownTransportDescription(source, cricket::CA_PRANSWER)) {
- return BadSdp(source, kPushDownPranswerTDFailed, err_desc);
+ if (!PushdownTransportDescription(source, cricket::CA_PRANSWER, &td_err)) {
+ return BadPranswerSdp(source, MakeTdErrorString(td_err), err_desc);
}
EnableChannels();
SetState(source == cricket::CS_LOCAL ?
STATE_SENTPRACCEPT : STATE_RECEIVEDPRACCEPT);
if (error() != cricket::BaseSession::ERROR_NONE) {
- return SetSessionStateFailed(source, error(), err_desc);
+ return BadPranswerSdp(source, GetSessionErrorMsg(), err_desc);
}
} else if (action == kAnswer) {
- if (!PushdownTransportDescription(source, cricket::CA_ANSWER)) {
- return BadSdp(source, kPushDownAnswerTDFailed, err_desc);
+ if (!PushdownTransportDescription(source, cricket::CA_ANSWER, &td_err)) {
+ return BadAnswerSdp(source, MakeTdErrorString(td_err), err_desc);
}
MaybeEnableMuxingSupport();
EnableChannels();
SetState(source == cricket::CS_LOCAL ?
STATE_SENTACCEPT : STATE_RECEIVEDACCEPT);
if (error() != cricket::BaseSession::ERROR_NONE) {
- return SetSessionStateFailed(source, error(), err_desc);
+ return BadAnswerSdp(source, GetSessionErrorMsg(), err_desc);
}
}
return true;
@@ -773,9 +890,32 @@ bool WebRtcSession::ProcessIceMessage(const IceCandidateInterface* candidate) {
return false;
}
- if (!local_description() || !remote_description()) {
- LOG(LS_INFO) << "ProcessIceMessage: Remote description not set, "
- << "save the candidate for later use.";
+ cricket::TransportProxy* transport_proxy = NULL;
+ if (remote_description()) {
+ size_t mediacontent_index =
+ static_cast<size_t>(candidate->sdp_mline_index());
+ size_t remote_content_size =
+ BaseSession::remote_description()->contents().size();
+ if (mediacontent_index >= remote_content_size) {
+ LOG(LS_ERROR)
+ << "ProcessIceMessage: Invalid candidate media index.";
+ return false;
+ }
+
+ cricket::ContentInfo content =
+ BaseSession::remote_description()->contents()[mediacontent_index];
+ transport_proxy = GetTransportProxy(content.name);
+ }
+
+ // We need to check the local/remote description for the Transport instead of
+ // the session, because a new Transport added during renegotiation may have
+ // them unset while the session has them set from the previou negotiation. Not
+ // doing so may trigger the auto generation of transport description and mess
+ // up DTLS identity information, ICE credential, etc.
+ if (!transport_proxy || !(transport_proxy->local_description_set() &&
+ transport_proxy->remote_description_set())) {
+ LOG(LS_INFO) << "ProcessIceMessage: Local/Remote description not set "
+ << "on the Transport, save the candidate for later use.";
saved_candidates_.push_back(
new JsepIceCandidate(candidate->sdp_mid(), candidate->sdp_mline_index(),
candidate->candidate()));
@@ -788,41 +928,30 @@ bool WebRtcSession::ProcessIceMessage(const IceCandidateInterface* candidate) {
return false;
}
- return UseCandidatesInSessionDescription(remote_desc_.get());
+ return UseCandidate(candidate);
}
-bool WebRtcSession::GetTrackIdBySsrc(uint32 ssrc, std::string* id) {
- if (GetLocalTrackId(ssrc, id)) {
- if (GetRemoteTrackId(ssrc, id)) {
- LOG(LS_WARNING) << "SSRC " << ssrc
- << " exists in both local and remote descriptions";
- return true; // We return the remote track id.
- }
- return true;
- } else {
- return GetRemoteTrackId(ssrc, id);
- }
+bool WebRtcSession::UpdateIce(PeerConnectionInterface::IceTransportsType type) {
+ return false;
}
-bool WebRtcSession::GetLocalTrackId(uint32 ssrc, std::string* track_id) {
+bool WebRtcSession::GetLocalTrackIdBySsrc(uint32 ssrc, std::string* track_id) {
if (!BaseSession::local_description())
return false;
return webrtc::GetTrackIdBySsrc(
- BaseSession::local_description(), ssrc, track_id);
+ BaseSession::local_description(), ssrc, track_id);
}
-bool WebRtcSession::GetRemoteTrackId(uint32 ssrc, std::string* track_id) {
+bool WebRtcSession::GetRemoteTrackIdBySsrc(uint32 ssrc, std::string* track_id) {
if (!BaseSession::remote_description())
- return false;
+ return false;
return webrtc::GetTrackIdBySsrc(
- BaseSession::remote_description(), ssrc, track_id);
+ BaseSession::remote_description(), ssrc, track_id);
}
-std::string WebRtcSession::BadStateErrMsg(
- const std::string& type, State state) {
+std::string WebRtcSession::BadStateErrMsg(State state) {
std::ostringstream desc;
- desc << "Called with type in wrong state, "
- << "type: " << type << " state: " << GetStateString(state);
+ desc << "Called in wrong state: " << GetStateString(state);
return desc.str();
}
@@ -870,6 +999,18 @@ void WebRtcSession::SetAudioSend(uint32 ssrc, bool enable,
voice_channel_->SetChannelOptions(options);
}
+void WebRtcSession::SetAudioPlayoutVolume(uint32 ssrc, double volume) {
+ ASSERT(signaling_thread()->IsCurrent());
+ ASSERT(volume >= 0 && volume <= 10);
+ if (!voice_channel_) {
+ LOG(LS_ERROR) << "SetAudioPlayoutVolume: No audio channel exists.";
+ return;
+ }
+
+ if (!voice_channel_->SetOutputScaling(ssrc, volume, volume))
+ ASSERT(false);
+}
+
bool WebRtcSession::SetCaptureDevice(uint32 ssrc,
cricket::VideoCapturer* camera) {
ASSERT(signaling_thread()->IsCurrent());
@@ -1007,6 +1148,8 @@ void WebRtcSession::AddSctpDataStream(uint32 sid) {
}
void WebRtcSession::RemoveSctpDataStream(uint32 sid) {
+ mediastream_signaling_->RemoveSctpDataChannel(static_cast<int>(sid));
+
if (!data_channel_.get()) {
LOG(LS_ERROR) << "RemoveDataChannelStreams called when data_channel_ is "
<< "NULL.";
@@ -1022,7 +1165,7 @@ bool WebRtcSession::ReadyToSendData() const {
talk_base::scoped_refptr<DataChannel> WebRtcSession::CreateDataChannel(
const std::string& label,
- const DataChannelInit* config) {
+ const InternalDataChannelInit* config) {
if (state() == STATE_RECEIVEDTERMINATE) {
return NULL;
}
@@ -1030,8 +1173,8 @@ talk_base::scoped_refptr<DataChannel> WebRtcSession::CreateDataChannel(
LOG(LS_ERROR) << "CreateDataChannel: Data is not supported in this call.";
return NULL;
}
- DataChannelInit new_config = config ? (*config) : DataChannelInit();
-
+ InternalDataChannelInit new_config =
+ config ? (*config) : InternalDataChannelInit();
if (data_channel_type_ == cricket::DCT_SCTP) {
if (new_config.id < 0) {
talk_base::SSLRole role;
@@ -1047,8 +1190,8 @@ talk_base::scoped_refptr<DataChannel> WebRtcSession::CreateDataChannel(
}
}
- talk_base::scoped_refptr<DataChannel> channel(
- DataChannel::Create(this, data_channel_type_, label, &new_config));
+ talk_base::scoped_refptr<DataChannel> channel(DataChannel::Create(
+ this, data_channel_type_, label, new_config));
if (channel && !mediastream_signaling_->AddDataChannel(channel))
return NULL;
@@ -1143,15 +1286,8 @@ void WebRtcSession::OnTransportConnecting(cricket::Transport* transport) {
void WebRtcSession::OnTransportWritable(cricket::Transport* transport) {
ASSERT(signaling_thread()->IsCurrent());
- // TODO(bemasc): Expose more API from Transport to detect when
- // candidate selection starts or stops, due to success or failure.
if (transport->all_channels_writable()) {
- if (ice_connection_state_ ==
- PeerConnectionInterface::kIceConnectionChecking ||
- ice_connection_state_ ==
- PeerConnectionInterface::kIceConnectionDisconnected) {
- SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
- }
+ SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
} else if (transport->HasChannels()) {
// If the current state is Connected or Completed, then there were writable
// channels but now there are not, so the next state must be Disconnected.
@@ -1165,6 +1301,16 @@ void WebRtcSession::OnTransportWritable(cricket::Transport* transport) {
}
}
+void WebRtcSession::OnTransportCompleted(cricket::Transport* transport) {
+ ASSERT(signaling_thread()->IsCurrent());
+ SetIceConnectionState(PeerConnectionInterface::kIceConnectionCompleted);
+}
+
+void WebRtcSession::OnTransportFailed(cricket::Transport* transport) {
+ ASSERT(signaling_thread()->IsCurrent());
+ SetIceConnectionState(PeerConnectionInterface::kIceConnectionFailed);
+}
+
void WebRtcSession::OnTransportProxyCandidatesReady(
cricket::TransportProxy* proxy, const cricket::Candidates& candidates) {
ASSERT(signaling_thread()->IsCurrent());
@@ -1284,7 +1430,9 @@ bool WebRtcSession::UseCandidate(
}
// TODO(bemasc): If state is Completed, go back to Connected.
} else {
- LOG(LS_WARNING) << error;
+ if (!error.empty()) {
+ LOG(LS_WARNING) << error;
+ }
}
return true;
}
@@ -1367,11 +1515,7 @@ bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content) {
if (!voice_channel_.get())
return false;
- if (dscp_enabled_) {
- cricket::AudioOptions options;
- options.dscp.Set(true);
- voice_channel_->SetChannelOptions(options);
- }
+ voice_channel_->SetChannelOptions(audio_options_);
return true;
}
@@ -1381,11 +1525,7 @@ bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content) {
if (!video_channel_.get())
return false;
- if (dscp_enabled_) {
- cricket::VideoOptions options;
- options.dscp.Set(true);
- video_channel_->SetChannelOptions(options);
- }
+ video_channel_->SetChannelOptions(video_options_);
return true;
}
@@ -1398,8 +1538,11 @@ bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content) {
}
if (sctp) {
mediastream_signaling_->OnDataTransportCreatedForSctp();
- data_channel_->SignalNewStreamReceived.connect(
- this, &WebRtcSession::OnNewDataChannelReceived);
+ data_channel_->SignalDataReceived.connect(
+ this, &WebRtcSession::OnDataChannelMessageReceived);
+ data_channel_->SignalStreamClosedRemotely.connect(
+ mediastream_signaling_,
+ &MediaStreamSignaling::OnRemoteSctpDataChannelClosed);
}
return true;
}
@@ -1417,14 +1560,17 @@ void WebRtcSession::CopySavedCandidates(
saved_candidates_.clear();
}
-void WebRtcSession::OnNewDataChannelReceived(
- const std::string& label, const DataChannelInit& init) {
+void WebRtcSession::OnDataChannelMessageReceived(
+ cricket::DataChannel* channel,
+ const cricket::ReceiveDataParams& params,
+ const talk_base::Buffer& payload) {
ASSERT(data_channel_type_ == cricket::DCT_SCTP);
- if (!mediastream_signaling_->AddDataChannelFromOpenMessage(
- label, init)) {
- LOG(LS_WARNING) << "Failed to create data channel from OPEN message.";
- return;
+ if (params.type == cricket::DMT_CONTROL &&
+ mediastream_signaling_->IsSctpSidAvailable(params.ssrc)) {
+ // Received CONTROL on unused sid, process as an OPEN message.
+ mediastream_signaling_->AddDataChannelFromOpenMessage(params, payload);
}
+ // otherwise ignore the message.
}
// Returns false if bundle is enabled and rtcp_mux is disabled.
@@ -1461,40 +1607,41 @@ bool WebRtcSession::HasRtcpMuxEnabled(
bool WebRtcSession::ValidateSessionDescription(
const SessionDescriptionInterface* sdesc,
- cricket::ContentSource source, std::string* error_desc) {
-
+ cricket::ContentSource source, std::string* err_desc) {
+ std::string type;
if (error() != cricket::BaseSession::ERROR_NONE) {
- return BadSdp(source, SessionErrorMsg(error()), error_desc);
+ return BadSdp(source, type, GetSessionErrorMsg(), err_desc);
}
if (!sdesc || !sdesc->description()) {
- return BadSdp(source, kInvalidSdp, error_desc);
+ return BadSdp(source, type, kInvalidSdp, err_desc);
}
- std::string type = sdesc->type();
+ type = sdesc->type();
Action action = GetAction(sdesc->type());
if (source == cricket::CS_LOCAL) {
if (!ExpectSetLocalDescription(action))
- return BadSdp(source, BadStateErrMsg(type, state()), error_desc);
+ return BadLocalSdp(type, BadStateErrMsg(state()), err_desc);
} else {
if (!ExpectSetRemoteDescription(action))
- return BadSdp(source, BadStateErrMsg(type, state()), error_desc);
+ return BadRemoteSdp(type, BadStateErrMsg(state()), err_desc);
}
// Verify crypto settings.
std::string crypto_error;
- if (webrtc_session_desc_factory_->Secure() == cricket::SEC_REQUIRED &&
+ if ((webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED ||
+ dtls_enabled_) &&
!VerifyCrypto(sdesc->description(), dtls_enabled_, &crypto_error)) {
- return BadSdp(source, crypto_error, error_desc);
+ return BadSdp(source, type, crypto_error, err_desc);
}
// Verify ice-ufrag and ice-pwd.
if (!VerifyIceUfragPwdPresent(sdesc->description())) {
- return BadSdp(source, kSdpWithoutIceUfragPwd, error_desc);
+ return BadSdp(source, type, kSdpWithoutIceUfragPwd, err_desc);
}
if (!ValidateBundleSettings(sdesc->description())) {
- return BadSdp(source, kBundleWithoutRtcpMux, error_desc);
+ return BadSdp(source, type, kBundleWithoutRtcpMux, err_desc);
}
// Verify m-lines in Answer when compared against Offer.
@@ -1503,7 +1650,7 @@ bool WebRtcSession::ValidateSessionDescription(
(source == cricket::CS_LOCAL) ? remote_description()->description() :
local_description()->description();
if (!VerifyMediaDescriptions(sdesc->description(), offer_desc)) {
- return BadSdp(source, kMlineMismatch, error_desc);
+ return BadAnswerSdp(source, kMlineMismatch, err_desc);
}
}
@@ -1540,4 +1687,11 @@ bool WebRtcSession::ExpectSetRemoteDescription(Action action) {
(action == kPrAnswer && state() == STATE_RECEIVEDPRACCEPT));
}
+std::string WebRtcSession::GetSessionErrorMsg() {
+ std::ostringstream desc;
+ desc << kSessionError << GetErrorCodeString(error()) << ". ";
+ desc << kSessionErrorDesc << error_desc() << ".";
+ return desc.str();
+}
+
} // namespace webrtc
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession.h b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession.h
index 4c83906ae98..3ffea8ffac5 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession.h
@@ -42,6 +42,7 @@
#include "talk/session/media/mediasession.h"
namespace cricket {
+
class BaseChannel;
class ChannelManager;
class DataChannel;
@@ -50,28 +51,28 @@ class Transport;
class VideoCapturer;
class VideoChannel;
class VoiceChannel;
+
} // namespace cricket
namespace webrtc {
+
class IceRestartAnswerLatch;
+class JsepIceCandidate;
class MediaStreamSignaling;
class WebRtcSessionDescriptionFactory;
-extern const char kSetLocalSdpFailed[];
-extern const char kSetRemoteSdpFailed[];
-extern const char kCreateChannelFailed[];
extern const char kBundleWithoutRtcpMux[];
+extern const char kCreateChannelFailed[];
extern const char kInvalidCandidates[];
extern const char kInvalidSdp[];
extern const char kMlineMismatch[];
-extern const char kSdpWithoutCrypto[];
-extern const char kSdpWithoutSdesAndDtlsDisabled[];
+extern const char kPushDownTDFailed[];
+extern const char kSdpWithoutDtlsFingerprint[];
+extern const char kSdpWithoutSdesCrypto[];
extern const char kSdpWithoutIceUfragPwd[];
+extern const char kSdpWithoutSdesAndDtlsDisabled[];
extern const char kSessionError[];
-extern const char kUpdateStateFailed[];
-extern const char kPushDownOfferTDFailed[];
-extern const char kPushDownPranswerTDFailed[];
-extern const char kPushDownAnswerTDFailed[];
+extern const char kSessionErrorDesc[];
// ICE state callback interface.
class IceObserver {
@@ -113,7 +114,8 @@ class WebRtcSession : public cricket::BaseSession,
bool Initialize(const PeerConnectionFactoryInterface::Options& options,
const MediaConstraintsInterface* constraints,
- DTLSIdentityServiceInterface* dtls_identity_service);
+ DTLSIdentityServiceInterface* dtls_identity_service,
+ PeerConnectionInterface::IceTransportsType ice_transport);
// Deletes the voice, video and data channel and changes the session state
// to STATE_RECEIVEDTERMINATE.
void Terminate();
@@ -132,8 +134,8 @@ class WebRtcSession : public cricket::BaseSession,
return data_channel_.get();
}
- void SetSecurePolicy(cricket::SecureMediaPolicy secure_policy);
- cricket::SecureMediaPolicy SecurePolicy() const;
+ void SetSdesPolicy(cricket::SecurePolicy secure_policy);
+ cricket::SecurePolicy SdesPolicy() const;
// Get current ssl role from transport.
bool GetSslRole(talk_base::SSLRole* role);
@@ -153,6 +155,9 @@ class WebRtcSession : public cricket::BaseSession,
bool SetRemoteDescription(SessionDescriptionInterface* desc,
std::string* err_desc);
bool ProcessIceMessage(const IceCandidateInterface* ice_candidate);
+
+ bool UpdateIce(PeerConnectionInterface::IceTransportsType type);
+
const SessionDescriptionInterface* local_description() const {
return local_desc_.get();
}
@@ -161,7 +166,9 @@ class WebRtcSession : public cricket::BaseSession,
}
// Get the id used as a media stream track's "id" field from ssrc.
- virtual bool GetTrackIdBySsrc(uint32 ssrc, std::string* id);
+ virtual bool GetLocalTrackIdBySsrc(uint32 ssrc, std::string* track_id);
+ virtual bool GetRemoteTrackIdBySsrc(uint32 ssrc, std::string* track_id);
+
// AudioMediaProviderInterface implementation.
virtual void SetAudioPlayout(uint32 ssrc, bool enable,
@@ -169,6 +176,7 @@ class WebRtcSession : public cricket::BaseSession,
virtual void SetAudioSend(uint32 ssrc, bool enable,
const cricket::AudioOptions& options,
cricket::AudioRenderer* renderer) OVERRIDE;
+ virtual void SetAudioPlayoutVolume(uint32 ssrc, double volume) OVERRIDE;
// Implements VideoMediaProviderInterface.
virtual bool SetCaptureDevice(uint32 ssrc,
@@ -195,9 +203,10 @@ class WebRtcSession : public cricket::BaseSession,
virtual void RemoveSctpDataStream(uint32 sid) OVERRIDE;
virtual bool ReadyToSendData() const OVERRIDE;
+ // Implements DataChannelFactory.
talk_base::scoped_refptr<DataChannel> CreateDataChannel(
const std::string& label,
- const DataChannelInit* config);
+ const InternalDataChannelInit* config) OVERRIDE;
cricket::DataChannelType data_channel_type() const;
@@ -225,7 +234,6 @@ class WebRtcSession : public cricket::BaseSession,
// candidates allocation.
bool StartCandidatesAllocation();
bool UpdateSessionState(Action action, cricket::ContentSource source,
- const cricket::SessionDescription* desc,
std::string* err_desc);
static Action GetAction(const std::string& type);
@@ -233,6 +241,8 @@ class WebRtcSession : public cricket::BaseSession,
virtual void OnTransportRequestSignaling(cricket::Transport* transport);
virtual void OnTransportConnecting(cricket::Transport* transport);
virtual void OnTransportWritable(cricket::Transport* transport);
+ virtual void OnTransportCompleted(cricket::Transport* transport);
+ virtual void OnTransportFailed(cricket::Transport* transport);
virtual void OnTransportProxyCandidatesReady(
cricket::TransportProxy* proxy,
const cricket::Candidates& candidates);
@@ -275,13 +285,13 @@ class WebRtcSession : public cricket::BaseSession,
// The |saved_candidates_| will be cleared after this function call.
void CopySavedCandidates(SessionDescriptionInterface* dest_desc);
- void OnNewDataChannelReceived(const std::string& label,
- const DataChannelInit& init);
+ // Listens to SCTP CONTROL messages on unused SIDs and process them as OPEN
+ // messages.
+ void OnDataChannelMessageReceived(cricket::DataChannel* channel,
+ const cricket::ReceiveDataParams& params,
+ const talk_base::Buffer& payload);
- bool GetLocalTrackId(uint32 ssrc, std::string* track_id);
- bool GetRemoteTrackId(uint32 ssrc, std::string* track_id);
-
- std::string BadStateErrMsg(const std::string& type, State state);
+ std::string BadStateErrMsg(State state);
void SetIceConnectionState(PeerConnectionInterface::IceConnectionState state);
bool ValidateBundleSettings(const cricket::SessionDescription* desc);
@@ -289,7 +299,7 @@ class WebRtcSession : public cricket::BaseSession,
// Below methods are helper methods which verifies SDP.
bool ValidateSessionDescription(const SessionDescriptionInterface* sdesc,
cricket::ContentSource source,
- std::string* error_desc);
+ std::string* err_desc);
// Check if a call to SetLocalDescription is acceptable with |action|.
bool ExpectSetLocalDescription(Action action);
@@ -299,6 +309,8 @@ class WebRtcSession : public cricket::BaseSession,
bool ValidateDtlsSetupAttribute(const cricket::SessionDescription* desc,
Action action);
+ std::string GetSessionErrorMsg();
+
talk_base::scoped_ptr<cricket::VoiceChannel> voice_channel_;
talk_base::scoped_ptr<cricket::VideoChannel> video_channel_;
talk_base::scoped_ptr<cricket::DataChannel> data_channel_;
@@ -313,8 +325,6 @@ class WebRtcSession : public cricket::BaseSession,
// If the remote peer is using a older version of implementation.
bool older_version_remote_peer_;
bool dtls_enabled_;
- // Flag will be set based on the constraint value.
- bool dscp_enabled_;
// Specifies which kind of data channel is allowed. This is controlled
// by the chrome command-line flag and constraints:
// 1. If chrome command-line switch 'enable-sctp-data-channels' is enabled,
@@ -332,6 +342,10 @@ class WebRtcSession : public cricket::BaseSession,
sigslot::signal0<> SignalVideoChannelDestroyed;
sigslot::signal0<> SignalDataChannelDestroyed;
+ // Member variables for caching global options.
+ cricket::AudioOptions audio_options_;
+ cricket::VideoOptions video_options_;
+
DISALLOW_COPY_AND_ASSIGN(WebRtcSession);
};
} // namespace webrtc
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession_unittest.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession_unittest.cc
index 5ec880a1db2..956f8a66fb2 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsession_unittest.cc
@@ -53,6 +53,7 @@
#include "talk/media/devices/fakedevicemanager.h"
#include "talk/p2p/base/stunserver.h"
#include "talk/p2p/base/teststunserver.h"
+#include "talk/p2p/base/testturnserver.h"
#include "talk/p2p/client/basicportallocator.h"
#include "talk/session/media/channelmanager.h"
#include "talk/session/media/mediasession.h"
@@ -72,6 +73,7 @@ using cricket::NS_JINGLE_ICE_UDP;
using cricket::TransportInfo;
using talk_base::SocketAddress;
using talk_base::scoped_ptr;
+using talk_base::Thread;
using webrtc::CreateSessionDescription;
using webrtc::CreateSessionDescriptionObserver;
using webrtc::CreateSessionDescriptionRequest;
@@ -87,20 +89,22 @@ using webrtc::SessionDescriptionInterface;
using webrtc::StreamCollection;
using webrtc::WebRtcSession;
using webrtc::kBundleWithoutRtcpMux;
+using webrtc::kCreateChannelFailed;
+using webrtc::kInvalidSdp;
using webrtc::kMlineMismatch;
-using webrtc::kPushDownAnswerTDFailed;
-using webrtc::kPushDownPranswerTDFailed;
-using webrtc::kSdpWithoutCrypto;
+using webrtc::kPushDownTDFailed;
using webrtc::kSdpWithoutIceUfragPwd;
-using webrtc::kSdpWithoutSdesAndDtlsDisabled;
+using webrtc::kSdpWithoutDtlsFingerprint;
+using webrtc::kSdpWithoutSdesCrypto;
using webrtc::kSessionError;
-using webrtc::kSetLocalSdpFailed;
-using webrtc::kSetRemoteSdpFailed;
+using webrtc::kSessionErrorDesc;
static const int kClientAddrPort = 0;
static const char kClientAddrHost1[] = "11.11.11.11";
static const char kClientAddrHost2[] = "22.22.22.22";
static const char kStunAddrHost[] = "99.99.99.1";
+static const SocketAddress kTurnUdpIntAddr("99.99.99.4", 3478);
+static const SocketAddress kTurnUdpExtAddr("99.99.99.6", 0);
static const char kSessionVersion[] = "1";
@@ -118,6 +122,12 @@ static const char kFakeDtlsFingerprint[] =
"BB:CD:72:F7:2F:D0:BA:43:F3:68:B1:0C:23:72:B6:4A:"
"0F:DE:34:06:BC:E0:FE:01:BC:73:C8:6D:F4:65:D5:24";
+static const char kTooLongIceUfragPwd[] =
+ "IceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfrag"
+ "IceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfrag"
+ "IceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfrag"
+ "IceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfrag";
+
// Add some extra |newlines| to the |message| after |line|.
static void InjectAfter(const std::string& line,
const std::string& newlines,
@@ -249,7 +259,11 @@ class WebRtcSessionCreateSDPObserverForTest
class FakeAudioRenderer : public cricket::AudioRenderer {
public:
- FakeAudioRenderer() : channel_id_(-1) {}
+ FakeAudioRenderer() : channel_id_(-1), sink_(NULL) {}
+ virtual ~FakeAudioRenderer() {
+ if (sink_)
+ sink_->OnClose();
+ }
virtual void AddChannel(int channel_id) OVERRIDE {
ASSERT(channel_id_ == -1);
@@ -259,10 +273,15 @@ class FakeAudioRenderer : public cricket::AudioRenderer {
ASSERT(channel_id == channel_id_);
channel_id_ = -1;
}
+ virtual void SetSink(Sink* sink) OVERRIDE {
+ sink_ = sink;
+ }
int channel_id() const { return channel_id_; }
+ cricket::AudioRenderer::Sink* sink() const { return sink_; }
private:
int channel_id_;
+ cricket::AudioRenderer::Sink* sink_;
};
class WebRtcSessionTest : public testing::Test {
@@ -285,16 +304,20 @@ class WebRtcSessionTest : public testing::Test {
ss_scope_(fss_.get()),
stun_socket_addr_(talk_base::SocketAddress(kStunAddrHost,
cricket::STUN_SERVER_PORT)),
- stun_server_(talk_base::Thread::Current(), stun_socket_addr_),
- allocator_(&network_manager_, stun_socket_addr_,
- SocketAddress(), SocketAddress(), SocketAddress()),
- mediastream_signaling_(channel_manager_.get()) {
+ stun_server_(Thread::Current(), stun_socket_addr_),
+ turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr),
+ allocator_(new cricket::BasicPortAllocator(
+ &network_manager_, stun_socket_addr_,
+ SocketAddress(), SocketAddress(), SocketAddress())),
+ mediastream_signaling_(channel_manager_.get()),
+ ice_type_(PeerConnectionInterface::kAll) {
tdesc_factory_->set_protocol(cricket::ICEPROTO_HYBRID);
- allocator_.set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
+ allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
cricket::PORTALLOCATOR_DISABLE_RELAY |
cricket::PORTALLOCATOR_ENABLE_BUNDLE);
EXPECT_TRUE(channel_manager_->Init());
desc_factory_->set_add_legacy_streams(false);
+ allocator_->set_step_delay(cricket::kMinimumStepDelay);
}
static void SetUpTestCase() {
@@ -309,11 +332,15 @@ class WebRtcSessionTest : public testing::Test {
network_manager_.AddInterface(addr);
}
+ void SetIceTransportType(PeerConnectionInterface::IceTransportsType type) {
+ ice_type_ = type;
+ }
+
void Init(DTLSIdentityServiceInterface* identity_service) {
ASSERT_TRUE(session_.get() == NULL);
session_.reset(new WebRtcSessionForTest(
channel_manager_.get(), talk_base::Thread::Current(),
- talk_base::Thread::Current(), &allocator_,
+ talk_base::Thread::Current(), allocator_.get(),
&observer_,
&mediastream_signaling_));
@@ -323,7 +350,7 @@ class WebRtcSessionTest : public testing::Test {
observer_.ice_gathering_state_);
EXPECT_TRUE(session_->Initialize(options_, constraints_.get(),
- identity_service));
+ identity_service, ice_type_));
}
void InitWithDtmfCodec() {
@@ -449,7 +476,7 @@ class WebRtcSessionTest : public testing::Test {
// Set the internal fake description factories to do DTLS-SRTP.
void SetFactoryDtlsSrtp() {
- desc_factory_->set_secure(cricket::SEC_ENABLED);
+ desc_factory_->set_secure(cricket::SEC_DISABLED);
std::string identity_name = "WebRTC" +
talk_base::ToString(talk_base::CreateRandomId());
identity_.reset(talk_base::SSLIdentity::Generate(identity_name));
@@ -475,8 +502,8 @@ class WebRtcSessionTest : public testing::Test {
CreateRemoteOffer(options, cricket::SEC_DISABLED));
ASSERT_TRUE(offer != NULL);
VerifyNoCryptoParams(offer->description(), false);
- SetRemoteDescriptionExpectError("Called with a SDP without crypto enabled",
- offer);
+ SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto,
+ offer);
const webrtc::SessionDescriptionInterface* answer = CreateAnswer(NULL);
// Answer should be NULL as no crypto params in offer.
ASSERT_TRUE(answer == NULL);
@@ -549,6 +576,35 @@ class WebRtcSessionTest : public testing::Test {
}
}
+ void ModifyIceUfragPwdLines(const SessionDescriptionInterface* current_desc,
+ const std::string& modified_ice_ufrag,
+ const std::string& modified_ice_pwd,
+ std::string* sdp) {
+ const cricket::SessionDescription* desc = current_desc->description();
+ EXPECT_TRUE(current_desc->ToString(sdp));
+
+ const cricket::ContentInfos& contents = desc->contents();
+ cricket::ContentInfos::const_iterator it = contents.begin();
+ // Replace ufrag and pwd lines with |modified_ice_ufrag| and
+ // |modified_ice_pwd| strings.
+ for (; it != contents.end(); ++it) {
+ const cricket::TransportDescription* transport_desc =
+ desc->GetTransportDescriptionByName(it->name);
+ std::string ufrag_line = "a=ice-ufrag:" + transport_desc->ice_ufrag
+ + "\r\n";
+ std::string pwd_line = "a=ice-pwd:" + transport_desc->ice_pwd
+ + "\r\n";
+ std::string mod_ufrag = "a=ice-ufrag:" + modified_ice_ufrag + "\r\n";
+ std::string mod_pwd = "a=ice-pwd:" + modified_ice_pwd + "\r\n";
+ talk_base::replace_substrs(ufrag_line.c_str(), ufrag_line.length(),
+ mod_ufrag.c_str(), mod_ufrag.length(),
+ sdp);
+ talk_base::replace_substrs(pwd_line.c_str(), pwd_line.length(),
+ mod_pwd.c_str(), mod_pwd.length(),
+ sdp);
+ }
+ }
+
// Creates a remote offer and and applies it as a remote description,
// creates a local answer and applies is as a local description.
// Call mediastream_signaling_.UseOptionsWithStreamX() before this function
@@ -567,13 +623,26 @@ class WebRtcSessionTest : public testing::Test {
SetLocalDescriptionWithoutError(desc);
EXPECT_EQ(expected_state, session_->state());
}
- void SetLocalDescriptionExpectError(const std::string& expected_error,
+ void SetLocalDescriptionExpectError(const std::string& action,
+ const std::string& expected_error,
SessionDescriptionInterface* desc) {
std::string error;
EXPECT_FALSE(session_->SetLocalDescription(desc, &error));
- EXPECT_NE(std::string::npos, error.find(kSetLocalSdpFailed));
+ std::string sdp_type = "local ";
+ sdp_type.append(action);
+ EXPECT_NE(std::string::npos, error.find(sdp_type));
EXPECT_NE(std::string::npos, error.find(expected_error));
}
+ void SetLocalDescriptionOfferExpectError(const std::string& expected_error,
+ SessionDescriptionInterface* desc) {
+ SetLocalDescriptionExpectError(SessionDescriptionInterface::kOffer,
+ expected_error, desc);
+ }
+ void SetLocalDescriptionAnswerExpectError(const std::string& expected_error,
+ SessionDescriptionInterface* desc) {
+ SetLocalDescriptionExpectError(SessionDescriptionInterface::kAnswer,
+ expected_error, desc);
+ }
void SetRemoteDescriptionWithoutError(SessionDescriptionInterface* desc) {
EXPECT_TRUE(session_->SetRemoteDescription(desc, NULL));
}
@@ -582,13 +651,31 @@ class WebRtcSessionTest : public testing::Test {
SetRemoteDescriptionWithoutError(desc);
EXPECT_EQ(expected_state, session_->state());
}
- void SetRemoteDescriptionExpectError(const std::string& expected_error,
+ void SetRemoteDescriptionExpectError(const std::string& action,
+ const std::string& expected_error,
SessionDescriptionInterface* desc) {
std::string error;
EXPECT_FALSE(session_->SetRemoteDescription(desc, &error));
- EXPECT_NE(std::string::npos, error.find(kSetRemoteSdpFailed));
+ std::string sdp_type = "remote ";
+ sdp_type.append(action);
+ EXPECT_NE(std::string::npos, error.find(sdp_type));
EXPECT_NE(std::string::npos, error.find(expected_error));
}
+ void SetRemoteDescriptionOfferExpectError(
+ const std::string& expected_error, SessionDescriptionInterface* desc) {
+ SetRemoteDescriptionExpectError(SessionDescriptionInterface::kOffer,
+ expected_error, desc);
+ }
+ void SetRemoteDescriptionPranswerExpectError(
+ const std::string& expected_error, SessionDescriptionInterface* desc) {
+ SetRemoteDescriptionExpectError(SessionDescriptionInterface::kPrAnswer,
+ expected_error, desc);
+ }
+ void SetRemoteDescriptionAnswerExpectError(
+ const std::string& expected_error, SessionDescriptionInterface* desc) {
+ SetRemoteDescriptionExpectError(SessionDescriptionInterface::kAnswer,
+ expected_error, desc);
+ }
void CreateCryptoOfferAndNonCryptoAnswer(SessionDescriptionInterface** offer,
SessionDescriptionInterface** nocrypto_answer) {
@@ -605,6 +692,28 @@ class WebRtcSessionTest : public testing::Test {
EXPECT_TRUE(*nocrypto_answer != NULL);
}
+ void CreateDtlsOfferAndNonDtlsAnswer(SessionDescriptionInterface** offer,
+ SessionDescriptionInterface** nodtls_answer) {
+ cricket::MediaSessionOptions options;
+ options.has_video = true;
+ options.bundle_enabled = true;
+
+ talk_base::scoped_ptr<SessionDescriptionInterface> temp_offer(
+ CreateRemoteOffer(options, cricket::SEC_ENABLED));
+
+ *nodtls_answer =
+ CreateRemoteAnswer(temp_offer.get(), options, cricket::SEC_ENABLED);
+ EXPECT_TRUE(*nodtls_answer != NULL);
+ VerifyFingerprintStatus((*nodtls_answer)->description(), false);
+ VerifyCryptoParams((*nodtls_answer)->description());
+
+ SetFactoryDtlsSrtp();
+ *offer = CreateRemoteOffer(options, cricket::SEC_ENABLED);
+ ASSERT_TRUE(*offer != NULL);
+ VerifyFingerprintStatus((*offer)->description(), true);
+ VerifyCryptoParams((*offer)->description());
+ }
+
JsepSessionDescription* CreateRemoteOfferWithVersion(
cricket::MediaSessionOptions options,
cricket::SecurePolicy secure_policy,
@@ -633,8 +742,9 @@ class WebRtcSessionTest : public testing::Test {
kSessionVersion, NULL);
}
JsepSessionDescription* CreateRemoteOffer(
- cricket::MediaSessionOptions options, cricket::SecurePolicy policy) {
- return CreateRemoteOfferWithVersion(options, policy, kSessionVersion, NULL);
+ cricket::MediaSessionOptions options, cricket::SecurePolicy sdes_policy) {
+ return CreateRemoteOfferWithVersion(
+ options, sdes_policy, kSessionVersion, NULL);
}
JsepSessionDescription* CreateRemoteOffer(
cricket::MediaSessionOptions options,
@@ -777,13 +887,15 @@ class WebRtcSessionTest : public testing::Test {
// The method sets up a call from the session to itself, in a loopback
// arrangement. It also uses a firewall rule to create a temporary
- // disconnection. This code is placed as a method so that it can be invoked
+ // disconnection, and then a permanent disconnection.
+ // This code is placed in a method so that it can be invoked
// by multiple tests with different allocators (e.g. with and without BUNDLE).
// While running the call, this method also checks if the session goes through
// the correct sequence of ICE states when a connection is established,
// broken, and re-established.
// The Connection state should go:
- // New -> Checking -> Connected -> Disconnected -> Connected.
+ // New -> Checking -> (Connected) -> Completed -> Disconnected -> Completed
+ // -> Failed.
// The Gathering state should go: New -> Gathering -> Completed.
void TestLoopbackCall() {
AddInterface(talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
@@ -814,10 +926,11 @@ class WebRtcSessionTest : public testing::Test {
EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking,
observer_.ice_connection_state_,
kIceCandidatesTimeout);
- EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
+
+ // The ice connection state is "Connected" too briefly to catch in a test.
+ EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
observer_.ice_connection_state_,
kIceCandidatesTimeout);
- // TODO(bemasc): EXPECT(Completed) once the details are standardized.
// Adding firewall rule to block ping requests, which should cause
// transport channel failure.
@@ -834,10 +947,21 @@ class WebRtcSessionTest : public testing::Test {
// Session is automatically calling OnSignalingReady after creation of
// new portallocator session which will allocate new set of candidates.
- // TODO(bemasc): Change this to Completed once the details are standardized.
- EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionConnected,
+ EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
observer_.ice_connection_state_,
kIceCandidatesTimeout);
+
+ // Now we block ping requests and wait until the ICE connection transitions
+ // to the Failed state. This will take at least 30 seconds because it must
+ // wait for the Port to timeout.
+ int port_timeout = 30000;
+ fss_->AddRule(false,
+ talk_base::FP_ANY,
+ talk_base::FD_ANY,
+ talk_base::SocketAddress(kClientAddrHost1, kClientAddrPort));
+ EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionFailed,
+ observer_.ice_connection_state_,
+ kIceCandidatesTimeout + port_timeout);
}
void VerifyTransportType(const std::string& content_name,
@@ -874,7 +998,7 @@ class WebRtcSessionTest : public testing::Test {
}
void SetLocalDescriptionWithDataChannel() {
- webrtc::DataChannelInit dci;
+ webrtc::InternalDataChannelInit dci;
dci.reliable = false;
session_->CreateDataChannel("datachannel", &dci);
SessionDescriptionInterface* offer = CreateOffer(NULL);
@@ -884,11 +1008,11 @@ class WebRtcSessionTest : public testing::Test {
void VerifyMultipleAsyncCreateDescription(
bool success, CreateSessionDescriptionRequest::Type type) {
InitWithDtls(!success);
-
+ SetFactoryDtlsSrtp();
if (type == CreateSessionDescriptionRequest::kAnswer) {
cricket::MediaSessionOptions options;
scoped_ptr<JsepSessionDescription> offer(
- CreateRemoteOffer(options, cricket::SEC_REQUIRED));
+ CreateRemoteOffer(options, cricket::SEC_DISABLED));
ASSERT_TRUE(offer.get() != NULL);
SetRemoteDescriptionWithoutError(offer.release());
}
@@ -932,8 +1056,9 @@ class WebRtcSessionTest : public testing::Test {
talk_base::SocketServerScope ss_scope_;
talk_base::SocketAddress stun_socket_addr_;
cricket::TestStunServer stun_server_;
+ cricket::TestTurnServer turn_server_;
talk_base::FakeNetworkManager network_manager_;
- cricket::BasicPortAllocator allocator_;
+ talk_base::scoped_ptr<cricket::BasicPortAllocator> allocator_;
PeerConnectionFactoryInterface::Options options_;
talk_base::scoped_ptr<FakeConstraints> constraints_;
FakeMediaStreamSignaling mediastream_signaling_;
@@ -941,20 +1066,19 @@ class WebRtcSessionTest : public testing::Test {
MockIceObserver observer_;
cricket::FakeVideoMediaChannel* video_channel_;
cricket::FakeVoiceMediaChannel* voice_channel_;
+ PeerConnectionInterface::IceTransportsType ice_type_;
};
-TEST_F(WebRtcSessionTest, TestInitialize) {
- Init(NULL);
-}
-
TEST_F(WebRtcSessionTest, TestInitializeWithDtls) {
InitWithDtls();
+ // SDES is disabled when DTLS is on.
+ EXPECT_EQ(cricket::SEC_DISABLED, session_->SdesPolicy());
}
-// Verifies that WebRtcSession uses SEC_REQUIRED by default.
-TEST_F(WebRtcSessionTest, TestDefaultSetSecurePolicy) {
+TEST_F(WebRtcSessionTest, TestInitializeWithoutDtls) {
Init(NULL);
- EXPECT_EQ(cricket::SEC_REQUIRED, session_->SecurePolicy());
+ // SDES is required if DTLS is off.
+ EXPECT_EQ(cricket::SEC_REQUIRED, session_->SdesPolicy());
}
TEST_F(WebRtcSessionTest, TestSessionCandidates) {
@@ -998,9 +1122,18 @@ TEST_F(WebRtcSessionTest, TestStunError) {
EXPECT_EQ(6u, observer_.mline_1_candidates_.size());
}
+TEST_F(WebRtcSessionTest, SetSdpFailedOnInvalidSdp) {
+ Init(NULL);
+ SessionDescriptionInterface* offer = NULL;
+ // Since |offer| is NULL, there's no way to tell if it's an offer or answer.
+ std::string unknown_action;
+ SetLocalDescriptionExpectError(unknown_action, kInvalidSdp, offer);
+ SetRemoteDescriptionExpectError(unknown_action, kInvalidSdp, offer);
+}
+
// Test creating offers and receive answers and make sure the
// media engine creates the expected send and receive streams.
-TEST_F(WebRtcSessionTest, TestCreateOfferReceiveAnswer) {
+TEST_F(WebRtcSessionTest, TestCreateSdesOfferReceiveSdesAnswer) {
Init(NULL);
mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer(NULL);
@@ -1055,14 +1188,16 @@ TEST_F(WebRtcSessionTest, TestCreateOfferReceiveAnswer) {
// Test receiving offers and creating answers and make sure the
// media engine creates the expected send and receive streams.
-TEST_F(WebRtcSessionTest, TestReceiveOfferCreateAnswer) {
+TEST_F(WebRtcSessionTest, TestReceiveSdesOfferCreateSdesAnswer) {
Init(NULL);
mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* offer = CreateOffer(NULL);
+ VerifyCryptoParams(offer->description());
SetRemoteDescriptionWithoutError(offer);
mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* answer = CreateAnswer(NULL);
+ VerifyCryptoParams(answer->description());
SetLocalDescriptionWithoutError(answer);
const std::string session_id_orig = answer->session_id();
@@ -1109,9 +1244,53 @@ TEST_F(WebRtcSessionTest, TestReceiveOfferCreateAnswer) {
EXPECT_EQ(0u, voice_channel_->send_streams().size());
}
-// Test we will return fail when apply an offer that doesn't have
-// crypto enabled.
-TEST_F(WebRtcSessionTest, SetNonCryptoOffer) {
+TEST_F(WebRtcSessionTest, SetLocalSdpFailedOnCreateChannel) {
+ Init(NULL);
+ media_engine_->set_fail_create_channel(true);
+
+ SessionDescriptionInterface* offer = CreateOffer(NULL);
+ ASSERT_TRUE(offer != NULL);
+ // SetRemoteDescription and SetLocalDescription will take the ownership of
+ // the offer.
+ SetRemoteDescriptionOfferExpectError(kCreateChannelFailed, offer);
+ offer = CreateOffer(NULL);
+ ASSERT_TRUE(offer != NULL);
+ SetLocalDescriptionOfferExpectError(kCreateChannelFailed, offer);
+}
+
+//
+// Tests for creating/setting SDP under different SDES/DTLS polices:
+//
+// --DTLS off and SDES on
+// TestCreateSdesOfferReceiveSdesAnswer/TestReceiveSdesOfferCreateSdesAnswer:
+// set local/remote offer/answer with crypto --> success
+// TestSetNonSdesOfferWhenSdesOn: set local/remote offer without crypto --->
+// failure
+// TestSetLocalNonSdesAnswerWhenSdesOn: set local answer without crypto -->
+// failure
+// TestSetRemoteNonSdesAnswerWhenSdesOn: set remote answer without crypto -->
+// failure
+//
+// --DTLS on and SDES off
+// TestCreateDtlsOfferReceiveDtlsAnswer/TestReceiveDtlsOfferCreateDtlsAnswer:
+// set local/remote offer/answer with DTLS fingerprint --> success
+// TestReceiveNonDtlsOfferWhenDtlsOn: set local/remote offer without DTLS
+// fingerprint --> failure
+// TestSetLocalNonDtlsAnswerWhenDtlsOn: set local answer without fingerprint
+// --> failure
+// TestSetRemoteNonDtlsAnswerWhenDtlsOn: set remote answer without fingerprint
+// --> failure
+//
+// --Encryption disabled: DTLS off and SDES off
+// TestCreateOfferReceiveAnswerWithoutEncryption: set local offer and remote
+// answer without SDES or DTLS --> success
+// TestCreateAnswerReceiveOfferWithoutEncryption: set remote offer and local
+// answer without SDES or DTLS --> success
+//
+
+// Test that we return a failure when applying a remote/local offer that doesn't
+// have cryptos enabled when DTLS is off.
+TEST_F(WebRtcSessionTest, TestSetNonSdesOfferWhenSdesOn) {
Init(NULL);
cricket::MediaSessionOptions options;
options.has_video = true;
@@ -1121,15 +1300,15 @@ TEST_F(WebRtcSessionTest, SetNonCryptoOffer) {
VerifyNoCryptoParams(offer->description(), false);
// SetRemoteDescription and SetLocalDescription will take the ownership of
// the offer.
- SetRemoteDescriptionExpectError(kSdpWithoutCrypto, offer);
+ SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto, offer);
offer = CreateRemoteOffer(options, cricket::SEC_DISABLED);
ASSERT_TRUE(offer != NULL);
- SetLocalDescriptionExpectError(kSdpWithoutCrypto, offer);
+ SetLocalDescriptionOfferExpectError(kSdpWithoutSdesCrypto, offer);
}
-// Test we will return fail when apply an answer that doesn't have
-// crypto enabled.
-TEST_F(WebRtcSessionTest, SetLocalNonCryptoAnswer) {
+// Test that we return a failure when applying a local answer that doesn't have
+// cryptos enabled when DTLS is off.
+TEST_F(WebRtcSessionTest, TestSetLocalNonSdesAnswerWhenSdesOn) {
Init(NULL);
SessionDescriptionInterface* offer = NULL;
SessionDescriptionInterface* answer = NULL;
@@ -1137,12 +1316,12 @@ TEST_F(WebRtcSessionTest, SetLocalNonCryptoAnswer) {
// SetRemoteDescription and SetLocalDescription will take the ownership of
// the offer.
SetRemoteDescriptionWithoutError(offer);
- SetLocalDescriptionExpectError(kSdpWithoutCrypto, answer);
+ SetLocalDescriptionAnswerExpectError(kSdpWithoutSdesCrypto, answer);
}
-// Test we will return fail when apply an answer that doesn't have
-// crypto enabled.
-TEST_F(WebRtcSessionTest, SetRemoteNonCryptoAnswer) {
+// Test we will return fail when apply an remote answer that doesn't have
+// crypto enabled when DTLS is off.
+TEST_F(WebRtcSessionTest, TestSetRemoteNonSdesAnswerWhenSdesOn) {
Init(NULL);
SessionDescriptionInterface* offer = NULL;
SessionDescriptionInterface* answer = NULL;
@@ -1150,32 +1329,23 @@ TEST_F(WebRtcSessionTest, SetRemoteNonCryptoAnswer) {
// SetRemoteDescription and SetLocalDescription will take the ownership of
// the offer.
SetLocalDescriptionWithoutError(offer);
- SetRemoteDescriptionExpectError(kSdpWithoutCrypto, answer);
+ SetRemoteDescriptionAnswerExpectError(kSdpWithoutSdesCrypto, answer);
}
-// Test that we can create and set an offer with a DTLS fingerprint.
-TEST_F(WebRtcSessionTest, CreateSetDtlsOffer) {
+// Test that we accept an offer with a DTLS fingerprint when DTLS is on
+// and that we return an answer with a DTLS fingerprint.
+TEST_F(WebRtcSessionTest, TestReceiveDtlsOfferCreateDtlsAnswer) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
- InitWithDtls();
mediastream_signaling_.SendAudioVideoStream1();
- SessionDescriptionInterface* offer = CreateOffer(NULL);
- ASSERT_TRUE(offer != NULL);
- VerifyFingerprintStatus(offer->description(), true);
- // SetLocalDescription will take the ownership of the offer.
- SetLocalDescriptionWithoutError(offer);
-}
-
-// Test that we can process an offer with a DTLS fingerprint
-// and that we return an answer with a fingerprint.
-TEST_F(WebRtcSessionTest, ReceiveDtlsOfferCreateAnswer) {
- MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
InitWithDtls();
SetFactoryDtlsSrtp();
cricket::MediaSessionOptions options;
options.has_video = true;
- JsepSessionDescription* offer = CreateRemoteOffer(options);
+ JsepSessionDescription* offer =
+ CreateRemoteOffer(options, cricket::SEC_DISABLED);
ASSERT_TRUE(offer != NULL);
VerifyFingerprintStatus(offer->description(), true);
+ VerifyNoCryptoParams(offer->description(), true);
// SetRemoteDescription will take the ownership of the offer.
SetRemoteDescriptionWithoutError(offer);
@@ -1191,28 +1361,148 @@ TEST_F(WebRtcSessionTest, ReceiveDtlsOfferCreateAnswer) {
SetLocalDescriptionWithoutError(answer);
}
-// Test that even if we support DTLS, if the other side didn't offer a
-// fingerprint, we don't either.
-TEST_F(WebRtcSessionTest, ReceiveNoDtlsOfferCreateAnswer) {
+// Test that we set a local offer with a DTLS fingerprint when DTLS is on
+// and then we accept a remote answer with a DTLS fingerprint successfully.
+TEST_F(WebRtcSessionTest, TestCreateDtlsOfferReceiveDtlsAnswer) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+ mediastream_signaling_.SendAudioVideoStream1();
InitWithDtls();
+ SetFactoryDtlsSrtp();
+
+ // Verify that we get a crypto fingerprint in the answer.
+ SessionDescriptionInterface* offer = CreateOffer(NULL);
+ ASSERT_TRUE(offer != NULL);
+ VerifyFingerprintStatus(offer->description(), true);
+ // Check that we don't have an a=crypto line in the offer.
+ VerifyNoCryptoParams(offer->description(), true);
+
+ // Now set the local description, which should work, even without a=crypto.
+ SetLocalDescriptionWithoutError(offer);
+
cricket::MediaSessionOptions options;
options.has_video = true;
+ JsepSessionDescription* answer =
+ CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED);
+ ASSERT_TRUE(answer != NULL);
+ VerifyFingerprintStatus(answer->description(), true);
+ VerifyNoCryptoParams(answer->description(), true);
+
+ // SetRemoteDescription will take the ownership of the answer.
+ SetRemoteDescriptionWithoutError(answer);
+}
+
+// Test that if we support DTLS and the other side didn't offer a fingerprint,
+// we will fail to set the remote description.
+TEST_F(WebRtcSessionTest, TestReceiveNonDtlsOfferWhenDtlsOn) {
+ MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+ InitWithDtls();
+ cricket::MediaSessionOptions options;
+ options.has_video = true;
+ options.bundle_enabled = true;
JsepSessionDescription* offer = CreateRemoteOffer(
options, cricket::SEC_REQUIRED);
ASSERT_TRUE(offer != NULL);
VerifyFingerprintStatus(offer->description(), false);
+ VerifyCryptoParams(offer->description());
- // SetRemoteDescription will take the ownership of
- // the offer.
+ // SetRemoteDescription will take the ownership of the offer.
+ SetRemoteDescriptionOfferExpectError(
+ kSdpWithoutDtlsFingerprint, offer);
+
+ offer = CreateRemoteOffer(options, cricket::SEC_REQUIRED);
+ // SetLocalDescription will take the ownership of the offer.
+ SetLocalDescriptionOfferExpectError(
+ kSdpWithoutDtlsFingerprint, offer);
+}
+
+// Test that we return a failure when applying a local answer that doesn't have
+// a DTLS fingerprint when DTLS is required.
+TEST_F(WebRtcSessionTest, TestSetLocalNonDtlsAnswerWhenDtlsOn) {
+ MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+ InitWithDtls();
+ SessionDescriptionInterface* offer = NULL;
+ SessionDescriptionInterface* answer = NULL;
+ CreateDtlsOfferAndNonDtlsAnswer(&offer, &answer);
+
+ // SetRemoteDescription and SetLocalDescription will take the ownership of
+ // the offer and answer.
SetRemoteDescriptionWithoutError(offer);
+ SetLocalDescriptionAnswerExpectError(
+ kSdpWithoutDtlsFingerprint, answer);
+}
+
+// Test that we return a failure when applying a remote answer that doesn't have
+// a DTLS fingerprint when DTLS is required.
+TEST_F(WebRtcSessionTest, TestSetRemoteNonDtlsAnswerWhenDtlsOn) {
+ MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+ InitWithDtls();
+ SessionDescriptionInterface* offer = CreateOffer(NULL);
+ cricket::MediaSessionOptions options;
+ options.has_video = true;
+ JsepSessionDescription* answer =
+ CreateRemoteAnswer(offer, options, cricket::SEC_ENABLED);
- // Verify that we don't get a crypto fingerprint in the answer.
+ // SetRemoteDescription and SetLocalDescription will take the ownership of
+ // the offer and answer.
+ SetLocalDescriptionWithoutError(offer);
+ SetRemoteDescriptionAnswerExpectError(
+ kSdpWithoutDtlsFingerprint, answer);
+}
+
+// Test that we create a local offer without SDES or DTLS and accept a remote
+// answer without SDES or DTLS when encryption is disabled.
+TEST_F(WebRtcSessionTest, TestCreateOfferReceiveAnswerWithoutEncryption) {
+ mediastream_signaling_.SendAudioVideoStream1();
+ options_.disable_encryption = true;
+ InitWithDtls();
+
+ // Verify that we get a crypto fingerprint in the answer.
+ SessionDescriptionInterface* offer = CreateOffer(NULL);
+ ASSERT_TRUE(offer != NULL);
+ VerifyFingerprintStatus(offer->description(), false);
+ // Check that we don't have an a=crypto line in the offer.
+ VerifyNoCryptoParams(offer->description(), false);
+
+ // Now set the local description, which should work, even without a=crypto.
+ SetLocalDescriptionWithoutError(offer);
+
+ cricket::MediaSessionOptions options;
+ options.has_video = true;
+ JsepSessionDescription* answer =
+ CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED);
+ ASSERT_TRUE(answer != NULL);
+ VerifyFingerprintStatus(answer->description(), false);
+ VerifyNoCryptoParams(answer->description(), false);
+
+ // SetRemoteDescription will take the ownership of the answer.
+ SetRemoteDescriptionWithoutError(answer);
+}
+
+// Test that we create a local answer without SDES or DTLS and accept a remote
+// offer without SDES or DTLS when encryption is disabled.
+TEST_F(WebRtcSessionTest, TestCreateAnswerReceiveOfferWithoutEncryption) {
+ options_.disable_encryption = true;
+ InitWithDtls();
+
+ cricket::MediaSessionOptions options;
+ options.has_video = true;
+ JsepSessionDescription* offer =
+ CreateRemoteOffer(options, cricket::SEC_DISABLED);
+ ASSERT_TRUE(offer != NULL);
+ VerifyFingerprintStatus(offer->description(), false);
+ VerifyNoCryptoParams(offer->description(), false);
+
+ // SetRemoteDescription will take the ownership of the offer.
+ SetRemoteDescriptionWithoutError(offer);
+
+ // Verify that we get a crypto fingerprint in the answer.
SessionDescriptionInterface* answer = CreateAnswer(NULL);
ASSERT_TRUE(answer != NULL);
VerifyFingerprintStatus(answer->description(), false);
+ // Check that we don't have an a=crypto line in the answer.
+ VerifyNoCryptoParams(answer->description(), false);
- // Now set the local description.
+ // Now set the local description, which should work, even without a=crypto.
SetLocalDescriptionWithoutError(answer);
}
@@ -1245,9 +1535,8 @@ TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteOffer) {
SessionDescriptionInterface* offer = CreateOffer(NULL);
SetLocalDescriptionWithoutError(offer);
offer = CreateOffer(NULL);
- SetRemoteDescriptionExpectError(
- "Called with type in wrong state, type: offer state: STATE_SENTINITIATE",
- offer);
+ SetRemoteDescriptionOfferExpectError(
+ "Called in wrong state: STATE_SENTINITIATE", offer);
}
TEST_F(WebRtcSessionTest, TestSetRemoteAndLocalOffer) {
@@ -1256,10 +1545,8 @@ TEST_F(WebRtcSessionTest, TestSetRemoteAndLocalOffer) {
SessionDescriptionInterface* offer = CreateOffer(NULL);
SetRemoteDescriptionWithoutError(offer);
offer = CreateOffer(NULL);
- SetLocalDescriptionExpectError(
- "Called with type in wrong state, type: "
- "offer state: STATE_RECEIVEDINITIATE",
- offer);
+ SetLocalDescriptionOfferExpectError(
+ "Called in wrong state: STATE_RECEIVEDINITIATE", offer);
}
TEST_F(WebRtcSessionTest, TestSetLocalPrAnswer) {
@@ -1319,9 +1606,8 @@ TEST_F(WebRtcSessionTest, TestSetLocalAnswerWithoutOffer) {
CreateOffer(NULL));
SessionDescriptionInterface* answer =
CreateRemoteAnswer(offer.get());
- SetLocalDescriptionExpectError(
- "Called with type in wrong state, type: answer state: STATE_INIT",
- answer);
+ SetLocalDescriptionAnswerExpectError("Called in wrong state: STATE_INIT",
+ answer);
}
TEST_F(WebRtcSessionTest, TestSetRemoteAnswerWithoutOffer) {
@@ -1331,9 +1617,8 @@ TEST_F(WebRtcSessionTest, TestSetRemoteAnswerWithoutOffer) {
CreateOffer(NULL));
SessionDescriptionInterface* answer =
CreateRemoteAnswer(offer.get());
- SetRemoteDescriptionExpectError(
- "Called with type in wrong state, type: answer state: STATE_INIT",
- answer);
+ SetRemoteDescriptionAnswerExpectError(
+ "Called in wrong state: STATE_INIT", answer);
}
TEST_F(WebRtcSessionTest, TestAddRemoteCandidate) {
@@ -1372,10 +1657,12 @@ TEST_F(WebRtcSessionTest, TestAddRemoteCandidate) {
EXPECT_EQ(1, candidates->at(0)->candidate().component());
EXPECT_EQ(2, candidates->at(1)->candidate().component());
+ // |ice_candidate3| is identical to |ice_candidate2|. It can be added
+ // successfully, but the total count of candidates will not increase.
candidate.set_component(2);
JsepIceCandidate ice_candidate3(kMediaContentName0, 0, candidate);
EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate3));
- ASSERT_EQ(3u, candidates->count());
+ ASSERT_EQ(2u, candidates->count());
JsepIceCandidate bad_ice_candidate("bad content name", 99, candidate);
EXPECT_FALSE(session_->ProcessIceMessage(&bad_ice_candidate));
@@ -1979,7 +2266,7 @@ TEST_F(WebRtcSessionTest, TestSetLocalDescriptionWithoutIce) {
RemoveIceUfragPwdLines(offer.get(), &sdp);
SessionDescriptionInterface* modified_offer =
CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL);
- SetLocalDescriptionExpectError(kSdpWithoutIceUfragPwd, modified_offer);
+ SetLocalDescriptionOfferExpectError(kSdpWithoutIceUfragPwd, modified_offer);
}
// This test verifies that setRemoteDescription fails if
@@ -1991,7 +2278,55 @@ TEST_F(WebRtcSessionTest, TestSetRemoteDescriptionWithoutIce) {
RemoveIceUfragPwdLines(offer.get(), &sdp);
SessionDescriptionInterface* modified_offer =
CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL);
- SetRemoteDescriptionExpectError(kSdpWithoutIceUfragPwd, modified_offer);
+ SetRemoteDescriptionOfferExpectError(kSdpWithoutIceUfragPwd, modified_offer);
+}
+
+// This test verifies that setLocalDescription fails if local offer has
+// too short ice ufrag and pwd strings.
+TEST_F(WebRtcSessionTest, TestSetLocalDescriptionInvalidIceCredentials) {
+ Init(NULL);
+ tdesc_factory_->set_protocol(cricket::ICEPROTO_RFC5245);
+ mediastream_signaling_.SendAudioVideoStream1();
+ talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
+ std::string sdp;
+ // Modifying ice ufrag and pwd in local offer with strings smaller than the
+ // recommended values of 4 and 22 bytes respectively.
+ ModifyIceUfragPwdLines(offer.get(), "ice", "icepwd", &sdp);
+ SessionDescriptionInterface* modified_offer =
+ CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL);
+ std::string error;
+ EXPECT_FALSE(session_->SetLocalDescription(modified_offer, &error));
+
+ // Test with string greater than 256.
+ sdp.clear();
+ ModifyIceUfragPwdLines(offer.get(), kTooLongIceUfragPwd, kTooLongIceUfragPwd,
+ &sdp);
+ modified_offer = CreateSessionDescription(JsepSessionDescription::kOffer, sdp,
+ NULL);
+ EXPECT_FALSE(session_->SetLocalDescription(modified_offer, &error));
+}
+
+// This test verifies that setRemoteDescription fails if remote offer has
+// too short ice ufrag and pwd strings.
+TEST_F(WebRtcSessionTest, TestSetRemoteDescriptionInvalidIceCredentials) {
+ Init(NULL);
+ tdesc_factory_->set_protocol(cricket::ICEPROTO_RFC5245);
+ talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer());
+ std::string sdp;
+ // Modifying ice ufrag and pwd in remote offer with strings smaller than the
+ // recommended values of 4 and 22 bytes respectively.
+ ModifyIceUfragPwdLines(offer.get(), "ice", "icepwd", &sdp);
+ SessionDescriptionInterface* modified_offer =
+ CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL);
+ std::string error;
+ EXPECT_FALSE(session_->SetRemoteDescription(modified_offer, &error));
+
+ sdp.clear();
+ ModifyIceUfragPwdLines(offer.get(), kTooLongIceUfragPwd, kTooLongIceUfragPwd,
+ &sdp);
+ modified_offer = CreateSessionDescription(JsepSessionDescription::kOffer, sdp,
+ NULL);
+ EXPECT_FALSE(session_->SetRemoteDescription(modified_offer, &error));
}
TEST_F(WebRtcSessionTest, VerifyBundleFlagInPA) {
@@ -1999,8 +2334,8 @@ TEST_F(WebRtcSessionTest, VerifyBundleFlagInPA) {
// local description is removed by the application, BUNDLE flag should be
// disabled in PortAllocator. By default BUNDLE is enabled in the WebRtc.
Init(NULL);
- EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE & allocator_.flags()) ==
- cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+ EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE &
+ allocator_->flags()) == cricket::PORTALLOCATOR_ENABLE_BUNDLE);
talk_base::scoped_ptr<SessionDescriptionInterface> offer(
CreateOffer(NULL));
cricket::SessionDescription* offer_copy =
@@ -2011,14 +2346,14 @@ TEST_F(WebRtcSessionTest, VerifyBundleFlagInPA) {
modified_offer->Initialize(offer_copy, "1", "1");
SetLocalDescriptionWithoutError(modified_offer);
- EXPECT_FALSE(allocator_.flags() & cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+ EXPECT_FALSE(allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_BUNDLE);
}
TEST_F(WebRtcSessionTest, TestDisabledBundleInAnswer) {
Init(NULL);
mediastream_signaling_.SendAudioVideoStream1();
- EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE & allocator_.flags()) ==
- cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+ EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE &
+ allocator_->flags()) == cricket::PORTALLOCATOR_ENABLE_BUNDLE);
FakeConstraints constraints;
constraints.SetMandatoryUseRtpMux(true);
SessionDescriptionInterface* offer = CreateOffer(&constraints);
@@ -2032,8 +2367,8 @@ TEST_F(WebRtcSessionTest, TestDisabledBundleInAnswer) {
new JsepSessionDescription(JsepSessionDescription::kAnswer);
modified_answer->Initialize(answer_copy, "1", "1");
SetRemoteDescriptionWithoutError(modified_answer);
- EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE & allocator_.flags()) ==
- cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+ EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE &
+ allocator_->flags()) == cricket::PORTALLOCATOR_ENABLE_BUNDLE);
video_channel_ = media_engine_->GetVideoChannel(0);
voice_channel_ = media_engine_->GetVoiceChannel(0);
@@ -2055,8 +2390,8 @@ TEST_F(WebRtcSessionTest, TestDisabledBundleInAnswer) {
TEST_F(WebRtcSessionTest, TestDisabledRtcpMuxWithBundleEnabled) {
WebRtcSessionTest::Init(NULL);
mediastream_signaling_.SendAudioVideoStream1();
- EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE & allocator_.flags()) ==
- cricket::PORTALLOCATOR_ENABLE_BUNDLE);
+ EXPECT_TRUE((cricket::PORTALLOCATOR_ENABLE_BUNDLE &
+ allocator_->flags()) == cricket::PORTALLOCATOR_ENABLE_BUNDLE);
FakeConstraints constraints;
constraints.SetMandatoryUseRtpMux(true);
SessionDescriptionInterface* offer = CreateOffer(&constraints);
@@ -2071,11 +2406,11 @@ TEST_F(WebRtcSessionTest, TestDisabledRtcpMuxWithBundleEnabled) {
JsepSessionDescription *local_offer =
new JsepSessionDescription(JsepSessionDescription::kOffer);
EXPECT_TRUE((local_offer)->Initialize(offer_str, NULL));
- SetLocalDescriptionExpectError(kBundleWithoutRtcpMux, local_offer);
+ SetLocalDescriptionOfferExpectError(kBundleWithoutRtcpMux, local_offer);
JsepSessionDescription *remote_offer =
new JsepSessionDescription(JsepSessionDescription::kOffer);
EXPECT_TRUE((remote_offer)->Initialize(offer_str, NULL));
- SetRemoteDescriptionExpectError(kBundleWithoutRtcpMux, remote_offer);
+ SetRemoteDescriptionOfferExpectError(kBundleWithoutRtcpMux, remote_offer);
// Trying unmodified SDP.
SetLocalDescriptionWithoutError(offer);
}
@@ -2123,13 +2458,39 @@ TEST_F(WebRtcSessionTest, SetAudioSend) {
EXPECT_TRUE(channel->IsStreamMuted(send_ssrc));
EXPECT_FALSE(channel->options().echo_cancellation.IsSet());
EXPECT_EQ(0, renderer->channel_id());
+ EXPECT_TRUE(renderer->sink() != NULL);
+ // This will trigger SetSink(NULL) to the |renderer|.
session_->SetAudioSend(send_ssrc, true, options, NULL);
EXPECT_FALSE(channel->IsStreamMuted(send_ssrc));
bool value;
EXPECT_TRUE(channel->options().echo_cancellation.Get(&value));
EXPECT_TRUE(value);
EXPECT_EQ(-1, renderer->channel_id());
+ EXPECT_TRUE(renderer->sink() == NULL);
+}
+
+TEST_F(WebRtcSessionTest, AudioRendererForLocalStream) {
+ Init(NULL);
+ mediastream_signaling_.SendAudioVideoStream1();
+ CreateAndSetRemoteOfferAndLocalAnswer();
+ cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
+ ASSERT_TRUE(channel != NULL);
+ ASSERT_EQ(1u, channel->send_streams().size());
+ uint32 send_ssrc = channel->send_streams()[0].first_ssrc();
+
+ talk_base::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer());
+ cricket::AudioOptions options;
+ session_->SetAudioSend(send_ssrc, true, options, renderer.get());
+ EXPECT_TRUE(renderer->sink() != NULL);
+
+ // Delete the |renderer| and it will trigger OnClose() to the sink, and this
+ // will invalidate the |renderer_| pointer in the sink and prevent getting a
+ // SetSink(NULL) callback afterwards.
+ renderer.reset();
+
+ // This will trigger SetSink(NULL) if no OnClose() callback.
+ session_->SetAudioSend(send_ssrc, true, options, NULL);
}
TEST_F(WebRtcSessionTest, SetVideoPlayout) {
@@ -2319,13 +2680,13 @@ TEST_F(WebRtcSessionTest, TestIceOfferGIceOnlyAnswer) {
SessionDescriptionInterface* pranswer_with_gice =
CreateSessionDescription(JsepSessionDescription::kPrAnswer,
original_offer_sdp, NULL);
- SetRemoteDescriptionExpectError(kPushDownPranswerTDFailed,
- pranswer_with_gice);
+ SetRemoteDescriptionPranswerExpectError(kPushDownTDFailed,
+ pranswer_with_gice);
SessionDescriptionInterface* answer_with_gice =
CreateSessionDescription(JsepSessionDescription::kAnswer,
original_offer_sdp, NULL);
- SetRemoteDescriptionExpectError(kPushDownAnswerTDFailed,
- answer_with_gice);
+ SetRemoteDescriptionAnswerExpectError(kPushDownTDFailed,
+ answer_with_gice);
}
// Verifing local offer and remote answer have matching m-lines as per RFC 3264.
@@ -2345,23 +2706,32 @@ TEST_F(WebRtcSessionTest, TestIncorrectMLinesInRemoteAnswer) {
EXPECT_TRUE(modified_answer->Initialize(answer_copy,
answer->session_id(),
answer->session_version()));
- SetRemoteDescriptionExpectError(kMlineMismatch, modified_answer);
+ SetRemoteDescriptionAnswerExpectError(kMlineMismatch, modified_answer);
- // Modifying content names.
+ // Different content names.
std::string sdp;
EXPECT_TRUE(answer->ToString(&sdp));
const std::string kAudioMid = "a=mid:audio";
const std::string kAudioMidReplaceStr = "a=mid:audio_content_name";
-
- // Replacing |audio| with |audio_content_name|.
talk_base::replace_substrs(kAudioMid.c_str(), kAudioMid.length(),
kAudioMidReplaceStr.c_str(),
kAudioMidReplaceStr.length(),
&sdp);
-
SessionDescriptionInterface* modified_answer1 =
CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL);
- SetRemoteDescriptionExpectError(kMlineMismatch, modified_answer1);
+ SetRemoteDescriptionAnswerExpectError(kMlineMismatch, modified_answer1);
+
+ // Different media types.
+ EXPECT_TRUE(answer->ToString(&sdp));
+ const std::string kAudioMline = "m=audio";
+ const std::string kAudioMlineReplaceStr = "m=video";
+ talk_base::replace_substrs(kAudioMline.c_str(), kAudioMline.length(),
+ kAudioMlineReplaceStr.c_str(),
+ kAudioMlineReplaceStr.length(),
+ &sdp);
+ SessionDescriptionInterface* modified_answer2 =
+ CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL);
+ SetRemoteDescriptionAnswerExpectError(kMlineMismatch, modified_answer2);
SetRemoteDescriptionWithoutError(answer.release());
}
@@ -2383,7 +2753,7 @@ TEST_F(WebRtcSessionTest, TestIncorrectMLinesInLocalAnswer) {
EXPECT_TRUE(modified_answer->Initialize(answer_copy,
answer->session_id(),
answer->session_version()));
- SetLocalDescriptionExpectError(kMlineMismatch, modified_answer);
+ SetLocalDescriptionAnswerExpectError(kMlineMismatch, modified_answer);
SetLocalDescriptionWithoutError(answer);
}
@@ -2537,33 +2907,49 @@ TEST_F(WebRtcSessionTest, TestSessionContentError) {
mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
- SetRemoteDescriptionExpectError("ERROR_CONTENT", answer);
+ SetRemoteDescriptionAnswerExpectError("ERROR_CONTENT", answer);
}
// Runs the loopback call test with BUNDLE and STUN disabled.
TEST_F(WebRtcSessionTest, TestIceStatesBasic) {
// Lets try with only UDP ports.
- allocator_.set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+ allocator_->set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
cricket::PORTALLOCATOR_DISABLE_TCP |
cricket::PORTALLOCATOR_DISABLE_STUN |
cricket::PORTALLOCATOR_DISABLE_RELAY);
TestLoopbackCall();
}
-// Regression-test for a crash which should have been an error.
-TEST_F(WebRtcSessionTest, TestNoStateTransitionPendingError) {
+// Runs the loopback call test with BUNDLE and STUN enabled.
+TEST_F(WebRtcSessionTest, TestIceStatesBundle) {
+ allocator_->set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+ cricket::PORTALLOCATOR_ENABLE_BUNDLE |
+ cricket::PORTALLOCATOR_DISABLE_TCP |
+ cricket::PORTALLOCATOR_DISABLE_RELAY);
+ TestLoopbackCall();
+}
+
+TEST_F(WebRtcSessionTest, SetSdpFailedOnSessionError) {
Init(NULL);
cricket::MediaSessionOptions options;
options.has_audio = true;
options.has_video = true;
- session_->SetError(cricket::BaseSession::ERROR_CONTENT);
+ cricket::BaseSession::Error error_code = cricket::BaseSession::ERROR_CONTENT;
+ std::string error_code_str = "ERROR_CONTENT";
+ std::string error_desc = "Fake session error description.";
+ session_->SetError(error_code, error_desc);
+
SessionDescriptionInterface* offer = CreateRemoteOffer(options);
SessionDescriptionInterface* answer =
CreateRemoteAnswer(offer, options);
- SetRemoteDescriptionExpectError(kSessionError, offer);
- SetLocalDescriptionExpectError(kSessionError, answer);
- // Not crashing is our success.
+
+ std::string action;
+ std::ostringstream session_error_msg;
+ session_error_msg << kSessionError << error_code_str << ". ";
+ session_error_msg << kSessionErrorDesc << error_desc << ".";
+ SetRemoteDescriptionExpectError(action, session_error_msg.str(), offer);
+ SetLocalDescriptionExpectError(action, session_error_msg.str(), answer);
}
TEST_F(WebRtcSessionTest, TestRtpDataChannel) {
@@ -2584,7 +2970,7 @@ TEST_F(WebRtcSessionTest, TestRtpDataChannelConstraintTakesPrecedence) {
webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, true);
options_.disable_sctp_data_channels = false;
- InitWithDtls(false);
+ InitWithDtls();
SetLocalDescriptionWithDataChannel();
EXPECT_EQ(cricket::DCT_RTP, data_engine_->last_channel_type());
@@ -2593,7 +2979,7 @@ TEST_F(WebRtcSessionTest, TestRtpDataChannelConstraintTakesPrecedence) {
TEST_F(WebRtcSessionTest, TestCreateOfferWithSctpEnabledWithoutStreams) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
- InitWithDtls(false);
+ InitWithDtls();
talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
EXPECT_TRUE(offer->description()->GetContentByName("data") == NULL);
@@ -2603,13 +2989,13 @@ TEST_F(WebRtcSessionTest, TestCreateOfferWithSctpEnabledWithoutStreams) {
TEST_F(WebRtcSessionTest, TestCreateAnswerWithSctpInOfferAndNoStreams) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
SetFactoryDtlsSrtp();
- InitWithDtls(false);
+ InitWithDtls();
// Create remote offer with SCTP.
cricket::MediaSessionOptions options;
options.data_channel_type = cricket::DCT_SCTP;
JsepSessionDescription* offer =
- CreateRemoteOffer(options, cricket::SEC_ENABLED);
+ CreateRemoteOffer(options, cricket::SEC_DISABLED);
SetRemoteDescriptionWithoutError(offer);
// Verifies the answer contains SCTP.
@@ -2623,7 +3009,7 @@ TEST_F(WebRtcSessionTest, TestSctpDataChannelWithoutDtls) {
constraints_.reset(new FakeConstraints());
constraints_->AddOptional(
webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, false);
- InitWithDtls(false);
+ InitWithDtls();
SetLocalDescriptionWithDataChannel();
EXPECT_EQ(cricket::DCT_NONE, data_engine_->last_channel_type());
@@ -2632,7 +3018,7 @@ TEST_F(WebRtcSessionTest, TestSctpDataChannelWithoutDtls) {
TEST_F(WebRtcSessionTest, TestSctpDataChannelWithDtls) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
- InitWithDtls(false);
+ InitWithDtls();
SetLocalDescriptionWithDataChannel();
EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type());
@@ -2641,7 +3027,7 @@ TEST_F(WebRtcSessionTest, TestSctpDataChannelWithDtls) {
TEST_F(WebRtcSessionTest, TestDisableSctpDataChannels) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
options_.disable_sctp_data_channels = true;
- InitWithDtls(false);
+ InitWithDtls();
SetLocalDescriptionWithDataChannel();
EXPECT_EQ(cricket::DCT_NONE, data_engine_->last_channel_type());
@@ -2652,7 +3038,7 @@ TEST_F(WebRtcSessionTest, TestSctpDataChannelSendPortParsing) {
const int new_send_port = 9998;
const int new_recv_port = 7775;
- InitWithDtls(false);
+ InitWithDtls();
SetFactoryDtlsSrtp();
// By default, don't actually add the codecs to desc_factory_; they don't
@@ -2675,7 +3061,7 @@ TEST_F(WebRtcSessionTest, TestSctpDataChannelSendPortParsing) {
// TEST PLAN: Set the port number to something new, set it in the SDP,
// and pass it all the way down.
- webrtc::DataChannelInit dci;
+ webrtc::InternalDataChannelInit dci;
dci.reliable = true;
EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type());
talk_base::scoped_refptr<webrtc::DataChannel> dc =
@@ -2705,34 +3091,41 @@ TEST_F(WebRtcSessionTest, TestSctpDataChannelSendPortParsing) {
// identity generation is finished.
TEST_F(WebRtcSessionTest, TestCreateOfferBeforeIdentityRequestReturnSuccess) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
- InitWithDtls(false);
+ InitWithDtls();
EXPECT_TRUE(session_->waiting_for_identity());
+ mediastream_signaling_.SendAudioVideoStream1();
talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
EXPECT_TRUE(offer != NULL);
+ VerifyNoCryptoParams(offer->description(), true);
+ VerifyFingerprintStatus(offer->description(), true);
}
// Verifies that CreateAnswer succeeds when CreateOffer is called before async
// identity generation is finished.
TEST_F(WebRtcSessionTest, TestCreateAnswerBeforeIdentityRequestReturnSuccess) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
- InitWithDtls(false);
+ InitWithDtls();
+ SetFactoryDtlsSrtp();
cricket::MediaSessionOptions options;
+ options.has_video = true;
scoped_ptr<JsepSessionDescription> offer(
- CreateRemoteOffer(options, cricket::SEC_REQUIRED));
+ CreateRemoteOffer(options, cricket::SEC_DISABLED));
ASSERT_TRUE(offer.get() != NULL);
SetRemoteDescriptionWithoutError(offer.release());
talk_base::scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL));
EXPECT_TRUE(answer != NULL);
+ VerifyNoCryptoParams(answer->description(), true);
+ VerifyFingerprintStatus(answer->description(), true);
}
// Verifies that CreateOffer succeeds when CreateOffer is called after async
// identity generation is finished.
TEST_F(WebRtcSessionTest, TestCreateOfferAfterIdentityRequestReturnSuccess) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
- InitWithDtls(false);
+ InitWithDtls();
EXPECT_TRUE_WAIT(!session_->waiting_for_identity(), 1000);
talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
@@ -2803,8 +3196,8 @@ TEST_F(WebRtcSessionTest, TestSetRemoteOfferFailIfDtlsDisabledAndNoCrypto) {
audio->description.identity_fingerprint.reset(
talk_base::SSLFingerprint::CreateFromRfc4572(
talk_base::DIGEST_SHA_256, kFakeDtlsFingerprint));
- SetRemoteDescriptionExpectError(kSdpWithoutSdesAndDtlsDisabled,
- offer);
+ SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto,
+ offer);
}
// This test verifies DSCP is properly applied on the media channels.
@@ -2833,6 +3226,26 @@ TEST_F(WebRtcSessionTest, TestDscpConstraint) {
EXPECT_TRUE(video_options.dscp.GetWithDefaultIfUnset(false));
}
+TEST_F(WebRtcSessionTest, TestSuspendBelowMinBitrateConstraint) {
+ constraints_.reset(new FakeConstraints());
+ constraints_->AddOptional(
+ webrtc::MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate,
+ true);
+ Init(NULL);
+ mediastream_signaling_.SendAudioVideoStream1();
+ SessionDescriptionInterface* offer = CreateOffer(NULL);
+
+ SetLocalDescriptionWithoutError(offer);
+
+ video_channel_ = media_engine_->GetVideoChannel(0);
+
+ ASSERT_TRUE(video_channel_ != NULL);
+ cricket::VideoOptions video_options;
+ EXPECT_TRUE(video_channel_->GetOptions(&video_options));
+ EXPECT_TRUE(
+ video_options.suspend_below_min_bitrate.GetWithDefaultIfUnset(false));
+}
+
// TODO(bemasc): Add a TestIceStatesBundle with BUNDLE enabled. That test
// currently fails because upon disconnection and reconnection OnIceComplete is
// called more than once without returning to IceGatheringGathering.
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsessiondescriptionfactory.cc b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
index b6f523ce0cf..25d8fc9316b 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
@@ -127,8 +127,8 @@ WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
identity_request_state_(IDENTITY_NOT_NEEDED) {
transport_desc_factory_.set_protocol(cricket::ICEPROTO_HYBRID);
session_desc_factory_.set_add_legacy_streams(false);
- // By default SRTP-SDES is enabled in WebRtc.
- SetSecure(cricket::SEC_REQUIRED);
+ // SRTP-SDES is disabled if DTLS is on.
+ SetSdesPolicy(dtls_enabled ? cricket::SEC_DISABLED : cricket::SEC_REQUIRED);
if (!dtls_enabled) {
return;
@@ -261,12 +261,12 @@ void WebRtcSessionDescriptionFactory::CreateAnswer(
}
}
-void WebRtcSessionDescriptionFactory::SetSecure(
- cricket::SecureMediaPolicy secure_policy) {
+void WebRtcSessionDescriptionFactory::SetSdesPolicy(
+ cricket::SecurePolicy secure_policy) {
session_desc_factory_.set_secure(secure_policy);
}
-cricket::SecureMediaPolicy WebRtcSessionDescriptionFactory::Secure() const {
+cricket::SecurePolicy WebRtcSessionDescriptionFactory::SdesPolicy() const {
return session_desc_factory_.secure();
}
@@ -318,7 +318,8 @@ void WebRtcSessionDescriptionFactory::InternalCreateOffer(
if (!offer->Initialize(desc, session_id_,
talk_base::ToString(session_version_++))) {
delete offer;
- PostCreateSessionDescriptionFailed(request.observer, "CreateOffer failed.");
+ PostCreateSessionDescriptionFailed(request.observer,
+ "Failed to initialize the offer.");
return;
}
if (session_->local_description() &&
@@ -362,7 +363,7 @@ void WebRtcSessionDescriptionFactory::InternalCreateAnswer(
talk_base::ToString(session_version_++))) {
delete answer;
PostCreateSessionDescriptionFailed(request.observer,
- "CreateAnswer failed.");
+ "Failed to initialize the answer.");
return;
}
if (session_->local_description() &&
@@ -380,6 +381,7 @@ void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionFailed(
CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
msg->error = error;
signaling_thread_->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
+ LOG(LS_ERROR) << "Create SDP failed: " << error;
}
void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionSucceeded(
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsessiondescriptionfactory.h b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsessiondescriptionfactory.h
index ca614b4356d..cad0c65da11 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsessiondescriptionfactory.h
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/webrtcsessiondescriptionfactory.h
@@ -112,8 +112,8 @@ class WebRtcSessionDescriptionFactory : public talk_base::MessageHandler,
CreateSessionDescriptionObserver* observer,
const MediaConstraintsInterface* constraints);
- void SetSecure(cricket::SecureMediaPolicy secure_policy);
- cricket::SecureMediaPolicy Secure() const;
+ void SetSdesPolicy(cricket::SecurePolicy secure_policy);
+ cricket::SecurePolicy SdesPolicy() const;
sigslot::signal1<talk_base::SSLIdentity*> SignalIdentityReady;
diff --git a/chromium/third_party/libjingle/source/talk/base/asyncinvoker-inl.h b/chromium/third_party/libjingle/source/talk/base/asyncinvoker-inl.h
new file mode 100644
index 00000000000..b6be1750453
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/asyncinvoker-inl.h
@@ -0,0 +1,146 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_BASE_ASYNCINVOKER_INL_H_
+#define TALK_BASE_ASYNCINVOKER_INL_H_
+
+#include "talk/base/bind.h"
+#include "talk/base/callback.h"
+#include "talk/base/criticalsection.h"
+#include "talk/base/messagehandler.h"
+#include "talk/base/refcount.h"
+#include "talk/base/scoped_ref_ptr.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/thread.h"
+
+namespace talk_base {
+
+class AsyncInvoker;
+
+// Helper class for AsyncInvoker. Runs a task and triggers a callback
+// on the calling thread if necessary. Instances are ref-counted so their
+// lifetime can be independent of AsyncInvoker.
+class AsyncClosure : public RefCountInterface {
+ public:
+ virtual ~AsyncClosure() {}
+ // Runs the asynchronous task, and triggers a callback to the calling
+ // thread if needed. Should be called from the target thread.
+ virtual void Execute() = 0;
+};
+
+// Simple closure that doesn't trigger a callback for the calling thread.
+template <class FunctorT>
+class FireAndForgetAsyncClosure : public AsyncClosure {
+ public:
+ explicit FireAndForgetAsyncClosure(const FunctorT& functor)
+ : functor_(functor) {}
+ virtual void Execute() {
+ functor_();
+ }
+ private:
+ FunctorT functor_;
+};
+
+// Base class for closures that may trigger a callback for the calling thread.
+// Listens for the "destroyed" signals from the calling thread and the invoker,
+// and cancels the callback to the calling thread if either is destroyed.
+class NotifyingAsyncClosureBase : public AsyncClosure,
+ public sigslot::has_slots<> {
+ public:
+ virtual ~NotifyingAsyncClosureBase() { disconnect_all(); }
+
+ protected:
+ NotifyingAsyncClosureBase(AsyncInvoker* invoker, Thread* calling_thread);
+ void TriggerCallback();
+ void SetCallback(const Callback0<void>& callback) {
+ CritScope cs(&crit_);
+ callback_ = callback;
+ }
+ bool CallbackCanceled() const { return calling_thread_ == NULL; }
+
+ private:
+ Callback0<void> callback_;
+ CriticalSection crit_;
+ AsyncInvoker* invoker_;
+ Thread* calling_thread_;
+
+ void CancelCallback();
+};
+
+// Closures that have a non-void return value and require a callback.
+template <class ReturnT, class FunctorT, class HostT>
+class NotifyingAsyncClosure : public NotifyingAsyncClosureBase {
+ public:
+ NotifyingAsyncClosure(AsyncInvoker* invoker,
+ Thread* calling_thread,
+ const FunctorT& functor,
+ void (HostT::*callback)(ReturnT),
+ HostT* callback_host)
+ : NotifyingAsyncClosureBase(invoker, calling_thread),
+ functor_(functor),
+ callback_(callback),
+ callback_host_(callback_host) {}
+ virtual void Execute() {
+ ReturnT result = functor_();
+ if (!CallbackCanceled()) {
+ SetCallback(Callback0<void>(Bind(callback_, callback_host_, result)));
+ TriggerCallback();
+ }
+ }
+
+ private:
+ FunctorT functor_;
+ void (HostT::*callback_)(ReturnT);
+ HostT* callback_host_;
+};
+
+// Closures that have a void return value and require a callback.
+template <class FunctorT, class HostT>
+class NotifyingAsyncClosure<void, FunctorT, HostT>
+ : public NotifyingAsyncClosureBase {
+ public:
+ NotifyingAsyncClosure(AsyncInvoker* invoker,
+ Thread* calling_thread,
+ const FunctorT& functor,
+ void (HostT::*callback)(),
+ HostT* callback_host)
+ : NotifyingAsyncClosureBase(invoker, calling_thread),
+ functor_(functor) {
+ SetCallback(Callback0<void>(Bind(callback, callback_host)));
+ }
+ virtual void Execute() {
+ functor_();
+ TriggerCallback();
+ }
+
+ private:
+ FunctorT functor_;
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_ASYNCINVOKER_INL_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/asyncinvoker.cc b/chromium/third_party/libjingle/source/talk/base/asyncinvoker.cc
new file mode 100644
index 00000000000..a57eb7b962d
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/asyncinvoker.cc
@@ -0,0 +1,108 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/asyncinvoker.h"
+
+namespace talk_base {
+
+AsyncInvoker::AsyncInvoker() : destroying_(false) {}
+
+AsyncInvoker::~AsyncInvoker() {
+ destroying_ = true;
+ SignalInvokerDestroyed();
+ // Messages for this need to be cleared *before* our destructor is complete.
+ MessageQueueManager::Clear(this);
+}
+
+void AsyncInvoker::OnMessage(Message* msg) {
+ // Get the AsyncClosure shared ptr from this message's data.
+ ScopedRefMessageData<AsyncClosure>* data =
+ static_cast<ScopedRefMessageData<AsyncClosure>*>(msg->pdata);
+ scoped_refptr<AsyncClosure> closure = data->data();
+ delete msg->pdata;
+ msg->pdata = NULL;
+
+ // Execute the closure and trigger the return message if needed.
+ closure->Execute();
+}
+
+void AsyncInvoker::Flush(Thread* thread, uint32 id /*= MQID_ANY*/) {
+ if (destroying_) return;
+
+ // Run this on |thread| to reduce the number of context switches.
+ if (Thread::Current() != thread) {
+ thread->Invoke<void>(Bind(&AsyncInvoker::Flush, this, thread, id));
+ return;
+ }
+
+ MessageList removed;
+ thread->Clear(this, id, &removed);
+ for (MessageList::iterator it = removed.begin(); it != removed.end(); ++it) {
+ // This message was pending on this thread, so run it now.
+ thread->Send(it->phandler,
+ it->message_id,
+ it->pdata);
+ }
+}
+
+void AsyncInvoker::DoInvoke(Thread* thread, AsyncClosure* closure,
+ uint32 id) {
+ if (destroying_) {
+ LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
+ // Since this call transwers ownership of |closure|, we clean it up here.
+ delete closure;
+ return;
+ }
+ thread->Post(this, id, new ScopedRefMessageData<AsyncClosure>(closure));
+}
+
+NotifyingAsyncClosureBase::NotifyingAsyncClosureBase(AsyncInvoker* invoker,
+ Thread* calling_thread)
+ : invoker_(invoker), calling_thread_(calling_thread) {
+ calling_thread->SignalQueueDestroyed.connect(
+ this, &NotifyingAsyncClosureBase::CancelCallback);
+ invoker->SignalInvokerDestroyed.connect(
+ this, &NotifyingAsyncClosureBase::CancelCallback);
+}
+
+void NotifyingAsyncClosureBase::TriggerCallback() {
+ CritScope cs(&crit_);
+ if (!CallbackCanceled() && !callback_.empty()) {
+ invoker_->AsyncInvoke<void>(calling_thread_, callback_);
+ }
+}
+
+void NotifyingAsyncClosureBase::CancelCallback() {
+ // If the callback is triggering when this is called, block the
+ // destructor of the dying object here by waiting until the callback
+ // is done triggering.
+ CritScope cs(&crit_);
+ // calling_thread_ == NULL means do not trigger the callback.
+ calling_thread_ = NULL;
+}
+
+} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/asyncinvoker.h b/chromium/third_party/libjingle/source/talk/base/asyncinvoker.h
new file mode 100644
index 00000000000..b7dfac98381
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/asyncinvoker.h
@@ -0,0 +1,151 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_BASE_ASYNCINVOKER_H_
+#define TALK_BASE_ASYNCINVOKER_H_
+
+#include "talk/base/asyncinvoker-inl.h"
+#include "talk/base/bind.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/scopedptrcollection.h"
+#include "talk/base/thread.h"
+
+namespace talk_base {
+
+// Invokes function objects (aka functors) asynchronously on a Thread, and
+// owns the lifetime of calls (ie, when this object is destroyed, calls in
+// flight are cancelled). AsyncInvoker can optionally execute a user-specified
+// function when the asynchronous call is complete, or operates in
+// fire-and-forget mode otherwise.
+//
+// AsyncInvoker does not own the thread it calls functors on.
+//
+// A note about async calls and object lifetimes: users should
+// be mindful of object lifetimes when calling functions asynchronously and
+// ensure objects used by the function _cannot_ be deleted between the
+// invocation and execution of the functor. AsyncInvoker is designed to
+// help: any calls in flight will be cancelled when the AsyncInvoker used to
+// make the call is destructed, and any calls executing will be allowed to
+// complete before AsyncInvoker destructs.
+//
+// The easiest way to ensure lifetimes are handled correctly is to create a
+// class that owns the Thread and AsyncInvoker objects, and then call its
+// methods asynchronously as needed.
+//
+// Example:
+// class MyClass {
+// public:
+// void FireAsyncTaskWithResult(Thread* thread, int x) {
+// // Specify a callback to get the result upon completion.
+// invoker_.AsyncInvoke<int>(
+// thread, Bind(&MyClass::AsyncTaskWithResult, this, x),
+// &MyClass::OnTaskComplete, this);
+// }
+// void FireAnotherAsyncTask(Thread* thread) {
+// // No callback specified means fire-and-forget.
+// invoker_.AsyncInvoke<void>(
+// thread, Bind(&MyClass::AnotherAsyncTask, this));
+//
+// private:
+// int AsyncTaskWithResult(int x) {
+// // Some long running process...
+// return x * x;
+// }
+// void AnotherAsyncTask() {
+// // Some other long running process...
+// }
+// void OnTaskComplete(int result) { result_ = result; }
+//
+// AsyncInvoker invoker_;
+// int result_;
+// };
+class AsyncInvoker : public MessageHandler {
+ public:
+ AsyncInvoker();
+ virtual ~AsyncInvoker();
+
+ // Call |functor| asynchronously on |thread|, with no callback upon
+ // completion. Returns immediately.
+ template <class ReturnT, class FunctorT>
+ void AsyncInvoke(Thread* thread,
+ const FunctorT& functor,
+ uint32 id = 0) {
+ AsyncClosure* closure =
+ new RefCountedObject<FireAndForgetAsyncClosure<FunctorT> >(functor);
+ DoInvoke(thread, closure, id);
+ }
+
+ // Call |functor| asynchronously on |thread|, calling |callback| when done.
+ template <class ReturnT, class FunctorT, class HostT>
+ void AsyncInvoke(Thread* thread,
+ const FunctorT& functor,
+ void (HostT::*callback)(ReturnT),
+ HostT* callback_host,
+ uint32 id = 0) {
+ AsyncClosure* closure =
+ new RefCountedObject<NotifyingAsyncClosure<ReturnT, FunctorT, HostT> >(
+ this, Thread::Current(), functor, callback, callback_host);
+ DoInvoke(thread, closure, id);
+ }
+
+ // Call |functor| asynchronously on |thread|, calling |callback| when done.
+ // Overloaded for void return.
+ template <class ReturnT, class FunctorT, class HostT>
+ void AsyncInvoke(Thread* thread,
+ const FunctorT& functor,
+ void (HostT::*callback)(),
+ HostT* callback_host,
+ uint32 id = 0) {
+ AsyncClosure* closure =
+ new RefCountedObject<NotifyingAsyncClosure<void, FunctorT, HostT> >(
+ this, Thread::Current(), functor, callback, callback_host);
+ DoInvoke(thread, closure, id);
+ }
+
+ // Synchronously execute on |thread| all outstanding calls we own
+ // that are pending on |thread|, and wait for calls to complete
+ // before returning. Optionally filter by message id.
+ // The destructor will not wait for outstanding calls, so if that
+ // behavior is desired, call Flush() before destroying this object.
+ void Flush(Thread* thread, uint32 id = MQID_ANY);
+
+ // Signaled when this object is destructed.
+ sigslot::signal0<> SignalInvokerDestroyed;
+
+ private:
+ virtual void OnMessage(Message* msg);
+ void DoInvoke(Thread* thread, AsyncClosure* closure, uint32 id);
+
+ bool destroying_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncInvoker);
+};
+
+} // namespace talk_base
+
+
+#endif // TALK_BASE_ASYNCINVOKER_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/asyncpacketsocket.h b/chromium/third_party/libjingle/source/talk/base/asyncpacketsocket.h
index 29ab55ffc47..091f1d0fe71 100644
--- a/chromium/third_party/libjingle/source/talk/base/asyncpacketsocket.h
+++ b/chromium/third_party/libjingle/source/talk/base/asyncpacketsocket.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -35,6 +35,31 @@
namespace talk_base {
+// This structure holds the info needed to update the packet send time header
+// extension, including the information needed to update the authentication tag
+// after changing the value.
+struct PacketTimeUpdateParams {
+ PacketTimeUpdateParams()
+ : rtp_sendtime_extension_id(-1), srtp_auth_tag_len(-1),
+ srtp_packet_index(-1) {
+ }
+
+ int rtp_sendtime_extension_id; // extension header id present in packet.
+ std::vector<char> srtp_auth_key; // Authentication key.
+ int srtp_auth_tag_len; // Authentication tag length.
+ int64 srtp_packet_index; // Required for Rtp Packet authentication.
+};
+
+// This structure holds meta information for the packet which is about to send
+// over network.
+struct PacketOptions {
+ PacketOptions() : dscp(DSCP_NO_CHANGE) {}
+ explicit PacketOptions(DiffServCodePoint dscp) : dscp(dscp) {}
+
+ DiffServCodePoint dscp;
+ PacketTimeUpdateParams packet_time_params;
+};
+
// This structure will have the information about when packet is actually
// received by socket.
struct PacketTime {
@@ -78,9 +103,9 @@ class AsyncPacketSocket : public sigslot::has_slots<> {
virtual SocketAddress GetRemoteAddress() const = 0;
// Send a packet.
- virtual int Send(const void *pv, size_t cb, DiffServCodePoint dscp) = 0;
+ virtual int Send(const void *pv, size_t cb, const PacketOptions& options) = 0;
virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
- DiffServCodePoint) = 0;
+ const PacketOptions& options) = 0;
// Close the socket.
virtual int Close() = 0;
diff --git a/chromium/third_party/libjingle/source/talk/base/asynctcpsocket.cc b/chromium/third_party/libjingle/source/talk/base/asynctcpsocket.cc
index d2ae513fd57..781fb0adee4 100644
--- a/chromium/third_party/libjingle/source/talk/base/asynctcpsocket.cc
+++ b/chromium/third_party/libjingle/source/talk/base/asynctcpsocket.cc
@@ -27,7 +27,7 @@
#include "talk/base/asynctcpsocket.h"
-#include <cstring>
+#include <string.h>
#include "talk/base/byteorder.h"
#include "talk/base/common.h"
@@ -141,12 +141,11 @@ void AsyncTCPSocketBase::SetError(int error) {
return socket_->SetError(error);
}
-// TODO(mallinath) - Add support of setting DSCP code on AsyncSocket.
int AsyncTCPSocketBase::SendTo(const void *pv, size_t cb,
const SocketAddress& addr,
- DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
if (addr == GetRemoteAddress())
- return Send(pv, cb, dscp);
+ return Send(pv, cb, options);
ASSERT(false);
socket_->SetError(ENOTCONN);
@@ -263,8 +262,8 @@ AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket, bool listen)
: AsyncTCPSocketBase(socket, listen, kBufSize) {
}
-// TODO(mallinath) - Add support of setting DSCP code on AsyncSocket.
-int AsyncTCPSocket::Send(const void *pv, size_t cb, DiffServCodePoint dscp) {
+int AsyncTCPSocket::Send(const void *pv, size_t cb,
+ const talk_base::PacketOptions& options) {
if (cb > kBufSize) {
SetError(EMSGSIZE);
return -1;
diff --git a/chromium/third_party/libjingle/source/talk/base/asynctcpsocket.h b/chromium/third_party/libjingle/source/talk/base/asynctcpsocket.h
index a0e7a7e2f41..2b795f64f9e 100644
--- a/chromium/third_party/libjingle/source/talk/base/asynctcpsocket.h
+++ b/chromium/third_party/libjingle/source/talk/base/asynctcpsocket.h
@@ -43,7 +43,8 @@ class AsyncTCPSocketBase : public AsyncPacketSocket {
virtual ~AsyncTCPSocketBase();
// Pure virtual methods to send and recv data.
- virtual int Send(const void *pv, size_t cb, DiffServCodePoint dscp) = 0;
+ virtual int Send(const void *pv, size_t cb,
+ const talk_base::PacketOptions& options) = 0;
virtual void ProcessInput(char* data, size_t* len) = 0;
// Signals incoming connection.
virtual void HandleIncomingConnection(AsyncSocket* socket) = 0;
@@ -51,7 +52,7 @@ class AsyncTCPSocketBase : public AsyncPacketSocket {
virtual SocketAddress GetLocalAddress() const;
virtual SocketAddress GetRemoteAddress() const;
virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
- DiffServCodePoint dscp);
+ const talk_base::PacketOptions& options);
virtual int Close();
virtual State GetState() const;
@@ -102,7 +103,8 @@ class AsyncTCPSocket : public AsyncTCPSocketBase {
AsyncTCPSocket(AsyncSocket* socket, bool listen);
virtual ~AsyncTCPSocket() {}
- virtual int Send(const void* pv, size_t cb, DiffServCodePoint dscp);
+ virtual int Send(const void* pv, size_t cb,
+ const talk_base::PacketOptions& options);
virtual void ProcessInput(char* data, size_t* len);
virtual void HandleIncomingConnection(AsyncSocket* socket);
diff --git a/chromium/third_party/libjingle/source/talk/base/asyncudpsocket.cc b/chromium/third_party/libjingle/source/talk/base/asyncudpsocket.cc
index 50052630d99..367287f800d 100644
--- a/chromium/third_party/libjingle/source/talk/base/asyncudpsocket.cc
+++ b/chromium/third_party/libjingle/source/talk/base/asyncudpsocket.cc
@@ -75,14 +75,14 @@ SocketAddress AsyncUDPSocket::GetRemoteAddress() const {
return socket_->GetRemoteAddress();
}
-// TODO(mallinath) - Add support of setting DSCP code on AsyncSocket.
-int AsyncUDPSocket::Send(const void *pv, size_t cb, DiffServCodePoint dscp) {
+int AsyncUDPSocket::Send(const void *pv, size_t cb,
+ const talk_base::PacketOptions& options) {
return socket_->Send(pv, cb);
}
-// TODO(mallinath) - Add support of setting DSCP code on AsyncSocket.
int AsyncUDPSocket::SendTo(const void *pv, size_t cb,
- const SocketAddress& addr, DiffServCodePoint dscp) {
+ const SocketAddress& addr,
+ const talk_base::PacketOptions& options) {
return socket_->SendTo(pv, cb, addr);
}
diff --git a/chromium/third_party/libjingle/source/talk/base/asyncudpsocket.h b/chromium/third_party/libjingle/source/talk/base/asyncudpsocket.h
index 17e12a26c31..17fb043a39e 100644
--- a/chromium/third_party/libjingle/source/talk/base/asyncudpsocket.h
+++ b/chromium/third_party/libjingle/source/talk/base/asyncudpsocket.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -52,9 +52,10 @@ class AsyncUDPSocket : public AsyncPacketSocket {
virtual SocketAddress GetLocalAddress() const;
virtual SocketAddress GetRemoteAddress() const;
- virtual int Send(const void *pv, size_t cb, DiffServCodePoint dscp);
+ virtual int Send(const void *pv, size_t cb,
+ const talk_base::PacketOptions& options);
virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
- DiffServCodePoint dscp);
+ const talk_base::PacketOptions& options);
virtual int Close();
virtual State GetState() const;
diff --git a/chromium/third_party/libjingle/source/talk/base/bandwidthsmoother.cc b/chromium/third_party/libjingle/source/talk/base/bandwidthsmoother.cc
index 39164884d40..edb4edab743 100644
--- a/chromium/third_party/libjingle/source/talk/base/bandwidthsmoother.cc
+++ b/chromium/third_party/libjingle/source/talk/base/bandwidthsmoother.cc
@@ -62,7 +62,7 @@ bool BandwidthSmoother::Sample(uint32 sample_time, int bandwidth) {
}
// Replace bandwidth with the mean of sampled bandwidths.
- const int mean_bandwidth = accumulator_.ComputeMean();
+ const int mean_bandwidth = static_cast<int>(accumulator_.ComputeMean());
if (mean_bandwidth < bandwidth_estimation_) {
time_at_last_change_ = sample_time;
diff --git a/chromium/third_party/libjingle/source/talk/base/bind.h b/chromium/third_party/libjingle/source/talk/base/bind.h
index 622cc679db1..5b4eaac943b 100644
--- a/chromium/third_party/libjingle/source/talk/base/bind.h
+++ b/chromium/third_party/libjingle/source/talk/base/bind.h
@@ -84,6 +84,18 @@ class MethodFunctor0 {
ObjectT* object_;
};
+template <class FunctorT, class R>
+class Functor0 {
+ public:
+ explicit Functor0(const FunctorT& functor)
+ : functor_(functor) {}
+ R operator()() const {
+ return functor_(); }
+ private:
+ FunctorT functor_;
+};
+
+
#define FP_T(x) R (ObjectT::*x)()
template <class ObjectT, class R>
@@ -104,6 +116,16 @@ Bind(FP_T(method), const ObjectT* object) {
}
#undef FP_T
+#define FP_T(x) R (*x)()
+
+template <class R>
+Functor0<FP_T(NONAME), R>
+Bind(FP_T(function)) {
+ return Functor0<FP_T(NONAME), R>(
+ function);
+}
+
+#undef FP_T
template <class ObjectT, class MethodT, class R,
class P1>
@@ -121,6 +143,21 @@ class MethodFunctor1 {
P1 p1_;
};
+template <class FunctorT, class R,
+ class P1>
+class Functor1 {
+ public:
+ Functor1(const FunctorT& functor, P1 p1)
+ : functor_(functor),
+ p1_(p1) {}
+ R operator()() const {
+ return functor_(p1_); }
+ private:
+ FunctorT functor_;
+ P1 p1_;
+};
+
+
#define FP_T(x) R (ObjectT::*x)(P1)
template <class ObjectT, class R,
@@ -145,6 +182,18 @@ Bind(FP_T(method), const ObjectT* object,
}
#undef FP_T
+#define FP_T(x) R (*x)(P1)
+
+template <class R,
+ class P1>
+Functor1<FP_T(NONAME), R, P1>
+Bind(FP_T(function),
+ typename detail::identity<P1>::type p1) {
+ return Functor1<FP_T(NONAME), R, P1>(
+ function, p1);
+}
+
+#undef FP_T
template <class ObjectT, class MethodT, class R,
class P1,
@@ -166,6 +215,24 @@ class MethodFunctor2 {
P2 p2_;
};
+template <class FunctorT, class R,
+ class P1,
+ class P2>
+class Functor2 {
+ public:
+ Functor2(const FunctorT& functor, P1 p1, P2 p2)
+ : functor_(functor),
+ p1_(p1),
+ p2_(p2) {}
+ R operator()() const {
+ return functor_(p1_, p2_); }
+ private:
+ FunctorT functor_;
+ P1 p1_;
+ P2 p2_;
+};
+
+
#define FP_T(x) R (ObjectT::*x)(P1, P2)
template <class ObjectT, class R,
@@ -194,6 +261,20 @@ Bind(FP_T(method), const ObjectT* object,
}
#undef FP_T
+#define FP_T(x) R (*x)(P1, P2)
+
+template <class R,
+ class P1,
+ class P2>
+Functor2<FP_T(NONAME), R, P1, P2>
+Bind(FP_T(function),
+ typename detail::identity<P1>::type p1,
+ typename detail::identity<P2>::type p2) {
+ return Functor2<FP_T(NONAME), R, P1, P2>(
+ function, p1, p2);
+}
+
+#undef FP_T
template <class ObjectT, class MethodT, class R,
class P1,
@@ -219,6 +300,27 @@ class MethodFunctor3 {
P3 p3_;
};
+template <class FunctorT, class R,
+ class P1,
+ class P2,
+ class P3>
+class Functor3 {
+ public:
+ Functor3(const FunctorT& functor, P1 p1, P2 p2, P3 p3)
+ : functor_(functor),
+ p1_(p1),
+ p2_(p2),
+ p3_(p3) {}
+ R operator()() const {
+ return functor_(p1_, p2_, p3_); }
+ private:
+ FunctorT functor_;
+ P1 p1_;
+ P2 p2_;
+ P3 p3_;
+};
+
+
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3)
template <class ObjectT, class R,
@@ -251,6 +353,22 @@ Bind(FP_T(method), const ObjectT* object,
}
#undef FP_T
+#define FP_T(x) R (*x)(P1, P2, P3)
+
+template <class R,
+ class P1,
+ class P2,
+ class P3>
+Functor3<FP_T(NONAME), R, P1, P2, P3>
+Bind(FP_T(function),
+ typename detail::identity<P1>::type p1,
+ typename detail::identity<P2>::type p2,
+ typename detail::identity<P3>::type p3) {
+ return Functor3<FP_T(NONAME), R, P1, P2, P3>(
+ function, p1, p2, p3);
+}
+
+#undef FP_T
template <class ObjectT, class MethodT, class R,
class P1,
@@ -280,6 +398,30 @@ class MethodFunctor4 {
P4 p4_;
};
+template <class FunctorT, class R,
+ class P1,
+ class P2,
+ class P3,
+ class P4>
+class Functor4 {
+ public:
+ Functor4(const FunctorT& functor, P1 p1, P2 p2, P3 p3, P4 p4)
+ : functor_(functor),
+ p1_(p1),
+ p2_(p2),
+ p3_(p3),
+ p4_(p4) {}
+ R operator()() const {
+ return functor_(p1_, p2_, p3_, p4_); }
+ private:
+ FunctorT functor_;
+ P1 p1_;
+ P2 p2_;
+ P3 p3_;
+ P4 p4_;
+};
+
+
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4)
template <class ObjectT, class R,
@@ -316,6 +458,24 @@ Bind(FP_T(method), const ObjectT* object,
}
#undef FP_T
+#define FP_T(x) R (*x)(P1, P2, P3, P4)
+
+template <class R,
+ class P1,
+ class P2,
+ class P3,
+ class P4>
+Functor4<FP_T(NONAME), R, P1, P2, P3, P4>
+Bind(FP_T(function),
+ typename detail::identity<P1>::type p1,
+ typename detail::identity<P2>::type p2,
+ typename detail::identity<P3>::type p3,
+ typename detail::identity<P4>::type p4) {
+ return Functor4<FP_T(NONAME), R, P1, P2, P3, P4>(
+ function, p1, p2, p3, p4);
+}
+
+#undef FP_T
template <class ObjectT, class MethodT, class R,
class P1,
@@ -349,6 +509,33 @@ class MethodFunctor5 {
P5 p5_;
};
+template <class FunctorT, class R,
+ class P1,
+ class P2,
+ class P3,
+ class P4,
+ class P5>
+class Functor5 {
+ public:
+ Functor5(const FunctorT& functor, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
+ : functor_(functor),
+ p1_(p1),
+ p2_(p2),
+ p3_(p3),
+ p4_(p4),
+ p5_(p5) {}
+ R operator()() const {
+ return functor_(p1_, p2_, p3_, p4_, p5_); }
+ private:
+ FunctorT functor_;
+ P1 p1_;
+ P2 p2_;
+ P3 p3_;
+ P4 p4_;
+ P5 p5_;
+};
+
+
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4, P5)
template <class ObjectT, class R,
@@ -389,6 +576,26 @@ Bind(FP_T(method), const ObjectT* object,
}
#undef FP_T
+#define FP_T(x) R (*x)(P1, P2, P3, P4, P5)
+
+template <class R,
+ class P1,
+ class P2,
+ class P3,
+ class P4,
+ class P5>
+Functor5<FP_T(NONAME), R, P1, P2, P3, P4, P5>
+Bind(FP_T(function),
+ typename detail::identity<P1>::type p1,
+ typename detail::identity<P2>::type p2,
+ typename detail::identity<P3>::type p3,
+ typename detail::identity<P4>::type p4,
+ typename detail::identity<P5>::type p5) {
+ return Functor5<FP_T(NONAME), R, P1, P2, P3, P4, P5>(
+ function, p1, p2, p3, p4, p5);
+}
+
+#undef FP_T
} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/bind.h.pump b/chromium/third_party/libjingle/source/talk/base/bind.h.pump
index 7f4c39e6344..2ebb8955159 100644
--- a/chromium/third_party/libjingle/source/talk/base/bind.h.pump
+++ b/chromium/third_party/libjingle/source/talk/base/bind.h.pump
@@ -91,6 +91,24 @@ class MethodFunctor$i {
};
+template <class FunctorT, class R$for j [[,
+ class P$j]]>
+class Functor$i {
+ public:
+ $if i == 0 [[explicit ]]
+Functor$i(const FunctorT& functor$for j [[, P$j p$j]])
+ : functor_(functor)$for j [[,
+ p$(j)_(p$j)]] {}
+ R operator()() const {
+ return functor_($for j , [[p$(j)_]]); }
+ private:
+ FunctorT functor_;$for j [[
+
+ P$j p$(j)_;]]
+
+};
+
+
#define FP_T(x) R (ObjectT::*x)($for j , [[P$j]])
template <class ObjectT, class R$for j [[,
@@ -115,6 +133,18 @@ Bind(FP_T(method), const ObjectT* object$for j [[,
}
#undef FP_T
+#define FP_T(x) R (*x)($for j , [[P$j]])
+
+template <class R$for j [[,
+ class P$j]]>
+Functor$i<FP_T(NONAME), R$for j [[, P$j]]>
+Bind(FP_T(function)$for j [[,
+ typename detail::identity<P$j>::type p$j]]) {
+ return Functor$i<FP_T(NONAME), R$for j [[, P$j]]>(
+ function$for j [[, p$j]]);
+}
+
+#undef FP_T
]]
diff --git a/chromium/third_party/libjingle/source/talk/base/bind_unittest.cc b/chromium/third_party/libjingle/source/talk/base/bind_unittest.cc
index 81bbddd6b70..78ac278376e 100644
--- a/chromium/third_party/libjingle/source/talk/base/bind_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/bind_unittest.cc
@@ -43,6 +43,10 @@ struct MethodBindTester {
mutable int call_count;
};
+int Return42() { return 42; }
+int Negate(int a) { return -a; }
+int Multiply(int a, int b) { return a * b; }
+
} // namespace
TEST(BindTest, BindToMethod) {
@@ -71,4 +75,10 @@ TEST(BindTest, BindToMethod) {
EXPECT_EQ(8, object.call_count);
}
+TEST(BindTest, BindToFunction) {
+ EXPECT_EQ(42, Bind(&Return42)());
+ EXPECT_EQ(3, Bind(&Negate, -3)());
+ EXPECT_EQ(56, Bind(&Multiply, 8, 7)());
+}
+
} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/buffer.h b/chromium/third_party/libjingle/source/talk/base/buffer.h
index 47096332c58..2d589f27ef4 100644
--- a/chromium/third_party/libjingle/source/talk/base/buffer.h
+++ b/chromium/third_party/libjingle/source/talk/base/buffer.h
@@ -28,7 +28,7 @@
#ifndef TALK_BASE_BUFFER_H_
#define TALK_BASE_BUFFER_H_
-#include <cstring>
+#include <string.h>
#include "talk/base/scoped_ptr.h"
diff --git a/chromium/third_party/libjingle/source/talk/base/bytebuffer.cc b/chromium/third_party/libjingle/source/talk/base/bytebuffer.cc
index 523475d82c4..396a1d34282 100644
--- a/chromium/third_party/libjingle/source/talk/base/bytebuffer.cc
+++ b/chromium/third_party/libjingle/source/talk/base/bytebuffer.cc
@@ -27,9 +27,10 @@
#include "talk/base/bytebuffer.h"
+#include <assert.h>
+#include <string.h>
+
#include <algorithm>
-#include <cassert>
-#include <cstring>
#include "talk/base/basictypes.h"
#include "talk/base/byteorder.h"
diff --git a/chromium/third_party/libjingle/source/talk/base/byteorder.h b/chromium/third_party/libjingle/source/talk/base/byteorder.h
index c6d0dbbe0ea..cf26a1292a6 100644
--- a/chromium/third_party/libjingle/source/talk/base/byteorder.h
+++ b/chromium/third_party/libjingle/source/talk/base/byteorder.h
@@ -28,7 +28,7 @@
#ifndef TALK_BASE_BYTEORDER_H_
#define TALK_BASE_BYTEORDER_H_
-#ifdef POSIX
+#if defined(POSIX) && !defined(__native_client__)
#include <arpa/inet.h>
#endif
diff --git a/chromium/third_party/libjingle/source/talk/base/callback.h b/chromium/third_party/libjingle/source/talk/base/callback.h
new file mode 100644
index 00000000000..11fbf86badb
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/callback.h
@@ -0,0 +1,278 @@
+// This file was GENERATED by command:
+// pump.py callback.h.pump
+// DO NOT EDIT BY HAND!!!
+
+/*
+ * libjingle
+ * Copyright 2012 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// To generate callback.h from callback.h.pump, execute:
+// /home/build/google3/third_party/gtest/scripts/pump.py callback.h.pump
+
+// Callbacks are callable object containers. They can hold a function pointer
+// or a function object and behave like a value type. Internally, data is
+// reference-counted, making copies and pass-by-value inexpensive.
+//
+// Callbacks are typed using template arguments. The format is:
+// CallbackN<ReturnType, ParamType1, ..., ParamTypeN>
+// where N is the number of arguments supplied to the callable object.
+// Callbacks are invoked using operator(), just like a function or a function
+// object. Default-constructed callbacks are "empty," and executing an empty
+// callback does nothing. A callback can be made empty by assigning it from
+// a default-constructed callback.
+//
+// Callbacks are similar in purpose to std::function (which isn't available on
+// all platforms we support) and a lightweight alternative to sigslots. Since
+// they effectively hide the type of the object they call, they're useful in
+// breaking dependencies between objects that need to interact with one another.
+// Notably, they can hold the results of Bind(), std::bind*, etc, without
+// needing
+// to know the resulting object type of those calls.
+//
+// Sigslots, on the other hand, provide a fuller feature set, such as multiple
+// subscriptions to a signal, optional thread-safety, and lifetime tracking of
+// slots. When these features are needed, choose sigslots.
+//
+// Example:
+// int sqr(int x) { return x * x; }
+// struct AddK {
+// int k;
+// int operator()(int x) const { return x + k; }
+// } add_k = {5};
+//
+// Callback1<int, int> my_callback;
+// cout << my_callback.empty() << endl; // true
+//
+// my_callback = Callback1<int, int>(&sqr);
+// cout << my_callback.empty() << endl; // false
+// cout << my_callback(3) << endl; // 9
+//
+// my_callback = Callback1<int, int>(add_k);
+// cout << my_callback(10) << endl; // 15
+//
+// my_callback = Callback1<int, int>();
+// cout << my_callback.empty() << endl; // true
+
+#ifndef TALK_BASE_CALLBACK_H_
+#define TALK_BASE_CALLBACK_H_
+
+#include "talk/base/logging.h"
+#include "talk/base/refcount.h"
+#include "talk/base/scoped_ref_ptr.h"
+
+namespace talk_base {
+
+template <class R>
+class Callback0 {
+ public:
+ // Default copy operations are appropriate for this class.
+ Callback0() {}
+ template <class T> Callback0(const T& functor)
+ : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+ R operator()() {
+ if (empty())
+ return R();
+ return helper_->Run();
+ }
+ bool empty() const { return !helper_; }
+
+ private:
+ struct Helper : RefCountInterface {
+ virtual ~Helper() {}
+ virtual R Run() = 0;
+ };
+ template <class T> struct HelperImpl : Helper {
+ explicit HelperImpl(const T& functor) : functor_(functor) {}
+ virtual R Run() {
+ return functor_();
+ }
+ T functor_;
+ };
+ scoped_refptr<Helper> helper_;
+};
+
+template <class R,
+ class P1>
+class Callback1 {
+ public:
+ // Default copy operations are appropriate for this class.
+ Callback1() {}
+ template <class T> Callback1(const T& functor)
+ : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+ R operator()(P1 p1) {
+ if (empty())
+ return R();
+ return helper_->Run(p1);
+ }
+ bool empty() const { return !helper_; }
+
+ private:
+ struct Helper : RefCountInterface {
+ virtual ~Helper() {}
+ virtual R Run(P1 p1) = 0;
+ };
+ template <class T> struct HelperImpl : Helper {
+ explicit HelperImpl(const T& functor) : functor_(functor) {}
+ virtual R Run(P1 p1) {
+ return functor_(p1);
+ }
+ T functor_;
+ };
+ scoped_refptr<Helper> helper_;
+};
+
+template <class R,
+ class P1,
+ class P2>
+class Callback2 {
+ public:
+ // Default copy operations are appropriate for this class.
+ Callback2() {}
+ template <class T> Callback2(const T& functor)
+ : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+ R operator()(P1 p1, P2 p2) {
+ if (empty())
+ return R();
+ return helper_->Run(p1, p2);
+ }
+ bool empty() const { return !helper_; }
+
+ private:
+ struct Helper : RefCountInterface {
+ virtual ~Helper() {}
+ virtual R Run(P1 p1, P2 p2) = 0;
+ };
+ template <class T> struct HelperImpl : Helper {
+ explicit HelperImpl(const T& functor) : functor_(functor) {}
+ virtual R Run(P1 p1, P2 p2) {
+ return functor_(p1, p2);
+ }
+ T functor_;
+ };
+ scoped_refptr<Helper> helper_;
+};
+
+template <class R,
+ class P1,
+ class P2,
+ class P3>
+class Callback3 {
+ public:
+ // Default copy operations are appropriate for this class.
+ Callback3() {}
+ template <class T> Callback3(const T& functor)
+ : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+ R operator()(P1 p1, P2 p2, P3 p3) {
+ if (empty())
+ return R();
+ return helper_->Run(p1, p2, p3);
+ }
+ bool empty() const { return !helper_; }
+
+ private:
+ struct Helper : RefCountInterface {
+ virtual ~Helper() {}
+ virtual R Run(P1 p1, P2 p2, P3 p3) = 0;
+ };
+ template <class T> struct HelperImpl : Helper {
+ explicit HelperImpl(const T& functor) : functor_(functor) {}
+ virtual R Run(P1 p1, P2 p2, P3 p3) {
+ return functor_(p1, p2, p3);
+ }
+ T functor_;
+ };
+ scoped_refptr<Helper> helper_;
+};
+
+template <class R,
+ class P1,
+ class P2,
+ class P3,
+ class P4>
+class Callback4 {
+ public:
+ // Default copy operations are appropriate for this class.
+ Callback4() {}
+ template <class T> Callback4(const T& functor)
+ : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+ R operator()(P1 p1, P2 p2, P3 p3, P4 p4) {
+ if (empty())
+ return R();
+ return helper_->Run(p1, p2, p3, p4);
+ }
+ bool empty() const { return !helper_; }
+
+ private:
+ struct Helper : RefCountInterface {
+ virtual ~Helper() {}
+ virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) = 0;
+ };
+ template <class T> struct HelperImpl : Helper {
+ explicit HelperImpl(const T& functor) : functor_(functor) {}
+ virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) {
+ return functor_(p1, p2, p3, p4);
+ }
+ T functor_;
+ };
+ scoped_refptr<Helper> helper_;
+};
+
+template <class R,
+ class P1,
+ class P2,
+ class P3,
+ class P4,
+ class P5>
+class Callback5 {
+ public:
+ // Default copy operations are appropriate for this class.
+ Callback5() {}
+ template <class T> Callback5(const T& functor)
+ : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+ R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+ if (empty())
+ return R();
+ return helper_->Run(p1, p2, p3, p4, p5);
+ }
+ bool empty() const { return !helper_; }
+
+ private:
+ struct Helper : RefCountInterface {
+ virtual ~Helper() {}
+ virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) = 0;
+ };
+ template <class T> struct HelperImpl : Helper {
+ explicit HelperImpl(const T& functor) : functor_(functor) {}
+ virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+ return functor_(p1, p2, p3, p4, p5);
+ }
+ T functor_;
+ };
+ scoped_refptr<Helper> helper_;
+};
+} // namespace talk_base
+
+#endif // TALK_BASE_CALLBACK_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/callback.h.pump b/chromium/third_party/libjingle/source/talk/base/callback.h.pump
new file mode 100644
index 00000000000..458eac73bf0
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/callback.h.pump
@@ -0,0 +1,120 @@
+/*
+ * libjingle
+ * Copyright 2012 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// To generate callback.h from callback.h.pump, execute:
+// /home/build/google3/third_party/gtest/scripts/pump.py callback.h.pump
+
+// Callbacks are callable object containers. They can hold a function pointer
+// or a function object and behave like a value type. Internally, data is
+// reference-counted, making copies and pass-by-value inexpensive.
+//
+// Callbacks are typed using template arguments. The format is:
+// CallbackN<ReturnType, ParamType1, ..., ParamTypeN>
+// where N is the number of arguments supplied to the callable object.
+// Callbacks are invoked using operator(), just like a function or a function
+// object. Default-constructed callbacks are "empty," and executing an empty
+// callback does nothing. A callback can be made empty by assigning it from
+// a default-constructed callback.
+//
+// Callbacks are similar in purpose to std::function (which isn't available on
+// all platforms we support) and a lightweight alternative to sigslots. Since
+// they effectively hide the type of the object they call, they're useful in
+// breaking dependencies between objects that need to interact with one another.
+// Notably, they can hold the results of Bind(), std::bind*, etc, without needing
+// to know the resulting object type of those calls.
+//
+// Sigslots, on the other hand, provide a fuller feature set, such as multiple
+// subscriptions to a signal, optional thread-safety, and lifetime tracking of
+// slots. When these features are needed, choose sigslots.
+//
+// Example:
+// int sqr(int x) { return x * x; }
+// struct AddK {
+// int k;
+// int operator()(int x) const { return x + k; }
+// } add_k = {5};
+//
+// Callback1<int, int> my_callback;
+// cout << my_callback.empty() << endl; // true
+//
+// my_callback = Callback1<int, int>(&sqr);
+// cout << my_callback.empty() << endl; // false
+// cout << my_callback(3) << endl; // 9
+//
+// my_callback = Callback1<int, int>(add_k);
+// cout << my_callback(10) << endl; // 15
+//
+// my_callback = Callback1<int, int>();
+// cout << my_callback.empty() << endl; // true
+
+#ifndef TALK_BASE_CALLBACK_H_
+#define TALK_BASE_CALLBACK_H_
+
+#include "talk/base/refcount.h"
+#include "talk/base/scoped_ref_ptr.h"
+
+namespace talk_base {
+
+$var n = 5
+$range i 0..n
+$for i [[
+$range j 1..i
+
+template <class R$for j [[,
+ class P$j]]>
+class Callback$i {
+ public:
+ // Default copy operations are appropriate for this class.
+ Callback$i() {}
+ template <class T> Callback$i(const T& functor)
+ : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+ R operator()($for j , [[P$j p$j]]) {
+ if (empty())
+ return R();
+ return helper_->Run($for j , [[p$j]]);
+ }
+ bool empty() const { return !helper_; }
+
+ private:
+ struct Helper : RefCountInterface {
+ virtual ~Helper() {}
+ virtual R Run($for j , [[P$j p$j]]) = 0;
+ };
+ template <class T> struct HelperImpl : Helper {
+ explicit HelperImpl(const T& functor) : functor_(functor) {}
+ virtual R Run($for j , [[P$j p$j]]) {
+ return functor_($for j , [[p$j]]);
+ }
+ T functor_;
+ };
+ scoped_refptr<Helper> helper_;
+};
+
+]]
+} // namespace talk_base
+
+#endif // TALK_BASE_CALLBACK_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/callback_unittest.cc b/chromium/third_party/libjingle/source/talk/base/callback_unittest.cc
new file mode 100644
index 00000000000..c7ca00f0fd2
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/callback_unittest.cc
@@ -0,0 +1,98 @@
+/*
+ * libjingle
+ * Copyright 2004--2011, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/bind.h"
+#include "talk/base/callback.h"
+#include "talk/base/gunit.h"
+
+namespace talk_base {
+
+namespace {
+
+void f() {}
+int g() { return 42; }
+int h(int x) { return x * x; }
+void i(int& x) { x *= x; } // NOLINT: Testing refs
+
+struct BindTester {
+ int a() { return 24; }
+ int b(int x) const { return x * x; }
+};
+
+} // namespace
+
+TEST(CallbackTest, VoidReturn) {
+ Callback0<void> cb;
+ EXPECT_TRUE(cb.empty());
+ cb(); // Executing an empty callback should not crash.
+ cb = Callback0<void>(&f);
+ EXPECT_FALSE(cb.empty());
+ cb();
+}
+
+TEST(CallbackTest, IntReturn) {
+ Callback0<int> cb;
+ EXPECT_TRUE(cb.empty());
+ cb = Callback0<int>(&g);
+ EXPECT_FALSE(cb.empty());
+ EXPECT_EQ(42, cb());
+ EXPECT_EQ(42, cb());
+}
+
+TEST(CallbackTest, OneParam) {
+ Callback1<int, int> cb1(&h);
+ EXPECT_FALSE(cb1.empty());
+ EXPECT_EQ(9, cb1(-3));
+ EXPECT_EQ(100, cb1(10));
+
+ // Try clearing a callback.
+ cb1 = Callback1<int, int>();
+ EXPECT_TRUE(cb1.empty());
+
+ // Try a callback with a ref parameter.
+ Callback1<void, int&> cb2(&i);
+ int x = 3;
+ cb2(x);
+ EXPECT_EQ(9, x);
+ cb2(x);
+ EXPECT_EQ(81, x);
+}
+
+TEST(CallbackTest, WithBind) {
+ BindTester t;
+ Callback0<int> cb1 = Bind(&BindTester::a, &t);
+ EXPECT_EQ(24, cb1());
+ EXPECT_EQ(24, cb1());
+ cb1 = Bind(&BindTester::b, &t, 10);
+ EXPECT_EQ(100, cb1());
+ EXPECT_EQ(100, cb1());
+ cb1 = Bind(&BindTester::b, &t, 5);
+ EXPECT_EQ(25, cb1());
+ EXPECT_EQ(25, cb1());
+}
+
+} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/common.cc b/chromium/third_party/libjingle/source/talk/base/common.cc
index 3c0c352a900..9f63aa4da99 100644
--- a/chromium/third_party/libjingle/source/talk/base/common.cc
+++ b/chromium/third_party/libjingle/source/talk/base/common.cc
@@ -28,7 +28,7 @@
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
-#include <memory.h>
+#include <string.h>
#if WIN32
#define WIN32_LEAN_AND_MEAN
@@ -78,4 +78,12 @@ void LogAssert(const char* function, const char* file, int line,
}
}
+bool IsOdd(int n) {
+ return (n & 0x1);
+}
+
+bool IsEven(int n) {
+ return !IsOdd(n);
+}
+
} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/common.h b/chromium/third_party/libjingle/source/talk/base/common.h
index a76748b3905..ed7d59ed676 100644
--- a/chromium/third_party/libjingle/source/talk/base/common.h
+++ b/chromium/third_party/libjingle/source/talk/base/common.h
@@ -61,8 +61,14 @@ inline void Unused(const void*) {}
#endif // UNUSED
#ifndef WIN32
+
+#ifndef strnicmp
#define strnicmp(x, y, n) strncasecmp(x, y, n)
+#endif
+
+#ifndef stricmp
#define stricmp(x, y) strcasecmp(x, y)
+#endif
// TODO(fbarchard): Remove this. std::max should be used everywhere in the code.
// NOMINMAX must be defined where we include <windows.h>.
@@ -87,6 +93,11 @@ inline void Unused(const void*) {}
namespace talk_base {
+
+// If a debugger is attached, triggers a debugger breakpoint. If a debugger is
+// not attached, forces program termination.
+void Break();
+
// LogAssert writes information about an assertion to the log. It's called by
// Assert (and from the ASSERT macro in debug mode) before any other action
// is taken (e.g. breaking the debugger, abort()ing, etc.).
@@ -105,17 +116,16 @@ typedef void (*AssertLogger)(const char* function,
// only by one component.
void SetCustomAssertLogger(AssertLogger logger);
-} // namespace talk_base
+bool IsOdd(int n);
+bool IsEven(int n);
+
+} // namespace talk_base
#if ENABLE_DEBUG
namespace talk_base {
-// If a debugger is attached, triggers a debugger breakpoint. If a debugger is
-// not attached, forces program termination.
-void Break();
-
inline bool Assert(bool result, const char* function, const char* file,
int line, const char* expression) {
if (!result) {
diff --git a/chromium/third_party/libjingle/source/talk/base/cpumonitor.cc b/chromium/third_party/libjingle/source/talk/base/cpumonitor.cc
index e9b481fdbd9..aaec77208d4 100644
--- a/chromium/third_party/libjingle/source/talk/base/cpumonitor.cc
+++ b/chromium/third_party/libjingle/source/talk/base/cpumonitor.cc
@@ -48,6 +48,7 @@
#if defined(IOS) || defined(OSX)
#include <mach/mach_host.h>
#include <mach/mach_init.h>
+#include <mach/mach_port.h>
#include <mach/host_info.h>
#include <mach/task.h>
#endif // defined(IOS) || defined(OSX)
@@ -241,11 +242,14 @@ float CpuSampler::GetSystemLoad() {
#endif // WIN32
#if defined(IOS) || defined(OSX)
+ mach_port_t mach_host = mach_host_self();
host_cpu_load_info_data_t cpu_info;
mach_msg_type_number_t info_count = HOST_CPU_LOAD_INFO_COUNT;
- if (KERN_SUCCESS != host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO,
- reinterpret_cast<host_info_t>(&cpu_info),
- &info_count)) {
+ kern_return_t kr = host_statistics(mach_host, HOST_CPU_LOAD_INFO,
+ reinterpret_cast<host_info_t>(&cpu_info),
+ &info_count);
+ mach_port_deallocate(mach_task_self(), mach_host);
+ if (KERN_SUCCESS != kr) {
LOG(LS_ERROR) << "::host_statistics() failed";
return 0.f;
}
diff --git a/chromium/third_party/libjingle/source/talk/base/cpumonitor_unittest.cc b/chromium/third_party/libjingle/source/talk/base/cpumonitor_unittest.cc
index b9f5ba33e77..cdc3e6b79b2 100644
--- a/chromium/third_party/libjingle/source/talk/base/cpumonitor_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/cpumonitor_unittest.cc
@@ -386,8 +386,8 @@ TEST(CpuMonitorTest, TestCpuMonitor) {
CpuLoadListener listener;
monitor.SignalUpdate.connect(&listener, &CpuLoadListener::OnCpuLoad);
EXPECT_TRUE(monitor.Start(10));
- Thread::Current()->ProcessMessages(50);
- EXPECT_GT(listener.count(), 2); // We have checked cpu load more than twice.
+ // We have checked cpu load more than twice.
+ EXPECT_TRUE_WAIT(listener.count() > 2, 1000);
EXPECT_GT(listener.current_cpus(), 0);
EXPECT_GT(listener.cpus(), 0);
EXPECT_GE(listener.process_load(), .0f);
diff --git a/chromium/third_party/libjingle/source/talk/base/criticalsection_unittest.cc b/chromium/third_party/libjingle/source/talk/base/criticalsection_unittest.cc
new file mode 100644
index 00000000000..0bb34b7026c
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/criticalsection_unittest.cc
@@ -0,0 +1,163 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <set>
+#include <vector>
+
+#include "talk/base/criticalsection.h"
+#include "talk/base/event.h"
+#include "talk/base/gunit.h"
+#include "talk/base/scopedptrcollection.h"
+#include "talk/base/thread.h"
+
+namespace talk_base {
+
+namespace {
+
+const int kLongTime = 10000; // 10 seconds
+const int kNumThreads = 16;
+const int kOperationsToRun = 1000;
+
+template <class T>
+class AtomicOpRunner : public MessageHandler {
+ public:
+ explicit AtomicOpRunner(int initial_value)
+ : value_(initial_value),
+ threads_active_(0),
+ start_event_(true, false),
+ done_event_(true, false) {}
+
+ int value() const { return value_; }
+
+ bool Run() {
+ // Signal all threads to start.
+ start_event_.Set();
+
+ // Wait for all threads to finish.
+ return done_event_.Wait(kLongTime);
+ }
+
+ void SetExpectedThreadCount(int count) {
+ threads_active_ = count;
+ }
+
+ virtual void OnMessage(Message* msg) {
+ std::vector<int> values;
+ values.reserve(kOperationsToRun);
+
+ // Wait to start.
+ ASSERT_TRUE(start_event_.Wait(kLongTime));
+
+ // Generate a bunch of values by updating value_ atomically.
+ for (int i = 0; i < kOperationsToRun; ++i) {
+ values.push_back(T::AtomicOp(&value_));
+ }
+
+ { // Add them all to the set.
+ CritScope cs(&all_values_crit_);
+ for (size_t i = 0; i < values.size(); ++i) {
+ std::pair<std::set<int>::iterator, bool> result =
+ all_values_.insert(values[i]);
+ // Each value should only be taken by one thread, so if this value
+ // has already been added, something went wrong.
+ EXPECT_TRUE(result.second)
+ << "Thread=" << Thread::Current() << " value=" << values[i];
+ }
+ }
+
+ // Signal that we're done.
+ if (AtomicOps::Decrement(&threads_active_) == 0) {
+ done_event_.Set();
+ }
+ }
+
+ private:
+ int value_;
+ int threads_active_;
+ CriticalSection all_values_crit_;
+ std::set<int> all_values_;
+ Event start_event_;
+ Event done_event_;
+};
+
+struct IncrementOp {
+ static int AtomicOp(int* i) { return AtomicOps::Increment(i); }
+};
+
+struct DecrementOp {
+ static int AtomicOp(int* i) { return AtomicOps::Decrement(i); }
+};
+
+void StartThreads(ScopedPtrCollection<Thread>* threads,
+ MessageHandler* handler) {
+ for (int i = 0; i < kNumThreads; ++i) {
+ Thread* thread = new Thread();
+ thread->Start();
+ thread->Post(handler);
+ threads->PushBack(thread);
+ }
+}
+
+} // namespace
+
+TEST(AtomicOpsTest, Simple) {
+ int value = 0;
+ EXPECT_EQ(1, AtomicOps::Increment(&value));
+ EXPECT_EQ(1, value);
+ EXPECT_EQ(2, AtomicOps::Increment(&value));
+ EXPECT_EQ(2, value);
+ EXPECT_EQ(1, AtomicOps::Decrement(&value));
+ EXPECT_EQ(1, value);
+ EXPECT_EQ(0, AtomicOps::Decrement(&value));
+ EXPECT_EQ(0, value);
+}
+
+TEST(AtomicOpsTest, Increment) {
+ // Create and start lots of threads.
+ AtomicOpRunner<IncrementOp> runner(0);
+ ScopedPtrCollection<Thread> threads;
+ StartThreads(&threads, &runner);
+ runner.SetExpectedThreadCount(kNumThreads);
+
+ // Release the hounds!
+ EXPECT_TRUE(runner.Run());
+ EXPECT_EQ(kOperationsToRun * kNumThreads, runner.value());
+}
+
+TEST(AtomicOpsTest, Decrement) {
+ // Create and start lots of threads.
+ AtomicOpRunner<DecrementOp> runner(kOperationsToRun * kNumThreads);
+ ScopedPtrCollection<Thread> threads;
+ StartThreads(&threads, &runner);
+ runner.SetExpectedThreadCount(kNumThreads);
+
+ // Release the hounds!
+ EXPECT_TRUE(runner.Run());
+ EXPECT_EQ(0, runner.value());
+}
+
+} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/cryptstring.h b/chromium/third_party/libjingle/source/talk/base/cryptstring.h
index eb39be229e0..600474f2adb 100644
--- a/chromium/third_party/libjingle/source/talk/base/cryptstring.h
+++ b/chromium/third_party/libjingle/source/talk/base/cryptstring.h
@@ -28,9 +28,11 @@
#ifndef _TALK_BASE_CRYPTSTRING_H_
#define _TALK_BASE_CRYPTSTRING_H_
-#include <cstring>
+#include <string.h>
+
#include <string>
#include <vector>
+
#include "talk/base/linked_ptr.h"
#include "talk/base/scoped_ptr.h"
diff --git a/chromium/third_party/libjingle/source/talk/base/event.cc b/chromium/third_party/libjingle/source/talk/base/event.cc
index 6089c8c9f94..410c65851f5 100644
--- a/chromium/third_party/libjingle/source/talk/base/event.cc
+++ b/chromium/third_party/libjingle/source/talk/base/event.cc
@@ -103,10 +103,16 @@ bool Event::Wait(int cms) {
// Converting from seconds and microseconds (1e-6) plus
// milliseconds (1e-3) to seconds and nanoseconds (1e-9).
+ struct timespec ts;
+#if HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
+ // Use relative time version, which tends to be more efficient for
+ // pthread implementations where provided (like on Android).
+ ts.tv_sec = cms / 1000;
+ ts.tv_nsec = (cms % 1000) * 1000000;
+#else
struct timeval tv;
gettimeofday(&tv, NULL);
- struct timespec ts;
ts.tv_sec = tv.tv_sec + (cms / 1000);
ts.tv_nsec = tv.tv_usec * 1000 + (cms % 1000) * 1000000;
@@ -115,9 +121,16 @@ bool Event::Wait(int cms) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
+#endif
- while (!event_status_ && error == 0)
+ while (!event_status_ && error == 0) {
+#if HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
+ error = pthread_cond_timedwait_relative_np(
+ &event_cond_, &event_mutex_, &ts);
+#else
error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts);
+#endif
+ }
} else {
while (!event_status_ && error == 0)
error = pthread_cond_wait(&event_cond_, &event_mutex_);
diff --git a/chromium/third_party/libjingle/source/talk/base/fakesslidentity.h b/chromium/third_party/libjingle/source/talk/base/fakesslidentity.h
index 203bb83bf0d..fbe5e648425 100644
--- a/chromium/third_party/libjingle/source/talk/base/fakesslidentity.h
+++ b/chromium/third_party/libjingle/source/talk/base/fakesslidentity.h
@@ -38,9 +38,12 @@ namespace talk_base {
class FakeSSLCertificate : public talk_base::SSLCertificate {
public:
- explicit FakeSSLCertificate(const std::string& data) : data_(data) {}
+ // SHA-1 is the default digest algorithm because it is available in all build
+ // configurations used for unit testing.
+ explicit FakeSSLCertificate(const std::string& data)
+ : data_(data), digest_algorithm_(DIGEST_SHA_1) {}
explicit FakeSSLCertificate(const std::vector<std::string>& certs)
- : data_(certs.front()) {
+ : data_(certs.front()), digest_algorithm_(DIGEST_SHA_1) {
std::vector<std::string>::const_iterator it;
// Skip certs[0].
for (it = certs.begin() + 1; it != certs.end(); ++it) {
@@ -58,15 +61,17 @@ class FakeSSLCertificate : public talk_base::SSLCertificate {
VERIFY(SSLIdentity::PemToDer(kPemTypeCertificate, data_, &der_string));
der_buffer->SetData(der_string.c_str(), der_string.size());
}
+ void set_digest_algorithm(const std::string& algorithm) {
+ digest_algorithm_ = algorithm;
+ }
virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const {
- // SHA-1 is chosen because it is available in all build configurations
- // used for unit testing.
- *algorithm = DIGEST_SHA_1;
+ *algorithm = digest_algorithm_;
return true;
}
- virtual bool ComputeDigest(const std::string &algorithm,
- unsigned char *digest, std::size_t size,
- std::size_t *length) const {
+ virtual bool ComputeDigest(const std::string& algorithm,
+ unsigned char* digest,
+ size_t size,
+ size_t* length) const {
*length = talk_base::ComputeDigest(algorithm, data_.c_str(), data_.size(),
digest, size);
return (*length != 0);
@@ -86,6 +91,7 @@ class FakeSSLCertificate : public talk_base::SSLCertificate {
}
std::string data_;
std::vector<FakeSSLCertificate> certs_;
+ std::string digest_algorithm_;
};
class FakeSSLIdentity : public talk_base::SSLIdentity {
diff --git a/chromium/third_party/libjingle/source/talk/base/fileutils.cc b/chromium/third_party/libjingle/source/talk/base/fileutils.cc
index ff34147db76..72797f3d0ff 100644
--- a/chromium/third_party/libjingle/source/talk/base/fileutils.cc
+++ b/chromium/third_party/libjingle/source/talk/base/fileutils.cc
@@ -25,9 +25,12 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <cassert>
+#include <assert.h>
#ifdef WIN32
+// TODO(grunell): Remove io.h includes when Chromium has started
+// to use AEC in each source. http://crbug.com/264611.
+#include <io.h>
#include "talk/base/win32.h"
#endif
@@ -294,4 +297,28 @@ bool CreateUniqueFile(Pathname& path, bool create_empty) {
return true;
}
+// Taken from Chromium's base/platform_file_*.cc.
+// TODO(grunell): Remove when Chromium has started to use AEC in each source.
+// http://crbug.com/264611.
+FILE* FdopenPlatformFileForWriting(PlatformFile file) {
+#if defined(WIN32)
+ if (file == kInvalidPlatformFileValue)
+ return NULL;
+ int fd = _open_osfhandle(reinterpret_cast<intptr_t>(file), 0);
+ if (fd < 0)
+ return NULL;
+ return _fdopen(fd, "w");
+#else
+ return fdopen(file, "w");
+#endif
+}
+
+bool ClosePlatformFile(PlatformFile file) {
+#if defined(WIN32)
+ return CloseHandle(file) != 0;
+#else
+ return close(file);
+#endif
+}
+
} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/fileutils.h b/chromium/third_party/libjingle/source/talk/base/fileutils.h
index 186c9633226..e58f76c7e9a 100644
--- a/chromium/third_party/libjingle/source/talk/base/fileutils.h
+++ b/chromium/third_party/libjingle/source/talk/base/fileutils.h
@@ -33,9 +33,10 @@
#ifdef WIN32
#include "talk/base/win32.h"
#else
-#include <sys/types.h>
#include <dirent.h>
+#include <stdio.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#endif
@@ -452,6 +453,24 @@ class FilesystemScope{
// process).
bool CreateUniqueFile(Pathname& path, bool create_empty);
+// Taken from Chromium's base/platform_file.h.
+// Don't use ClosePlatformFile to close a file opened with FdopenPlatformFile.
+// Use fclose instead.
+// TODO(grunell): Remove when Chromium has started to use AEC in each source.
+// http://crbug.com/264611.
+#if defined(WIN32)
+typedef HANDLE PlatformFile;
+const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
+#elif defined(POSIX)
+typedef int PlatformFile;
+const PlatformFile kInvalidPlatformFileValue = -1;
+#else
+#error Unsupported platform
+#endif
+
+FILE* FdopenPlatformFileForWriting(PlatformFile file);
+bool ClosePlatformFile(PlatformFile file);
+
} // namespace talk_base
#endif // TALK_BASE_FILEUTILS_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/firewallsocketserver.cc b/chromium/third_party/libjingle/source/talk/base/firewallsocketserver.cc
index be8f2e1831c..4a8a66d43e4 100644
--- a/chromium/third_party/libjingle/source/talk/base/firewallsocketserver.cc
+++ b/chromium/third_party/libjingle/source/talk/base/firewallsocketserver.cc
@@ -27,7 +27,8 @@
#include "talk/base/firewallsocketserver.h"
-#include <cassert>
+#include <assert.h>
+
#include <algorithm>
#include "talk/base/asyncsocket.h"
diff --git a/chromium/third_party/libjingle/source/talk/base/gunit.h b/chromium/third_party/libjingle/source/talk/base/gunit.h
index 3a0321468a7..e56dd6f617a 100644
--- a/chromium/third_party/libjingle/source/talk/base/gunit.h
+++ b/chromium/third_party/libjingle/source/talk/base/gunit.h
@@ -36,11 +36,6 @@
#include "testing/base/public/gunit.h"
#endif
-// forward declarations
-namespace talk_base {
-class Pathname;
-}
-
// Wait until "ex" is true, or "timeout" expires.
#define WAIT(ex, timeout) \
for (uint32 start = talk_base::Time(); \
@@ -107,6 +102,4 @@ class Pathname;
} \
} while (0);
-talk_base::Pathname GetTalkDirectory();
-
#endif // TALK_BASE_GUNIT_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/helpers.cc b/chromium/third_party/libjingle/source/talk/base/helpers.cc
index b10a3f742a7..691a8131f84 100644
--- a/chromium/third_party/libjingle/source/talk/base/helpers.cc
+++ b/chromium/third_party/libjingle/source/talk/base/helpers.cc
@@ -29,6 +29,7 @@
#include <limits>
+#if defined(FEATURE_ENABLE_SSL)
#include "talk/base/sslconfig.h"
#if defined(SSL_USE_OPENSSL)
#include <openssl/rand.h>
@@ -40,7 +41,8 @@
#include <windows.h>
#include <ntsecapi.h>
#endif // WIN32
-#endif
+#endif // else
+#endif // FEATURE_ENABLED_SSL
#include "talk/base/base64.h"
#include "talk/base/basictypes.h"
@@ -153,6 +155,28 @@ class SecureRandomGenerator : public RandomGenerator {
RtlGenRandomProc rtl_gen_random_;
};
+#elif !defined(FEATURE_ENABLE_SSL)
+
+// No SSL implementation -- use rand()
+class SecureRandomGenerator : public RandomGenerator {
+ public:
+ virtual bool Init(const void* seed, size_t len) {
+ if (len >= 4) {
+ srand(*reinterpret_cast<const int*>(seed));
+ } else {
+ srand(*reinterpret_cast<const char*>(seed));
+ }
+ return true;
+ }
+ virtual bool Generate(void* buf, size_t len) {
+ char* bytes = reinterpret_cast<char*>(buf);
+ for (size_t i = 0; i < len; ++i) {
+ bytes[i] = static_cast<char>(rand());
+ }
+ return true;
+ }
+};
+
#else
#error No SSL implementation has been selected!
diff --git a/chromium/third_party/libjingle/source/talk/base/helpers_unittest.cc b/chromium/third_party/libjingle/source/talk/base/helpers_unittest.cc
index 0fe1d5b36e1..c2cfdb193d3 100644
--- a/chromium/third_party/libjingle/source/talk/base/helpers_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/helpers_unittest.cc
@@ -29,14 +29,26 @@
#include "talk/base/gunit.h"
#include "talk/base/helpers.h"
+#include "talk/base/ssladapter.h"
namespace talk_base {
-TEST(RandomTest, TestCreateRandomId) {
+class RandomTest : public testing::Test {
+ public:
+ static void SetUpTestCase() {
+ talk_base::InitializeSSL();
+ }
+
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
+ }
+};
+
+TEST_F(RandomTest, TestCreateRandomId) {
CreateRandomId();
}
-TEST(RandomTest, TestCreateRandomDouble) {
+TEST_F(RandomTest, TestCreateRandomDouble) {
for (int i = 0; i < 100; ++i) {
double r = CreateRandomDouble();
EXPECT_GE(r, 0.0);
@@ -44,11 +56,11 @@ TEST(RandomTest, TestCreateRandomDouble) {
}
}
-TEST(RandomTest, TestCreateNonZeroRandomId) {
+TEST_F(RandomTest, TestCreateNonZeroRandomId) {
EXPECT_NE(0U, CreateRandomNonZeroId());
}
-TEST(RandomTest, TestCreateRandomString) {
+TEST_F(RandomTest, TestCreateRandomString) {
std::string random = CreateRandomString(256);
EXPECT_EQ(256U, random.size());
std::string random2;
@@ -57,7 +69,7 @@ TEST(RandomTest, TestCreateRandomString) {
EXPECT_EQ(256U, random2.size());
}
-TEST(RandomTest, TestCreateRandomForTest) {
+TEST_F(RandomTest, TestCreateRandomForTest) {
// Make sure we get the output we expect.
SetRandomTestMode(true);
EXPECT_EQ(2154761789U, CreateRandomId());
diff --git a/chromium/third_party/libjingle/source/talk/base/httpserver_unittest.cc b/chromium/third_party/libjingle/source/talk/base/httpserver_unittest.cc
index d0e0760af89..6e12cf51205 100644
--- a/chromium/third_party/libjingle/source/talk/base/httpserver_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/httpserver_unittest.cc
@@ -16,12 +16,6 @@ namespace {
"Host: localhost\r\n"
"\r\n";
- const char* const kResponse =
- "HTTP/1.1 200\r\n"
- "Connection: Close\r\n"
- "Content-Length: 0\r\n"
- "\r\n";
-
struct HttpServerMonitor : public sigslot::has_slots<> {
HttpServerTransaction* transaction;
bool server_closed, connection_closed;
diff --git a/chromium/third_party/libjingle/source/talk/base/iosfilesystem.mm b/chromium/third_party/libjingle/source/talk/base/iosfilesystem.mm
new file mode 100644
index 00000000000..aaefcb03fb5
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/iosfilesystem.mm
@@ -0,0 +1,70 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file only exists because various iOS system APIs are only
+// available from Objective-C. See unixfilesystem.cc for the only use
+// (enforced by a lack of a header file).
+
+#import <Foundation/NSPathUtilities.h>
+#import <Foundation/NSProcessInfo.h>
+#include <string.h>
+
+#include "talk/base/common.h"
+#include "talk/base/pathutils.h"
+
+// Return a new[]'d |char*| copy of the UTF8 representation of |s|.
+// Caller owns the returned memory and must use delete[] on it.
+static char* copyString(NSString* s) {
+ const char* utf8 = [s UTF8String];
+ size_t len = strlen(utf8) + 1;
+ char* copy = new char[len];
+ // This uses a new[] + strcpy (instead of strdup) because the
+ // receiver expects to be able to delete[] the returned pointer
+ // (instead of free()ing it).
+ strcpy(copy, utf8);
+ return copy;
+}
+
+// Return a (leaked) copy of a directory name suitable for application data.
+char* IOSDataDirectory() {
+ NSArray* paths = NSSearchPathForDirectoriesInDomains(
+ NSApplicationSupportDirectory, NSUserDomainMask, YES);
+ ASSERT([paths count] == 1);
+ return copyString([paths objectAtIndex:0]);
+}
+
+// Return a (leaked) copy of a directory name suitable for use as a $TEMP.
+char* IOSTempDirectory() {
+ return copyString(NSTemporaryDirectory());
+}
+
+// Return the binary's path.
+void IOSAppName(talk_base::Pathname* path) {
+ NSProcessInfo *pInfo = [NSProcessInfo processInfo];
+ NSString* argv0 = [[pInfo arguments] objectAtIndex:0];
+ path->SetPathname([argv0 UTF8String]);
+}
diff --git a/chromium/third_party/libjingle/source/talk/base/ipaddress.cc b/chromium/third_party/libjingle/source/talk/base/ipaddress.cc
index 46725908d7d..6c2212bf8b5 100644
--- a/chromium/third_party/libjingle/source/talk/base/ipaddress.cc
+++ b/chromium/third_party/libjingle/source/talk/base/ipaddress.cc
@@ -32,7 +32,9 @@
#ifdef OPENBSD
#include <netinet/in_systm.h>
#endif
+#ifndef __native_client__
#include <netinet/ip.h>
+#endif
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
@@ -49,13 +51,11 @@
namespace talk_base {
// Prefixes used for categorizing IPv6 addresses.
-static const in6_addr kULAPrefix = {{{0xfc, 0}}};
static const in6_addr kV4MappedPrefix = {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0xFF, 0xFF, 0}}};
static const in6_addr k6To4Prefix = {{{0x20, 0x02, 0}}};
static const in6_addr kTeredoPrefix = {{{0x20, 0x01, 0x00, 0x00}}};
static const in6_addr kV4CompatibilityPrefix = {{{0}}};
-static const in6_addr kSiteLocalPrefix = {{{0xfe, 0xc0, 0}}};
static const in6_addr k6BonePrefix = {{{0x3f, 0xfe, 0}}};
bool IPAddress::strip_sensitive_ = false;
diff --git a/chromium/third_party/libjingle/source/talk/base/ipaddress_unittest.cc b/chromium/third_party/libjingle/source/talk/base/ipaddress_unittest.cc
index 424b557cd63..2c03cbdbd06 100644
--- a/chromium/third_party/libjingle/source/talk/base/ipaddress_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/ipaddress_unittest.cc
@@ -42,18 +42,10 @@ static const in6_addr kIPv6PublicAddr = {{{0x24, 0x01, 0xfa, 0x00,
0x00, 0x04, 0x10, 0x00,
0xbe, 0x30, 0x5b, 0xff,
0xfe, 0xe5, 0x00, 0xc3}}};
-static const in6_addr kIPv6CompatAddr = {{{0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0xfe, 0xe5, 0x00, 0xc3}}};
static const in6_addr kIPv4MappedAnyAddr = {{{0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00}}};
-static const in6_addr kIPv4MappedLoopbackAddr = {{{0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xff, 0xff,
- 0x7f, 0x00, 0x00, 0x01}}};
static const in6_addr kIPv4MappedRFC1918Addr = {{{0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff,
@@ -62,10 +54,6 @@ static const in6_addr kIPv4MappedPublicAddr = {{{0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff,
0x01, 0x02, 0x03, 0x04}}};
-static const in6_addr kIPv6AllNodes = {{{0xff, 0x02, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01}}};
static const std::string kIPv4AnyAddrString = "0.0.0.0";
static const std::string kIPv4LoopbackAddrString = "127.0.0.1";
diff --git a/chromium/third_party/libjingle/source/talk/base/json.cc b/chromium/third_party/libjingle/source/talk/base/json.cc
index af81e06949c..6b9fce1ae91 100644
--- a/chromium/third_party/libjingle/source/talk/base/json.cc
+++ b/chromium/third_party/libjingle/source/talk/base/json.cc
@@ -28,9 +28,9 @@
#include "talk/base/json.h"
#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
-#include <climits>
-#include <cstdlib>
#include <sstream>
bool GetStringFromJson(const Json::Value& in, std::string* out) {
diff --git a/chromium/third_party/libjingle/source/talk/base/latebindingsymboltable.cc.def b/chromium/third_party/libjingle/source/talk/base/latebindingsymboltable.cc.def
index 1f84f30fc55..64fc0dce2b1 100644
--- a/chromium/third_party/libjingle/source/talk/base/latebindingsymboltable.cc.def
+++ b/chromium/third_party/libjingle/source/talk/base/latebindingsymboltable.cc.def
@@ -63,16 +63,17 @@
#error You must define LATE_BINDING_SYMBOL_TABLE_DLL_NAME
#endif
+#define X(sym) #sym,
+const char* const LATE_BINDING_SYMBOL_TABLE_CLASS_NAME::kSymbolNames[] = {
+ LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST
+};
+#undef X
+
const ::talk_base::LateBindingSymbolTable::TableInfo
LATE_BINDING_SYMBOL_TABLE_CLASS_NAME::kTableInfo = {
LATE_BINDING_SYMBOL_TABLE_DLL_NAME,
SYMBOL_TABLE_SIZE,
- (const char *const []){
-#define X(sym) \
- #sym,
-LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST
-#undef X
- },
+ LATE_BINDING_SYMBOL_TABLE_CLASS_NAME::kSymbolNames
};
LATE_BINDING_SYMBOL_TABLE_CLASS_NAME::LATE_BINDING_SYMBOL_TABLE_CLASS_NAME()
diff --git a/chromium/third_party/libjingle/source/talk/base/latebindingsymboltable.h.def b/chromium/third_party/libjingle/source/talk/base/latebindingsymboltable.h.def
index cd8c176f36b..3e1cdab599e 100644
--- a/chromium/third_party/libjingle/source/talk/base/latebindingsymboltable.h.def
+++ b/chromium/third_party/libjingle/source/talk/base/latebindingsymboltable.h.def
@@ -89,6 +89,7 @@ LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST
};
static const ::talk_base::LateBindingSymbolTable::TableInfo kTableInfo;
+ static const char *const kSymbolNames[];
void *table_[SYMBOL_TABLE_SIZE];
diff --git a/chromium/third_party/libjingle/source/talk/base/linux.cc b/chromium/third_party/libjingle/source/talk/base/linux.cc
index 644ec450655..16666f89761 100644
--- a/chromium/third_party/libjingle/source/talk/base/linux.cc
+++ b/chromium/third_party/libjingle/source/talk/base/linux.cc
@@ -250,6 +250,89 @@ bool ConfigParser::ParseLine(std::string* key, std::string* value) {
return true;
}
+#if !defined(GOOGLE_CHROME_BUILD) && !defined(CHROMIUM_BUILD)
+static bool ExpectLineFromStream(FileStream* stream,
+ std::string* out) {
+ StreamResult res = stream->ReadLine(out);
+ if (res != SR_SUCCESS) {
+ if (res != SR_EOS) {
+ LOG(LS_ERROR) << "Error when reading from stream";
+ } else {
+ LOG(LS_ERROR) << "Incorrect number of lines in stream";
+ }
+ return false;
+ }
+ return true;
+}
+
+static void ExpectEofFromStream(FileStream* stream) {
+ std::string unused;
+ StreamResult res = stream->ReadLine(&unused);
+ if (res == SR_SUCCESS) {
+ LOG(LS_WARNING) << "Ignoring unexpected extra lines from stream";
+ } else if (res != SR_EOS) {
+ LOG(LS_WARNING) << "Error when checking for extra lines from stream";
+ }
+}
+
+// For caching the lsb_release output (reading it invokes a sub-process and
+// hence is somewhat expensive).
+static std::string lsb_release_string;
+static CriticalSection lsb_release_string_critsec;
+
+std::string ReadLinuxLsbRelease() {
+ CritScope cs(&lsb_release_string_critsec);
+ if (!lsb_release_string.empty()) {
+ // Have cached result from previous call.
+ return lsb_release_string;
+ }
+ // No cached result. Run lsb_release and parse output.
+ POpenStream lsb_release_output;
+ if (!lsb_release_output.Open("lsb_release -idrcs", "r", NULL)) {
+ LOG_ERR(LS_ERROR) << "Can't run lsb_release";
+ return lsb_release_string; // empty
+ }
+ // Read in the command's output and build the string.
+ std::ostringstream sstr;
+ std::string line;
+ int wait_status;
+
+ if (!ExpectLineFromStream(&lsb_release_output, &line)) {
+ return lsb_release_string; // empty
+ }
+ sstr << "DISTRIB_ID=" << line;
+
+ if (!ExpectLineFromStream(&lsb_release_output, &line)) {
+ return lsb_release_string; // empty
+ }
+ sstr << " DISTRIB_DESCRIPTION=\"" << line << '"';
+
+ if (!ExpectLineFromStream(&lsb_release_output, &line)) {
+ return lsb_release_string; // empty
+ }
+ sstr << " DISTRIB_RELEASE=" << line;
+
+ if (!ExpectLineFromStream(&lsb_release_output, &line)) {
+ return lsb_release_string; // empty
+ }
+ sstr << " DISTRIB_CODENAME=" << line;
+
+ // Should not be anything left.
+ ExpectEofFromStream(&lsb_release_output);
+
+ lsb_release_output.Close();
+ wait_status = lsb_release_output.GetWaitStatus();
+ if (wait_status == -1 ||
+ !WIFEXITED(wait_status) ||
+ WEXITSTATUS(wait_status) != 0) {
+ LOG(LS_WARNING) << "Unexpected exit status from lsb_release";
+ }
+
+ lsb_release_string = sstr.str();
+
+ return lsb_release_string;
+}
+#endif
std::string ReadLinuxUname() {
struct utsname buf;
diff --git a/chromium/third_party/libjingle/source/talk/base/linux.h b/chromium/third_party/libjingle/source/talk/base/linux.h
index 63e30218140..46fa5ed6b27 100644
--- a/chromium/third_party/libjingle/source/talk/base/linux.h
+++ b/chromium/third_party/libjingle/source/talk/base/linux.h
@@ -121,6 +121,11 @@ class ProcCpuInfo {
ConfigParser::MapVector sections_;
};
+#if !defined(GOOGLE_CHROME_BUILD) && !defined(CHROMIUM_BUILD)
+// Builds a string containing the info from lsb_release on a single line.
+std::string ReadLinuxLsbRelease();
+#endif
+
// Returns the output of "uname".
std::string ReadLinuxUname();
diff --git a/chromium/third_party/libjingle/source/talk/base/linux_unittest.cc b/chromium/third_party/libjingle/source/talk/base/linux_unittest.cc
index efc7f87c1e4..f6815141d2b 100644
--- a/chromium/third_party/libjingle/source/talk/base/linux_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/linux_unittest.cc
@@ -105,6 +105,14 @@ TEST(ConfigParser, ParseConfig) {
EXPECT_EQ(true, parser.Parse(&key_val_pairs));
}
+#if !defined(GOOGLE_CHROME_BUILD) && !defined(CHROMIUM_BUILD)
+TEST(ReadLinuxLsbRelease, ReturnsSomething) {
+ std::string str = ReadLinuxLsbRelease();
+ // ChromeOS don't have lsb_release
+ // EXPECT_FALSE(str.empty());
+}
+#endif
+
TEST(ReadLinuxUname, ReturnsSomething) {
std::string str = ReadLinuxUname();
EXPECT_FALSE(str.empty());
diff --git a/chromium/third_party/libjingle/source/talk/base/logging.cc b/chromium/third_party/libjingle/source/talk/base/logging.cc
index 4c7eae172e7..c1d0a53baaf 100644
--- a/chromium/third_party/libjingle/source/talk/base/logging.cc
+++ b/chromium/third_party/libjingle/source/talk/base/logging.cc
@@ -349,6 +349,9 @@ void LogMessage::ConfigureLogging(const char* params, const char* filename) {
}
#endif // WIN32
+ LogToDebug(debug_level);
+
+#if !defined(__native_client__) // No logging to file in NaCl.
scoped_ptr<FileStream> stream;
if (NO_LOGGING != file_level) {
stream.reset(new FileStream);
@@ -357,8 +360,8 @@ void LogMessage::ConfigureLogging(const char* params, const char* filename) {
}
}
- LogToDebug(debug_level);
LogToStream(stream.release(), file_level);
+#endif
}
int LogMessage::ParseLogSeverity(const std::string& value) {
diff --git a/chromium/third_party/libjingle/source/talk/base/logging.h b/chromium/third_party/libjingle/source/talk/base/logging.h
index 49e126bab0c..01636e89fd6 100644
--- a/chromium/third_party/libjingle/source/talk/base/logging.h
+++ b/chromium/third_party/libjingle/source/talk/base/logging.h
@@ -376,6 +376,13 @@ inline bool LogCheckLevel(LoggingSeverity sev) {
LOG_GLE(sev)
#define LAST_SYSTEM_ERROR \
(::GetLastError())
+#elif __native_client__
+#define LOG_ERR_EX(sev, err) \
+ LOG(sev)
+#define LOG_ERR(sev) \
+ LOG(sev)
+#define LAST_SYSTEM_ERROR \
+ (0)
#elif POSIX
#define LOG_ERR_EX(sev, err) \
LOG_ERRNO_EX(sev, err)
diff --git a/chromium/third_party/libjingle/source/talk/base/maccocoasocketserver.h b/chromium/third_party/libjingle/source/talk/base/maccocoasocketserver.h
index f4aeb339768..51dc749d794 100644
--- a/chromium/third_party/libjingle/source/talk/base/maccocoasocketserver.h
+++ b/chromium/third_party/libjingle/source/talk/base/maccocoasocketserver.h
@@ -54,6 +54,8 @@ class MacCocoaSocketServer : public MacBaseSocketServer {
private:
MacCocoaSocketServerHelper* helper_;
NSTimer* timer_; // Weak.
+ // The count of how many times we're inside the NSApplication main loop.
+ int run_count_;
DISALLOW_EVIL_CONSTRUCTORS(MacCocoaSocketServer);
};
diff --git a/chromium/third_party/libjingle/source/talk/base/maccocoasocketserver.mm b/chromium/third_party/libjingle/source/talk/base/maccocoasocketserver.mm
index bf308e610e0..8257e386626 100644
--- a/chromium/third_party/libjingle/source/talk/base/maccocoasocketserver.mm
+++ b/chromium/third_party/libjingle/source/talk/base/maccocoasocketserver.mm
@@ -53,6 +53,25 @@
- (void)timerFired:(NSTimer*)timer {
socketServer_->WakeUp();
}
+
+- (void)breakMainloop {
+ [NSApp stop:self];
+ // NSApp stop only exits after finishing processing of the
+ // current event. Since we're potentially in a timer callback
+ // and not an NSEvent handler, we need to trigger a dummy one
+ // and turn the loop over. We may be able to skip this if we're
+ // on the ss' thread and not inside the app loop already.
+ NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined
+ location:NSMakePoint(0,0)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:0
+ context:nil
+ subtype:0
+ data1:0
+ data2:0];
+ [NSApp postEvent:event atStart:NO];
+}
@end
namespace talk_base {
@@ -60,6 +79,7 @@ namespace talk_base {
MacCocoaSocketServer::MacCocoaSocketServer() {
helper_ = [[MacCocoaSocketServerHelper alloc] initWithSocketServer:this];
timer_ = nil;
+ run_count_ = 0;
// Initialize the shared NSApplication
[NSApplication sharedApplication];
@@ -71,12 +91,19 @@ MacCocoaSocketServer::~MacCocoaSocketServer() {
[helper_ release];
}
+// ::Wait is reentrant, for example when blocking on another thread while
+// responding to I/O. Calls to [NSApp] MUST be made from the main thread
+// only!
bool MacCocoaSocketServer::Wait(int cms, bool process_io) {
talk_base::ScopedAutoreleasePool pool;
if (!process_io && cms == 0) {
// No op.
return true;
}
+ if ([NSApp isRunning]) {
+ // Only allow reentrant waiting if we're in a blocking send.
+ ASSERT(!process_io && cms == kForever);
+ }
if (!process_io) {
// No way to listen to common modes and not get socket events, unless
@@ -96,7 +123,9 @@ bool MacCocoaSocketServer::Wait(int cms, bool process_io) {
}
// Run until WakeUp is called, which will call stop and exit this loop.
+ run_count_++;
[NSApp run];
+ run_count_--;
if (!process_io) {
// Reenable them. Hopefully this won't cause spurious callbacks or
@@ -107,28 +136,22 @@ bool MacCocoaSocketServer::Wait(int cms, bool process_io) {
return true;
}
+// Can be called from any thread. Post a message back to the main thread to
+// break out of the NSApp loop.
void MacCocoaSocketServer::WakeUp() {
- // Timer has either fired or shortcutted.
- [timer_ invalidate];
- [timer_ release];
- timer_ = nil;
- [NSApp stop:nil];
+ if (timer_ != nil) {
+ [timer_ invalidate];
+ [timer_ release];
+ timer_ = nil;
+ }
- // NSApp stop only exits after finishing processing of the
- // current event. Since we're potentially in a timer callback
- // and not an NSEvent handler, we need to trigger a dummy one
- // and turn the loop over. We may be able to skip this if we're
- // on the ss' thread and not inside the app loop already.
- NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined
- location:NSMakePoint(0,0)
- modifierFlags:0
- timestamp:0
- windowNumber:0
- context:nil
- subtype:1
- data1:1
- data2:1];
- [NSApp postEvent:event atStart:YES];
+ // [NSApp isRunning] returns unexpected results when called from another
+ // thread. Maintain our own count of how many times to break the main loop.
+ if (run_count_ > 0) {
+ [helper_ performSelectorOnMainThread:@selector(breakMainloop)
+ withObject:nil
+ waitUntilDone:false];
+ }
}
} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/messagedigest.cc b/chromium/third_party/libjingle/source/talk/base/messagedigest.cc
index d91d0674b5f..975991db7c0 100644
--- a/chromium/third_party/libjingle/source/talk/base/messagedigest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/messagedigest.cc
@@ -70,6 +70,19 @@ MessageDigest* MessageDigestFactory::Create(const std::string& alg) {
#endif
}
+bool IsFips180DigestAlgorithm(const std::string& alg) {
+ // These are the FIPS 180 algorithms. According to RFC 4572 Section 5,
+ // "Self-signed certificates (for which legacy certificates are not a
+ // consideration) MUST use one of the FIPS 180 algorithms (SHA-1,
+ // SHA-224, SHA-256, SHA-384, or SHA-512) as their signature algorithm,
+ // and thus also MUST use it to calculate certificate fingerprints."
+ return alg == DIGEST_SHA_1 ||
+ alg == DIGEST_SHA_224 ||
+ alg == DIGEST_SHA_256 ||
+ alg == DIGEST_SHA_384 ||
+ alg == DIGEST_SHA_512;
+}
+
size_t ComputeDigest(MessageDigest* digest, const void* input, size_t in_len,
void* output, size_t out_len) {
digest->Update(input, in_len);
diff --git a/chromium/third_party/libjingle/source/talk/base/messagedigest.h b/chromium/third_party/libjingle/source/talk/base/messagedigest.h
index 734082b0166..e8f303f2666 100644
--- a/chromium/third_party/libjingle/source/talk/base/messagedigest.h
+++ b/chromium/third_party/libjingle/source/talk/base/messagedigest.h
@@ -60,6 +60,9 @@ class MessageDigestFactory {
static MessageDigest* Create(const std::string& alg);
};
+// A whitelist of approved digest algorithms from RFC 4572 (FIPS 180).
+bool IsFips180DigestAlgorithm(const std::string& alg);
+
// Functions to create hashes.
// Computes the hash of |in_len| bytes of |input|, using the |digest| hash
diff --git a/chromium/third_party/libjingle/source/talk/base/messagehandler.h b/chromium/third_party/libjingle/source/talk/base/messagehandler.h
index 913edf8ce26..6494f2b2561 100644
--- a/chromium/third_party/libjingle/source/talk/base/messagehandler.h
+++ b/chromium/third_party/libjingle/source/talk/base/messagehandler.h
@@ -38,16 +38,48 @@ struct Message;
class MessageHandler {
public:
+ virtual ~MessageHandler();
virtual void OnMessage(Message* msg) = 0;
protected:
MessageHandler() {}
- virtual ~MessageHandler();
private:
DISALLOW_COPY_AND_ASSIGN(MessageHandler);
};
+// Helper class to facilitate executing a functor on a thread.
+template <class ReturnT, class FunctorT>
+class FunctorMessageHandler : public MessageHandler {
+ public:
+ explicit FunctorMessageHandler(const FunctorT& functor)
+ : functor_(functor) {}
+ virtual void OnMessage(Message* msg) {
+ result_ = functor_();
+ }
+ const ReturnT& result() const { return result_; }
+
+ private:
+ FunctorT functor_;
+ ReturnT result_;
+};
+
+// Specialization for ReturnT of void.
+template <class FunctorT>
+class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
+ public:
+ explicit FunctorMessageHandler(const FunctorT& functor)
+ : functor_(functor) {}
+ virtual void OnMessage(Message* msg) {
+ functor_();
+ }
+ void result() const {}
+
+ private:
+ FunctorT functor_;
+};
+
+
} // namespace talk_base
#endif // TALK_BASE_MESSAGEHANDLER_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/messagequeue.cc b/chromium/third_party/libjingle/source/talk/base/messagequeue.cc
index 15b700ffe48..7bda92411c4 100644
--- a/chromium/third_party/libjingle/source/talk/base/messagequeue.cc
+++ b/chromium/third_party/libjingle/source/talk/base/messagequeue.cc
@@ -32,8 +32,13 @@
#include "talk/base/common.h"
#include "talk/base/logging.h"
#include "talk/base/messagequeue.h"
+#if defined(__native_client__)
+#include "talk/base/nullsocketserver.h"
+typedef talk_base::NullSocketServer DefaultSocketServer;
+#else
#include "talk/base/physicalsocketserver.h"
-
+typedef talk_base::PhysicalSocketServer DefaultSocketServer;
+#endif
namespace talk_base {
@@ -121,7 +126,7 @@ void MessageQueueManager::ClearInternal(MessageHandler *handler) {
// MessageQueue
MessageQueue::MessageQueue(SocketServer* ss)
- : ss_(ss), fStop_(false), fPeekKeep_(false), active_(false),
+ : ss_(ss), fStop_(false), fPeekKeep_(false),
dmsgq_next_num_(0) {
if (!ss_) {
// Currently, MessageQueue holds a socket server, and is the base class for
@@ -129,10 +134,11 @@ MessageQueue::MessageQueue(SocketServer* ss)
// server, and provide it to the MessageQueue, since the Thread controls
// the I/O model, and MQ is agnostic to those details. Anyway, this causes
// messagequeue_unittest to depend on network libraries... yuck.
- default_ss_.reset(new PhysicalSocketServer());
+ default_ss_.reset(new DefaultSocketServer());
ss_ = default_ss_.get();
}
ss_->SetMessageQueue(this);
+ MessageQueueManager::Add(this);
}
MessageQueue::~MessageQueue() {
@@ -140,10 +146,8 @@ MessageQueue::~MessageQueue() {
// that it always gets called when the queue
// is going away.
SignalQueueDestroyed();
- if (active_) {
- MessageQueueManager::Remove(this);
- Clear(NULL);
- }
+ MessageQueueManager::Remove(this);
+ Clear(NULL);
if (ss_) {
ss_->SetMessageQueue(NULL);
}
@@ -291,7 +295,6 @@ void MessageQueue::Post(MessageHandler *phandler, uint32 id,
// Signal for the multiplexer to return
CritScope cs(&crit_);
- EnsureActive();
Message msg;
msg.phandler = phandler;
msg.message_id = id;
@@ -313,7 +316,6 @@ void MessageQueue::DoDelayPost(int cmsDelay, uint32 tstamp,
// Signal for the multiplexer to return.
CritScope cs(&crit_);
- EnsureActive();
Message msg;
msg.phandler = phandler;
msg.message_id = id;
@@ -396,12 +398,4 @@ void MessageQueue::Dispatch(Message *pmsg) {
pmsg->phandler->OnMessage(pmsg);
}
-void MessageQueue::EnsureActive() {
- ASSERT(crit_.CurrentThreadIsOwner());
- if (!active_) {
- active_ = true;
- MessageQueueManager::Add(this);
- }
-}
-
} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/messagequeue.h b/chromium/third_party/libjingle/source/talk/base/messagequeue.h
index 7b38ba0082d..dc2b5a89a53 100644
--- a/chromium/third_party/libjingle/source/talk/base/messagequeue.h
+++ b/chromium/third_party/libjingle/source/talk/base/messagequeue.h
@@ -28,8 +28,9 @@
#ifndef TALK_BASE_MESSAGEQUEUE_H_
#define TALK_BASE_MESSAGEQUEUE_H_
+#include <string.h>
+
#include <algorithm>
-#include <cstring>
#include <list>
#include <queue>
#include <vector>
@@ -74,7 +75,7 @@ class MessageQueueManager {
void ClearInternal(MessageHandler *handler);
static MessageQueueManager* instance_;
- // This list contains 'active' MessageQueues.
+ // This list contains all live MessageQueues.
std::vector<MessageQueue *> message_queues_;
CriticalSection crit_;
};
@@ -246,7 +247,6 @@ class MessageQueue {
void reheap() { make_heap(c.begin(), c.end(), comp); }
};
- void EnsureActive();
void DoDelayPost(int cmsDelay, uint32 tstamp, MessageHandler *phandler,
uint32 id, MessageData* pdata);
@@ -257,9 +257,6 @@ class MessageQueue {
bool fStop_;
bool fPeekKeep_;
Message msgPeek_;
- // A message queue is active if it has ever had a message posted to it.
- // This also corresponds to being in MessageQueueManager's global list.
- bool active_;
MessageList msgq_;
PriorityQueue dmsgq_;
uint32 dmsgq_next_num_;
diff --git a/chromium/third_party/libjingle/source/talk/base/natserver.cc b/chromium/third_party/libjingle/source/talk/base/natserver.cc
index 46980487175..f69baa0c427 100644
--- a/chromium/third_party/libjingle/source/talk/base/natserver.cc
+++ b/chromium/third_party/libjingle/source/talk/base/natserver.cc
@@ -126,8 +126,8 @@ void NATServer::OnInternalPacket(
iter->second->WhitelistInsert(dest_addr);
// Send the packet to its intended destination.
- iter->second->socket->SendTo(buf + length, size - length, dest_addr,
- DSCP_NO_CHANGE);
+ talk_base::PacketOptions options;
+ iter->second->socket->SendTo(buf + length, size - length, dest_addr, options);
}
void NATServer::OnExternalPacket(
@@ -154,9 +154,10 @@ void NATServer::OnExternalPacket(
size + kNATEncodedIPv6AddressSize,
remote_addr);
// Copy the data part after the address.
- std::memcpy(real_buf.get() + addrlength, buf, size);
+ talk_base::PacketOptions options;
+ memcpy(real_buf.get() + addrlength, buf, size);
server_socket_->SendTo(real_buf.get(), size + addrlength,
- iter->second->route.source(), DSCP_NO_CHANGE);
+ iter->second->route.source(), options);
}
void NATServer::Translate(const SocketAddressPair& route) {
diff --git a/chromium/third_party/libjingle/source/talk/base/natsocketfactory.cc b/chromium/third_party/libjingle/source/talk/base/natsocketfactory.cc
index 395069e6658..6ce09fd251c 100644
--- a/chromium/third_party/libjingle/source/talk/base/natsocketfactory.cc
+++ b/chromium/third_party/libjingle/source/talk/base/natsocketfactory.cc
@@ -47,12 +47,12 @@ size_t PackAddressForNAT(char* buf, size_t buf_size,
if (family == AF_INET) {
ASSERT(buf_size >= kNATEncodedIPv4AddressSize);
in_addr v4addr = ip.ipv4_address();
- std::memcpy(&buf[4], &v4addr, kNATEncodedIPv4AddressSize - 4);
+ memcpy(&buf[4], &v4addr, kNATEncodedIPv4AddressSize - 4);
return kNATEncodedIPv4AddressSize;
} else if (family == AF_INET6) {
ASSERT(buf_size >= kNATEncodedIPv6AddressSize);
in6_addr v6addr = ip.ipv6_address();
- std::memcpy(&buf[4], &v6addr, kNATEncodedIPv6AddressSize - 4);
+ memcpy(&buf[4], &v6addr, kNATEncodedIPv6AddressSize - 4);
return kNATEncodedIPv6AddressSize;
}
return 0U;
@@ -159,7 +159,7 @@ class NATSocket : public AsyncSocket, public sigslot::has_slots<> {
size + kNATEncodedIPv6AddressSize,
addr);
size_t encoded_size = size + addrlength;
- std::memcpy(buf.get() + addrlength, data, size);
+ memcpy(buf.get() + addrlength, data, size);
int result = socket_->SendTo(buf.get(), encoded_size, server_addr_);
if (result >= 0) {
ASSERT(result == static_cast<int>(encoded_size));
@@ -196,7 +196,7 @@ class NATSocket : public AsyncSocket, public sigslot::has_slots<> {
SocketAddress real_remote_addr;
size_t addrlength =
UnpackAddressFromNAT(buf_, result, &real_remote_addr);
- std::memcpy(data, buf_ + addrlength, result - addrlength);
+ memcpy(data, buf_ + addrlength, result - addrlength);
// Make sure this packet should be delivered before returning it.
if (!connected_ || (real_remote_addr == remote_addr_)) {
diff --git a/chromium/third_party/libjingle/source/talk/base/nattypes.cc b/chromium/third_party/libjingle/source/talk/base/nattypes.cc
index 290c3adde77..da1d0116110 100644
--- a/chromium/third_party/libjingle/source/talk/base/nattypes.cc
+++ b/chromium/third_party/libjingle/source/talk/base/nattypes.cc
@@ -25,7 +25,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <cassert>
+#include <assert.h>
#include "talk/base/nattypes.h"
diff --git a/chromium/third_party/libjingle/source/talk/base/nethelpers.cc b/chromium/third_party/libjingle/source/talk/base/nethelpers.cc
index e6310ac45fe..057f34ddc15 100644
--- a/chromium/third_party/libjingle/source/talk/base/nethelpers.cc
+++ b/chromium/third_party/libjingle/source/talk/base/nethelpers.cc
@@ -34,12 +34,18 @@
#endif
#include "talk/base/byteorder.h"
+#include "talk/base/logging.h"
#include "talk/base/signalthread.h"
namespace talk_base {
int ResolveHostname(const std::string& hostname, int family,
std::vector<IPAddress>* addresses) {
+#ifdef __native_client__
+ ASSERT(false);
+ LOG(LS_WARNING) << "ResolveHostname() is not implemented for NaCl";
+ return -1;
+#else // __native_client__
if (!addresses) {
return -1;
}
@@ -64,6 +70,7 @@ int ResolveHostname(const std::string& hostname, int family,
}
freeaddrinfo(result);
return 0;
+#endif // !__native_client__
}
// AsyncResolver
@@ -83,7 +90,7 @@ bool AsyncResolver::GetResolvedAddress(int family, SocketAddress* addr) const {
*addr = addr_;
for (size_t i = 0; i < addresses_.size(); ++i) {
if (family == addresses_[i].family()) {
- addr->SetIP(addresses_[i]);
+ addr->SetResolvedIP(addresses_[i]);
return true;
}
}
diff --git a/chromium/third_party/libjingle/source/talk/base/nethelpers.h b/chromium/third_party/libjingle/source/talk/base/nethelpers.h
index a49f48ac7cd..5b385bbc509 100644
--- a/chromium/third_party/libjingle/source/talk/base/nethelpers.h
+++ b/chromium/third_party/libjingle/source/talk/base/nethelpers.h
@@ -30,7 +30,7 @@
#ifdef POSIX
#include <netdb.h>
-#include <cstddef>
+#include <stddef.h>
#elif WIN32
#include <winsock2.h> // NOLINT
#endif
diff --git a/chromium/third_party/libjingle/source/talk/base/network.cc b/chromium/third_party/libjingle/source/talk/base/network.cc
index d4dda138135..829507aec7d 100644
--- a/chromium/third_party/libjingle/source/talk/base/network.cc
+++ b/chromium/third_party/libjingle/source/talk/base/network.cc
@@ -38,7 +38,7 @@
#if defined(ANDROID) || defined(LINUX)
#include <linux/if.h>
#include <linux/route.h>
-#else
+#elif !defined(__native_client__)
#include <net/if.h>
#endif
#include <sys/socket.h>
@@ -46,11 +46,13 @@
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
+
#ifdef ANDROID
#include "talk/base/ifaddrs-android.h"
-#else
+#elif !defined(__native_client__)
#include <ifaddrs.h>
#endif
+
#endif // POSIX
#ifdef WIN32
@@ -58,8 +60,9 @@
#include <Iphlpapi.h>
#endif
+#include <stdio.h>
+
#include <algorithm>
-#include <cstdio>
#include "talk/base/logging.h"
#include "talk/base/scoped_ptr.h"
@@ -77,16 +80,7 @@ const uint32 kSignalNetworksMessage = 2;
// Fetch list of networks every two seconds.
const int kNetworksUpdateIntervalMs = 2000;
-
-// Makes a string key for this network. Used in the network manager's maps.
-// Network objects are keyed on interface name, network prefix and the
-// length of that prefix.
-std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix,
- int prefix_length) {
- std::ostringstream ost;
- ost << name << "%" << prefix.ToString() << "/" << prefix_length;
- return ost.str();
-}
+const int kHighestNetworkPreference = 127;
bool CompareNetworks(const Network* a, const Network* b) {
if (a->prefix_length() == b->prefix_length()) {
@@ -97,9 +91,54 @@ bool CompareNetworks(const Network* a, const Network* b) {
return a->name() < b->name();
}
+bool SortNetworks(const Network* a, const Network* b) {
+ // Network types will be preferred above everything else while sorting
+ // Networks.
+
+ // Networks are sorted first by type.
+ if (a->type() != b->type()) {
+ return a->type() < b->type();
+ }
+
+ // After type, networks are sorted by IP address precedence values
+ // from RFC 3484-bis
+ if (IPAddressPrecedence(a->ip()) != IPAddressPrecedence(b->ip())) {
+ return IPAddressPrecedence(a->ip()) > IPAddressPrecedence(b->ip());
+ }
+
+ // TODO(mallinath) - Add VPN and Link speed conditions while sorting.
+
+ // Networks are sorted last by key.
+ return a->key() > b->key();
+}
+
+std::string AdapterTypeToString(AdapterType type) {
+ switch (type) {
+ case ADAPTER_TYPE_UNKNOWN:
+ return "Unknown";
+ case ADAPTER_TYPE_ETHERNET:
+ return "Ethernet";
+ case ADAPTER_TYPE_WIFI:
+ return "Wifi";
+ case ADAPTER_TYPE_CELLULAR:
+ return "Cellular";
+ case ADAPTER_TYPE_VPN:
+ return "VPN";
+ default:
+ ASSERT(false);
+ return std::string();
+ }
+}
} // namespace
+std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix,
+ int prefix_length) {
+ std::ostringstream ost;
+ ost << name << "%" << prefix.ToString() << "/" << prefix_length;
+ return ost.str();
+}
+
NetworkManager::NetworkManager() {
}
@@ -178,6 +217,29 @@ void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks,
}
}
networks_ = merged_list;
+
+ // If the network lists changes, we resort it.
+ if (changed) {
+ std::sort(networks_.begin(), networks_.end(), SortNetworks);
+ // Now network interfaces are sorted, we should set the preference value
+ // for each of the interfaces we are planning to use.
+ // Preference order of network interfaces might have changed from previous
+ // sorting due to addition of higher preference network interface.
+ // Since we have already sorted the network interfaces based on our
+ // requirements, we will just assign a preference value starting with 127,
+ // in decreasing order.
+ int pref = kHighestNetworkPreference;
+ for (NetworkList::const_iterator iter = networks_.begin();
+ iter != networks_.end(); ++iter) {
+ (*iter)->set_preference(pref);
+ if (pref > 0) {
+ --pref;
+ } else {
+ LOG(LS_ERROR) << "Too many network interfaces to handle!";
+ break;
+ }
+ }
+ }
}
BasicNetworkManager::BasicNetworkManager()
@@ -188,7 +250,16 @@ BasicNetworkManager::BasicNetworkManager()
BasicNetworkManager::~BasicNetworkManager() {
}
-#if defined(POSIX)
+#if defined(__native_client__)
+
+bool BasicNetworkManager::CreateNetworks(bool include_ignored,
+ NetworkList* networks) const {
+ ASSERT(false);
+ LOG(LS_WARNING) << "BasicNetworkManager doesn't work on NaCl yet";
+ return false;
+}
+
+#elif defined(POSIX)
void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
bool include_ignored,
NetworkList* networks) const {
@@ -229,6 +300,7 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
continue;
}
}
+
int prefix_length = CountIPMaskBits(mask);
prefix = TruncateIP(ip, prefix_length);
std::string key = MakeNetworkKey(std::string(cursor->ifa_name),
@@ -375,6 +447,7 @@ bool BasicNetworkManager::CreateNetworks(bool include_ignored,
continue;
}
}
+
IPAddress prefix;
int prefix_length = GetPrefix(prefixlist, ip, &prefix);
std::string key = MakeNetworkKey(name, prefix, prefix_length);
@@ -553,9 +626,17 @@ void BasicNetworkManager::DumpNetworks(bool include_ignored) {
Network::Network(const std::string& name, const std::string& desc,
const IPAddress& prefix, int prefix_length)
: name_(name), description_(desc), prefix_(prefix),
- prefix_length_(prefix_length), scope_id_(0), ignored_(false),
- uniform_numerator_(0), uniform_denominator_(0), exponential_numerator_(0),
- exponential_denominator_(0) {
+ prefix_length_(prefix_length),
+ key_(MakeNetworkKey(name, prefix, prefix_length)), scope_id_(0),
+ ignored_(false), type_(ADAPTER_TYPE_UNKNOWN), preference_(0) {
+}
+
+Network::Network(const std::string& name, const std::string& desc,
+ const IPAddress& prefix, int prefix_length, AdapterType type)
+ : name_(name), description_(desc), prefix_(prefix),
+ prefix_length_(prefix_length),
+ key_(MakeNetworkKey(name, prefix, prefix_length)), scope_id_(0),
+ ignored_(false), type_(type), preference_(0) {
}
std::string Network::ToString() const {
@@ -563,7 +644,8 @@ std::string Network::ToString() const {
// Print out the first space-terminated token of the network desc, plus
// the IP address.
ss << "Net[" << description_.substr(0, description_.find(' '))
- << ":" << prefix_.ToSensitiveString() << "/" << prefix_length_ << "]";
+ << ":" << prefix_.ToSensitiveString() << "/" << prefix_length_
+ << ":" << AdapterTypeToString(type_) << "]";
return ss.str();
}
@@ -589,4 +671,5 @@ bool Network::SetIPs(const std::vector<IPAddress>& ips, bool changed) {
ips_ = ips;
return changed;
}
+
} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/network.h b/chromium/third_party/libjingle/source/talk/base/network.h
index 63f3e732fd9..2be81bb1c8d 100644
--- a/chromium/third_party/libjingle/source/talk/base/network.h
+++ b/chromium/third_party/libjingle/source/talk/base/network.h
@@ -45,9 +45,23 @@ struct ifaddrs;
namespace talk_base {
class Network;
-class NetworkSession;
class Thread;
+enum AdapterType {
+ // This enum resembles the one in Chromium net::ConnectionType.
+ ADAPTER_TYPE_UNKNOWN = 0,
+ ADAPTER_TYPE_ETHERNET = 1,
+ ADAPTER_TYPE_WIFI = 2,
+ ADAPTER_TYPE_CELLULAR = 3,
+ ADAPTER_TYPE_VPN = 4
+};
+
+// Makes a string key for this network. Used in the network manager's maps.
+// Network objects are keyed on interface name, network prefix and the
+// length of that prefix.
+std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix,
+ int prefix_length);
+
// Generic network manager interface. It provides list of local
// networks.
class NetworkManager {
@@ -168,10 +182,12 @@ class BasicNetworkManager : public NetworkManagerBase,
// Represents a Unix-type network interface, with a name and single address.
class Network {
public:
- Network() : prefix_(INADDR_ANY), scope_id_(0) {}
Network(const std::string& name, const std::string& description,
const IPAddress& prefix, int prefix_length);
+ Network(const std::string& name, const std::string& description,
+ const IPAddress& prefix, int prefix_length, AdapterType type);
+
// Returns the name of the interface this network is associated wtih.
const std::string& name() const { return name_; }
@@ -184,6 +200,10 @@ class Network {
// Returns the length, in bits, of this network's prefix.
int prefix_length() const { return prefix_length_; }
+ // |key_| has unique value per network interface. Used in sorting network
+ // interfaces. Key is derived from interface name and it's prefix.
+ std::string key() const { return key_; }
+
// Returns the Network's current idea of the 'best' IP it has.
// 'Best' currently means the first one added.
// TODO: We should be preferring temporary addresses.
@@ -215,27 +235,28 @@ class Network {
bool ignored() const { return ignored_; }
void set_ignored(bool ignored) { ignored_ = ignored; }
+ AdapterType type() const { return type_; }
+ int preference() const { return preference_; }
+ void set_preference(int preference) { preference_ = preference; }
+
// Debugging description of this network
std::string ToString() const;
private:
- typedef std::vector<NetworkSession*> SessionList;
-
std::string name_;
std::string description_;
IPAddress prefix_;
int prefix_length_;
+ std::string key_;
std::vector<IPAddress> ips_;
int scope_id_;
bool ignored_;
- SessionList sessions_;
- double uniform_numerator_;
- double uniform_denominator_;
- double exponential_numerator_;
- double exponential_denominator_;
+ AdapterType type_;
+ int preference_;
friend class NetworkManager;
};
+
} // namespace talk_base
#endif // TALK_BASE_NETWORK_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/network_unittest.cc b/chromium/third_party/libjingle/source/talk/base/network_unittest.cc
index e11e78daa4a..56b11c617aa 100644
--- a/chromium/third_party/libjingle/source/talk/base/network_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/network_unittest.cc
@@ -527,6 +527,51 @@ TEST_F(NetworkTest, TestIPv6Toggle) {
}
}
+TEST_F(NetworkTest, TestNetworkListSorting) {
+ BasicNetworkManager manager;
+ Network ipv4_network1("test_eth0", "Test Network Adapter 1",
+ IPAddress(0x12345600U), 24);
+ ipv4_network1.AddIP(IPAddress(0x12345600U));
+
+ IPAddress ip;
+ IPAddress prefix;
+ EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:abcd:efab:cdef", &ip));
+ prefix = TruncateIP(ip, 64);
+ Network ipv6_eth1_publicnetwork1_ip1("test_eth1", "Test NetworkAdapter 2",
+ prefix, 64);
+ ipv6_eth1_publicnetwork1_ip1.AddIP(ip);
+
+ NetworkManager::NetworkList list;
+ list.push_back(new Network(ipv4_network1));
+ list.push_back(new Network(ipv6_eth1_publicnetwork1_ip1));
+ Network* net1 = list[0];
+ Network* net2 = list[1];
+
+ bool changed = false;
+ MergeNetworkList(manager, list, &changed);
+ ASSERT_TRUE(changed);
+ // After sorting IPv6 network should be higher order than IPv4 networks.
+ EXPECT_TRUE(net1->preference() < net2->preference());
+}
+
+TEST_F(NetworkTest, TestNetworkAdapterTypes) {
+ Network wifi("wlan0", "Wireless Adapter", IPAddress(0x12345600U), 24,
+ ADAPTER_TYPE_WIFI);
+ EXPECT_EQ(ADAPTER_TYPE_WIFI, wifi.type());
+ Network ethernet("eth0", "Ethernet", IPAddress(0x12345600U), 24,
+ ADAPTER_TYPE_ETHERNET);
+ EXPECT_EQ(ADAPTER_TYPE_ETHERNET, ethernet.type());
+ Network cellular("test_cell", "Cellular Adapter", IPAddress(0x12345600U), 24,
+ ADAPTER_TYPE_CELLULAR);
+ EXPECT_EQ(ADAPTER_TYPE_CELLULAR, cellular.type());
+ Network vpn("bridge_test", "VPN Adapter", IPAddress(0x12345600U), 24,
+ ADAPTER_TYPE_VPN);
+ EXPECT_EQ(ADAPTER_TYPE_VPN, vpn.type());
+ Network unknown("test", "Test Adapter", IPAddress(0x12345600U), 24,
+ ADAPTER_TYPE_UNKNOWN);
+ EXPECT_EQ(ADAPTER_TYPE_UNKNOWN, unknown.type());
+}
+
#if defined(POSIX)
// Verify that we correctly handle interfaces with no address.
TEST_F(NetworkTest, TestConvertIfAddrsNoAddress) {
diff --git a/chromium/third_party/libjingle/source/talk/base/nssidentity.cc b/chromium/third_party/libjingle/source/talk/base/nssidentity.cc
index 053035e562e..a0cd8b217bb 100644
--- a/chromium/third_party/libjingle/source/talk/base/nssidentity.cc
+++ b/chromium/third_party/libjingle/source/talk/base/nssidentity.cc
@@ -48,9 +48,16 @@
#include "talk/base/logging.h"
#include "talk/base/helpers.h"
#include "talk/base/nssstreamadapter.h"
+#include "talk/base/safe_conversions.h"
namespace talk_base {
+// Certificate validity lifetime in seconds.
+static const int CERTIFICATE_LIFETIME = 60*60*24*30; // 30 days, arbitrarily
+// Certificate validity window in seconds.
+// This is to compensate for slightly incorrect system clocks.
+static const int CERTIFICATE_WINDOW = -60*60*24;
+
NSSKeyPair::~NSSKeyPair() {
if (privkey_)
SECKEY_DestroyPrivateKey(privkey_);
@@ -137,7 +144,7 @@ NSSCertificate *NSSCertificate::FromPEMString(const std::string &pem_string) {
SECItem der_cert;
der_cert.data = reinterpret_cast<unsigned char *>(const_cast<char *>(
der.data()));
- der_cert.len = der.size();
+ der_cert.len = checked_cast<unsigned int>(der.size());
CERTCertificate *cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
&der_cert, NULL, PR_FALSE, PR_TRUE);
@@ -163,8 +170,49 @@ void NSSCertificate::ToDER(Buffer* der_buffer) const {
der_buffer->SetData(certificate_->derCert.data, certificate_->derCert.len);
}
-bool NSSCertificate::GetDigestLength(const std::string &algorithm,
- std::size_t *length) {
+static bool Certifies(CERTCertificate* parent, CERTCertificate* child) {
+ // TODO(bemasc): Identify stricter validation checks to use here. In the
+ // context of some future identity standard, it might make sense to check
+ // the certificates' roles, expiration dates, self-signatures (if
+ // self-signed), certificate transparency logging, or many other attributes.
+ // NOTE: Future changes to this validation may reject some previously allowed
+ // certificate chains. Users should be advised not to deploy chained
+ // certificates except in controlled environments until the validity
+ // requirements are finalized.
+
+ // Check that the parent's name is the same as the child's claimed issuer.
+ SECComparison name_status =
+ CERT_CompareName(&child->issuer, &parent->subject);
+ if (name_status != SECEqual)
+ return false;
+
+ // Extract the parent's public key, or fail if the key could not be read
+ // (e.g. certificate is corrupted).
+ SECKEYPublicKey* parent_key = CERT_ExtractPublicKey(parent);
+ if (!parent_key)
+ return false;
+
+ // Check that the parent's privkey was actually used to generate the child's
+ // signature.
+ SECStatus verified = CERT_VerifySignedDataWithPublicKey(
+ &child->signatureWrap, parent_key, NULL);
+ SECKEY_DestroyPublicKey(parent_key);
+ return verified == SECSuccess;
+}
+
+bool NSSCertificate::IsValidChain(const CERTCertList* cert_list) {
+ CERTCertListNode* child = CERT_LIST_HEAD(cert_list);
+ for (CERTCertListNode* parent = CERT_LIST_NEXT(child);
+ !CERT_LIST_END(parent, cert_list);
+ child = parent, parent = CERT_LIST_NEXT(parent)) {
+ if (!Certifies(parent->cert, child->cert))
+ return false;
+ }
+ return true;
+}
+
+bool NSSCertificate::GetDigestLength(const std::string& algorithm,
+ size_t* length) {
const SECHashObject *ho;
if (!GetDigestObject(algorithm, &ho))
@@ -223,9 +271,10 @@ bool NSSCertificate::GetSignatureDigestAlgorithm(std::string* algorithm) const {
return true;
}
-bool NSSCertificate::ComputeDigest(const std::string &algorithm,
- unsigned char *digest, std::size_t size,
- std::size_t *length) const {
+bool NSSCertificate::ComputeDigest(const std::string& algorithm,
+ unsigned char* digest,
+ size_t size,
+ size_t* length) const {
const SECHashObject *ho;
if (!GetDigestObject(algorithm, &ho))
@@ -299,23 +348,25 @@ bool NSSCertificate::GetDigestObject(const std::string &algorithm,
}
-NSSIdentity *NSSIdentity::Generate(const std::string &common_name) {
- std::string subject_name_string = "CN=" + common_name;
+NSSIdentity* NSSIdentity::GenerateInternal(const SSLIdentityParams& params) {
+ std::string subject_name_string = "CN=" + params.common_name;
CERTName *subject_name = CERT_AsciiToName(
const_cast<char *>(subject_name_string.c_str()));
NSSIdentity *identity = NULL;
CERTSubjectPublicKeyInfo *spki = NULL;
CERTCertificateRequest *certreq = NULL;
- CERTValidity *validity;
+ CERTValidity *validity = NULL;
CERTCertificate *certificate = NULL;
NSSKeyPair *keypair = NSSKeyPair::Generate();
SECItem inner_der;
SECStatus rv;
PLArenaPool* arena;
SECItem signed_cert;
- PRTime not_before, not_after;
PRTime now = PR_Now();
- PRTime one_day;
+ PRTime not_before =
+ now + static_cast<PRTime>(params.not_before) * PR_USEC_PER_SEC;
+ PRTime not_after =
+ now + static_cast<PRTime>(params.not_after) * PR_USEC_PER_SEC;
inner_der.len = 0;
inner_der.data = NULL;
@@ -342,11 +393,6 @@ NSSIdentity *NSSIdentity::Generate(const std::string &common_name) {
goto fail;
}
- one_day = 86400;
- one_day *= PR_USEC_PER_SEC;
- not_before = now - one_day;
- not_after = now + 30 * one_day;
-
validity = CERT_CreateValidity(not_before, not_after);
if (!validity) {
LOG(LS_ERROR) << "Couldn't create validity";
@@ -408,6 +454,18 @@ NSSIdentity *NSSIdentity::Generate(const std::string &common_name) {
return identity;
}
+NSSIdentity* NSSIdentity::Generate(const std::string &common_name) {
+ SSLIdentityParams params;
+ params.common_name = common_name;
+ params.not_before = CERTIFICATE_WINDOW;
+ params.not_after = CERTIFICATE_LIFETIME;
+ return GenerateInternal(params);
+}
+
+NSSIdentity* NSSIdentity::GenerateForTest(const SSLIdentityParams& params) {
+ return GenerateInternal(params);
+}
+
SSLIdentity* NSSIdentity::FromPEMStrings(const std::string& private_key,
const std::string& certificate) {
std::string private_key_der;
@@ -416,10 +474,9 @@ SSLIdentity* NSSIdentity::FromPEMStrings(const std::string& private_key,
return NULL;
SECItem private_key_item;
- private_key_item.data =
- reinterpret_cast<unsigned char *>(
- const_cast<char *>(private_key_der.c_str()));
- private_key_item.len = private_key_der.size();
+ private_key_item.data = reinterpret_cast<unsigned char *>(
+ const_cast<char *>(private_key_der.c_str()));
+ private_key_item.len = checked_cast<unsigned int>(private_key_der.size());
const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
KU_DIGITAL_SIGNATURE;
diff --git a/chromium/third_party/libjingle/source/talk/base/nssidentity.h b/chromium/third_party/libjingle/source/talk/base/nssidentity.h
index 3f97ebbb619..b4376d521a6 100644
--- a/chromium/third_party/libjingle/source/talk/base/nssidentity.h
+++ b/chromium/third_party/libjingle/source/talk/base/nssidentity.h
@@ -84,16 +84,21 @@ class NSSCertificate : public SSLCertificate {
virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const;
virtual bool ComputeDigest(const std::string& algorithm,
- unsigned char* digest, std::size_t size,
- std::size_t* length) const;
+ unsigned char* digest,
+ size_t size,
+ size_t* length) const;
virtual bool GetChain(SSLCertChain** chain) const;
CERTCertificate* certificate() { return certificate_; }
+ // Performs minimal checks to determine if the list is a valid chain. This
+ // only checks that each certificate certifies the preceding certificate,
+ // and ignores many other certificate features such as expiration dates.
+ static bool IsValidChain(const CERTCertList* cert_list);
+
// Helper function to get the length of a digest
- static bool GetDigestLength(const std::string& algorithm,
- std::size_t* length);
+ static bool GetDigestLength(const std::string& algorithm, size_t* length);
// Comparison. Only the certificate itself is considered, not the chain.
bool Equals(const NSSCertificate* tocompare) const;
@@ -113,6 +118,7 @@ class NSSCertificate : public SSLCertificate {
class NSSIdentity : public SSLIdentity {
public:
static NSSIdentity* Generate(const std::string& common_name);
+ static NSSIdentity* GenerateForTest(const SSLIdentityParams& params);
static SSLIdentity* FromPEMStrings(const std::string& private_key,
const std::string& certificate);
virtual ~NSSIdentity() {
@@ -128,6 +134,8 @@ class NSSIdentity : public SSLIdentity {
NSSIdentity(NSSKeyPair* keypair, NSSCertificate* cert) :
keypair_(keypair), certificate_(cert) {}
+ static NSSIdentity* GenerateInternal(const SSLIdentityParams& params);
+
talk_base::scoped_ptr<NSSKeyPair> keypair_;
talk_base::scoped_ptr<NSSCertificate> certificate_;
diff --git a/chromium/third_party/libjingle/source/talk/base/nssstreamadapter.cc b/chromium/third_party/libjingle/source/talk/base/nssstreamadapter.cc
index 185c243f5e5..60fa738b3c1 100644
--- a/chromium/third_party/libjingle/source/talk/base/nssstreamadapter.cc
+++ b/chromium/third_party/libjingle/source/talk/base/nssstreamadapter.cc
@@ -53,6 +53,7 @@
#endif
#include "talk/base/nssidentity.h"
+#include "talk/base/safe_conversions.h"
#include "talk/base/thread.h"
namespace talk_base {
@@ -86,7 +87,8 @@ static const SrtpCipherMapEntry kSrtpCipherMap[] = {
// Implementation of NSPR methods
static PRStatus StreamClose(PRFileDesc *socket) {
- // Noop
+ ASSERT(!socket->lower);
+ socket->dtor(socket);
return PR_SUCCESS;
}
@@ -96,7 +98,7 @@ static PRInt32 StreamRead(PRFileDesc *socket, void *buf, PRInt32 length) {
int error;
StreamResult result = stream->Read(buf, length, &read, &error);
if (result == SR_SUCCESS) {
- return read;
+ return checked_cast<PRInt32>(read);
}
if (result == SR_EOS) {
@@ -119,7 +121,7 @@ static PRInt32 StreamWrite(PRFileDesc *socket, const void *buf,
int error;
StreamResult result = stream->Write(buf, length, &written, &error);
if (result == SR_SUCCESS) {
- return written;
+ return checked_cast<PRInt32>(written);
}
if (result == SR_BLOCK) {
@@ -437,7 +439,7 @@ bool NSSStreamAdapter::Init() {
LOG(LS_ERROR) << "Error disabling false start";
return false;
}
-
+
ssl_fd_ = ssl_fd;
return true;
@@ -515,7 +517,7 @@ int NSSStreamAdapter::BeginSSL() {
SSL_LIBRARY_VERSION_TLS_1_1 :
SSL_LIBRARY_VERSION_TLS_1_0;
vrange.max = SSL_LIBRARY_VERSION_TLS_1_1;
-
+
rv = SSL_VersionRangeSet(ssl_fd_, &vrange);
if (rv != SECSuccess) {
Error("BeginSSL", -1, false);
@@ -525,7 +527,9 @@ int NSSStreamAdapter::BeginSSL() {
// SRTP
#ifdef HAVE_DTLS_SRTP
if (!srtp_ciphers_.empty()) {
- rv = SSL_SetSRTPCiphers(ssl_fd_, &srtp_ciphers_[0], srtp_ciphers_.size());
+ rv = SSL_SetSRTPCiphers(
+ ssl_fd_, &srtp_ciphers_[0],
+ checked_cast<unsigned int>(srtp_ciphers_.size()));
if (rv != SECSuccess) {
Error("BeginSSL", -1, false);
return -1;
@@ -644,7 +648,7 @@ StreamResult NSSStreamAdapter::Read(void* data, size_t data_len,
return SR_ERROR;
}
- PRInt32 rv = PR_Read(ssl_fd_, data, data_len);
+ PRInt32 rv = PR_Read(ssl_fd_, data, checked_cast<PRInt32>(data_len));
if (rv == 0) {
return SR_EOS;
@@ -681,7 +685,7 @@ StreamResult NSSStreamAdapter::Write(const void* data, size_t data_len,
case SSL_CONNECTED:
break;
-
+
case SSL_ERROR:
case SSL_CLOSED:
default:
@@ -690,7 +694,7 @@ StreamResult NSSStreamAdapter::Write(const void* data, size_t data_len,
return SR_ERROR;
}
- PRInt32 rv = PR_Write(ssl_fd_, data, data_len);
+ PRInt32 rv = PR_Write(ssl_fd_, data, checked_cast<PRInt32>(data_len));
// Error
if (rv < 0) {
@@ -780,12 +784,33 @@ SECStatus NSSStreamAdapter::AuthCertificateHook(void *arg,
PRBool checksig,
PRBool isServer) {
LOG(LS_INFO) << "NSSStreamAdapter::AuthCertificateHook";
- NSSCertificate peer_cert(SSL_PeerCertificate(fd));
- bool ok = false;
+ // SSL_PeerCertificate returns a pointer that is owned by the caller, and
+ // the NSSCertificate constructor copies its argument, so |raw_peer_cert|
+ // must be destroyed in this function.
+ CERTCertificate* raw_peer_cert = SSL_PeerCertificate(fd);
+ NSSCertificate peer_cert(raw_peer_cert);
+ CERT_DestroyCertificate(raw_peer_cert);
- // TODO(ekr@rtfm.com): Should we be enforcing self-signed like
- // the OpenSSL version?
NSSStreamAdapter *stream = reinterpret_cast<NSSStreamAdapter *>(arg);
+ stream->cert_ok_ = false;
+
+ // Read the peer's certificate chain.
+ CERTCertList* cert_list = SSL_PeerCertificateChain(fd);
+ ASSERT(cert_list != NULL);
+
+ // If the peer provided multiple certificates, check that they form a valid
+ // chain as defined by RFC 5246 Section 7.4.2: "Each following certificate
+ // MUST directly certify the one preceding it.". This check does NOT
+ // verify other requirements, such as whether the chain reaches a trusted
+ // root, self-signed certificates have valid signatures, certificates are not
+ // expired, etc.
+ // Even if the chain is valid, the leaf certificate must still match a
+ // provided certificate or digest.
+ if (!NSSCertificate::IsValidChain(cert_list)) {
+ CERT_DestroyCertList(cert_list);
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ return SECFailure;
+ }
if (stream->peer_certificate_.get()) {
LOG(LS_INFO) << "Checking against specified certificate";
@@ -794,13 +819,13 @@ SECStatus NSSStreamAdapter::AuthCertificateHook(void *arg,
if (reinterpret_cast<NSSCertificate *>(stream->peer_certificate_.get())->
Equals(&peer_cert)) {
LOG(LS_INFO) << "Accepted peer certificate";
- ok = true;
+ stream->cert_ok_ = true;
}
} else if (!stream->peer_certificate_digest_algorithm_.empty()) {
LOG(LS_INFO) << "Checking against specified digest";
// The peer certificate digest was specified
unsigned char digest[64]; // Maximum size
- std::size_t digest_length;
+ size_t digest_length;
if (!peer_cert.ComputeDigest(
stream->peer_certificate_digest_algorithm_,
@@ -810,7 +835,7 @@ SECStatus NSSStreamAdapter::AuthCertificateHook(void *arg,
Buffer computed_digest(digest, digest_length);
if (computed_digest == stream->peer_certificate_digest_value_) {
LOG(LS_INFO) << "Accepted peer certificate";
- ok = true;
+ stream->cert_ok_ = true;
}
}
} else {
@@ -819,23 +844,18 @@ SECStatus NSSStreamAdapter::AuthCertificateHook(void *arg,
UNIMPLEMENTED;
}
- if (ok) {
+ if (!stream->cert_ok_ && stream->ignore_bad_cert()) {
+ LOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
stream->cert_ok_ = true;
+ }
- // Record the peer's certificate chain.
- CERTCertList* cert_list = SSL_PeerCertificateChain(fd);
- ASSERT(cert_list != NULL);
-
+ if (stream->cert_ok_)
stream->peer_certificate_.reset(new NSSCertificate(cert_list));
- CERT_DestroyCertList(cert_list);
- return SECSuccess;
- }
- if (!ok && stream->ignore_bad_cert()) {
- LOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
- stream->cert_ok_ = true;
+ CERT_DestroyCertList(cert_list);
+
+ if (stream->cert_ok_)
return SECSuccess;
- }
PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
return SECFailure;
@@ -869,11 +889,15 @@ bool NSSStreamAdapter::ExportKeyingMaterial(const std::string& label,
bool use_context,
uint8* result,
size_t result_len) {
- SECStatus rv = SSL_ExportKeyingMaterial(ssl_fd_,
- label.c_str(), label.size(),
- use_context,
- context, context_len,
- result, result_len);
+ SECStatus rv = SSL_ExportKeyingMaterial(
+ ssl_fd_,
+ label.c_str(),
+ checked_cast<unsigned int>(label.size()),
+ use_context,
+ context,
+ checked_cast<unsigned int>(context_len),
+ result,
+ checked_cast<unsigned int>(result_len));
return rv == SECSuccess;
}
diff --git a/chromium/third_party/libjingle/source/talk/base/nssstreamadapter.h b/chromium/third_party/libjingle/source/talk/base/nssstreamadapter.h
index 219f6193f07..3919c5a1571 100644
--- a/chromium/third_party/libjingle/source/talk/base/nssstreamadapter.h
+++ b/chromium/third_party/libjingle/source/talk/base/nssstreamadapter.h
@@ -103,8 +103,7 @@ class NSSStreamAdapter : public SSLStreamAdapterHelper {
// Override SSLStreamAdapterHelper
virtual int BeginSSL();
virtual void Cleanup();
- virtual bool GetDigestLength(const std::string &algorithm,
- std::size_t *length) {
+ virtual bool GetDigestLength(const std::string& algorithm, size_t* length) {
return NSSCertificate::GetDigestLength(algorithm, length);
}
diff --git a/chromium/third_party/libjingle/source/talk/base/openssl.h b/chromium/third_party/libjingle/source/talk/base/openssl.h
new file mode 100644
index 00000000000..d9628a76368
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/openssl.h
@@ -0,0 +1,37 @@
+/*
+ * libjingle
+ * Copyright 2013, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_BASE_OPENSSL_H_
+#define TALK_BASE_OPENSSL_H_
+
+#include <openssl/ssl.h>
+
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+#error OpenSSL is older than 1.0.0, which is the minimum supported version.
+#endif
+
+#endif // TALK_BASE_OPENSSL_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/openssladapter.cc b/chromium/third_party/libjingle/source/talk/base/openssladapter.cc
index af92f0c4534..9e6fe72c244 100644
--- a/chromium/third_party/libjingle/source/talk/base/openssladapter.cc
+++ b/chromium/third_party/libjingle/source/talk/base/openssladapter.cc
@@ -41,7 +41,6 @@
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include <openssl/rand.h>
-#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#if HAVE_CONFIG_H
@@ -50,6 +49,7 @@
#include "talk/base/common.h"
#include "talk/base/logging.h"
+#include "talk/base/openssl.h"
#include "talk/base/sslroots.h"
#include "talk/base/stringutils.h"
@@ -62,9 +62,7 @@
#define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE)
#define MUTEX_UNLOCK(x) ReleaseMutex(x)
#define THREAD_ID GetCurrentThreadId()
-#elif defined(_POSIX_THREADS)
- // _POSIX_THREADS is normally defined in unistd.h if pthreads are available
- // on your platform.
+#elif defined(POSIX)
#define MUTEX_TYPE pthread_mutex_t
#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
@@ -690,11 +688,7 @@ bool OpenSSLAdapter::VerifyServerName(SSL* ssl, const char* host,
int extension_nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension));
if (extension_nid == NID_subject_alt_name) {
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
const X509V3_EXT_METHOD* meth = X509V3_EXT_get(extension);
-#else
- X509V3_EXT_METHOD* meth = X509V3_EXT_get(extension);
-#endif
if (!meth)
break;
@@ -705,12 +699,8 @@ bool OpenSSLAdapter::VerifyServerName(SSL* ssl, const char* host,
// See http://readlist.com/lists/openssl.org/openssl-users/0/4761.html.
unsigned char* ext_value_data = extension->value->data;
-#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
const unsigned char **ext_value_data_ptr =
(const_cast<const unsigned char **>(&ext_value_data));
-#else
- unsigned char **ext_value_data_ptr = &ext_value_data;
-#endif
if (meth->it) {
ext_str = ASN1_item_d2i(NULL, ext_value_data_ptr,
diff --git a/chromium/third_party/libjingle/source/talk/base/openssldigest.cc b/chromium/third_party/libjingle/source/talk/base/openssldigest.cc
index 3d9276de844..3d0d227e67c 100644
--- a/chromium/third_party/libjingle/source/talk/base/openssldigest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/openssldigest.cc
@@ -30,6 +30,7 @@
#include "talk/base/openssldigest.h"
#include "talk/base/common.h"
+#include "talk/base/openssl.h"
namespace talk_base {
@@ -78,7 +79,6 @@ bool OpenSSLDigest::GetDigestEVP(const std::string& algorithm,
md = EVP_md5();
} else if (algorithm == DIGEST_SHA_1) {
md = EVP_sha1();
-#if OPENSSL_VERSION_NUMBER >= 0x00908000L
} else if (algorithm == DIGEST_SHA_224) {
md = EVP_sha224();
} else if (algorithm == DIGEST_SHA_256) {
@@ -87,7 +87,6 @@ bool OpenSSLDigest::GetDigestEVP(const std::string& algorithm,
md = EVP_sha384();
} else if (algorithm == DIGEST_SHA_512) {
md = EVP_sha512();
-#endif
} else {
return false;
}
@@ -108,7 +107,6 @@ bool OpenSSLDigest::GetDigestName(const EVP_MD* md,
*algorithm = DIGEST_MD5;
} else if (md_type == NID_sha1) {
*algorithm = DIGEST_SHA_1;
-#if OPENSSL_VERSION_NUMBER >= 0x00908000L
} else if (md_type == NID_sha224) {
*algorithm = DIGEST_SHA_224;
} else if (md_type == NID_sha256) {
@@ -117,7 +115,6 @@ bool OpenSSLDigest::GetDigestName(const EVP_MD* md,
*algorithm = DIGEST_SHA_384;
} else if (md_type == NID_sha512) {
*algorithm = DIGEST_SHA_512;
-#endif
} else {
algorithm->clear();
return false;
diff --git a/chromium/third_party/libjingle/source/talk/base/opensslidentity.cc b/chromium/third_party/libjingle/source/talk/base/opensslidentity.cc
index 4ff76016183..a58f83967e8 100644
--- a/chromium/third_party/libjingle/source/talk/base/opensslidentity.cc
+++ b/chromium/third_party/libjingle/source/talk/base/opensslidentity.cc
@@ -32,7 +32,6 @@
// Must be included first before openssl headers.
#include "talk/base/win32.h" // NOLINT
-#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
@@ -43,6 +42,7 @@
#include "talk/base/checks.h"
#include "talk/base/helpers.h"
#include "talk/base/logging.h"
+#include "talk/base/openssl.h"
#include "talk/base/openssldigest.h"
namespace talk_base {
@@ -57,7 +57,7 @@ static const int KEY_LENGTH = 1024;
static const int SERIAL_RAND_BITS = 64;
// Certificate validity lifetime
-static const int CERTIFICATE_LIFETIME = 60*60*24*365; // one year, arbitrarily
+static const int CERTIFICATE_LIFETIME = 60*60*24*30; // 30 days, arbitrarily
// Certificate validity window.
// This is to compensate for slightly incorrect system clocks.
static const int CERTIFICATE_WINDOW = -60*60*24;
@@ -66,15 +66,6 @@ static const int CERTIFICATE_WINDOW = -60*60*24;
static EVP_PKEY* MakeKey() {
LOG(LS_INFO) << "Making key pair";
EVP_PKEY* pkey = EVP_PKEY_new();
-#if OPENSSL_VERSION_NUMBER < 0x00908000l
- // Only RSA_generate_key is available. Use that.
- RSA* rsa = RSA_generate_key(KEY_LENGTH, 0x10001, NULL, NULL);
- if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
- EVP_PKEY_free(pkey);
- RSA_free(rsa);
- return NULL;
- }
-#else
// RSA_generate_key is deprecated. Use _ex version.
BIGNUM* exponent = BN_new();
RSA* rsa = RSA_new();
@@ -89,15 +80,14 @@ static EVP_PKEY* MakeKey() {
}
// ownership of rsa struct was assigned, don't free it.
BN_free(exponent);
-#endif
LOG(LS_INFO) << "Returning key pair";
return pkey;
}
// Generate a self-signed certificate, with the public key from the
// given key pair. Caller is responsible for freeing the returned object.
-static X509* MakeCertificate(EVP_PKEY* pkey, const char* common_name) {
- LOG(LS_INFO) << "Making certificate for " << common_name;
+static X509* MakeCertificate(EVP_PKEY* pkey, const SSLIdentityParams& params) {
+ LOG(LS_INFO) << "Making certificate for " << params.common_name;
X509* x509 = NULL;
BIGNUM* serial_number = NULL;
X509_NAME* name = NULL;
@@ -128,14 +118,15 @@ static X509* MakeCertificate(EVP_PKEY* pkey, const char* common_name) {
// clear during SSL negotiation, so there may be a privacy issue in
// putting anything recognizable here.
if ((name = X509_NAME_new()) == NULL ||
- !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_UTF8,
- (unsigned char*)common_name, -1, -1, 0) ||
+ !X509_NAME_add_entry_by_NID(
+ name, NID_commonName, MBSTRING_UTF8,
+ (unsigned char*)params.common_name.c_str(), -1, -1, 0) ||
!X509_set_subject_name(x509, name) ||
!X509_set_issuer_name(x509, name))
goto error;
- if (!X509_gmtime_adj(X509_get_notBefore(x509), CERTIFICATE_WINDOW) ||
- !X509_gmtime_adj(X509_get_notAfter(x509), CERTIFICATE_LIFETIME))
+ if (!X509_gmtime_adj(X509_get_notBefore(x509), params.not_before) ||
+ !X509_gmtime_adj(X509_get_notAfter(x509), params.not_after))
goto error;
if (!X509_sign(x509, pkey, EVP_sha1()))
@@ -199,12 +190,13 @@ static void PrintCert(X509* x509) {
#endif
OpenSSLCertificate* OpenSSLCertificate::Generate(
- OpenSSLKeyPair* key_pair, const std::string& common_name) {
- std::string actual_common_name = common_name;
- if (actual_common_name.empty())
+ OpenSSLKeyPair* key_pair, const SSLIdentityParams& params) {
+ SSLIdentityParams actual_params(params);
+ if (actual_params.common_name.empty()) {
// Use a random string, arbitrarily 8chars long.
- actual_common_name = CreateRandomString(8);
- X509* x509 = MakeCertificate(key_pair->pkey(), actual_common_name.c_str());
+ actual_params.common_name = CreateRandomString(8);
+ }
+ X509* x509 = MakeCertificate(key_pair->pkey(), actual_params);
if (!x509) {
LogSSLErrors("Generating certificate");
return NULL;
@@ -222,11 +214,11 @@ OpenSSLCertificate* OpenSSLCertificate::FromPEMString(
BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
if (!bio)
return NULL;
- (void)BIO_set_close(bio, BIO_NOCLOSE);
BIO_set_mem_eof_return(bio, 0);
X509 *x509 = PEM_read_bio_X509(bio, NULL, NULL,
const_cast<char*>("\0"));
- BIO_free(bio);
+ BIO_free(bio); // Frees the BIO, but not the pointed-to string.
+
if (!x509)
return NULL;
@@ -243,18 +235,18 @@ bool OpenSSLCertificate::GetSignatureDigestAlgorithm(
EVP_get_digestbyobj(x509_->sig_alg->algorithm), algorithm);
}
-bool OpenSSLCertificate::ComputeDigest(const std::string &algorithm,
- unsigned char *digest,
- std::size_t size,
- std::size_t *length) const {
+bool OpenSSLCertificate::ComputeDigest(const std::string& algorithm,
+ unsigned char* digest,
+ size_t size,
+ size_t* length) const {
return ComputeDigest(x509_, algorithm, digest, size, length);
}
-bool OpenSSLCertificate::ComputeDigest(const X509 *x509,
- const std::string &algorithm,
- unsigned char *digest,
- std::size_t size,
- std::size_t *length) {
+bool OpenSSLCertificate::ComputeDigest(const X509* x509,
+ const std::string& algorithm,
+ unsigned char* digest,
+ size_t size,
+ size_t* length) {
const EVP_MD *md;
unsigned int n;
@@ -320,11 +312,12 @@ void OpenSSLCertificate::AddReference() const {
CRYPTO_add(&x509_->references, 1, CRYPTO_LOCK_X509);
}
-OpenSSLIdentity* OpenSSLIdentity::Generate(const std::string& common_name) {
+OpenSSLIdentity* OpenSSLIdentity::GenerateInternal(
+ const SSLIdentityParams& params) {
OpenSSLKeyPair *key_pair = OpenSSLKeyPair::Generate();
if (key_pair) {
- OpenSSLCertificate *certificate =
- OpenSSLCertificate::Generate(key_pair, common_name);
+ OpenSSLCertificate *certificate = OpenSSLCertificate::Generate(
+ key_pair, params);
if (certificate)
return new OpenSSLIdentity(key_pair, certificate);
delete key_pair;
@@ -333,6 +326,19 @@ OpenSSLIdentity* OpenSSLIdentity::Generate(const std::string& common_name) {
return NULL;
}
+OpenSSLIdentity* OpenSSLIdentity::Generate(const std::string& common_name) {
+ SSLIdentityParams params;
+ params.common_name = common_name;
+ params.not_before = CERTIFICATE_WINDOW;
+ params.not_after = CERTIFICATE_LIFETIME;
+ return GenerateInternal(params);
+}
+
+OpenSSLIdentity* OpenSSLIdentity::GenerateForTest(
+ const SSLIdentityParams& params) {
+ return GenerateInternal(params);
+}
+
SSLIdentity* OpenSSLIdentity::FromPEMStrings(
const std::string& private_key,
const std::string& certificate) {
@@ -348,11 +354,10 @@ SSLIdentity* OpenSSLIdentity::FromPEMStrings(
LOG(LS_ERROR) << "Failed to create a new BIO buffer.";
return NULL;
}
- (void)BIO_set_close(bio, BIO_NOCLOSE);
BIO_set_mem_eof_return(bio, 0);
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL,
const_cast<char*>("\0"));
- BIO_free(bio);
+ BIO_free(bio); // Frees the BIO, but not the pointed-to string.
if (!pkey) {
LOG(LS_ERROR) << "Failed to create the private key from PEM string.";
@@ -376,5 +381,3 @@ bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
} // namespace talk_base
#endif // HAVE_OPENSSL_SSL_H
-
-
diff --git a/chromium/third_party/libjingle/source/talk/base/opensslidentity.h b/chromium/third_party/libjingle/source/talk/base/opensslidentity.h
index af18c5c4d09..84b28261e4d 100644
--- a/chromium/third_party/libjingle/source/talk/base/opensslidentity.h
+++ b/chromium/third_party/libjingle/source/talk/base/opensslidentity.h
@@ -78,7 +78,7 @@ class OpenSSLCertificate : public SSLCertificate {
}
static OpenSSLCertificate* Generate(OpenSSLKeyPair* key_pair,
- const std::string& common_name);
+ const SSLIdentityParams& params);
static OpenSSLCertificate* FromPEMString(const std::string& pem_string);
virtual ~OpenSSLCertificate();
@@ -94,16 +94,17 @@ class OpenSSLCertificate : public SSLCertificate {
virtual void ToDER(Buffer* der_buffer) const;
// Compute the digest of the certificate given algorithm
- virtual bool ComputeDigest(const std::string &algorithm,
- unsigned char *digest, std::size_t size,
- std::size_t *length) const;
+ virtual bool ComputeDigest(const std::string& algorithm,
+ unsigned char* digest,
+ size_t size,
+ size_t* length) const;
// Compute the digest of a certificate as an X509 *
- static bool ComputeDigest(const X509 *x509,
- const std::string &algorithm,
- unsigned char *digest,
- std::size_t size,
- std::size_t *length);
+ static bool ComputeDigest(const X509* x509,
+ const std::string& algorithm,
+ unsigned char* digest,
+ size_t size,
+ size_t* length);
virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const;
@@ -127,6 +128,7 @@ class OpenSSLCertificate : public SSLCertificate {
class OpenSSLIdentity : public SSLIdentity {
public:
static OpenSSLIdentity* Generate(const std::string& common_name);
+ static OpenSSLIdentity* GenerateForTest(const SSLIdentityParams& params);
static SSLIdentity* FromPEMStrings(const std::string& private_key,
const std::string& certificate);
virtual ~OpenSSLIdentity() { }
@@ -151,6 +153,8 @@ class OpenSSLIdentity : public SSLIdentity {
ASSERT(certificate != NULL);
}
+ static OpenSSLIdentity* GenerateInternal(const SSLIdentityParams& params);
+
scoped_ptr<OpenSSLKeyPair> key_pair_;
scoped_ptr<OpenSSLCertificate> certificate_;
diff --git a/chromium/third_party/libjingle/source/talk/base/opensslstreamadapter.cc b/chromium/third_party/libjingle/source/talk/base/opensslstreamadapter.cc
index 034dfcf9266..218f656be12 100644
--- a/chromium/third_party/libjingle/source/talk/base/opensslstreamadapter.cc
+++ b/chromium/third_party/libjingle/source/talk/base/opensslstreamadapter.cc
@@ -37,7 +37,6 @@
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
-#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#include <vector>
@@ -45,6 +44,7 @@
#include "talk/base/common.h"
#include "talk/base/logging.h"
#include "talk/base/stream.h"
+#include "talk/base/openssl.h"
#include "talk/base/openssladapter.h"
#include "talk/base/openssldigest.h"
#include "talk/base/opensslidentity.h"
@@ -57,10 +57,6 @@ namespace talk_base {
#define HAVE_DTLS_SRTP
#endif
-#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
-#define HAVE_DTLS
-#endif
-
#ifdef HAVE_DTLS_SRTP
// SRTP cipher suite table
struct SrtpCipherMapEntry {
@@ -210,13 +206,6 @@ void OpenSSLStreamAdapter::SetServerRole(SSLRole role) {
role_ = role;
}
-void OpenSSLStreamAdapter::SetPeerCertificate(SSLCertificate* cert) {
- ASSERT(!peer_certificate_);
- ASSERT(peer_certificate_digest_algorithm_.empty());
- ASSERT(ssl_server_name_.empty());
- peer_certificate_.reset(static_cast<OpenSSLCertificate*>(cert));
-}
-
bool OpenSSLStreamAdapter::GetPeerCertificate(SSLCertificate** cert) const {
if (!peer_certificate_)
return false;
@@ -274,12 +263,12 @@ bool OpenSSLStreamAdapter::ExportKeyingMaterial(const std::string& label,
bool OpenSSLStreamAdapter::SetDtlsSrtpCiphers(
const std::vector<std::string>& ciphers) {
+#ifdef HAVE_DTLS_SRTP
std::string internal_ciphers;
if (state_ != SSL_NONE)
return false;
-#ifdef HAVE_DTLS_SRTP
for (std::vector<std::string>::const_iterator cipher = ciphers.begin();
cipher != ciphers.end(); ++cipher) {
bool found = false;
@@ -613,7 +602,6 @@ int OpenSSLStreamAdapter::BeginSSL() {
// The underlying stream has open. If we are in peer-to-peer mode
// then a peer certificate must have been specified by now.
ASSERT(!ssl_server_name_.empty() ||
- peer_certificate_ ||
!peer_certificate_digest_algorithm_.empty());
LOG(LS_INFO) << "BeginSSL: "
<< (!ssl_server_name_.empty() ? ssl_server_name_ :
@@ -661,9 +649,7 @@ int OpenSSLStreamAdapter::ContinueSSL() {
case SSL_ERROR_NONE:
LOG(LS_VERBOSE) << " -- success";
- if (!SSLPostConnectionCheck(ssl_, ssl_server_name_.c_str(),
- peer_certificate_ ?
- peer_certificate_->x509() : NULL,
+ if (!SSLPostConnectionCheck(ssl_, ssl_server_name_.c_str(), NULL,
peer_certificate_digest_algorithm_)) {
LOG(LS_ERROR) << "TLS post connection check failed";
return -1;
@@ -675,14 +661,12 @@ int OpenSSLStreamAdapter::ContinueSSL() {
case SSL_ERROR_WANT_READ: {
LOG(LS_VERBOSE) << " -- error want read";
-#ifdef HAVE_DTLS
struct timeval timeout;
if (DTLSv1_get_timeout(ssl_, &timeout)) {
int delay = timeout.tv_sec * 1000 + timeout.tv_usec/1000;
Thread::Current()->PostDelayed(delay, this, MSG_TIMEOUT, 0);
}
-#endif
}
break;
@@ -737,9 +721,7 @@ void OpenSSLStreamAdapter::OnMessage(Message* msg) {
// Process our own messages and then pass others to the superclass
if (MSG_TIMEOUT == msg->message_id) {
LOG(LS_INFO) << "DTLS timeout expired";
-#ifdef HAVE_DTLS
DTLSv1_handle_timeout(ssl_);
-#endif
ContinueSSL();
} else {
StreamInterface::OnMessage(msg);
@@ -750,19 +732,11 @@ SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
SSL_CTX *ctx = NULL;
if (role_ == SSL_CLIENT) {
-#ifdef HAVE_DTLS
ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ?
DTLSv1_client_method() : TLSv1_client_method());
-#else
- ctx = SSL_CTX_new(TLSv1_client_method());
-#endif
} else {
-#ifdef HAVE_DTLS
ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ?
DTLSv1_server_method() : TLSv1_server_method());
-#else
- ctx = SSL_CTX_new(TLSv1_server_method());
-#endif
}
if (ctx == NULL)
return NULL;
@@ -772,18 +746,6 @@ SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
return NULL;
}
- if (!peer_certificate_) { // traditional mode
- // Add the root cert to the SSL context
- if (!OpenSSLAdapter::ConfigureTrustedRootCertificates(ctx)) {
- SSL_CTX_free(ctx);
- return NULL;
- }
- }
-
- if (peer_certificate_ && role_ == SSL_SERVER)
- // we must specify which client cert to ask for
- SSL_CTX_add_client_CA(ctx, peer_certificate_->x509());
-
#ifdef _DEBUG
SSL_CTX_set_info_callback(ctx, OpenSSLAdapter::SSLInfoCallback);
#endif
@@ -806,88 +768,53 @@ SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
}
int OpenSSLStreamAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) {
-#if _DEBUG
- if (!ok) {
- char data[256];
- X509* cert = X509_STORE_CTX_get_current_cert(store);
- int depth = X509_STORE_CTX_get_error_depth(store);
- int err = X509_STORE_CTX_get_error(store);
-
- LOG(LS_INFO) << "Error with certificate at depth: " << depth;
- X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof(data));
- LOG(LS_INFO) << " issuer = " << data;
- X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof(data));
- LOG(LS_INFO) << " subject = " << data;
- LOG(LS_INFO) << " err = " << err
- << ":" << X509_verify_cert_error_string(err);
- }
-#endif
-
// Get our SSL structure from the store
SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(
store,
SSL_get_ex_data_X509_STORE_CTX_idx()));
-
OpenSSLStreamAdapter* stream =
reinterpret_cast<OpenSSLStreamAdapter*>(SSL_get_app_data(ssl));
- // In peer-to-peer mode, no root cert / certificate authority was
- // specified, so the libraries knows of no certificate to accept,
- // and therefore it will necessarily call here on the first cert it
- // tries to verify.
- if (!ok && stream->peer_certificate_) {
- X509* cert = X509_STORE_CTX_get_current_cert(store);
- int err = X509_STORE_CTX_get_error(store);
- // peer-to-peer mode: allow the certificate to be self-signed,
- // assuming it matches the cert that was specified.
- if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT &&
- X509_cmp(cert, stream->peer_certificate_->x509()) == 0) {
- LOG(LS_INFO) << "Accepted self-signed peer certificate authority";
- ok = 1;
- }
- } else if (!ok && !stream->peer_certificate_digest_algorithm_.empty()) {
- X509* cert = X509_STORE_CTX_get_current_cert(store);
- int err = X509_STORE_CTX_get_error(store);
-
- // peer-to-peer mode: allow the certificate to be self-signed,
- // assuming it matches the digest that was specified.
- if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) {
- unsigned char digest[EVP_MAX_MD_SIZE];
- std::size_t digest_length;
-
- if (OpenSSLCertificate::
- ComputeDigest(cert,
- stream->peer_certificate_digest_algorithm_,
- digest, sizeof(digest),
- &digest_length)) {
- Buffer computed_digest(digest, digest_length);
- if (computed_digest == stream->peer_certificate_digest_value_) {
- LOG(LS_INFO) <<
- "Accepted self-signed peer certificate authority";
- ok = 1;
-
- // Record the peer's certificate.
- stream->peer_certificate_.reset(new OpenSSLCertificate(cert));
- }
- }
- }
- } else if (!ok && OpenSSLAdapter::custom_verify_callback_) {
- // this applies only in traditional mode
- void* cert =
- reinterpret_cast<void*>(X509_STORE_CTX_get_current_cert(store));
- if (OpenSSLAdapter::custom_verify_callback_(cert)) {
- stream->custom_verification_succeeded_ = true;
- LOG(LS_INFO) << "validated certificate using custom callback";
- ok = 1;
- }
+ if (stream->peer_certificate_digest_algorithm_.empty()) {
+ return 0;
+ }
+ X509* cert = X509_STORE_CTX_get_current_cert(store);
+ int depth = X509_STORE_CTX_get_error_depth(store);
+
+ // For now We ignore the parent certificates and verify the leaf against
+ // the digest.
+ //
+ // TODO(jiayl): Verify the chain is a proper chain and report the chain to
+ // |stream->peer_certificate_|, like what NSS does.
+ if (depth > 0) {
+ LOG(LS_INFO) << "Ignored chained certificate at depth " << depth;
+ return 1;
+ }
+
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ size_t digest_length;
+ if (!OpenSSLCertificate::ComputeDigest(
+ cert,
+ stream->peer_certificate_digest_algorithm_,
+ digest, sizeof(digest),
+ &digest_length)) {
+ LOG(LS_WARNING) << "Failed to compute peer cert digest.";
+ return 0;
}
- if (!ok && stream->ignore_bad_cert()) {
- LOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
- ok = 1;
+ Buffer computed_digest(digest, digest_length);
+ if (computed_digest != stream->peer_certificate_digest_value_) {
+ LOG(LS_WARNING) << "Rejected peer certificate due to mismatched digest.";
+ return 0;
}
+ // Ignore any verification error if the digest matches, since there is no
+ // value in checking the validity of a self-signed cert issued by untrusted
+ // sources.
+ LOG(LS_INFO) << "Accepted peer certificate.";
- return ok;
+ // Record the peer's certificate.
+ stream->peer_certificate_.reset(new OpenSSLCertificate(cert));
+ return 1;
}
// This code is taken from the "Network Security with OpenSSL"
@@ -923,11 +850,7 @@ bool OpenSSLStreamAdapter::SSLPostConnectionCheck(SSL* ssl,
}
bool OpenSSLStreamAdapter::HaveDtls() {
-#ifdef HAVE_DTLS
return true;
-#else
- return false;
-#endif
}
bool OpenSSLStreamAdapter::HaveDtlsSrtp() {
diff --git a/chromium/third_party/libjingle/source/talk/base/opensslstreamadapter.h b/chromium/third_party/libjingle/source/talk/base/opensslstreamadapter.h
index 3c478187fcc..744d29980e1 100644
--- a/chromium/third_party/libjingle/source/talk/base/opensslstreamadapter.h
+++ b/chromium/third_party/libjingle/source/talk/base/opensslstreamadapter.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2008, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -81,7 +81,6 @@ class OpenSSLStreamAdapter : public SSLStreamAdapter {
// Default argument is for compatibility
virtual void SetServerRole(SSLRole role = SSL_SERVER);
- virtual void SetPeerCertificate(SSLCertificate* cert);
virtual bool SetPeerCertificateDigest(const std::string& digest_alg,
const unsigned char* digest_val,
size_t digest_len);
@@ -175,7 +174,6 @@ class OpenSSLStreamAdapter : public SSLStreamAdapter {
// passed.
static int SSLVerifyCallback(int ok, X509_STORE_CTX* store);
-
SSLState state_;
SSLRole role_;
int ssl_error_code_; // valid when state_ == SSL_ERROR or SSL_CLOSED
diff --git a/chromium/third_party/libjingle/source/talk/base/optionsfile_unittest.cc b/chromium/third_party/libjingle/source/talk/base/optionsfile_unittest.cc
index 65861ff4982..afb79cf9a7b 100644
--- a/chromium/third_party/libjingle/source/talk/base/optionsfile_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/optionsfile_unittest.cc
@@ -25,19 +25,13 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "talk/base/fileutils.h"
#include "talk/base/gunit.h"
#include "talk/base/optionsfile.h"
+#include "talk/base/pathutils.h"
namespace talk_base {
-#ifdef ANDROID
-static const char *kTestFile = "/sdcard/.testfile";
-#elif CHROMEOS
-static const char *kTestFile = "/tmp/.testfile";
-#else
-static const char *kTestFile = ".testfile";
-#endif
-
static const std::string kTestOptionA = "test-option-a";
static const std::string kTestOptionB = "test-option-b";
static const std::string kTestString1 = "a string";
@@ -56,122 +50,135 @@ static int kTestInt2 = 67890;
static int kNegInt = -634;
static int kZero = 0;
-TEST(OptionsFile, GetSetString) {
- OptionsFile store(kTestFile);
+class OptionsFileTest : public testing::Test {
+ public:
+ OptionsFileTest() {
+ Pathname dir;
+ ASSERT(Filesystem::GetTemporaryFolder(dir, true, NULL));
+ test_file_ = Filesystem::TempFilename(dir, ".testfile");
+ OpenStore();
+ }
+
+ protected:
+ void OpenStore() {
+ store_.reset(new OptionsFile(test_file_));
+ }
+
+ talk_base::scoped_ptr<OptionsFile> store_;
+
+ private:
+ std::string test_file_;
+};
+
+TEST_F(OptionsFileTest, GetSetString) {
// Clear contents of the file on disk.
- EXPECT_TRUE(store.Save());
+ EXPECT_TRUE(store_->Save());
std::string out1, out2;
- EXPECT_FALSE(store.GetStringValue(kTestOptionA, &out1));
- EXPECT_FALSE(store.GetStringValue(kTestOptionB, &out2));
- EXPECT_TRUE(store.SetStringValue(kTestOptionA, kTestString1));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_TRUE(store.SetStringValue(kTestOptionB, kTestString2));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_TRUE(store.GetStringValue(kTestOptionA, &out1));
- EXPECT_TRUE(store.GetStringValue(kTestOptionB, &out2));
+ EXPECT_FALSE(store_->GetStringValue(kTestOptionA, &out1));
+ EXPECT_FALSE(store_->GetStringValue(kTestOptionB, &out2));
+ EXPECT_TRUE(store_->SetStringValue(kTestOptionA, kTestString1));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_TRUE(store_->SetStringValue(kTestOptionB, kTestString2));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_TRUE(store_->GetStringValue(kTestOptionA, &out1));
+ EXPECT_TRUE(store_->GetStringValue(kTestOptionB, &out2));
EXPECT_EQ(kTestString1, out1);
EXPECT_EQ(kTestString2, out2);
- EXPECT_TRUE(store.RemoveValue(kTestOptionA));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_TRUE(store.RemoveValue(kTestOptionB));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_FALSE(store.GetStringValue(kTestOptionA, &out1));
- EXPECT_FALSE(store.GetStringValue(kTestOptionB, &out2));
+ EXPECT_TRUE(store_->RemoveValue(kTestOptionA));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_TRUE(store_->RemoveValue(kTestOptionB));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_FALSE(store_->GetStringValue(kTestOptionA, &out1));
+ EXPECT_FALSE(store_->GetStringValue(kTestOptionB, &out2));
}
-TEST(OptionsFile, GetSetInt) {
- OptionsFile store(kTestFile);
+TEST_F(OptionsFileTest, GetSetInt) {
// Clear contents of the file on disk.
- EXPECT_TRUE(store.Save());
+ EXPECT_TRUE(store_->Save());
int out1, out2;
- EXPECT_FALSE(store.GetIntValue(kTestOptionA, &out1));
- EXPECT_FALSE(store.GetIntValue(kTestOptionB, &out2));
- EXPECT_TRUE(store.SetIntValue(kTestOptionA, kTestInt1));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_TRUE(store.SetIntValue(kTestOptionB, kTestInt2));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_TRUE(store.GetIntValue(kTestOptionA, &out1));
- EXPECT_TRUE(store.GetIntValue(kTestOptionB, &out2));
+ EXPECT_FALSE(store_->GetIntValue(kTestOptionA, &out1));
+ EXPECT_FALSE(store_->GetIntValue(kTestOptionB, &out2));
+ EXPECT_TRUE(store_->SetIntValue(kTestOptionA, kTestInt1));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_TRUE(store_->SetIntValue(kTestOptionB, kTestInt2));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_TRUE(store_->GetIntValue(kTestOptionA, &out1));
+ EXPECT_TRUE(store_->GetIntValue(kTestOptionB, &out2));
EXPECT_EQ(kTestInt1, out1);
EXPECT_EQ(kTestInt2, out2);
- EXPECT_TRUE(store.RemoveValue(kTestOptionA));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_TRUE(store.RemoveValue(kTestOptionB));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_FALSE(store.GetIntValue(kTestOptionA, &out1));
- EXPECT_FALSE(store.GetIntValue(kTestOptionB, &out2));
- EXPECT_TRUE(store.SetIntValue(kTestOptionA, kNegInt));
- EXPECT_TRUE(store.GetIntValue(kTestOptionA, &out1));
+ EXPECT_TRUE(store_->RemoveValue(kTestOptionA));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_TRUE(store_->RemoveValue(kTestOptionB));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_FALSE(store_->GetIntValue(kTestOptionA, &out1));
+ EXPECT_FALSE(store_->GetIntValue(kTestOptionB, &out2));
+ EXPECT_TRUE(store_->SetIntValue(kTestOptionA, kNegInt));
+ EXPECT_TRUE(store_->GetIntValue(kTestOptionA, &out1));
EXPECT_EQ(kNegInt, out1);
- EXPECT_TRUE(store.SetIntValue(kTestOptionA, kZero));
- EXPECT_TRUE(store.GetIntValue(kTestOptionA, &out1));
+ EXPECT_TRUE(store_->SetIntValue(kTestOptionA, kZero));
+ EXPECT_TRUE(store_->GetIntValue(kTestOptionA, &out1));
EXPECT_EQ(kZero, out1);
}
-TEST(OptionsFile, Persist) {
- {
- OptionsFile store(kTestFile);
- // Clear contents of the file on disk.
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.SetStringValue(kTestOptionA, kTestString1));
- EXPECT_TRUE(store.SetIntValue(kTestOptionB, kNegInt));
- EXPECT_TRUE(store.Save());
- }
- {
- OptionsFile store(kTestFile);
- // Load the saved contents from above.
- EXPECT_TRUE(store.Load());
- std::string out1;
- int out2;
- EXPECT_TRUE(store.GetStringValue(kTestOptionA, &out1));
- EXPECT_TRUE(store.GetIntValue(kTestOptionB, &out2));
- EXPECT_EQ(kTestString1, out1);
- EXPECT_EQ(kNegInt, out2);
- }
+TEST_F(OptionsFileTest, Persist) {
+ // Clear contents of the file on disk.
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->SetStringValue(kTestOptionA, kTestString1));
+ EXPECT_TRUE(store_->SetIntValue(kTestOptionB, kNegInt));
+ EXPECT_TRUE(store_->Save());
+
+ // Load the saved contents from above.
+ OpenStore();
+ EXPECT_TRUE(store_->Load());
+ std::string out1;
+ int out2;
+ EXPECT_TRUE(store_->GetStringValue(kTestOptionA, &out1));
+ EXPECT_TRUE(store_->GetIntValue(kTestOptionB, &out2));
+ EXPECT_EQ(kTestString1, out1);
+ EXPECT_EQ(kNegInt, out2);
}
-TEST(OptionsFile, SpecialCharacters) {
- OptionsFile store(kTestFile);
+TEST_F(OptionsFileTest, SpecialCharacters) {
// Clear contents of the file on disk.
- EXPECT_TRUE(store.Save());
+ EXPECT_TRUE(store_->Save());
std::string out;
- EXPECT_FALSE(store.SetStringValue(kOptionWithEquals, kTestString1));
- EXPECT_FALSE(store.GetStringValue(kOptionWithEquals, &out));
- EXPECT_FALSE(store.SetStringValue(kOptionWithNewline, kTestString1));
- EXPECT_FALSE(store.GetStringValue(kOptionWithNewline, &out));
- EXPECT_TRUE(store.SetStringValue(kOptionWithUtf8, kValueWithUtf8));
- EXPECT_TRUE(store.SetStringValue(kTestOptionA, kTestString1));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_TRUE(store.GetStringValue(kTestOptionA, &out));
+ EXPECT_FALSE(store_->SetStringValue(kOptionWithEquals, kTestString1));
+ EXPECT_FALSE(store_->GetStringValue(kOptionWithEquals, &out));
+ EXPECT_FALSE(store_->SetStringValue(kOptionWithNewline, kTestString1));
+ EXPECT_FALSE(store_->GetStringValue(kOptionWithNewline, &out));
+ EXPECT_TRUE(store_->SetStringValue(kOptionWithUtf8, kValueWithUtf8));
+ EXPECT_TRUE(store_->SetStringValue(kTestOptionA, kTestString1));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_TRUE(store_->GetStringValue(kTestOptionA, &out));
EXPECT_EQ(kTestString1, out);
- EXPECT_TRUE(store.GetStringValue(kOptionWithUtf8, &out));
+ EXPECT_TRUE(store_->GetStringValue(kOptionWithUtf8, &out));
EXPECT_EQ(kValueWithUtf8, out);
- EXPECT_FALSE(store.SetStringValue(kTestOptionA, kValueWithNewline));
- EXPECT_TRUE(store.GetStringValue(kTestOptionA, &out));
+ EXPECT_FALSE(store_->SetStringValue(kTestOptionA, kValueWithNewline));
+ EXPECT_TRUE(store_->GetStringValue(kTestOptionA, &out));
EXPECT_EQ(kTestString1, out);
- EXPECT_TRUE(store.SetStringValue(kTestOptionA, kValueWithEquals));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_TRUE(store.GetStringValue(kTestOptionA, &out));
+ EXPECT_TRUE(store_->SetStringValue(kTestOptionA, kValueWithEquals));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_TRUE(store_->GetStringValue(kTestOptionA, &out));
EXPECT_EQ(kValueWithEquals, out);
- EXPECT_TRUE(store.SetStringValue(kEmptyString, kTestString2));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_TRUE(store.GetStringValue(kEmptyString, &out));
+ EXPECT_TRUE(store_->SetStringValue(kEmptyString, kTestString2));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_TRUE(store_->GetStringValue(kEmptyString, &out));
EXPECT_EQ(kTestString2, out);
- EXPECT_TRUE(store.SetStringValue(kTestOptionB, kEmptyString));
- EXPECT_TRUE(store.Save());
- EXPECT_TRUE(store.Load());
- EXPECT_TRUE(store.GetStringValue(kTestOptionB, &out));
+ EXPECT_TRUE(store_->SetStringValue(kTestOptionB, kEmptyString));
+ EXPECT_TRUE(store_->Save());
+ EXPECT_TRUE(store_->Load());
+ EXPECT_TRUE(store_->GetStringValue(kTestOptionB, &out));
EXPECT_EQ(kEmptyString, out);
}
diff --git a/chromium/third_party/libjingle/source/talk/base/physicalsocketserver.cc b/chromium/third_party/libjingle/source/talk/base/physicalsocketserver.cc
index 43be440e7bd..a7f65c57acc 100644
--- a/chromium/third_party/libjingle/source/talk/base/physicalsocketserver.cc
+++ b/chromium/third_party/libjingle/source/talk/base/physicalsocketserver.cc
@@ -29,13 +29,14 @@
#pragma warning(disable:4786)
#endif
-#include <cassert>
+#include <assert.h>
#ifdef POSIX
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
+#include <sys/select.h>
#include <unistd.h>
#include <signal.h>
#endif
@@ -78,6 +79,7 @@ typedef char* SockOptArg;
namespace talk_base {
+#if defined(WIN32)
// Standard MTUs, from RFC 1191
const uint16 PACKET_MAXIMUMS[] = {
65535, // Theoretical maximum, Hyperchannel
@@ -105,6 +107,7 @@ static const int IP_HEADER_SIZE = 20u;
static const int IPV6_HEADER_SIZE = 40u;
static const int ICMP_HEADER_SIZE = 8u;
static const int ICMP_PING_TIMEOUT_MILLIS = 10000u;
+#endif
class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
public:
@@ -498,7 +501,7 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
}
void MaybeRemapSendError() {
-#if defined(OSX)
+#if defined(OSX) || defined(IOS)
// https://developer.apple.com/library/mac/documentation/Darwin/
// Reference/ManPages/man2/sendto.2.html
// ENOBUFS - The output queue for a network interface is full.
@@ -517,7 +520,7 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
*slevel = IPPROTO_IP;
*sopt = IP_DONTFRAGMENT;
break;
-#elif defined(IOS) || defined(OSX) || defined(BSD)
+#elif defined(IOS) || defined(OSX) || defined(BSD) || defined(__native_client__)
LOG(LS_WARNING) << "Socket::OPT_DONTFRAGMENT not supported.";
return -1;
#elif defined(POSIX)
@@ -540,6 +543,8 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
case OPT_DSCP:
LOG(LS_WARNING) << "Socket::OPT_DSCP not supported.";
return -1;
+ case OPT_RTP_SENDTIME_EXTN_ID:
+ return -1; // No logging is necessary as this not a OS socket option.
default:
ASSERT(false);
return -1;
@@ -1199,9 +1204,7 @@ class Signaler : public EventDispatcher {
};
PhysicalSocketServer::PhysicalSocketServer()
- : fWait_(false),
- last_tick_tracked_(0),
- last_tick_dispatch_count_(0) {
+ : fWait_(false) {
signal_wakeup_ = new Signaler(this, &fWait_);
#ifdef WIN32
socket_ev_ = WSACreateEvent();
@@ -1489,10 +1492,14 @@ bool PhysicalSocketServer::InstallSignal(int signum, void (*handler)(int)) {
return false;
}
act.sa_handler = handler;
+#if !defined(__native_client__)
// Use SA_RESTART so that our syscalls don't get EINTR, since we don't need it
// and it's a nuisance. Though some syscalls still return EINTR and there's no
// real standard for which ones. :(
act.sa_flags = SA_RESTART;
+#else
+ act.sa_flags = 0;
+#endif
if (sigaction(signum, &act, NULL) != 0) {
LOG_ERR(LS_ERROR) << "Couldn't set sigaction";
return false;
@@ -1507,12 +1514,6 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
int cmsElapsed = 0;
uint32 msStart = Time();
-#if LOGGING
- if (last_tick_dispatch_count_ == 0) {
- last_tick_tracked_ = msStart;
- }
-#endif
-
fWait_ = true;
while (fWait_) {
std::vector<WSAEVENT> events;
@@ -1562,27 +1563,10 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
cmsNext,
false);
-#if 0 // LOGGING
- // we track this information purely for logging purposes.
- last_tick_dispatch_count_++;
- if (last_tick_dispatch_count_ >= 1000) {
- int32 elapsed = TimeSince(last_tick_tracked_);
- LOG(INFO) << "PhysicalSocketServer took " << elapsed
- << "ms for 1000 events";
-
- // If we get more than 1000 events in a second, we are spinning badly
- // (normally it should take about 8-20 seconds).
- ASSERT(elapsed > 1000);
-
- last_tick_tracked_ = Time();
- last_tick_dispatch_count_ = 0;
- }
-#endif
-
if (dw == WSA_WAIT_FAILED) {
// Failed?
// TODO: need a better strategy than this!
- int error = WSAGetLastError();
+ WSAGetLastError();
ASSERT(false);
return false;
} else if (dw == WSA_WAIT_TIMEOUT) {
diff --git a/chromium/third_party/libjingle/source/talk/base/physicalsocketserver.h b/chromium/third_party/libjingle/source/talk/base/physicalsocketserver.h
index 709f85ab105..9173f238dff 100644
--- a/chromium/third_party/libjingle/source/talk/base/physicalsocketserver.h
+++ b/chromium/third_party/libjingle/source/talk/base/physicalsocketserver.h
@@ -127,8 +127,6 @@ class PhysicalSocketServer : public SocketServer {
Signaler* signal_wakeup_;
CriticalSection crit_;
bool fWait_;
- uint32 last_tick_tracked_;
- int last_tick_dispatch_count_;
#ifdef WIN32
WSAEVENT socket_ev_;
#endif
diff --git a/chromium/third_party/libjingle/source/talk/base/physicalsocketserver_unittest.cc b/chromium/third_party/libjingle/source/talk/base/physicalsocketserver_unittest.cc
index 329cf5d5f25..cbdbd9cad6a 100644
--- a/chromium/third_party/libjingle/source/talk/base/physicalsocketserver_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/physicalsocketserver_unittest.cc
@@ -33,6 +33,7 @@
#include "talk/base/physicalsocketserver.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/socket_unittest.h"
+#include "talk/base/testutils.h"
#include "talk/base/thread.h"
namespace talk_base {
@@ -74,21 +75,11 @@ TEST_F(PhysicalSocketTest, TestConnectWithDnsLookupFailIPv6) {
}
-#ifdef OSX
-// This test crashes the OS X kernel on 10.6 (at bsd/netinet/tcp_subr.c:2118).
-TEST_F(PhysicalSocketTest, DISABLED_TestConnectWithClosedSocketIPv4) {
-#else
TEST_F(PhysicalSocketTest, TestConnectWithClosedSocketIPv4) {
-#endif
SocketTest::TestConnectWithClosedSocketIPv4();
}
-#ifdef OSX
-// This test crashes the OS X kernel on 10.6 (at bsd/netinet/tcp_subr.c:2118).
-TEST_F(PhysicalSocketTest, DISABLED_TestConnectWithClosedSocketIPv6) {
-#else
TEST_F(PhysicalSocketTest, TestConnectWithClosedSocketIPv6) {
-#endif
SocketTest::TestConnectWithClosedSocketIPv6();
}
@@ -227,7 +218,7 @@ Thread *PosixSignalDeliveryTest::signaled_thread_ = NULL;
// Test receiving a synchronous signal while not in Wait() and then entering
// Wait() afterwards.
TEST_F(PosixSignalDeliveryTest, RaiseThenWait) {
- ss_->SetPosixSignalHandler(SIGTERM, &RecordSignal);
+ ASSERT_TRUE(ss_->SetPosixSignalHandler(SIGTERM, &RecordSignal));
raise(SIGTERM);
EXPECT_TRUE(ss_->Wait(0, true));
EXPECT_TRUE(ExpectSignal(SIGTERM));
diff --git a/chromium/third_party/libjingle/source/talk/base/profiler.h b/chromium/third_party/libjingle/source/talk/base/profiler.h
index 90c5c722a30..f74a540ae47 100644
--- a/chromium/third_party/libjingle/source/talk/base/profiler.h
+++ b/chromium/third_party/libjingle/source/talk/base/profiler.h
@@ -57,7 +57,9 @@
#include "talk/base/sharedexclusivelock.h"
// Profiling could be switched via a build flag, but for now, it's always on.
+#ifndef ENABLE_PROFILING
#define ENABLE_PROFILING
+#endif
#ifdef ENABLE_PROFILING
diff --git a/chromium/third_party/libjingle/source/talk/base/profiler_unittest.cc b/chromium/third_party/libjingle/source/talk/base/profiler_unittest.cc
index f451e5fab83..a39b32c4995 100644
--- a/chromium/third_party/libjingle/source/talk/base/profiler_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/profiler_unittest.cc
@@ -47,13 +47,15 @@ namespace talk_base {
TEST(ProfilerTest, TestFunction) {
ASSERT_TRUE(Profiler::Instance()->Clear());
+
// Profile a long-running function.
const char* function_name = TestFunc();
const ProfilerEvent* event = Profiler::Instance()->GetEvent(function_name);
ASSERT_TRUE(event != NULL);
EXPECT_FALSE(event->is_started());
EXPECT_EQ(1, event->event_count());
- EXPECT_NEAR(kWaitSec, event->mean(), kTolerance);
+ EXPECT_NEAR(kWaitSec, event->mean(), kTolerance * 3);
+
// Run it a second time.
TestFunc();
EXPECT_FALSE(event->is_started());
@@ -95,7 +97,9 @@ TEST(ProfilerTest, TestScopedEvents) {
// Check the result.
EXPECT_FALSE(event2->is_started());
EXPECT_EQ(1, event2->event_count());
- EXPECT_NEAR(kEvent2WaitSec, event2->mean(), kTolerance);
+
+ // The difference here can be as much as 0.33, so we need high tolerance.
+ EXPECT_NEAR(kEvent2WaitSec, event2->mean(), kTolerance * 4);
// Make sure event1 is unchanged.
EXPECT_FALSE(event1->is_started());
EXPECT_EQ(1, event1->event_count());
diff --git a/chromium/third_party/libjingle/source/talk/base/proxydetect.cc b/chromium/third_party/libjingle/source/talk/base/proxydetect.cc
index 7292f3b9fd2..8f7f7f87260 100644
--- a/chromium/third_party/libjingle/source/talk/base/proxydetect.cc
+++ b/chromium/third_party/libjingle/source/talk/base/proxydetect.cc
@@ -638,27 +638,27 @@ bool IsDefaultBrowserFirefox() {
if (ERROR_SUCCESS != result)
return false;
- wchar_t* value = NULL;
DWORD size, type;
+ bool success = false;
result = RegQueryValueEx(key, L"", 0, &type, NULL, &size);
- if (REG_SZ != type) {
- result = ERROR_ACCESS_DENIED; // Any error is fine
- } else if (ERROR_SUCCESS == result) {
- value = new wchar_t[size+1];
+ if (result == ERROR_SUCCESS && type == REG_SZ) {
+ wchar_t* value = new wchar_t[size+1];
BYTE* buffer = reinterpret_cast<BYTE*>(value);
result = RegQueryValueEx(key, L"", 0, &type, buffer, &size);
- }
- RegCloseKey(key);
-
- bool success = false;
- if (ERROR_SUCCESS == result) {
- value[size] = L'\0';
- for (size_t i = 0; i < size; ++i) {
- value[i] = tolowercase(value[i]);
+ if (result == ERROR_SUCCESS) {
+ // Size returned by RegQueryValueEx is in bytes, convert to number of
+ // wchar_t's.
+ size /= sizeof(value[0]);
+ value[size] = L'\0';
+ for (size_t i = 0; i < size; ++i) {
+ value[i] = tolowercase(value[i]);
+ }
+ success = (NULL != strstr(value, L"firefox.exe"));
}
- success = (NULL != strstr(value, L"firefox.exe"));
+ delete[] value;
}
- delete [] value;
+
+ RegCloseKey(key);
return success;
}
diff --git a/chromium/third_party/libjingle/source/talk/base/proxydetect_unittest.cc b/chromium/third_party/libjingle/source/talk/base/proxydetect_unittest.cc
index 685066d9432..e09518b5f41 100644
--- a/chromium/third_party/libjingle/source/talk/base/proxydetect_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/proxydetect_unittest.cc
@@ -51,7 +51,6 @@ static const std::string kFirefoxCorruptHeader =
"iuahueqe32164";
static const std::string kProxyAddress = "proxy.net.com";
-static const int kProxyPort = 9999;
// Mocking out platform specific path to firefox prefs file.
class FirefoxPrefsFileSystem : public FakeFileSystem {
diff --git a/chromium/third_party/libjingle/source/talk/base/refcount.h b/chromium/third_party/libjingle/source/talk/base/refcount.h
index 38cf147621a..e8950e9b04c 100644
--- a/chromium/third_party/libjingle/source/talk/base/refcount.h
+++ b/chromium/third_party/libjingle/source/talk/base/refcount.h
@@ -28,7 +28,7 @@
#ifndef TALK_APP_BASE_REFCOUNT_H_
#define TALK_APP_BASE_REFCOUNT_H_
-#include <cstring>
+#include <string.h>
#include "talk/base/criticalsection.h"
diff --git a/chromium/third_party/libjingle/source/talk/base/rollingaccumulator.h b/chromium/third_party/libjingle/source/talk/base/rollingaccumulator.h
index cdad0251f3f..dfda8fec072 100644
--- a/chromium/third_party/libjingle/source/talk/base/rollingaccumulator.h
+++ b/chromium/third_party/libjingle/source/talk/base/rollingaccumulator.h
@@ -42,11 +42,8 @@ template<typename T>
class RollingAccumulator {
public:
explicit RollingAccumulator(size_t max_count)
- : count_(0),
- next_index_(0),
- sum_(0.0),
- sum_2_(0.0),
- samples_(max_count) {
+ : samples_(max_count) {
+ Reset();
}
~RollingAccumulator() {
}
@@ -59,12 +56,29 @@ class RollingAccumulator {
return count_;
}
+ void Reset() {
+ count_ = 0U;
+ next_index_ = 0U;
+ sum_ = 0.0;
+ sum_2_ = 0.0;
+ max_ = T();
+ max_stale_ = false;
+ min_ = T();
+ min_stale_ = false;
+ }
+
void AddSample(T sample) {
if (count_ == max_count()) {
// Remove oldest sample.
T sample_to_remove = samples_[next_index_];
sum_ -= sample_to_remove;
sum_2_ -= sample_to_remove * sample_to_remove;
+ if (sample_to_remove >= max_) {
+ max_stale_ = true;
+ }
+ if (sample_to_remove <= min_) {
+ min_stale_ = true;
+ }
} else {
// Increase count of samples.
++count_;
@@ -73,6 +87,14 @@ class RollingAccumulator {
samples_[next_index_] = sample;
sum_ += sample;
sum_2_ += sample * sample;
+ if (count_ == 1 || sample >= max_) {
+ max_ = sample;
+ max_stale_ = false;
+ }
+ if (count_ == 1 || sample <= min_) {
+ min_ = sample;
+ min_stale_ = false;
+ }
// Update next_index_.
next_index_ = (next_index_ + 1) % max_count();
}
@@ -81,17 +103,43 @@ class RollingAccumulator {
return static_cast<T>(sum_);
}
- T ComputeMean() const {
+ double ComputeMean() const {
if (count_ == 0) {
- return static_cast<T>(0);
+ return 0.0;
+ }
+ return sum_ / count_;
+ }
+
+ T ComputeMax() const {
+ if (max_stale_) {
+ ASSERT(count_ > 0 &&
+ "It shouldn't be possible for max_stale_ && count_ == 0");
+ max_ = samples_[next_index_];
+ for (size_t i = 1u; i < count_; i++) {
+ max_ = _max(max_, samples_[(next_index_ + i) % max_count()]);
+ }
+ max_stale_ = false;
+ }
+ return max_;
+ }
+
+ T ComputeMin() const {
+ if (min_stale_) {
+ ASSERT(count_ > 0 &&
+ "It shouldn't be possible for min_stale_ && count_ == 0");
+ min_ = samples_[next_index_];
+ for (size_t i = 1u; i < count_; i++) {
+ min_ = _min(min_, samples_[(next_index_ + i) % max_count()]);
+ }
+ min_stale_ = false;
}
- return static_cast<T>(sum_ / count_);
+ return min_;
}
// O(n) time complexity.
// Weights nth sample with weight (learning_rate)^n. Learning_rate should be
// between (0.0, 1.0], otherwise the non-weighted mean is returned.
- T ComputeWeightedMean(double learning_rate) const {
+ double ComputeWeightedMean(double learning_rate) const {
if (count_ < 1 || learning_rate <= 0.0 || learning_rate >= 1.0) {
return ComputeMean();
}
@@ -106,27 +154,31 @@ class RollingAccumulator {
size_t index = (next_index_ + max_size - i - 1) % max_size;
weighted_mean += current_weight * samples_[index];
}
- return static_cast<T>(weighted_mean / weight_sum);
+ return weighted_mean / weight_sum;
}
// Compute estimated variance. Estimation is more accurate
// as the number of samples grows.
- T ComputeVariance() const {
+ double ComputeVariance() const {
if (count_ == 0) {
- return static_cast<T>(0);
+ return 0.0;
}
// Var = E[x^2] - (E[x])^2
double count_inv = 1.0 / count_;
double mean_2 = sum_2_ * count_inv;
double mean = sum_ * count_inv;
- return static_cast<T>(mean_2 - (mean * mean));
+ return mean_2 - (mean * mean);
}
private:
size_t count_;
size_t next_index_;
- double sum_; // Sum(x)
- double sum_2_; // Sum(x*x)
+ double sum_; // Sum(x) - double to avoid overflow
+ double sum_2_; // Sum(x*x) - double to avoid overflow
+ mutable T max_;
+ mutable bool max_stale_;
+ mutable T min_;
+ mutable bool min_stale_;
std::vector<T> samples_;
DISALLOW_COPY_AND_ASSIGN(RollingAccumulator);
diff --git a/chromium/third_party/libjingle/source/talk/base/rollingaccumulator_unittest.cc b/chromium/third_party/libjingle/source/talk/base/rollingaccumulator_unittest.cc
index c2831033645..e6d0ea2b750 100644
--- a/chromium/third_party/libjingle/source/talk/base/rollingaccumulator_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/rollingaccumulator_unittest.cc
@@ -40,8 +40,10 @@ TEST(RollingAccumulatorTest, ZeroSamples) {
RollingAccumulator<int> accum(10);
EXPECT_EQ(0U, accum.count());
- EXPECT_EQ(0, accum.ComputeMean());
- EXPECT_EQ(0, accum.ComputeVariance());
+ EXPECT_DOUBLE_EQ(0.0, accum.ComputeMean());
+ EXPECT_DOUBLE_EQ(0.0, accum.ComputeVariance());
+ EXPECT_EQ(0, accum.ComputeMin());
+ EXPECT_EQ(0, accum.ComputeMax());
}
TEST(RollingAccumulatorTest, SomeSamples) {
@@ -52,9 +54,11 @@ TEST(RollingAccumulatorTest, SomeSamples) {
EXPECT_EQ(4U, accum.count());
EXPECT_EQ(6, accum.ComputeSum());
- EXPECT_EQ(1, accum.ComputeMean());
- EXPECT_EQ(2, accum.ComputeWeightedMean(kLearningRate));
- EXPECT_EQ(1, accum.ComputeVariance());
+ EXPECT_DOUBLE_EQ(1.5, accum.ComputeMean());
+ EXPECT_NEAR(2.26666, accum.ComputeWeightedMean(kLearningRate), 0.01);
+ EXPECT_DOUBLE_EQ(1.25, accum.ComputeVariance());
+ EXPECT_EQ(0, accum.ComputeMin());
+ EXPECT_EQ(3, accum.ComputeMax());
}
TEST(RollingAccumulatorTest, RollingSamples) {
@@ -65,9 +69,36 @@ TEST(RollingAccumulatorTest, RollingSamples) {
EXPECT_EQ(10U, accum.count());
EXPECT_EQ(65, accum.ComputeSum());
- EXPECT_EQ(6, accum.ComputeMean());
- EXPECT_EQ(10, accum.ComputeWeightedMean(kLearningRate));
- EXPECT_NEAR(9, accum.ComputeVariance(), 1);
+ EXPECT_DOUBLE_EQ(6.5, accum.ComputeMean());
+ EXPECT_NEAR(10.0, accum.ComputeWeightedMean(kLearningRate), 0.01);
+ EXPECT_NEAR(9.0, accum.ComputeVariance(), 1.0);
+ EXPECT_EQ(2, accum.ComputeMin());
+ EXPECT_EQ(11, accum.ComputeMax());
+}
+
+TEST(RollingAccumulatorTest, ResetSamples) {
+ RollingAccumulator<int> accum(10);
+
+ for (int i = 0; i < 10; ++i) {
+ accum.AddSample(100);
+ }
+ EXPECT_EQ(10U, accum.count());
+ EXPECT_DOUBLE_EQ(100.0, accum.ComputeMean());
+ EXPECT_EQ(100, accum.ComputeMin());
+ EXPECT_EQ(100, accum.ComputeMax());
+
+ accum.Reset();
+ EXPECT_EQ(0U, accum.count());
+
+ for (int i = 0; i < 5; ++i) {
+ accum.AddSample(i);
+ }
+
+ EXPECT_EQ(5U, accum.count());
+ EXPECT_EQ(10, accum.ComputeSum());
+ EXPECT_DOUBLE_EQ(2.0, accum.ComputeMean());
+ EXPECT_EQ(0, accum.ComputeMin());
+ EXPECT_EQ(4, accum.ComputeMax());
}
TEST(RollingAccumulatorTest, RollingSamplesDouble) {
@@ -81,22 +112,24 @@ TEST(RollingAccumulatorTest, RollingSamplesDouble) {
EXPECT_DOUBLE_EQ(87.5, accum.ComputeMean());
EXPECT_NEAR(105.049, accum.ComputeWeightedMean(kLearningRate), 0.1);
EXPECT_NEAR(229.166667, accum.ComputeVariance(), 25);
+ EXPECT_DOUBLE_EQ(65.0, accum.ComputeMin());
+ EXPECT_DOUBLE_EQ(110.0, accum.ComputeMax());
}
TEST(RollingAccumulatorTest, ComputeWeightedMeanCornerCases) {
RollingAccumulator<int> accum(10);
- EXPECT_EQ(0, accum.ComputeWeightedMean(kLearningRate));
- EXPECT_EQ(0, accum.ComputeWeightedMean(0.0));
- EXPECT_EQ(0, accum.ComputeWeightedMean(1.1));
+ EXPECT_DOUBLE_EQ(0.0, accum.ComputeWeightedMean(kLearningRate));
+ EXPECT_DOUBLE_EQ(0.0, accum.ComputeWeightedMean(0.0));
+ EXPECT_DOUBLE_EQ(0.0, accum.ComputeWeightedMean(1.1));
for (int i = 0; i < 8; ++i) {
accum.AddSample(i);
}
- EXPECT_EQ(3, accum.ComputeMean());
- EXPECT_EQ(3, accum.ComputeWeightedMean(0));
- EXPECT_EQ(3, accum.ComputeWeightedMean(1.1));
- EXPECT_EQ(6, accum.ComputeWeightedMean(kLearningRate));
+ EXPECT_DOUBLE_EQ(3.5, accum.ComputeMean());
+ EXPECT_DOUBLE_EQ(3.5, accum.ComputeWeightedMean(0));
+ EXPECT_DOUBLE_EQ(3.5, accum.ComputeWeightedMean(1.1));
+ EXPECT_NEAR(6.0, accum.ComputeWeightedMean(kLearningRate), 0.1);
}
} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/safe_conversions.h b/chromium/third_party/libjingle/source/talk/base/safe_conversions.h
new file mode 100644
index 00000000000..d246d4ffce1
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/safe_conversions.h
@@ -0,0 +1,96 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Borrowed from Chromium's src/base/numerics/safe_conversions.h.
+
+#ifndef TALK_BASE_SAFE_CONVERSIONS_H_
+#define TALK_BASE_SAFE_CONVERSIONS_H_
+
+#include <limits>
+
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/safe_conversions_impl.h"
+
+namespace talk_base {
+
+inline void Check(bool condition) {
+ if (!condition) {
+ LOG(LS_ERROR) << "CHECK failed.";
+ Break();
+ // The program should have crashed at this point.
+ }
+}
+
+// Convenience function that returns true if the supplied value is in range
+// for the destination type.
+template <typename Dst, typename Src>
+inline bool IsValueInRangeForNumericType(Src value) {
+ return internal::RangeCheck<Dst>(value) == internal::TYPE_VALID;
+}
+
+// checked_cast<> is analogous to static_cast<> for numeric types,
+// except that it CHECKs that the specified numeric conversion will not
+// overflow or underflow. NaN source will always trigger a CHECK.
+template <typename Dst, typename Src>
+inline Dst checked_cast(Src value) {
+ Check(IsValueInRangeForNumericType<Dst>(value));
+ return static_cast<Dst>(value);
+}
+
+// saturated_cast<> is analogous to static_cast<> for numeric types, except
+// that the specified numeric conversion will saturate rather than overflow or
+// underflow. NaN assignment to an integral will trigger a CHECK condition.
+template <typename Dst, typename Src>
+inline Dst saturated_cast(Src value) {
+ // Optimization for floating point values, which already saturate.
+ if (std::numeric_limits<Dst>::is_iec559)
+ return static_cast<Dst>(value);
+
+ switch (internal::RangeCheck<Dst>(value)) {
+ case internal::TYPE_VALID:
+ return static_cast<Dst>(value);
+
+ case internal::TYPE_UNDERFLOW:
+ return std::numeric_limits<Dst>::min();
+
+ case internal::TYPE_OVERFLOW:
+ return std::numeric_limits<Dst>::max();
+
+ // Should fail only on attempting to assign NaN to a saturated integer.
+ case internal::TYPE_INVALID:
+ Check(false);
+ return std::numeric_limits<Dst>::max();
+ }
+
+ Check(false); // NOTREACHED();
+ return static_cast<Dst>(value);
+}
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SAFE_CONVERSIONS_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/safe_conversions_impl.h b/chromium/third_party/libjingle/source/talk/base/safe_conversions_impl.h
new file mode 100644
index 00000000000..391e5966b9a
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/safe_conversions_impl.h
@@ -0,0 +1,205 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h.
+
+#ifndef TALK_BASE_SAFE_CONVERSIONS_IMPL_H_
+#define TALK_BASE_SAFE_CONVERSIONS_IMPL_H_
+
+#include <limits>
+
+namespace talk_base {
+namespace internal {
+
+enum DstSign {
+ DST_UNSIGNED,
+ DST_SIGNED
+};
+
+enum SrcSign {
+ SRC_UNSIGNED,
+ SRC_SIGNED
+};
+
+enum DstRange {
+ OVERLAPS_RANGE,
+ CONTAINS_RANGE
+};
+
+// Helper templates to statically determine if our destination type can contain
+// all values represented by the source type.
+
+template <typename Dst, typename Src,
+ DstSign IsDstSigned = std::numeric_limits<Dst>::is_signed ?
+ DST_SIGNED : DST_UNSIGNED,
+ SrcSign IsSrcSigned = std::numeric_limits<Src>::is_signed ?
+ SRC_SIGNED : SRC_UNSIGNED>
+struct StaticRangeCheck {};
+
+template <typename Dst, typename Src>
+struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_SIGNED> {
+ typedef std::numeric_limits<Dst> DstLimits;
+ typedef std::numeric_limits<Src> SrcLimits;
+ // Compare based on max_exponent, which we must compute for integrals.
+ static const size_t kDstMaxExponent = DstLimits::is_iec559 ?
+ DstLimits::max_exponent :
+ (sizeof(Dst) * 8 - 1);
+ static const size_t kSrcMaxExponent = SrcLimits::is_iec559 ?
+ SrcLimits::max_exponent :
+ (sizeof(Src) * 8 - 1);
+ static const DstRange value = kDstMaxExponent >= kSrcMaxExponent ?
+ CONTAINS_RANGE : OVERLAPS_RANGE;
+};
+
+template <typename Dst, typename Src>
+struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED> {
+ static const DstRange value = sizeof(Dst) >= sizeof(Src) ?
+ CONTAINS_RANGE : OVERLAPS_RANGE;
+};
+
+template <typename Dst, typename Src>
+struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_UNSIGNED> {
+ typedef std::numeric_limits<Dst> DstLimits;
+ typedef std::numeric_limits<Src> SrcLimits;
+ // Compare based on max_exponent, which we must compute for integrals.
+ static const size_t kDstMaxExponent = DstLimits::is_iec559 ?
+ DstLimits::max_exponent :
+ (sizeof(Dst) * 8 - 1);
+ static const size_t kSrcMaxExponent = sizeof(Src) * 8;
+ static const DstRange value = kDstMaxExponent >= kSrcMaxExponent ?
+ CONTAINS_RANGE : OVERLAPS_RANGE;
+};
+
+template <typename Dst, typename Src>
+struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_SIGNED> {
+ static const DstRange value = OVERLAPS_RANGE;
+};
+
+
+enum RangeCheckResult {
+ TYPE_VALID = 0, // Value can be represented by the destination type.
+ TYPE_UNDERFLOW = 1, // Value would overflow.
+ TYPE_OVERFLOW = 2, // Value would underflow.
+ TYPE_INVALID = 3 // Source value is invalid (i.e. NaN).
+};
+
+// This macro creates a RangeCheckResult from an upper and lower bound
+// check by taking advantage of the fact that only NaN can be out of range in
+// both directions at once.
+#define BASE_NUMERIC_RANGE_CHECK_RESULT(is_in_upper_bound, is_in_lower_bound) \
+ RangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) | \
+ ((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW))
+
+template <typename Dst,
+ typename Src,
+ DstSign IsDstSigned = std::numeric_limits<Dst>::is_signed ?
+ DST_SIGNED : DST_UNSIGNED,
+ SrcSign IsSrcSigned = std::numeric_limits<Src>::is_signed ?
+ SRC_SIGNED : SRC_UNSIGNED,
+ DstRange IsSrcRangeContained = StaticRangeCheck<Dst, Src>::value>
+struct RangeCheckImpl {};
+
+// The following templates are for ranges that must be verified at runtime. We
+// split it into checks based on signedness to avoid confusing casts and
+// compiler warnings on signed an unsigned comparisons.
+
+// Dst range always contains the result: nothing to check.
+template <typename Dst, typename Src, DstSign IsDstSigned, SrcSign IsSrcSigned>
+struct RangeCheckImpl<Dst, Src, IsDstSigned, IsSrcSigned, CONTAINS_RANGE> {
+ static RangeCheckResult Check(Src value) {
+ return TYPE_VALID;
+ }
+};
+
+// Signed to signed narrowing.
+template <typename Dst, typename Src>
+struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_SIGNED, OVERLAPS_RANGE> {
+ static RangeCheckResult Check(Src value) {
+ typedef std::numeric_limits<Dst> DstLimits;
+ return DstLimits::is_iec559 ?
+ BASE_NUMERIC_RANGE_CHECK_RESULT(
+ value <= static_cast<Src>(DstLimits::max()),
+ value >= static_cast<Src>(DstLimits::max() * -1)) :
+ BASE_NUMERIC_RANGE_CHECK_RESULT(
+ value <= static_cast<Src>(DstLimits::max()),
+ value >= static_cast<Src>(DstLimits::min()));
+ }
+};
+
+// Unsigned to unsigned narrowing.
+template <typename Dst, typename Src>
+struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> {
+ static RangeCheckResult Check(Src value) {
+ typedef std::numeric_limits<Dst> DstLimits;
+ return BASE_NUMERIC_RANGE_CHECK_RESULT(
+ value <= static_cast<Src>(DstLimits::max()), true);
+ }
+};
+
+// Unsigned to signed.
+template <typename Dst, typename Src>
+struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> {
+ static RangeCheckResult Check(Src value) {
+ typedef std::numeric_limits<Dst> DstLimits;
+ return sizeof(Dst) > sizeof(Src) ? TYPE_VALID :
+ BASE_NUMERIC_RANGE_CHECK_RESULT(
+ value <= static_cast<Src>(DstLimits::max()), true);
+ }
+};
+
+// Signed to unsigned.
+template <typename Dst, typename Src>
+struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_SIGNED, OVERLAPS_RANGE> {
+ static RangeCheckResult Check(Src value) {
+ typedef std::numeric_limits<Dst> DstLimits;
+ typedef std::numeric_limits<Src> SrcLimits;
+ // Compare based on max_exponent, which we must compute for integrals.
+ static const size_t kDstMaxExponent = sizeof(Dst) * 8;
+ static const size_t kSrcMaxExponent = SrcLimits::is_iec559 ?
+ SrcLimits::max_exponent :
+ (sizeof(Src) * 8 - 1);
+ return (kDstMaxExponent >= kSrcMaxExponent) ?
+ BASE_NUMERIC_RANGE_CHECK_RESULT(true, value >= static_cast<Src>(0)) :
+ BASE_NUMERIC_RANGE_CHECK_RESULT(
+ value <= static_cast<Src>(DstLimits::max()),
+ value >= static_cast<Src>(0));
+ }
+};
+
+template <typename Dst, typename Src>
+inline RangeCheckResult RangeCheck(Src value) {
+ COMPILE_ASSERT(std::numeric_limits<Src>::is_specialized,
+ argument_must_be_numeric);
+ COMPILE_ASSERT(std::numeric_limits<Dst>::is_specialized,
+ result_must_be_numeric);
+ return RangeCheckImpl<Dst, Src>::Check(value);
+}
+
+} // namespace internal
+} // namespace talk_base
+
+#endif // TALK_BASE_SAFE_CONVERSIONS_IMPL_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/scoped_ptr.h b/chromium/third_party/libjingle/source/talk/base/scoped_ptr.h
index 90f743c6285..5158a9e69cd 100644
--- a/chromium/third_party/libjingle/source/talk/base/scoped_ptr.h
+++ b/chromium/third_party/libjingle/source/talk/base/scoped_ptr.h
@@ -88,8 +88,8 @@
#ifndef TALK_BASE_SCOPED_PTR_H__
#define TALK_BASE_SCOPED_PTR_H__
-#include <cstddef> // for std::ptrdiff_t
-#include <stdlib.h> // for free() decl
+#include <stddef.h> // for ptrdiff_t
+#include <stdlib.h> // for free() decl
#include <algorithm> // For std::swap().
diff --git a/chromium/third_party/libjingle/source/talk/base/scoped_ref_ptr.h b/chromium/third_party/libjingle/source/talk/base/scoped_ref_ptr.h
index 3ce72cbce6d..ae1ab0f230e 100644
--- a/chromium/third_party/libjingle/source/talk/base/scoped_ref_ptr.h
+++ b/chromium/third_party/libjingle/source/talk/base/scoped_ref_ptr.h
@@ -80,6 +80,8 @@
#ifndef TALK_BASE_SCOPED_REF_PTR_H_
#define TALK_BASE_SCOPED_REF_PTR_H_
+#include <stddef.h>
+
namespace talk_base {
template <class T>
diff --git a/chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_unittest.cc b/chromium/third_party/libjingle/source/talk/base/scopedptrcollection.h
index d7f63252261..ec2726e272c 100644
--- a/chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/scopedptrcollection.h
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2006, Google Inc.
+ * Copyright 2014 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,28 +25,53 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "testing/base/gunit.h"
-#include "talk/libjingle-plus/libjingleplus.h"
-#include "talk/libjingle-plus/testutil/libjingleplus_test_notifier.h"
+// Stores a collection of pointers that are deleted when the container is
+// destructed.
-#if defined(_MSC_VER) && (_MSC_VER < 1400)
-void __cdecl std::_Throw(const std::exception &) {}
-std::_Prhand std::_Raise_handler =0;
-#endif
+#ifndef TALK_BASE_SCOPEDPTRCOLLECTION_H_
+#define TALK_BASE_SCOPEDPTRCOLLECTION_H_
+
+#include <algorithm>
+#include <vector>
+
+#include "talk/base/basictypes.h"
+#include "talk/base/constructormagic.h"
namespace talk_base {
-TEST(LibjingleTest, ConstructDestruct) {
- for (int i = 0; i < 5; ++i) {
- LibjinglePlus *libjingleplus = new LibjinglePlus(new Notifier);
- libjingleplus->Login("eaterleaver0", "Buzzt3st", "talk.google.com", false, false);
+template<class T>
+class ScopedPtrCollection {
+ public:
+ typedef std::vector<T*> VectorT;
+
+ ScopedPtrCollection() { }
+ ~ScopedPtrCollection() {
+ for (typename VectorT::iterator it = collection_.begin();
+ it != collection_.end(); ++it) {
+ delete *it;
+ }
+ }
+
+ const VectorT& collection() const { return collection_; }
+ void Reserve(size_t size) {
+ collection_.reserve(size);
+ }
+ void PushBack(T* t) {
+ collection_.push_back(t);
+ }
- delete libjingleplus;
+ // Remove |t| from the collection without deleting it.
+ void Remove(T* t) {
+ collection_.erase(std::remove(collection_.begin(), collection_.end(), t),
+ collection_.end());
}
-}
-}
-int main(int argc, char** argv) {
- testing::ParseGUnitFlags(&argc, argv);
- return RUN_ALL_TESTS();
-}
+ private:
+ VectorT collection_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedPtrCollection);
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_SCOPEDPTRCOLLECTION_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/scopedptrcollection_unittest.cc b/chromium/third_party/libjingle/source/talk/base/scopedptrcollection_unittest.cc
new file mode 100644
index 00000000000..dd9002e42f1
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/scopedptrcollection_unittest.cc
@@ -0,0 +1,90 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/scopedptrcollection.h"
+#include "talk/base/gunit.h"
+
+namespace talk_base {
+
+namespace {
+
+class InstanceCounter {
+ public:
+ explicit InstanceCounter(int* num_instances)
+ : num_instances_(num_instances) {
+ ++(*num_instances_);
+ }
+ ~InstanceCounter() {
+ --(*num_instances_);
+ }
+
+ private:
+ int* num_instances_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstanceCounter);
+};
+
+} // namespace
+
+class ScopedPtrCollectionTest : public testing::Test {
+ protected:
+ ScopedPtrCollectionTest()
+ : num_instances_(0),
+ collection_(new ScopedPtrCollection<InstanceCounter>()) {
+ }
+
+ int num_instances_;
+ scoped_ptr<ScopedPtrCollection<InstanceCounter> > collection_;
+};
+
+TEST_F(ScopedPtrCollectionTest, PushBack) {
+ EXPECT_EQ(0u, collection_->collection().size());
+ EXPECT_EQ(0, num_instances_);
+ const int kNum = 100;
+ for (int i = 0; i < kNum; ++i) {
+ collection_->PushBack(new InstanceCounter(&num_instances_));
+ }
+ EXPECT_EQ(static_cast<size_t>(kNum), collection_->collection().size());
+ EXPECT_EQ(kNum, num_instances_);
+ collection_.reset();
+ EXPECT_EQ(0, num_instances_);
+}
+
+TEST_F(ScopedPtrCollectionTest, Remove) {
+ InstanceCounter* ic = new InstanceCounter(&num_instances_);
+ collection_->PushBack(ic);
+ EXPECT_EQ(1u, collection_->collection().size());
+ collection_->Remove(ic);
+ EXPECT_EQ(1, num_instances_);
+ collection_.reset();
+ EXPECT_EQ(1, num_instances_);
+ delete ic;
+ EXPECT_EQ(0, num_instances_);
+}
+
+
+} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/sharedexclusivelock_unittest.cc b/chromium/third_party/libjingle/source/talk/base/sharedexclusivelock_unittest.cc
index 46b7fdfdc2c..e280aa28a88 100644
--- a/chromium/third_party/libjingle/source/talk/base/sharedexclusivelock_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/sharedexclusivelock_unittest.cc
@@ -148,7 +148,8 @@ class SharedExclusiveLockTest
int value_;
};
-TEST_F(SharedExclusiveLockTest, TestSharedShared) {
+// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3318
+TEST_F(SharedExclusiveLockTest, DISABLED_TestSharedShared) {
int value0, value1;
bool done0, done1;
ReadTask reader0(shared_exclusive_lock_.get(), &value_, &done0);
diff --git a/chromium/third_party/libjingle/source/talk/base/signalthread_unittest.cc b/chromium/third_party/libjingle/source/talk/base/signalthread_unittest.cc
index e5734d4df11..7bc73f05d0c 100644
--- a/chromium/third_party/libjingle/source/talk/base/signalthread_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/signalthread_unittest.cc
@@ -50,19 +50,19 @@ class SignalThreadTest : public testing::Test, public sigslot::has_slots<> {
ASSERT_TRUE(harness_ != NULL);
++harness_->thread_started_;
EXPECT_EQ(harness_->main_thread_, Thread::Current());
- EXPECT_FALSE(worker()->started()); // not started yet
+ EXPECT_FALSE(worker()->RunningForTest()); // not started yet
}
virtual void OnWorkStop() {
++harness_->thread_stopped_;
EXPECT_EQ(harness_->main_thread_, Thread::Current());
- EXPECT_TRUE(worker()->started()); // not stopped yet
+ EXPECT_TRUE(worker()->RunningForTest()); // not stopped yet
}
virtual void OnWorkDone() {
++harness_->thread_done_;
EXPECT_EQ(harness_->main_thread_, Thread::Current());
- EXPECT_TRUE(worker()->started()); // not stopped yet
+ EXPECT_TRUE(worker()->RunningForTest()); // not stopped yet
}
virtual void DoWork() {
diff --git a/chromium/third_party/libjingle/source/talk/base/sigslottester.h b/chromium/third_party/libjingle/source/talk/base/sigslottester.h
new file mode 100755
index 00000000000..9422318e236
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/sigslottester.h
@@ -0,0 +1,216 @@
+// This file was GENERATED by command:
+// pump.py sigslottester.h.pump
+// DO NOT EDIT BY HAND!!!
+
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_BASE_SIGSLOTTESTER_H_
+#define TALK_BASE_SIGSLOTTESTER_H_
+
+// To generate sigslottester.h from sigslottester.h.pump, execute:
+// /home/build/google3/third_party/gtest/scripts/pump.py sigslottester.h.pump
+
+
+// SigslotTester(s) are utility classes to check if signals owned by an
+// object are being invoked at the right time and with the right arguments.
+// They are meant to be used in tests. Tests must provide "capture" pointers
+// (i.e. address of variables) where the arguments from the signal callback
+// can be stored.
+//
+// Example:
+// /* Some signal */
+// sigslot::signal1<const std::string&> foo;
+//
+// /* We want to monitor foo in some test. Note how signal argument is
+// const std::string&, but capture-type is std::string. Capture type
+// must be type that can be assigned to. */
+// std::string capture;
+// SigslotTester1<const std::string&, std::string> slot(&foo, &capture);
+// foo.emit("hello");
+// EXPECT_EQ(1, slot.callback_count());
+// EXPECT_EQ("hello", capture);
+// /* See unit-tests for more examples */
+
+#include "talk/base/constructormagic.h"
+#include "talk/base/sigslot.h"
+
+namespace talk_base {
+
+// For all the templates below:
+// - A1-A5 is the type of the argument i in the callback. Signals may and often
+// do use const-references here for efficiency.
+// - C1-C5 is the type of the variable to capture argument i. These should be
+// non-const value types suitable for use as lvalues.
+
+template <class A1, class C1>
+class SigslotTester1 : public sigslot::has_slots<> {
+ public:
+ SigslotTester1(sigslot::signal1<A1>* signal,
+ C1* capture1)
+ : callback_count_(0),
+ capture1_(capture1) {
+ signal->connect(this, &SigslotTester1::OnSignalCallback);
+ }
+
+ int callback_count() const { return callback_count_; }
+
+ private:
+ void OnSignalCallback(A1 arg1) {
+ callback_count_++;
+ *capture1_ = arg1;
+ }
+
+ int callback_count_;
+ C1* capture1_;
+
+ DISALLOW_COPY_AND_ASSIGN(SigslotTester1);
+};
+
+template <class A1, class A2, class C1, class C2>
+class SigslotTester2 : public sigslot::has_slots<> {
+ public:
+ SigslotTester2(sigslot::signal2<A1, A2>* signal,
+ C1* capture1, C2* capture2)
+ : callback_count_(0),
+ capture1_(capture1), capture2_(capture2) {
+ signal->connect(this, &SigslotTester2::OnSignalCallback);
+ }
+
+ int callback_count() const { return callback_count_; }
+
+ private:
+ void OnSignalCallback(A1 arg1, A2 arg2) {
+ callback_count_++;
+ *capture1_ = arg1;
+ *capture2_ = arg2;
+ }
+
+ int callback_count_;
+ C1* capture1_;
+ C2* capture2_;
+
+ DISALLOW_COPY_AND_ASSIGN(SigslotTester2);
+};
+
+template <class A1, class A2, class A3, class C1, class C2, class C3>
+class SigslotTester3 : public sigslot::has_slots<> {
+ public:
+ SigslotTester3(sigslot::signal3<A1, A2, A3>* signal,
+ C1* capture1, C2* capture2, C3* capture3)
+ : callback_count_(0),
+ capture1_(capture1), capture2_(capture2), capture3_(capture3) {
+ signal->connect(this, &SigslotTester3::OnSignalCallback);
+ }
+
+ int callback_count() const { return callback_count_; }
+
+ private:
+ void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3) {
+ callback_count_++;
+ *capture1_ = arg1;
+ *capture2_ = arg2;
+ *capture3_ = arg3;
+ }
+
+ int callback_count_;
+ C1* capture1_;
+ C2* capture2_;
+ C3* capture3_;
+
+ DISALLOW_COPY_AND_ASSIGN(SigslotTester3);
+};
+
+template <class A1, class A2, class A3, class A4, class C1, class C2, class C3,
+ class C4>
+class SigslotTester4 : public sigslot::has_slots<> {
+ public:
+ SigslotTester4(sigslot::signal4<A1, A2, A3, A4>* signal,
+ C1* capture1, C2* capture2, C3* capture3, C4* capture4)
+ : callback_count_(0),
+ capture1_(capture1), capture2_(capture2), capture3_(capture3),
+ capture4_(capture4) {
+ signal->connect(this, &SigslotTester4::OnSignalCallback);
+ }
+
+ int callback_count() const { return callback_count_; }
+
+ private:
+ void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
+ callback_count_++;
+ *capture1_ = arg1;
+ *capture2_ = arg2;
+ *capture3_ = arg3;
+ *capture4_ = arg4;
+ }
+
+ int callback_count_;
+ C1* capture1_;
+ C2* capture2_;
+ C3* capture3_;
+ C4* capture4_;
+
+ DISALLOW_COPY_AND_ASSIGN(SigslotTester4);
+};
+
+template <class A1, class A2, class A3, class A4, class A5, class C1, class C2,
+ class C3, class C4, class C5>
+class SigslotTester5 : public sigslot::has_slots<> {
+ public:
+ SigslotTester5(sigslot::signal5<A1, A2, A3, A4, A5>* signal,
+ C1* capture1, C2* capture2, C3* capture3, C4* capture4,
+ C5* capture5)
+ : callback_count_(0),
+ capture1_(capture1), capture2_(capture2), capture3_(capture3),
+ capture4_(capture4), capture5_(capture5) {
+ signal->connect(this, &SigslotTester5::OnSignalCallback);
+ }
+
+ int callback_count() const { return callback_count_; }
+
+ private:
+ void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) {
+ callback_count_++;
+ *capture1_ = arg1;
+ *capture2_ = arg2;
+ *capture3_ = arg3;
+ *capture4_ = arg4;
+ *capture5_ = arg5;
+ }
+
+ int callback_count_;
+ C1* capture1_;
+ C2* capture2_;
+ C3* capture3_;
+ C4* capture4_;
+ C5* capture5_;
+
+ DISALLOW_COPY_AND_ASSIGN(SigslotTester5);
+};
+} // namespace talk_base
+
+#endif // TALK_BASE_SIGSLOTTESTER_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/sigslottester.h.pump b/chromium/third_party/libjingle/source/talk/base/sigslottester.h.pump
new file mode 100755
index 00000000000..dce1c7b26ea
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/sigslottester.h.pump
@@ -0,0 +1,102 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_BASE_SIGSLOTTESTER_H_
+#define TALK_BASE_SIGSLOTTESTER_H_
+
+// To generate sigslottester.h from sigslottester.h.pump, execute:
+// /home/build/google3/third_party/gtest/scripts/pump.py sigslottester.h.pump
+
+
+// SigslotTester(s) are utility classes to check if signals owned by an
+// object are being invoked at the right time and with the right arguments.
+// They are meant to be used in tests. Tests must provide "capture" pointers
+// (i.e. address of variables) where the arguments from the signal callback
+// can be stored.
+//
+// Example:
+// /* Some signal */
+// sigslot::signal1<const std::string&> foo;
+//
+// /* We want to monitor foo in some test. Note how signal argument is
+// const std::string&, but capture-type is std::string. Capture type
+// must be type that can be assigned to. */
+// std::string capture;
+// SigslotTester1<const std::string&, std::string> slot(&foo, &capture);
+// foo.emit("hello");
+// EXPECT_EQ(1, slot.callback_count());
+// EXPECT_EQ("hello", capture);
+// /* See unit-tests for more examples */
+
+#include "talk/base/constructormagic.h"
+#include "talk/base/sigslot.h"
+
+namespace talk_base {
+
+// For all the templates below:
+// - A1-A5 is the type of the argument i in the callback. Signals may and often
+// do use const-references here for efficiency.
+// - C1-C5 is the type of the variable to capture argument i. These should be
+// non-const value types suitable for use as lvalues.
+
+$var n = 5
+$range i 1..n
+$for i [[
+$range j 1..i
+
+template <$for j , [[class A$j]], $for j , [[class C$j]]>
+class SigslotTester$i : public sigslot::has_slots<> {
+ public:
+ SigslotTester$i(sigslot::signal$i<$for j , [[A$j]]>* signal,
+ $for j , [[C$j* capture$j]])
+ : callback_count_(0),
+ $for j , [[capture$j[[]]_(capture$j)]] {
+ signal->connect(this, &SigslotTester$i::OnSignalCallback);
+ }
+
+ int callback_count() const { return callback_count_; }
+
+ private:
+ void OnSignalCallback($for j , [[A$j arg$j]]) {
+ callback_count_++;$for j [[
+
+ *capture$j[[]]_ = arg$j;]]
+
+ }
+
+ int callback_count_;$for j [[
+
+ C$j* capture$j[[]]_;]]
+
+
+ DISALLOW_COPY_AND_ASSIGN(SigslotTester$i);
+};
+
+]]
+} // namespace talk_base
+
+#endif // TALK_BASE_SIGSLOTTESTER_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/sigslottester_unittest.cc b/chromium/third_party/libjingle/source/talk/base/sigslottester_unittest.cc
new file mode 100755
index 00000000000..b427ef67c2d
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/sigslottester_unittest.cc
@@ -0,0 +1,74 @@
+#include "talk/base/sigslottester.h"
+
+#include "talk/base/gunit.h"
+#include "talk/base/sigslot.h"
+
+namespace talk_base {
+
+TEST(SigslotTester, TestSignal1Arg) {
+ sigslot::signal1<int> source1;
+ int capture1;
+ SigslotTester1<int, int> slot1(&source1, &capture1);
+ EXPECT_EQ(0, slot1.callback_count());
+
+ source1.emit(10);
+ EXPECT_EQ(1, slot1.callback_count());
+ EXPECT_EQ(10, capture1);
+
+ source1.emit(20);
+ EXPECT_EQ(2, slot1.callback_count());
+ EXPECT_EQ(20, capture1);
+}
+
+TEST(SigslotTester, TestSignal2Args) {
+ sigslot::signal2<int, char> source2;
+ int capture1;
+ char capture2;
+ SigslotTester2<int, char, int, char> slot2(&source2, &capture1, &capture2);
+ EXPECT_EQ(0, slot2.callback_count());
+
+ source2.emit(10, 'x');
+ EXPECT_EQ(1, slot2.callback_count());
+ EXPECT_EQ(10, capture1);
+ EXPECT_EQ('x', capture2);
+
+ source2.emit(20, 'y');
+ EXPECT_EQ(2, slot2.callback_count());
+ EXPECT_EQ(20, capture1);
+ EXPECT_EQ('y', capture2);
+}
+
+// Since it applies for 1 and 2 args, we assume it will work for up to 5 args.
+
+TEST(SigslotTester, TestSignalWithConstReferenceArgs) {
+ sigslot::signal1<const std::string&> source1;
+ std::string capture1;
+ SigslotTester1<const std::string&, std::string> slot1(&source1, &capture1);
+ EXPECT_EQ(0, slot1.callback_count());
+ source1.emit("hello");
+ EXPECT_EQ(1, slot1.callback_count());
+ EXPECT_EQ("hello", capture1);
+}
+
+TEST(SigslotTester, TestSignalWithPointerToConstArgs) {
+ sigslot::signal1<const std::string*> source1;
+ const std::string* capture1;
+ SigslotTester1<const std::string*, const std::string*> slot1(&source1,
+ &capture1);
+ EXPECT_EQ(0, slot1.callback_count());
+ source1.emit(NULL);
+ EXPECT_EQ(1, slot1.callback_count());
+ EXPECT_EQ(NULL, capture1);
+}
+
+TEST(SigslotTester, TestSignalWithConstPointerArgs) {
+ sigslot::signal1<std::string* const> source1;
+ std::string* capture1;
+ SigslotTester1<std::string* const, std::string*> slot1(&source1, &capture1);
+ EXPECT_EQ(0, slot1.callback_count());
+ source1.emit(NULL);
+ EXPECT_EQ(1, slot1.callback_count());
+ EXPECT_EQ(NULL, capture1);
+}
+
+} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/socket.h b/chromium/third_party/libjingle/source/talk/base/socket.h
index e738060f89d..590645f83d4 100644
--- a/chromium/third_party/libjingle/source/talk/base/socket.h
+++ b/chromium/third_party/libjingle/source/talk/base/socket.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -185,7 +185,10 @@ class Socket {
OPT_SNDBUF, // send buffer size
OPT_NODELAY, // whether Nagle algorithm is enabled
OPT_IPV6_V6ONLY, // Whether the socket is IPv6 only.
- OPT_DSCP // DSCP code
+ OPT_DSCP, // DSCP code
+ OPT_RTP_SENDTIME_EXTN_ID, // This is a non-traditional socket option param.
+ // This is specific to libjingle and will be used
+ // if SendTime option is needed at socket level.
};
virtual int GetOption(Option opt, int* value) = 0;
virtual int SetOption(Option opt, int value) = 0;
diff --git a/chromium/third_party/libjingle/source/talk/base/socket_unittest.cc b/chromium/third_party/libjingle/source/talk/base/socket_unittest.cc
index a9c4dbb0de4..e76d113b2e9 100644
--- a/chromium/third_party/libjingle/source/talk/base/socket_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/socket_unittest.cc
@@ -172,8 +172,8 @@ void SocketTest::TestUdpIPv6() {
}
void SocketTest::TestUdpReadyToSendIPv4() {
-#if !defined(OSX)
- // TODO(ronghuawu): Enable this test (currently failed on build bots) on mac.
+#if !defined(OSX) && !defined(IOS)
+ // TODO(ronghuawu): Enable this test on mac/ios.
UdpReadyToSend(kIPv4Loopback);
#endif
}
diff --git a/chromium/third_party/libjingle/source/talk/base/socketaddress.cc b/chromium/third_party/libjingle/source/talk/base/socketaddress.cc
index 193a2328208..792d414adcf 100644
--- a/chromium/third_party/libjingle/source/talk/base/socketaddress.cc
+++ b/chromium/third_party/libjingle/source/talk/base/socketaddress.cc
@@ -34,7 +34,9 @@
#if defined(OPENBSD)
#include <netinet/in_systm.h>
#endif
+#if !defined(__native_client__)
#include <netinet/ip.h>
+#endif
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
diff --git a/chromium/third_party/libjingle/source/talk/base/sslfingerprint.cc b/chromium/third_party/libjingle/source/talk/base/sslfingerprint.cc
new file mode 100644
index 00000000000..dfd5551abcd
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/base/sslfingerprint.cc
@@ -0,0 +1,114 @@
+/*
+ * libjingle
+ * Copyright 2012, Google Inc.
+ * Copyright 2012, RTFM Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/sslfingerprint.h"
+
+#include <ctype.h>
+#include <string>
+
+#include "talk/base/helpers.h"
+#include "talk/base/messagedigest.h"
+#include "talk/base/stringencode.h"
+
+namespace talk_base {
+
+SSLFingerprint* SSLFingerprint::Create(
+ const std::string& algorithm, const talk_base::SSLIdentity* identity) {
+ if (!identity) {
+ return NULL;
+ }
+
+ return Create(algorithm, &(identity->certificate()));
+}
+
+SSLFingerprint* SSLFingerprint::Create(
+ const std::string& algorithm, const talk_base::SSLCertificate* cert) {
+ uint8 digest_val[64];
+ size_t digest_len;
+ bool ret = cert->ComputeDigest(
+ algorithm, digest_val, sizeof(digest_val), &digest_len);
+ if (!ret) {
+ return NULL;
+ }
+
+ return new SSLFingerprint(algorithm, digest_val, digest_len);
+}
+
+SSLFingerprint* SSLFingerprint::CreateFromRfc4572(
+ const std::string& algorithm, const std::string& fingerprint) {
+ if (algorithm.empty() || !talk_base::IsFips180DigestAlgorithm(algorithm))
+ return NULL;
+
+ if (fingerprint.empty())
+ return NULL;
+
+ size_t value_len;
+ char value[talk_base::MessageDigest::kMaxSize];
+ value_len = talk_base::hex_decode_with_delimiter(value, sizeof(value),
+ fingerprint.c_str(),
+ fingerprint.length(),
+ ':');
+ if (!value_len)
+ return NULL;
+
+ return new SSLFingerprint(algorithm,
+ reinterpret_cast<uint8*>(value),
+ value_len);
+}
+
+SSLFingerprint::SSLFingerprint(
+ const std::string& algorithm, const uint8* digest_in, size_t digest_len)
+ : algorithm(algorithm) {
+ digest.SetData(digest_in, digest_len);
+}
+
+SSLFingerprint::SSLFingerprint(const SSLFingerprint& from)
+ : algorithm(from.algorithm), digest(from.digest) {}
+
+bool SSLFingerprint::operator==(const SSLFingerprint& other) const {
+ return algorithm == other.algorithm &&
+ digest == other.digest;
+}
+
+std::string SSLFingerprint::GetRfc4572Fingerprint() const {
+ std::string fingerprint =
+ talk_base::hex_encode_with_delimiter(
+ digest.data(), digest.length(), ':');
+ std::transform(fingerprint.begin(), fingerprint.end(),
+ fingerprint.begin(), ::toupper);
+ return fingerprint;
+}
+
+std::string SSLFingerprint::ToString() {
+ std::string fp_str = algorithm;
+ fp_str.append(" ");
+ fp_str.append(GetRfc4572Fingerprint());
+ return fp_str;
+}
+
+} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/sslfingerprint.h b/chromium/third_party/libjingle/source/talk/base/sslfingerprint.h
index b85778947e6..a803d2129a7 100644
--- a/chromium/third_party/libjingle/source/talk/base/sslfingerprint.h
+++ b/chromium/third_party/libjingle/source/talk/base/sslfingerprint.h
@@ -29,81 +29,35 @@
#ifndef TALK_BASE_SSLFINGERPRINT_H_
#define TALK_BASE_SSLFINGERPRINT_H_
-#include <ctype.h>
#include <string>
#include "talk/base/buffer.h"
-#include "talk/base/helpers.h"
-#include "talk/base/messagedigest.h"
#include "talk/base/sslidentity.h"
-#include "talk/base/stringencode.h"
namespace talk_base {
+class SSLCertificate;
+
struct SSLFingerprint {
static SSLFingerprint* Create(const std::string& algorithm,
- const talk_base::SSLIdentity* identity) {
- if (!identity) {
- return NULL;
- }
-
- return Create(algorithm, &(identity->certificate()));
- }
+ const talk_base::SSLIdentity* identity);
static SSLFingerprint* Create(const std::string& algorithm,
- const talk_base::SSLCertificate* cert) {
- uint8 digest_val[64];
- size_t digest_len;
- bool ret = cert->ComputeDigest(
- algorithm, digest_val, sizeof(digest_val), &digest_len);
- if (!ret) {
- return NULL;
- }
-
- return new SSLFingerprint(algorithm, digest_val, digest_len);
- }
+ const talk_base::SSLCertificate* cert);
static SSLFingerprint* CreateFromRfc4572(const std::string& algorithm,
- const std::string& fingerprint) {
- if (algorithm.empty())
- return NULL;
-
- if (fingerprint.empty())
- return NULL;
-
- size_t value_len;
- char value[talk_base::MessageDigest::kMaxSize];
- value_len = talk_base::hex_decode_with_delimiter(value, sizeof(value),
- fingerprint.c_str(),
- fingerprint.length(),
- ':');
- if (!value_len)
- return NULL;
-
- return new SSLFingerprint(algorithm,
- reinterpret_cast<uint8*>(value),
- value_len);
- }
+ const std::string& fingerprint);
SSLFingerprint(const std::string& algorithm, const uint8* digest_in,
- size_t digest_len) : algorithm(algorithm) {
- digest.SetData(digest_in, digest_len);
- }
- SSLFingerprint(const SSLFingerprint& from)
- : algorithm(from.algorithm), digest(from.digest) {}
- bool operator==(const SSLFingerprint& other) const {
- return algorithm == other.algorithm &&
- digest == other.digest;
- }
-
- std::string GetRfc4572Fingerprint() const {
- std::string fingerprint =
- talk_base::hex_encode_with_delimiter(
- digest.data(), digest.length(), ':');
- std::transform(fingerprint.begin(), fingerprint.end(),
- fingerprint.begin(), ::toupper);
- return fingerprint;
- }
+ size_t digest_len);
+
+ SSLFingerprint(const SSLFingerprint& from);
+
+ bool operator==(const SSLFingerprint& other) const;
+
+ std::string GetRfc4572Fingerprint() const;
+
+ std::string ToString();
std::string algorithm;
talk_base::Buffer digest;
diff --git a/chromium/third_party/libjingle/source/talk/base/sslidentity.cc b/chromium/third_party/libjingle/source/talk/base/sslidentity.cc
index 8f704dc300e..d2d2b11f173 100644
--- a/chromium/third_party/libjingle/source/talk/base/sslidentity.cc
+++ b/chromium/third_party/libjingle/source/talk/base/sslidentity.cc
@@ -115,6 +115,10 @@ SSLIdentity* SSLIdentity::Generate(const std::string& common_name) {
return NULL;
}
+SSLIdentity* GenerateForTest(const SSLIdentityParams& params) {
+ return NULL;
+}
+
SSLIdentity* SSLIdentity::FromPEMStrings(const std::string& private_key,
const std::string& certificate) {
return NULL;
@@ -130,6 +134,10 @@ SSLIdentity* SSLIdentity::Generate(const std::string& common_name) {
return OpenSSLIdentity::Generate(common_name);
}
+SSLIdentity* SSLIdentity::GenerateForTest(const SSLIdentityParams& params) {
+ return OpenSSLIdentity::GenerateForTest(params);
+}
+
SSLIdentity* SSLIdentity::FromPEMStrings(const std::string& private_key,
const std::string& certificate) {
return OpenSSLIdentity::FromPEMStrings(private_key, certificate);
@@ -145,6 +153,10 @@ SSLIdentity* SSLIdentity::Generate(const std::string& common_name) {
return NSSIdentity::Generate(common_name);
}
+SSLIdentity* SSLIdentity::GenerateForTest(const SSLIdentityParams& params) {
+ return NSSIdentity::GenerateForTest(params);
+}
+
SSLIdentity* SSLIdentity::FromPEMStrings(const std::string& private_key,
const std::string& certificate) {
return NSSIdentity::FromPEMStrings(private_key, certificate);
diff --git a/chromium/third_party/libjingle/source/talk/base/sslidentity.h b/chromium/third_party/libjingle/source/talk/base/sslidentity.h
index 89b1008983c..b930f063ce2 100644
--- a/chromium/third_party/libjingle/source/talk/base/sslidentity.h
+++ b/chromium/third_party/libjingle/source/talk/base/sslidentity.h
@@ -81,9 +81,10 @@ class SSLCertificate {
virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const = 0;
// Compute the digest of the certificate given algorithm
- virtual bool ComputeDigest(const std::string &algorithm,
- unsigned char* digest, std::size_t size,
- std::size_t* length) const = 0;
+ virtual bool ComputeDigest(const std::string& algorithm,
+ unsigned char* digest,
+ size_t size,
+ size_t* length) const = 0;
};
// SSLCertChain is a simple wrapper for a vector of SSLCertificates. It serves
@@ -132,6 +133,16 @@ class SSLCertChain {
DISALLOW_COPY_AND_ASSIGN(SSLCertChain);
};
+// Parameters for generating an identity for testing. If common_name is
+// non-empty, it will be used for the certificate's subject and issuer name,
+// otherwise a random string will be used. |not_before| and |not_after| are
+// offsets to the current time in number of seconds.
+struct SSLIdentityParams {
+ std::string common_name;
+ int not_before; // in seconds.
+ int not_after; // in seconds.
+};
+
// Our identity in an SSL negotiation: a keypair and certificate (both
// with the same public key).
// This too is pretty much immutable once created.
@@ -144,6 +155,9 @@ class SSLIdentity {
// Caller is responsible for freeing the returned object.
static SSLIdentity* Generate(const std::string& common_name);
+ // Generates an identity with the specified validity period.
+ static SSLIdentity* GenerateForTest(const SSLIdentityParams& params);
+
// Construct an identity from a private key and a certificate.
static SSLIdentity* FromPEMStrings(const std::string& private_key,
const std::string& certificate);
diff --git a/chromium/third_party/libjingle/source/talk/base/sslidentity_unittest.cc b/chromium/third_party/libjingle/source/talk/base/sslidentity_unittest.cc
index b63b8b9d439..fdb165c9f61 100644
--- a/chromium/third_party/libjingle/source/talk/base/sslidentity_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/sslidentity_unittest.cc
@@ -177,32 +177,33 @@ TEST_F(SSLIdentityTest, DigestSHA512) {
TEST_F(SSLIdentityTest, FromPEMStrings) {
static const char kRSA_PRIVATE_KEY_PEM[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
- "MIICXQIBAAKBgQDCueE4a9hDMZ3sbVZdlXOz9ZA+cvzie3zJ9gXnT/BCt9P4b9HE\n"
- "vD/tr73YBqD3Wr5ZWScmyGYF9EMn0r3rzBxv6oooLU5TdUvOm4rzUjkCLQaQML8o\n"
- "NxXq+qW/j3zUKGikLhaaAl/amaX2zSWUsRQ1CpngQ3+tmDNH4/25TncNmQIDAQAB\n"
- "AoGAUcuU0Id0k10fMjYHZk4mCPzot2LD2Tr4Aznl5vFMQipHzv7hhZtx2xzMSRcX\n"
- "vG+Qr6VkbcUWHgApyWubvZXCh3+N7Vo2aYdMAQ8XqmFpBdIrL5CVdVfqFfEMlgEy\n"
- "LSZNG5klnrIfl3c7zQVovLr4eMqyl2oGfAqPQz75+fecv1UCQQD6wNHch9NbAG1q\n"
- "yuFEhMARB6gDXb+5SdzFjjtTWW5uJfm4DcZLoYyaIZm0uxOwsUKd0Rsma+oGitS1\n"
- "CXmuqfpPAkEAxszyN3vIdpD44SREEtyKZBMNOk5pEIIGdbeMJC5/XHvpxww9xkoC\n"
- "+39NbvUZYd54uT+rafbx4QZKc0h9xA/HlwJBAL37lYVWy4XpPv1olWCKi9LbUCqs\n"
- "vvQtyD1N1BkEayy9TQRsO09WKOcmigRqsTJwOx7DLaTgokEuspYvhagWVPUCQE/y\n"
- "0+YkTbYBD1Xbs9SyBKXCU6uDJRWSdO6aZi2W1XloC9gUwDMiSJjD1Wwt/YsyYPJ+\n"
- "/Hyc5yFL2l0KZimW/vkCQQCjuZ/lPcH46EuzhdbRfumDOG5N3ld7UhGI1TIRy17W\n"
- "dGF90cG33/L6BfS8Ll+fkkW/2AMRk8FDvF4CZi2nfW4L\n"
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMYRkbhmI7kVA/rM\n"
+ "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n"
+ "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n"
+ "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAECgYAvgOs4FJcgvp+TuREx7YtiYVsH\n"
+ "mwQPTum2z/8VzWGwR8BBHBvIpVe1MbD/Y4seyI2aco/7UaisatSgJhsU46/9Y4fq\n"
+ "2TwXH9QANf4at4d9n/R6rzwpAJOpgwZgKvdQjkfrKTtgLV+/dawvpxUYkRH4JZM1\n"
+ "CVGukMfKNrSVH4Ap4QJBAOJmGV1ASPnB4r4nc99at7JuIJmd7fmuVUwUgYi4XgaR\n"
+ "WhScBsgYwZ/JoywdyZJgnbcrTDuVcWG56B3vXbhdpMsCQQDf9zeJrjnPZ3Cqm79y\n"
+ "kdqANep0uwZciiNiWxsQrCHztywOvbFhdp8iYVFG9EK8DMY41Y5TxUwsHD+67zao\n"
+ "ZNqJAkEA1suLUP/GvL8IwuRneQd2tWDqqRQ/Td3qq03hP7e77XtF/buya3Ghclo5\n"
+ "54czUR89QyVfJEC6278nzA7n2h1uVQJAcG6mztNL6ja/dKZjYZye2CY44QjSlLo0\n"
+ "MTgTSjdfg/28fFn2Jjtqf9Pi/X+50LWI/RcYMC2no606wRk9kyOuIQJBAK6VSAim\n"
+ "1pOEjsYQn0X5KEIrz1G3bfCbB848Ime3U2/FWlCHMr6ch8kCZ5d1WUeJD3LbwMNG\n"
+ "UCXiYxSsu20QNVw=\n"
"-----END RSA PRIVATE KEY-----\n";
static const char kCERT_PEM[] =
"-----BEGIN CERTIFICATE-----\n"
- "MIIBmTCCAQICCQCPNJORW/M13DANBgkqhkiG9w0BAQUFADARMQ8wDQYDVQQDDAZ3\n"
- "ZWJydGMwHhcNMTMwNjE0MjIzMDAxWhcNMTQwNjE0MjIzMDAxWjARMQ8wDQYDVQQD\n"
- "DAZ3ZWJydGMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMK54Thr2EMxnext\n"
- "Vl2Vc7P1kD5y/OJ7fMn2BedP8EK30/hv0cS8P+2vvdgGoPdavllZJybIZgX0QyfS\n"
- "vevMHG/qiigtTlN1S86bivNSOQItBpAwvyg3Fer6pb+PfNQoaKQuFpoCX9qZpfbN\n"
- "JZSxFDUKmeBDf62YM0fj/blOdw2ZAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAECMt\n"
- "UZb35H8TnjGx4XPzco/kbnurMLFFWcuve/DwTsuf10Ia9N4md8LY0UtgIgtyNqWc\n"
- "ZwyRMwxONF6ty3wcaIiPbGqiAa55T3YRuPibkRmck9CjrmM9JAtyvqHnpHd2TsBD\n"
- "qCV42aXS3onOXDQ1ibuWq0fr0//aj0wo4KV474c=\n"
+ "MIIBmTCCAQKgAwIBAgIEbzBSAjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZX\n"
+ "ZWJSVEMwHhcNMTQwMTAyMTgyNDQ3WhcNMTQwMjAxMTgyNDQ3WjARMQ8wDQYDVQQD\n"
+ "EwZXZWJSVEMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYRkbhmI7kVA/rM\n"
+ "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n"
+ "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n"
+ "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAUflI\n"
+ "VUe5Krqf5RVa5C3u/UTAOAUJBiDS3VANTCLBxjuMsvqOG0WvaYWP3HYPgrz0jXK2\n"
+ "LJE/mGw3MyFHEqi81jh95J+ypl6xKW6Rm8jKLR87gUvCaVYn/Z4/P3AqcQTB7wOv\n"
+ "UD0A8qfhfDM+LK6rPAnCsVN0NRDY3jvd6rzix9M=\n"
"-----END CERTIFICATE-----\n";
talk_base::scoped_ptr<SSLIdentity> identity(
diff --git a/chromium/third_party/libjingle/source/talk/base/sslstreamadapter.h b/chromium/third_party/libjingle/source/talk/base/sslstreamadapter.h
index 3a7797370c3..1811f9566b8 100644
--- a/chromium/third_party/libjingle/source/talk/base/sslstreamadapter.h
+++ b/chromium/third_party/libjingle/source/talk/base/sslstreamadapter.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2008, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
+ * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -116,17 +116,6 @@ class SSLStreamAdapter : public StreamAdapterInterface {
// underlying stream opens.
virtual int StartSSLWithPeer() = 0;
- // Specify the certificate that our peer is expected to use in
- // peer-to-peer mode. Only this certificate will be accepted during
- // SSL verification. The certificate is assumed to have been
- // obtained through some other secure channel (such as the XMPP
- // channel). (This could also specify the certificate authority that
- // will sign the peer's certificate.)
- // SSLStream takes ownership of the SSLCertificate object and will
- // free it when appropriate. Should be called no more than once on a
- // given SSLStream instance.
- virtual void SetPeerCertificate(SSLCertificate* cert) = 0;
-
// Specify the digest of the certificate that our peer is expected to use in
// peer-to-peer mode. Only this certificate will be accepted during
// SSL verification. The certificate is assumed to have been
@@ -138,11 +127,9 @@ class SSLStreamAdapter : public StreamAdapterInterface {
const unsigned char* digest_val,
size_t digest_len) = 0;
- // Retrieves the peer's X.509 certificate, if a certificate has been
- // provided by SetPeerCertificate or a connection has been established. If
- // a connection has been established, this returns the
- // certificate transmitted over SSL, including the entire chain.
- // The returned certificate is owned by the caller.
+ // Retrieves the peer's X.509 certificate, if a connection has been
+ // established. It returns the transmitted over SSL, including the entire
+ // chain. The returned certificate is owned by the caller.
virtual bool GetPeerCertificate(SSLCertificate** cert) const = 0;
// Key Exporter interface from RFC 5705
diff --git a/chromium/third_party/libjingle/source/talk/base/sslstreamadapter_unittest.cc b/chromium/third_party/libjingle/source/talk/base/sslstreamadapter_unittest.cc
index 4b2fd6d84c0..fe276b3fcc7 100644
--- a/chromium/third_party/libjingle/source/talk/base/sslstreamadapter_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/sslstreamadapter_unittest.cc
@@ -49,32 +49,33 @@ static int kExporterContextLen = sizeof(kExporterContext);
static const char kRSA_PRIVATE_KEY_PEM[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
- "MIICXQIBAAKBgQDCueE4a9hDMZ3sbVZdlXOz9ZA+cvzie3zJ9gXnT/BCt9P4b9HE\n"
- "vD/tr73YBqD3Wr5ZWScmyGYF9EMn0r3rzBxv6oooLU5TdUvOm4rzUjkCLQaQML8o\n"
- "NxXq+qW/j3zUKGikLhaaAl/amaX2zSWUsRQ1CpngQ3+tmDNH4/25TncNmQIDAQAB\n"
- "AoGAUcuU0Id0k10fMjYHZk4mCPzot2LD2Tr4Aznl5vFMQipHzv7hhZtx2xzMSRcX\n"
- "vG+Qr6VkbcUWHgApyWubvZXCh3+N7Vo2aYdMAQ8XqmFpBdIrL5CVdVfqFfEMlgEy\n"
- "LSZNG5klnrIfl3c7zQVovLr4eMqyl2oGfAqPQz75+fecv1UCQQD6wNHch9NbAG1q\n"
- "yuFEhMARB6gDXb+5SdzFjjtTWW5uJfm4DcZLoYyaIZm0uxOwsUKd0Rsma+oGitS1\n"
- "CXmuqfpPAkEAxszyN3vIdpD44SREEtyKZBMNOk5pEIIGdbeMJC5/XHvpxww9xkoC\n"
- "+39NbvUZYd54uT+rafbx4QZKc0h9xA/HlwJBAL37lYVWy4XpPv1olWCKi9LbUCqs\n"
- "vvQtyD1N1BkEayy9TQRsO09WKOcmigRqsTJwOx7DLaTgokEuspYvhagWVPUCQE/y\n"
- "0+YkTbYBD1Xbs9SyBKXCU6uDJRWSdO6aZi2W1XloC9gUwDMiSJjD1Wwt/YsyYPJ+\n"
- "/Hyc5yFL2l0KZimW/vkCQQCjuZ/lPcH46EuzhdbRfumDOG5N3ld7UhGI1TIRy17W\n"
- "dGF90cG33/L6BfS8Ll+fkkW/2AMRk8FDvF4CZi2nfW4L\n"
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMYRkbhmI7kVA/rM\n"
+ "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n"
+ "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n"
+ "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAECgYAvgOs4FJcgvp+TuREx7YtiYVsH\n"
+ "mwQPTum2z/8VzWGwR8BBHBvIpVe1MbD/Y4seyI2aco/7UaisatSgJhsU46/9Y4fq\n"
+ "2TwXH9QANf4at4d9n/R6rzwpAJOpgwZgKvdQjkfrKTtgLV+/dawvpxUYkRH4JZM1\n"
+ "CVGukMfKNrSVH4Ap4QJBAOJmGV1ASPnB4r4nc99at7JuIJmd7fmuVUwUgYi4XgaR\n"
+ "WhScBsgYwZ/JoywdyZJgnbcrTDuVcWG56B3vXbhdpMsCQQDf9zeJrjnPZ3Cqm79y\n"
+ "kdqANep0uwZciiNiWxsQrCHztywOvbFhdp8iYVFG9EK8DMY41Y5TxUwsHD+67zao\n"
+ "ZNqJAkEA1suLUP/GvL8IwuRneQd2tWDqqRQ/Td3qq03hP7e77XtF/buya3Ghclo5\n"
+ "54czUR89QyVfJEC6278nzA7n2h1uVQJAcG6mztNL6ja/dKZjYZye2CY44QjSlLo0\n"
+ "MTgTSjdfg/28fFn2Jjtqf9Pi/X+50LWI/RcYMC2no606wRk9kyOuIQJBAK6VSAim\n"
+ "1pOEjsYQn0X5KEIrz1G3bfCbB848Ime3U2/FWlCHMr6ch8kCZ5d1WUeJD3LbwMNG\n"
+ "UCXiYxSsu20QNVw=\n"
"-----END RSA PRIVATE KEY-----\n";
static const char kCERT_PEM[] =
"-----BEGIN CERTIFICATE-----\n"
- "MIIBmTCCAQICCQCPNJORW/M13DANBgkqhkiG9w0BAQUFADARMQ8wDQYDVQQDDAZ3\n"
- "ZWJydGMwHhcNMTMwNjE0MjIzMDAxWhcNMTQwNjE0MjIzMDAxWjARMQ8wDQYDVQQD\n"
- "DAZ3ZWJydGMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMK54Thr2EMxnext\n"
- "Vl2Vc7P1kD5y/OJ7fMn2BedP8EK30/hv0cS8P+2vvdgGoPdavllZJybIZgX0QyfS\n"
- "vevMHG/qiigtTlN1S86bivNSOQItBpAwvyg3Fer6pb+PfNQoaKQuFpoCX9qZpfbN\n"
- "JZSxFDUKmeBDf62YM0fj/blOdw2ZAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAECMt\n"
- "UZb35H8TnjGx4XPzco/kbnurMLFFWcuve/DwTsuf10Ia9N4md8LY0UtgIgtyNqWc\n"
- "ZwyRMwxONF6ty3wcaIiPbGqiAa55T3YRuPibkRmck9CjrmM9JAtyvqHnpHd2TsBD\n"
- "qCV42aXS3onOXDQ1ibuWq0fr0//aj0wo4KV474c=\n"
+ "MIIBmTCCAQKgAwIBAgIEbzBSAjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZX\n"
+ "ZWJSVEMwHhcNMTQwMTAyMTgyNDQ3WhcNMTQwMjAxMTgyNDQ3WjARMQ8wDQYDVQQD\n"
+ "EwZXZWJSVEMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYRkbhmI7kVA/rM\n"
+ "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n"
+ "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n"
+ "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAUflI\n"
+ "VUe5Krqf5RVa5C3u/UTAOAUJBiDS3VANTCLBxjuMsvqOG0WvaYWP3HYPgrz0jXK2\n"
+ "LJE/mGw3MyFHEqi81jh95J+ypl6xKW6Rm8jKLR87gUvCaVYn/Z4/P3AqcQTB7wOv\n"
+ "UD0A8qfhfDM+LK6rPAnCsVN0NRDY3jvd6rzix9M=\n"
"-----END CERTIFICATE-----\n";
#define MAYBE_SKIP_TEST(feature) \
@@ -208,13 +209,47 @@ class SSLStreamAdapterTestBase : public testing::Test,
~SSLStreamAdapterTestBase() {
// Put it back for the next test.
talk_base::SetRandomTestMode(false);
- talk_base::CleanupSSL();
}
static void SetUpTestCase() {
talk_base::InitializeSSL();
}
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
+ }
+
+ // Recreate the client/server identities with the specified validity period.
+ // |not_before| and |not_after| are offsets from the current time in number
+ // of seconds.
+ void ResetIdentitiesWithValidity(int not_before, int not_after) {
+ client_stream_ =
+ new SSLDummyStream(this, "c2s", &client_buffer_, &server_buffer_);
+ server_stream_ =
+ new SSLDummyStream(this, "s2c", &server_buffer_, &client_buffer_);
+
+ client_ssl_.reset(talk_base::SSLStreamAdapter::Create(client_stream_));
+ server_ssl_.reset(talk_base::SSLStreamAdapter::Create(server_stream_));
+
+ client_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent);
+ server_ssl_->SignalEvent.connect(this, &SSLStreamAdapterTestBase::OnEvent);
+
+ talk_base::SSLIdentityParams client_params;
+ client_params.common_name = "client";
+ client_params.not_before = not_before;
+ client_params.not_after = not_after;
+ client_identity_ = talk_base::SSLIdentity::GenerateForTest(client_params);
+
+ talk_base::SSLIdentityParams server_params;
+ server_params.common_name = "server";
+ server_params.not_before = not_before;
+ server_params.not_after = not_after;
+ server_identity_ = talk_base::SSLIdentity::GenerateForTest(server_params);
+
+ client_ssl_->SetIdentity(client_identity_);
+ server_ssl_->SetIdentity(server_identity_);
+ }
+
virtual void OnEvent(talk_base::StreamInterface *stream, int sig, int err) {
LOG(LS_INFO) << "SSLStreamAdapterTestBase::OnEvent sig=" << sig;
@@ -227,24 +262,6 @@ class SSLStreamAdapterTestBase : public testing::Test,
}
}
- void SetPeerIdentitiesByCertificate(bool correct) {
- LOG(LS_INFO) << "Setting peer identities by certificate";
-
- if (correct) {
- client_ssl_->SetPeerCertificate(server_identity_->certificate().
- GetReference());
- server_ssl_->SetPeerCertificate(client_identity_->certificate().
- GetReference());
- } else {
- // If incorrect, set up to expect our own certificate at the peer
- client_ssl_->SetPeerCertificate(client_identity_->certificate().
- GetReference());
- server_ssl_->SetPeerCertificate(server_identity_->certificate().
- GetReference());
- }
- identities_set_ = true;
- }
-
void SetPeerIdentitiesByDigest(bool correct) {
unsigned char digest[20];
size_t digest_len;
@@ -253,8 +270,8 @@ class SSLStreamAdapterTestBase : public testing::Test,
LOG(LS_INFO) << "Setting peer identities by digest";
rv = server_identity_->certificate().ComputeDigest(talk_base::DIGEST_SHA_1,
- digest, 20,
- &digest_len);
+ digest, 20,
+ &digest_len);
ASSERT_TRUE(rv);
if (!correct) {
LOG(LS_INFO) << "Setting bogus digest for server cert";
@@ -266,7 +283,7 @@ class SSLStreamAdapterTestBase : public testing::Test,
rv = client_identity_->certificate().ComputeDigest(talk_base::DIGEST_SHA_1,
- digest, 20, &digest_len);
+ digest, 20, &digest_len);
ASSERT_TRUE(rv);
if (!correct) {
LOG(LS_INFO) << "Setting bogus digest for client cert";
@@ -722,17 +739,6 @@ TEST_F(SSLStreamAdapterTestTLS, TestTLSBogusDigest) {
TestHandshake(false);
};
-// Test a handshake with a peer certificate
-TEST_F(SSLStreamAdapterTestTLS, TestTLSPeerCertificate) {
- SetPeerIdentitiesByCertificate(true);
- TestHandshake();
-};
-
-// Test a handshake with a bogus peer certificate
-TEST_F(SSLStreamAdapterTestTLS, TestTLSBogusPeerCertificate) {
- SetPeerIdentitiesByCertificate(false);
- TestHandshake(false);
-};
// Test moving a bunch of data
// Basic tests: DTLS
@@ -762,7 +768,7 @@ TEST_F(SSLStreamAdapterTestDTLS,
};
// Test a handshake with small MTU
-TEST_F(SSLStreamAdapterTestDTLS, DISABLED_TestDTLSConnectWithSmallMtu) {
+TEST_F(SSLStreamAdapterTestDTLS, TestDTLSConnectWithSmallMtu) {
MAYBE_SKIP_TEST(HaveDtls);
SetMtu(700);
SetHandshakeWait(20000);
@@ -887,6 +893,24 @@ TEST_F(SSLStreamAdapterTestDTLS, TestDTLSExporter) {
ASSERT_TRUE(!memcmp(client_out, server_out, sizeof(client_out)));
}
+// Test not yet valid certificates are not rejected.
+TEST_F(SSLStreamAdapterTestDTLS, TestCertNotYetValid) {
+ MAYBE_SKIP_TEST(HaveDtls);
+ long one_day = 60 * 60 * 24;
+ // Make the certificates not valid until one day later.
+ ResetIdentitiesWithValidity(one_day, one_day);
+ TestHandshake();
+}
+
+// Test expired certificates are not rejected.
+TEST_F(SSLStreamAdapterTestDTLS, TestCertExpired) {
+ MAYBE_SKIP_TEST(HaveDtls);
+ long one_day = 60 * 60 * 24;
+ // Make the certificates already expired.
+ ResetIdentitiesWithValidity(-one_day, -one_day);
+ TestHandshake();
+}
+
// Test data transfer using certs created from strings.
TEST_F(SSLStreamAdapterTestDTLSFromPEMStrings, TestTransfer) {
MAYBE_SKIP_TEST(HaveDtls);
diff --git a/chromium/third_party/libjingle/source/talk/base/sslstreamadapterhelper.cc b/chromium/third_party/libjingle/source/talk/base/sslstreamadapterhelper.cc
index b42faa80c60..7be2878d016 100644
--- a/chromium/third_party/libjingle/source/talk/base/sslstreamadapterhelper.cc
+++ b/chromium/third_party/libjingle/source/talk/base/sslstreamadapterhelper.cc
@@ -80,13 +80,6 @@ StreamState SSLStreamAdapterHelper::GetState() const {
// not reached
}
-void SSLStreamAdapterHelper::SetPeerCertificate(SSLCertificate* cert) {
- ASSERT(peer_certificate_.get() == NULL);
- ASSERT(peer_certificate_digest_algorithm_.empty());
- ASSERT(ssl_server_name_.empty());
- peer_certificate_.reset(cert);
-}
-
bool SSLStreamAdapterHelper::GetPeerCertificate(SSLCertificate** cert) const {
if (!peer_certificate_)
return false;
diff --git a/chromium/third_party/libjingle/source/talk/base/sslstreamadapterhelper.h b/chromium/third_party/libjingle/source/talk/base/sslstreamadapterhelper.h
index 7c280566127..5023d52ec19 100644
--- a/chromium/third_party/libjingle/source/talk/base/sslstreamadapterhelper.h
+++ b/chromium/third_party/libjingle/source/talk/base/sslstreamadapterhelper.h
@@ -59,7 +59,6 @@ class SSLStreamAdapterHelper : public SSLStreamAdapter {
virtual int StartSSLWithServer(const char* server_name);
virtual int StartSSLWithPeer();
- virtual void SetPeerCertificate(SSLCertificate* cert);
virtual bool SetPeerCertificateDigest(const std::string& digest_alg,
const unsigned char* digest_val,
size_t digest_len);
@@ -88,8 +87,8 @@ class SSLStreamAdapterHelper : public SSLStreamAdapter {
// Must be implemented by descendents
virtual int BeginSSL() = 0;
virtual void Cleanup() = 0;
- virtual bool GetDigestLength(const std::string &algorithm,
- std::size_t *length) = 0;
+ virtual bool GetDigestLength(const std::string& algorithm,
+ size_t* length) = 0;
enum SSLState {
// Before calling one of the StartSSL methods, data flows
@@ -114,12 +113,10 @@ class SSLStreamAdapterHelper : public SSLStreamAdapter {
// in traditional mode, the server name that the server's certificate
// must specify. Empty in peer-to-peer mode.
std::string ssl_server_name_;
- // In peer-to-peer mode, the certificate that the peer must
- // present. Empty in traditional mode.
+ // The peer's certificate. Only used for GetPeerCertificate.
scoped_ptr<SSLCertificate> peer_certificate_;
- // In peer-to-peer mode, the digest of the certificate that
- // the peer must present.
+ // The digest of the certificate that the peer must present.
Buffer peer_certificate_digest_value_;
std::string peer_certificate_digest_algorithm_;
diff --git a/chromium/third_party/libjingle/source/talk/base/stream.cc b/chromium/third_party/libjingle/source/talk/base/stream.cc
index c1cf90743a0..02ae4094fa5 100644
--- a/chromium/third_party/libjingle/source/talk/base/stream.cc
+++ b/chromium/third_party/libjingle/source/talk/base/stream.cc
@@ -495,7 +495,7 @@ bool FileStream::Flush() {
return false;
}
-#if defined(POSIX)
+#if defined(POSIX) && !defined(__native_client__)
bool FileStream::TryLock() {
if (file_ == NULL) {
@@ -711,7 +711,7 @@ void AsyncWriteStream::ClearBufferAndWrite() {
}
}
-#ifdef POSIX
+#if defined(POSIX) && !defined(__native_client__)
// Have to identically rewrite the FileStream destructor or else it would call
// the base class's Close() instead of the sub-class's.
diff --git a/chromium/third_party/libjingle/source/talk/base/stream.h b/chromium/third_party/libjingle/source/talk/base/stream.h
index 4571def9bb9..fceb4a80f0d 100644
--- a/chromium/third_party/libjingle/source/talk/base/stream.h
+++ b/chromium/third_party/libjingle/source/talk/base/stream.h
@@ -28,6 +28,8 @@
#ifndef TALK_BASE_STREAM_H_
#define TALK_BASE_STREAM_H_
+#include <stdio.h>
+
#include "talk/base/basictypes.h"
#include "talk/base/buffer.h"
#include "talk/base/criticalsection.h"
@@ -449,7 +451,7 @@ class FileStream : public StreamInterface {
virtual bool Flush();
-#if defined(POSIX)
+#if defined(POSIX) && !defined(__native_client__)
// Tries to aquire an exclusive lock on the file.
// Use OpenShare(...) on win32 to get similar functionality.
bool TryLock();
@@ -497,7 +499,6 @@ class CircularFileStream : public FileStream {
size_t read_segment_available_;
};
-
// A stream which pushes writes onto a separate thread and
// returns from the write call immediately.
class AsyncWriteStream : public StreamInterface {
@@ -539,7 +540,7 @@ class AsyncWriteStream : public StreamInterface {
};
-#ifdef POSIX
+#if defined(POSIX) && !defined(__native_client__)
// A FileStream that is actually not a file, but the output or input of a
// sub-command. See "man 3 popen" for documentation of the underlying OS popen()
// function.
diff --git a/chromium/third_party/libjingle/source/talk/base/stringencode.cc b/chromium/third_party/libjingle/source/talk/base/stringencode.cc
index 194848e1ec6..4c88a9772f1 100644
--- a/chromium/third_party/libjingle/source/talk/base/stringencode.cc
+++ b/chromium/third_party/libjingle/source/talk/base/stringencode.cc
@@ -27,8 +27,8 @@
#include "talk/base/stringencode.h"
-#include <cstdio>
-#include <cstdlib>
+#include <stdio.h>
+#include <stdlib.h>
#include "talk/base/basictypes.h"
#include "talk/base/common.h"
diff --git a/chromium/third_party/libjingle/source/talk/base/stringutils.h b/chromium/third_party/libjingle/source/talk/base/stringutils.h
index 9f9e1a65a55..2c12118b96f 100644
--- a/chromium/third_party/libjingle/source/talk/base/stringutils.h
+++ b/chromium/third_party/libjingle/source/talk/base/stringutils.h
@@ -31,6 +31,7 @@
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
+#include <string.h>
#ifdef WIN32
#include <malloc.h>
@@ -46,7 +47,6 @@
#endif // !BSD
#endif // POSIX
-#include <cstring>
#include <string>
#include "talk/base/basictypes.h"
diff --git a/chromium/third_party/libjingle/source/talk/base/template_util.h b/chromium/third_party/libjingle/source/talk/base/template_util.h
index 5cc4ba430a2..00f1d7d4a11 100644
--- a/chromium/third_party/libjingle/source/talk/base/template_util.h
+++ b/chromium/third_party/libjingle/source/talk/base/template_util.h
@@ -5,7 +5,7 @@
#ifndef TALK_BASE_TEMPLATE_UTIL_H_
#define TALK_BASE_TEMPLATE_UTIL_H_
-#include <cstddef> // For size_t.
+#include <stddef.h> // For size_t.
namespace talk_base {
diff --git a/chromium/third_party/libjingle/source/talk/base/testclient.cc b/chromium/third_party/libjingle/source/talk/base/testclient.cc
index 04d60309963..92e1f397424 100644
--- a/chromium/third_party/libjingle/source/talk/base/testclient.cc
+++ b/chromium/third_party/libjingle/source/talk/base/testclient.cc
@@ -25,7 +25,6 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "talk/base/dscp.h"
#include "talk/base/testclient.h"
#include "talk/base/thread.h"
#include "talk/base/timeutils.h"
@@ -59,12 +58,14 @@ bool TestClient::CheckConnState(AsyncPacketSocket::State state) {
}
int TestClient::Send(const char* buf, size_t size) {
- return socket_->Send(buf, size, DSCP_NO_CHANGE);
+ talk_base::PacketOptions options;
+ return socket_->Send(buf, size, options);
}
int TestClient::SendTo(const char* buf, size_t size,
const SocketAddress& dest) {
- return socket_->SendTo(buf, size, dest, DSCP_NO_CHANGE);
+ talk_base::PacketOptions options;
+ return socket_->SendTo(buf, size, dest, options);
}
TestClient::Packet* TestClient::NextPacket() {
@@ -106,7 +107,7 @@ bool TestClient::CheckNextPacket(const char* buf, size_t size,
bool res = false;
Packet* packet = NextPacket();
if (packet) {
- res = (packet->size == size && std::memcmp(packet->buf, buf, size) == 0);
+ res = (packet->size == size && memcmp(packet->buf, buf, size) == 0);
if (addr)
*addr = packet->addr;
delete packet;
diff --git a/chromium/third_party/libjingle/source/talk/base/testechoserver.h b/chromium/third_party/libjingle/source/talk/base/testechoserver.h
index 5c1045423c3..380f9615363 100644
--- a/chromium/third_party/libjingle/source/talk/base/testechoserver.h
+++ b/chromium/third_party/libjingle/source/talk/base/testechoserver.h
@@ -69,7 +69,8 @@ class TestEchoServer : public sigslot::has_slots<> {
void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t size,
const SocketAddress& remote_addr,
const PacketTime& packet_time) {
- socket->Send(buf, size, DSCP_NO_CHANGE);
+ talk_base::PacketOptions options;
+ socket->Send(buf, size, options);
}
void OnClose(AsyncPacketSocket* socket, int err) {
ClientList::iterator it =
diff --git a/chromium/third_party/libjingle/source/talk/base/testutils.h b/chromium/third_party/libjingle/source/talk/base/testutils.h
index e8ad7200940..86e946fc0d2 100644
--- a/chromium/third_party/libjingle/source/talk/base/testutils.h
+++ b/chromium/third_party/libjingle/source/talk/base/testutils.h
@@ -32,6 +32,8 @@
#ifdef LINUX
#include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.h>
+
// X defines a few macros that stomp on types that gunit.h uses.
#undef None
#undef Bool
@@ -43,6 +45,7 @@
#include "talk/base/common.h"
#include "talk/base/gunit.h"
#include "talk/base/nethelpers.h"
+#include "talk/base/pathutils.h"
#include "talk/base/stream.h"
#include "talk/base/stringencode.h"
#include "talk/base/stringutils.h"
@@ -449,6 +452,30 @@ inline bool ReadFile(const char* filename, std::string* contents) {
return success;
}
+// Look in parent dir for parallel directory.
+inline talk_base::Pathname GetSiblingDirectory(
+ const std::string& parallel_dir) {
+ talk_base::Pathname path = talk_base::Filesystem::GetCurrentDirectory();
+ while (!path.empty()) {
+ talk_base::Pathname potential_parallel_dir = path;
+ potential_parallel_dir.AppendFolder(parallel_dir);
+ if (talk_base::Filesystem::IsFolder(potential_parallel_dir)) {
+ return potential_parallel_dir;
+ }
+
+ path.SetFolder(path.parent_folder());
+ }
+ return path;
+}
+
+inline talk_base::Pathname GetGoogle3Directory() {
+ return GetSiblingDirectory("google3");
+}
+
+inline talk_base::Pathname GetTalkDirectory() {
+ return GetSiblingDirectory("talk");
+}
+
///////////////////////////////////////////////////////////////////////////////
// Unittest predicates which are similar to STREQ, but for raw memory
///////////////////////////////////////////////////////////////////////////////
@@ -601,6 +628,16 @@ inline bool IsScreencastingAvailable() {
LOG(LS_WARNING) << "No X Display available.";
return false;
}
+ int ignored_int, major_version, minor_version;
+ if (!XRRQueryExtension(display, &ignored_int, &ignored_int) ||
+ !XRRQueryVersion(display, &major_version, &minor_version) ||
+ major_version < 1 ||
+ (major_version < 2 && minor_version < 3)) {
+ LOG(LS_WARNING) << "XRandr version: " << major_version << "."
+ << minor_version;
+ LOG(LS_WARNING) << "XRandr is not supported or is too old (pre 1.3).";
+ return false;
+ }
#endif
return true;
}
diff --git a/chromium/third_party/libjingle/source/talk/base/thread.cc b/chromium/third_party/libjingle/source/talk/base/thread.cc
index d07efb51568..87e4ffff614 100644
--- a/chromium/third_party/libjingle/source/talk/base/thread.cc
+++ b/chromium/third_party/libjingle/source/talk/base/thread.cc
@@ -145,20 +145,18 @@ struct ThreadInit {
Thread::Thread(SocketServer* ss)
: MessageQueue(ss),
priority_(PRIORITY_NORMAL),
- started_(false),
+ running_(true, false),
#if defined(WIN32)
thread_(NULL),
thread_id_(0),
#endif
- owned_(true),
- delete_self_when_complete_(false) {
+ owned_(true) {
SetName("Thread", this); // default name
}
Thread::~Thread() {
Stop();
- if (active_)
- Clear(NULL);
+ Clear(NULL);
}
bool Thread::SleepMs(int milliseconds) {
@@ -181,7 +179,7 @@ bool Thread::SleepMs(int milliseconds) {
}
bool Thread::SetName(const std::string& name, const void* obj) {
- if (started_) return false;
+ if (running()) return false;
name_ = name;
if (obj) {
char buf[16];
@@ -193,7 +191,7 @@ bool Thread::SetName(const std::string& name, const void* obj) {
bool Thread::SetPriority(ThreadPriority priority) {
#if defined(WIN32)
- if (started_) {
+ if (running()) {
BOOL ret = FALSE;
if (priority == PRIORITY_NORMAL) {
ret = ::SetThreadPriority(thread_, THREAD_PRIORITY_NORMAL);
@@ -212,7 +210,7 @@ bool Thread::SetPriority(ThreadPriority priority) {
return true;
#else
// TODO: Implement for Linux/Mac if possible.
- if (started_) return false;
+ if (running()) return false;
priority_ = priority;
return true;
#endif
@@ -221,8 +219,8 @@ bool Thread::SetPriority(ThreadPriority priority) {
bool Thread::Start(Runnable* runnable) {
ASSERT(owned_);
if (!owned_) return false;
- ASSERT(!started_);
- if (started_) return false;
+ ASSERT(!running());
+ if (running()) return false;
Restart(); // reset fStop_ if the thread is being restarted
@@ -241,7 +239,7 @@ bool Thread::Start(Runnable* runnable) {
thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, init, flags,
&thread_id_);
if (thread_) {
- started_ = true;
+ running_.Set();
if (priority_ != PRIORITY_NORMAL) {
SetPriority(priority_);
::ResumeThread(thread_);
@@ -252,6 +250,9 @@ bool Thread::Start(Runnable* runnable) {
#elif defined(POSIX)
pthread_attr_t attr;
pthread_attr_init(&attr);
+
+ // Thread priorities are not supported in NaCl.
+#if !defined(__native_client__)
if (priority_ != PRIORITY_NORMAL) {
if (priority_ == PRIORITY_IDLE) {
// There is no POSIX-standard way to set a below-normal priority for an
@@ -279,18 +280,20 @@ bool Thread::Start(Runnable* runnable) {
}
}
}
+#endif // !defined(__native_client__)
+
int error_code = pthread_create(&thread_, &attr, PreRun, init);
if (0 != error_code) {
LOG(LS_ERROR) << "Unable to create pthread, error " << error_code;
return false;
}
- started_ = true;
+ running_.Set();
#endif
return true;
}
void Thread::Join() {
- if (started_) {
+ if (running()) {
ASSERT(!IsCurrent());
#if defined(WIN32)
WaitForSingleObject(thread_, INFINITE);
@@ -301,7 +304,7 @@ void Thread::Join() {
void *pv;
pthread_join(thread_, &pv);
#endif
- started_ = false;
+ running_.Reset();
}
}
@@ -352,10 +355,6 @@ void* Thread::PreRun(void* pv) {
} else {
init->thread->Run();
}
- if (init->thread->delete_self_when_complete_) {
- init->thread->started_ = false;
- delete init->thread;
- }
delete init;
return NULL;
}
@@ -398,7 +397,6 @@ void Thread::Send(MessageHandler *phandler, uint32 id, MessageData *pdata) {
bool ready = false;
{
CritScope cs(&crit_);
- EnsureActive();
_SendMessage smsg;
smsg.thread = current_thread;
smsg.msg = msg;
@@ -518,7 +516,7 @@ bool Thread::WrapCurrent() {
}
bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager) {
- if (started_)
+ if (running())
return false;
#if defined(WIN32)
// We explicitly ask for no rights other than synchronization.
@@ -533,7 +531,7 @@ bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager) {
thread_ = pthread_self();
#endif
owned_ = false;
- started_ = true;
+ running_.Set();
thread_manager->SetCurrentThread(this);
return true;
}
@@ -546,7 +544,7 @@ void Thread::UnwrapCurrent() {
LOG_GLE(LS_ERROR) << "When unwrapping thread, failed to close handle.";
}
#endif
- started_ = false;
+ running_.Reset();
}
diff --git a/chromium/third_party/libjingle/source/talk/base/thread.h b/chromium/third_party/libjingle/source/talk/base/thread.h
index 4dc09f641d7..4cbf721fa63 100644
--- a/chromium/third_party/libjingle/source/talk/base/thread.h
+++ b/chromium/third_party/libjingle/source/talk/base/thread.h
@@ -37,6 +37,7 @@
#include <pthread.h>
#endif
#include "talk/base/constructormagic.h"
+#include "talk/base/event.h"
#include "talk/base/messagequeue.h"
#ifdef WIN32
@@ -143,15 +144,8 @@ class Thread : public MessageQueue {
bool SetPriority(ThreadPriority priority);
// Starts the execution of the thread.
- bool started() const { return started_; }
bool Start(Runnable* runnable = NULL);
- // Used for fire-and-forget threads. Deletes this thread object when the
- // Run method returns.
- void Release() {
- delete_self_when_complete_ = true;
- }
-
// Tells the thread to stop and waits until it is joined.
// Never call Stop on the current thread. Instead use the inherited Quit
// function which will exit the base MessageQueue without terminating the
@@ -218,38 +212,24 @@ class Thread : public MessageQueue {
bool WrapCurrent();
void UnwrapCurrent();
+ // Expose private method running() for tests.
+ //
+ // DANGER: this is a terrible public API. Most callers that might want to
+ // call this likely do not have enough control/knowledge of the Thread in
+ // question to guarantee that the returned value remains true for the duration
+ // of whatever code is conditionally executing because of the return value!
+ bool RunningForTest() { return running(); }
+ // This is a legacy call-site that probably doesn't need to exist in the first
+ // place.
+ // TODO(fischman): delete once the ASSERT added in channelmanager.cc sticks
+ // for a month (ETA 2014/06/22).
+ bool RunningForChannelManager() { return running(); }
+
protected:
// Blocks the calling thread until this thread has terminated.
void Join();
private:
- // Helper class to facilitate executing a functor on a thread.
- template <class ReturnT, class FunctorT>
- class FunctorMessageHandler : public MessageHandler {
- public:
- explicit FunctorMessageHandler(const FunctorT& functor)
- : functor_(functor) {}
- virtual void OnMessage(Message* msg) {
- result_ = functor_();
- }
- const ReturnT& result() const { return result_; }
- private:
- FunctorT functor_;
- ReturnT result_;
- };
-
- // Specialization for ReturnT of void.
- template <class FunctorT>
- class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
- public:
- explicit FunctorMessageHandler(const FunctorT& functor)
- : functor_(functor) {}
- virtual void OnMessage(Message* msg) { functor_(); }
- void result() const {}
- private:
- FunctorT functor_;
- };
-
static void *PreRun(void *pv);
// ThreadManager calls this instead WrapCurrent() because
@@ -257,10 +237,13 @@ class Thread : public MessageQueue {
// being created.
bool WrapCurrentWithThreadManager(ThreadManager* thread_manager);
+ // Return true if the thread was started and hasn't yet stopped.
+ bool running() { return running_.Wait(0); }
+
std::list<_SendMessage> sendlist_;
std::string name_;
ThreadPriority priority_;
- bool started_;
+ Event running_; // Signalled means running.
#ifdef POSIX
pthread_t thread_;
@@ -272,7 +255,6 @@ class Thread : public MessageQueue {
#endif
bool owned_;
- bool delete_self_when_complete_;
friend class ThreadManager;
diff --git a/chromium/third_party/libjingle/source/talk/base/thread_unittest.cc b/chromium/third_party/libjingle/source/talk/base/thread_unittest.cc
index 896fbabc5fd..d7d6a0129e4 100644
--- a/chromium/third_party/libjingle/source/talk/base/thread_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/thread_unittest.cc
@@ -25,6 +25,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "talk/base/asyncinvoker.h"
#include "talk/base/asyncudpsocket.h"
#include "talk/base/event.h"
#include "talk/base/gunit.h"
@@ -38,8 +39,6 @@
using namespace talk_base;
-const int MAX = 65536;
-
// Generates a sequence of numbers (collaboratively).
class TestGenerator {
public:
@@ -87,7 +86,6 @@ class SocketClient : public TestGenerator, public sigslot::has_slots<> {
uint32 prev = reinterpret_cast<const uint32*>(buf)[0];
uint32 result = Next(prev);
- //socket_->set_readable(last < MAX);
post_thread_->PostDelayed(200, post_handler_, 0, new TestMessage(result));
}
@@ -101,7 +99,7 @@ class SocketClient : public TestGenerator, public sigslot::has_slots<> {
class MessageClient : public MessageHandler, public TestGenerator {
public:
MessageClient(Thread* pth, Socket* socket)
- : thread_(pth), socket_(socket) {
+ : socket_(socket) {
}
virtual ~MessageClient() {
@@ -116,7 +114,6 @@ class MessageClient : public MessageHandler, public TestGenerator {
}
private:
- Thread* thread_;
Socket* socket_;
};
@@ -150,16 +147,22 @@ class SignalWhenDestroyedThread : public Thread {
};
// Function objects to test Thread::Invoke.
-struct Functor1 {
+struct FunctorA {
int operator()() { return 42; }
};
-class Functor2 {
+class FunctorB {
public:
- explicit Functor2(bool* flag) : flag_(flag) {}
+ explicit FunctorB(bool* flag) : flag_(flag) {}
void operator()() { if (flag_) *flag_ = true; }
private:
bool* flag_;
};
+struct FunctorC {
+ int operator()() {
+ Thread::Current()->ProcessMessages(50);
+ return 24;
+ }
+};
// See: https://code.google.com/p/webrtc/issues/detail?id=2409
TEST(ThreadTest, DISABLED_Main) {
@@ -258,40 +261,22 @@ TEST(ThreadTest, Wrap) {
current_thread->UnwrapCurrent();
CustomThread* cthread = new CustomThread();
EXPECT_TRUE(cthread->WrapCurrent());
- EXPECT_TRUE(cthread->started());
+ EXPECT_TRUE(cthread->RunningForTest());
EXPECT_FALSE(cthread->IsOwned());
cthread->UnwrapCurrent();
- EXPECT_FALSE(cthread->started());
+ EXPECT_FALSE(cthread->RunningForTest());
delete cthread;
current_thread->WrapCurrent();
}
-// Test that calling Release on a thread causes it to self-destruct when
-// it's finished running
-TEST(ThreadTest, Release) {
- scoped_ptr<Event> event(new Event(true, false));
- // Ensure the event is initialized.
- event->Reset();
-
- Thread* thread = new SignalWhenDestroyedThread(event.get());
- thread->Start();
- thread->Release();
-
- // The event should get signaled when the thread completes, which should
- // be nearly instantaneous, since it doesn't do anything. For safety,
- // give it 3 seconds in case the machine is under load.
- bool signaled = event->Wait(3000);
- EXPECT_TRUE(signaled);
-}
-
TEST(ThreadTest, Invoke) {
// Create and start the thread.
Thread thread;
thread.Start();
// Try calling functors.
- EXPECT_EQ(42, thread.Invoke<int>(Functor1()));
+ EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
bool called = false;
- Functor2 f2(&called);
+ FunctorB f2(&called);
thread.Invoke<void>(f2);
EXPECT_TRUE(called);
// Try calling bare functions.
@@ -303,6 +288,152 @@ TEST(ThreadTest, Invoke) {
thread.Invoke<void>(&LocalFuncs::Func2);
}
+class AsyncInvokeTest : public testing::Test {
+ public:
+ void IntCallback(int value) {
+ EXPECT_EQ(expected_thread_, Thread::Current());
+ int_value_ = value;
+ }
+ void AsyncInvokeIntCallback(AsyncInvoker* invoker, Thread* thread) {
+ expected_thread_ = thread;
+ invoker->AsyncInvoke(thread, FunctorC(),
+ &AsyncInvokeTest::IntCallback,
+ static_cast<AsyncInvokeTest*>(this));
+ invoke_started_.Set();
+ }
+ void SetExpectedThreadForIntCallback(Thread* thread) {
+ expected_thread_ = thread;
+ }
+
+ protected:
+ enum { kWaitTimeout = 1000 };
+ AsyncInvokeTest()
+ : int_value_(0),
+ invoke_started_(true, false),
+ expected_thread_(NULL) {}
+
+ int int_value_;
+ Event invoke_started_;
+ Thread* expected_thread_;
+};
+
+TEST_F(AsyncInvokeTest, FireAndForget) {
+ AsyncInvoker invoker;
+ // Create and start the thread.
+ Thread thread;
+ thread.Start();
+ // Try calling functor.
+ bool called = false;
+ invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
+ EXPECT_TRUE_WAIT(called, kWaitTimeout);
+}
+
+TEST_F(AsyncInvokeTest, WithCallback) {
+ AsyncInvoker invoker;
+ // Create and start the thread.
+ Thread thread;
+ thread.Start();
+ // Try calling functor.
+ SetExpectedThreadForIntCallback(Thread::Current());
+ invoker.AsyncInvoke(&thread, FunctorA(),
+ &AsyncInvokeTest::IntCallback,
+ static_cast<AsyncInvokeTest*>(this));
+ EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
+}
+
+TEST_F(AsyncInvokeTest, CancelInvoker) {
+ // Create and start the thread.
+ Thread thread;
+ thread.Start();
+ // Try destroying invoker during call.
+ {
+ AsyncInvoker invoker;
+ invoker.AsyncInvoke(&thread, FunctorC(),
+ &AsyncInvokeTest::IntCallback,
+ static_cast<AsyncInvokeTest*>(this));
+ }
+ // With invoker gone, callback should be cancelled.
+ Thread::Current()->ProcessMessages(kWaitTimeout);
+ EXPECT_EQ(0, int_value_);
+}
+
+TEST_F(AsyncInvokeTest, CancelCallingThread) {
+ AsyncInvoker invoker;
+ { // Create and start the thread.
+ Thread thread;
+ thread.Start();
+ // Try calling functor.
+ thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
+ static_cast<AsyncInvokeTest*>(this),
+ &invoker, Thread::Current()));
+ // Wait for the call to begin.
+ ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
+ }
+ // Calling thread is gone. Return message shouldn't happen.
+ Thread::Current()->ProcessMessages(kWaitTimeout);
+ EXPECT_EQ(0, int_value_);
+}
+
+TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) {
+ Thread thread;
+ thread.Start();
+ {
+ AsyncInvoker invoker;
+ // Try calling functor.
+ thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
+ static_cast<AsyncInvokeTest*>(this),
+ &invoker, Thread::Current()));
+ // Wait for the call to begin.
+ ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
+ }
+ // Invoker is destroyed. Function should not execute.
+ Thread::Current()->ProcessMessages(kWaitTimeout);
+ EXPECT_EQ(0, int_value_);
+}
+
+TEST_F(AsyncInvokeTest, Flush) {
+ AsyncInvoker invoker;
+ bool flag1 = false;
+ bool flag2 = false;
+ // Queue two async calls to the current thread.
+ invoker.AsyncInvoke<void>(Thread::Current(),
+ FunctorB(&flag1));
+ invoker.AsyncInvoke<void>(Thread::Current(),
+ FunctorB(&flag2));
+ // Because we haven't pumped messages, these should not have run yet.
+ EXPECT_FALSE(flag1);
+ EXPECT_FALSE(flag2);
+ // Force them to run now.
+ invoker.Flush(Thread::Current());
+ EXPECT_TRUE(flag1);
+ EXPECT_TRUE(flag2);
+}
+
+TEST_F(AsyncInvokeTest, FlushWithIds) {
+ AsyncInvoker invoker;
+ bool flag1 = false;
+ bool flag2 = false;
+ // Queue two async calls to the current thread, one with a message id.
+ invoker.AsyncInvoke<void>(Thread::Current(),
+ FunctorB(&flag1),
+ 5);
+ invoker.AsyncInvoke<void>(Thread::Current(),
+ FunctorB(&flag2));
+ // Because we haven't pumped messages, these should not have run yet.
+ EXPECT_FALSE(flag1);
+ EXPECT_FALSE(flag2);
+ // Execute pending calls with id == 5.
+ invoker.Flush(Thread::Current(), 5);
+ EXPECT_TRUE(flag1);
+ EXPECT_FALSE(flag2);
+ flag1 = false;
+ // Execute all pending calls. The id == 5 call should not execute again.
+ invoker.Flush(Thread::Current());
+ EXPECT_FALSE(flag1);
+ EXPECT_TRUE(flag2);
+}
+
+
#ifdef WIN32
class ComThreadTest : public testing::Test, public MessageHandler {
public:
diff --git a/chromium/third_party/libjingle/source/talk/base/timeutils.cc b/chromium/third_party/libjingle/source/talk/base/timeutils.cc
index 54db3418bbb..c4e84cc20db 100644
--- a/chromium/third_party/libjingle/source/talk/base/timeutils.cc
+++ b/chromium/third_party/libjingle/source/talk/base/timeutils.cc
@@ -25,6 +25,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <stdint.h>
+
#ifdef POSIX
#include <sys/time.h>
#if defined(OSX) || defined(IOS)
@@ -45,7 +47,6 @@
namespace talk_base {
-const uint32 LAST = 0xFFFFFFFF;
const uint32 HALF = 0x80000000;
uint64 TimeNanos() {
@@ -190,16 +191,30 @@ int32 TimeDiff(uint32 later, uint32 earlier) {
if (earlier <= later) {
return static_cast<long>(later - earlier);
} else {
- return static_cast<long>(later + (LAST - earlier) + 1);
+ return static_cast<long>(later + (UINT32_MAX - earlier) + 1);
}
} else {
if (later <= earlier) {
return -static_cast<long>(earlier - later);
} else {
- return -static_cast<long>(earlier + (LAST - later) + 1);
+ return -static_cast<long>(earlier + (UINT32_MAX - later) + 1);
}
}
#endif
}
+TimestampWrapAroundHandler::TimestampWrapAroundHandler()
+ : last_ts_(0), num_wrap_(0) {}
+
+int64 TimestampWrapAroundHandler::Unwrap(uint32 ts) {
+ if (ts < last_ts_) {
+ if (last_ts_ > 0xf0000000 && ts < 0x0fffffff) {
+ ++num_wrap_;
+ }
+ }
+ last_ts_ = ts;
+ int64_t unwrapped_ts = ts + (num_wrap_ << 32);
+ return unwrapped_ts;
+}
+
} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/timeutils.h b/chromium/third_party/libjingle/source/talk/base/timeutils.h
index f13c3f2ef2d..6de9df67142 100644
--- a/chromium/third_party/libjingle/source/talk/base/timeutils.h
+++ b/chromium/third_party/libjingle/source/talk/base/timeutils.h
@@ -97,6 +97,17 @@ inline int64 UnixTimestampNanosecsToNtpMillisecs(int64 unix_ts_ns) {
return unix_ts_ns / kNumNanosecsPerMillisec + kJan1970AsNtpMillisecs;
}
+class TimestampWrapAroundHandler {
+ public:
+ TimestampWrapAroundHandler();
+
+ int64 Unwrap(uint32 ts);
+
+ private:
+ uint32 last_ts_;
+ int64 num_wrap_;
+};
+
} // namespace talk_base
#endif // TALK_BASE_TIMEUTILS_H_
diff --git a/chromium/third_party/libjingle/source/talk/base/timeutils_unittest.cc b/chromium/third_party/libjingle/source/talk/base/timeutils_unittest.cc
index 0fc5eb19c8a..a078abee2c1 100644
--- a/chromium/third_party/libjingle/source/talk/base/timeutils_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/timeutils_unittest.cc
@@ -160,4 +160,27 @@ TEST(TimeTest, DISABLED_CurrentTmTime) {
EXPECT_TRUE(0 <= microseconds && microseconds < 1000000);
}
+class TimestampWrapAroundHandlerTest : public testing::Test {
+ public:
+ TimestampWrapAroundHandlerTest() {}
+
+ protected:
+ TimestampWrapAroundHandler wraparound_handler_;
+};
+
+TEST_F(TimestampWrapAroundHandlerTest, Unwrap) {
+ uint32 ts = 0xfffffff2;
+ int64 unwrapped_ts = ts;
+ EXPECT_EQ(ts, wraparound_handler_.Unwrap(ts));
+ ts = 2;
+ unwrapped_ts += 0x10;
+ EXPECT_EQ(unwrapped_ts, wraparound_handler_.Unwrap(ts));
+ ts = 0xfffffff2;
+ unwrapped_ts += 0xfffffff0;
+ EXPECT_EQ(unwrapped_ts, wraparound_handler_.Unwrap(ts));
+ ts = 0;
+ unwrapped_ts += 0xe;
+ EXPECT_EQ(unwrapped_ts, wraparound_handler_.Unwrap(ts));
+}
+
} // namespace talk_base
diff --git a/chromium/third_party/libjingle/source/talk/base/transformadapter.cc b/chromium/third_party/libjingle/source/talk/base/transformadapter.cc
index 53a55a85b4d..2a240eb9f73 100644
--- a/chromium/third_party/libjingle/source/talk/base/transformadapter.cc
+++ b/chromium/third_party/libjingle/source/talk/base/transformadapter.cc
@@ -27,7 +27,7 @@
#include "talk/base/transformadapter.h"
-#include <cstring>
+#include <string.h>
#include "talk/base/common.h"
diff --git a/chromium/third_party/libjingle/source/talk/base/unittest_main.cc b/chromium/third_party/libjingle/source/talk/base/unittest_main.cc
index bca3671b0c4..def763c30d8 100644
--- a/chromium/third_party/libjingle/source/talk/base/unittest_main.cc
+++ b/chromium/third_party/libjingle/source/talk/base/unittest_main.cc
@@ -12,7 +12,6 @@
#include "talk/base/fileutils.h"
#include "talk/base/gunit.h"
#include "talk/base/logging.h"
-#include "talk/base/pathutils.h"
DEFINE_bool(help, false, "prints this message");
DEFINE_string(log, "", "logging options to use");
@@ -47,28 +46,6 @@ int TestCrtReportHandler(int report_type, char* msg, int* retval) {
}
#endif // WIN32
-talk_base::Pathname GetTalkDirectory() {
- // Locate talk directory.
- talk_base::Pathname path = talk_base::Filesystem::GetCurrentDirectory();
- std::string talk_folder_name("talk");
- talk_folder_name += path.folder_delimiter();
- while (path.folder_name() != talk_folder_name && !path.empty()) {
- path.SetFolder(path.parent_folder());
- }
-
- // If not running inside "talk" folder, then assume running in its parent
- // folder.
- if (path.empty()) {
- path = talk_base::Filesystem::GetCurrentDirectory();
- path.AppendFolder("talk");
- // Make sure the folder exist.
- if (!talk_base::Filesystem::IsFolder(path)) {
- path.clear();
- }
- }
- return path;
-}
-
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
FlagList::SetFlagsFromCommandLine(&argc, argv, false);
diff --git a/chromium/third_party/libjingle/source/talk/base/unixfilesystem.cc b/chromium/third_party/libjingle/source/talk/base/unixfilesystem.cc
index 74168f267bd..8ac74994586 100644
--- a/chromium/third_party/libjingle/source/talk/base/unixfilesystem.cc
+++ b/chromium/third_party/libjingle/source/talk/base/unixfilesystem.cc
@@ -42,26 +42,39 @@
#if defined(POSIX) && !defined(OSX)
#include <sys/types.h>
-#ifdef ANDROID
+#if defined(ANDROID)
#include <sys/statfs.h>
-#else
+#elif !defined(__native_client__)
#include <sys/statvfs.h>
-#endif // ANDROID
+#endif // !defined(__native_client__)
+#include <limits.h>
#include <pwd.h>
#include <stdio.h>
-#include <unistd.h>
#endif // POSIX && !OSX
-#ifdef LINUX
+#if defined(LINUX)
#include <ctype.h>
#include <algorithm>
#endif
+#if defined(__native_client__) && !defined(__GLIBC__)
+#include <sys/syslimits.h>
+#endif
+
#include "talk/base/fileutils.h"
#include "talk/base/pathutils.h"
#include "talk/base/stream.h"
#include "talk/base/stringutils.h"
+#if defined(IOS)
+// Defined in iosfilesystem.mm. No header file to discourage use
+// elsewhere; other places should use GetApp{Data,Temp}Folder() in
+// this file. Don't copy/paste. I mean it.
+char* IOSDataDirectory();
+char* IOSTempDirectory();
+void IOSAppName(talk_base::Pathname* path);
+#endif
+
namespace talk_base {
#if !defined(ANDROID) && !defined(IOS)
@@ -81,6 +94,17 @@ void UnixFilesystem::SetAppTempFolder(const std::string& folder) {
}
#endif
+UnixFilesystem::UnixFilesystem() {
+#if defined(IOS)
+ if (!provided_app_data_folder_)
+ provided_app_data_folder_ = IOSDataDirectory();
+ if (!provided_app_temp_folder_)
+ provided_app_temp_folder_ = IOSTempDirectory();
+#endif
+}
+
+UnixFilesystem::~UnixFilesystem() {}
+
bool UnixFilesystem::CreateFolder(const Pathname &path, mode_t mode) {
std::string pathname(path.pathname());
int len = pathname.length();
@@ -363,10 +387,15 @@ bool UnixFilesystem::GetAppPathname(Pathname* path) {
if (success)
path->SetPathname(path8);
return success;
+#elif defined(__native_client__)
+ return false;
+#elif IOS
+ IOSAppName(path);
+ return true;
#else // OSX
- char buffer[NAME_MAX+1];
- size_t len = readlink("/proc/self/exe", buffer, ARRAY_SIZE(buffer) - 1);
- if (len <= 0)
+ char buffer[PATH_MAX + 2];
+ ssize_t len = readlink("/proc/self/exe", buffer, ARRAY_SIZE(buffer) - 1);
+ if ((len <= 0) || (len == PATH_MAX + 1))
return false;
buffer[len] = '\0';
path->SetPathname(buffer);
@@ -448,6 +477,7 @@ bool UnixFilesystem::GetAppDataFolder(Pathname* path, bool per_user) {
if (!CreateFolder(*path, 0700)) {
return false;
}
+#if !defined(__native_client__)
// If the folder already exists, it may have the wrong mode or be owned by
// someone else, both of which are security problems. Setting the mode
// avoids both issues since it will fail if the path is not owned by us.
@@ -455,6 +485,7 @@ bool UnixFilesystem::GetAppDataFolder(Pathname* path, bool per_user) {
LOG_ERR(LS_ERROR) << "Can't set mode on " << path;
return false;
}
+#endif
return true;
}
@@ -489,6 +520,9 @@ bool UnixFilesystem::GetAppTempFolder(Pathname* path) {
}
bool UnixFilesystem::GetDiskFreeSpace(const Pathname& path, int64 *freebytes) {
+#ifdef __native_client__
+ return false;
+#else // __native_client__
ASSERT(NULL != freebytes);
// TODO: Consider making relative paths absolute using cwd.
// TODO: When popping off a symlink, push back on the components of the
@@ -510,11 +544,12 @@ bool UnixFilesystem::GetDiskFreeSpace(const Pathname& path, int64 *freebytes) {
#endif // ANDROID
#if defined(LINUX) || defined(ANDROID)
*freebytes = static_cast<int64>(vfs.f_bsize) * vfs.f_bavail;
-#elif defined(OSX)
+#elif defined(OSX) || defined(IOS)
*freebytes = static_cast<int64>(vfs.f_frsize) * vfs.f_bavail;
#endif
return true;
+#endif // !__native_client__
}
Pathname UnixFilesystem::GetCurrentDirectory() {
@@ -544,3 +579,11 @@ char* UnixFilesystem::CopyString(const std::string& str) {
}
} // namespace talk_base
+
+#if defined(__native_client__)
+extern "C" int __attribute__((weak))
+link(const char* oldpath, const char* newpath) {
+ errno = EACCES;
+ return -1;
+}
+#endif
diff --git a/chromium/third_party/libjingle/source/talk/base/unixfilesystem.h b/chromium/third_party/libjingle/source/talk/base/unixfilesystem.h
index aa9c920e625..d709115fe9f 100644
--- a/chromium/third_party/libjingle/source/talk/base/unixfilesystem.h
+++ b/chromium/third_party/libjingle/source/talk/base/unixfilesystem.h
@@ -36,13 +36,17 @@ namespace talk_base {
class UnixFilesystem : public FilesystemInterface {
public:
+ UnixFilesystem();
+ virtual ~UnixFilesystem();
#if defined(ANDROID) || defined(IOS)
-// Android does not have a native code API to fetch the app data or temp
-// folders. That needs to be passed into this class from Java. Similarly, iOS
-// only supports an Objective-C API for fetching the folder locations, so that
-// needs to be passed in here from Objective-C.
-
+ // Android does not have a native code API to fetch the app data or temp
+ // folders. That needs to be passed into this class from Java. Similarly, iOS
+ // only supports an Objective-C API for fetching the folder locations, so that
+ // needs to be passed in here from Objective-C. Or at least that used to be
+ // the case; now the ctor will do the work if necessary and possible.
+ // TODO(fischman): add an Android version that uses JNI and drop the
+ // SetApp*Folder() APIs once external users stop using them.
static void SetAppDataFolder(const std::string& folder);
static void SetAppTempFolder(const std::string& folder);
#endif
diff --git a/chromium/third_party/libjingle/source/talk/base/versionparsing.cc b/chromium/third_party/libjingle/source/talk/base/versionparsing.cc
index 03f3dec1ee9..6a57dc9fe0c 100644
--- a/chromium/third_party/libjingle/source/talk/base/versionparsing.cc
+++ b/chromium/third_party/libjingle/source/talk/base/versionparsing.cc
@@ -27,7 +27,7 @@
#include "talk/base/versionparsing.h"
-#include <cstdlib>
+#include <stdlib.h>
namespace talk_base {
diff --git a/chromium/third_party/libjingle/source/talk/base/virtualsocket_unittest.cc b/chromium/third_party/libjingle/source/talk/base/virtualsocket_unittest.cc
index b31b8c8b074..58dab143a27 100644
--- a/chromium/third_party/libjingle/source/talk/base/virtualsocket_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/virtualsocket_unittest.cc
@@ -25,11 +25,11 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <math.h>
#include <time.h>
#ifdef POSIX
#include <netinet/in.h>
#endif
-#include <cmath>
#include "talk/base/logging.h"
#include "talk/base/gunit.h"
@@ -69,7 +69,7 @@ struct Sender : public MessageHandler {
count += size;
memcpy(dummy, &cur_time, sizeof(cur_time));
- socket->Send(dummy, size, DSCP_NO_CHANGE);
+ socket->Send(dummy, size, options);
last_send = cur_time;
thread->PostDelayed(NextDelay(), this, 1);
@@ -77,6 +77,7 @@ struct Sender : public MessageHandler {
Thread* thread;
scoped_ptr<AsyncUDPSocket> socket;
+ talk_base::PacketOptions options;
bool done;
uint32 rate; // bytes per second
uint32 count;
@@ -685,7 +686,7 @@ class VirtualSocketServerTest : public testing::Test {
double num =
receiver.samples * receiver.sum_sq - receiver.sum * receiver.sum;
double den = receiver.samples * (receiver.samples - 1);
- const double sample_stddev = std::sqrt(num / den);
+ const double sample_stddev = sqrt(num / den);
LOG(LS_VERBOSE) << "mean=" << sample_mean << " stddev=" << sample_stddev;
EXPECT_LE(500u, receiver.samples);
@@ -1001,7 +1002,7 @@ TEST_F(VirtualSocketServerTest, CreatesStandardDistribution) {
double dev = (*f)[i].second - mean;
sum_sq_dev += dev * dev;
}
- const double stddev = std::sqrt(sum_sq_dev / f->size());
+ const double stddev = sqrt(sum_sq_dev / f->size());
EXPECT_NEAR(kTestMean[midx], mean, 0.1 * kTestMean[midx])
<< "M=" << kTestMean[midx]
<< " SD=" << kStdDev
diff --git a/chromium/third_party/libjingle/source/talk/base/virtualsocketserver.cc b/chromium/third_party/libjingle/source/talk/base/virtualsocketserver.cc
index 6d95c19d1d1..6589ebb5a20 100644
--- a/chromium/third_party/libjingle/source/talk/base/virtualsocketserver.cc
+++ b/chromium/third_party/libjingle/source/talk/base/virtualsocketserver.cc
@@ -28,9 +28,9 @@
#include "talk/base/virtualsocketserver.h"
#include <errno.h>
+#include <math.h>
#include <algorithm>
-#include <cmath>
#include <map>
#include <vector>
@@ -80,7 +80,7 @@ class Packet : public MessageData {
: size_(size), consumed_(0), from_(from) {
ASSERT(NULL != data);
data_ = new char[size_];
- std::memcpy(data_, data, size_);
+ memcpy(data_, data, size_);
}
virtual ~Packet() {
@@ -283,7 +283,7 @@ class VirtualSocket : public AsyncSocket, public MessageHandler {
// Return the packet at the front of the queue.
Packet* packet = recv_buffer_.front();
size_t data_read = _min(cb, packet->size());
- std::memcpy(pv, packet->data(), data_read);
+ memcpy(pv, packet->data(), data_read);
*paddr = packet->from();
if (data_read < packet->size()) {
@@ -963,11 +963,11 @@ void VirtualSocketServer::UpdateDelayDistribution() {
}
}
-static double PI = 4 * std::atan(1.0);
+static double PI = 4 * atan(1.0);
static double Normal(double x, double mean, double stddev) {
double a = (x - mean) * (x - mean) / (2 * stddev * stddev);
- return std::exp(-a) / (stddev * sqrt(2 * PI));
+ return exp(-a) / (stddev * sqrt(2 * PI));
}
#if 0 // static unused gives a warning
diff --git a/chromium/third_party/libjingle/source/talk/base/virtualsocketserver.h b/chromium/third_party/libjingle/source/talk/base/virtualsocketserver.h
index 280ae657295..56e37a14e3b 100644
--- a/chromium/third_party/libjingle/source/talk/base/virtualsocketserver.h
+++ b/chromium/third_party/libjingle/source/talk/base/virtualsocketserver.h
@@ -28,7 +28,8 @@
#ifndef TALK_BASE_VIRTUALSOCKETSERVER_H_
#define TALK_BASE_VIRTUALSOCKETSERVER_H_
-#include <cassert>
+#include <assert.h>
+
#include <deque>
#include <map>
diff --git a/chromium/third_party/libjingle/source/talk/base/win32regkey.cc b/chromium/third_party/libjingle/source/talk/base/win32regkey.cc
index 403fdc014c0..614f698e7c4 100644
--- a/chromium/third_party/libjingle/source/talk/base/win32regkey.cc
+++ b/chromium/third_party/libjingle/source/talk/base/win32regkey.cc
@@ -984,21 +984,21 @@ std::wstring RegKey::GetParentKeyInfo(std::wstring* key_name) {
uint32 RegKey::GetValueCount() {
DWORD num_values = 0;
- LONG res = ::RegQueryInfoKey(
- h_key_, // key handle
- NULL, // buffer for class name
- NULL, // size of class string
- NULL, // reserved
- NULL, // number of subkeys
- NULL, // longest subkey size
- NULL, // longest class string
- &num_values, // number of values for this key
- NULL, // longest value name
- NULL, // longest value data
- NULL, // security descriptor
- NULL); // last write time
-
- ASSERT(res == ERROR_SUCCESS);
+ if (ERROR_SUCCESS != ::RegQueryInfoKey(
+ h_key_, // key handle
+ NULL, // buffer for class name
+ NULL, // size of class string
+ NULL, // reserved
+ NULL, // number of subkeys
+ NULL, // longest subkey size
+ NULL, // longest class string
+ &num_values, // number of values for this key
+ NULL, // longest value name
+ NULL, // longest value data
+ NULL, // security descriptor
+ NULL)) { // last write time
+ ASSERT(false);
+ }
return num_values;
}
@@ -1028,21 +1028,21 @@ uint32 RegKey::GetSubkeyCount() {
// number of values for key
DWORD num_subkeys = 0;
- LONG res = ::RegQueryInfoKey(
- h_key_, // key handle
- NULL, // buffer for class name
- NULL, // size of class string
- NULL, // reserved
- &num_subkeys, // number of subkeys
- NULL, // longest subkey size
- NULL, // longest class string
- NULL, // number of values for this key
- NULL, // longest value name
- NULL, // longest value data
- NULL, // security descriptor
- NULL); // last write time
-
- ASSERT(res == ERROR_SUCCESS);
+ if (ERROR_SUCCESS != ::RegQueryInfoKey(
+ h_key_, // key handle
+ NULL, // buffer for class name
+ NULL, // size of class string
+ NULL, // reserved
+ &num_subkeys, // number of subkeys
+ NULL, // longest subkey size
+ NULL, // longest class string
+ NULL, // number of values for this key
+ NULL, // longest value name
+ NULL, // longest value data
+ NULL, // security descriptor
+ NULL)) { // last write time
+ ASSERT(false);
+ }
return num_subkeys;
}
diff --git a/chromium/third_party/libjingle/source/talk/base/win32toolhelp_unittest.cc b/chromium/third_party/libjingle/source/talk/base/win32toolhelp_unittest.cc
index 529bef95ab5..e740345978c 100644
--- a/chromium/third_party/libjingle/source/talk/base/win32toolhelp_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/base/win32toolhelp_unittest.cc
@@ -267,7 +267,6 @@ TEST_F(Win32ToolhelpTest, TestCurrentNextCalled) {
}
TEST_F(Win32ToolhelpTest, TestCurrentProcess) {
- int size = MAX_PATH;
WCHAR buf[MAX_PATH];
GetModuleFileName(NULL, buf, ARRAY_SIZE(buf));
std::wstring name = ToUtf16(Pathname(ToUtf8(buf)).filename());
diff --git a/chromium/third_party/libjingle/source/talk/base/windowpickerfactory.h b/chromium/third_party/libjingle/source/talk/base/windowpickerfactory.h
index b55cc7dc35e..e9ba6c46a2a 100644
--- a/chromium/third_party/libjingle/source/talk/base/windowpickerfactory.h
+++ b/chromium/third_party/libjingle/source/talk/base/windowpickerfactory.h
@@ -55,7 +55,7 @@ class WindowPickerFactory {
return new Win32WindowPicker();
#elif defined(OSX)
return new MacWindowPicker();
-#elif defined(LINUX)
+#elif defined(LINUX) && defined(HAVE_X11)
return new LinuxWindowPicker();
#else
return NULL;
diff --git a/chromium/third_party/libjingle/source/talk/base/winping.cc b/chromium/third_party/libjingle/source/talk/base/winping.cc
index 001740ad26d..fd25a2374d4 100644
--- a/chromium/third_party/libjingle/source/talk/base/winping.cc
+++ b/chromium/third_party/libjingle/source/talk/base/winping.cc
@@ -27,8 +27,8 @@
#include "talk/base/winping.h"
+#include <assert.h>
#include <Iphlpapi.h>
-#include <cassert>
#include "talk/base/byteorder.h"
#include "talk/base/common.h"
diff --git a/chromium/third_party/libjingle/source/talk/build/OWNERS b/chromium/third_party/libjingle/source/talk/build/OWNERS
new file mode 100644
index 00000000000..3ee6b4bf5f9
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/build/OWNERS
@@ -0,0 +1,5 @@
+
+# These are for the common case of adding or renaming files. If you're doing
+# structural changes, please get a review from a reviewer in this file.
+per-file *.gyp=*
+per-file *.gypi=*
diff --git a/chromium/third_party/libjingle/source/talk/build/common.gypi b/chromium/third_party/libjingle/source/talk/build/common.gypi
index 50acb39ea95..8261c2085e3 100644
--- a/chromium/third_party/libjingle/source/talk/build/common.gypi
+++ b/chromium/third_party/libjingle/source/talk/build/common.gypi
@@ -46,7 +46,8 @@
},
'target_defaults': {
'include_dirs': [
- '../..',
+ '<(libjingle_root)',
+ '<(DEPTH)',
'../../third_party',
'../../third_party/webrtc',
'../../webrtc',
@@ -85,6 +86,9 @@
'conditions': [
['clang==1', {
'cflags': [
+ '-Wall',
+ '-Wextra',
+ '-Wunused-variable',
# TODO(ronghuawu): Fix the warning caused by
# LateBindingSymbolTable::TableInfo from
# latebindingsymboltable.cc.def and remove below flag.
@@ -101,11 +105,10 @@
['OS=="ios"', {
'defines': [
'IOS',
- 'HAVE_NSS_SSL_H=1',
- 'SSL_USE_NSS_RNG',
],
- 'defines!': [
- 'HAVE_OPENSSL_SSL_H=1',
+ }, {
+ 'defines': [
+ 'HAVE_SCTP',
],
}],
['OS=="ios" or (OS=="mac" and target_arch!="ia32")', {
@@ -114,15 +117,55 @@
],
}],
['os_posix==1', {
+ 'configurations': {
+ 'Debug_Base': {
+ 'defines': [
+ # Chromium's build/common.gypi defines this for all posix _except_
+ # for ios & mac. We want it there as well, e.g. because ASSERT
+ # and friends trigger off of it.
+ '_DEBUG',
+ ],
+ },
+ },
'defines': [
'HASH_NAMESPACE=__gnu_cxx',
'POSIX',
'DISABLE_DYNAMIC_CAST',
- 'HAVE_OPENSSL_SSL_H=1',
# The POSIX standard says we have to define this.
'_REENTRANT',
],
}],
+ # TODO(jiayl): collapse the following 5 defines into 2, one for NSS and
+ # one for OPENSSL, and update the relevant code.
+ ['use_openssl==1', {
+ 'defines': [
+ 'SSL_USE_OPENSSL',
+ 'HAVE_OPENSSL_SSL_H',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/third_party/openssl/openssl.gyp:openssl',
+ ],
+ }, {
+ 'defines': [
+ 'SSL_USE_NSS',
+ 'HAVE_NSS_SSL_H',
+ 'SSL_USE_NSS_RNG',
+ ],
+ 'conditions': [
+ ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
+ 'dependencies': [
+ '<(DEPTH)/build/linux/system.gyp:ssl',
+ ],
+ }],
+ ['OS == "mac" or OS == "ios" or OS == "win"', {
+ 'dependencies': [
+ '<(DEPTH)/net/third_party/nss/ssl.gyp:libssl',
+ '<(DEPTH)/third_party/nss/nss.gyp:nspr',
+ '<(DEPTH)/third_party/nss/nss.gyp:nss',
+ ],
+ }],
+ ],
+ }],
],
}, # target_defaults
}
diff --git a/chromium/third_party/libjingle/source/talk/build/ios_test.plist b/chromium/third_party/libjingle/source/talk/build/ios_test.plist
new file mode 100644
index 00000000000..c2fb0617f33
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/build/ios_test.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.Google.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
diff --git a/chromium/third_party/libjingle/source/talk/build/ios_tests.gypi b/chromium/third_party/libjingle/source/talk/build/ios_tests.gypi
new file mode 100644
index 00000000000..baf1f100a61
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/build/ios_tests.gypi
@@ -0,0 +1,55 @@
+#
+# libjingle
+# Copyright 2014, Google Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# Include this .gypi in an ObjC target's definition to allow it to be
+# used as an iOS or OS/X application.
+
+{
+ 'conditions': [
+ ['OS=="ios"', {
+ 'variables': {
+ 'infoplist_file': './ios_test.plist',
+ },
+ 'mac_bundle': 1,
+ 'mac_bundle_resources': [
+ '<(infoplist_file)',
+ ],
+ # The plist is listed above so that it appears in XCode's file list,
+ # but we don't actually want to bundle it.
+ 'mac_bundle_resources!': [
+ '<(infoplist_file)',
+ ],
+ 'xcode_settings': {
+ 'CLANG_ENABLE_OBJC_ARC': 'YES',
+ # common.gypi enables this for mac but we want this to be disabled
+ # like it is for ios.
+ 'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'NO',
+ 'INFOPLIST_FILE': '<(infoplist_file)',
+ },
+ }],
+ ], # conditions
+}
diff --git a/chromium/third_party/libjingle/source/talk/build/isolate.gypi b/chromium/third_party/libjingle/source/talk/build/isolate.gypi
index 7b0ac1254d6..24f7ea1edc1 100644
--- a/chromium/third_party/libjingle/source/talk/build/isolate.gypi
+++ b/chromium/third_party/libjingle/source/talk/build/isolate.gypi
@@ -31,6 +31,11 @@
# build/common.gypi is different for the standalone and Chromium builds. Gyp
# doesn't permit conditional inclusion or variable expansion in include paths.
# http://code.google.com/p/gyp/wiki/InputFormatReference#Including_Other_Files
+#
+# Local modifications:
+# * Removed include of '../chrome/version.gypi'.
+# * Removal passing of version_full variable created in version.gypi:
+# '--extra-variable', 'version_full=<(version_full)',
# This file is meant to be included into a target to provide a rule
# to "build" .isolate files into a .isolated file.
@@ -63,6 +68,9 @@
#
# The generated .isolated file will be:
# <(PRODUCT_DIR)/foo_test.isolated
+#
+# See http://dev.chromium.org/developers/testing/isolated-testing/for-swes
+# for more information.
{
'rules': [
@@ -73,7 +81,6 @@
# Files that are known to be involved in this step.
'<(DEPTH)/tools/swarming_client/isolate.py',
'<(DEPTH)/tools/swarming_client/run_isolated.py',
- '<(DEPTH)/tools/swarming_client/googletest/run_test_cases.py',
# Disable file tracking by the build driver for now. This means the
# project must have the proper build-time dependency for their runtime
@@ -90,47 +97,51 @@
'outputs': [
'<(PRODUCT_DIR)/<(RULE_INPUT_ROOT).isolated',
],
+ 'action': [
+ 'python',
+ '<(DEPTH)/tools/swarming_client/isolate.py',
+ '<(test_isolation_mode)',
+ '--result', '<@(_outputs)',
+ '--isolate', '<(RULE_INPUT_PATH)',
+
+ # Variables should use the -V FOO=<(FOO) form so frequent values,
+ # like '0' or '1', aren't stripped out by GYP. Run 'isolate.py help' for
+ # more details.
+ #
+ # This list needs to be kept in sync with the cmd line options
+ # in src/build/android/pylib/gtest/setup.py.
+
+ # Path variables are used to replace file paths when loading a .isolate
+ # file
+ '--path-variable', 'DEPTH', '<(DEPTH)',
+ '--path-variable', 'PRODUCT_DIR', '<(PRODUCT_DIR) ',
+
+ '--config-variable', 'OS=<(OS)',
+ '--config-variable', 'chromeos=<(chromeos)',
+ '--config-variable', 'component=<(component)',
+ # TODO(kbr): move this to chrome_tests.gypi:gles2_conform_tests_run
+ # once support for user-defined config variables is added.
+ '--config-variable',
+ 'internal_gles2_conform_tests=<(internal_gles2_conform_tests)',
+ '--config-variable', 'icu_use_data_file_flag=<(icu_use_data_file_flag)',
+ '--config-variable', 'use_openssl=<(use_openssl)',
+ ],
'conditions': [
- ["test_isolation_outdir==''", {
- 'action': [
- 'python',
- '<(DEPTH)/tools/swarming_client/isolate.py',
- '<(test_isolation_mode)',
- # GYP will eliminate duplicate arguments so '<(PRODUCT_DIR)' cannot
- # be provided twice. To work around this behavior, append '/'.
- #
- # Also have a space after <(PRODUCT_DIR) or visual studio will
- # escape the argument wrappping " with the \ and merge it into
- # the following arguments.
- #
- # Other variables should use the -V FOO=<(FOO) form so frequent
- # values, like '0' or '1', aren't stripped out by GYP.
- '--outdir', '<(PRODUCT_DIR)/ ',
- '--variable', 'PRODUCT_DIR', '<(PRODUCT_DIR) ',
- '--variable', 'OS=<(OS)',
- '--result', '<@(_outputs)',
- '--isolate', '<(RULE_INPUT_PATH)',
- ],
- }, {
+ # Note: When gyp merges lists, it appends them to the old value.
+ ['OS=="mac"', {
+ # <(mac_product_name) can contain a space, so don't use FOO=<(FOO)
+ # form.
'action': [
- 'python',
- '<(DEPTH)/tools/swarming_client/isolate.py',
- '<(test_isolation_mode)',
- '--outdir', '<(test_isolation_outdir)',
- # See comment above.
- '--variable', 'PRODUCT_DIR', '<(PRODUCT_DIR) ',
- '--variable', 'OS=<(OS)',
- '--result', '<@(_outputs)',
- '--isolate', '<(RULE_INPUT_PATH)',
+ '--extra-variable', 'mac_product_name', '<(mac_product_name)',
],
}],
+ ["test_isolation_outdir!=''", {
+ 'action': [ '--isolate-server', '<(test_isolation_outdir)' ],
+ }],
['test_isolation_fail_on_missing == 0', {
- 'action': ['--ignore_broken_items'],
- },
- ],
+ 'action': ['--ignore_broken_items'],
+ }],
],
-
- 'msvs_cygwin_shell': 0,
},
],
}
diff --git a/chromium/third_party/libjingle/source/talk/examples/android/AndroidManifest.xml b/chromium/third_party/libjingle/source/talk/examples/android/AndroidManifest.xml
index 59974f7a834..f898641f8c2 100644
--- a/chromium/third_party/libjingle/source/talk/examples/android/AndroidManifest.xml
+++ b/chromium/third_party/libjingle/source/talk/examples/android/AndroidManifest.xml
@@ -17,10 +17,12 @@
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
+ android:debuggable="true"
android:allowBackup="false">
<activity android:name="AppRTCDemoActivity"
android:label="@string/app_name"
- android:screenOrientation="landscape"
+ android:screenOrientation="fullUser"
+ android:configChanges="orientation|screenSize"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/chromium/third_party/libjingle/source/talk/examples/android/README b/chromium/third_party/libjingle/source/talk/examples/android/README
index feabadb979c..faf4e924d01 100644
--- a/chromium/third_party/libjingle/source/talk/examples/android/README
+++ b/chromium/third_party/libjingle/source/talk/examples/android/README
@@ -1,19 +1,9 @@
This directory contains an example Android client for http://apprtc.appspot.com
Prerequisites:
-- Make sure gclient is checking out tools necessary to target Android: your
- .gclient file should contain a line like:
- target_os = ['android', 'unix']
- Make sure to re-run gclient sync after adding this to download the tools.
-- Env vars need to be set up to target Android; easiest way to do this is to run
- (from the libjingle trunk directory):
- . ./build/android/envsetup.sh
- Note that this clobbers any previously-set $GYP_DEFINES so it must be done
- before the next item.
+- "Android Specific Steps" on http://www.webrtc.org/reference/getting-started
- Set up webrtc-related GYP variables:
export GYP_DEFINES="build_with_libjingle=1 build_with_chromium=0 libjingle_java=1 $GYP_DEFINES"
- export JAVA_HOME=</path/to/JDK>
- export PATH=$JAVA_HOME/bin:$PATH
To cause WEBRTC_LOGGING to emit to Android's logcat, add enable_tracing=1 to
the $GYP_DEFINES above.
- When targeting both desktop & android, make sure to use a different output_dir
@@ -34,7 +24,7 @@ the dialog box.
Alternatively, replace the <NNN> from the desktop chrome into the following
command:
-adb shell am start -a android.intent.action.VIEW -d '"https://apprtc.appspot.com/?r=<NNN>"'
+adb shell am start -n org.appspot.apprtc/.AppRTCDemoActivity -a android.intent.action.VIEW -d '"https://apprtc.appspot.com/?r=<NNN>"'
This should result in the app launching on Android and connecting to the apprtc
page displayed in the desktop browser.
diff --git a/chromium/third_party/libjingle/source/talk/examples/call/call_main.cc b/chromium/third_party/libjingle/source/talk/examples/call/call_main.cc
index 2ee796b1c25..33d5385719d 100644
--- a/chromium/third_party/libjingle/source/talk/examples/call/call_main.cc
+++ b/chromium/third_party/libjingle/source/talk/examples/call/call_main.cc
@@ -25,9 +25,10 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <cstdio>
-#include <cstring>
+#include <stdio.h>
+#include <string.h>
#include <time.h>
+
#include <iomanip>
#include <iostream>
#include <vector>
@@ -45,9 +46,6 @@
#include "talk/examples/call/console.h"
#include "talk/examples/call/mediaenginefactory.h"
#include "talk/p2p/base/constants.h"
-#ifdef ANDROID
-#include "talk/media/other/androidmediaengine.h"
-#endif
#include "talk/session/media/mediasessionclient.h"
#include "talk/session/media/srtpfilter.h"
#include "talk/xmpp/xmppauth.h"
@@ -185,7 +183,7 @@ static const int DEFAULT_PORT = 5222;
static std::vector<cricket::AudioCodec> codecs;
static const cricket::AudioCodec ISAC(103, "ISAC", 40000, 16000, 1, 0);
-cricket::MediaEngine *AndroidMediaEngineFactory() {
+cricket::MediaEngineInterface *CreateAndroidMediaEngine() {
cricket::FakeMediaEngine *engine = new cricket::FakeMediaEngine();
codecs.push_back(ISAC);
@@ -438,7 +436,7 @@ int main(int argc, char **argv) {
}
#ifdef ANDROID
- InitAndroidMediaEngineFactory(AndroidMediaEngineFactory);
+ MediaEngineFactory::SetCreateFunction(&CreateAndroidMediaEngine);
#endif
#if WIN32
diff --git a/chromium/third_party/libjingle/source/talk/examples/call/console.cc b/chromium/third_party/libjingle/source/talk/examples/call/console.cc
index dec3b4abc11..647601e8170 100644
--- a/chromium/third_party/libjingle/source/talk/examples/call/console.cc
+++ b/chromium/third_party/libjingle/source/talk/examples/call/console.cc
@@ -27,12 +27,14 @@
#define _CRT_SECURE_NO_DEPRECATE 1
+#include <assert.h>
+
#ifdef POSIX
#include <signal.h>
#include <termios.h>
#include <unistd.h>
#endif // POSIX
-#include <cassert>
+
#include "talk/base/logging.h"
#include "talk/base/messagequeue.h"
#include "talk/base/stringutils.h"
@@ -46,28 +48,29 @@ static void DoNothing(int unused) {}
Console::Console(talk_base::Thread *thread, CallClient *client) :
client_(client),
client_thread_(thread),
- console_thread_(new talk_base::Thread()) {}
+ stopped_(false) {}
Console::~Console() {
Stop();
}
void Console::Start() {
- if (!console_thread_) {
+ if (stopped_) {
// stdin was closed in Stop(), so we can't restart.
LOG(LS_ERROR) << "Cannot re-start";
return;
}
- if (console_thread_->started()) {
+ if (console_thread_) {
LOG(LS_WARNING) << "Already started";
return;
}
+ console_thread_.reset(new talk_base::Thread());
console_thread_->Start();
console_thread_->Post(this, MSG_START);
}
void Console::Stop() {
- if (console_thread_ && console_thread_->started()) {
+ if (console_thread_) {
#ifdef WIN32
CloseHandle(GetStdHandle(STD_INPUT_HANDLE));
#else
@@ -78,6 +81,7 @@ void Console::Stop() {
#endif
console_thread_->Stop();
console_thread_.reset();
+ stopped_ = true;
}
}
diff --git a/chromium/third_party/libjingle/source/talk/examples/call/console.h b/chromium/third_party/libjingle/source/talk/examples/call/console.h
index 4a90a7fe540..f0f36e34677 100644
--- a/chromium/third_party/libjingle/source/talk/examples/call/console.h
+++ b/chromium/third_party/libjingle/source/talk/examples/call/console.h
@@ -28,7 +28,7 @@
#ifndef TALK_EXAMPLES_CALL_CONSOLE_H_
#define TALK_EXAMPLES_CALL_CONSOLE_H_
-#include <cstdio>
+#include <stdio.h>
#include "talk/base/thread.h"
#include "talk/base/messagequeue.h"
@@ -64,6 +64,7 @@ class Console : public talk_base::MessageHandler {
CallClient *client_;
talk_base::Thread *client_thread_;
talk_base::scoped_ptr<talk_base::Thread> console_thread_;
+ bool stopped_;
};
#endif // TALK_EXAMPLES_CALL_CONSOLE_H_
diff --git a/chromium/third_party/libjingle/source/talk/examples/chat/Info.plist b/chromium/third_party/libjingle/source/talk/examples/chat/Info.plist
deleted file mode 100644
index ecd083ac639..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/chat/Info.plist
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleIdentifier</key>
- <string>com.google.call</string>
- <key>CFBundleName</key>
- <string>chat</string>
-</dict>
-</plist>
-
diff --git a/chromium/third_party/libjingle/source/talk/examples/chat/chat_main.cc b/chromium/third_party/libjingle/source/talk/examples/chat/chat_main.cc
deleted file mode 100644
index 09a454e2d88..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/chat/chat_main.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * libjingle
- * Copyright 2004--2013, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-//
-// A simple text chat application, largely copied from examples/call.
-//
-
-#include <iostream>
-
-#include "talk/base/logging.h"
-#include "talk/base/ssladapter.h"
-
-#ifdef OSX
-#include "talk/base/maccocoasocketserver.h"
-#elif defined(WIN32)
-#include "talk/base/win32socketserver.h"
-#else
-#include "talk/base/physicalsocketserver.h"
-#endif
-
-#include "talk/xmpp/constants.h"
-#include "talk/xmpp/xmppauth.h"
-#include "talk/xmpp/xmppclientsettings.h"
-#include "talk/xmpp/xmpppump.h"
-#include "talk/xmpp/xmppsocket.h"
-
-#include "talk/examples/chat/chatapp.h"
-#include "talk/examples/chat/consoletask.h"
-
-static const int kDefaultPort = 5222;
-
-int main(int argc, char* argv[]) {
- // TODO(pmclean): Remove duplication of code with examples/call.
- // Set up debugging.
- bool debug = true;
- if (debug) {
- talk_base::LogMessage::LogToDebug(talk_base::LS_VERBOSE);
- }
-
- // Set up the crypto subsystem.
- talk_base::InitializeSSL();
-
- // Parse username and password, if present.
- buzz::Jid jid;
- std::string username;
- talk_base::InsecureCryptStringImpl pass;
- if (argc > 1) {
- username = argv[1];
- if (argc > 2) {
- pass.password() = argv[2];
- }
- }
-
- // ... else prompt for them
- if (username.empty()) {
- printf("JID: ");
- std::cin >> username;
- }
- if (username.find('@') == std::string::npos) {
- username.append("@localhost");
- }
-
- jid = buzz::Jid(username);
- if (!jid.IsValid() || jid.node() == "") {
- printf("Invalid JID. JIDs should be in the form user@domain\n");
- return 1;
- }
-
- if (pass.password().empty()) {
- buzz::ConsoleTask::SetEcho(false);
- printf("Password: ");
- std::cin >> pass.password();
- buzz::ConsoleTask::SetEcho(true);
- printf("\n");
- }
-
- // OTP (this can be skipped)
- std::string otp_token;
- printf("OTP: ");
- fflush(stdin);
- std::getline(std::cin, otp_token);
-
- // Setup the connection settings.
- buzz::XmppClientSettings xcs;
- xcs.set_user(jid.node());
- xcs.set_resource("chat");
- xcs.set_host(jid.domain());
- bool allow_plain = false;
- xcs.set_allow_plain(allow_plain);
- xcs.set_use_tls(buzz::TLS_REQUIRED);
- xcs.set_pass(talk_base::CryptString(pass));
- if (!otp_token.empty() && *otp_token.c_str() != '\n') {
- xcs.set_auth_token(buzz::AUTH_MECHANISM_OAUTH2, otp_token);
- }
-
- // Build the server spec
- std::string host;
- int port;
-
- std::string server = "talk.google.com";
- int colon = server.find(':');
- if (colon == -1) {
- host = server;
- port = kDefaultPort;
- } else {
- host = server.substr(0, colon);
- port = atoi(server.substr(colon + 1).c_str());
- }
- xcs.set_server(talk_base::SocketAddress(host, port));
-
- talk_base::Thread* main_thread = talk_base::Thread::Current();
-#if WIN32
- // Need to pump messages on our main thread on Windows.
- talk_base::Win32Thread w32_thread;
- talk_base::ThreadManager::Instance()->SetCurrentThread(&w32_thread);
-#elif defined(OSX)
- talk_base::MacCocoaSocketServer ss;
- talk_base::SocketServerScope ss_scope(&ss);
-#else
- talk_base::PhysicalSocketServer ss;
-#endif
-
- buzz::XmppPump* pump = new buzz::XmppPump();
- ChatApp *client = new ChatApp(pump->client(), main_thread);
-
- // Start pumping messages!
- pump->DoLogin(xcs, new buzz::XmppSocket(buzz::TLS_REQUIRED), new XmppAuth());
-
- main_thread->Run();
- pump->DoDisconnect();
-
- delete client;
-
- return 0;
-}
diff --git a/chromium/third_party/libjingle/source/talk/examples/chat/chatapp.cc b/chromium/third_party/libjingle/source/talk/examples/chat/chatapp.cc
deleted file mode 100644
index 59b1c69fb9a..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/chat/chatapp.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * libjingle
- * Copyright 2004--2013, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "talk/examples/chat/chatapp.h"
-
-#include "talk/examples/chat/consoletask.h"
-#include "talk/examples/chat/textchatsendtask.h"
-#include "talk/examples/chat/textchatreceivetask.h"
-#include "talk/xmpp/presenceouttask.h"
-#include "talk/xmpp/presencereceivetask.h"
-
-#ifdef WIN32
-#define snprintf _snprintf
-#endif
-
-ChatApp::ChatApp(buzz::XmppClient* xmpp_client, talk_base::Thread* main_thread)
- : xmpp_client_(xmpp_client),
- presence_out_task_(),
- presence_receive_task_(),
- message_send_task_(),
- message_received_task_(),
- console_task_(new buzz::ConsoleTask(main_thread)),
- ui_state_(STATE_BASE) {
- xmpp_client_->SignalStateChange.connect(this, &ChatApp::OnStateChange);
-
- console_task_->TextInputHandler.connect(this, &ChatApp::OnConsoleMessage);
- console_task_->Start();
-}
-
-ChatApp::~ChatApp() {
- if (presence_out_task_ != NULL) {
- // Check out
- BroadcastPresence(away);
- }
-}
-
-void ChatApp::Quit() {
- talk_base::Thread::Current()->Quit();
-}
-
-void ChatApp::OnXmppOpen() {
- presence_out_task_.reset(new buzz::PresenceOutTask(xmpp_client_));
- presence_receive_task_.reset(new buzz::PresenceReceiveTask(xmpp_client_));
- presence_receive_task_->PresenceUpdate.connect(this,
- &ChatApp::OnPresenceUpdate);
- message_send_task_.reset(new buzz::TextChatSendTask(xmpp_client_));
- message_received_task_.reset(new buzz::TextChatReceiveTask(xmpp_client_));
- message_received_task_->SignalTextChatReceived.connect(
- this, &ChatApp::OnTextMessage);
-
- presence_out_task_->Start();
- presence_receive_task_->Start();
- message_send_task_->Start();
- message_received_task_->Start();
-}
-
-void ChatApp::BroadcastPresence(PresenceState state) {
- buzz::PresenceStatus status;
- status.set_jid(xmpp_client_->jid());
- status.set_available(state == online);
- status.set_show(state == online ? buzz::PresenceStatus::SHOW_ONLINE
- : buzz::PresenceStatus::SHOW_AWAY);
- presence_out_task_->Send(status);
-}
-
-// UI Stuff
-static const char* kMenuChoiceQuit = "0";
-static const char* kMenuChoiceRoster = "1";
-static const char* kMenuChoiceChat = "2";
-
-static const char* kUIStrings[3][2] = {
- {kMenuChoiceQuit, "Quit"},
- {kMenuChoiceRoster, "Roster"},
- {kMenuChoiceChat, "Send"}};
-
-void ChatApp::PrintMenu() {
- char buff[128];
- int numMenuItems = sizeof(kUIStrings) / sizeof(kUIStrings[0]);
- for (int index = 0; index < numMenuItems; ++index) {
- snprintf(buff, sizeof(buff), "%s) %s\n", kUIStrings[index][0],
- kUIStrings[index][1]);
- console_task_->Print(buff);
- }
- console_task_->Print("choice:");
-}
-
-void ChatApp::PrintRoster() {
- int index = 0;
- for (RosterList::iterator iter = roster_list_.begin();
- iter != roster_list_.end(); ++iter) {
- const buzz::Jid& jid = iter->second.jid();
- console_task_->Print(
- "%d: (*) %s@%s [%s] \n",
- index++,
- jid.node().c_str(),
- jid.domain().c_str(),
- jid.resource().c_str());
- }
-}
-
-void ChatApp::PromptJid() {
- PrintRoster();
- console_task_->Print("choice:");
-}
-
-void ChatApp::PromptChatMessage() {
- console_task_->Print(":");
-}
-
-bool ChatApp::GetRosterItem(int index, buzz::PresenceStatus* status) {
- int found_index = 0;
- for (RosterList::iterator iter = roster_list_.begin();
- iter != roster_list_.end() && found_index <= index; ++iter) {
- if (found_index == index) {
- *status = iter->second;
- return true;
- }
- found_index++;
- }
-
- return false;
-}
-
-void ChatApp::HandleBaseInput(const std::string& message) {
- if (message == kMenuChoiceQuit) {
- Quit();
- } else if (message == kMenuChoiceRoster) {
- PrintRoster();
- } else if (message == kMenuChoiceChat) {
- ui_state_ = STATE_PROMPTJID;
- PromptJid();
- } else if (message == "") {
- PrintMenu();
- }
-}
-
-void ChatApp::HandleJidInput(const std::string& message) {
- if (isdigit(message[0])) {
- // It's an index-based roster choice.
- int index = 0;
- buzz::PresenceStatus status;
- if (!talk_base::FromString(message, &index) ||
- !GetRosterItem(index, &status)) {
- // fail, so drop back
- ui_state_ = STATE_BASE;
- return;
- }
-
- chat_dest_jid_ = status.jid();
- } else {
- // It's an explicit address.
- chat_dest_jid_ = buzz::Jid(message.c_str());
- }
- ui_state_ = STATE_CHATTING;
- PromptChatMessage();
-}
-
-void ChatApp::HandleChatInput(const std::string& message) {
- if (message == "") {
- ui_state_ = STATE_BASE;
- PrintMenu();
- } else {
- message_send_task_->Send(chat_dest_jid_, message);
- PromptChatMessage();
- }
-}
-
-// Connection state notifications
-void ChatApp::OnStateChange(buzz::XmppEngine::State state) {
- switch (state) {
- // Nonexistent state
- case buzz::XmppEngine::STATE_NONE:
- break;
-
- // Nonexistent state
- case buzz::XmppEngine::STATE_START:
- break;
-
- // Exchanging stream headers, authenticating and so on.
- case buzz::XmppEngine::STATE_OPENING:
- break;
-
- // Authenticated and bound.
- case buzz::XmppEngine::STATE_OPEN:
- OnXmppOpen();
- BroadcastPresence(online);
- PrintMenu();
- break;
-
- // Session closed, possibly due to error.
- case buzz::XmppEngine::STATE_CLOSED:
- break;
- }
-}
-
-// Presence Notifications
-void ChatApp::OnPresenceUpdate(const buzz::PresenceStatus& status) {
- if (status.available()) {
- roster_list_[status.jid().Str()] = status;
- } else {
- RosterList::iterator iter = roster_list_.find(status.jid().Str());
- if (iter != roster_list_.end()) {
- roster_list_.erase(iter);
- }
- }
-}
-
-// Text message handlers
-void ChatApp::OnTextMessage(const buzz::Jid& from, const buzz::Jid& to,
- const std::string& message) {
- console_task_->Print("%s says: %s\n", from.node().c_str(), message.c_str());
-}
-
-void ChatApp::OnConsoleMessage(const std::string &message) {
- switch (ui_state_) {
- case STATE_BASE:
- HandleBaseInput(message);
- break;
-
- case STATE_PROMPTJID:
- HandleJidInput(message);
- break;
-
- case STATE_CHATTING:
- HandleChatInput(message);
- break;
- }
-}
diff --git a/chromium/third_party/libjingle/source/talk/examples/chat/chatapp.h b/chromium/third_party/libjingle/source/talk/examples/chat/chatapp.h
deleted file mode 100644
index cc032a67f61..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/chat/chatapp.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * libjingle
- * Copyright 2004--2013, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TALK_EXAMPLES_CHAT_CHATAPP_H_
-#define TALK_EXAMPLES_CHAT_CHATAPP_H_
-
-#include "talk/base/thread.h"
-#include "talk/base/scoped_ptr.h"
-
-#include "talk/xmpp/jid.h"
-#include "talk/xmpp/xmppclient.h"
-
-namespace buzz {
-class XmppClient;
-class PresenceOutTask;
-class PresenceReceiveTask;
-class TextChatSendTask;
-class TextChatReceiveTask;
-class ConsoleTask;
-class PresenceStatus;
-}
-
-// This is an example chat app for libjingle, showing how to use xmpp tasks,
-// data, callbacks, etc. It has a simple text-based UI for logging in,
-// sending and receiving messages, and printing the roster.
-class ChatApp: public sigslot::has_slots<> {
- public:
- // Arguments:
- // xmpp_client Points to the XmppClient for the communication channel
- // (typically created by the XmppPump object).
- // main_thread Wraps the application's main thread. Subsidiary threads
- // for the various tasks will be forked off of this.
- ChatApp(buzz::XmppClient* xmpp_client, talk_base::Thread* main_thread);
-
- // Shuts down and releases all of the contained tasks/threads
- ~ChatApp();
-
- // Shuts down the current thread and quits
- void Quit();
-
- private:
- //
- // Initialization
- //
- // Called explicitly after the connection to the chat server is established.
- void OnXmppOpen();
-
- //
- // UI Stuff
- //
- // Prints the app main menu on the console.
- // Called when ui_state_ == STATE_BASE.
- void PrintMenu();
-
- // Prints a numbered list of the logged-in user's roster on the console.
- void PrintRoster();
-
- // Prints a prompt for the user to enter either the index from the
- // roster list of the user they wish to chat with, or a fully-qualified
- // (user@server.ext) jid.
- // Called when when ui_state_ == STATE_PROMPTJID.
- void PromptJid();
-
- // Prints a prompt on the console for the user to enter a message to send.
- // Called when when ui_state_ == STATE_CHATTING.
- void PromptChatMessage();
-
- // Sends our presence state to the chat server (and on to your roster list).
- // Arguments:
- // state Specifies the presence state to show.
- enum PresenceState {online, away};
- void BroadcastPresence(PresenceState state);
-
- // Returns the RosterItem associated with the specified index.
- // Just a helper to select a roster item from a numbered list in the UI.
- bool GetRosterItem(int index, buzz::PresenceStatus* status);
-
- //
- // Input Handling
- //
- // Receives input when ui_state_ == STATE_BASE. Handles choices from the
- // main menu.
- void HandleBaseInput(const std::string& message);
-
- // Receives input when ui_state_ == STATE_PROMPTJID. Handles selection
- // of a JID to chat to.
- void HandleJidInput(const std::string& message);
-
- // Receives input when ui_state_ == STATE_CHATTING. Handles text messages.
- void HandleChatInput(const std::string& message);
-
- //
- // signal/slot Callbacks
- //
- // Connected to the XmppClient::SignalStateChange slot. Receives
- // notifications of state changes of the connection.
- void OnStateChange(buzz::XmppEngine::State state);
-
- // Connected to the PresenceReceiveTask::PresenceUpdate slot.
- // Receives status messages for the logged-in user's roster (i.e.
- // an initial list from the server and people coming/going).
- void OnPresenceUpdate(const buzz::PresenceStatus& status);
-
- // Connected to the TextChatReceiveTask::SignalTextChatReceived slot.
- // Called when we receive a text chat from someone else.
- void OnTextMessage(const buzz::Jid& from, const buzz::Jid& to,
- const std::string& message);
-
- // Receives text input from the console task. This is where any input
- // from the user comes in.
- // Arguments:
- // message What the user typed.
- void OnConsoleMessage(const std::string &message);
-
- // The XmppClient object associated with this chat application instance.
- buzz::XmppClient* xmpp_client_;
-
- // We send presence information through this object.
- talk_base::scoped_ptr<buzz::PresenceOutTask> presence_out_task_;
-
- // We receive others presence information through this object.
- talk_base::scoped_ptr<buzz::PresenceReceiveTask> presence_receive_task_;
-
- // We send text messages though this object.
- talk_base::scoped_ptr<buzz::TextChatSendTask> message_send_task_;
-
- // We receive messages through this object.
- talk_base::scoped_ptr<buzz::TextChatReceiveTask> message_received_task_;
-
- // UI gets drawn and receives input through this task.
- talk_base::scoped_ptr< buzz::ConsoleTask> console_task_;
-
- // The list of JIDs for the people in the logged-in users roster.
- // RosterList roster_list_;
- typedef std::map<std::string, buzz::PresenceStatus> RosterList;
- RosterList roster_list_;
-
- // The JID of the user currently being chatted with.
- buzz::Jid chat_dest_jid_;
-
- // UI State constants
- enum UIState { STATE_BASE, STATE_PROMPTJID, STATE_CHATTING };
- UIState ui_state_;
-};
-
-#endif // TALK_EXAMPLES_CHAT_CHATAPP_H_
-
diff --git a/chromium/third_party/libjingle/source/talk/examples/chat/consoletask.cc b/chromium/third_party/libjingle/source/talk/examples/chat/consoletask.cc
deleted file mode 100644
index 2577c79cb54..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/chat/consoletask.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * libjingle
- * Copyright 2004--2013, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// TODO(pmclean): Perhaps this should be unified with examples/call/console.cc
-// and refactor to talk/base.
-#include "talk/examples/chat/consoletask.h"
-
-#define _CRT_SECURE_NO_DEPRECATE 1
-
-#include <stdarg.h>
-#ifdef POSIX
-#include <signal.h>
-#include <termios.h>
-#include <unistd.h>
-#endif // POSIX
-#include <cassert>
-
-#include "talk/base/logging.h"
-
-#ifdef POSIX
-static void DoNothing(int unused) {}
-#endif
-
-namespace buzz {
-
-ConsoleTask::ConsoleTask(talk_base::Thread *thread) :
- client_thread_(thread),
- console_thread_(new talk_base::Thread()) {
-}
-
-ConsoleTask::~ConsoleTask() {
- Stop();
-}
-
-void ConsoleTask::Start() {
- if (!console_thread_) {
- // stdin was closed in Stop(), so we can't restart.
- LOG(LS_ERROR) << "Cannot re-start";
- return;
- }
- if (console_thread_->started()) {
- LOG(LS_WARNING) << "Already started";
- return;
- }
- console_thread_->Start();
- console_thread_->Post(this, MSG_START);
-}
-
-void ConsoleTask::Stop() {
- if (console_thread_ && console_thread_->started()) {
-#ifdef WIN32
- CloseHandle(GetStdHandle(STD_INPUT_HANDLE));
-#else
- close(fileno(stdin));
- // This forces the read() in fgets() to return with errno = EINTR. fgets()
- // will retry the read() and fail, thus returning.
- pthread_kill(console_thread_->GetPThread(), SIGUSR1);
-#endif
- console_thread_->Stop();
- console_thread_.reset();
- }
-}
-
-void ConsoleTask::SetEcho(bool on) {
-#ifdef WIN32
- HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
- if ((hIn == INVALID_HANDLE_VALUE) || (hIn == NULL))
- return;
-
- DWORD mode;
- if (!GetConsoleMode(hIn, &mode))
- return;
-
- if (on) {
- mode = mode | ENABLE_ECHO_INPUT;
- } else {
- mode = mode & ~ENABLE_ECHO_INPUT;
- }
-
- SetConsoleMode(hIn, mode);
-#else // MAC & LINUX
- const int fd = fileno(stdin);
- if (fd == -1) {
- return;
- }
-
- struct termios tcflags;
- if (tcgetattr(fd, &tcflags) == -1) {
- return;
- }
-
- if (on) {
- tcflags.c_lflag |= ECHO;
- } else {
- tcflags.c_lflag &= ~ECHO;
- }
-
- tcsetattr(fd, TCSANOW, &tcflags);
-#endif
-}
-
-void ConsoleTask::Print(const char* format, ...) {
- va_list ap;
- va_start(ap, format);
-
- char buf[4096];
- int size = vsnprintf(buf, sizeof(buf), format, ap);
- assert(size >= 0);
- assert(size < static_cast<int>(sizeof(buf)));
- buf[size] = '\0';
- printf("%s", buf);
- fflush(stdout);
-
- va_end(ap);
-}
-
-void ConsoleTask::RunConsole() {
- char input_buffer[128];
- while (fgets(input_buffer, sizeof(input_buffer), stdin) != NULL) {
- client_thread_->Post(this, MSG_INPUT,
- new talk_base::TypedMessageData<std::string>(input_buffer));
- }
-}
-
-void ConsoleTask::OnMessage(talk_base::Message *msg) {
- switch (msg->message_id) {
- case MSG_START:
-#ifdef POSIX
- // Install a no-op signal so that we can abort RunConsole() by raising
- // SIGUSR1.
- struct sigaction act;
- act.sa_handler = &DoNothing;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- if (sigaction(SIGUSR1, &act, NULL) < 0) {
- LOG(LS_WARNING) << "Can't install signal";
- }
-#endif
- RunConsole();
- break;
-
- case MSG_INPUT:
- talk_base::TypedMessageData<std::string> *data =
- static_cast<talk_base::TypedMessageData<std::string>*>(msg->pdata);
- // Trim off the .line-terminator to make processing easier.
- std::string parsed_message =
- data->data().substr(0, data->data().length() - 1);
- TextInputHandler(parsed_message);
- break;
- }
-}
-
-} // namespace buzz
diff --git a/chromium/third_party/libjingle/source/talk/examples/chat/consoletask.h b/chromium/third_party/libjingle/source/talk/examples/chat/consoletask.h
deleted file mode 100644
index 1d45b3a7f53..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/chat/consoletask.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * libjingle
- * Copyright 2004--2013, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TALK_EXAMPLES_CHAT_CONSOLETASK_H_
-#define TALK_EXAMPLES_CHAT_CONSOLETASK_H_
-
-#include <cstdio>
-
-#include "talk/base/thread.h"
-#include "talk/base/sigslot.h"
-
-namespace buzz {
-
-//
-// Provides properly threaded console I/O.
-//
-class ConsoleTask : public talk_base::MessageHandler {
- public:
- // Arguments:
- // thread The main application thread. Input messages get posted through
- // this.
- explicit ConsoleTask(talk_base::Thread *thread);
-
- // Shuts down the thread associated with this task.
- ~ConsoleTask();
-
- // Slot for text inputs handler.
- sigslot::signal1<const std::string&> TextInputHandler;
-
- // Starts reading lines from the console and passes them to the
- // TextInputHandler.
- void Start();
-
- // Stops reading lines and shuts down the thread. Cannot be restarted.
- void Stop();
-
- // Thread messages (especialy text-input messages) come in through here.
- virtual void OnMessage(talk_base::Message *msg);
-
- // printf() style output to the console.
- void Print(const char* format, ...);
-
- // Turns on/off the echo of input characters on the console.
- // Arguments:
- // on If true turns echo on, off otherwise.
- static void SetEcho(bool on);
-
- private:
- /** Message IDs (for OnMessage()). */
- enum {
- MSG_START,
- MSG_INPUT,
- };
-
- // Starts up polling for console input
- void RunConsole();
-
- // The main application thread
- talk_base::Thread *client_thread_;
-
- // The tread associated with this console object
- talk_base::scoped_ptr<talk_base::Thread> console_thread_;
-};
-
-} // namespace buzz
-
-#endif // TALK_EXAMPLES_CHAT_CONSOLETASK_H_
-
diff --git a/chromium/third_party/libjingle/source/talk/examples/chat/textchatsendtask.cc b/chromium/third_party/libjingle/source/talk/examples/chat/textchatsendtask.cc
deleted file mode 100644
index ba144530294..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/chat/textchatsendtask.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * libjingle
- * Copyright 2004--2013, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "talk/examples/chat/textchatsendtask.h"
-
-#include "talk/xmpp/constants.h"
-#include "talk/xmpp/xmppclient.h"
-
-namespace buzz {
-TextChatSendTask::TextChatSendTask(XmppTaskParentInterface* parent)
- : XmppTask(parent) {
-}
-
-TextChatSendTask::~TextChatSendTask() {
- Stop();
-}
-
-XmppReturnStatus TextChatSendTask::Send(const Jid& to,
- const std::string& textmessage) {
- // Make sure we are actually connected.
- if (GetState() != STATE_INIT && GetState() != STATE_START) {
- return XMPP_RETURN_BADSTATE;
- }
-
- // Put together the chat stanza...
- XmlElement* message_stanza = new XmlElement(QN_MESSAGE);
-
- // ... and specify the required attributes...
- message_stanza->AddAttr(QN_TO, to.Str());
- message_stanza->AddAttr(QN_TYPE, "chat");
- message_stanza->AddAttr(QN_LANG, "en");
-
- // ... and fill out the body.
- XmlElement* message_body = new XmlElement(QN_BODY);
- message_body->AddText(textmessage);
- message_stanza->AddElement(message_body);
-
- // Now queue it up.
- QueueStanza(message_stanza);
-
- return XMPP_RETURN_OK;
-}
-
-int TextChatSendTask::ProcessStart() {
- const XmlElement* stanza = NextStanza();
- if (stanza == NULL) {
- return STATE_BLOCKED;
- }
-
- if (SendStanza(stanza) != XMPP_RETURN_OK) {
- return STATE_ERROR;
- }
-
- return STATE_START;
-}
-
-} // namespace buzz
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppClient.m b/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppClient.m
deleted file mode 100644
index d6c86d8422f..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppClient.m
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * libjingle
- * Copyright 2013, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "APPRTCAppClient.h"
-
-#import <dispatch/dispatch.h>
-
-#import "GAEChannelClient.h"
-#import "RTCICEServer.h"
-
-@interface APPRTCAppClient ()
-
-@property(nonatomic, strong) dispatch_queue_t backgroundQueue;
-@property(nonatomic, copy) NSString *baseURL;
-@property(nonatomic, strong) GAEChannelClient *gaeChannel;
-@property(nonatomic, copy) NSString *postMessageUrl;
-@property(nonatomic, copy) NSString *pcConfig;
-@property(nonatomic, strong) NSMutableString *roomHtml;
-@property(atomic, strong) NSMutableArray *sendQueue;
-@property(nonatomic, copy) NSString *token;
-
-@property(nonatomic, assign) BOOL verboseLogging;
-
-@end
-
-@implementation APPRTCAppClient
-
-@synthesize ICEServerDelegate = _ICEServerDelegate;
-@synthesize messageHandler = _messageHandler;
-
-@synthesize backgroundQueue = _backgroundQueue;
-@synthesize baseURL = _baseURL;
-@synthesize gaeChannel = _gaeChannel;
-@synthesize postMessageUrl = _postMessageUrl;
-@synthesize pcConfig = _pcConfig;
-@synthesize roomHtml = _roomHtml;
-@synthesize sendQueue = _sendQueue;
-@synthesize token = _token;
-@synthesize verboseLogging = _verboseLogging;
-
-- (id)init {
- if (self = [super init]) {
- _backgroundQueue = dispatch_queue_create("RTCBackgroundQueue", NULL);
- _sendQueue = [NSMutableArray array];
- // Uncomment to see Request/Response logging.
- // _verboseLogging = YES;
- }
- return self;
-}
-
-#pragma mark - Public methods
-
-- (void)connectToRoom:(NSURL *)url {
- NSURLRequest *request = [self getRequestFromUrl:url];
- [NSURLConnection connectionWithRequest:request delegate:self];
-}
-
-- (void)sendData:(NSData *)data {
- @synchronized(self) {
- [self maybeLogMessage:@"Send message"];
- [self.sendQueue addObject:[data copy]];
- }
- [self requestQueueDrainInBackground];
-}
-
-#pragma mark - Internal methods
-
-- (NSString*)findVar:(NSString*)name
- strippingQuotes:(BOOL)strippingQuotes {
- NSError* error;
- NSString* pattern =
- [NSString stringWithFormat:@".*\n *var %@ = ([^\n]*);\n.*", name];
- NSRegularExpression *regexp =
- [NSRegularExpression regularExpressionWithPattern:pattern
- options:0
- error:&error];
- NSAssert(!error, @"Unexpected error compiling regex: ",
- error.localizedDescription);
-
- NSRange fullRange = NSMakeRange(0, [self.roomHtml length]);
- NSArray *matches =
- [regexp matchesInString:self.roomHtml options:0 range:fullRange];
- if ([matches count] != 1) {
- [self showMessage:[NSString stringWithFormat:@"%d matches for %@ in %@",
- [matches count], name, self.roomHtml]];
- return nil;
- }
- NSRange matchRange = [matches[0] rangeAtIndex:1];
- NSString* value = [self.roomHtml substringWithRange:matchRange];
- if (strippingQuotes) {
- NSAssert([value length] > 2,
- @"Can't strip quotes from short string: [%@]", value);
- NSAssert(([value characterAtIndex:0] == '\'' &&
- [value characterAtIndex:[value length] - 1] == '\''),
- @"Can't strip quotes from unquoted string: [%@]", value);
- value = [value substringWithRange:NSMakeRange(1, [value length] - 2)];
- }
- return value;
-}
-
-- (NSURLRequest *)getRequestFromUrl:(NSURL *)url {
- self.roomHtml = [NSMutableString stringWithCapacity:20000];
- NSString *path =
- [NSString stringWithFormat:@"https:%@", [url resourceSpecifier]];
- NSURLRequest *request =
- [NSURLRequest requestWithURL:[NSURL URLWithString:path]];
- return request;
-}
-
-- (void)maybeLogMessage:(NSString *)message {
- if (self.verboseLogging) {
- NSLog(@"%@", message);
- }
-}
-
-- (void)requestQueueDrainInBackground {
- dispatch_async(self.backgroundQueue, ^(void) {
- // TODO(hughv): This can block the UI thread. Fix.
- @synchronized(self) {
- if ([self.postMessageUrl length] < 1) {
- return;
- }
- for (NSData *data in self.sendQueue) {
- NSString *url = [NSString stringWithFormat:@"%@/%@",
- self.baseURL,
- self.postMessageUrl];
- [self sendData:data withUrl:url];
- }
- [self.sendQueue removeAllObjects];
- }
- });
-}
-
-- (void)sendData:(NSData *)data withUrl:(NSString *)url {
- NSMutableURLRequest *request =
- [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
- request.HTTPMethod = @"POST";
- [request setHTTPBody:data];
- NSURLResponse *response;
- NSError *error;
- NSData *responseData = [NSURLConnection sendSynchronousRequest:request
- returningResponse:&response
- error:&error];
- NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
- int status = [httpResponse statusCode];
- NSAssert(status == 200,
- @"Bad response [%d] to message: %@\n\n%@",
- status,
- [NSString stringWithUTF8String:[data bytes]],
- [NSString stringWithUTF8String:[responseData bytes]]);
-}
-
-- (void)showMessage:(NSString *)message {
- NSLog(@"%@", message);
- UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Unable to join"
- message:message
- delegate:nil
- cancelButtonTitle:@"OK"
- otherButtonTitles:nil];
- [alertView show];
-}
-
-- (void)updateICEServers:(NSMutableArray *)ICEServers
- withTurnServer:(NSString *)turnServerUrl {
- if ([turnServerUrl length] < 1) {
- [self.ICEServerDelegate onICEServers:ICEServers];
- return;
- }
- dispatch_async(self.backgroundQueue, ^(void) {
- NSMutableURLRequest *request = [NSMutableURLRequest
- requestWithURL:[NSURL URLWithString:turnServerUrl]];
- [request addValue:@"Mozilla/5.0" forHTTPHeaderField:@"user-agent"];
- [request addValue:@"https://apprtc.appspot.com"
- forHTTPHeaderField:@"origin"];
- NSURLResponse *response;
- NSError *error;
- NSData *responseData = [NSURLConnection sendSynchronousRequest:request
- returningResponse:&response
- error:&error];
- if (!error) {
- NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData
- options:0
- error:&error];
- NSAssert(!error, @"Unable to parse. %@", error.localizedDescription);
- NSString *username = json[@"username"];
- NSString *password = json[@"password"];
- NSArray* uris = json[@"uris"];
- for (int i = 0; i < [uris count]; ++i) {
- NSString *turnServer = [uris objectAtIndex:i];
- RTCICEServer *ICEServer =
- [[RTCICEServer alloc] initWithURI:[NSURL URLWithString:turnServer]
- username:username
- password:password];
- NSLog(@"Added ICE Server: %@", ICEServer);
- [ICEServers addObject:ICEServer];
- }
- } else {
- NSLog(@"Unable to get TURN server. Error: %@", error.description);
- }
-
- dispatch_async(dispatch_get_main_queue(), ^(void) {
- [self.ICEServerDelegate onICEServers:ICEServers];
- });
- });
-}
-
-#pragma mark - NSURLConnectionDataDelegate methods
-
-- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
- NSString *roomHtml = [NSString stringWithUTF8String:[data bytes]];
- [self maybeLogMessage:
- [NSString stringWithFormat:@"Received %d chars", [roomHtml length]]];
- [self.roomHtml appendString:roomHtml];
-}
-
-- (void)connection:(NSURLConnection *)connection
- didReceiveResponse:(NSURLResponse *)response {
- NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
- int statusCode = [httpResponse statusCode];
- [self maybeLogMessage:
- [NSString stringWithFormat:
- @"Response received\nURL\n%@\nStatus [%d]\nHeaders\n%@",
- [httpResponse URL],
- statusCode,
- [httpResponse allHeaderFields]]];
- NSAssert(statusCode == 200, @"Invalid response of %d received.", statusCode);
-}
-
-- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
- [self maybeLogMessage:[NSString stringWithFormat:@"finished loading %d chars",
- [self.roomHtml length]]];
- NSRegularExpression* fullRegex =
- [NSRegularExpression regularExpressionWithPattern:@"room is full"
- options:0
- error:nil];
- if ([fullRegex
- numberOfMatchesInString:self.roomHtml
- options:0
- range:NSMakeRange(0, [self.roomHtml length])]) {
- [self showMessage:@"Room full"];
- return;
- }
-
-
- NSString *fullUrl = [[[connection originalRequest] URL] absoluteString];
- NSRange queryRange = [fullUrl rangeOfString:@"?"];
- self.baseURL = [fullUrl substringToIndex:queryRange.location];
- [self maybeLogMessage:
- [NSString stringWithFormat:@"Base URL: %@", self.baseURL]];
-
- self.token = [self findVar:@"channelToken" strippingQuotes:YES];
- if (!self.token)
- return;
- [self maybeLogMessage:[NSString stringWithFormat:@"Token: %@", self.token]];
-
- NSString* roomKey = [self findVar:@"roomKey" strippingQuotes:YES];
- NSString* me = [self findVar:@"me" strippingQuotes:YES];
- if (!roomKey || !me)
- return;
- self.postMessageUrl =
- [NSString stringWithFormat:@"/message?r=%@&u=%@", roomKey, me];
- [self maybeLogMessage:[NSString stringWithFormat:@"POST message URL: %@",
- self.postMessageUrl]];
-
- NSString* pcConfig = [self findVar:@"pcConfig" strippingQuotes:NO];
- if (!pcConfig)
- return;
- [self maybeLogMessage:
- [NSString stringWithFormat:@"PC Config JSON: %@", pcConfig]];
-
- NSString *turnServerUrl = [self findVar:@"turnUrl" strippingQuotes:YES];
- if (turnServerUrl) {
- [self maybeLogMessage:
- [NSString stringWithFormat:@"TURN server request URL: %@",
- turnServerUrl]];
- }
-
- NSError *error;
- NSData *pcData = [pcConfig dataUsingEncoding:NSUTF8StringEncoding];
- NSDictionary *json =
- [NSJSONSerialization JSONObjectWithData:pcData options:0 error:&error];
- NSAssert(!error, @"Unable to parse. %@", error.localizedDescription);
- NSArray *servers = [json objectForKey:@"iceServers"];
- NSMutableArray *ICEServers = [NSMutableArray array];
- for (NSDictionary *server in servers) {
- NSString *url = [server objectForKey:@"url"];
- NSString *username = json[@"username"];
- NSString *credential = [server objectForKey:@"credential"];
- if (!username) {
- username = @"";
- }
- if (!credential) {
- credential = @"";
- }
- [self maybeLogMessage:
- [NSString stringWithFormat:@"url [%@] - credential [%@]",
- url,
- credential]];
- RTCICEServer *ICEServer =
- [[RTCICEServer alloc] initWithURI:[NSURL URLWithString:url]
- username:username
- password:credential];
- NSLog(@"Added ICE Server: %@", ICEServer);
- [ICEServers addObject:ICEServer];
- }
- [self updateICEServers:ICEServers withTurnServer:turnServerUrl];
-
- [self maybeLogMessage:
- [NSString stringWithFormat:@"About to open GAE with token: %@",
- self.token]];
- self.gaeChannel =
- [[GAEChannelClient alloc] initWithToken:self.token
- delegate:self.messageHandler];
-}
-
-@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.m b/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.m
deleted file mode 100644
index 65cdd097944..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.m
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * libjingle
- * Copyright 2013, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "APPRTCAppDelegate.h"
-
-#import "APPRTCViewController.h"
-#import "RTCICECandidate.h"
-#import "RTCICEServer.h"
-#import "RTCMediaConstraints.h"
-#import "RTCMediaStream.h"
-#import "RTCPair.h"
-#import "RTCPeerConnection.h"
-#import "RTCPeerConnectionDelegate.h"
-#import "RTCPeerConnectionFactory.h"
-#import "RTCSessionDescription.h"
-
-@interface PCObserver : NSObject<RTCPeerConnectionDelegate>
-
-- (id)initWithDelegate:(id<APPRTCSendMessage>)delegate;
-
-@end
-
-@implementation PCObserver {
- id<APPRTCSendMessage> _delegate;
-}
-
-- (id)initWithDelegate:(id<APPRTCSendMessage>)delegate {
- if (self = [super init]) {
- _delegate = delegate;
- }
- return self;
-}
-
-- (void)peerConnectionOnError:(RTCPeerConnection *)peerConnection {
- NSLog(@"PCO onError.");
- NSAssert(NO, @"PeerConnection failed.");
-}
-
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- signalingStateChanged:(RTCSignalingState)stateChanged {
- NSLog(@"PCO onSignalingStateChange: %d", stateChanged);
-}
-
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- addedStream:(RTCMediaStream *)stream {
- NSLog(@"PCO onAddStream.");
- dispatch_async(dispatch_get_main_queue(), ^(void) {
- NSAssert([stream.audioTracks count] >= 1,
- @"Expected at least 1 audio stream");
- //NSAssert([stream.videoTracks count] >= 1,
- // @"Expected at least 1 video stream");
- // TODO(hughv): Add video support
- });
-}
-
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- removedStream:(RTCMediaStream *)stream {
- NSLog(@"PCO onRemoveStream.");
- // TODO(hughv): Remove video track.
-}
-
-- (void)
- peerConnectionOnRenegotiationNeeded:(RTCPeerConnection *)peerConnection {
- NSLog(@"PCO onRenegotiationNeeded.");
- // TODO(hughv): Handle this.
-}
-
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- gotICECandidate:(RTCICECandidate *)candidate {
- NSLog(@"PCO onICECandidate.\n Mid[%@] Index[%d] Sdp[%@]",
- candidate.sdpMid,
- candidate.sdpMLineIndex,
- candidate.sdp);
- NSDictionary *json =
- @{ @"type" : @"candidate",
- @"label" : [NSNumber numberWithInt:candidate.sdpMLineIndex],
- @"id" : candidate.sdpMid,
- @"candidate" : candidate.sdp };
- NSError *error;
- NSData *data =
- [NSJSONSerialization dataWithJSONObject:json options:0 error:&error];
- if (!error) {
- [_delegate sendData:data];
- } else {
- NSAssert(NO, @"Unable to serialize JSON object with error: %@",
- error.localizedDescription);
- }
-}
-
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- iceGatheringChanged:(RTCICEGatheringState)newState {
- NSLog(@"PCO onIceGatheringChange. %d", newState);
-}
-
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- iceConnectionChanged:(RTCICEConnectionState)newState {
- NSLog(@"PCO onIceConnectionChange. %d", newState);
- if (newState == RTCICEConnectionConnected)
- [self displayLogMessage:@"ICE Connection Connected."];
- NSAssert(newState != RTCICEConnectionFailed, @"ICE Connection failed!");
-}
-
-- (void)displayLogMessage:(NSString *)message {
- [_delegate displayLogMessage:message];
-}
-
-@end
-
-@interface APPRTCAppDelegate ()
-
-@property(nonatomic, strong) APPRTCAppClient *client;
-@property(nonatomic, strong) PCObserver *pcObserver;
-@property(nonatomic, strong) RTCPeerConnection *peerConnection;
-@property(nonatomic, strong) RTCPeerConnectionFactory *peerConnectionFactory;
-@property(nonatomic, strong) NSMutableArray *queuedRemoteCandidates;
-
-@end
-
-@implementation APPRTCAppDelegate
-
-@synthesize window = _window;
-@synthesize viewController = _viewController;
-@synthesize client = _client;
-@synthesize pcObserver = _pcObserver;
-@synthesize peerConnection = _peerConnection;
-@synthesize peerConnectionFactory = _peerConnectionFactory;
-@synthesize queuedRemoteCandidates = _queuedRemoteCandidates;
-
-#pragma mark - UIApplicationDelegate methods
-
-- (BOOL)application:(UIApplication *)application
- didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- [RTCPeerConnectionFactory initializeSSL];
- self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- self.viewController =
- [[APPRTCViewController alloc] initWithNibName:@"APPRTCViewController"
- bundle:nil];
- self.window.rootViewController = self.viewController;
- [self.window makeKeyAndVisible];
- return YES;
-}
-
-- (void)applicationWillResignActive:(UIApplication *)application {
- [self displayLogMessage:@"Application lost focus, connection broken."];
- [self disconnect];
- [self.viewController resetUI];
-}
-
-- (void)applicationDidEnterBackground:(UIApplication *)application {
-}
-
-- (void)applicationWillEnterForeground:(UIApplication *)application {
-}
-
-- (void)applicationDidBecomeActive:(UIApplication *)application {
-}
-
-- (void)applicationWillTerminate:(UIApplication *)application {
-}
-
-- (BOOL)application:(UIApplication *)application
- openURL:(NSURL *)url
- sourceApplication:(NSString *)sourceApplication
- annotation:(id)annotation {
- if (self.client) {
- return NO;
- }
- self.client = [[APPRTCAppClient alloc] init];
- self.client.ICEServerDelegate = self;
- self.client.messageHandler = self;
- [self.client connectToRoom:url];
- return YES;
-}
-
-- (void)displayLogMessage:(NSString *)message {
- NSLog(@"%@", message);
- [self.viewController displayText:message];
-}
-
-#pragma mark - RTCSendMessage method
-
-- (void)sendData:(NSData *)data {
- [self.client sendData:data];
-}
-
-#pragma mark - ICEServerDelegate method
-
-- (void)onICEServers:(NSArray *)servers {
- self.queuedRemoteCandidates = [NSMutableArray array];
- self.peerConnectionFactory = [[RTCPeerConnectionFactory alloc] init];
- RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] init];
- self.pcObserver = [[PCObserver alloc] initWithDelegate:self];
- self.peerConnection =
- [self.peerConnectionFactory peerConnectionWithICEServers:servers
- constraints:constraints
- delegate:self.pcObserver];
- RTCMediaStream *lms =
- [self.peerConnectionFactory mediaStreamWithLabel:@"ARDAMS"];
- // TODO(hughv): Add video.
- [lms addAudioTrack:[self.peerConnectionFactory audioTrackWithID:@"ARDAMSa0"]];
- [self.peerConnection addStream:lms constraints:constraints];
- [self displayLogMessage:@"onICEServers - add local stream."];
-}
-
-#pragma mark - GAEMessageHandler methods
-
-- (void)onOpen {
- [self displayLogMessage:@"GAE onOpen - create offer."];
- RTCPair *audio =
- [[RTCPair alloc] initWithKey:@"OfferToReceiveAudio" value:@"true"];
- // TODO(hughv): Add video.
- // RTCPair *video = [[RTCPair alloc] initWithKey:@"OfferToReceiveVideo"
- // value:@"true"];
- NSArray *mandatory = @[ audio /*, video*/ ];
- RTCMediaConstraints *constraints =
- [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatory
- optionalConstraints:nil];
- [self.peerConnection createOfferWithDelegate:self constraints:constraints];
- [self displayLogMessage:@"PC - createOffer."];
-}
-
-- (void)onMessage:(NSString *)data {
- NSString *message = [self unHTMLifyString:data];
- NSError *error;
- NSDictionary *objects = [NSJSONSerialization
- JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding]
- options:0
- error:&error];
- NSAssert(!error,
- @"%@",
- [NSString stringWithFormat:@"Error: %@", error.description]);
- NSAssert([objects count] > 0, @"Invalid JSON object");
- NSString *value = [objects objectForKey:@"type"];
- [self displayLogMessage:
- [NSString stringWithFormat:@"GAE onMessage type - %@", value]];
- if ([value compare:@"candidate"] == NSOrderedSame) {
- NSString *mid = [objects objectForKey:@"id"];
- NSNumber *sdpLineIndex = [objects objectForKey:@"label"];
- NSString *sdp = [objects objectForKey:@"candidate"];
- RTCICECandidate *candidate =
- [[RTCICECandidate alloc] initWithMid:mid
- index:sdpLineIndex.intValue
- sdp:sdp];
- if (self.queuedRemoteCandidates) {
- [self.queuedRemoteCandidates addObject:candidate];
- } else {
- [self.peerConnection addICECandidate:candidate];
- }
- } else if (([value compare:@"offer"] == NSOrderedSame) ||
- ([value compare:@"answer"] == NSOrderedSame)) {
- NSString *sdpString = [objects objectForKey:@"sdp"];
- RTCSessionDescription *sdp = [[RTCSessionDescription alloc]
- initWithType:value sdp:[APPRTCAppDelegate preferISAC:sdpString]];
- [self.peerConnection setRemoteDescriptionWithDelegate:self
- sessionDescription:sdp];
- [self displayLogMessage:@"PC - setRemoteDescription."];
- } else if ([value compare:@"bye"] == NSOrderedSame) {
- [self disconnect];
- } else {
- NSAssert(NO, @"Invalid message: %@", data);
- }
-}
-
-- (void)onClose {
- [self displayLogMessage:@"GAE onClose."];
- [self disconnect];
-}
-
-- (void)onError:(int)code withDescription:(NSString *)description {
- [self displayLogMessage:
- [NSString stringWithFormat:@"GAE onError: %@", description]];
- [self disconnect];
-}
-
-#pragma mark - RTCSessionDescriptonDelegate methods
-
-// Match |pattern| to |string| and return the first group of the first
-// match, or nil if no match was found.
-+ (NSString *)firstMatch:(NSRegularExpression *)pattern
- withString:(NSString *)string {
- NSTextCheckingResult* result =
- [pattern firstMatchInString:string
- options:0
- range:NSMakeRange(0, [string length])];
- if (!result)
- return nil;
- return [string substringWithRange:[result rangeAtIndex:1]];
-}
-
-// Mangle |origSDP| to prefer the ISAC/16k audio codec.
-+ (NSString *)preferISAC:(NSString *)origSDP {
- int mLineIndex = -1;
- NSString* isac16kRtpMap = nil;
- NSArray* lines = [origSDP componentsSeparatedByString:@"\n"];
- NSRegularExpression* isac16kRegex = [NSRegularExpression
- regularExpressionWithPattern:@"^a=rtpmap:(\\d+) ISAC/16000[\r]?$"
- options:0
- error:nil];
- for (int i = 0;
- (i < [lines count]) && (mLineIndex == -1 || isac16kRtpMap == nil);
- ++i) {
- NSString* line = [lines objectAtIndex:i];
- if ([line hasPrefix:@"m=audio "]) {
- mLineIndex = i;
- continue;
- }
- isac16kRtpMap = [self firstMatch:isac16kRegex withString:line];
- }
- if (mLineIndex == -1) {
- NSLog(@"No m=audio line, so can't prefer iSAC");
- return origSDP;
- }
- if (isac16kRtpMap == nil) {
- NSLog(@"No ISAC/16000 line, so can't prefer iSAC");
- return origSDP;
- }
- NSArray* origMLineParts =
- [[lines objectAtIndex:mLineIndex] componentsSeparatedByString:@" "];
- NSMutableArray* newMLine =
- [NSMutableArray arrayWithCapacity:[origMLineParts count]];
- int origPartIndex = 0;
- // Format is: m=<media> <port> <proto> <fmt> ...
- [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
- [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
- [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
- [newMLine addObject:isac16kRtpMap];
- for (; origPartIndex < [origMLineParts count]; ++origPartIndex) {
- if ([isac16kRtpMap compare:[origMLineParts objectAtIndex:origPartIndex]]
- != NSOrderedSame) {
- [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex]];
- }
- }
- NSMutableArray* newLines = [NSMutableArray arrayWithCapacity:[lines count]];
- [newLines addObjectsFromArray:lines];
- [newLines replaceObjectAtIndex:mLineIndex
- withObject:[newMLine componentsJoinedByString:@" "]];
- return [newLines componentsJoinedByString:@"\n"];
-}
-
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- didCreateSessionDescription:(RTCSessionDescription *)origSdp
- error:(NSError *)error {
- if (error) {
- [self displayLogMessage:@"SDP onFailure."];
- NSAssert(NO, error.description);
- return;
- }
-
- [self displayLogMessage:@"SDP onSuccess(SDP) - set local description."];
- RTCSessionDescription* sdp =
- [[RTCSessionDescription alloc]
- initWithType:origSdp.type
- sdp:[APPRTCAppDelegate preferISAC:origSdp.description]];
- [self.peerConnection setLocalDescriptionWithDelegate:self
- sessionDescription:sdp];
- [self displayLogMessage:@"PC setLocalDescription."];
- dispatch_async(dispatch_get_main_queue(), ^(void) {
- NSDictionary *json = @{ @"type" : sdp.type, @"sdp" : sdp.description };
- NSError *error;
- NSData *data =
- [NSJSONSerialization dataWithJSONObject:json options:0 error:&error];
- NSAssert(!error,
- @"%@",
- [NSString stringWithFormat:@"Error: %@", error.description]);
- [self sendData:data];
- });
-}
-
-- (void)peerConnection:(RTCPeerConnection *)peerConnection
- didSetSessionDescriptionWithError:(NSError *)error {
- if (error) {
- [self displayLogMessage:@"SDP onFailure."];
- NSAssert(NO, error.description);
- return;
- }
-
- [self displayLogMessage:@"SDP onSuccess() - possibly drain candidates"];
- dispatch_async(dispatch_get_main_queue(), ^(void) {
- // TODO(hughv): Handle non-initiator case. http://s10/46622051
- if (self.peerConnection.remoteDescription) {
- [self displayLogMessage:@"SDP onSuccess - drain candidates"];
- [self drainRemoteCandidates];
- }
- });
-}
-
-#pragma mark - internal methods
-
-- (void)disconnect {
- [self.client
- sendData:[@"{\"type\": \"bye\"}" dataUsingEncoding:NSUTF8StringEncoding]];
- self.peerConnection = nil;
- self.peerConnectionFactory = nil;
- self.pcObserver = nil;
- self.client.ICEServerDelegate = nil;
- self.client.messageHandler = nil;
- self.client = nil;
- [RTCPeerConnectionFactory deinitializeSSL];
-}
-
-- (void)drainRemoteCandidates {
- for (RTCICECandidate *candidate in self.queuedRemoteCandidates) {
- [self.peerConnection addICECandidate:candidate];
- }
- self.queuedRemoteCandidates = nil;
-}
-
-- (NSString *)unHTMLifyString:(NSString *)base {
- // TODO(hughv): Investigate why percent escapes are being added. Removing
- // them isn't necessary on Android.
- // convert HTML escaped characters to UTF8.
- NSString *removePercent =
- [base stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- // remove leading and trailing ".
- NSRange range;
- range.length = [removePercent length] - 2;
- range.location = 1;
- NSString *removeQuotes = [removePercent substringWithRange:range];
- // convert \" to ".
- NSString *removeEscapedQuotes =
- [removeQuotes stringByReplacingOccurrencesOfString:@"\\\""
- withString:@"\""];
- // convert \\ to \.
- NSString *removeBackslash =
- [removeEscapedQuotes stringByReplacingOccurrencesOfString:@"\\\\"
- withString:@"\\"];
- return removeBackslash;
-}
-
-@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCViewController.m b/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCViewController.m
deleted file mode 100644
index bd346efcd3a..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCViewController.m
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * libjingle
- * Copyright 2013, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "APPRTCViewController.h"
-
-@interface APPRTCViewController ()
-
-@end
-
-@implementation APPRTCViewController
-
-@synthesize textField = _textField;
-@synthesize textInstructions = _textInstructions;
-@synthesize textOutput = _textOutput;
-
-- (void)viewDidLoad {
- [super viewDidLoad];
- self.textField.delegate = self;
- [self.textField becomeFirstResponder];
-}
-
-- (void)displayText:(NSString *)text {
- dispatch_async(dispatch_get_main_queue(), ^(void) {
- NSString *output =
- [NSString stringWithFormat:@"%@\n%@", self.textOutput.text, text];
- self.textOutput.text = output;
- });
-}
-
-- (void)resetUI {
- self.textField.text = nil;
- self.textField.hidden = NO;
- self.textInstructions.hidden = NO;
- self.textOutput.hidden = YES;
- self.textOutput.text = nil;
-}
-
-#pragma mark - UITextFieldDelegate
-
-- (void)textFieldDidEndEditing:(UITextField *)textField {
- NSString *room = textField.text;
- if ([room length] == 0) {
- return;
- }
- textField.hidden = YES;
- self.textInstructions.hidden = YES;
- self.textOutput.hidden = NO;
- // TODO(hughv): Instead of launching a URL with apprtc scheme, change to
- // prepopulating the textField with a valid URL missing the room. This allows
- // the user to have the simplicity of just entering the room or the ability to
- // override to a custom appspot instance. Remove apprtc:// when this is done.
- NSString *url =
- [NSString stringWithFormat:@"apprtc://apprtc.appspot.com/?r=%@", room];
- [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
-}
-
-- (BOOL)textFieldShouldReturn:(UITextField *)textField {
- // There is no other control that can take focus, so manually resign focus
- // when return (Join) is pressed to trigger |textFieldDidEndEditing|.
- [textField resignFirstResponder];
- return YES;
-}
-
-@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/GAEChannelClient.m b/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/GAEChannelClient.m
deleted file mode 100644
index e0d9a807692..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/GAEChannelClient.m
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * libjingle
- * Copyright 2013, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "GAEChannelClient.h"
-
-#import "RTCPeerConnectionFactory.h"
-
-@interface GAEChannelClient ()
-
-@property(nonatomic, assign) id<GAEMessageHandler> delegate;
-@property(nonatomic, strong) UIWebView *webView;
-
-@end
-
-@implementation GAEChannelClient
-
-@synthesize delegate = _delegate;
-@synthesize webView = _webView;
-
-- (id)initWithToken:(NSString *)token delegate:(id<GAEMessageHandler>)delegate {
- self = [super init];
- if (self) {
- _webView = [[UIWebView alloc] init];
- _webView.delegate = self;
- _delegate = delegate;
- NSString *htmlPath =
- [[NSBundle mainBundle] pathForResource:@"ios_channel" ofType:@"html"];
- NSURL *htmlUrl = [NSURL fileURLWithPath:htmlPath];
- NSString *path = [NSString stringWithFormat:@"%@?token=%@",
- [htmlUrl absoluteString],
- token];
-
- [_webView
- loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:path]]];
- }
- return self;
-}
-
-- (void)dealloc {
- _webView.delegate = nil;
- [_webView stopLoading];
-}
-
-#pragma mark - UIWebViewDelegate method
-
-- (BOOL)webView:(UIWebView *)webView
- shouldStartLoadWithRequest:(NSURLRequest *)request
- navigationType:(UIWebViewNavigationType)navigationType {
- NSString *scheme = [request.URL scheme];
- if ([scheme compare:@"js-frame"] != NSOrderedSame) {
- return YES;
- }
- NSString *resourceSpecifier = [request.URL resourceSpecifier];
- NSRange range = [resourceSpecifier rangeOfString:@":"];
- NSString *method;
- NSString *message;
- if (range.length == 0 && range.location == NSNotFound) {
- method = resourceSpecifier;
- } else {
- method = [resourceSpecifier substringToIndex:range.location];
- message = [resourceSpecifier substringFromIndex:range.location + 1];
- }
- dispatch_async(dispatch_get_main_queue(), ^(void) {
- if ([method compare:@"onopen"] == NSOrderedSame) {
- [self.delegate onOpen];
- } else if ([method compare:@"onmessage"] == NSOrderedSame) {
- [self.delegate onMessage:message];
- } else if ([method compare:@"onclose"] == NSOrderedSame) {
- [self.delegate onClose];
- } else if ([method compare:@"onerror"] == NSOrderedSame) {
- // TODO(hughv): Get error.
- int code = -1;
- NSString *description = message;
- [self.delegate onError:code withDescription:description];
- } else {
- NSAssert(NO, @"Invalid message sent from UIWebView: %@",
- resourceSpecifier);
- }
- });
- return YES;
-}
-
-@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/README b/chromium/third_party/libjingle/source/talk/examples/ios/README
deleted file mode 100644
index 9c0d134171a..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/ios/README
+++ /dev/null
@@ -1,3 +0,0 @@
-This directory contains an example iOS client for http://apprtc.appspot.com
-
-See ../../app/webrtc/objc/README for information on how to use it.
diff --git a/chromium/third_party/libjingle/source/talk/examples/login/login_main.cc b/chromium/third_party/libjingle/source/talk/examples/login/login_main.cc
index 55bb893ad49..5c5d1d78387 100644
--- a/chromium/third_party/libjingle/source/talk/examples/login/login_main.cc
+++ b/chromium/third_party/libjingle/source/talk/examples/login/login_main.cc
@@ -25,7 +25,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <cstdio>
+#include <stdio.h>
+
#include <iostream>
#include "talk/base/thread.h"
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppClient.h b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCAppClient.h
index c737beaa99a..8b21db58586 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppClient.h
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCAppClient.h
@@ -29,13 +29,18 @@
#import "GAEChannelClient.h"
-// Called when there are RTCICEServers.
-@protocol ICEServerDelegate<NSObject>
+@class APPRTCAppClient;
+@protocol APPRTCAppClientDelegate
-- (void)onICEServers:(NSArray*)servers;
+- (void)appClient:(APPRTCAppClient*)appClient
+ didErrorWithMessage:(NSString*)message;
+- (void)appClient:(APPRTCAppClient*)appClient
+ didReceiveICEServers:(NSArray*)servers;
@end
+@class RTCMediaConstraints;
+
// Negotiates signaling for chatting with apprtc.appspot.com "rooms".
// Uses the client<->server specifics of the apprtc AppEngine webapp.
//
@@ -43,12 +48,21 @@
// call connectToRoom(). apprtc.appspot.com will signal that is successful via
// onOpen through the browser channel. Then you should call sendData() and wait
// for the registered handler to be called with received messages.
-@interface APPRTCAppClient : NSObject<NSURLConnectionDataDelegate>
+@interface APPRTCAppClient : NSObject
+
+@property(nonatomic) BOOL initiator;
+@property(nonatomic, copy, readonly) RTCMediaConstraints* videoConstraints;
+@property(nonatomic, weak) id<APPRTCAppClientDelegate> delegate;
-@property(nonatomic, assign) id<ICEServerDelegate> ICEServerDelegate;
-@property(nonatomic, assign) id<GAEMessageHandler> messageHandler;
+- (instancetype)initWithDelegate:(id<APPRTCAppClientDelegate>)delegate
+ messageHandler:(id<GAEMessageHandler>)handler;
+- (void)connectToRoom:(NSURL*)room;
+- (void)sendData:(NSData*)data;
-- (void)connectToRoom:(NSURL *)room;
-- (void)sendData:(NSData *)data;
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+// Disallow init and don't add to documentation
+- (instancetype)init __attribute__((
+ unavailable("init is not a supported initializer for this class.")));
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCAppClient.m b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCAppClient.m
new file mode 100644
index 00000000000..853496f81b5
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCAppClient.m
@@ -0,0 +1,320 @@
+/*
+ * libjingle
+ * Copyright 2013, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "APPRTCAppClient.h"
+
+#import <dispatch/dispatch.h>
+
+#import "GAEChannelClient.h"
+#import "RTCICEServer.h"
+#import "RTCMediaConstraints.h"
+#import "RTCPair.h"
+
+@implementation APPRTCAppClient {
+ dispatch_queue_t _backgroundQueue;
+ GAEChannelClient* _gaeChannel;
+ NSURL* _postMessageURL;
+ BOOL _verboseLogging;
+ __weak id<GAEMessageHandler> _messageHandler;
+}
+
+- (instancetype)initWithDelegate:(id<APPRTCAppClientDelegate>)delegate
+ messageHandler:(id<GAEMessageHandler>)handler {
+ if (self = [super init]) {
+ _delegate = delegate;
+ _messageHandler = handler;
+ _backgroundQueue = dispatch_queue_create("RTCBackgroundQueue",
+ DISPATCH_QUEUE_SERIAL);
+ // Uncomment to see Request/Response logging.
+ // _verboseLogging = YES;
+ }
+ return self;
+}
+
+- (void)connectToRoom:(NSURL*)url {
+ NSString* urlString =
+ [[url absoluteString] stringByAppendingString:@"&t=json"];
+ NSURL* requestURL = [NSURL URLWithString:urlString];
+ NSURLRequest* request = [NSURLRequest requestWithURL:requestURL];
+ [self sendURLRequest:request
+ completionHandler:^(NSError* error,
+ NSHTTPURLResponse* httpResponse,
+ NSData* responseData) {
+ int statusCode = [httpResponse statusCode];
+ [self logVerbose:[NSString stringWithFormat:
+ @"Response received\nURL\n%@\nStatus [%d]\nHeaders\n%@",
+ [httpResponse URL],
+ statusCode,
+ [httpResponse allHeaderFields]]];
+ NSAssert(statusCode == 200,
+ @"Invalid response of %d received while connecting to: %@",
+ statusCode,
+ urlString);
+ if (statusCode != 200) {
+ return;
+ }
+ [self handleResponseData:responseData
+ forRoomRequest:request];
+ }];
+}
+
+- (void)sendData:(NSData*)data {
+ NSParameterAssert([data length] > 0);
+ NSString* message = [NSString stringWithUTF8String:[data bytes]];
+ [self logVerbose:[NSString stringWithFormat:@"Send message:\n%@", message]];
+ if (!_postMessageURL) {
+ return;
+ }
+ NSMutableURLRequest* request =
+ [NSMutableURLRequest requestWithURL:_postMessageURL];
+ request.HTTPMethod = @"POST";
+ [request setHTTPBody:data];
+ [self sendURLRequest:request
+ completionHandler:^(NSError* error,
+ NSHTTPURLResponse* httpResponse,
+ NSData* responseData) {
+ int status = [httpResponse statusCode];
+ NSString* response = [responseData length] > 0 ?
+ [NSString stringWithUTF8String:[responseData bytes]] :
+ nil;
+ NSAssert(status == 200,
+ @"Bad response [%d] to message: %@\n\n%@",
+ status,
+ message,
+ response);
+ }];
+}
+
+#pragma mark - Private
+
+- (void)logVerbose:(NSString*)message {
+ if (_verboseLogging) {
+ NSLog(@"%@", message);
+ }
+}
+
+- (void)handleResponseData:(NSData*)responseData
+ forRoomRequest:(NSURLRequest*)request {
+ NSDictionary* roomJSON = [self parseJSONData:responseData];
+ [self logVerbose:[NSString stringWithFormat:@"Room JSON:\n%@", roomJSON]];
+ NSParameterAssert(roomJSON);
+ if (roomJSON[@"error"]) {
+ NSArray* errorMessages = roomJSON[@"error_messages"];
+ NSMutableString* message = [NSMutableString string];
+ for (NSString* errorMessage in errorMessages) {
+ [message appendFormat:@"%@\n", errorMessage];
+ }
+ [self.delegate appClient:self didErrorWithMessage:message];
+ return;
+ }
+ NSString* pcConfig = roomJSON[@"pc_config"];
+ NSData* pcConfigData = [pcConfig dataUsingEncoding:NSUTF8StringEncoding];
+ NSDictionary* pcConfigJSON = [self parseJSONData:pcConfigData];
+ [self logVerbose:[NSString stringWithFormat:@"PCConfig JSON:\n%@",
+ pcConfigJSON]];
+ NSParameterAssert(pcConfigJSON);
+
+ NSArray* iceServers = [self parseICEServersForPCConfigJSON:pcConfigJSON];
+ [self requestTURNServerForICEServers:iceServers
+ turnServerUrl:roomJSON[@"turn_url"]];
+
+ _initiator = [roomJSON[@"initiator"] boolValue];
+ [self logVerbose:[NSString stringWithFormat:@"Initiator: %d", _initiator]];
+ _postMessageURL = [self parsePostMessageURLForRoomJSON:roomJSON
+ request:request];
+ [self logVerbose:[NSString stringWithFormat:@"POST message URL:\n%@",
+ _postMessageURL]];
+ _videoConstraints = [self parseVideoConstraintsForRoomJSON:roomJSON];
+ [self logVerbose:[NSString stringWithFormat:@"Media constraints:\n%@",
+ _videoConstraints]];
+ NSString* token = roomJSON[@"token"];
+ [self logVerbose:
+ [NSString stringWithFormat:@"About to open GAE with token: %@",
+ token]];
+ _gaeChannel =
+ [[GAEChannelClient alloc] initWithToken:token
+ delegate:_messageHandler];
+}
+
+- (NSDictionary*)parseJSONData:(NSData*)data {
+ NSError* error = nil;
+ NSDictionary* json =
+ [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
+ NSAssert(!error, @"Unable to parse. %@", error.localizedDescription);
+ return json;
+}
+
+- (NSArray*)parseICEServersForPCConfigJSON:(NSDictionary*)pcConfigJSON {
+ NSMutableArray* result = [NSMutableArray array];
+ NSArray* iceServers = pcConfigJSON[@"iceServers"];
+ for (NSDictionary* iceServer in iceServers) {
+ NSString* url = iceServer[@"urls"];
+ NSString* username = pcConfigJSON[@"username"];
+ NSString* credential = iceServer[@"credential"];
+ username = username ? username : @"";
+ credential = credential ? credential : @"";
+ [self logVerbose:[NSString stringWithFormat:@"url [%@] - credential [%@]",
+ url,
+ credential]];
+ RTCICEServer* server =
+ [[RTCICEServer alloc] initWithURI:[NSURL URLWithString:url]
+ username:username
+ password:credential];
+ [result addObject:server];
+ }
+ return result;
+}
+
+- (NSURL*)parsePostMessageURLForRoomJSON:(NSDictionary*)roomJSON
+ request:(NSURLRequest*)request {
+ NSString* requestUrl = [[request URL] absoluteString];
+ NSRange queryRange = [requestUrl rangeOfString:@"?"];
+ NSString* baseUrl = [requestUrl substringToIndex:queryRange.location];
+ NSString* roomKey = roomJSON[@"room_key"];
+ NSParameterAssert([roomKey length] > 0);
+ NSString* me = roomJSON[@"me"];
+ NSParameterAssert([me length] > 0);
+ NSString* postMessageUrl =
+ [NSString stringWithFormat:@"%@/message?r=%@&u=%@", baseUrl, roomKey, me];
+ return [NSURL URLWithString:postMessageUrl];
+}
+
+- (RTCMediaConstraints*)parseVideoConstraintsForRoomJSON:
+ (NSDictionary*)roomJSON {
+ NSString* mediaConstraints = roomJSON[@"media_constraints"];
+ RTCMediaConstraints* constraints = nil;
+ if ([mediaConstraints length] > 0) {
+ NSData* constraintsData =
+ [mediaConstraints dataUsingEncoding:NSUTF8StringEncoding];
+ NSDictionary* constraintsJSON = [self parseJSONData:constraintsData];
+ id video = constraintsJSON[@"video"];
+ if ([video isKindOfClass:[NSDictionary class]]) {
+ NSDictionary* mandatory = video[@"mandatory"];
+ NSMutableArray* mandatoryContraints =
+ [NSMutableArray arrayWithCapacity:[mandatory count]];
+ [mandatory enumerateKeysAndObjectsUsingBlock:^(
+ id key, id obj, BOOL* stop) {
+ [mandatoryContraints addObject:[[RTCPair alloc] initWithKey:key
+ value:obj]];
+ }];
+ // TODO(tkchin): figure out json formats for optional constraints.
+ constraints =
+ [[RTCMediaConstraints alloc]
+ initWithMandatoryConstraints:mandatoryContraints
+ optionalConstraints:nil];
+ } else if ([video isKindOfClass:[NSNumber class]] && [video boolValue]) {
+ constraints = [[RTCMediaConstraints alloc] init];
+ }
+ }
+ return constraints;
+}
+
+- (void)requestTURNServerWithUrl:(NSString*)turnServerUrl
+ completionHandler:
+ (void (^)(RTCICEServer* turnServer))completionHandler {
+ NSURL* turnServerURL = [NSURL URLWithString:turnServerUrl];
+ NSMutableURLRequest* request =
+ [NSMutableURLRequest requestWithURL:turnServerURL];
+ [request addValue:@"Mozilla/5.0" forHTTPHeaderField:@"user-agent"];
+ [request addValue:@"https://apprtc.appspot.com"
+ forHTTPHeaderField:@"origin"];
+ [self sendURLRequest:request
+ completionHandler:^(NSError* error,
+ NSHTTPURLResponse* response,
+ NSData* responseData) {
+ if (error) {
+ NSLog(@"Unable to get TURN server.");
+ completionHandler(nil);
+ return;
+ }
+ NSDictionary* json = [self parseJSONData:responseData];
+ NSString* username = json[@"username"];
+ NSString* password = json[@"password"];
+ NSArray* uris = json[@"uris"];
+ NSParameterAssert([uris count] > 0);
+ RTCICEServer* turnServer =
+ [[RTCICEServer alloc] initWithURI:[NSURL URLWithString:uris[0]]
+ username:username
+ password:password];
+ completionHandler(turnServer);
+ }];
+}
+
+- (void)requestTURNServerForICEServers:(NSArray*)iceServers
+ turnServerUrl:(NSString*)turnServerUrl {
+ BOOL isTurnPresent = NO;
+ for (RTCICEServer* iceServer in iceServers) {
+ if ([[iceServer.URI scheme] isEqualToString:@"turn"]) {
+ isTurnPresent = YES;
+ break;
+ }
+ }
+ if (!isTurnPresent) {
+ [self requestTURNServerWithUrl:turnServerUrl
+ completionHandler:^(RTCICEServer* turnServer) {
+ NSArray* servers = iceServers;
+ if (turnServer) {
+ servers = [servers arrayByAddingObject:turnServer];
+ }
+ NSLog(@"ICE servers:\n%@", servers);
+ [self.delegate appClient:self didReceiveICEServers:servers];
+ }];
+ } else {
+ NSLog(@"ICE servers:\n%@", iceServers);
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self.delegate appClient:self didReceiveICEServers:iceServers];
+ });
+ }
+}
+
+- (void)sendURLRequest:(NSURLRequest*)request
+ completionHandler:(void (^)(NSError* error,
+ NSHTTPURLResponse* httpResponse,
+ NSData* responseData))completionHandler {
+ dispatch_async(_backgroundQueue, ^{
+ NSError* error = nil;
+ NSURLResponse* response = nil;
+ NSData* responseData = [NSURLConnection sendSynchronousRequest:request
+ returningResponse:&response
+ error:&error];
+ NSParameterAssert(!response ||
+ [response isKindOfClass:[NSHTTPURLResponse class]]);
+ if (error) {
+ NSLog(@"Failed URL request for:%@\nError:%@", request, error);
+ }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
+ completionHandler(error, httpResponse, responseData);
+ });
+ });
+}
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCConnectionManager.h b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCConnectionManager.h
new file mode 100644
index 00000000000..98fe755ef63
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCConnectionManager.h
@@ -0,0 +1,66 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Foundation/Foundation.h>
+
+// Used to log messages to destination like UI.
+@protocol APPRTCLogger<NSObject>
+- (void)logMessage:(NSString*)message;
+@end
+
+@class RTCVideoTrack;
+@class APPRTCConnectionManager;
+
+// Used to provide AppRTC connection information.
+@protocol APPRTCConnectionManagerDelegate<NSObject>
+
+- (void)connectionManager:(APPRTCConnectionManager*)manager
+ didReceiveLocalVideoTrack:(RTCVideoTrack*)localVideoTrack;
+
+- (void)connectionManager:(APPRTCConnectionManager*)manager
+ didReceiveRemoteVideoTrack:(RTCVideoTrack*)remoteVideoTrack;
+
+- (void)connectionManagerDidReceiveHangup:(APPRTCConnectionManager*)manager;
+
+- (void)connectionManager:(APPRTCConnectionManager*)manager
+ didErrorWithMessage:(NSString*)errorMessage;
+
+@end
+
+// Abstracts the network connection aspect of AppRTC. The delegate will receive
+// information about connection status as changes occur.
+@interface APPRTCConnectionManager : NSObject
+
+@property(nonatomic, weak) id<APPRTCConnectionManagerDelegate> delegate;
+@property(nonatomic, weak) id<APPRTCLogger> logger;
+
+- (instancetype)initWithDelegate:(id<APPRTCConnectionManagerDelegate>)delegate
+ logger:(id<APPRTCLogger>)logger;
+- (BOOL)connectToRoomWithURL:(NSURL*)url;
+- (void)disconnect;
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCConnectionManager.m b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCConnectionManager.m
new file mode 100644
index 00000000000..b411a621544
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/APPRTCConnectionManager.m
@@ -0,0 +1,495 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "APPRTCConnectionManager.h"
+
+#import <AVFoundation/AVFoundation.h>
+#import "APPRTCAppClient.h"
+#import "GAEChannelClient.h"
+#import "RTCICECandidate.h"
+#import "RTCMediaConstraints.h"
+#import "RTCMediaStream.h"
+#import "RTCPair.h"
+#import "RTCPeerConnection.h"
+#import "RTCPeerConnectionDelegate.h"
+#import "RTCPeerConnectionFactory.h"
+#import "RTCSessionDescription.h"
+#import "RTCSessionDescriptionDelegate.h"
+#import "RTCStatsDelegate.h"
+#import "RTCVideoCapturer.h"
+#import "RTCVideoSource.h"
+
+@interface APPRTCConnectionManager ()
+ <APPRTCAppClientDelegate, GAEMessageHandler, RTCPeerConnectionDelegate,
+ RTCSessionDescriptionDelegate, RTCStatsDelegate>
+
+@property(nonatomic, strong) APPRTCAppClient* client;
+@property(nonatomic, strong) RTCPeerConnection* peerConnection;
+@property(nonatomic, strong) RTCPeerConnectionFactory* peerConnectionFactory;
+@property(nonatomic, strong) RTCVideoSource* videoSource;
+@property(nonatomic, strong) NSMutableArray* queuedRemoteCandidates;
+
+@end
+
+@implementation APPRTCConnectionManager {
+ NSTimer* _statsTimer;
+}
+
+- (instancetype)initWithDelegate:(id<APPRTCConnectionManagerDelegate>)delegate
+ logger:(id<APPRTCLogger>)logger {
+ if (self = [super init]) {
+ self.delegate = delegate;
+ self.logger = logger;
+ self.peerConnectionFactory = [[RTCPeerConnectionFactory alloc] init];
+ // TODO(tkchin): turn this into a button.
+ // Uncomment for stat logs.
+ // _statsTimer =
+ // [NSTimer scheduledTimerWithTimeInterval:10
+ // target:self
+ // selector:@selector(didFireStatsTimer:)
+ // userInfo:nil
+ // repeats:YES];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self disconnect];
+}
+
+- (BOOL)connectToRoomWithURL:(NSURL*)url {
+ if (self.client) {
+ // Already have a connection.
+ return NO;
+ }
+ self.client = [[APPRTCAppClient alloc] initWithDelegate:self
+ messageHandler:self];
+ [self.client connectToRoom:url];
+ return YES;
+}
+
+- (void)disconnect {
+ if (!self.client) {
+ return;
+ }
+ [self.client
+ sendData:[@"{\"type\": \"bye\"}" dataUsingEncoding:NSUTF8StringEncoding]];
+ [self.peerConnection close];
+ self.peerConnection = nil;
+ self.client = nil;
+ self.videoSource = nil;
+ self.queuedRemoteCandidates = nil;
+}
+
+#pragma mark - APPRTCAppClientDelegate
+
+- (void)appClient:(APPRTCAppClient*)appClient
+ didErrorWithMessage:(NSString*)message {
+ [self.delegate connectionManager:self
+ didErrorWithMessage:message];
+}
+
+- (void)appClient:(APPRTCAppClient*)appClient
+ didReceiveICEServers:(NSArray*)servers {
+ self.queuedRemoteCandidates = [NSMutableArray array];
+ RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc]
+ initWithMandatoryConstraints:
+ @[
+ [[RTCPair alloc] initWithKey:@"OfferToReceiveAudio" value:@"true"],
+ [[RTCPair alloc] initWithKey:@"OfferToReceiveVideo" value:@"true"]
+ ]
+ optionalConstraints:
+ @[
+ [[RTCPair alloc] initWithKey:@"internalSctpDataChannels"
+ value:@"true"],
+ [[RTCPair alloc] initWithKey:@"DtlsSrtpKeyAgreement"
+ value:@"true"]
+ ]];
+ self.peerConnection =
+ [self.peerConnectionFactory peerConnectionWithICEServers:servers
+ constraints:constraints
+ delegate:self];
+ RTCMediaStream* lms =
+ [self.peerConnectionFactory mediaStreamWithLabel:@"ARDAMS"];
+
+ // The iOS simulator doesn't provide any sort of camera capture
+ // support or emulation (http://goo.gl/rHAnC1) so don't bother
+ // trying to open a local stream.
+ RTCVideoTrack* localVideoTrack;
+
+ // TODO(tkchin): local video capture for OSX. See
+ // https://code.google.com/p/webrtc/issues/detail?id=3417.
+#if !TARGET_IPHONE_SIMULATOR && TARGET_OS_IPHONE
+ NSString* cameraID = nil;
+ for (AVCaptureDevice* captureDevice in
+ [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
+ if (captureDevice.position == AVCaptureDevicePositionFront) {
+ cameraID = [captureDevice localizedName];
+ break;
+ }
+ }
+ NSAssert(cameraID, @"Unable to get the front camera id");
+
+ RTCVideoCapturer* capturer =
+ [RTCVideoCapturer capturerWithDeviceName:cameraID];
+ self.videoSource = [self.peerConnectionFactory
+ videoSourceWithCapturer:capturer
+ constraints:self.client.videoConstraints];
+ localVideoTrack =
+ [self.peerConnectionFactory videoTrackWithID:@"ARDAMSv0"
+ source:self.videoSource];
+ if (localVideoTrack) {
+ [lms addVideoTrack:localVideoTrack];
+ }
+ [self.delegate connectionManager:self
+ didReceiveLocalVideoTrack:localVideoTrack];
+#endif
+
+ [lms addAudioTrack:[self.peerConnectionFactory audioTrackWithID:@"ARDAMSa0"]];
+ [self.peerConnection addStream:lms constraints:constraints];
+ [self.logger logMessage:@"onICEServers - added local stream."];
+}
+
+#pragma mark - GAEMessageHandler methods
+
+- (void)onOpen {
+ if (!self.client.initiator) {
+ [self.logger logMessage:@"Callee; waiting for remote offer"];
+ return;
+ }
+ [self.logger logMessage:@"GAE onOpen - create offer."];
+ RTCPair* audio =
+ [[RTCPair alloc] initWithKey:@"OfferToReceiveAudio" value:@"true"];
+ RTCPair* video =
+ [[RTCPair alloc] initWithKey:@"OfferToReceiveVideo" value:@"true"];
+ NSArray* mandatory = @[ audio, video ];
+ RTCMediaConstraints* constraints =
+ [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatory
+ optionalConstraints:nil];
+ [self.peerConnection createOfferWithDelegate:self constraints:constraints];
+ [self.logger logMessage:@"PC - createOffer."];
+}
+
+- (void)onMessage:(NSDictionary*)messageData {
+ NSString* type = messageData[@"type"];
+ NSAssert(type, @"Missing type: %@", messageData);
+ [self.logger logMessage:[NSString stringWithFormat:@"GAE onMessage type - %@",
+ type]];
+ if ([type isEqualToString:@"candidate"]) {
+ NSString* mid = messageData[@"id"];
+ NSNumber* sdpLineIndex = messageData[@"label"];
+ NSString* sdp = messageData[@"candidate"];
+ RTCICECandidate* candidate =
+ [[RTCICECandidate alloc] initWithMid:mid
+ index:sdpLineIndex.intValue
+ sdp:sdp];
+ if (self.queuedRemoteCandidates) {
+ [self.queuedRemoteCandidates addObject:candidate];
+ } else {
+ [self.peerConnection addICECandidate:candidate];
+ }
+ } else if ([type isEqualToString:@"offer"] ||
+ [type isEqualToString:@"answer"]) {
+ NSString* sdpString = messageData[@"sdp"];
+ RTCSessionDescription* sdp = [[RTCSessionDescription alloc]
+ initWithType:type
+ sdp:[[self class] preferISAC:sdpString]];
+ [self.peerConnection setRemoteDescriptionWithDelegate:self
+ sessionDescription:sdp];
+ [self.logger logMessage:@"PC - setRemoteDescription."];
+ } else if ([type isEqualToString:@"bye"]) {
+ [self.delegate connectionManagerDidReceiveHangup:self];
+ } else {
+ NSAssert(NO, @"Invalid message: %@", messageData);
+ }
+}
+
+- (void)onClose {
+ [self.logger logMessage:@"GAE onClose."];
+ [self.delegate connectionManagerDidReceiveHangup:self];
+}
+
+- (void)onError:(int)code withDescription:(NSString*)description {
+ NSString* message = [NSString stringWithFormat:@"GAE onError: %d, %@",
+ code, description];
+ [self.logger logMessage:message];
+ [self.delegate connectionManager:self
+ didErrorWithMessage:message];
+}
+
+#pragma mark - RTCPeerConnectionDelegate
+
+- (void)peerConnectionOnError:(RTCPeerConnection*)peerConnection {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSString* message = @"PeerConnection error";
+ NSLog(@"%@", message);
+ NSAssert(NO, @"PeerConnection failed.");
+ [self.delegate connectionManager:self
+ didErrorWithMessage:message];
+ });
+}
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ signalingStateChanged:(RTCSignalingState)stateChanged {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSLog(@"PCO onSignalingStateChange: %d", stateChanged);
+ });
+}
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ addedStream:(RTCMediaStream*)stream {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSLog(@"PCO onAddStream.");
+ NSAssert([stream.audioTracks count] == 1 || [stream.videoTracks count] == 1,
+ @"Expected audio or video track");
+ NSAssert([stream.audioTracks count] <= 1,
+ @"Expected at most 1 audio stream");
+ NSAssert([stream.videoTracks count] <= 1,
+ @"Expected at most 1 video stream");
+ if ([stream.videoTracks count] != 0) {
+ [self.delegate connectionManager:self
+ didReceiveRemoteVideoTrack:stream.videoTracks[0]];
+ }
+ });
+}
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ removedStream:(RTCMediaStream*)stream {
+ dispatch_async(dispatch_get_main_queue(),
+ ^{ NSLog(@"PCO onRemoveStream."); });
+}
+
+- (void)peerConnectionOnRenegotiationNeeded:(RTCPeerConnection*)peerConnection {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSLog(@"PCO onRenegotiationNeeded - ignoring because AppRTC has a "
+ "predefined negotiation strategy");
+ });
+}
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ gotICECandidate:(RTCICECandidate*)candidate {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSLog(@"PCO onICECandidate.\n Mid[%@] Index[%li] Sdp[%@]",
+ candidate.sdpMid,
+ (long)candidate.sdpMLineIndex,
+ candidate.sdp);
+ NSDictionary* json = @{
+ @"type" : @"candidate",
+ @"label" : @(candidate.sdpMLineIndex),
+ @"id" : candidate.sdpMid,
+ @"candidate" : candidate.sdp
+ };
+ NSError* error;
+ NSData* data =
+ [NSJSONSerialization dataWithJSONObject:json options:0 error:&error];
+ if (!error) {
+ [self.client sendData:data];
+ } else {
+ NSAssert(NO,
+ @"Unable to serialize JSON object with error: %@",
+ error.localizedDescription);
+ }
+ });
+}
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ iceGatheringChanged:(RTCICEGatheringState)newState {
+ dispatch_async(dispatch_get_main_queue(),
+ ^{ NSLog(@"PCO onIceGatheringChange. %d", newState); });
+}
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ iceConnectionChanged:(RTCICEConnectionState)newState {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSLog(@"PCO onIceConnectionChange. %d", newState);
+ if (newState == RTCICEConnectionConnected)
+ [self.logger logMessage:@"ICE Connection Connected."];
+ NSAssert(newState != RTCICEConnectionFailed, @"ICE Connection failed!");
+ });
+}
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ didOpenDataChannel:(RTCDataChannel*)dataChannel {
+ NSAssert(NO, @"AppRTC doesn't use DataChannels");
+}
+
+#pragma mark - RTCSessionDescriptionDelegate
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ didCreateSessionDescription:(RTCSessionDescription*)origSdp
+ error:(NSError*)error {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (error) {
+ [self.logger logMessage:@"SDP onFailure."];
+ NSAssert(NO, error.description);
+ return;
+ }
+ [self.logger logMessage:@"SDP onSuccess(SDP) - set local description."];
+ RTCSessionDescription* sdp = [[RTCSessionDescription alloc]
+ initWithType:origSdp.type
+ sdp:[[self class] preferISAC:origSdp.description]];
+ [self.peerConnection setLocalDescriptionWithDelegate:self
+ sessionDescription:sdp];
+ [self.logger logMessage:@"PC setLocalDescription."];
+ NSDictionary* json = @{@"type" : sdp.type, @"sdp" : sdp.description};
+ NSError* jsonError;
+ NSData* data = [NSJSONSerialization dataWithJSONObject:json
+ options:0
+ error:&jsonError];
+ NSAssert(!jsonError, @"Error: %@", jsonError.description);
+ [self.client sendData:data];
+ });
+}
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ didSetSessionDescriptionWithError:(NSError*)error {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (error) {
+ [self.logger logMessage:@"SDP onFailure."];
+ NSAssert(NO, error.description);
+ return;
+ }
+ [self.logger logMessage:@"SDP onSuccess() - possibly drain candidates"];
+ if (!self.client.initiator) {
+ if (self.peerConnection.remoteDescription &&
+ !self.peerConnection.localDescription) {
+ [self.logger logMessage:@"Callee, setRemoteDescription succeeded"];
+ RTCPair* audio = [[RTCPair alloc] initWithKey:@"OfferToReceiveAudio"
+ value:@"true"];
+ RTCPair* video = [[RTCPair alloc] initWithKey:@"OfferToReceiveVideo"
+ value:@"true"];
+ NSArray* mandatory = @[ audio, video ];
+ RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc]
+ initWithMandatoryConstraints:mandatory
+ optionalConstraints:nil];
+ [self.peerConnection createAnswerWithDelegate:self
+ constraints:constraints];
+ [self.logger logMessage:@"PC - createAnswer."];
+ } else {
+ [self.logger logMessage:@"SDP onSuccess - drain candidates"];
+ [self drainRemoteCandidates];
+ }
+ } else {
+ if (self.peerConnection.remoteDescription) {
+ [self.logger logMessage:@"SDP onSuccess - drain candidates"];
+ [self drainRemoteCandidates];
+ }
+ }
+ });
+}
+
+#pragma mark - RTCStatsDelegate methods
+
+- (void)peerConnection:(RTCPeerConnection*)peerConnection
+ didGetStats:(NSArray*)stats {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSString* message = [NSString stringWithFormat:@"Stats:\n %@", stats];
+ [self.logger logMessage:message];
+ });
+}
+
+#pragma mark - Private
+
+// Match |pattern| to |string| and return the first group of the first
+// match, or nil if no match was found.
++ (NSString*)firstMatch:(NSRegularExpression*)pattern
+ withString:(NSString*)string {
+ NSTextCheckingResult* result =
+ [pattern firstMatchInString:string
+ options:0
+ range:NSMakeRange(0, [string length])];
+ if (!result)
+ return nil;
+ return [string substringWithRange:[result rangeAtIndex:1]];
+}
+
+// Mangle |origSDP| to prefer the ISAC/16k audio codec.
++ (NSString*)preferISAC:(NSString*)origSDP {
+ int mLineIndex = -1;
+ NSString* isac16kRtpMap = nil;
+ NSArray* lines = [origSDP componentsSeparatedByString:@"\n"];
+ NSRegularExpression* isac16kRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"^a=rtpmap:(\\d+) ISAC/16000[\r]?$"
+ options:0
+ error:nil];
+ for (int i = 0;
+ (i < [lines count]) && (mLineIndex == -1 || isac16kRtpMap == nil);
+ ++i) {
+ NSString* line = [lines objectAtIndex:i];
+ if ([line hasPrefix:@"m=audio "]) {
+ mLineIndex = i;
+ continue;
+ }
+ isac16kRtpMap = [self firstMatch:isac16kRegex withString:line];
+ }
+ if (mLineIndex == -1) {
+ NSLog(@"No m=audio line, so can't prefer iSAC");
+ return origSDP;
+ }
+ if (isac16kRtpMap == nil) {
+ NSLog(@"No ISAC/16000 line, so can't prefer iSAC");
+ return origSDP;
+ }
+ NSArray* origMLineParts =
+ [[lines objectAtIndex:mLineIndex] componentsSeparatedByString:@" "];
+ NSMutableArray* newMLine =
+ [NSMutableArray arrayWithCapacity:[origMLineParts count]];
+ int origPartIndex = 0;
+ // Format is: m=<media> <port> <proto> <fmt> ...
+ [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
+ [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
+ [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex++]];
+ [newMLine addObject:isac16kRtpMap];
+ for (; origPartIndex < [origMLineParts count]; ++origPartIndex) {
+ if (![isac16kRtpMap
+ isEqualToString:[origMLineParts objectAtIndex:origPartIndex]]) {
+ [newMLine addObject:[origMLineParts objectAtIndex:origPartIndex]];
+ }
+ }
+ NSMutableArray* newLines = [NSMutableArray arrayWithCapacity:[lines count]];
+ [newLines addObjectsFromArray:lines];
+ [newLines replaceObjectAtIndex:mLineIndex
+ withObject:[newMLine componentsJoinedByString:@" "]];
+ return [newLines componentsJoinedByString:@"\n"];
+}
+
+- (void)drainRemoteCandidates {
+ for (RTCICECandidate* candidate in self.queuedRemoteCandidates) {
+ [self.peerConnection addICECandidate:candidate];
+ }
+ self.queuedRemoteCandidates = nil;
+}
+
+- (void)didFireStatsTimer:(NSTimer*)timer {
+ if (self.peerConnection) {
+ [self.peerConnection getStatsWithDelegate:self
+ mediaStreamTrack:nil
+ statsOutputLevel:RTCStatsOutputLevelDebug];
+ }
+}
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/GAEChannelClient.h b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/GAEChannelClient.h
index 49a928d8213..dbaecebd974 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/GAEChannelClient.h
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/GAEChannelClient.h
@@ -25,7 +25,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#import <UIKit/UIKit.h>
+#import <Foundation/Foundation.h>
// These methods will be called by the AppEngine chanel. The documentation
// for these methods is found here. (Yes, it is a JS API.)
@@ -33,17 +33,20 @@
@protocol GAEMessageHandler<NSObject>
- (void)onOpen;
-- (void)onMessage:(NSString *)data;
+- (void)onMessage:(NSDictionary*)data;
- (void)onClose;
-- (void)onError:(int)code withDescription:(NSString *)description;
+- (void)onError:(int)code withDescription:(NSString*)description;
@end
// Initialize with a token for an AppRTC data channel. This will load
// ios_channel.html and use the token to establish a data channel between the
// application and AppEngine.
-@interface GAEChannelClient : NSObject<UIWebViewDelegate>
+@interface GAEChannelClient : NSObject
-- (id)initWithToken:(NSString *)token delegate:(id<GAEMessageHandler>)delegate;
+@property(nonatomic, weak) id<GAEMessageHandler> delegate;
+
+- (instancetype)initWithToken:(NSString*)token
+ delegate:(id<GAEMessageHandler>)delegate;
@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/GAEChannelClient.m b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/GAEChannelClient.m
new file mode 100644
index 00000000000..a95e99a8d6c
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/GAEChannelClient.m
@@ -0,0 +1,167 @@
+/*
+ * libjingle
+ * Copyright 2013, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "GAEChannelClient.h"
+
+#import "RTCPeerConnectionFactory.h"
+
+#if TARGET_OS_IPHONE
+
+#import <UIKit/UIKit.h>
+
+@interface GAEChannelClient () <UIWebViewDelegate>
+
+@property(nonatomic, strong) UIWebView* webView;
+
+#else
+
+#import <WebKit/WebKit.h>
+
+@interface GAEChannelClient ()
+
+@property(nonatomic, strong) WebView* webView;
+
+#endif
+
+@end
+
+@implementation GAEChannelClient
+
+- (instancetype)initWithToken:(NSString*)token
+ delegate:(id<GAEMessageHandler>)delegate {
+ NSParameterAssert([token length] > 0);
+ NSParameterAssert(delegate);
+ self = [super init];
+ if (self) {
+#if TARGET_OS_IPHONE
+ _webView = [[UIWebView alloc] init];
+ _webView.delegate = self;
+#else
+ _webView = [[WebView alloc] init];
+ _webView.policyDelegate = self;
+#endif
+ _delegate = delegate;
+ NSString* htmlPath =
+ [[NSBundle mainBundle] pathForResource:@"channel" ofType:@"html"];
+ NSURL* htmlUrl = [NSURL fileURLWithPath:htmlPath];
+ NSString* path = [NSString
+ stringWithFormat:@"%@?token=%@", [htmlUrl absoluteString], token];
+#if TARGET_OS_IPHONE
+ [_webView
+#else
+ [[_webView mainFrame]
+#endif
+ loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:path]]];
+ }
+ return self;
+}
+
+- (void)dealloc {
+#if TARGET_OS_IPHONE
+ _webView.delegate = nil;
+ [_webView stopLoading];
+#else
+ _webView.policyDelegate = nil;
+ [[_webView mainFrame] stopLoading];
+#endif
+}
+
+#if TARGET_OS_IPHONE
+#pragma mark - UIWebViewDelegate
+
+- (BOOL)webView:(UIWebView*)webView
+ shouldStartLoadWithRequest:(NSURLRequest*)request
+ navigationType:(UIWebViewNavigationType)navigationType {
+#else
+// WebPolicyDelegate is an informal delegate.
+#pragma mark - WebPolicyDelegate
+
+- (void)webView:(WebView*)webView
+ decidePolicyForNavigationAction:(NSDictionary*)actionInformation
+ request:(NSURLRequest*)request
+ frame:(WebFrame*)frame
+ decisionListener:(id<WebPolicyDecisionListener>)listener {
+#endif
+ NSString* scheme = [request.URL scheme];
+ NSAssert(scheme, @"scheme is nil: %@", request);
+ if (![scheme isEqualToString:@"js-frame"]) {
+#if TARGET_OS_IPHONE
+ return YES;
+#else
+ [listener use];
+ return;
+#endif
+ }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSString* queuedMessage = [webView
+ stringByEvaluatingJavaScriptFromString:@"popQueuedMessage();"];
+ NSAssert([queuedMessage length], @"Empty queued message from JS");
+
+ NSDictionary* queuedMessageDict =
+ [GAEChannelClient jsonStringToDictionary:queuedMessage];
+ NSString* method = queuedMessageDict[@"type"];
+ NSAssert(method, @"Missing method: %@", queuedMessageDict);
+ NSDictionary* payload = queuedMessageDict[@"payload"]; // May be nil.
+
+ if ([method isEqualToString:@"onopen"]) {
+ [self.delegate onOpen];
+ } else if ([method isEqualToString:@"onmessage"]) {
+ NSDictionary* payloadData =
+ [GAEChannelClient jsonStringToDictionary:payload[@"data"]];
+ [self.delegate onMessage:payloadData];
+ } else if ([method isEqualToString:@"onclose"]) {
+ [self.delegate onClose];
+ } else if ([method isEqualToString:@"onerror"]) {
+ NSNumber* codeNumber = payload[@"code"];
+ int code = [codeNumber intValue];
+ NSAssert([codeNumber isEqualToNumber:[NSNumber numberWithInt:code]],
+ @"Unexpected non-integral code: %@", payload);
+ [self.delegate onError:code withDescription:payload[@"description"]];
+ } else {
+ NSAssert(NO, @"Invalid message sent from UIWebView: %@", queuedMessage);
+ }
+ });
+#if TARGET_OS_IPHONE
+ return NO;
+#else
+ [listener ignore];
+ return;
+#endif
+}
+
+#pragma mark - Private
+
++ (NSDictionary*)jsonStringToDictionary:(NSString*)str {
+ NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];
+ NSError* error;
+ NSDictionary* dict =
+ [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
+ NSAssert(!error, @"Invalid JSON? %@", str);
+ return dict;
+}
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/ios_channel.html b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/channel.html
index a55b8f48bc3..86846dd6870 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/ios_channel.html
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/channel.html
@@ -6,10 +6,11 @@
Helper HTML that redirects Google AppEngine's Channel API to Objective C.
This is done by hosting this page in an iOS application. The hosting
class creates a UIWebView control and implements the UIWebViewDelegate
- protocol. Then when there is a channel message, it is encoded in an IFRAME.
- That IFRAME is added to the DOM which triggers a navigation event
- |shouldStartLoadWithRequest| in Objective C which can then be routed in the
- application as desired.
+ protocol. Then when there is a channel message it is queued in JS,
+ and an IFRAME is added to the DOM, triggering a navigation event
+ |shouldStartLoadWithRequest| in Objective C which can then fetch the
+ message using |popQueuedMessage|. This queuing is necessary to avoid URL
+ length limits in UIWebView (which are undocumented).
-->
<body onbeforeunload="closeSocket()" onload="openSocket()">
<script type="text/javascript">
@@ -38,6 +39,10 @@
var channel = null;
var socket = null;
+ // In-order queue of messages to be delivered to ObjectiveC.
+ // Each is a JSON.stringify()'d dictionary containing a 'type'
+ // field and optionally a 'payload'.
+ var messageQueue = [];
function openSocket() {
if (!QueryString.token || !QueryString.token.match(/^[A-z0-9_-]+$/)) {
@@ -52,17 +57,13 @@
sendMessageToObjC("onopen");
},
'onmessage': function(msg) {
- sendMessageToObjC("onmessage:" +
- encodeURIComponent(JSON.stringify(msg.data)));
+ sendMessageToObjC("onmessage", msg);
},
'onclose': function() {
sendMessageToObjC("onclose");
},
'onerror': function(err) {
- sendMessageToObjC("onerror:" +
- encodeURIComponent(JSON.stringify(err.code)) +
- ":message:" +
- encodeURIComponent(JSON.stringify(err.description)));
+ sendMessageToObjC("onerror", err);
}
});
}
@@ -73,9 +74,10 @@
// Add an IFRAME to the DOM to trigger a navigation event. Then remove
// it as it is no longer needed. Only one event is generated.
- function sendMessageToObjC(message) {
+ function sendMessageToObjC(type, payload) {
+ messageQueue.push(JSON.stringify({'type': type, 'payload': payload}));
var iframe = document.createElement("IFRAME");
- iframe.setAttribute("src", "js-frame:" + message);
+ iframe.setAttribute("src", "js-frame:");
// For some reason we need to set a non-empty size for the iOS6
// simulator...
iframe.setAttribute("height", "1px");
@@ -83,6 +85,10 @@
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
}
+
+ function popQueuedMessage() {
+ return messageQueue.shift();
+ }
</script>
</body>
</html>
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.h b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.h
new file mode 100644
index 00000000000..196b39fd9d4
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.h
@@ -0,0 +1,34 @@
+/*
+ * libjingle
+ * Copyright 2013, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <UIKit/UIKit.h>
+
+// The main application class of the AppRTCDemo iOS app demonstrating
+// interoperability between the Objective C implementation of PeerConnection
+// and the apprtc.appspot.com demo webapp.
+@interface APPRTCAppDelegate : NSObject<UIApplicationDelegate>
+@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.h b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.m
index 22754e3ad26..58963d53e93 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCAppDelegate.h
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.m
@@ -25,32 +25,41 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#import <UIKit/UIKit.h>
+#import "APPRTCAppDelegate.h"
-#import "GAEChannelClient.h"
-#import "APPRTCAppClient.h"
-#import "RTCSessionDescriptonDelegate.h"
+#import "APPRTCViewController.h"
+#import "RTCPeerConnectionFactory.h"
-// Used to send a message to an apprtc.appspot.com "room".
-@protocol APPRTCSendMessage<NSObject>
+@implementation APPRTCAppDelegate {
+ UIWindow* _window;
+}
-- (void)sendData:(NSData *)data;
-// Logging helper.
-- (void)displayLogMessage:(NSString *)message;
-@end
+#pragma mark - UIApplicationDelegate methods
+
+- (BOOL)application:(UIApplication*)application
+ didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
+ [RTCPeerConnectionFactory initializeSSL];
+ _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+ APPRTCViewController* viewController =
+ [[APPRTCViewController alloc] initWithNibName:@"APPRTCViewController"
+ bundle:nil];
+ _window.rootViewController = viewController;
+ [_window makeKeyAndVisible];
+ return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication*)application {
+ [[self appRTCViewController] applicationWillResignActive:application];
+}
-@class APPRTCViewController;
+- (void)applicationWillTerminate:(UIApplication*)application {
+ [RTCPeerConnectionFactory deinitializeSSL];
+}
-// The main application class of the AppRTCDemo iOS app demonstrating
-// interoperability between the Objcective C implementation of PeerConnection
-// and the apprtc.appspot.com demo webapp.
-@interface APPRTCAppDelegate : UIResponder<ICEServerDelegate,
- GAEMessageHandler,
- APPRTCSendMessage,
- RTCSessionDescriptonDelegate,
- UIApplicationDelegate>
+#pragma mark - Private
-@property (strong, nonatomic) UIWindow *window;
-@property (strong, nonatomic) APPRTCViewController *viewController;
+- (APPRTCViewController*)appRTCViewController {
+ return (APPRTCViewController*)_window.rootViewController;
+}
@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCViewController.h b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.h
index 6b107a564c2..5b10199c2ce 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/APPRTCViewController.h
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.h
@@ -30,11 +30,11 @@
// The view controller that is displayed when AppRTCDemo is loaded.
@interface APPRTCViewController : UIViewController<UITextFieldDelegate>
-@property (weak, nonatomic) IBOutlet UITextField *textField;
-@property (weak, nonatomic) IBOutlet UITextView *textInstructions;
-@property (weak, nonatomic) IBOutlet UITextView *textOutput;
+@property(weak, nonatomic) IBOutlet UITextField* roomInput;
+@property(weak, nonatomic) IBOutlet UITextView* instructionsView;
+@property(weak, nonatomic) IBOutlet UITextView* logView;
+@property(weak, nonatomic) IBOutlet UIView* blackView;
-- (void)displayText:(NSString *)text;
-- (void)resetUI;
+- (void)applicationWillResignActive:(UIApplication*)application;
@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m
new file mode 100644
index 00000000000..a4a0bd33d1b
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m
@@ -0,0 +1,231 @@
+/*
+ * libjingle
+ * Copyright 2013, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "APPRTCViewController.h"
+
+#import <AVFoundation/AVFoundation.h>
+#import "APPRTCConnectionManager.h"
+#import "RTCEAGLVideoView.h"
+
+// Padding space for local video view with its parent.
+static CGFloat const kLocalViewPadding = 20;
+
+@interface APPRTCViewController ()
+<APPRTCConnectionManagerDelegate, APPRTCLogger, RTCEAGLVideoViewDelegate>
+@property(nonatomic, assign) UIInterfaceOrientation statusBarOrientation;
+@property(nonatomic, strong) RTCEAGLVideoView* localVideoView;
+@property(nonatomic, strong) RTCEAGLVideoView* remoteVideoView;
+@end
+
+@implementation APPRTCViewController {
+ APPRTCConnectionManager* _connectionManager;
+ CGSize _localVideoSize;
+ CGSize _remoteVideoSize;
+}
+
+- (instancetype)initWithNibName:(NSString*)nibName
+ bundle:(NSBundle*)bundle {
+ if (self = [super initWithNibName:nibName bundle:bundle]) {
+ _connectionManager =
+ [[APPRTCConnectionManager alloc] initWithDelegate:self
+ logger:self];
+ }
+ return self;
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ self.statusBarOrientation =
+ [UIApplication sharedApplication].statusBarOrientation;
+ self.roomInput.delegate = self;
+ [self.roomInput becomeFirstResponder];
+}
+
+- (void)viewDidLayoutSubviews {
+ if (self.statusBarOrientation !=
+ [UIApplication sharedApplication].statusBarOrientation) {
+ self.statusBarOrientation =
+ [UIApplication sharedApplication].statusBarOrientation;
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:@"StatusBarOrientationDidChange"
+ object:nil];
+ }
+}
+
+- (void)applicationWillResignActive:(UIApplication*)application {
+ [self logMessage:@"Application lost focus, connection broken."];
+ [self disconnect];
+}
+
+#pragma mark - APPRTCConnectionManagerDelegate
+
+- (void)connectionManager:(APPRTCConnectionManager*)manager
+ didReceiveLocalVideoTrack:(RTCVideoTrack*)localVideoTrack {
+ self.localVideoView.hidden = NO;
+ self.localVideoView.videoTrack = localVideoTrack;
+}
+
+- (void)connectionManager:(APPRTCConnectionManager*)manager
+ didReceiveRemoteVideoTrack:(RTCVideoTrack*)remoteVideoTrack {
+ self.remoteVideoView.videoTrack = remoteVideoTrack;
+}
+
+- (void)connectionManagerDidReceiveHangup:(APPRTCConnectionManager*)manager {
+ [self showAlertWithMessage:@"Remote hung up."];
+ [self disconnect];
+}
+
+- (void)connectionManager:(APPRTCConnectionManager*)manager
+ didErrorWithMessage:(NSString*)message {
+ [self showAlertWithMessage:message];
+ [self disconnect];
+}
+
+#pragma mark - APPRTCLogger
+
+- (void)logMessage:(NSString*)message {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSString* output =
+ [NSString stringWithFormat:@"%@\n%@", self.logView.text, message];
+ self.logView.text = output;
+ [self.logView
+ scrollRangeToVisible:NSMakeRange([self.logView.text length], 0)];
+ });
+}
+
+#pragma mark - RTCEAGLVideoViewDelegate
+
+- (void)videoView:(RTCEAGLVideoView*)videoView
+ didChangeVideoSize:(CGSize)size {
+ if (videoView == self.localVideoView) {
+ _localVideoSize = size;
+ } else if (videoView == self.remoteVideoView) {
+ _remoteVideoSize = size;
+ } else {
+ NSParameterAssert(NO);
+ }
+ [self updateVideoViewLayout];
+}
+
+#pragma mark - UITextFieldDelegate
+
+- (void)textFieldDidEndEditing:(UITextField*)textField {
+ NSString* room = textField.text;
+ if ([room length] == 0) {
+ return;
+ }
+ textField.hidden = YES;
+ self.instructionsView.hidden = YES;
+ self.logView.hidden = NO;
+ NSString* url =
+ [NSString stringWithFormat:@"https://apprtc.appspot.com/?r=%@", room];
+ [_connectionManager connectToRoomWithURL:[NSURL URLWithString:url]];
+ [self setupCaptureSession];
+}
+
+- (BOOL)textFieldShouldReturn:(UITextField*)textField {
+ // There is no other control that can take focus, so manually resign focus
+ // when return (Join) is pressed to trigger |textFieldDidEndEditing|.
+ [textField resignFirstResponder];
+ return YES;
+}
+
+#pragma mark - Private
+
+- (void)disconnect {
+ [self resetUI];
+ [_connectionManager disconnect];
+}
+
+- (void)showAlertWithMessage:(NSString*)message {
+ UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:nil
+ message:message
+ delegate:nil
+ cancelButtonTitle:@"OK"
+ otherButtonTitles:nil];
+ [alertView show];
+}
+
+- (void)resetUI {
+ [self.roomInput resignFirstResponder];
+ self.roomInput.text = nil;
+ self.roomInput.hidden = NO;
+ self.instructionsView.hidden = NO;
+ self.logView.hidden = YES;
+ self.logView.text = nil;
+ self.blackView.hidden = YES;
+ [self.remoteVideoView removeFromSuperview];
+ self.remoteVideoView = nil;
+ [self.localVideoView removeFromSuperview];
+ self.localVideoView = nil;
+}
+
+- (void)setupCaptureSession {
+ self.blackView.hidden = NO;
+ self.remoteVideoView =
+ [[RTCEAGLVideoView alloc] initWithFrame:self.blackView.bounds];
+ self.remoteVideoView.delegate = self;
+ self.remoteVideoView.transform = CGAffineTransformMakeScale(-1, 1);
+ [self.blackView addSubview:self.remoteVideoView];
+
+ self.localVideoView =
+ [[RTCEAGLVideoView alloc] initWithFrame:self.blackView.bounds];
+ self.localVideoView.delegate = self;
+ [self.blackView addSubview:self.localVideoView];
+ [self updateVideoViewLayout];
+}
+
+- (void)updateVideoViewLayout {
+ // TODO(tkchin): handle rotation.
+ CGSize defaultAspectRatio = CGSizeMake(4, 3);
+ CGSize localAspectRatio = CGSizeEqualToSize(_localVideoSize, CGSizeZero) ?
+ defaultAspectRatio : _localVideoSize;
+ CGSize remoteAspectRatio = CGSizeEqualToSize(_remoteVideoSize, CGSizeZero) ?
+ defaultAspectRatio : _remoteVideoSize;
+
+ CGRect remoteVideoFrame =
+ AVMakeRectWithAspectRatioInsideRect(remoteAspectRatio,
+ self.blackView.bounds);
+ self.remoteVideoView.frame = remoteVideoFrame;
+
+ CGRect localVideoFrame =
+ AVMakeRectWithAspectRatioInsideRect(localAspectRatio,
+ self.blackView.bounds);
+ localVideoFrame.size.width = localVideoFrame.size.width / 3;
+ localVideoFrame.size.height = localVideoFrame.size.height / 3;
+ localVideoFrame.origin.x = CGRectGetMaxX(self.blackView.bounds)
+ - localVideoFrame.size.width - kLocalViewPadding;
+ localVideoFrame.origin.y = CGRectGetMaxY(self.blackView.bounds)
+ - localVideoFrame.size.height - kLocalViewPadding;
+ self.localVideoView.frame = localVideoFrame;
+}
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/AppRTCDemo-Prefix.pch b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/AppRTCDemo-Prefix.pch
index 3ac2c3b1a5c..3ac2c3b1a5c 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/AppRTCDemo-Prefix.pch
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/AppRTCDemo-Prefix.pch
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/Default.png b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/Default.png
index 4c8ca6f693f..4c8ca6f693f 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/Default.png
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/Default.png
Binary files differ
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/Info.plist b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/Info.plist
index 72504aa5c88..b61648057c8 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/Info.plist
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/Info.plist
@@ -38,19 +38,6 @@
<array>
<string>iPhoneOS</string>
</array>
- <key>CFBundleURLTypes</key>
- <array>
- <dict>
- <key>CFBundleTypeRole</key>
- <string>Editor</string>
- <key>CFBundleURLName</key>
- <string>com.google.apprtcdemo</string>
- <key>CFBundleURLSchemes</key>
- <array>
- <string>apprtc</string>
- </array>
- </dict>
- </array>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>UIRequiredDeviceCapabilities</key>
@@ -70,8 +57,6 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
- <string>UIInterfaceOrientationLandscapeLeft</string>
- <string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/ResourceRules.plist b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/ResourceRules.plist
index e7ec329dccb..e7ec329dccb 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/ResourceRules.plist
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/ResourceRules.plist
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/en.lproj/APPRTCViewController.xib b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/en.lproj/APPRTCViewController.xib
index cd73ea64ef0..cb2dc8394e0 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/en.lproj/APPRTCViewController.xib
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/en.lproj/APPRTCViewController.xib
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
<data>
- <int key="IBDocument.SystemTarget">1552</int>
- <string key="IBDocument.SystemVersion">12D78</string>
- <string key="IBDocument.InterfaceBuilderVersion">3084</string>
- <string key="IBDocument.AppKitVersion">1187.37</string>
- <string key="IBDocument.HIToolboxVersion">626.00</string>
+ <int key="IBDocument.SystemTarget">1536</int>
+ <string key="IBDocument.SystemVersion">13B42</string>
+ <string key="IBDocument.InterfaceBuilderVersion">4514</string>
+ <string key="IBDocument.AppKitVersion">1265</string>
+ <string key="IBDocument.HIToolboxVersion">696.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
- <string key="NS.object.0">2083</string>
+ <string key="NS.object.0">3747</string>
</object>
<array key="IBDocument.IntegratedClassDependencies">
<string>IBNSLayoutConstraint</string>
@@ -34,7 +34,7 @@
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
<object class="IBUIView" id="774585933">
- <nil key="NSNextResponder"/>
+ <reference key="NSNextResponder"/>
<int key="NSvFlags">274</int>
<array class="NSMutableArray" key="NSSubviews">
<object class="IBUITextView" id="176994284">
@@ -42,7 +42,8 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{20, 20}, {280, 141}}</string>
<reference key="NSSuperview" ref="774585933"/>
- <reference key="NSNextKeyView" ref="546385578"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="634862110"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<object class="NSColor" key="IBUIBackgroundColor" id="621995359">
<int key="NSColorSpace">1</int>
@@ -51,7 +52,7 @@
<bool key="IBUIClipsSubviews">YES</bool>
<bool key="IBUIUserInteractionEnabled">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
- <string key="IBUIText">Use Safari and open a URL with a scheme of apprtc to load the test app and connect. i.e. apprtc://apprtc.appspot.com/?r=12345678 Or just enter the room below to connect to apprtc.</string>
+ <string key="IBUIText">Enter the room below to connect to apprtc.</string>
<object class="IBUITextInputTraits" key="IBUITextInputTraits">
<int key="IBUIAutocapitalizationType">2</int>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
@@ -60,8 +61,8 @@
<int key="type">1</int>
<double key="pointSize">14</double>
</object>
- <object class="NSFont" key="IBUIFont" id="371333696">
- <string key="NSName">Helvetica</string>
+ <object class="NSFont" key="IBUIFont" id="144501234">
+ <string key="NSName">HelveticaNeue</string>
<double key="NSSize">14</double>
<int key="NSfFlags">16</int>
</object>
@@ -71,7 +72,8 @@
<int key="NSvFlags">292</int>
<string key="NSFrame">{{20, 180}, {280, 30}}</string>
<reference key="NSSuperview" ref="774585933"/>
- <reference key="NSNextKeyView" ref="634862110"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="261050959"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClipsSubviews">YES</bool>
@@ -95,13 +97,15 @@
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
<reference key="IBUIFontDescription" ref="166497611"/>
- <reference key="IBUIFont" ref="371333696"/>
+ <reference key="IBUIFont" ref="144501234"/>
</object>
<object class="IBUITextView" id="634862110">
<reference key="NSNextResponder" ref="774585933"/>
<int key="NSvFlags">-2147483356</int>
- <string key="NSFrame">{{20, 20}, {280, 508}}</string>
+ <string key="NSFrame">{{20, 20}, {280, 190}}</string>
<reference key="NSSuperview" ref="774585933"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="546385578"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<reference key="IBUIBackgroundColor" ref="621995359"/>
<bool key="IBUIClipsSubviews">YES</bool>
@@ -114,10 +118,26 @@
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
<reference key="IBUIFontDescription" ref="166497611"/>
- <reference key="IBUIFont" ref="371333696"/>
+ <reference key="IBUIFont" ref="144501234"/>
+ </object>
+ <object class="IBUIView" id="261050959">
+ <reference key="NSNextResponder" ref="774585933"/>
+ <int key="NSvFlags">-2147483356</int>
+ <string key="NSFrame">{{20, 228}, {280, 300}}</string>
+ <reference key="NSSuperview" ref="774585933"/>
+ <reference key="NSWindow"/>
+ <reference key="NSNextKeyView"/>
+ <string key="NSReuseIdentifierKey">_NS:9</string>
+ <object class="NSColor" key="IBUIBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
</array>
<string key="NSFrame">{{0, 20}, {320, 548}}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="176994284"/>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">3</int>
@@ -140,7 +160,7 @@
</array>
</object>
<string key="IBUITargetRuntime">IBCocoaTouchFramework</string>
- <string key="IBUIDisplayName">Retina 4 Full Screen</string>
+ <string key="IBUIDisplayName">Retina 4-inch Full Screen</string>
<int key="IBUIType">2</int>
</object>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
@@ -158,7 +178,7 @@
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
- <string key="label">textField</string>
+ <string key="label">roomInput</string>
<reference key="source" ref="372490531"/>
<reference key="destination" ref="546385578"/>
</object>
@@ -166,7 +186,7 @@
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
- <string key="label">textInstructions</string>
+ <string key="label">instructionsView</string>
<reference key="source" ref="372490531"/>
<reference key="destination" ref="176994284"/>
</object>
@@ -174,12 +194,20 @@
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
- <string key="label">textOutput</string>
+ <string key="label">logView</string>
<reference key="source" ref="372490531"/>
<reference key="destination" ref="634862110"/>
</object>
<int key="connectionID">138</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">blackView</string>
+ <reference key="source" ref="372490531"/>
+ <reference key="destination" ref="261050959"/>
+ </object>
+ <int key="connectionID">151</int>
+ </object>
</array>
<object class="IBMutableOrderedSet" key="objectRecords">
<array key="orderedObjects">
@@ -204,12 +232,12 @@
<int key="objectID">6</int>
<reference key="object" ref="774585933"/>
<array class="NSMutableArray" key="children">
- <object class="IBNSLayoutConstraint" id="117610664">
+ <object class="IBNSLayoutConstraint" id="933872207">
<reference key="firstItem" ref="774585933"/>
- <int key="firstAttribute">6</int>
+ <int key="firstAttribute">4</int>
<int key="relation">0</int>
- <reference key="secondItem" ref="546385578"/>
- <int key="secondAttribute">6</int>
+ <reference key="secondItem" ref="261050959"/>
+ <int key="secondAttribute">4</int>
<float key="multiplier">1</float>
<object class="IBNSLayoutSymbolicConstant" key="constant">
<double key="value">20</double>
@@ -217,88 +245,145 @@
<float key="priority">1000</float>
<reference key="containingView" ref="774585933"/>
<int key="scoringType">8</int>
- <float key="scoringTypeFloat">29</float>
+ <float key="scoringTypeFloat">23</float>
<int key="contentType">3</int>
+ <bool key="placeholder">NO</bool>
</object>
- <object class="IBNSLayoutConstraint" id="555801739">
- <reference key="firstItem" ref="546385578"/>
+ <object class="IBNSLayoutConstraint" id="863471211">
+ <reference key="firstItem" ref="261050959"/>
<int key="firstAttribute">3</int>
<int key="relation">0</int>
<reference key="secondItem" ref="774585933"/>
<int key="secondAttribute">3</int>
<float key="multiplier">1</float>
<object class="IBLayoutConstant" key="constant">
- <double key="value">180</double>
+ <double key="value">228</double>
</object>
<float key="priority">1000</float>
<reference key="containingView" ref="774585933"/>
<int key="scoringType">3</int>
<float key="scoringTypeFloat">9</float>
<int key="contentType">3</int>
+ <bool key="placeholder">NO</bool>
</object>
- <object class="IBNSLayoutConstraint" id="860801955">
+ <object class="IBNSLayoutConstraint" id="590654550">
<reference key="firstItem" ref="546385578"/>
<int key="firstAttribute">5</int>
<int key="relation">0</int>
- <reference key="secondItem" ref="774585933"/>
+ <reference key="secondItem" ref="261050959"/>
<int key="secondAttribute">5</int>
<float key="multiplier">1</float>
+ <object class="IBLayoutConstant" key="constant">
+ <double key="value">0.0</double>
+ </object>
+ <float key="priority">1000</float>
+ <reference key="containingView" ref="774585933"/>
+ <int key="scoringType">6</int>
+ <float key="scoringTypeFloat">24</float>
+ <int key="contentType">2</int>
+ <bool key="placeholder">NO</bool>
+ </object>
+ <object class="IBNSLayoutConstraint" id="734153049">
+ <reference key="firstItem" ref="546385578"/>
+ <int key="firstAttribute">6</int>
+ <int key="relation">0</int>
+ <reference key="secondItem" ref="261050959"/>
+ <int key="secondAttribute">6</int>
+ <float key="multiplier">1</float>
+ <object class="IBLayoutConstant" key="constant">
+ <double key="value">0.0</double>
+ </object>
+ <float key="priority">1000</float>
+ <reference key="containingView" ref="774585933"/>
+ <int key="scoringType">6</int>
+ <float key="scoringTypeFloat">24</float>
+ <int key="contentType">2</int>
+ <bool key="placeholder">NO</bool>
+ </object>
+ <object class="IBNSLayoutConstraint" id="117610664">
+ <reference key="firstItem" ref="774585933"/>
+ <int key="firstAttribute">6</int>
+ <int key="relation">0</int>
+ <reference key="secondItem" ref="546385578"/>
+ <int key="secondAttribute">6</int>
+ <float key="multiplier">1</float>
<object class="IBNSLayoutSymbolicConstant" key="constant">
<double key="value">20</double>
</object>
<float key="priority">1000</float>
<reference key="containingView" ref="774585933"/>
- <int key="scoringType">8</int>
+ <int key="scoringType">0</int>
<float key="scoringTypeFloat">29</float>
<int key="contentType">3</int>
+ <bool key="placeholder">NO</bool>
</object>
- <object class="IBNSLayoutConstraint" id="19985792">
- <reference key="firstItem" ref="634862110"/>
- <int key="firstAttribute">3</int>
+ <object class="IBNSLayoutConstraint" id="860801955">
+ <reference key="firstItem" ref="546385578"/>
+ <int key="firstAttribute">5</int>
<int key="relation">0</int>
<reference key="secondItem" ref="774585933"/>
- <int key="secondAttribute">3</int>
+ <int key="secondAttribute">5</int>
<float key="multiplier">1</float>
<object class="IBNSLayoutSymbolicConstant" key="constant">
<double key="value">20</double>
</object>
<float key="priority">1000</float>
<reference key="containingView" ref="774585933"/>
- <int key="scoringType">8</int>
+ <int key="scoringType">0</int>
<float key="scoringTypeFloat">29</float>
<int key="contentType">3</int>
+ <bool key="placeholder">NO</bool>
</object>
- <object class="IBNSLayoutConstraint" id="1001701893">
- <reference key="firstItem" ref="774585933"/>
- <int key="firstAttribute">6</int>
+ <object class="IBNSLayoutConstraint" id="544488581">
+ <reference key="firstItem" ref="634862110"/>
+ <int key="firstAttribute">4</int>
<int key="relation">0</int>
- <reference key="secondItem" ref="634862110"/>
- <int key="secondAttribute">6</int>
+ <reference key="secondItem" ref="546385578"/>
+ <int key="secondAttribute">4</int>
+ <float key="multiplier">1</float>
+ <object class="IBLayoutConstant" key="constant">
+ <double key="value">0.0</double>
+ </object>
+ <float key="priority">1000</float>
+ <reference key="containingView" ref="774585933"/>
+ <int key="scoringType">6</int>
+ <float key="scoringTypeFloat">24</float>
+ <int key="contentType">2</int>
+ <bool key="placeholder">NO</bool>
+ </object>
+ <object class="IBNSLayoutConstraint" id="19985792">
+ <reference key="firstItem" ref="634862110"/>
+ <int key="firstAttribute">3</int>
+ <int key="relation">0</int>
+ <reference key="secondItem" ref="774585933"/>
+ <int key="secondAttribute">3</int>
<float key="multiplier">1</float>
<object class="IBNSLayoutSymbolicConstant" key="constant">
<double key="value">20</double>
</object>
<float key="priority">1000</float>
<reference key="containingView" ref="774585933"/>
- <int key="scoringType">8</int>
+ <int key="scoringType">0</int>
<float key="scoringTypeFloat">29</float>
<int key="contentType">3</int>
+ <bool key="placeholder">NO</bool>
</object>
- <object class="IBNSLayoutConstraint" id="914503793">
+ <object class="IBNSLayoutConstraint" id="1001701893">
<reference key="firstItem" ref="774585933"/>
- <int key="firstAttribute">4</int>
+ <int key="firstAttribute">6</int>
<int key="relation">0</int>
<reference key="secondItem" ref="634862110"/>
- <int key="secondAttribute">4</int>
+ <int key="secondAttribute">6</int>
<float key="multiplier">1</float>
<object class="IBNSLayoutSymbolicConstant" key="constant">
<double key="value">20</double>
</object>
<float key="priority">1000</float>
<reference key="containingView" ref="774585933"/>
- <int key="scoringType">8</int>
+ <int key="scoringType">0</int>
<float key="scoringTypeFloat">29</float>
<int key="contentType">3</int>
+ <bool key="placeholder">NO</bool>
</object>
<object class="IBNSLayoutConstraint" id="858545289">
<reference key="firstItem" ref="634862110"/>
@@ -312,9 +397,10 @@
</object>
<float key="priority">1000</float>
<reference key="containingView" ref="774585933"/>
- <int key="scoringType">8</int>
+ <int key="scoringType">0</int>
<float key="scoringTypeFloat">29</float>
<int key="contentType">3</int>
+ <bool key="placeholder">NO</bool>
</object>
<object class="IBNSLayoutConstraint" id="1039342825">
<reference key="firstItem" ref="774585933"/>
@@ -328,9 +414,10 @@
</object>
<float key="priority">1000</float>
<reference key="containingView" ref="774585933"/>
- <int key="scoringType">8</int>
+ <int key="scoringType">0</int>
<float key="scoringTypeFloat">29</float>
<int key="contentType">3</int>
+ <bool key="placeholder">NO</bool>
</object>
<object class="IBNSLayoutConstraint" id="663764352">
<reference key="firstItem" ref="176994284"/>
@@ -344,9 +431,10 @@
</object>
<float key="priority">1000</float>
<reference key="containingView" ref="774585933"/>
- <int key="scoringType">8</int>
+ <int key="scoringType">0</int>
<float key="scoringTypeFloat">29</float>
<int key="contentType">3</int>
+ <bool key="placeholder">NO</bool>
</object>
<object class="IBNSLayoutConstraint" id="46028745">
<reference key="firstItem" ref="176994284"/>
@@ -360,13 +448,15 @@
</object>
<float key="priority">1000</float>
<reference key="containingView" ref="774585933"/>
- <int key="scoringType">8</int>
+ <int key="scoringType">0</int>
<float key="scoringTypeFloat">29</float>
<int key="contentType">3</int>
+ <bool key="placeholder">NO</bool>
</object>
<reference ref="176994284"/>
<reference ref="546385578"/>
<reference ref="634862110"/>
+ <reference ref="261050959"/>
</array>
<reference key="parent" ref="0"/>
</object>
@@ -389,6 +479,7 @@
<int key="scoringType">3</int>
<float key="scoringTypeFloat">9</float>
<int key="contentType">1</int>
+ <bool key="placeholder">NO</bool>
</object>
</array>
<reference key="parent" ref="774585933"/>
@@ -425,11 +516,6 @@
<reference key="parent" ref="176994284"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">124</int>
- <reference key="object" ref="555801739"/>
- <reference key="parent" ref="774585933"/>
- </object>
- <object class="IBObjectRecord">
<int key="objectID">126</int>
<reference key="object" ref="117610664"/>
<reference key="parent" ref="774585933"/>
@@ -437,7 +523,25 @@
<object class="IBObjectRecord">
<int key="objectID">128</int>
<reference key="object" ref="634862110"/>
- <array class="NSMutableArray" key="children"/>
+ <array class="NSMutableArray" key="children">
+ <object class="IBNSLayoutConstraint" id="988159807">
+ <reference key="firstItem" ref="634862110"/>
+ <int key="firstAttribute">8</int>
+ <int key="relation">0</int>
+ <nil key="secondItem"/>
+ <int key="secondAttribute">0</int>
+ <float key="multiplier">1</float>
+ <object class="IBLayoutConstant" key="constant">
+ <double key="value">190</double>
+ </object>
+ <float key="priority">1000</float>
+ <reference key="containingView" ref="634862110"/>
+ <int key="scoringType">3</int>
+ <float key="scoringTypeFloat">9</float>
+ <int key="contentType">1</int>
+ <bool key="placeholder">NO</bool>
+ </object>
+ </array>
<reference key="parent" ref="774585933"/>
</object>
<object class="IBObjectRecord">
@@ -446,11 +550,6 @@
<reference key="parent" ref="774585933"/>
</object>
<object class="IBObjectRecord">
- <int key="objectID">136</int>
- <reference key="object" ref="914503793"/>
- <reference key="parent" ref="774585933"/>
- </object>
- <object class="IBObjectRecord">
<int key="objectID">137</int>
<reference key="object" ref="1001701893"/>
<reference key="parent" ref="774585933"/>
@@ -460,6 +559,41 @@
<reference key="object" ref="19985792"/>
<reference key="parent" ref="774585933"/>
</object>
+ <object class="IBObjectRecord">
+ <int key="objectID">141</int>
+ <reference key="object" ref="988159807"/>
+ <reference key="parent" ref="634862110"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">142</int>
+ <reference key="object" ref="261050959"/>
+ <reference key="parent" ref="774585933"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">148</int>
+ <reference key="object" ref="734153049"/>
+ <reference key="parent" ref="774585933"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">149</int>
+ <reference key="object" ref="590654550"/>
+ <reference key="parent" ref="774585933"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">153</int>
+ <reference key="object" ref="863471211"/>
+ <reference key="parent" ref="774585933"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">154</int>
+ <reference key="object" ref="933872207"/>
+ <reference key="parent" ref="774585933"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">155</int>
+ <reference key="object" ref="544488581"/>
+ <reference key="parent" ref="774585933"/>
+ </object>
</array>
</object>
<dictionary class="NSMutableDictionary" key="flattenedProperties">
@@ -471,31 +605,43 @@
<boolean value="NO" key="104.IBViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
<string key="107.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="123.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
- <string key="124.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="126.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="128.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <array key="128.IBViewMetadataConstraints">
+ <reference ref="988159807"/>
+ </array>
<boolean value="NO" key="128.IBViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
<string key="133.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
- <string key="136.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="137.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="139.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string key="141.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string key="142.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <boolean value="NO" key="142.IBViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
+ <string key="148.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string key="149.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string key="153.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string key="154.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string key="155.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="57.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<array class="NSMutableArray" key="57.IBViewMetadataConstraints">
<reference ref="234302232"/>
</array>
<boolean value="NO" key="57.IBViewMetadataTranslatesAutoresizingMaskIntoConstraints"/>
<string key="6.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
- <array key="6.IBViewMetadataConstraints">
+ <array class="NSMutableArray" key="6.IBViewMetadataConstraints">
<reference ref="46028745"/>
<reference ref="663764352"/>
<reference ref="1039342825"/>
<reference ref="858545289"/>
- <reference ref="914503793"/>
<reference ref="1001701893"/>
<reference ref="19985792"/>
+ <reference ref="544488581"/>
<reference ref="860801955"/>
- <reference ref="555801739"/>
<reference ref="117610664"/>
+ <reference ref="734153049"/>
+ <reference ref="590654550"/>
+ <reference ref="863471211"/>
+ <reference ref="933872207"/>
</array>
<string key="62.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="63.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
@@ -505,11 +651,43 @@
<nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/>
- <int key="maxID">139</int>
+ <int key="maxID">155</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
<object class="IBPartialClassDescription">
+ <string key="className">APPRTCViewController</string>
+ <string key="superclassName">UIViewController</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="blackView">UIView</string>
+ <string key="roomInput">UITextField</string>
+ <string key="instructionsView">UITextView</string>
+ <string key="logView">UITextView</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="blackView">
+ <string key="name">blackView</string>
+ <string key="candidateClassName">UIView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="roomInput">
+ <string key="name">roomInput</string>
+ <string key="candidateClassName">UITextField</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="instructionsView">
+ <string key="name">instructionsView</string>
+ <string key="candidateClassName">UITextView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="logView">
+ <string key="name">logView</string>
+ <string key="candidateClassName">UITextView</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/APPRTCViewController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
<string key="className">NSLayoutConstraint</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
@@ -521,9 +699,18 @@
</object>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <bool key="IBDocument.previouslyAttemptedUpgradeToXcode5">YES</bool>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
+ <real value="1536" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
+ <integer value="4600" key="NS.object.0"/>
+ </object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
<bool key="IBDocument.UseAutolayout">YES</bool>
- <string key="IBCocoaTouchPluginVersion">2083</string>
+ <string key="IBCocoaTouchPluginVersion">3747</string>
</data>
</archive>
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/main.m b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/main.m
index bf35f4cbfe9..e9a1f63efb6 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/AppRTCDemo/main.m
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/ios/main.m
@@ -29,7 +29,7 @@
#import "APPRTCAppDelegate.h"
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(
argc, argv, nil, NSStringFromClass([APPRTCAppDelegate class]));
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCAppDelegate.h b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCAppDelegate.h
new file mode 100644
index 00000000000..77011f194a0
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCAppDelegate.h
@@ -0,0 +1,31 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface APPRTCAppDelegate : NSObject<NSApplicationDelegate>
+@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCAppDelegate.m b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCAppDelegate.m
new file mode 100644
index 00000000000..d6bd4fc039e
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCAppDelegate.m
@@ -0,0 +1,77 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "APPRTCAppDelegate.h"
+
+#import "APPRTCViewController.h"
+#import "RTCPeerConnectionFactory.h"
+
+@interface APPRTCAppDelegate () <NSWindowDelegate>
+@end
+
+@implementation APPRTCAppDelegate {
+ APPRTCViewController* _viewController;
+ NSWindow* _window;
+}
+
+#pragma mark - NSApplicationDelegate
+
+- (void)applicationDidFinishLaunching:(NSNotification*)notification {
+ [RTCPeerConnectionFactory initializeSSL];
+ NSScreen* screen = [NSScreen mainScreen];
+ NSRect visibleRect = [screen visibleFrame];
+ NSRect windowRect = NSMakeRect(NSMidX(visibleRect),
+ NSMidY(visibleRect),
+ 1320,
+ 1140);
+ NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask;
+ _window = [[NSWindow alloc] initWithContentRect:windowRect
+ styleMask:styleMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ _window.delegate = self;
+ [_window makeKeyAndOrderFront:self];
+ [_window makeMainWindow];
+ _viewController = [[APPRTCViewController alloc] initWithNibName:nil
+ bundle:nil];
+ [_window setContentView:[_viewController view]];
+}
+
+#pragma mark - NSWindow
+
+- (void)windowWillClose:(NSNotification*)notification {
+ [_viewController windowWillClose:notification];
+ [RTCPeerConnectionFactory deinitializeSSL];
+ [NSApp terminate:self];
+}
+
+@end
+
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.h b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.h
new file mode 100644
index 00000000000..3ef058c6cf9
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.h
@@ -0,0 +1,34 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface APPRTCViewController : NSViewController
+
+- (void)windowWillClose:(NSNotification*)notification;
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.m b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.m
new file mode 100644
index 00000000000..cf5b836012a
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.m
@@ -0,0 +1,312 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "APPRTCViewController.h"
+
+#import <AVFoundation/AVFoundation.h>
+#import "APPRTCConnectionManager.h"
+#import "RTCNSGLVideoView.h"
+
+static NSUInteger const kContentWidth = 1280;
+static NSUInteger const kContentHeight = 720;
+static NSUInteger const kRoomFieldWidth = 80;
+static NSUInteger const kLogViewHeight = 280;
+
+@class APPRTCMainView;
+@protocol APPRTCMainViewDelegate
+
+- (void)appRTCMainView:(APPRTCMainView*)mainView
+ didEnterRoomId:(NSString*)roomId;
+
+@end
+
+@interface APPRTCMainView : NSView
+
+@property(nonatomic, weak) id<APPRTCMainViewDelegate> delegate;
+@property(nonatomic, readonly) RTCNSGLVideoView* localVideoView;
+@property(nonatomic, readonly) RTCNSGLVideoView* remoteVideoView;
+
+- (void)displayLogMessage:(NSString*)message;
+
+@end
+
+@interface APPRTCMainView () <NSTextFieldDelegate, RTCNSGLVideoViewDelegate>
+@end
+@implementation APPRTCMainView {
+ NSScrollView* _scrollView;
+ NSTextField* _roomLabel;
+ NSTextField* _roomField;
+ NSTextView* _logView;
+ RTCNSGLVideoView* _localVideoView;
+ RTCNSGLVideoView* _remoteVideoView;
+ CGSize _localVideoSize;
+ CGSize _remoteVideoSize;
+}
+
++ (BOOL)requiresConstraintBasedLayout {
+ return YES;
+}
+
+- (instancetype)initWithFrame:(NSRect)frame {
+ if (self = [super initWithFrame:frame]) {
+ [self setupViews];
+ }
+ return self;
+}
+
+- (void)updateConstraints {
+ NSParameterAssert(
+ _roomField != nil && _scrollView != nil && _remoteVideoView != nil);
+ [self removeConstraints:[self constraints]];
+ NSDictionary* viewsDictionary =
+ NSDictionaryOfVariableBindings(_roomLabel,
+ _roomField,
+ _scrollView,
+ _remoteVideoView);
+
+ NSSize remoteViewSize = [self remoteVideoViewSize];
+ NSDictionary* metrics = @{
+ @"kLogViewHeight" : @(kLogViewHeight),
+ @"kRoomFieldWidth" : @(kRoomFieldWidth),
+ @"remoteViewWidth" : @(remoteViewSize.width),
+ @"remoteViewHeight" : @(remoteViewSize.height),
+ };
+ // Declare this separately to avoid compiler warning about splitting string
+ // within an NSArray expression.
+ NSString* verticalConstraint =
+ @"V:|-[_roomLabel]-[_roomField]-[_scrollView(kLogViewHeight)]"
+ "-[_remoteVideoView(remoteViewHeight)]-|";
+ NSArray* constraintFormats = @[
+ verticalConstraint,
+ @"|-[_roomLabel]",
+ @"|-[_roomField(kRoomFieldWidth)]",
+ @"|-[_scrollView(remoteViewWidth)]-|",
+ @"|-[_remoteVideoView(remoteViewWidth)]-|",
+ ];
+ for (NSString* constraintFormat in constraintFormats) {
+ NSArray* constraints =
+ [NSLayoutConstraint constraintsWithVisualFormat:constraintFormat
+ options:0
+ metrics:metrics
+ views:viewsDictionary];
+ for (NSLayoutConstraint* constraint in constraints) {
+ [self addConstraint:constraint];
+ }
+ }
+ [super updateConstraints];
+}
+
+- (void)displayLogMessage:(NSString*)message {
+ _logView.string =
+ [NSString stringWithFormat:@"%@%@\n", _logView.string, message];
+ NSRange range = NSMakeRange([_logView.string length], 0);
+ [_logView scrollRangeToVisible:range];
+}
+
+#pragma mark - NSControl delegate
+
+- (void)controlTextDidEndEditing:(NSNotification*)notification {
+ NSDictionary* userInfo = [notification userInfo];
+ NSInteger textMovement = [userInfo[@"NSTextMovement"] intValue];
+ if (textMovement == NSReturnTextMovement) {
+ [self.delegate appRTCMainView:self didEnterRoomId:_roomField.stringValue];
+ }
+}
+
+#pragma mark - RTCNSGLVideoViewDelegate
+
+- (void)videoView:(RTCNSGLVideoView*)videoView
+ didChangeVideoSize:(NSSize)size {
+ if (videoView == _remoteVideoView) {
+ _remoteVideoSize = size;
+ } else if (videoView == _localVideoView) {
+ _localVideoSize = size;
+ } else {
+ return;
+ }
+ [self setNeedsUpdateConstraints:YES];
+}
+
+#pragma mark - Private
+
+- (void)setupViews {
+ NSParameterAssert([[self subviews] count] == 0);
+
+ _roomLabel = [[NSTextField alloc] initWithFrame:NSZeroRect];
+ [_roomLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [_roomLabel setBezeled:NO];
+ [_roomLabel setDrawsBackground:NO];
+ [_roomLabel setEditable:NO];
+ [_roomLabel setStringValue:@"Enter AppRTC room id:"];
+ [self addSubview:_roomLabel];
+
+ _roomField = [[NSTextField alloc] initWithFrame:NSZeroRect];
+ [_roomField setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [self addSubview:_roomField];
+ [_roomField setEditable:YES];
+ [_roomField setDelegate:self];
+
+ _logView = [[NSTextView alloc] initWithFrame:NSZeroRect];
+ [_logView setMinSize:NSMakeSize(0, kLogViewHeight)];
+ [_logView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ [_logView setVerticallyResizable:YES];
+ [_logView setAutoresizingMask:NSViewWidthSizable];
+ NSTextContainer* textContainer = [_logView textContainer];
+ NSSize containerSize = NSMakeSize(kContentWidth, FLT_MAX);
+ [textContainer setContainerSize:containerSize];
+ [textContainer setWidthTracksTextView:YES];
+ [_logView setEditable:NO];
+
+ _scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect];
+ [_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [_scrollView setHasVerticalScroller:YES];
+ [_scrollView setDocumentView:_logView];
+ [self addSubview:_scrollView];
+
+ NSOpenGLPixelFormatAttribute attributes[] = {
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFADepthSize, 24,
+ NSOpenGLPFAOpenGLProfile,
+ NSOpenGLProfileVersion3_2Core,
+ 0
+ };
+ NSOpenGLPixelFormat* pixelFormat =
+ [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
+ _remoteVideoView = [[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect
+ pixelFormat:pixelFormat];
+ [_remoteVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
+ _remoteVideoView.delegate = self;
+ [self addSubview:_remoteVideoView];
+
+ // TODO(tkchin): create local video view.
+ // https://code.google.com/p/webrtc/issues/detail?id=3417.
+}
+
+- (NSSize)remoteVideoViewSize {
+ if (_remoteVideoSize.width > 0 && _remoteVideoSize.height > 0) {
+ return _remoteVideoSize;
+ } else {
+ return NSMakeSize(kContentWidth, kContentHeight);
+ }
+}
+
+- (NSSize)localVideoViewSize {
+ return NSZeroSize;
+}
+
+@end
+
+@interface APPRTCViewController ()
+ <APPRTCConnectionManagerDelegate, APPRTCMainViewDelegate, APPRTCLogger>
+@property(nonatomic, readonly) APPRTCMainView* mainView;
+@end
+
+@implementation APPRTCViewController {
+ APPRTCConnectionManager* _connectionManager;
+}
+
+- (instancetype)initWithNibName:(NSString*)nibName
+ bundle:(NSBundle*)bundle {
+ if (self = [super initWithNibName:nibName bundle:bundle]) {
+ _connectionManager =
+ [[APPRTCConnectionManager alloc] initWithDelegate:self
+ logger:self];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self disconnect];
+}
+
+- (void)loadView {
+ APPRTCMainView* view = [[APPRTCMainView alloc] initWithFrame:NSZeroRect];
+ [view setTranslatesAutoresizingMaskIntoConstraints:NO];
+ view.delegate = self;
+ self.view = view;
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ [self disconnect];
+}
+
+#pragma mark - APPRTCConnectionManagerDelegate
+
+- (void)connectionManager:(APPRTCConnectionManager*)manager
+ didReceiveLocalVideoTrack:(RTCVideoTrack*)localVideoTrack {
+ self.mainView.localVideoView.videoTrack = localVideoTrack;
+}
+
+- (void)connectionManager:(APPRTCConnectionManager*)manager
+ didReceiveRemoteVideoTrack:(RTCVideoTrack*)remoteVideoTrack {
+ self.mainView.remoteVideoView.videoTrack = remoteVideoTrack;
+}
+
+- (void)connectionManagerDidReceiveHangup:(APPRTCConnectionManager*)manager {
+ [self showAlertWithMessage:@"Remote closed connection"];
+ [self disconnect];
+}
+
+- (void)connectionManager:(APPRTCConnectionManager*)manager
+ didErrorWithMessage:(NSString*)message {
+ [self showAlertWithMessage:message];
+ [self disconnect];
+}
+
+#pragma mark - APPRTCLogger
+
+- (void)logMessage:(NSString*)message {
+ [self.mainView displayLogMessage:message];
+}
+
+#pragma mark - APPRTCMainViewDelegate
+
+- (void)appRTCMainView:(APPRTCMainView*)mainView
+ didEnterRoomId:(NSString*)roomId {
+ NSString* urlString =
+ [NSString stringWithFormat:@"https://apprtc.appspot.com/?r=%@", roomId];
+ [_connectionManager connectToRoomWithURL:[NSURL URLWithString:urlString]];
+}
+
+#pragma mark - Private
+
+- (APPRTCMainView*)mainView {
+ return (APPRTCMainView*)self.view;
+}
+
+- (void)showAlertWithMessage:(NSString*)message {
+ NSAlert* alert = [[NSAlert alloc] init];
+ [alert setMessageText:message];
+ [alert runModal];
+}
+
+- (void)disconnect {
+ self.mainView.remoteVideoView.videoTrack = nil;
+ [_connectionManager disconnect];
+}
+
+@end
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/Info.plist b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/Info.plist
new file mode 100644
index 00000000000..4dcb2403812
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/Info.plist
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE plist PUBLIC "-//Apple/DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.Google.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist> \ No newline at end of file
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/main.m b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/main.m
new file mode 100644
index 00000000000..9ce3de27a98
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/AppRTCDemo/mac/main.m
@@ -0,0 +1,39 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+#import "APPRTCAppDelegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ [NSApplication sharedApplication];
+ APPRTCAppDelegate* delegate = [[APPRTCAppDelegate alloc] init];
+ [NSApp setDelegate:delegate];
+ [NSApp run];
+ }
+}
diff --git a/chromium/third_party/libjingle/source/talk/examples/ios/Icon.png b/chromium/third_party/libjingle/source/talk/examples/objc/Icon.png
index 55773ca9d99..55773ca9d99 100644
--- a/chromium/third_party/libjingle/source/talk/examples/ios/Icon.png
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/Icon.png
Binary files differ
diff --git a/chromium/third_party/libjingle/source/talk/examples/objc/README b/chromium/third_party/libjingle/source/talk/examples/objc/README
new file mode 100644
index 00000000000..bfe18b37c5c
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/examples/objc/README
@@ -0,0 +1,3 @@
+This directory contains sample iOS and mac clients for http://apprtc.appspot.com
+
+See ../../app/webrtc/objc/README for information on how to use it.
diff --git a/chromium/third_party/libjingle/source/talk/examples/pcp/pcp_main.cc b/chromium/third_party/libjingle/source/talk/examples/pcp/pcp_main.cc
deleted file mode 100644
index 1b8974dea03..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/pcp/pcp_main.cc
+++ /dev/null
@@ -1,715 +0,0 @@
-#define _CRT_SECURE_NO_DEPRECATE 1
-
-#include <time.h>
-
-#if defined(POSIX)
-#include <unistd.h>
-#endif
-
-#include <iomanip>
-#include <iostream>
-#include <string>
-
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif // HAVE_CONFIG_H
-
-#include "talk/base/sslconfig.h" // For SSL_USE_*
-
-#if SSL_USE_OPENSSL
-#define USE_SSL_TUNNEL
-#endif
-
-#include "talk/base/basicdefs.h"
-#include "talk/base/common.h"
-#include "talk/base/helpers.h"
-#include "talk/base/logging.h"
-#include "talk/base/ssladapter.h"
-#include "talk/base/stringutils.h"
-#include "talk/base/thread.h"
-#include "talk/p2p/base/sessionmanager.h"
-#include "talk/p2p/client/autoportallocator.h"
-#include "talk/p2p/client/sessionmanagertask.h"
-#include "talk/xmpp/xmppengine.h"
-#ifdef USE_SSL_TUNNEL
-#include "talk/session/tunnel/securetunnelsessionclient.h"
-#endif
-#include "talk/session/tunnel/tunnelsessionclient.h"
-#include "talk/xmpp/xmppclient.h"
-#include "talk/xmpp/xmppclientsettings.h"
-#include "talk/xmpp/xmpppump.h"
-#include "talk/xmpp/xmppsocket.h"
-
-#ifndef MAX_PATH
-#define MAX_PATH 256
-#endif
-
-#if defined(_MSC_VER) && (_MSC_VER < 1400)
-// The following are necessary to properly link when compiling STL without
-// /EHsc, otherwise known as C++ exceptions.
-void __cdecl std::_Throw(const std::exception &) {}
-std::_Prhand std::_Raise_handler = 0;
-#endif
-
-enum {
- MSG_LOGIN_COMPLETE = 1,
- MSG_LOGIN_FAILED,
- MSG_DONE,
-};
-
-buzz::Jid gUserJid;
-talk_base::InsecureCryptStringImpl gUserPass;
-std::string gXmppHost = "talk.google.com";
-int gXmppPort = 5222;
-buzz::TlsOptions gXmppUseTls = buzz::TLS_REQUIRED;
-
-class DebugLog : public sigslot::has_slots<> {
-public:
- DebugLog() :
- debug_input_buf_(NULL), debug_input_len_(0), debug_input_alloc_(0),
- debug_output_buf_(NULL), debug_output_len_(0), debug_output_alloc_(0),
- censor_password_(false)
- {}
- char * debug_input_buf_;
- int debug_input_len_;
- int debug_input_alloc_;
- char * debug_output_buf_;
- int debug_output_len_;
- int debug_output_alloc_;
- bool censor_password_;
-
- void Input(const char * data, int len) {
- if (debug_input_len_ + len > debug_input_alloc_) {
- char * old_buf = debug_input_buf_;
- debug_input_alloc_ = 4096;
- while (debug_input_alloc_ < debug_input_len_ + len) {
- debug_input_alloc_ *= 2;
- }
- debug_input_buf_ = new char[debug_input_alloc_];
- memcpy(debug_input_buf_, old_buf, debug_input_len_);
- delete[] old_buf;
- }
- memcpy(debug_input_buf_ + debug_input_len_, data, len);
- debug_input_len_ += len;
- DebugPrint(debug_input_buf_, &debug_input_len_, false);
- }
-
- void Output(const char * data, int len) {
- if (debug_output_len_ + len > debug_output_alloc_) {
- char * old_buf = debug_output_buf_;
- debug_output_alloc_ = 4096;
- while (debug_output_alloc_ < debug_output_len_ + len) {
- debug_output_alloc_ *= 2;
- }
- debug_output_buf_ = new char[debug_output_alloc_];
- memcpy(debug_output_buf_, old_buf, debug_output_len_);
- delete[] old_buf;
- }
- memcpy(debug_output_buf_ + debug_output_len_, data, len);
- debug_output_len_ += len;
- DebugPrint(debug_output_buf_, &debug_output_len_, true);
- }
-
- static bool
- IsAuthTag(const char * str, size_t len) {
- if (str[0] == '<' && str[1] == 'a' &&
- str[2] == 'u' &&
- str[3] == 't' &&
- str[4] == 'h' &&
- str[5] <= ' ') {
- std::string tag(str, len);
-
- if (tag.find("mechanism") != std::string::npos)
- return true;
-
- }
- return false;
- }
-
- void
- DebugPrint(char * buf, int * plen, bool output) {
- int len = *plen;
- if (len > 0) {
- time_t tim = time(NULL);
- struct tm * now = localtime(&tim);
- char *time_string = asctime(now);
- if (time_string) {
- size_t time_len = strlen(time_string);
- if (time_len > 0) {
- time_string[time_len-1] = 0; // trim off terminating \n
- }
- }
- LOG(INFO) << (output ? "SEND >>>>>>>>>>>>>>>>>>>>>>>>>" : "RECV <<<<<<<<<<<<<<<<<<<<<<<<<")
- << " : " << time_string;
-
- bool indent;
- int start = 0, nest = 3;
- for (int i = 0; i < len; i += 1) {
- if (buf[i] == '>') {
- if ((i > 0) && (buf[i-1] == '/')) {
- indent = false;
- } else if ((start + 1 < len) && (buf[start + 1] == '/')) {
- indent = false;
- nest -= 2;
- } else {
- indent = true;
- }
-
- // Output a tag
- LOG(INFO) << std::setw(nest) << " " << std::string(buf + start, i + 1 - start);
-
- if (indent)
- nest += 2;
-
- // Note if it's a PLAIN auth tag
- if (IsAuthTag(buf + start, i + 1 - start)) {
- censor_password_ = true;
- }
-
- // incr
- start = i + 1;
- }
-
- if (buf[i] == '<' && start < i) {
- if (censor_password_) {
- LOG(INFO) << std::setw(nest) << " " << "## TEXT REMOVED ##";
- censor_password_ = false;
- }
- else {
- LOG(INFO) << std::setw(nest) << " " << std::string(buf + start, i - start);
- }
- start = i;
- }
- }
- len = len - start;
- memcpy(buf, buf + start, len);
- *plen = len;
- }
- }
-
-};
-
-static DebugLog debug_log_;
-
-// Prints out a usage message then exits.
-void Usage() {
- std::cerr << "Usage:" << std::endl;
- std::cerr << " pcp [options] <my_jid> (server mode)" << std::endl;
- std::cerr << " pcp [options] <my_jid> <src_file> <dst_full_jid>:<dst_file> (client sending)" << std::endl;
- std::cerr << " pcp [options] <my_jid> <src_full_jid>:<src_file> <dst_file> (client rcv'ing)" << std::endl;
- std::cerr << " --verbose" << std::endl;
- std::cerr << " --xmpp-host=<host>" << std::endl;
- std::cerr << " --xmpp-port=<port>" << std::endl;
- std::cerr << " --xmpp-use-tls=(true|false)" << std::endl;
- exit(1);
-}
-
-// Prints out an error message, a usage message, then exits.
-void Error(const std::string& msg) {
- std::cerr << "error: " << msg << std::endl;
- std::cerr << std::endl;
- Usage();
-}
-
-void FatalError(const std::string& msg) {
- std::cerr << "error: " << msg << std::endl;
- std::cerr << std::endl;
- exit(1);
-}
-
-// Determines whether the given string is an option. If so, the name and
-// value are appended to the given strings.
-bool ParseArg(const char* arg, std::string* name, std::string* value) {
- if (strncmp(arg, "--", 2) != 0)
- return false;
-
- const char* eq = strchr(arg + 2, '=');
- if (eq) {
- if (name)
- name->append(arg + 2, eq);
- if (value)
- value->append(eq + 1, arg + strlen(arg));
- } else {
- if (name)
- name->append(arg + 2, arg + strlen(arg));
- if (value)
- value->clear();
- }
-
- return true;
-}
-
-int ParseIntArg(const std::string& name, const std::string& value) {
- char* end;
- long val = strtol(value.c_str(), &end, 10);
- if (*end != '\0')
- Error(std::string("value of option ") + name + " must be an integer");
- return static_cast<int>(val);
-}
-
-#ifdef WIN32
-#pragma warning(push)
-// disable "unreachable code" warning b/c it varies between dbg and opt
-#pragma warning(disable: 4702)
-#endif
-bool ParseBoolArg(const std::string& name, const std::string& value) {
- if (value == "true")
- return true;
- else if (value == "false")
- return false;
- else {
- Error(std::string("value of option ") + name + " must be true or false");
- return false;
- }
-}
-#ifdef WIN32
-#pragma warning(pop)
-#endif
-
-void ParseFileArg(const char* arg, buzz::Jid* jid, std::string* file) {
- const char* sep = strchr(arg, ':');
- if (!sep) {
- *file = arg;
- } else {
- buzz::Jid jid_arg(std::string(arg, sep-arg));
- if (jid_arg.IsBare())
- Error("A full JID is required for the source or destination arguments.");
- *jid = jid_arg;
- *file = std::string(sep+1);
- }
-}
-
-
-void SetConsoleEcho(bool on) {
-#ifdef WIN32
- HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
- if ((hIn == INVALID_HANDLE_VALUE) || (hIn == NULL))
- return;
-
- DWORD mode;
- if (!GetConsoleMode(hIn, &mode))
- return;
-
- if (on) {
- mode = mode | ENABLE_ECHO_INPUT;
- } else {
- mode = mode & ~ENABLE_ECHO_INPUT;
- }
-
- SetConsoleMode(hIn, mode);
-#else
- int re;
- if (on)
- re = system("stty echo");
- else
- re = system("stty -echo");
- if (-1 == re)
- return;
-#endif
-}
-
-// Fills in a settings object with the values from the arguments.
-buzz::XmppClientSettings LoginSettings() {
- buzz::XmppClientSettings xcs;
- xcs.set_user(gUserJid.node());
- xcs.set_host(gUserJid.domain());
- xcs.set_resource("pcp");
- xcs.set_pass(talk_base::CryptString(gUserPass));
- talk_base::SocketAddress server(gXmppHost, gXmppPort);
- xcs.set_server(server);
- xcs.set_use_tls(gXmppUseTls);
- return xcs;
-}
-
-// Runs the current thread until a message with the given ID is seen.
-uint32 Loop(const std::vector<uint32>& ids) {
- talk_base::Message msg;
- while (talk_base::Thread::Current()->Get(&msg)) {
- if (msg.phandler == NULL) {
- if (std::find(ids.begin(), ids.end(), msg.message_id) != ids.end())
- return msg.message_id;
- std::cout << "orphaned message: " << msg.message_id;
- continue;
- }
- talk_base::Thread::Current()->Dispatch(&msg);
- }
- return 0;
-}
-
-#ifdef WIN32
-#pragma warning(disable:4355)
-#endif
-
-class CustomXmppPump : public buzz::XmppPumpNotify, public buzz::XmppPump {
-public:
- CustomXmppPump() : XmppPump(this), server_(false) { }
-
- void Serve(cricket::TunnelSessionClient* client) {
- client->SignalIncomingTunnel.connect(this,
- &CustomXmppPump::OnIncomingTunnel);
- server_ = true;
- }
-
- void OnStateChange(buzz::XmppEngine::State state) {
- switch (state) {
- case buzz::XmppEngine::STATE_START:
- std::cout << "connecting..." << std::endl;
- break;
- case buzz::XmppEngine::STATE_OPENING:
- std::cout << "logging in..." << std::endl;
- break;
- case buzz::XmppEngine::STATE_OPEN:
- std::cout << "logged in..." << std::endl;
- talk_base::Thread::Current()->Post(NULL, MSG_LOGIN_COMPLETE);
- break;
- case buzz::XmppEngine::STATE_CLOSED:
- std::cout << "logged out..." << std::endl;
- talk_base::Thread::Current()->Post(NULL, MSG_LOGIN_FAILED);
- break;
- }
- }
-
- void OnIncomingTunnel(cricket::TunnelSessionClient* client, buzz::Jid jid,
- std::string description, cricket::Session* session) {
- std::cout << "IncomingTunnel from " << jid.Str()
- << ": " << description << std::endl;
- if (!server_ || file_) {
- client->DeclineTunnel(session);
- return;
- }
- std::string filename;
- bool send;
- if (strncmp(description.c_str(), "send:", 5) == 0) {
- send = true;
- } else if (strncmp(description.c_str(), "recv:", 5) == 0) {
- send = false;
- } else {
- client->DeclineTunnel(session);
- return;
- }
- filename = description.substr(5);
- talk_base::StreamInterface* stream = client->AcceptTunnel(session);
- if (!ProcessStream(stream, filename, send))
- talk_base::Thread::Current()->Post(NULL, MSG_DONE);
-
- // TODO: There is a potential memory leak, however, since the PCP
- // app doesn't work right now, I can't verify the fix actually works, so
- // comment out the following line until we fix the PCP app.
-
- // delete stream;
- }
-
- bool ProcessStream(talk_base::StreamInterface* stream,
- const std::string& filename, bool send) {
- ASSERT(file_);
- sending_ = send;
- file_.reset(new talk_base::FileStream);
- buffer_len_ = 0;
- int err;
- if (!file_->Open(filename.c_str(), sending_ ? "rb" : "wb", &err)) {
- std::cerr << "Error opening <" << filename << ">: "
- << std::strerror(err) << std::endl;
- return false;
- }
- stream->SignalEvent.connect(this, &CustomXmppPump::OnStreamEvent);
- if (stream->GetState() == talk_base::SS_CLOSED) {
- std::cerr << "Failed to establish P2P tunnel" << std::endl;
- return false;
- }
- if (stream->GetState() == talk_base::SS_OPEN) {
- OnStreamEvent(stream,
- talk_base::SE_OPEN | talk_base::SE_READ | talk_base::SE_WRITE, 0);
- }
- return true;
- }
-
- void OnStreamEvent(talk_base::StreamInterface* stream, int events,
- int error) {
- if (events & talk_base::SE_CLOSE) {
- if (error == 0) {
- std::cout << "Tunnel closed normally" << std::endl;
- } else {
- std::cout << "Tunnel closed with error: " << error << std::endl;
- }
- Cleanup(stream);
- return;
- }
- if (events & talk_base::SE_OPEN) {
- std::cout << "Tunnel connected" << std::endl;
- }
- talk_base::StreamResult result;
- size_t count;
- if (sending_ && (events & talk_base::SE_WRITE)) {
- LOG(LS_VERBOSE) << "Tunnel SE_WRITE";
- while (true) {
- size_t write_pos = 0;
- while (write_pos < buffer_len_) {
- result = stream->Write(buffer_ + write_pos, buffer_len_ - write_pos,
- &count, &error);
- if (result == talk_base::SR_SUCCESS) {
- write_pos += count;
- continue;
- }
- if (result == talk_base::SR_BLOCK) {
- buffer_len_ -= write_pos;
- memmove(buffer_, buffer_ + write_pos, buffer_len_);
- LOG(LS_VERBOSE) << "Tunnel write block";
- return;
- }
- if (result == talk_base::SR_EOS) {
- std::cout << "Tunnel closed unexpectedly on write" << std::endl;
- } else {
- std::cout << "Tunnel write error: " << error << std::endl;
- }
- Cleanup(stream);
- return;
- }
- buffer_len_ = 0;
- while (buffer_len_ < sizeof(buffer_)) {
- result = file_->Read(buffer_ + buffer_len_,
- sizeof(buffer_) - buffer_len_,
- &count, &error);
- if (result == talk_base::SR_SUCCESS) {
- buffer_len_ += count;
- continue;
- }
- if (result == talk_base::SR_EOS) {
- if (buffer_len_ > 0)
- break;
- std::cout << "End of file" << std::endl;
- // A hack until we have friendly shutdown
- Cleanup(stream, true);
- return;
- } else if (result == talk_base::SR_BLOCK) {
- std::cout << "File blocked unexpectedly on read" << std::endl;
- } else {
- std::cout << "File read error: " << error << std::endl;
- }
- Cleanup(stream);
- return;
- }
- }
- }
- if (!sending_ && (events & talk_base::SE_READ)) {
- LOG(LS_VERBOSE) << "Tunnel SE_READ";
- while (true) {
- buffer_len_ = 0;
- while (buffer_len_ < sizeof(buffer_)) {
- result = stream->Read(buffer_ + buffer_len_,
- sizeof(buffer_) - buffer_len_,
- &count, &error);
- if (result == talk_base::SR_SUCCESS) {
- buffer_len_ += count;
- continue;
- }
- if (result == talk_base::SR_BLOCK) {
- if (buffer_len_ > 0)
- break;
- LOG(LS_VERBOSE) << "Tunnel read block";
- return;
- }
- if (result == talk_base::SR_EOS) {
- std::cout << "Tunnel closed unexpectedly on read" << std::endl;
- } else {
- std::cout << "Tunnel read error: " << error << std::endl;
- }
- Cleanup(stream);
- return;
- }
- size_t write_pos = 0;
- while (write_pos < buffer_len_) {
- result = file_->Write(buffer_ + write_pos, buffer_len_ - write_pos,
- &count, &error);
- if (result == talk_base::SR_SUCCESS) {
- write_pos += count;
- continue;
- }
- if (result == talk_base::SR_EOS) {
- std::cout << "File closed unexpectedly on write" << std::endl;
- } else if (result == talk_base::SR_BLOCK) {
- std::cout << "File blocked unexpectedly on write" << std::endl;
- } else {
- std::cout << "File write error: " << error << std::endl;
- }
- Cleanup(stream);
- return;
- }
- }
- }
- }
-
- void Cleanup(talk_base::StreamInterface* stream, bool delay = false) {
- LOG(LS_VERBOSE) << "Closing";
- stream->Close();
- file_.reset();
- if (!server_) {
- if (delay)
- talk_base::Thread::Current()->PostDelayed(2000, NULL, MSG_DONE);
- else
- talk_base::Thread::Current()->Post(NULL, MSG_DONE);
- }
- }
-
-private:
- bool server_, sending_;
- talk_base::scoped_ptr<talk_base::FileStream> file_;
- char buffer_[1024 * 64];
- size_t buffer_len_;
-};
-
-int main(int argc, char **argv) {
- talk_base::LogMessage::LogThreads();
- talk_base::LogMessage::LogTimestamps();
-
- // TODO: Default the username to the current users's name.
-
- // Parse the arguments.
-
- int index = 1;
- while (index < argc) {
- std::string name, value;
- if (!ParseArg(argv[index], &name, &value))
- break;
-
- if (name == "help") {
- Usage();
- } else if (name == "verbose") {
- talk_base::LogMessage::LogToDebug(talk_base::LS_VERBOSE);
- } else if (name == "xmpp-host") {
- gXmppHost = value;
- } else if (name == "xmpp-port") {
- gXmppPort = ParseIntArg(name, value);
- } else if (name == "xmpp-use-tls") {
- gXmppUseTls = ParseBoolArg(name, value)?
- buzz::TLS_REQUIRED : buzz::TLS_DISABLED;
- } else {
- Error(std::string("unknown option: ") + name);
- }
-
- index += 1;
- }
-
- if (index >= argc)
- Error("bad arguments");
- gUserJid = buzz::Jid(argv[index++]);
- if (!gUserJid.IsValid())
- Error("bad arguments");
-
- char path[MAX_PATH];
-#if WIN32
- GetCurrentDirectoryA(MAX_PATH, path);
-#else
- if (NULL == getcwd(path, MAX_PATH))
- Error("Unable to get current path");
-#endif
-
- std::cout << "Directory: " << std::string(path) << std::endl;
-
- buzz::Jid gSrcJid;
- buzz::Jid gDstJid;
- std::string gSrcFile;
- std::string gDstFile;
-
- bool as_server = true;
- if (index + 2 == argc) {
- ParseFileArg(argv[index], &gSrcJid, &gSrcFile);
- ParseFileArg(argv[index+1], &gDstJid, &gDstFile);
- if(gSrcJid.Str().empty() == gDstJid.Str().empty())
- Error("Exactly one of source JID or destination JID must be empty.");
- as_server = false;
- } else if (index != argc) {
- Error("bad arguments");
- }
-
- std::cout << "Password: ";
- SetConsoleEcho(false);
- std::cin >> gUserPass.password();
- SetConsoleEcho(true);
- std::cout << std::endl;
-
- talk_base::InitializeSSL();
- // Log in.
- CustomXmppPump pump;
- pump.client()->SignalLogInput.connect(&debug_log_, &DebugLog::Input);
- pump.client()->SignalLogOutput.connect(&debug_log_, &DebugLog::Output);
- pump.DoLogin(LoginSettings(), new buzz::XmppSocket(gXmppUseTls), 0);
- //new XmppAuth());
-
- // Wait until login succeeds.
- std::vector<uint32> ids;
- ids.push_back(MSG_LOGIN_COMPLETE);
- ids.push_back(MSG_LOGIN_FAILED);
- if (MSG_LOGIN_FAILED == Loop(ids))
- FatalError("Failed to connect");
-
- {
- talk_base::scoped_ptr<buzz::XmlElement> presence(
- new buzz::XmlElement(buzz::QN_PRESENCE));
- presence->AddElement(new buzz::XmlElement(buzz::QN_PRIORITY));
- presence->AddText("-1", 1);
- pump.SendStanza(presence.get());
- }
-
- std::string user_jid_str = pump.client()->jid().Str();
- std::cout << "Logged in as " << user_jid_str << std::endl;
-
- // Prepare the random number generator.
- talk_base::InitRandom(user_jid_str.c_str(), user_jid_str.size());
-
- // Create the P2P session manager.
- talk_base::BasicNetworkManager network_manager;
- AutoPortAllocator allocator(&network_manager, "pcp_agent");
- allocator.SetXmppClient(pump.client());
- cricket::SessionManager session_manager(&allocator);
-#ifdef USE_SSL_TUNNEL
- cricket::SecureTunnelSessionClient session_client(pump.client()->jid(),
- &session_manager);
- if (!session_client.GenerateIdentity())
- FatalError("Failed to generate SSL identity");
-#else // !USE_SSL_TUNNEL
- cricket::TunnelSessionClient session_client(pump.client()->jid(),
- &session_manager);
-#endif // USE_SSL_TUNNEL
- cricket::SessionManagerTask *receiver =
- new cricket::SessionManagerTask(pump.client(), &session_manager);
- receiver->EnableOutgoingMessages();
- receiver->Start();
-
- bool success = true;
-
- // Establish the appropriate connection.
- if (as_server) {
- pump.Serve(&session_client);
- } else {
- talk_base::StreamInterface* stream = NULL;
- std::string filename;
- bool sending;
- if (gSrcJid.Str().empty()) {
- std::string message("recv:");
- message.append(gDstFile);
- stream = session_client.CreateTunnel(gDstJid, message);
- filename = gSrcFile;
- sending = true;
- } else {
- std::string message("send:");
- message.append(gSrcFile);
- stream = session_client.CreateTunnel(gSrcJid, message);
- filename = gDstFile;
- sending = false;
- }
- success = pump.ProcessStream(stream, filename, sending);
- }
-
- if (success) {
- // Wait until the copy is done.
- ids.clear();
- ids.push_back(MSG_DONE);
- ids.push_back(MSG_LOGIN_FAILED);
- Loop(ids);
- }
-
- // Log out.
- pump.DoDisconnect();
-
- return 0;
-}
diff --git a/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/conductor.cc b/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/conductor.cc
index b35a054828b..bbab3d06e35 100644
--- a/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/conductor.cc
+++ b/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/conductor.cc
@@ -105,6 +105,7 @@ bool Conductor::InitializePeerConnection() {
peer_connection_ = peer_connection_factory_->CreatePeerConnection(servers,
NULL,
NULL,
+ NULL,
this);
if (!peer_connection_.get()) {
main_wnd_->MessageBox("Error",
diff --git a/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/linux/main.cc b/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/linux/main.cc
index aee1bb100d6..4ef81cdac72 100644
--- a/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/linux/main.cc
+++ b/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/linux/main.cc
@@ -32,6 +32,7 @@
#include "talk/examples/peerconnection/client/linux/main_wnd.h"
#include "talk/examples/peerconnection/client/peer_connection_client.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/thread.h"
class CustomSocketServer : public talk_base::PhysicalSocketServer {
@@ -94,6 +95,7 @@ int main(int argc, char* argv[]) {
CustomSocketServer socket_server(thread, &wnd);
thread->set_socketserver(&socket_server);
+ talk_base::InitializeSSL();
// Must be constructed after we set the socketserver.
PeerConnectionClient client;
talk_base::scoped_refptr<Conductor> conductor(
@@ -111,7 +113,7 @@ int main(int argc, char* argv[]) {
//while (gtk_events_pending()) {
// gtk_main_iteration();
//}
-
+ talk_base::CleanupSSL();
return 0;
}
diff --git a/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/main.cc b/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/main.cc
index bd0a5c3c17c..e68c78ef870 100644
--- a/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/main.cc
+++ b/chromium/third_party/libjingle/source/talk/examples/peerconnection/client/main.cc
@@ -28,6 +28,7 @@
#include "talk/examples/peerconnection/client/conductor.h"
#include "talk/examples/peerconnection/client/main_wnd.h"
#include "talk/examples/peerconnection/client/peer_connection_client.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/win32socketinit.h"
#include "talk/base/win32socketserver.h"
@@ -44,6 +45,7 @@ int PASCAL wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
return -1;
}
+ talk_base::InitializeSSL();
PeerConnectionClient client;
talk_base::scoped_refptr<Conductor> conductor(
new talk_base::RefCountedObject<Conductor>(&client, &wnd));
@@ -68,5 +70,6 @@ int PASCAL wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
}
}
+ talk_base::CleanupSSL();
return 0;
}
diff --git a/chromium/third_party/libjingle/source/talk/examples/peerconnection/peerconnection.scons b/chromium/third_party/libjingle/source/talk/examples/peerconnection/peerconnection.scons
deleted file mode 100644
index 7a7d2f3be95..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/peerconnection/peerconnection.scons
+++ /dev/null
@@ -1,64 +0,0 @@
-# -*- Python -*-
-import talk
-
-Import('env')
-
-if env.Bit('have_webrtc_voice') and env.Bit('have_webrtc_video'):
- talk.App(
- env,
- name = 'peerconnection_client',
- # TODO: Build peerconnection_client on mac.
- libs = [
- 'base',
- 'expat',
- 'json',
- 'p2p',
- 'peerconnection',
- 'phone',
- 'srtp',
- 'xmllite',
- 'xmpp',
- 'yuvscaler',
- ],
- win_srcs = [
- 'client/conductor.cc',
- 'client/defaults.cc',
- 'client/main.cc',
- 'client/main_wnd.cc',
- 'client/peer_connection_client.cc',
- ],
- posix_libs = [
- 'crypto',
- 'securetunnel',
- 'ssl',
- ],
- lin_srcs = [
- 'client/conductor.cc',
- 'client/defaults.cc',
- 'client/peer_connection_client.cc',
- 'client/linux/main.cc',
- 'client/linux/main_wnd.cc',
- ],
- lin_packages = [
- 'glib-2.0',
- 'gobject-2.0',
- 'gtk+-2.0',
- ],
- lin_libs = [
- 'sound',
- ],
- win_link_flags = [
- ('', '/nodefaultlib:libcmt')[env.Bit('debug')],
- ],
- )
-
- talk.App(
- env,
- name = 'peerconnection_server',
- srcs = [
- 'server/data_socket.cc',
- 'server/main.cc',
- 'server/peer_channel.cc',
- 'server/utils.cc',
- ],
- )
diff --git a/chromium/third_party/libjingle/source/talk/examples/plus/libjingleplus.cc b/chromium/third_party/libjingle/source/talk/examples/plus/libjingleplus.cc
deleted file mode 100644
index 4d27dfd120b..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/plus/libjingleplus.cc
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * libjingle
- * Copyright 2006, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <iostream>
-#include "libjingleplus.h"
-#ifdef WIN32
-#include "talk/base/win32socketserver.h"
-#endif
-#include "talk/base/physicalsocketserver.h"
-#include "talk/base/logging.h"
-#include "talk/examples/login/xmppauth.h"
-#include "talk/examples/login/xmppsocket.h"
-#include "talk/examples/login/xmpppump.h"
-#include "presencepushtask.h"
-#include "talk/app/status.h"
-#include "talk/app/message.h"
-#include "rostertask.h"
-#include "talk/app/iqtask.h"
-#include "talk/app/presenceouttask.h"
-#include "talk/app/receivemessagetask.h"
-#include "talk/app/rostersettask.h"
-#include "talk/app/sendmessagetask.h"
-
-enum {
- MSG_START,
-
- // main thread to worker
- MSG_LOGIN,
- MSG_DISCONNECT,
- MSG_SEND_PRESENCE,
- MSG_SEND_DIRECTED_PRESENCE,
- MSG_SEND_DIRECTED_MUC_PRESENCE,
- MSG_SEND_XMPP_MESSAGE,
- MSG_SEND_XMPP_IQ,
- MSG_UPDATE_ROSTER_ITEM,
- MSG_REMOVE_ROSTER_ITEM,
-
- // worker thread to main thread
- MSG_STATE_CHANGE,
- MSG_STATUS_UPDATE,
- MSG_STATUS_ERROR,
- MSG_ROSTER_REFRESH_STARTED,
- MSG_ROSTER_REFRESH_FINISHED,
- MSG_ROSTER_ITEM_UPDATED,
- MSG_ROSTER_ITEM_REMOVED,
- MSG_ROSTER_SUBSCRIBE,
- MSG_ROSTER_UNSUBSCRIBE,
- MSG_ROSTER_SUBSCRIBED,
- MSG_ROSTER_UNSUBSCRIBED,
- MSG_INCOMING_MESSAGE,
- MSG_IQ_COMPLETE,
- MSG_XMPP_INPUT,
- MSG_XMPP_OUTPUT
-};
-
-class LibjinglePlusWorker : public talk_base::MessageHandler,
- public XmppPumpNotify,
- public sigslot::has_slots<> {
- public:
- LibjinglePlusWorker(LibjinglePlus *ljp, LibjinglePlusNotify *notify) :
- worker_thread_(NULL), ljp_(ljp), notify_(notify),
- ppt_(NULL), rmt_(NULL), rt_(NULL), is_test_login_(false) {
-
- main_thread_.reset(new talk_base::AutoThread());
-#ifdef WIN32
- ss_.reset(new talk_base::Win32SocketServer(main_thread_.get()));
- main_thread_->set_socketserver(ss_.get());
-#endif
-
- pump_.reset(new XmppPump(this));
-
- pump_->client()->SignalLogInput.connect(this, &LibjinglePlusWorker::OnInputDebug);
- pump_->client()->SignalLogOutput.connect(this, &LibjinglePlusWorker::OnOutputDebug);
- //pump_->client()->SignalStateChange.connect(this, &LibjinglePlusWorker::OnStateChange);
- }
-
- ~LibjinglePlusWorker() {
- if (worker_thread_) {
- worker_thread_->Send(this, MSG_DISCONNECT);
- delete worker_thread_;
- }
- }
-
- virtual void OnMessage(talk_base::Message *msg) {
- switch (msg->message_id) {
- case MSG_START:
- LoginW();
- break;
- case MSG_DISCONNECT:
- DisconnectW();
- break;
- case MSG_SEND_XMPP_MESSAGE:
- SendXmppMessageW(static_cast<SendMessageData*>(msg->pdata)->m_);
- delete msg->pdata;
- break;
- case MSG_SEND_XMPP_IQ:
- SendXmppIqW(static_cast<SendIqData*>(msg->pdata)->to_jid_,
- static_cast<SendIqData*>(msg->pdata)->is_get_,
- static_cast<SendIqData*>(msg->pdata)->xml_element_);
- delete msg->pdata;
- break;
- case MSG_SEND_PRESENCE:
- SendPresenceW(static_cast<SendPresenceData*>(msg->pdata)->s_);
- delete msg->pdata;
- break;
- case MSG_SEND_DIRECTED_PRESENCE:
- SendDirectedPresenceW(static_cast<SendDirectedPresenceData*>(msg->pdata)->j_,
- static_cast<SendDirectedPresenceData*>(msg->pdata)->s_);
- delete msg->pdata;
- break;
- case MSG_SEND_DIRECTED_MUC_PRESENCE:
- SendDirectedMUCPresenceW(static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->j_,
- static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->s_,
- static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->un_,
- static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->ac_,
- static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->am_,
- static_cast<SendDirectedMUCPresenceData*>(msg->pdata)->role_);
- delete msg->pdata;
- break;
- case MSG_UPDATE_ROSTER_ITEM:
- UpdateRosterItemW(static_cast<UpdateRosterItemData*>(msg->pdata)->jid_,
- static_cast<UpdateRosterItemData*>(msg->pdata)->n_,
- static_cast<UpdateRosterItemData*>(msg->pdata)->g_,
- static_cast<UpdateRosterItemData*>(msg->pdata)->grt_);
- delete msg->pdata;
- break;
- case MSG_REMOVE_ROSTER_ITEM:
- RemoveRosterItemW(static_cast<JidData*>(msg->pdata)->jid_);
- delete msg->pdata;
- break;
-
-
-
-
- case MSG_STATUS_UPDATE:
- OnStatusUpdateW(static_cast<SendPresenceData*>(msg->pdata)->s_);
- delete msg->pdata;
- break;
- case MSG_STATUS_ERROR:
- OnStatusErrorW(static_cast<StatusErrorData*>(msg->pdata)->stanza_);
- delete msg->pdata;
- break;
- case MSG_STATE_CHANGE:
- OnStateChangeW(static_cast<StateChangeData*>(msg->pdata)->s_);
- delete msg->pdata;
- break;
- case MSG_ROSTER_REFRESH_STARTED:
- OnRosterRefreshStartedW();
- break;
- case MSG_ROSTER_REFRESH_FINISHED:
- OnRosterRefreshFinishedW();
- break;
- case MSG_ROSTER_ITEM_UPDATED:
- OnRosterItemUpdatedW(static_cast<RosterItemData*>(msg->pdata)->ri_);
- delete msg->pdata;
- break;
- case MSG_ROSTER_ITEM_REMOVED:
- OnRosterItemRemovedW(static_cast<RosterItemData*>(msg->pdata)->ri_);
- delete msg->pdata;
- break;
- case MSG_ROSTER_SUBSCRIBE:
- OnRosterSubscribeW(static_cast<JidData*>(msg->pdata)->jid_);
- delete msg->pdata;
- break;
- case MSG_ROSTER_UNSUBSCRIBE:
- OnRosterUnsubscribeW(static_cast<JidData*>(msg->pdata)->jid_);
- delete msg->pdata;
- break;
- case MSG_ROSTER_SUBSCRIBED:
- OnRosterSubscribedW(static_cast<JidData*>(msg->pdata)->jid_);
- delete msg->pdata;
- break;
- case MSG_ROSTER_UNSUBSCRIBED:
- OnRosterUnsubscribedW(static_cast<JidData*>(msg->pdata)->jid_);
- delete msg->pdata;
- break;
- case MSG_INCOMING_MESSAGE:
- OnIncomingMessageW(static_cast<XmppMessageData*>(msg->pdata)->m_);
- delete msg->pdata;
- break;
- case MSG_IQ_COMPLETE:
- OnIqCompleteW(static_cast<IqCompleteData*>(msg->pdata)->success_,
- static_cast<IqCompleteData*>(msg->pdata)->stanza_);
- delete msg->pdata;
- break;
- case MSG_XMPP_OUTPUT:
- OnOutputDebugW(static_cast<StringData*>(msg->pdata)->s_);
- delete msg->pdata;
- break;
- case MSG_XMPP_INPUT:
- OnInputDebugW(static_cast<StringData*>(msg->pdata)->s_);
- delete msg->pdata;
- break;
- }
- }
-
- void Login(const std::string &jid, const std::string &password,
- const std::string &machine_address, bool is_test, bool cookie_auth) {
- is_test_login_ = is_test;
-
- xcs_.set_user(jid);
- if (cookie_auth) {
- xcs_.set_auth_cookie(password);
- } else {
- talk_base::InsecureCryptStringImpl pass;
- pass.password() = password;
- xcs_.set_pass(talk_base::CryptString(pass));
- }
- xcs_.set_host(is_test ? "google.com" : "gmail.com");
- xcs_.set_resource("libjingleplus");
- xcs_.set_server(talk_base::SocketAddress(machine_address, 5222));
- xcs_.set_use_tls(!is_test);
- if (is_test) {
- xcs_.set_allow_plain(true);
- }
-
- worker_thread_ = new talk_base::Thread(&pss_);
- worker_thread_->Start();
- worker_thread_->Send(this, MSG_START);
- }
-
- void SendXmppMessage(const buzz::XmppMessage &m) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- worker_thread_->Post(this, MSG_SEND_XMPP_MESSAGE, new SendMessageData(m));
- }
-
- void SendXmppIq(const buzz::Jid &to_jid, bool is_get,
- const buzz::XmlElement *xml_element) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- worker_thread_->Post(this, MSG_SEND_XMPP_IQ,
- new SendIqData(to_jid, is_get, xml_element));
- }
-
- void SendPresence(const buzz::Status & s) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- worker_thread_->Post(this, MSG_SEND_PRESENCE, new SendPresenceData(s));
- }
-
- void SendDirectedPresence (const buzz::Jid &j, const buzz::Status &s) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- worker_thread_->Post(this, MSG_SEND_DIRECTED_PRESENCE, new SendDirectedPresenceData(j,s));
- }
-
- void SendDirectedMUCPresence(const buzz::Jid &j, const buzz::Status &s,
- const std::string &un, const std::string &ac,
- const std::string &am, const std::string &role) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- worker_thread_->Post(this, MSG_SEND_DIRECTED_MUC_PRESENCE, new SendDirectedMUCPresenceData(j,s,un,ac,am, role));
- }
-
- void UpdateRosterItem(const buzz::Jid & jid, const std::string & name,
- const std::vector<std::string> & groups, buzz::GrType grt) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- worker_thread_->Post(this, MSG_UPDATE_ROSTER_ITEM, new UpdateRosterItemData(jid,name,groups,grt));
- }
-
- void RemoveRosterItemW(const buzz::Jid &jid) {
- buzz::RosterSetTask *rst = new buzz::RosterSetTask(pump_.get()->client());
- rst->Remove(jid);
- rst->Start();
- }
-
- void RemoveRosterItem(const buzz::Jid &jid) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- worker_thread_->Post(this, MSG_REMOVE_ROSTER_ITEM, new JidData(jid));
- }
-
- void DoCallbacks() {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- talk_base::Message m;
- while (main_thread_->Get(&m, 0)) {
- main_thread_->Dispatch(&m);
- }
- }
-
- private:
-
- struct UpdateRosterItemData : public talk_base::MessageData {
- UpdateRosterItemData(const buzz::Jid &jid, const std::string &name,
- const std::vector<std::string> &groups, buzz::GrType grt) :
- jid_(jid), n_(name), g_(groups), grt_(grt) {}
- buzz::Jid jid_;
- std::string n_;
- std::vector<std::string> g_;
- buzz::GrType grt_;
- };
-
- void UpdateRosterItemW(const buzz::Jid &jid, const std::string &name,
- const std::vector<std::string> &groups, buzz::GrType grt) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- buzz::RosterSetTask *rst = new buzz::RosterSetTask(pump_.get()->client());
- rst->Update(jid, name, groups, grt);
- rst->Start();
- }
-
- struct StringData : public talk_base::MessageData {
- StringData(std::string s) : s_(s) {}
- std::string s_;
- };
-
- void OnInputDebugW(const std::string &data) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnXmppInput(data);
- }
-
- void OnInputDebug(const char *data, int len) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_XMPP_INPUT, new StringData(std::string(data,len)));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void OnOutputDebugW(const std::string &data) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnXmppOutput(data);
- }
-
- void OnOutputDebug(const char *data, int len) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_XMPP_OUTPUT, new StringData(std::string(data,len)));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- struct StateChangeData : public talk_base::MessageData {
- StateChangeData(buzz::XmppEngine::State state) : s_(state) {}
- buzz::XmppEngine::State s_;
- };
-
- void OnStateChange(buzz::XmppEngine::State state) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- switch (state) {
- case buzz::XmppEngine::STATE_OPEN:
- ppt_ = new buzz::PresencePushTask(pump_.get()->client());
- ppt_->SignalStatusUpdate.connect(this,
- &LibjinglePlusWorker::OnStatusUpdate);
- ppt_->SignalStatusError.connect(this,
- &LibjinglePlusWorker::OnStatusError);
- ppt_->Start();
-
- rmt_ = new buzz::ReceiveMessageTask(pump_.get()->client(), buzz::XmppEngine::HL_ALL);
- rmt_->SignalIncomingMessage.connect(this, &LibjinglePlusWorker::OnIncomingMessage);
- rmt_->Start();
-
- rt_ = new buzz::RosterTask(pump_.get()->client());
- rt_->SignalRosterItemUpdated.connect(this, &LibjinglePlusWorker::OnRosterItemUpdated);
- rt_->SignalRosterItemRemoved.connect(this, &LibjinglePlusWorker::OnRosterItemRemoved);
- rt_->SignalSubscribe.connect(this, &LibjinglePlusWorker::OnRosterSubscribe);
- rt_->SignalUnsubscribe.connect(this, &LibjinglePlusWorker::OnRosterUnsubscribe);
- rt_->SignalSubscribed.connect(this, &LibjinglePlusWorker::OnRosterSubscribed);
- rt_->SignalUnsubscribed.connect(this, &LibjinglePlusWorker::OnRosterUnsubscribed);
- rt_->SignalRosterRefreshStarted.connect(this, &LibjinglePlusWorker::OnRosterRefreshStarted);
- rt_->SignalRosterRefreshFinished.connect(this, &LibjinglePlusWorker::OnRosterRefreshFinished);
- rt_->Start();
- rt_->RefreshRosterNow();
-
- break;
- }
- main_thread_->Post(this, MSG_STATE_CHANGE, new StateChangeData(state));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void OnStateChangeW(buzz::XmppEngine::State state) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnStateChange(state);
- }
-
- struct RosterItemData : public talk_base::MessageData {
- RosterItemData(const buzz::RosterItem &ri) : ri_(ri) {}
- buzz::RosterItem ri_;
- };
-
- void OnRosterItemUpdatedW(const buzz::RosterItem &ri) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnRosterItemUpdated(ri);
- }
-
- void OnRosterItemUpdated(const buzz::RosterItem &ri, bool huh) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_ROSTER_ITEM_UPDATED, new RosterItemData(ri));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void OnRosterItemRemovedW(const buzz::RosterItem &ri) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnRosterItemRemoved(ri);
- }
-
- void OnRosterItemRemoved(const buzz::RosterItem &ri) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_ROSTER_ITEM_REMOVED, new RosterItemData(ri));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- struct JidData : public talk_base::MessageData {
- JidData(const buzz::Jid& jid) : jid_(jid) {}
- const buzz::Jid jid_;
- };
-
- void OnRosterSubscribeW(const buzz::Jid& jid) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnRosterSubscribe(jid);
- }
-
- void OnRosterSubscribe(const buzz::Jid& jid) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_ROSTER_SUBSCRIBE, new JidData(jid));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void OnRosterUnsubscribeW(const buzz::Jid &jid) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnRosterUnsubscribe(jid);
- }
-
- void OnRosterUnsubscribe(const buzz::Jid &jid) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_ROSTER_UNSUBSCRIBE, new JidData(jid));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void OnRosterSubscribedW(const buzz::Jid &jid) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnRosterSubscribed(jid);
- }
-
- void OnRosterSubscribed(const buzz::Jid &jid) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_ROSTER_SUBSCRIBED, new JidData(jid));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void OnRosterUnsubscribedW(const buzz::Jid &jid) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnRosterUnsubscribed(jid);
- }
-
- void OnRosterUnsubscribed(const buzz::Jid &jid) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_ROSTER_UNSUBSCRIBED, new JidData(jid));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void OnRosterRefreshStartedW() {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnRosterRefreshStarted();
- }
-
- void OnRosterRefreshStarted() {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_ROSTER_REFRESH_STARTED);
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void OnRosterRefreshFinishedW() {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnRosterRefreshFinished();
- }
-
- void OnRosterRefreshFinished() {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_ROSTER_REFRESH_FINISHED);
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- struct XmppMessageData : talk_base::MessageData {
- XmppMessageData(const buzz::XmppMessage &m) : m_(m) {}
- buzz::XmppMessage m_;
- };
-
- void OnIncomingMessageW(const buzz::XmppMessage &msg) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnMessage(msg);
- }
-
- void OnIncomingMessage(const buzz::XmppMessage &msg) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_INCOMING_MESSAGE, new XmppMessageData(msg));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void OnStatusUpdateW (const buzz::Status &status) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnStatusUpdate(status);
- }
-
- void OnStatusUpdate (const buzz::Status &status) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_STATUS_UPDATE, new SendPresenceData(status));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- struct StatusErrorData : talk_base::MessageData {
- StatusErrorData(const buzz::XmlElement &stanza) : stanza_(stanza) {}
- buzz::XmlElement stanza_;
- };
-
- void OnStatusErrorW (const buzz::XmlElement &stanza) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnStatusError(stanza);
- }
-
- void OnStatusError (const buzz::XmlElement &stanza) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_STATUS_ERROR, new StatusErrorData(stanza));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void LoginW() {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- XmppSocket* socket = new XmppSocket(true);
- pump_->DoLogin(xcs_, socket, is_test_login_ ? NULL : new XmppAuth());
- socket->SignalCloseEvent.connect(this,
- &LibjinglePlusWorker::OnXmppSocketClose);
- }
-
- void DisconnectW() {
- assert(talk_base::ThreadManager::CurrentThread() == worker_thread_);
- pump_->DoDisconnect();
- }
-
- void SendXmppMessageW(const buzz::XmppMessage &m) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- buzz::SendMessageTask * smt = new buzz::SendMessageTask(pump_.get()->client());
- smt->Send(m);
- smt->Start();
- }
-
- void SendXmppIqW(const buzz::Jid &to_jid, bool is_get,
- const buzz::XmlElement *xml_element) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- buzz::IqTask *iq_task = new buzz::IqTask(pump_.get()->client(),
- is_get, to_jid, const_cast<buzz::XmlElement *>(xml_element));
- iq_task->SignalDone.connect(this, &LibjinglePlusWorker::OnIqComplete);
- iq_task->Start();
- }
-
- struct IqCompleteData : public talk_base::MessageData {
- IqCompleteData(bool success, const buzz::XmlElement *stanza) :
- success_(success), stanza_(*stanza) {}
- bool success_;
- buzz::XmlElement stanza_;
- };
-
- void OnIqCompleteW(bool success, const buzz::XmlElement& stanza) {
- assert(talk_base::ThreadManager::CurrentThread() != worker_thread_);
- if (notify_)
- notify_->OnIqDone(success, stanza);
- }
-
- void OnIqComplete(bool success, const buzz::XmlElement *stanza) {
- assert(talk_base::ThreadManager::CurrentThread() == worker_thread_);
- main_thread_->Post(this, MSG_IQ_COMPLETE,
- new IqCompleteData(success, stanza));
- if (notify_)
- notify_->WakeupMainThread();
- }
-
- void SendPresenceW(const buzz::Status & s) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- buzz::PresenceOutTask *pot = new buzz::PresenceOutTask(pump_.get()->client());
- pot->Send(s);
- pot->Start();
- }
-
-
- void SendDirectedMUCPresenceW(const buzz::Jid & j, const buzz::Status & s,
- const std::string &user_nick, const std::string &api_capability,
- const std::string &api_message, const std::string &role) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- buzz::PresenceOutTask *pot = new buzz::PresenceOutTask(pump_.get()->client());
- pot->SendDirectedMUC(j,s,user_nick,api_capability,api_message, role);
- pot->Start();
- }
-
- void SendDirectedPresenceW(const buzz::Jid & j, const buzz::Status & s) {
- assert (talk_base::ThreadManager::CurrentThread() == worker_thread_);
- buzz::PresenceOutTask *pot = new buzz::PresenceOutTask(pump_.get()->client());
- pot->SendDirected(j,s);
- pot->Start();
- }
-
- void OnXmppSocketClose(int error) {
- notify_->OnSocketClose(error);
- }
-
- struct SendMessageData : public talk_base::MessageData {
- SendMessageData(const buzz::XmppMessage &m) : m_(m) {}
- buzz::XmppMessage m_;
- };
-
- struct SendIqData : public talk_base::MessageData {
- SendIqData(const buzz::Jid &jid, bool is_get, const buzz::XmlElement *m)
- : to_jid_(jid), is_get_(is_get), xml_element_(m) {}
- buzz::Jid to_jid_;
- bool is_get_;
- const buzz::XmlElement *xml_element_;
- };
-
- struct SendPresenceData : public talk_base::MessageData {
- SendPresenceData(const buzz::Status &s) : s_(s) {}
- buzz::Status s_;
- };
-
- struct SendDirectedPresenceData : public talk_base::MessageData {
- SendDirectedPresenceData(const buzz::Jid &j, const buzz::Status &s) : j_(j), s_(s) {}
- buzz::Jid j_;
- buzz::Status s_;
- };
-
- struct SendDirectedMUCPresenceData : public talk_base::MessageData {
- SendDirectedMUCPresenceData(const buzz::Jid &j, const buzz::Status &s,
- const std::string &un, const std::string &ac,
- const std::string &am, const std::string &role)
- : j_(j), s_(s), un_(un), ac_(ac), am_(am), role_(role) {}
- buzz::Jid j_;
- buzz::Status s_;
- std::string un_;
- std::string ac_;
- std::string am_;
- std::string role_;
- };
-
- talk_base::scoped_ptr<talk_base::Win32SocketServer> ss_;
- talk_base::scoped_ptr<talk_base::Thread> main_thread_;
- talk_base::Thread *worker_thread_;
-
- LibjinglePlus *ljp_;
- LibjinglePlusNotify *notify_;
- buzz::XmppClientSettings xcs_;
- talk_base::PhysicalSocketServer pss_;
-
- talk_base::scoped_ptr<XmppPump> pump_;
- buzz::PresencePushTask * ppt_;
- buzz::ReceiveMessageTask * rmt_;
- buzz::RosterTask * rt_;
-
- bool is_test_login_;
-};
-
-LibjinglePlus::LibjinglePlus(LibjinglePlusNotify *notify)
-{
- worker_ = new LibjinglePlusWorker(this, notify);
-}
-
-LibjinglePlus::~LibjinglePlus()
-{
- delete worker_;
- worker_ = NULL;
-}
-
-void LibjinglePlus::Login(const std::string &jid,
- const std::string &password,
- const std::string &machine_address,
- bool is_test, bool cookie_auth) {
- worker_->Login(jid, password, machine_address, is_test, cookie_auth);
-}
-
-void LibjinglePlus::SendPresence(const buzz::Status & s) {
- worker_->SendPresence(s);
-}
-
-void LibjinglePlus::SendDirectedPresence(const buzz::Jid & j, const buzz::Status & s) {
- worker_->SendDirectedPresence(j,s);
-}
-
-void LibjinglePlus::SendDirectedMUCPresence(const buzz::Jid & j,
- const buzz::Status & s, const std::string &user_nick,
- const std::string &api_capability, const std::string &api_message,
- const std::string &role) {
- worker_->SendDirectedMUCPresence(j,s,user_nick,api_capability,api_message,
- role);
-}
-
-void LibjinglePlus::SendXmppMessage(const buzz::XmppMessage & m) {
- worker_->SendXmppMessage(m);
-}
-
-void LibjinglePlus::SendXmppIq(const buzz::Jid &to_jid, bool is_get,
- const buzz::XmlElement *iq_element) {
- worker_->SendXmppIq(to_jid, is_get, iq_element);
-}
-
-void LibjinglePlus::DoCallbacks() {
- worker_->DoCallbacks();
-}
diff --git a/chromium/third_party/libjingle/source/talk/examples/plus/libjingleplus.h b/chromium/third_party/libjingle/source/talk/examples/plus/libjingleplus.h
deleted file mode 100644
index a2898f51a3f..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/plus/libjingleplus.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * libjingle
- * Copyright 2006, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// LibjinglePlus is a class that connects to Google Talk, creates
-// some common tasks, and emits signals when things change
-
-#ifndef LIBJINGLEPLUS_H__
-#define LIBJINGLEPLUS_H__
-
-#include "talk/base/basicdefs.h"
-#include "talk/app/rosteritem.h"
-#include "talk/app/message.h"
-#include "talk/app/status.h"
-#include "talk/xmpp/xmppengine.h"
-#include "talk/base/scoped_ptr.h"
-
-
-class LibjinglePlusWorker;
-
-class LibjinglePlusNotify {
- public:
- virtual ~LibjinglePlusNotify() {}
-
- /* Libjingle+ works on its own thread. It will call WakeupMainThread
- * when it has something to report. The main thread should then wake up,
- * and call DoCallbacks on the LibjinglePlus object.
- *
- * This function gets called from libjingle+'s worker thread. All other
- * methods in LibjinglePlusNotify get called from the thread you call
- * DoCallbacks() on.
- *
- * If running on Windows, libjingle+ will use Windows messages to generate
- * callbacks from the main thread, and you don't need to do anything here.
- */
- virtual void WakeupMainThread() = 0;
-
- /* Connection */
- /* Called when the connection state changes */
- virtual void OnStateChange(buzz::XmppEngine::State) = 0;
-
- /* Called when the socket closes */
- virtual void OnSocketClose(int error_code) = 0;
-
- /* Called when XMPP is being sent or received. Used for debugging */
- virtual void OnXmppOutput(const std::string &output) = 0;
- virtual void OnXmppInput(const std::string &input) = 0;
-
- /* Presence */
- /* Called when someone's Status is updated */
- virtual void OnStatusUpdate(const buzz::Status &status) = 0;
-
- /* Called when a status update results in an error */
- virtual void OnStatusError(const buzz::XmlElement &stanza) = 0;
-
- /* Called with an IQ return code */
- virtual void OnIqDone(bool success, const buzz::XmlElement &stanza) = 0;
-
- /* Message */
- /* Called when a message comes in. */
- virtual void OnMessage(const buzz::XmppMessage &message) = 0;
-
- /* Roster */
-
- /* Called when we start refreshing the roster */
- virtual void OnRosterRefreshStarted() = 0;
- /* Called when we have the entire roster */
- virtual void OnRosterRefreshFinished() = 0;
- /* Called when an item on the roster is created or updated */
- virtual void OnRosterItemUpdated(const buzz::RosterItem &ri) = 0;
- /* Called when an item on the roster is removed */
- virtual void OnRosterItemRemoved(const buzz::RosterItem &ri) = 0;
-
- /* Subscriptions */
- virtual void OnRosterSubscribe(const buzz::Jid &jid) = 0;
- virtual void OnRosterUnsubscribe(const buzz::Jid &jid) = 0;
- virtual void OnRosterSubscribed(const buzz::Jid &jid) = 0;
- virtual void OnRosterUnsubscribed(const buzz::Jid &jid) = 0;
-
-};
-
-class LibjinglePlus
-{
- public:
- /* Provide the constructor with your interface. */
- LibjinglePlus(LibjinglePlusNotify *notify);
- ~LibjinglePlus();
-
- /* Logs in and starts doing stuff
- *
- * If cookie_auth is true, password must be a Gaia SID. Otherwise,
- * it should be the user's password
- */
- void Login(const std::string &username, const std::string &password,
- const std::string &machine_address, bool is_test, bool cookie_auth);
-
- /* Set Presence */
- void SendPresence(const buzz::Status & s);
- void SendDirectedPresence(const buzz::Jid & j, const buzz::Status & s);
- void SendDirectedMUCPresence(const buzz::Jid & j, const buzz::Status & s,
- const std::string &user_nick, const std::string &api_capability,
- const std::string &api_message, const std::string &role);
-
- /* Send Message */
- void SendXmppMessage(const buzz::XmppMessage & m);
-
- /* Send IQ */
- void SendXmppIq(const buzz::Jid &to_jid, bool is_get,
- const buzz::XmlElement *iq_element);
-
- /* Set Roster */
- void UpdateRosterItem(const buzz::Jid & jid, const std::string & name,
- const std::vector<std::string> & groups, buzz::GrType grt);
- void RemoveRosterItem(const buzz::Jid &jid);
-
- /* Call this from the thread you want to receive callbacks on. Typically, this will be called
- * after your WakeupMainThread() notify function is called.
- *
- * On Windows, libjingle+ will trigger its callback from the Windows message loop, and
- * you needn't call this yourself.
- */
- void DoCallbacks();
-
- private:
- void LoginInternal(const std::string &jid, const std::string &password,
- const std::string &machine_address, bool is_test);
-
- LibjinglePlusWorker *worker_;
-};
-
-#endif // LIBJINGLE_PLUS_H__
diff --git a/chromium/third_party/libjingle/source/talk/examples/plus/presencepushtask.cc b/chromium/third_party/libjingle/source/talk/examples/plus/presencepushtask.cc
deleted file mode 100644
index 9d5ed28db7e..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/plus/presencepushtask.cc
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * libjingle
- * Copyright 2004--2005, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "talk/base/stringencode.h"
-#include "presencepushtask.h"
-#include "talk/xmpp/constants.h"
-#include <sstream>
-
-
-namespace buzz {
-
-// string helper functions -----------------------------------------------------
-
-static bool
-IsXmlSpace(int ch) {
- return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
-}
-
-static bool
-ListContainsToken(const std::string & list, const std::string & token) {
- size_t i = list.find(token);
- if (i == std::string::npos || token.empty())
- return false;
- bool boundary_before = (i == 0 || IsXmlSpace(list[i - 1]));
- bool boundary_after = (i == list.length() - token.length() || IsXmlSpace(list[i + token.length()]));
- return boundary_before && boundary_after;
-}
-
-
-bool
-PresencePushTask::HandleStanza(const XmlElement * stanza) {
- if (stanza->Name() != QN_PRESENCE)
- return false;
- if (stanza->HasAttr(QN_TYPE) && stanza->Attr(QN_TYPE) != STR_UNAVAILABLE) {
- if (stanza->Attr(QN_TYPE) == STR_ERROR) {
- // Pass on the error.
- const XmlElement* error_xml_elem = stanza->FirstNamed(QN_ERROR);
- if (!error_xml_elem) {
- return false;
- }
- SignalStatusError(*error_xml_elem);
- return true;
- }
- }
- QueueStanza(stanza);
- return true;
-}
-
-static bool IsUtf8FirstByte(int c) {
- return (((c)&0x80)==0) || // is single byte
- ((unsigned char)((c)-0xc0)<0x3e); // or is lead byte
-}
-
-int
-PresencePushTask::ProcessStart() {
- const XmlElement * stanza = NextStanza();
- if (stanza == NULL)
- return STATE_BLOCKED;
- Status s;
-
- s.set_jid(Jid(stanza->Attr(QN_FROM)));
-
- if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) {
- s.set_available(false);
- SignalStatusUpdate(s);
- }
- else {
- s.set_available(true);
- const XmlElement * status = stanza->FirstNamed(QN_STATUS);
- if (status != NULL) {
- s.set_status(status->BodyText());
-
- // Truncate status messages longer than 300 bytes
- if (s.status().length() > 300) {
- size_t len = 300;
-
- // Be careful not to split legal utf-8 chars in half
- while (!IsUtf8FirstByte(s.status()[len]) && len > 0) {
- len -= 1;
- }
- std::string truncated(s.status(), 0, len);
- s.set_status(truncated);
- }
- }
-
- const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY);
- if (priority != NULL) {
- int pri;
- if (talk_base::FromString(priority->BodyText(), &pri)) {
- s.set_priority(pri);
- }
- }
-
- const XmlElement * show = stanza->FirstNamed(QN_SHOW);
- if (show == NULL || show->FirstChild() == NULL) {
- s.set_show(Status::SHOW_ONLINE);
- }
- else {
- if (show->BodyText() == "away") {
- s.set_show(Status::SHOW_AWAY);
- }
- else if (show->BodyText() == "xa") {
- s.set_show(Status::SHOW_XA);
- }
- else if (show->BodyText() == "dnd") {
- s.set_show(Status::SHOW_DND);
- }
- else if (show->BodyText() == "chat") {
- s.set_show(Status::SHOW_CHAT);
- }
- else {
- s.set_show(Status::SHOW_ONLINE);
- }
- }
-
- const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C);
- if (caps != NULL) {
- std::string node = caps->Attr(QN_NODE);
- std::string ver = caps->Attr(QN_VER);
- std::string exts = caps->Attr(QN_EXT);
-
- s.set_know_capabilities(true);
- std::string capability;
- std::stringstream ss(exts);
- while (ss >> capability) {
- s.AddCapability(capability);
- }
-
- s->set_caps_node(node);
- s->set_version(ver);
- }
-
- const XmlElement* delay = stanza->FirstNamed(kQnDelayX);
- if (delay != NULL) {
- // Ideally we would parse this according to the Psuedo ISO-8601 rules
- // that are laid out in JEP-0082:
- // http://www.jabber.org/jeps/jep-0082.html
- std::string stamp = delay->Attr(kQnStamp);
- s.set_sent_time(stamp);
- }
-
- const XmlElement *nick = stanza->FirstNamed(kQnNickname);
- if (nick) {
- std::string user_nick = nick->BodyText();
- s.set_user_nick(user_nick);
- }
-
- const XmlElement *plugin = stanza->FirstNamed(QN_PLUGIN);
- if (plugin) {
- const XmlElement *api_cap = plugin->FirstNamed(QN_CAPABILITY);
- if (api_cap) {
- const std::string &api_capability = api_cap->BodyText();
- s.set_api_capability(api_capability);
- }
- const XmlElement *api_msg = plugin->FirstNamed(QN_DATA);
- if (api_msg) {
- const std::string &api_message = api_msg->BodyText();
- s.set_api_message(api_message);
- }
- }
-
- const XmlElement* data_x = stanza->FirstNamed(QN_MUC_USER_X);
- if (data_x != NULL) {
- const XmlElement* item = data_x->FirstNamed(QN_MUC_USER_ITEM);
- if (item != NULL) {
- s.set_muc_role(item->Attr(QN_ROLE));
- }
- }
-
- SignalStatusUpdate(s);
- }
-
- return STATE_START;
-}
-
-
-}
diff --git a/chromium/third_party/libjingle/source/talk/examples/plus/rostertask.cc b/chromium/third_party/libjingle/source/talk/examples/plus/rostertask.cc
deleted file mode 100644
index 1344d08316d..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/plus/rostertask.cc
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * libjingle
- * Copyright 2004--2005, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "rostertask.h"
-#include "talk/xmpp/constants.h"
-#include "talk/base/stream.h"
-
-#undef WIN32
-#ifdef WIN32
-#include "talk/app/win32/offlineroster.h"
-#endif
-
-namespace buzz {
-
-class RosterTask::RosterGetTask : public XmppTask {
-public:
- RosterGetTask(Task * parent) : XmppTask(parent, XmppEngine::HL_SINGLE),
- done_(false) {}
-
- virtual int ProcessStart();
- virtual int ProcessResponse();
-
-protected:
- virtual bool HandleStanza(const XmlElement * stanza);
-
- bool done_;
-};
-
-//==============================================================================
-// RosterTask
-//==============================================================================
-void RosterTask::RefreshRosterNow() {
- RosterGetTask* get_task = new RosterGetTask(this);
- ResumeTimeout();
- get_task->Start();
-}
-
-void RosterTask::TranslateItems(const XmlElement * rosterQueryResult) {
-#if defined(FEATURE_ENABLE_PSTN)
-#ifdef WIN32
- // We build up a list of contacts which have had information persisted offline.
- // we'll remove items from this list if we get a buzz::SUBSCRIBE_REMOVE
- // subscription. After updating all the items from the server, we'll then
- // update (and merge) any roster items left in our map of offline items
- XmlElement *el_local = OfflineRoster::RetrieveOfflineRoster(GetClient()->jid());
- std::map<buzz::Jid, RosterItem> jid_to_item;
- if (el_local) {
- for (XmlElement *el_item = el_local->FirstNamed(QN_ROSTER_ITEM);
- el_item != NULL;
- el_item = el_item->NextNamed(QN_ROSTER_ITEM)) {
- RosterItem roster_item;
- roster_item.FromXml(el_item);
-
- jid_to_item[roster_item.jid()] = roster_item;
- }
- }
-#endif // WIN32
-#endif // FEATURE_ENABLE_PSTN
-
- const XmlElement * xml_item;
- for (xml_item = rosterQueryResult->FirstNamed(QN_ROSTER_ITEM);
- xml_item != NULL; xml_item = xml_item->NextNamed(QN_ROSTER_ITEM)) {
- RosterItem roster_item;
- roster_item.FromXml(xml_item);
-
- if (roster_item.subscription() == buzz::SUBSCRIBE_REMOVE) {
- SignalRosterItemRemoved(roster_item);
-
-#if defined(FEATURE_ENABLE_PSTN)
-#ifdef WIN32
- std::map<buzz::Jid, RosterItem>::iterator it =
- jid_to_item.find(roster_item.jid());
-
- if (it != jid_to_item.end())
- jid_to_item.erase(it);
-#endif
-#endif
- } else {
- SignalRosterItemUpdated(roster_item, false);
- }
- }
-
-#if defined(FEATURE_ENABLE_PSTN)
-#ifdef WIN32
- for (std::map<buzz::Jid, RosterItem>::iterator it = jid_to_item.begin();
- it != jid_to_item.end(); ++it) {
- SignalRosterItemUpdated(it->second, true);
- }
-#endif
-#endif
-}
-
-int RosterTask::ProcessStart() {
- const XmlElement * stanza = NextStanza();
- if (stanza == NULL)
- return STATE_BLOCKED;
-
- if (stanza->Name() == QN_IQ) {
- SuspendTimeout();
- bool result = (stanza->Attr(QN_TYPE) == STR_RESULT);
- if (result)
- SignalRosterRefreshStarted();
-
- TranslateItems(stanza->FirstNamed(QN_ROSTER_QUERY));
-
- if (result)
- SignalRosterRefreshFinished();
- } else if (stanza->Name() == QN_PRESENCE) {
- Jid jid(stanza->Attr(QN_FROM));
- std::string type = stanza->Attr(QN_TYPE);
- if (type == "subscribe")
- SignalSubscribe(jid);
- else if (type == "unsubscribe")
- SignalUnsubscribe(jid);
- else if (type == "subscribed")
- SignalSubscribed(jid);
- else if (type == "unsubscribed")
- SignalUnsubscribed(jid);
- }
-
- return STATE_START;
-}
-
-bool RosterTask::HandleStanza(const XmlElement * stanza) {
- if (!MatchRequestIq(stanza, STR_SET, QN_ROSTER_QUERY)) {
- // Not a roster IQ. Look for a presence instead
- if (stanza->Name() != QN_PRESENCE)
- return false;
- if (!stanza->HasAttr(QN_TYPE))
- return false;
- std::string type = stanza->Attr(QN_TYPE);
- if (type == "subscribe" || type == "unsubscribe" ||
- type == "subscribed" || type == "unsubscribed") {
- QueueStanza(stanza);
- return true;
- }
- return false;
- }
-
- // only respect roster push from the server
- Jid from(stanza->Attr(QN_FROM));
- if (from != JID_EMPTY &&
- !from.BareEquals(GetClient()->jid()) &&
- from != Jid(GetClient()->jid().domain()))
- return false;
-
- XmlElement * result = MakeIqResult(stanza);
- result->AddElement(new XmlElement(QN_ROSTER_QUERY, true));
- SendStanza(result);
-
- QueueStanza(stanza);
- return true;
-}
-
-
-//==============================================================================
-// RosterTask::RosterGetTask
-//==============================================================================
-int RosterTask::RosterGetTask::ProcessStart() {
- talk_base::scoped_ptr<XmlElement> get(MakeIq(STR_GET, JID_EMPTY, task_id()));
- get->AddElement(new XmlElement(QN_ROSTER_QUERY, true));
- get->AddAttr(QN_XMLNS_GR, NS_GR, 1);
- get->AddAttr(QN_GR_EXT, "2", 1);
- get->AddAttr(QN_GR_INCLUDE, "all", 1);
- if (SendStanza(get.get()) != XMPP_RETURN_OK) {
- return STATE_ERROR;
- }
- return STATE_RESPONSE;
-}
-
-int RosterTask::RosterGetTask::ProcessResponse() {
- if (done_)
- return STATE_DONE;
- return STATE_BLOCKED;
-}
-
-bool RosterTask::RosterGetTask::HandleStanza(const XmlElement * stanza) {
- if (!MatchResponseIq(stanza, JID_EMPTY, task_id()))
- return false;
-
- if (stanza->Attr(QN_TYPE) != STR_RESULT)
- return false;
-
- // Queue the stanza with the parent so these don't get handled out of order
- RosterTask* parent = static_cast<RosterTask*>(GetParent());
- parent->QueueStanza(stanza);
-
- // Wake ourselves so we can go into the done state
- done_ = true;
- Wake();
- return true;
-}
-
-}
diff --git a/chromium/third_party/libjingle/source/talk/examples/plus/rostertask.h b/chromium/third_party/libjingle/source/talk/examples/plus/rostertask.h
deleted file mode 100644
index beab1f9a5e8..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/plus/rostertask.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * libjingle
- * Copyright 2004--2005, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _PHONE_CLIENT_ROSTERTASK_H_
-#define _PHONE_CLIENT_ROSTERTASK_H_
-
-#include "talk/xmpp/xmppclient.h"
-#include "talk/xmpp/xmpptask.h"
-#include "talk/app/rosteritem.h"
-#include "talk/base/sigslot.h"
-
-namespace buzz {
-
-class RosterTask : public XmppTask {
-public:
- RosterTask(Task * parent) :
- XmppTask(parent, XmppEngine::HL_TYPE) {}
-
- // Roster items removed or updated. This can come from a push or a get
- sigslot::signal2<const RosterItem &, bool> SignalRosterItemUpdated;
- sigslot::signal1<const RosterItem &> SignalRosterItemRemoved;
-
- // Subscription messages
- sigslot::signal1<const Jid &> SignalSubscribe;
- sigslot::signal1<const Jid &> SignalUnsubscribe;
- sigslot::signal1<const Jid &> SignalSubscribed;
- sigslot::signal1<const Jid &> SignalUnsubscribed;
-
- // Roster get
- void RefreshRosterNow();
- sigslot::signal0<> SignalRosterRefreshStarted;
- sigslot::signal0<> SignalRosterRefreshFinished;
-
- virtual int ProcessStart();
-
-protected:
- void TranslateItems(const XmlElement *rosterQueryResult);
-
- virtual bool HandleStanza(const XmlElement * stanza);
-
- // Inner class for doing the roster get
- class RosterGetTask;
- friend class RosterGetTask;
-};
-
-}
-
-#endif // _PHONE_CLIENT_ROSTERTASK_H_
diff --git a/chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_main.cc b/chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_main.cc
deleted file mode 100644
index b5a0686ba76..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_main.cc
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * libjingle
- * Copyright 2006, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <iostream>
-#include <string>
-
-#include "talk/base/thread.h"
-#include "talk/libjingle-plus/libjingleplus.h"
-#include "talk/libjingle-plus/testutil/libjingleplus_test_notifier.h"
-
-#if defined(_MSC_VER) && (_MSC_VER < 1400)
-void __cdecl std::_Throw(const std::exception &) {}
-std::_Prhand std::_Raise_handler =0;
-#endif
-
-
-void SetConsoleEcho(bool on) {
-#ifdef WIN32
- HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
- if ((hIn == INVALID_HANDLE_VALUE) || (hIn == NULL))
- return;
-
- DWORD mode;
- if (!GetConsoleMode(hIn, &mode))
- return;
-
- if (on) {
- mode = mode | ENABLE_ECHO_INPUT;
- } else {
- mode = mode & ~ENABLE_ECHO_INPUT;
- }
-
- SetConsoleMode(hIn, mode);
-#else
- if (on)
- system("stty echo");
- else
- system("stty -echo");
-#endif
-}
-
-int main (int argc, char **argv)
-{
- std::string username;
- std::string password;
-
- bool gaia = false;
-
- for (int i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-gaia"))
- gaia = true;
- }
-
- std::cout << "Username: ";
- std::cin >> username;
- std::cout << (gaia ? "Gaia cookie: " : "Password: ");
- SetConsoleEcho(false);
- std::cin >> password;
- SetConsoleEcho(true);
-
- // Create a LibjinglePlus object and give it the notifier interface
- LibjinglePlus ljp(new Notifier);
-
- // Login
- ljp.Login(username, password, "talk.google.com", false, gaia);
-
- buzz::Status s;
- s.set_available(true);
- s.set_show(buzz::Status::SHOW_ONLINE);
- s.set_status("I'm online.");
-
- buzz::XmppMessage m;
- m.set_to(buzz::Jid(username + "@gmail.com"));
- m.set_body("What's up?");
-
- // Typically, you would wait for WakeupMainThread to be called, and then call
- // DoCallbacks. Because I have nothing else to do on the main thread, I'm just going
- // to do a few things after 10 seconds and then poll every 2ms.
- Sleep(10000);
- // ljp.DoCallbacks();
- ljp.SendPresence(s);
- ljp.SendXmppMessage(m);
-
-#ifdef WIN32
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0)) {
- DispatchMessage(&msg);
- }
-#else
- for (;;) {
- ljp.DoCallbacks();
- Sleep(2);
- }
-#endif
-}
diff --git a/chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_test_notifier.h b/chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_test_notifier.h
deleted file mode 100644
index 3a1af552a14..00000000000
--- a/chromium/third_party/libjingle/source/talk/examples/plus/testutil/libjingleplus_test_notifier.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * libjingle
- * Copyright 2006, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <iostream>
-#include <string>
-
-#include "talk/libjingle-plus/libjingleplus.h"
-
-class Notifier : virtual public LibjinglePlusNotify {
- virtual void OnStateChange(buzz::XmppEngine::State state) {
- std::cout << "State change: " << state << std::endl;
- }
-
- virtual void OnSocketClose(int error_code) {
- std::cout << "Socket close: " << error_code << std::endl;
- }
-
- virtual void OnXmppOutput(const std::string &output) {
- std::cout << ">>>>>>>>" << std::endl << output << std::endl << ">>>>>>>>" << std::endl;
- }
-
- virtual void OnXmppInput(const std::string &input) {
- std::cout << "<<<<<<<<" << std::endl << input << std::endl << "<<<<<<<<" << std::endl;
- }
-
-
- virtual void OnStatusUpdate(const buzz::Status &status) {
- std::string from = status.jid().Str();
- std::cout << from << " - " << status.status() << std::endl;
- }
-
- virtual void OnStatusError(const buzz::XmlElement &stanza) {
- }
-
- virtual void OnIqDone(bool success, const buzz::XmlElement &stanza) {
- }
-
- virtual void OnMessage(const buzz::XmppMessage &m) {
- if (m.body() != "")
- std::cout << m.from().Str() << ": " << m.body() << std::endl;
- }
-
- void OnRosterItemUpdated(const buzz::RosterItem &ri) {
- std::cout << "Roster item: " << ri.jid().Str() << std::endl;
- }
-
- virtual void OnRosterItemRemoved(const buzz::RosterItem &ri) {
- std::cout << "Roster item removed: " << ri.jid().Str() << std::endl;
- }
-
- virtual void OnRosterSubscribe(const buzz::Jid& jid) {
- std::cout << "Subscribing: " << jid.Str() << std::endl;
- }
-
- virtual void OnRosterUnsubscribe(const buzz::Jid &jid) {
- std::cout << "Unsubscribing: " <<jid.Str() << std::endl;
- }
-
- virtual void OnRosterSubscribed(const buzz::Jid &jid) {
- std::cout << "Subscribed: " << jid.Str() << std::endl;
- }
-
- virtual void OnRosterUnsubscribed(const buzz::Jid &jid) {
- std::cout << "Unsubscribed: " << jid.Str() << std::endl;
- }
-
- virtual void OnRosterRefreshStarted() {
- std::cout << "Refreshing roster." << std::endl;
- }
-
- virtual void OnRosterRefreshFinished() {
- std::cout << "Roster refreshed." << std::endl;
- }
-
- virtual void WakeupMainThread() {
- }
-};
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/relayserver_main.cc b/chromium/third_party/libjingle/source/talk/examples/relayserver/relayserver_main.cc
index 11e8a5bf16e..11e8a5bf16e 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/relayserver_main.cc
+++ b/chromium/third_party/libjingle/source/talk/examples/relayserver/relayserver_main.cc
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/stunserver_main.cc b/chromium/third_party/libjingle/source/talk/examples/stunserver/stunserver_main.cc
index 446794486e9..446794486e9 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/stunserver_main.cc
+++ b/chromium/third_party/libjingle/source/talk/examples/stunserver/stunserver_main.cc
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/turnserver_main.cc b/chromium/third_party/libjingle/source/talk/examples/turnserver/turnserver_main.cc
index d40fede0324..d40fede0324 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/turnserver_main.cc
+++ b/chromium/third_party/libjingle/source/talk/examples/turnserver/turnserver_main.cc
diff --git a/chromium/third_party/libjingle/source/talk/libjingle.gyp b/chromium/third_party/libjingle/source/talk/libjingle.gyp
index dced3d924be..2182561e041 100755
--- a/chromium/third_party/libjingle/source/talk/libjingle.gyp
+++ b/chromium/third_party/libjingle/source/talk/libjingle.gyp
@@ -27,7 +27,6 @@
{
'includes': ['build/common.gypi'],
-
'conditions': [
['os_posix == 1 and OS != "mac" and OS != "ios"', {
'conditions': [
@@ -54,6 +53,9 @@
'sources': [
'app/webrtc/java/jni/peerconnection_jni.cc'
],
+ 'include_dirs': [
+ '<(DEPTH)/third_party/libyuv/include',
+ ],
'conditions': [
['OS=="linux"', {
'defines': [
@@ -80,6 +82,7 @@
'variables': {
'java_src_dir': 'app/webrtc/java/src',
'webrtc_modules_dir': '<(webrtc_root)/modules',
+ 'build_jar_log': '<(INTERMEDIATE_DIR)/build_jar.log',
'peerconnection_java_files': [
'app/webrtc/java/src/org/webrtc/AudioSource.java',
'app/webrtc/java/src/org/webrtc/AudioTrack.java',
@@ -105,6 +108,8 @@
# included here, or better yet, build a proper .jar in webrtc
# and include it here.
'android_java_files': [
+ 'app/webrtc/java/android/org/webrtc/VideoRendererGui.java',
+ 'app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java',
'<(webrtc_modules_dir)/audio_device/android/java/src/org/webrtc/voiceengine/AudioManagerAndroid.java',
'<(webrtc_modules_dir)/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java',
'<(webrtc_modules_dir)/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java',
@@ -137,10 +142,13 @@
}],
],
'action': [
- 'build/build_jar.sh', '<(java_home)', '<@(_outputs)',
- '<(INTERMEDIATE_DIR)',
- '<(build_classpath)',
- '<@(java_files)'
+ 'bash', '-ec',
+ 'mkdir -p <(INTERMEDIATE_DIR) && '
+ '{ build/build_jar.sh <(java_home) <@(_outputs) '
+ ' <(INTERMEDIATE_DIR)/build_jar.tmp '
+ ' <(build_classpath) <@(java_files) '
+ ' > <(build_jar_log) 2>&1 || '
+ ' { cat <(build_jar_log) ; exit 1; } }'
],
},
],
@@ -150,7 +158,8 @@
},
],
}],
- ['OS=="ios" or (OS=="mac" and target_arch!="ia32")', {
+ ['OS=="ios" or (OS=="mac" and target_arch!="ia32" and mac_sdk>="10.7")', {
+ # The >= 10.7 above is required for ARC.
'targets': [
{
'target_name': 'libjingle_peerconnection_objc',
@@ -161,8 +170,11 @@
'sources': [
'app/webrtc/objc/RTCAudioTrack+Internal.h',
'app/webrtc/objc/RTCAudioTrack.mm',
+ 'app/webrtc/objc/RTCDataChannel+Internal.h',
+ 'app/webrtc/objc/RTCDataChannel.mm',
'app/webrtc/objc/RTCEnumConverter.h',
'app/webrtc/objc/RTCEnumConverter.mm',
+ 'app/webrtc/objc/RTCI420Frame+Internal.h',
'app/webrtc/objc/RTCI420Frame.mm',
'app/webrtc/objc/RTCICECandidate+Internal.h',
'app/webrtc/objc/RTCICECandidate.mm',
@@ -178,6 +190,7 @@
'app/webrtc/objc/RTCMediaStream.mm',
'app/webrtc/objc/RTCMediaStreamTrack+Internal.h',
'app/webrtc/objc/RTCMediaStreamTrack.mm',
+ 'app/webrtc/objc/RTCOpenGLVideoRenderer.mm',
'app/webrtc/objc/RTCPair.m',
'app/webrtc/objc/RTCPeerConnection+Internal.h',
'app/webrtc/objc/RTCPeerConnection.mm',
@@ -186,6 +199,8 @@
'app/webrtc/objc/RTCPeerConnectionObserver.mm',
'app/webrtc/objc/RTCSessionDescription+Internal.h',
'app/webrtc/objc/RTCSessionDescription.mm',
+ 'app/webrtc/objc/RTCStatsReport+Internal.h',
+ 'app/webrtc/objc/RTCStatsReport.mm',
'app/webrtc/objc/RTCVideoCapturer+Internal.h',
'app/webrtc/objc/RTCVideoCapturer.mm',
'app/webrtc/objc/RTCVideoRenderer+Internal.h',
@@ -196,6 +211,7 @@
'app/webrtc/objc/RTCVideoTrack.mm',
'app/webrtc/objc/public/RTCAudioSource.h',
'app/webrtc/objc/public/RTCAudioTrack.h',
+ 'app/webrtc/objc/public/RTCDataChannel.h',
'app/webrtc/objc/public/RTCI420Frame.h',
'app/webrtc/objc/public/RTCICECandidate.h',
'app/webrtc/objc/public/RTCICEServer.h',
@@ -203,16 +219,18 @@
'app/webrtc/objc/public/RTCMediaSource.h',
'app/webrtc/objc/public/RTCMediaStream.h',
'app/webrtc/objc/public/RTCMediaStreamTrack.h',
+ 'app/webrtc/objc/public/RTCOpenGLVideoRenderer.h',
'app/webrtc/objc/public/RTCPair.h',
'app/webrtc/objc/public/RTCPeerConnection.h',
'app/webrtc/objc/public/RTCPeerConnectionDelegate.h',
'app/webrtc/objc/public/RTCPeerConnectionFactory.h',
'app/webrtc/objc/public/RTCSessionDescription.h',
- 'app/webrtc/objc/public/RTCSessionDescriptonDelegate.h',
+ 'app/webrtc/objc/public/RTCSessionDescriptionDelegate.h',
+ 'app/webrtc/objc/public/RTCStatsDelegate.h',
+ 'app/webrtc/objc/public/RTCStatsReport.h',
'app/webrtc/objc/public/RTCTypes.h',
'app/webrtc/objc/public/RTCVideoCapturer.h',
'app/webrtc/objc/public/RTCVideoRenderer.h',
- 'app/webrtc/objc/public/RTCVideoRendererDelegate.h',
'app/webrtc/objc/public/RTCVideoSource.h',
'app/webrtc/objc/public/RTCVideoTrack.h',
],
@@ -228,13 +246,50 @@
],
'link_settings': {
'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
'-lstdc++',
],
},
'xcode_settings': {
'CLANG_ENABLE_OBJC_ARC': 'YES',
+ # common.gypi enables this for mac but we want this to be disabled
+ # like it is for ios.
+ 'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'NO',
},
+ 'conditions': [
+ ['OS=="ios"', {
+ 'sources': [
+ 'app/webrtc/objc/RTCEAGLVideoView+Internal.h',
+ 'app/webrtc/objc/RTCEAGLVideoView.m',
+ 'app/webrtc/objc/public/RTCEAGLVideoView.h',
+ ],
+ 'link_settings': {
+ 'xcode_settings': {
+ 'OTHER_LDFLAGS': [
+ '-framework CoreGraphics',
+ '-framework GLKit',
+ ],
+ },
+ },
+ }],
+ ['OS=="mac"', {
+ 'sources': [
+ 'app/webrtc/objc/RTCNSGLVideoView.m',
+ 'app/webrtc/objc/public/RTCNSGLVideoView.h',
+ ],
+ 'xcode_settings': {
+ # Need to build against 10.7 framework for full ARC support
+ # on OSX.
+ 'MACOSX_DEPLOYMENT_TARGET' : '10.7',
+ },
+ 'link_settings': {
+ 'xcode_settings': {
+ 'OTHER_LDFLAGS': [
+ '-framework Cocoa',
+ ],
+ },
+ },
+ }],
+ ],
}, # target libjingle_peerconnection_objc
],
}],
@@ -257,6 +312,8 @@
'base/asyncfile.h',
'base/asynchttprequest.cc',
'base/asynchttprequest.h',
+ 'base/asyncinvoker.cc',
+ 'base/asyncinvoker.h',
'base/asyncpacketsocket.h',
'base/asyncresolverinterface.h',
'base/asyncsocket.cc',
@@ -279,6 +336,7 @@
'base/bytebuffer.cc',
'base/bytebuffer.h',
'base/byteorder.h',
+ 'base/callback.h',
'base/checks.cc',
'base/checks.h',
'base/common.cc',
@@ -380,6 +438,7 @@
'base/scoped_autorelease_pool.h',
'base/scoped_ptr.h',
'base/scoped_ref_ptr.h',
+ 'base/scopedptrcollection.h',
'base/sec_buffer.h',
'base/sha1.cc',
'base/sha1.h',
@@ -406,6 +465,7 @@
'base/ssladapter.cc',
'base/ssladapter.h',
'base/sslconfig.h',
+ 'base/sslfingerprint.cc',
'base/sslfingerprint.h',
'base/sslidentity.cc',
'base/sslidentity.h',
@@ -504,6 +564,8 @@
'xmpp/pubsub_task.h',
'xmpp/pubsubclient.cc',
'xmpp/pubsubclient.h',
+ 'xmpp/pubsubstateclient.cc',
+ 'xmpp/pubsubstateclient.h',
'xmpp/pubsubtasks.cc',
'xmpp/pubsubtasks.h',
'xmpp/receivetask.cc',
@@ -539,13 +601,6 @@
'xmpp/xmppthread.h',
],
'conditions': [
- ['OS=="mac" or OS=="ios" or OS=="win"', {
- 'dependencies': [
- # The chromium copy of nss should NOT be used on platforms that
- # have NSS as system libraries, such as linux.
- '<(DEPTH)/third_party/nss/nss.gyp:nss',
- ],
- }],
['OS=="android"', {
'sources': [
'base/ifaddrs-android.cc',
@@ -643,16 +698,16 @@
}],
['OS=="ios"', {
'sources': [
+ 'base/iosfilesystem.mm',
'base/scoped_autorelease_pool.mm',
],
'dependencies': [
- '../net/third_party/nss/ssl.gyp:libssl',
+ '<(DEPTH)/net/third_party/nss/ssl.gyp:libssl',
],
'all_dependent_settings': {
'xcode_settings': {
'OTHER_LDFLAGS': [
'-framework Foundation',
- '-framework IOKit',
'-framework Security',
'-framework SystemConfiguration',
'-framework UIKit',
@@ -706,13 +761,9 @@
'base/unixfilesystem.h',
],
'conditions': [
- ['OS=="linux" or OS=="android"', {
- 'dependencies': [
- '<(DEPTH)/third_party/openssl/openssl.gyp:openssl',
- ],
- }],
['OS!="ios"', {
'sources': [
+ 'base/openssl.h',
'base/openssladapter.cc',
'base/openssladapter.h',
'base/openssldigest.cc',
@@ -772,13 +823,20 @@
{
'target_name': 'libjingle_media',
'type': 'static_library',
+ 'include_dirs': [
+ # TODO(jiayl): move this into the direct_dependent_settings of
+ # usrsctp.gyp.
+ '<(DEPTH)/third_party/usrsctp',
+ ],
'dependencies': [
'<(DEPTH)/third_party/libyuv/libyuv.gyp:libyuv',
+ '<(DEPTH)/third_party/usrsctp/usrsctp.gyp:usrsctplib',
'<(webrtc_root)/modules/modules.gyp:video_capture_module',
'<(webrtc_root)/modules/modules.gyp:video_render_module',
- '<(webrtc_root)/video_engine/video_engine.gyp:video_engine_core',
+ '<(webrtc_root)/webrtc.gyp:webrtc',
'<(webrtc_root)/voice_engine/voice_engine.gyp:voice_engine',
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
+ '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
'libjingle',
'libjingle_sound',
],
@@ -832,6 +890,8 @@
'media/base/videoprocessor.h',
'media/base/videorenderer.h',
'media/base/voiceprocessor.h',
+ 'media/base/yuvframegenerator.cc',
+ 'media/base/yuvframegenerator.h',
'media/devices/deviceinfo.h',
'media/devices/devicemanager.cc',
'media/devices/devicemanager.h',
@@ -839,14 +899,14 @@
'media/devices/filevideocapturer.cc',
'media/devices/filevideocapturer.h',
'media/devices/videorendererfactory.h',
+ 'media/devices/yuvframescapturer.cc',
+ 'media/devices/yuvframescapturer.h',
'media/other/linphonemediaengine.h',
- # TODO(ronghuawu): Enable when SCTP is ready.
- # 'media/sctp/sctpdataengine.cc',
- # 'media/sctp/sctpdataengine.h',
- 'media/sctp/sctputils.cc',
- 'media/sctp/sctputils.h',
+ 'media/sctp/sctpdataengine.cc',
+ 'media/sctp/sctpdataengine.h',
'media/webrtc/webrtccommon.h',
'media/webrtc/webrtcexport.h',
+ 'media/webrtc/webrtcmediaengine.cc',
'media/webrtc/webrtcmediaengine.h',
'media/webrtc/webrtcpassthroughrender.cc',
'media/webrtc/webrtcpassthroughrender.h',
@@ -858,6 +918,8 @@
'media/webrtc/webrtcvideoencoderfactory.h',
'media/webrtc/webrtcvideoengine.cc',
'media/webrtc/webrtcvideoengine.h',
+ 'media/webrtc/webrtcvideoengine2.cc',
+ 'media/webrtc/webrtcvideoengine2.h',
'media/webrtc/webrtcvideoframe.cc',
'media/webrtc/webrtcvideoframe.h',
'media/webrtc/webrtcvie.h',
@@ -952,7 +1014,6 @@
}],
['OS=="ios"', {
'sources': [
- 'media/devices/iosdeviceinfo.cc',
'media/devices/mobiledevicemanager.cc',
],
'include_dirs': [
@@ -960,6 +1021,13 @@
# libjpeg which pulls in libyuv which currently disabled.
'../third_party/libyuv/include',
],
+ 'dependencies!': [
+ '<(DEPTH)/third_party/usrsctp/usrsctp.gyp:usrsctplib',
+ ],
+ 'sources!': [
+ 'media/sctp/sctpdataengine.cc',
+ 'media/sctp/sctpdataengine.h',
+ ],
}],
['OS=="android"', {
'sources': [
@@ -984,10 +1052,6 @@
'<(DEPTH)/testing/gtest/include',
],
},
- 'defines': [
- # TODO(ronghuawu): enable SCTP when it's ready.
- # 'HAVE_SCTP',
- ],
'sources': [
'p2p/base/asyncstuntcpsocket.cc',
'p2p/base/asyncstuntcpsocket.h',
@@ -1081,6 +1145,8 @@
'session/tunnel/securetunnelsessionclient.h',
'session/media/audiomonitor.cc',
'session/media/audiomonitor.h',
+ 'session/media/bundlefilter.cc',
+ 'session/media/bundlefilter.h',
'session/media/call.cc',
'session/media/call.h',
'session/media/channel.cc',
@@ -1106,8 +1172,6 @@
'session/media/soundclip.h',
'session/media/srtpfilter.cc',
'session/media/srtpfilter.h',
- 'session/media/ssrcmuxfilter.cc',
- 'session/media/ssrcmuxfilter.h',
'session/media/typingmonitor.cc',
'session/media/typingmonitor.h',
'session/media/voicechannel.h',
@@ -1163,8 +1227,12 @@
'app/webrtc/portallocatorfactory.cc',
'app/webrtc/portallocatorfactory.h',
'app/webrtc/proxy.h',
+ 'app/webrtc/remoteaudiosource.cc',
+ 'app/webrtc/remoteaudiosource.h',
'app/webrtc/remotevideocapturer.cc',
'app/webrtc/remotevideocapturer.h',
+ 'app/webrtc/sctputils.cc',
+ 'app/webrtc/sctputils.h',
'app/webrtc/statscollector.cc',
'app/webrtc/statscollector.h',
'app/webrtc/statstypes.h',
diff --git a/chromium/third_party/libjingle/source/talk/libjingle.scons b/chromium/third_party/libjingle/source/talk/libjingle.scons
deleted file mode 100644
index 87b43f50ed0..00000000000
--- a/chromium/third_party/libjingle/source/talk/libjingle.scons
+++ /dev/null
@@ -1,790 +0,0 @@
-import talk
-Import("env")
-
-talk.Library(env, name = "expat",
- cppdefines = [
- "XML_STATIC",
- ],
- srcs = [
- "third_party/expat-2.0.1/lib/xmlparse.c",
- "third_party/expat-2.0.1/lib/xmlrole.c",
- "third_party/expat-2.0.1/lib/xmltok.c",
- ],
- includedirs = [
- "third_party/expat-2.0.1/lib",
- ],
- win_cppdefines = [
- "COMPILED_FROM_DSP",
- ],
- posix_cppdefines = [
- "HAVE_EXPAT_CONFIG_H",
- ],
-)
-talk.Library(env, name = "gunit",
- srcs = [
- "testing/gtest/src/gtest-all.cc",
- ],
- includedirs = [
- "testing/gtest/include",
- "third_party/expat-2.0.1/lib",
- "third_party/srtp",
- "testing/gtest",
- ],
- cppdefines = [
- "EXPAT_RELATIVE_PATH",
- "GTEST_RELATIVE_PATH",
- "SRTP_RELATIVE_PATH",
- ],
-)
-talk.Library(env, name = "srtp",
- srcs = [
- "third_party/srtp/crypto/cipher/aes.c",
- "third_party/srtp/crypto/cipher/aes_cbc.c",
- "third_party/srtp/crypto/cipher/aes_icm.c",
- "third_party/srtp/crypto/cipher/cipher.c",
- "third_party/srtp/crypto/cipher/null_cipher.c",
- "third_party/srtp/crypto/hash/auth.c",
- "third_party/srtp/crypto/hash/hmac.c",
- "third_party/srtp/crypto/hash/null_auth.c",
- "third_party/srtp/crypto/hash/sha1.c",
- "third_party/srtp/crypto/replay/rdb.c",
- "third_party/srtp/crypto/replay/rdbx.c",
- "third_party/srtp/crypto/replay/ut_sim.c",
- "third_party/srtp/crypto/math/datatypes.c",
- "third_party/srtp/crypto/math/stat.c",
- "third_party/srtp/crypto/kernel/alloc.c",
- "third_party/srtp/crypto/kernel/crypto_kernel.c",
- "third_party/srtp/crypto/kernel/err.c",
- "third_party/srtp/crypto/kernel/key.c",
- "third_party/srtp/crypto/rng/ctr_prng.c",
- "third_party/srtp/crypto/rng/rand_source.c",
- "third_party/srtp/srtp/ekt.c",
- "third_party/srtp/srtp/srtp.c",
- ],
- includedirs = [
- "third_party/srtp/include",
- "third_party/srtp/crypto/include",
- ],
- win_ccflags = [
- "/wd4701",
- "/wd4702",
- ],
-)
-# Set up the SSL/TLS includes
-if 'NSS_BUILD_PLATFORM' in env['ENV']:
- SSL_INCLUDES = [
- "third_party/mozilla/dist/public/nss",
- "third_party/mozilla/dist/" + env['ENV']['NSS_BUILD_PLATFORM']+ "/include"
- ]
- SSL_LIBS = [
- "ssl3",
- "nss3",
- "nssutil3",
- "plc4",
- "plds4",
- "nspr4",
- ]
-else:
- SSL_INCLUDES = ["third_party/openssl/include"]
- SSL_LIBS = ["crypto", "ssl"]
-
-talk.Library(env, name = "jingle",
- lin_packages = [
- "x11",
- "xcomposite",
- "xrender",
- ],
- lin_srcs = [
- "base/latebindingsymboltable.cc",
- "base/latebindingsymboltable.h.def",
- "base/latebindingsymboltable.cc.def",
- "base/linux.cc",
- "base/linuxfdwalk.c",
- "base/linuxwindowpicker.cc",
- "media/devices/libudevsymboltable.cc",
- "media/devices/linuxdeviceinfo.cc",
- "media/devices/linuxdevicemanager.cc",
- "media/devices/v4llookup.cc",
- "sound/alsasoundsystem.cc",
- "sound/alsasymboltable.cc",
- "sound/linuxsoundsystem.cc",
- "sound/pulseaudiosoundsystem.cc",
- "sound/pulseaudiosymboltable.cc",
- ],
- dependent_target_settings = {
- 'lin_libs': [
- "dl",
- "pthread",
- "rt",
- "gthread-2.0",
- ],
- 'mac_libs': SSL_LIBS,
- 'win_libs': [
- "winmm.lib",
- ],
- },
- mac_srcs = [
- "base/macasyncsocket.cc",
- "base/maccocoasocketserver.mm",
- "base/maccocoathreadhelper.mm",
- "base/macconversion.cc",
- "base/macsocketserver.cc",
- "base/macutils.cc",
- "base/macwindowpicker.cc",
- "base/scoped_autorelease_pool.mm",
- "media/devices/carbonvideorenderer.cc",
- "media/devices/macdeviceinfo.cc",
- "media/devices/macdevicemanager.cc",
- "media/devices/macdevicemanagermm.mm",
- ],
- posix_srcs = [
- "base/unixfilesystem.cc",
- "base/posix.cc",
- ],
- linphone_srcs = [
- "media/other/linphonemediaengine.cc",
- ],
- cppdefines = [
- "FEATURE_ENABLE_VOICEMAIL",
- "EXPAT_RELATIVE_PATH",
- "GTEST_RELATIVE_PATH",
- "SRTP_RELATIVE_PATH",
- "XML_STATIC",
- ],
- srcs = [
- "base/asyncfile.cc",
- "base/asynchttprequest.cc",
- "base/asyncsocket.cc",
- "base/asynctcpsocket.cc",
- "base/asyncudpsocket.cc",
- "base/autodetectproxy.cc",
- "base/bandwidthsmoother.cc",
- "base/base64.cc",
- "base/basicpacketsocketfactory.cc",
- "base/bytebuffer.cc",
- "base/checks.cc",
- "base/common.cc",
- "base/cpumonitor.cc",
- "base/crc32.cc",
- "base/diskcache.cc",
- "base/event.cc",
- "base/filelock.cc",
- "base/fileutils.cc",
- "base/firewallsocketserver.cc",
- "base/flags.cc",
- "base/helpers.cc",
- "base/host.cc",
- "base/httpbase.cc",
- "base/httpclient.cc",
- "base/httpcommon.cc",
- "base/httprequest.cc",
- "base/httpserver.cc",
- "base/ipaddress.cc",
- "base/logging.cc",
- "base/md5.cc",
- "base/messagedigest.cc",
- "base/messagehandler.cc",
- "base/messagequeue.cc",
- "base/multipart.cc",
- "base/natserver.cc",
- "base/natsocketfactory.cc",
- "base/nattypes.cc",
- "base/nethelpers.cc",
- "base/network.cc",
- "base/nssidentity.cc",
- "base/nssstreamadapter.cc",
- "base/openssladapter.cc",
- "base/openssldigest.cc",
- "base/opensslidentity.cc",
- "base/opensslstreamadapter.cc",
- "base/optionsfile.cc",
- "base/pathutils.cc",
- "base/physicalsocketserver.cc",
- "base/profiler.cc",
- "base/proxydetect.cc",
- "base/proxyinfo.cc",
- "base/proxyserver.cc",
- "base/ratelimiter.cc",
- "base/ratetracker.cc",
- "base/sha1.cc",
- "base/sharedexclusivelock.cc",
- "base/signalthread.cc",
- "base/socketadapters.cc",
- "base/socketaddress.cc",
- "base/socketaddresspair.cc",
- "base/socketpool.cc",
- "base/socketstream.cc",
- "base/ssladapter.cc",
- "base/sslsocketfactory.cc",
- "base/sslidentity.cc",
- "base/sslstreamadapter.cc",
- "base/sslstreamadapterhelper.cc",
- "base/stream.cc",
- "base/stringencode.cc",
- "base/stringutils.cc",
- "base/systeminfo.cc",
- "base/task.cc",
- "base/taskparent.cc",
- "base/taskrunner.cc",
- "base/testclient.cc",
- "base/thread.cc",
- "base/timeutils.cc",
- "base/timing.cc",
- "base/transformadapter.cc",
- "base/urlencode.cc",
- "base/versionparsing.cc",
- "base/virtualsocketserver.cc",
- "base/worker.cc",
- "p2p/base/constants.cc",
- "p2p/base/dtlstransportchannel.cc",
- "p2p/base/p2ptransport.cc",
- "p2p/base/p2ptransportchannel.cc",
- "p2p/base/parsing.cc",
- "p2p/base/port.cc",
- "p2p/base/portallocator.cc",
- "p2p/base/portallocatorsessionproxy.cc",
- "p2p/base/portproxy.cc",
- "p2p/base/pseudotcp.cc",
- "p2p/base/relayport.cc",
- "p2p/base/relayserver.cc",
- "p2p/base/rawtransport.cc",
- "p2p/base/rawtransportchannel.cc",
- "p2p/base/session.cc",
- "p2p/base/sessiondescription.cc",
- "p2p/base/sessionmanager.cc",
- "p2p/base/sessionmessages.cc",
- "p2p/base/stun.cc",
- "p2p/base/stunport.cc",
- "p2p/base/stunrequest.cc",
- "p2p/base/stunserver.cc",
- "p2p/base/tcpport.cc",
- "p2p/base/transport.cc",
- "p2p/base/transportchannel.cc",
- "p2p/base/transportchannelproxy.cc",
- "p2p/base/transportdescriptionfactory.cc",
- "p2p/base/turnport.cc",
- "p2p/base/turnserver.cc",
- "p2p/client/basicportallocator.cc",
- "p2p/client/connectivitychecker.cc",
- "p2p/client/httpportallocator.cc",
- "p2p/client/socketmonitor.cc",
- "session/tunnel/pseudotcpchannel.cc",
- "session/tunnel/tunnelsessionclient.cc",
- "session/tunnel/securetunnelsessionclient.cc",
- "media/base/capturemanager.cc",
- "media/base/capturerenderadapter.cc",
- "media/base/codec.cc",
- "media/base/constants.cc",
- "media/base/cpuid.cc",
- "media/base/filemediaengine.cc",
- "media/base/hybridvideoengine.cc",
- "media/base/mediaengine.cc",
- "media/base/rtpdataengine.cc",
- "media/base/rtpdump.cc",
- "media/base/rtputils.cc",
- "media/base/streamparams.cc",
- "media/base/videoadapter.cc",
- "media/base/videocapturer.cc",
- "media/base/mutedvideocapturer.cc",
- "media/base/videocommon.cc",
- "media/base/videoframe.cc",
- "media/devices/devicemanager.cc",
- "media/devices/filevideocapturer.cc",
- "media/sctp/sctputils.cc",
- "session/media/audiomonitor.cc",
- "session/media/call.cc",
- "session/media/channel.cc",
- "session/media/channelmanager.cc",
- "session/media/currentspeakermonitor.cc",
- "session/media/mediamessages.cc",
- "session/media/mediamonitor.cc",
- "session/media/mediarecorder.cc",
- "session/media/mediasession.cc",
- "session/media/mediasessionclient.cc",
- "session/media/rtcpmuxfilter.cc",
- "session/media/rtcpmuxfilter.cc",
- "session/media/soundclip.cc",
- "session/media/srtpfilter.cc",
- "session/media/ssrcmuxfilter.cc",
- "session/media/typingmonitor.cc",
- "sound/nullsoundsystem.cc",
- "sound/nullsoundsystemfactory.cc",
- "sound/platformsoundsystem.cc",
- "sound/platformsoundsystemfactory.cc",
- "sound/soundsysteminterface.cc",
- "sound/soundsystemproxy.cc",
- "xmllite/qname.cc",
- "xmllite/xmlbuilder.cc",
- "xmllite/xmlconstants.cc",
- "xmllite/xmlelement.cc",
- "xmllite/xmlnsstack.cc",
- "xmllite/xmlparser.cc",
- "xmllite/xmlprinter.cc",
- "xmpp/chatroommoduleimpl.cc",
- "xmpp/constants.cc",
- "xmpp/discoitemsquerytask.cc",
- "xmpp/hangoutpubsubclient.cc",
- "xmpp/iqtask.cc",
- "xmpp/jid.cc",
- "xmpp/jingleinfotask.cc",
- "xmpp/moduleimpl.cc",
- "xmpp/mucroomconfigtask.cc",
- "xmpp/mucroomdiscoverytask.cc",
- "xmpp/mucroomlookuptask.cc",
- "xmpp/mucroomuniquehangoutidtask.cc",
- "xmpp/pingtask.cc",
- "xmpp/presenceouttask.cc",
- "xmpp/presencereceivetask.cc",
- "xmpp/presencestatus.cc",
- "xmpp/pubsubclient.cc",
- "xmpp/pubsub_task.cc",
- "xmpp/pubsubtasks.cc",
- "xmpp/receivetask.cc",
- "xmpp/rostermoduleimpl.cc",
- "xmpp/saslmechanism.cc",
- "xmpp/xmppclient.cc",
- "xmpp/xmppengineimpl.cc",
- "xmpp/xmppengineimpl_iq.cc",
- "xmpp/xmpplogintask.cc",
- "xmpp/xmppstanzaparser.cc",
- "xmpp/xmpptask.cc",
- "xmpp/xmppauth.cc",
- "xmpp/xmpppump.cc",
- "xmpp/xmppsocket.cc",
- "xmpp/xmppthread.cc",
- ],
- includedirs = [
- "third_party/libudev",
- "third_party/expat-2.0.1/lib",
- "testing/gtest/include",
- "third_party/srtp/include",
- "third_party/srtp/crypto/include",
- ] + SSL_INCLUDES,
- win_srcs = [
- "base/diskcache_win32.cc",
- "base/schanneladapter.cc",
- "base/win32.cc",
- "base/win32regkey.cc",
- "base/win32filesystem.cc",
- "base/win32securityerrors.cc",
- "base/win32socketserver.cc",
- "base/win32socketinit.cc",
- "base/win32window.cc",
- "base/win32windowpicker.cc",
- "base/winfirewall.cc",
- "base/winping.cc",
- "media/devices/gdivideorenderer.cc",
- "media/devices/win32deviceinfo.cc",
- "media/devices/win32devicemanager.cc",
- ],
- mac_ccflags = [
- "-Wno-deprecated-declarations",
- ],
- extra_srcs = [
- "media/devices/dummydevicemanager.cc",
- "base/dbus.cc",
- "base/libdbusglibsymboltable.cc",
- "base/json.cc",
- "base/natserver_main.cc",
- ],
-)
-talk.Library(env, name = "videorenderer",
- lin_srcs = [
- "media/devices/gtkvideorenderer.cc",
- ],
- lin_packages = [
- "gobject-2.0",
- "gthread-2.0",
- "gtk+-2.0",
- ],
-)
-talk.Library(env, name = "unittest_main",
- libs = [
- "gunit",
- ],
- srcs = [
- "base/unittest_main.cc",
- ],
- includedirs = [
- "testing/gtest/include",
- "third_party/expat-2.0.1/lib",
- "third_party/srtp",
- "testing/gtest",
- ],
- cppdefines = [
- "EXPAT_RELATIVE_PATH",
- "GTEST_RELATIVE_PATH",
- "SRTP_RELATIVE_PATH",
- ],
-)
-talk.App(env, name = "login",
- libs = [
- "jingle",
- "expat",
- ],
- srcs = [
- "examples/login/login_main.cc",
- ],
- posix_libs = SSL_LIBS,
- lin_libs = [
- "videorenderer",
- ],
-)
-talk.App(env, name = "chat",
- libs = [
- "jingle",
- "expat",
- ],
- srcs = [
- "examples/chat/chatapp.cc",
- "examples/chat/chat_main.cc",
- "examples/chat/consoletask.cc",
- "examples/chat/textchatreceivetask.cc",
- "examples/chat/textchatsendtask.cc",
- ],
- posix_libs = SSL_LIBS,
-)
-talk.App(env, name = "call",
- mac_frameworks = [
- "AudioToolbox",
- "AudioUnit",
- "Cocoa",
- "CoreAudio",
- "CoreFoundation",
- "IOKit",
- "QTKit",
- "QuickTime",
- ],
- win_libs = [
- "d3d9.lib",
- "gdi32.lib",
- "powrprof.lib",
- "strmiids.lib",
- "winmm.lib",
- ],
- posix_libs = SSL_LIBS,
- lin_libs = [
- "videorenderer",
- ],
- srcs = [
- "examples/call/call_main.cc",
- "examples/call/callclient.cc",
- "examples/call/console.cc",
- "examples/call/friendinvitesendtask.cc",
- "examples/call/mediaenginefactory.cc",
- "examples/call/mucinviterecvtask.cc",
- "examples/call/mucinvitesendtask.cc",
- "examples/call/presencepushtask.cc",
- ],
- libs = [
- "jingle",
- "expat",
- "srtp",
- ],
-)
-talk.App(env, name = "relayserver",
- libs = [
- "jingle",
- ],
- srcs = [
- "p2p/base/relayserver_main.cc",
- ],
-)
-talk.App(env, name = "stunserver",
- libs = [
- "jingle",
- ],
- srcs = [
- "p2p/base/stunserver_main.cc",
- ],
-)
-talk.App(env, name = "turnserver",
- lin_libs = [
- "crypto",
- "ssl",
- ],
- srcs = [
- "p2p/base/turnserver_main.cc",
- ],
- libs = [
- "jingle",
- ],
-)
-talk.Unittest(env, name = "base",
- lin_srcs = [
- "base/latebindingsymboltable_unittest.cc",
- "base/linux_unittest.cc",
- "base/linuxfdwalk_unittest.cc",
- ],
- mac_srcs = [
- "base/macsocketserver_unittest.cc",
- "base/macutils_unittest.cc",
- "base/macwindowpicker_unittest.cc",
- ],
- posix_srcs = [
- "base/sslidentity_unittest.cc",
- "base/sslstreamadapter_unittest.cc",
- ],
- cppdefines = [
- "EXPAT_RELATIVE_PATH",
- "GTEST_RELATIVE_PATH",
- "SRTP_RELATIVE_PATH",
- ],
- srcs = [
- "base/asynchttprequest_unittest.cc",
- "base/atomicops_unittest.cc",
- "base/autodetectproxy_unittest.cc",
- "base/bandwidthsmoother_unittest.cc",
- "base/base64_unittest.cc",
- "base/basictypes_unittest.cc",
- "base/bind_unittest.cc",
- "base/buffer_unittest.cc",
- "base/bytebuffer_unittest.cc",
- "base/byteorder_unittest.cc",
- "base/cpumonitor_unittest.cc",
- "base/crc32_unittest.cc",
- "base/event_unittest.cc",
- "base/filelock_unittest.cc",
- "base/fileutils_unittest.cc",
- "base/helpers_unittest.cc",
- "base/host_unittest.cc",
- "base/httpbase_unittest.cc",
- "base/httpcommon_unittest.cc",
- "base/httpserver_unittest.cc",
- "base/ipaddress_unittest.cc",
- "base/logging_unittest.cc",
- "base/md5digest_unittest.cc",
- "base/messagedigest_unittest.cc",
- "base/messagequeue_unittest.cc",
- "base/multipart_unittest.cc",
- "base/nat_unittest.cc",
- "base/network_unittest.cc",
- "base/nullsocketserver_unittest.cc",
- "base/optionsfile_unittest.cc",
- "base/pathutils_unittest.cc",
- "base/physicalsocketserver_unittest.cc",
- "base/profiler_unittest.cc",
- "base/proxy_unittest.cc",
- "base/proxydetect_unittest.cc",
- "base/ratelimiter_unittest.cc",
- "base/ratetracker_unittest.cc",
- "base/referencecountedsingletonfactory_unittest.cc",
- "base/rollingaccumulator_unittest.cc",
- "base/sha1digest_unittest.cc",
- "base/sharedexclusivelock_unittest.cc",
- "base/signalthread_unittest.cc",
- "base/sigslot_unittest.cc",
- "base/socket_unittest.cc",
- "base/socketaddress_unittest.cc",
- "base/stream_unittest.cc",
- "base/stringencode_unittest.cc",
- "base/stringutils_unittest.cc",
- "base/systeminfo_unittest.cc",
- "base/task_unittest.cc",
- "base/testclient_unittest.cc",
- "base/thread_unittest.cc",
- "base/timeutils_unittest.cc",
- "base/urlencode_unittest.cc",
- "base/versionparsing_unittest.cc",
- "base/virtualsocket_unittest.cc",
- "base/windowpicker_unittest.cc",
- ],
- includedirs = [
- "testing/gtest/include",
- "third_party/expat-2.0.1/lib",
- "third_party/srtp",
- "testing/gtest",
- ],
- win_srcs = [
- "base/win32_unittest.cc",
- "base/win32regkey_unittest.cc",
- "base/win32socketserver_unittest.cc",
- "base/win32toolhelp_unittest.cc",
- "base/win32window_unittest.cc",
- "base/win32windowpicker_unittest.cc",
- "base/winfirewall_unittest.cc",
- ],
- libs = [
- "jingle",
- ],
- extra_srcs = [
- "base/dbus_unittest.cc",
- "base/json_unittest.cc",
- "base/linuxwindowpicker_unittest.cc",
- ],
-)
-talk.Unittest(env, name = "p2p",
- mac_FRAMEWORKS = [
- "Foundation",
- "IOKit",
- "QTKit",
- ],
- mac_libs = SSL_LIBS,
- cppdefines = [
- "EXPAT_RELATIVE_PATH",
- "GTEST_RELATIVE_PATH",
- "SRTP_RELATIVE_PATH",
- ],
- srcs = [
- "p2p/base/dtlstransportchannel_unittest.cc",
- "p2p/base/p2ptransportchannel_unittest.cc",
- "p2p/base/port_unittest.cc",
- "p2p/base/portallocatorsessionproxy_unittest.cc",
- "p2p/base/pseudotcp_unittest.cc",
- "p2p/base/relayport_unittest.cc",
- "p2p/base/relayserver_unittest.cc",
- "p2p/base/session_unittest.cc",
- "p2p/base/stun_unittest.cc",
- "p2p/base/stunport_unittest.cc",
- "p2p/base/stunrequest_unittest.cc",
- "p2p/base/stunserver_unittest.cc",
- "p2p/base/transport_unittest.cc",
- "p2p/base/transportdescriptionfactory_unittest.cc",
- "p2p/base/turnport_unittest.cc",
- "p2p/client/connectivitychecker_unittest.cc",
- "p2p/client/portallocator_unittest.cc",
- ],
- includedirs = [
- "testing/gtest/include",
- "third_party/expat-2.0.1/lib",
- "third_party/srtp",
- "testing/gtest",
- ],
- libs = [
- "jingle",
- "expat",
- ],
-)
-talk.Unittest(env, name = "media",
- win_libs = [
- "winmm.lib",
- "strmiids",
- ],
- cppdefines = [
- "EXPAT_RELATIVE_PATH",
- "GTEST_RELATIVE_PATH",
- "SRTP_RELATIVE_PATH",
- ],
- srcs = [
- "media/base/capturemanager_unittest.cc",
- "media/base/codec_unittest.cc",
- "media/base/filemediaengine_unittest.cc",
- "media/base/rtpdataengine_unittest.cc",
- "media/base/rtpdump_unittest.cc",
- "media/base/rtputils_unittest.cc",
- "media/base/testutils.cc",
- "media/base/videocapturer_unittest.cc",
- "media/base/videocommon_unittest.cc",
- "media/devices/devicemanager_unittest.cc",
- "media/devices/filevideocapturer_unittest.cc",
- "media/sctp/sctputils_unittest.cc",
- "session/media/channel_unittest.cc",
- "session/media/channelmanager_unittest.cc",
- "session/media/currentspeakermonitor_unittest.cc",
- "session/media/mediarecorder_unittest.cc",
- "session/media/mediamessages_unittest.cc",
- "session/media/mediasession_unittest.cc",
- "session/media/mediasessionclient_unittest.cc",
- "session/media/rtcpmuxfilter_unittest.cc",
- "session/media/srtpfilter_unittest.cc",
- "session/media/ssrcmuxfilter_unittest.cc",
- ],
- includedirs = [
- "testing/gtest/include",
- "third_party/expat-2.0.1/lib",
- "third_party/srtp",
- "testing/gtest",
- ],
- libs = [
- "jingle",
- "expat",
- "srtp",
- ],
- extra_srcs = [
- "media/devices/dummydevicemanager_unittest.cc",
- ],
-)
-talk.Unittest(env, name = "sound",
- libs = [
- "jingle",
- ],
- srcs = [
- "sound/automaticallychosensoundsystem_unittest.cc",
- ],
- mac_libs = SSL_LIBS,
-
- includedirs = [
- "testing/gtest/include",
- "third_party/expat-2.0.1/lib",
- "third_party/srtp",
- "testing/gtest",
- ],
- cppdefines = [
- "EXPAT_RELATIVE_PATH",
- "GTEST_RELATIVE_PATH",
- "SRTP_RELATIVE_PATH",
- ],
-)
-talk.Unittest(env, name = "xmllite",
- libs = [
- "jingle",
- "expat",
- ],
- srcs = [
- "xmllite/qname_unittest.cc",
- "xmllite/xmlbuilder_unittest.cc",
- "xmllite/xmlelement_unittest.cc",
- "xmllite/xmlnsstack_unittest.cc",
- "xmllite/xmlparser_unittest.cc",
- "xmllite/xmlprinter_unittest.cc",
- ],
- mac_libs = SSL_LIBS,
- includedirs = [
- "testing/gtest/include",
- "third_party/expat-2.0.1/lib",
- "third_party/srtp",
- "testing/gtest",
- ],
- cppdefines = [
- "EXPAT_RELATIVE_PATH",
- "GTEST_RELATIVE_PATH",
- "SRTP_RELATIVE_PATH",
- ],
-)
-talk.Unittest(env, name = "xmpp",
- mac_libs = SSL_LIBS,
- cppdefines = [
- "EXPAT_RELATIVE_PATH",
- "GTEST_RELATIVE_PATH",
- "SRTP_RELATIVE_PATH",
- ],
- srcs = [
- "xmpp/hangoutpubsubclient_unittest.cc",
- "xmpp/jid_unittest.cc",
- "xmpp/mucroomconfigtask_unittest.cc",
- "xmpp/mucroomdiscoverytask_unittest.cc",
- "xmpp/mucroomlookuptask_unittest.cc",
- "xmpp/mucroomuniquehangoutidtask_unittest.cc",
- "xmpp/pingtask_unittest.cc",
- "xmpp/pubsubclient_unittest.cc",
- "xmpp/pubsubtasks_unittest.cc",
- "xmpp/util_unittest.cc",
- "xmpp/xmppengine_unittest.cc",
- "xmpp/xmpplogintask_unittest.cc",
- "xmpp/xmppstanzaparser_unittest.cc",
- ],
- includedirs = [
- "testing/gtest/include",
- "third_party/expat-2.0.1/lib",
- "third_party/srtp",
- "testing/gtest",
- ],
- libs = [
- "jingle",
- "expat",
- ],
- extra_srcs = [
- "xmpp/chatroommodule_unittest.cc",
- "xmpp/rostermodule_unittest.cc",
- ],
-)
diff --git a/chromium/third_party/libjingle/source/talk/libjingle_examples.gyp b/chromium/third_party/libjingle/source/talk/libjingle_examples.gyp
index 1e2eeb0fb75..f69c5dcf8dc 100755
--- a/chromium/third_party/libjingle/source/talk/libjingle_examples.gyp
+++ b/chromium/third_party/libjingle/source/talk/libjingle_examples.gyp
@@ -51,7 +51,7 @@
'libjingle.gyp:libjingle_p2p',
],
'sources': [
- 'p2p/base/relayserver_main.cc',
+ 'examples/relayserver/relayserver_main.cc',
],
}, # target relayserver
{
@@ -62,7 +62,7 @@
'libjingle.gyp:libjingle_p2p',
],
'sources': [
- 'p2p/base/stunserver_main.cc',
+ 'examples/stunserver/stunserver_main.cc',
],
}, # target stunserver
{
@@ -73,7 +73,7 @@
'libjingle.gyp:libjingle_p2p',
],
'sources': [
- 'p2p/base/turnserver_main.cc',
+ 'examples/turnserver/turnserver_main.cc',
],
}, # target turnserver
{
@@ -218,7 +218,7 @@
], # targets
}], # OS=="linux" or OS=="win"
- ['OS=="ios"', {
+ ['OS=="ios" or (OS=="mac" and target_arch!="ia32" and mac_sdk>="10.8")', {
'targets': [
{
'target_name': 'AppRTCDemo',
@@ -226,44 +226,71 @@
'product_name': 'AppRTCDemo',
'mac_bundle': 1,
'mac_bundle_resources': [
- 'examples/ios/AppRTCDemo/ResourceRules.plist',
- 'examples/ios/AppRTCDemo/en.lproj/APPRTCViewController.xib',
- 'examples/ios/AppRTCDemo/ios_channel.html',
- 'examples/ios/Icon.png',
+ 'examples/objc/AppRTCDemo/channel.html',
],
'dependencies': [
'libjingle.gyp:libjingle_peerconnection_objc',
],
'conditions': [
+ ['OS=="ios"', {
+ 'mac_bundle_resources': [
+ 'examples/objc/AppRTCDemo/ios/ResourceRules.plist',
+ 'examples/objc/AppRTCDemo/ios/en.lproj/APPRTCViewController.xib',
+ 'examples/objc/Icon.png',
+ ],
+ 'sources': [
+ 'examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.h',
+ 'examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.m',
+ 'examples/objc/AppRTCDemo/ios/APPRTCViewController.h',
+ 'examples/objc/AppRTCDemo/ios/APPRTCViewController.m',
+ 'examples/objc/AppRTCDemo/ios/AppRTCDemo-Prefix.pch',
+ 'examples/objc/AppRTCDemo/ios/main.m',
+ ],
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'examples/objc/AppRTCDemo/ios/Info.plist',
+ },
+ }],
+ ['OS=="mac"', {
+ 'sources': [
+ 'examples/objc/AppRTCDemo/mac/APPRTCAppDelegate.h',
+ 'examples/objc/AppRTCDemo/mac/APPRTCAppDelegate.m',
+ 'examples/objc/AppRTCDemo/mac/APPRTCViewController.h',
+ 'examples/objc/AppRTCDemo/mac/APPRTCViewController.m',
+ 'examples/objc/AppRTCDemo/mac/main.m',
+ ],
+ 'xcode_settings': {
+ 'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'NO',
+ 'INFOPLIST_FILE': 'examples/objc/AppRTCDemo/mac/Info.plist',
+ 'MACOSX_DEPLOYMENT_TARGET' : '10.8',
+ 'OTHER_LDFLAGS': [
+ '-framework AVFoundation',
+ '-framework WebKit',
+ ],
+ },
+ }],
['target_arch=="ia32"', {
'dependencies' : [
'<(DEPTH)/testing/iossim/iossim.gyp:iossim#host',
],
}],
],
+ 'include_dirs': [
+ 'examples/objc/APPRTCDemo',
+ ],
'sources': [
- 'examples/ios/AppRTCDemo/APPRTCAppClient.h',
- 'examples/ios/AppRTCDemo/APPRTCAppClient.m',
- 'examples/ios/AppRTCDemo/APPRTCAppDelegate.h',
- 'examples/ios/AppRTCDemo/APPRTCAppDelegate.m',
- 'examples/ios/AppRTCDemo/APPRTCViewController.h',
- 'examples/ios/AppRTCDemo/APPRTCViewController.m',
- 'examples/ios/AppRTCDemo/AppRTCDemo-Prefix.pch',
- 'examples/ios/AppRTCDemo/GAEChannelClient.h',
- 'examples/ios/AppRTCDemo/GAEChannelClient.m',
- 'examples/ios/AppRTCDemo/main.m',
+ 'examples/objc/AppRTCDemo/APPRTCAppClient.h',
+ 'examples/objc/AppRTCDemo/APPRTCAppClient.m',
+ 'examples/objc/AppRTCDemo/APPRTCConnectionManager.h',
+ 'examples/objc/AppRTCDemo/APPRTCConnectionManager.m',
+ 'examples/objc/AppRTCDemo/GAEChannelClient.h',
+ 'examples/objc/AppRTCDemo/GAEChannelClient.m',
],
'xcode_settings': {
'CLANG_ENABLE_OBJC_ARC': 'YES',
- 'INFOPLIST_FILE': 'examples/ios/AppRTCDemo/Info.plist',
- 'OTHER_LDFLAGS': [
- '-framework Foundation',
- '-framework UIKit',
- ],
},
}, # target AppRTCDemo
], # targets
- }], # OS=="ios"
+ }], # OS=="ios" or (OS=="mac" and target_arch!="ia32" and mac_sdk>="10.8")
['OS=="android"', {
'targets': [
@@ -296,26 +323,26 @@
'examples/android/res/values/strings.xml',
'examples/android/src/org/appspot/apprtc/AppRTCClient.java',
'examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java',
+ 'examples/android/src/org/appspot/apprtc/AppRTCGLView.java',
'examples/android/src/org/appspot/apprtc/UnhandledExceptionHandler.java',
- 'examples/android/src/org/appspot/apprtc/FramePool.java',
'examples/android/src/org/appspot/apprtc/GAEChannelClient.java',
- 'examples/android/src/org/appspot/apprtc/VideoStreamsView.java',
],
'outputs': [
'<(PRODUCT_DIR)/AppRTCDemo-debug.apk',
],
'variables': {
- 'ant_log': '<(INTERMEDIATE_DIR)/ant.log',
+ 'ant_log': '../../<(INTERMEDIATE_DIR)/ant.log', # ../.. to compensate for the cd examples/android below.
},
'action': [
'bash', '-ec',
'rm -fr <(_outputs) examples/android/{bin,libs} && '
+ 'mkdir -p <(INTERMEDIATE_DIR) && ' # Must happen _before_ the cd below
'mkdir -p examples/android/libs/<(android_app_abi) && '
'cp <(PRODUCT_DIR)/libjingle_peerconnection.jar examples/android/libs/ &&'
'<(android_strip) -o examples/android/libs/<(android_app_abi)/libjingle_peerconnection_so.so <(PRODUCT_DIR)/libjingle_peerconnection_so.so &&'
'cd examples/android && '
- 'mkdir -p <(INTERMEDIATE_DIR) && '
- '{ ant -q -l <(ant_log) debug || '
+ '{ ANDROID_SDK_ROOT=<(android_sdk_root) '
+ 'ant debug > <(ant_log) 2>&1 || '
' { cat <(ant_log) ; exit 1; } } && '
'cd - > /dev/null && '
'cp examples/android/bin/AppRTCDemo-debug.apk <(_outputs)'
diff --git a/chromium/third_party/libjingle/source/talk/libjingle_media_unittest.isolate b/chromium/third_party/libjingle/source/talk/libjingle_media_unittest.isolate
index 36b50b5f3aa..666478b438c 100644
--- a/chromium/third_party/libjingle/source/talk/libjingle_media_unittest.isolate
+++ b/chromium/third_party/libjingle/source/talk/libjingle_media_unittest.isolate
@@ -29,16 +29,14 @@
['OS=="linux" or OS=="mac" or OS=="win"', {
'variables': {
'command': [
- '../testing/test_env.py',
'<(PRODUCT_DIR)/libjingle_media_unittest<(EXECUTABLE_SUFFIX)',
],
'isolate_dependency_tracked': [
'media/testdata/captured-320x240-2s-48.frames',
- '../testing/test_env.py',
'<(PRODUCT_DIR)/libjingle_media_unittest<(EXECUTABLE_SUFFIX)',
],
'isolate_dependency_untracked': [
- '../tools/swarming_client/',
+ '<(DEPTH)/tools/swarming_client/',
],
},
}],
diff --git a/chromium/third_party/libjingle/source/talk/libjingle_p2p_unittest.isolate b/chromium/third_party/libjingle/source/talk/libjingle_p2p_unittest.isolate
index b5ad4ff2d89..9ff0d77ad6e 100644
--- a/chromium/third_party/libjingle/source/talk/libjingle_p2p_unittest.isolate
+++ b/chromium/third_party/libjingle/source/talk/libjingle_p2p_unittest.isolate
@@ -29,15 +29,13 @@
['OS=="linux" or OS=="mac" or OS=="win"', {
'variables': {
'command': [
- '../testing/test_env.py',
'<(PRODUCT_DIR)/libjingle_p2p_unittest<(EXECUTABLE_SUFFIX)',
],
'isolate_dependency_tracked': [
- '../testing/test_env.py',
'<(PRODUCT_DIR)/libjingle_p2p_unittest<(EXECUTABLE_SUFFIX)',
],
'isolate_dependency_untracked': [
- '../tools/swarming_client/',
+ '<(DEPTH)/tools/swarming_client/',
],
},
}],
diff --git a/chromium/third_party/libjingle/source/talk/libjingle_peerconnection_unittest.isolate b/chromium/third_party/libjingle/source/talk/libjingle_peerconnection_unittest.isolate
index e7dd6878a64..df07d4a9de3 100644
--- a/chromium/third_party/libjingle/source/talk/libjingle_peerconnection_unittest.isolate
+++ b/chromium/third_party/libjingle/source/talk/libjingle_peerconnection_unittest.isolate
@@ -29,15 +29,13 @@
['OS=="linux" or OS=="mac" or OS=="win"', {
'variables': {
'command': [
- '../testing/test_env.py',
'<(PRODUCT_DIR)/libjingle_peerconnection_unittest<(EXECUTABLE_SUFFIX)',
],
'isolate_dependency_tracked': [
- '../testing/test_env.py',
'<(PRODUCT_DIR)/libjingle_peerconnection_unittest<(EXECUTABLE_SUFFIX)',
],
'isolate_dependency_untracked': [
- '../tools/swarming_client/',
+ '<(DEPTH)/tools/swarming_client/',
],
},
}],
diff --git a/chromium/third_party/libjingle/source/talk/libjingle_sound_unittest.isolate b/chromium/third_party/libjingle/source/talk/libjingle_sound_unittest.isolate
index 7166337956c..728e8104184 100644
--- a/chromium/third_party/libjingle/source/talk/libjingle_sound_unittest.isolate
+++ b/chromium/third_party/libjingle/source/talk/libjingle_sound_unittest.isolate
@@ -29,15 +29,13 @@
['OS=="linux" or OS=="mac" or OS=="win"', {
'variables': {
'command': [
- '../testing/test_env.py',
'<(PRODUCT_DIR)/libjingle_sound_unittest<(EXECUTABLE_SUFFIX)',
],
'isolate_dependency_tracked': [
- '../testing/test_env.py',
'<(PRODUCT_DIR)/libjingle_sound_unittest<(EXECUTABLE_SUFFIX)',
],
'isolate_dependency_untracked': [
- '../tools/swarming_client/',
+ '<(DEPTH)/tools/swarming_client/',
],
},
}],
diff --git a/chromium/third_party/libjingle/source/talk/libjingle_tests.gyp b/chromium/third_party/libjingle/source/talk/libjingle_tests.gyp
index 7bfea590d7d..016f0a506ac 100755
--- a/chromium/third_party/libjingle/source/talk/libjingle_tests.gyp
+++ b/chromium/third_party/libjingle/source/talk/libjingle_tests.gyp
@@ -39,7 +39,11 @@
'<(DEPTH)/testing/gtest/include',
'<(DEPTH)/testing/gtest',
],
+ 'defines': ['_VARIADIC_MAX=10'],
'direct_dependent_settings': {
+ 'defines': [
+ '_VARIADIC_MAX=10',
+ ],
'include_dirs': [
'<(DEPTH)/testing/gtest/include',
],
@@ -100,6 +104,7 @@
{
'target_name': 'libjingle_unittest',
'type': 'executable',
+ 'includes': [ 'build/ios_tests.gypi', ],
'dependencies': [
'gunit',
'libjingle.gyp:libjingle',
@@ -116,8 +121,10 @@
'base/buffer_unittest.cc',
'base/bytebuffer_unittest.cc',
'base/byteorder_unittest.cc',
+ 'base/callback_unittest.cc',
'base/cpumonitor_unittest.cc',
'base/crc32_unittest.cc',
+ 'base/criticalsection_unittest.cc',
'base/event_unittest.cc',
'base/filelock_unittest.cc',
'base/fileutils_unittest.cc',
@@ -144,6 +151,7 @@
'base/ratetracker_unittest.cc',
'base/referencecountedsingletonfactory_unittest.cc',
'base/rollingaccumulator_unittest.cc',
+ 'base/scopedptrcollection_unittest.cc',
'base/sha1digest_unittest.cc',
'base/sharedexclusivelock_unittest.cc',
'base/signalthread_unittest.cc',
@@ -279,6 +287,7 @@
'media/base/videoengine_unittest.h',
'media/devices/dummydevicemanager_unittest.cc',
'media/devices/filevideocapturer_unittest.cc',
+ 'media/sctp/sctpdataengine_unittest.cc',
'media/webrtc/webrtcpassthroughrender_unittest.cc',
'media/webrtc/webrtcvideocapturer_unittest.cc',
# Omitted because depends on non-open-source testdata files.
@@ -288,8 +297,10 @@
# Disabled because some tests fail.
# TODO(ronghuawu): Reenable these tests.
# 'media/devices/devicemanager_unittest.cc',
- # 'media/webrtc/webrtcvideoengine_unittest.cc',
- # 'media/webrtc/webrtcvoiceengine_unittest.cc',
+ 'media/webrtc/webrtcvideoengine_unittest.cc',
+ 'media/webrtc/webrtcvideoengine2_unittest.cc',
+ 'media/webrtc/webrtcvideoengine2_unittest.h',
+ 'media/webrtc/webrtcvoiceengine_unittest.cc',
],
'conditions': [
['OS=="win"', {
@@ -304,6 +315,11 @@
},
},
}],
+ ['OS=="ios"', {
+ 'sources!': [
+ 'media/sctp/sctpdataengine_unittest.cc',
+ ],
+ }],
],
}, # target libjingle_media_unittest
{
@@ -341,6 +357,7 @@
'p2p/client/connectivitychecker_unittest.cc',
'p2p/client/fakeportallocator.h',
'p2p/client/portallocator_unittest.cc',
+ 'session/media/bundlefilter_unittest.cc',
'session/media/channel_unittest.cc',
'session/media/channelmanager_unittest.cc',
'session/media/currentspeakermonitor_unittest.cc',
@@ -350,7 +367,6 @@
'session/media/mediasessionclient_unittest.cc',
'session/media/rtcpmuxfilter_unittest.cc',
'session/media/srtpfilter_unittest.cc',
- 'session/media/ssrcmuxfilter_unittest.cc',
],
'conditions': [
['OS=="win"', {
@@ -368,20 +384,25 @@
'target_name': 'libjingle_peerconnection_unittest',
'type': 'executable',
'dependencies': [
+ '<(DEPTH)/testing/gmock.gyp:gmock',
'gunit',
'libjingle.gyp:libjingle',
'libjingle.gyp:libjingle_p2p',
'libjingle.gyp:libjingle_peerconnection',
'libjingle_unittest_main',
],
- # TODO(ronghuawu): Reenable below unit tests that require gmock.
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(DEPTH)/testing/gmock/include',
+ ],
+ },
'sources': [
- # 'app/webrtc/datachannel_unittest.cc',
+ 'app/webrtc/datachannel_unittest.cc',
'app/webrtc/dtmfsender_unittest.cc',
'app/webrtc/jsepsessiondescription_unittest.cc',
'app/webrtc/localaudiosource_unittest.cc',
- # 'app/webrtc/mediastream_unittest.cc',
- # 'app/webrtc/mediastreamhandler_unittest.cc',
+ 'app/webrtc/mediastream_unittest.cc',
+ 'app/webrtc/mediastreamhandler_unittest.cc',
'app/webrtc/mediastreamsignaling_unittest.cc',
'app/webrtc/peerconnection_unittest.cc',
'app/webrtc/peerconnectionendtoend_unittest.cc',
@@ -389,6 +410,8 @@
'app/webrtc/peerconnectioninterface_unittest.cc',
# 'app/webrtc/peerconnectionproxy_unittest.cc',
'app/webrtc/remotevideocapturer_unittest.cc',
+ 'app/webrtc/sctputils.cc',
+ 'app/webrtc/statscollector_unittest.cc',
'app/webrtc/test/fakeaudiocapturemodule.cc',
'app/webrtc/test/fakeaudiocapturemodule.h',
'app/webrtc/test/fakeaudiocapturemodule_unittest.cc',
@@ -407,6 +430,21 @@
'app/webrtc/webrtcsdp_unittest.cc',
'app/webrtc/webrtcsession_unittest.cc',
],
+ 'conditions': [
+ ['OS=="android"', {
+ # We want gmock features that use tr1::tuple, but we currently
+ # don't support the variadic templates used by libstdc++'s
+ # implementation. gmock supports this scenario by providing its
+ # own implementation but we must opt in to it.
+ 'defines': [
+ 'GTEST_USE_OWN_TR1_TUPLE=1',
+ # GTEST_USE_OWN_TR1_TUPLE only works if GTEST_HAS_TR1_TUPLE is set.
+ # gmock r625 made it so that GTEST_HAS_TR1_TUPLE is set to 0
+ # automatically on android, so it has to be set explicitly here.
+ 'GTEST_HAS_TR1_TUPLE=1',
+ ],
+ }],
+ ],
}, # target libjingle_peerconnection_unittest
],
'conditions': [
@@ -476,11 +514,37 @@
# does just fine on 10.6 too).
'targets': [
{
- 'target_name': 'libjingle_peerconnection_objc_test',
+ 'target_name': 'libjingle_peerconnection_objc_test',
+ 'type': 'executable',
+ 'includes': [ 'build/ios_tests.gypi', ],
+ 'dependencies': [
+ 'gunit',
+ 'libjingle.gyp:libjingle_peerconnection_objc',
+ ],
+ 'sources': [
+ 'app/webrtc/objctests/RTCPeerConnectionSyncObserver.h',
+ 'app/webrtc/objctests/RTCPeerConnectionSyncObserver.m',
+ 'app/webrtc/objctests/RTCPeerConnectionTest.mm',
+ 'app/webrtc/objctests/RTCSessionDescriptionSyncObserver.h',
+ 'app/webrtc/objctests/RTCSessionDescriptionSyncObserver.m',
+ # TODO(fischman): figure out if this works for ios or if it
+ # needs a GUI driver.
+ 'app/webrtc/objctests/mac/main.mm',
+ ],
+ 'FRAMEWORK_SEARCH_PATHS': [
+ '$(inherited)',
+ '$(SDKROOT)/Developer/Library/Frameworks',
+ '$(DEVELOPER_LIBRARY_DIR)/Frameworks',
+ ],
+
+ # TODO(fischman): there is duplication here with
+ # build/ios_tests.gypi, because for historical reasons the
+ # mac x64 bots expect this unittest to be in a bundle
+ # directory (.app). Once the bots don't expect this
+ # anymore, remove this duplication.
'variables': {
- 'infoplist_file': './app/webrtc/objctests/Info.plist',
+ 'infoplist_file': 'build/ios_test.plist',
},
- 'type': 'executable',
'mac_bundle': 1,
'mac_bundle_resources': [
'<(infoplist_file)',
@@ -492,31 +556,18 @@
],
'xcode_settings': {
'CLANG_ENABLE_OBJC_ARC': 'YES',
+ # common.gypi enables this for mac but we want this to be disabled
+ # like it is for ios.
+ 'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'NO',
'INFOPLIST_FILE': '<(infoplist_file)',
},
- 'dependencies': [
- 'gunit',
- 'libjingle.gyp:libjingle_peerconnection_objc',
- ],
- 'FRAMEWORK_SEARCH_PATHS': [
- '$(inherited)',
- '$(SDKROOT)/Developer/Library/Frameworks',
- '$(DEVELOPER_LIBRARY_DIR)/Frameworks',
- ],
- 'sources': [
- 'app/webrtc/objctests/RTCPeerConnectionSyncObserver.h',
- 'app/webrtc/objctests/RTCPeerConnectionSyncObserver.m',
- 'app/webrtc/objctests/RTCPeerConnectionTest.mm',
- 'app/webrtc/objctests/RTCSessionDescriptionSyncObserver.h',
- 'app/webrtc/objctests/RTCSessionDescriptionSyncObserver.m',
- ],
'conditions': [
- ['OS=="mac" or OS=="ios"', {
- 'sources': [
- # TODO(fischman): figure out if this works for ios or if it
- # needs a GUI driver.
- 'app/webrtc/objctests/mac/main.mm',
- ],
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ # Need to build against 10.7 framework for full ARC support
+ # on OSX.
+ 'MACOSX_DEPLOYMENT_TARGET' : '10.7',
+ },
}],
],
}, # target libjingle_peerconnection_objc_test
diff --git a/chromium/third_party/libjingle/source/talk/libjingle_unittest.isolate b/chromium/third_party/libjingle/source/talk/libjingle_unittest.isolate
index e678af013e4..0507f6a8eeb 100644
--- a/chromium/third_party/libjingle/source/talk/libjingle_unittest.isolate
+++ b/chromium/third_party/libjingle/source/talk/libjingle_unittest.isolate
@@ -29,15 +29,13 @@
['OS=="linux" or OS=="mac" or OS=="win"', {
'variables': {
'command': [
- '../testing/test_env.py',
'<(PRODUCT_DIR)/libjingle_unittest<(EXECUTABLE_SUFFIX)',
],
'isolate_dependency_tracked': [
- '../testing/test_env.py',
'<(PRODUCT_DIR)/libjingle_unittest<(EXECUTABLE_SUFFIX)',
],
'isolate_dependency_untracked': [
- '../tools/swarming_client/',
+ '<(DEPTH)/tools/swarming_client/',
],
},
}],
diff --git a/chromium/third_party/libjingle/source/talk/main.scons b/chromium/third_party/libjingle/source/talk/main.scons
deleted file mode 100644
index 76b24af6413..00000000000
--- a/chromium/third_party/libjingle/source/talk/main.scons
+++ /dev/null
@@ -1,889 +0,0 @@
-# -*- Python -*-
-#
-#
-# All the helper functions are defined in:
-# - site_scons/talk.py
-# Use 'import talk' in any .scons file to get access to it.
-# Add any new helper functions to it; unittest are available
-# in talk_unittest.py.
-#
-# Each 'component' that is built is defined in a .scons file.
-# See talk.Components(...) for further info on file naming convention.
-#
-# To add a new platform clone and modify the root_env object. Remember to add
-# the new environment object to the envs list otherwise it will not be included
-# in the build.
-#
-#
-#
-
-import talk
-import os
-import platform
-
-#-------------------------------------------------------------------------------
-# The build files/directories to 'build'.
-# If the name is the name of a directory then that directory shall contain a
-# .scons file with the same name as the directory itself:
-# Ex: The directory session/phone contains a file called phone.scons
-# This list must be in order of library dependencies. e.g., if
-# session/phone/phone.scons defines a target that links to a library target
-# defined in sound/sound.scons, then 'sound' must come first.
-# When no particular order is imposed by library dependencies, try to keep in
-# mostly alphabetical order.
-#
-components = talk.Components("libjingle.scons")
-
-#-------------------------------------------------------------------------------
-# Build environments
-#
-
-# The list of build environments.
-envs = []
-
-# The root of all builds.
-root_env = Environment(
- tools = [
- 'component_bits',
- 'component_setup',
- 'replace_strings',
- 'talk_noops',
- #'talk_utils',
- ],
- BUILD_SCONSCRIPTS = components,
- DESTINATION_ROOT = '$MAIN_DIR/build',
- CPPPATH = [
- '$OBJ_ROOT', # generated headers are relative to here
- '$MAIN_DIR/..', # TODO(dape): how can we use GOOGLECLIENT instead?
- ],
- CPPDEFINES = [
- 'LOGGING=1',
-
- # Feature selection
- 'FEATURE_ENABLE_SSL',
- 'FEATURE_ENABLE_VOICEMAIL',
- 'FEATURE_ENABLE_PSTN',
- 'HAVE_SRTP',
- ],
- # Ensure the os environment is captured for any scripts we call out to
- ENV = os.environ,
-)
-
-# This is where we set common environments
-#
-# Detect if building on 64-bit or 32-bit platform.
-DeclareBit('build_platform_64bit', 'Platform of the build machine is 64-bit')
-if platform.architecture()[0] == "64bit":
- root_env.SetBits('build_platform_64bit')
-
-# This bit denotes that an env is for 64-bit builds. When set, all build
-# artifacts will be 64-bit. When unset, all build artifacts will be 32-bit.
-DeclareBit('host_platform_64bit',
- 'Platform of the host machine (where artifacts will execute) is '
- '64-bit')
-
-# This bit denotes that we are cross-compiling using a sysroot.
-DeclareBit('cross_compile',
- 'Cross compiling using the SYSROOT environment variable')
-
-def CrossArch(env):
- """Return whether or not the host platform architecture differs from the build
- environment architecture."""
- if env.Bit('cross_compile'):
- # The architecture of the Python process may not match the architecture of
- # the sysroot, so we just assume it's not a cross-arch build or that it
- # doesn't matter. Currently it only matters if you try to build a cross-arch
- # Debian package, so just don't do that.
- return False
- else:
- return env.Bit('host_platform_64bit') != env.Bit('build_platform_64bit')
-root_env.AddMethod(CrossArch)
-
-DeclareBit('use_static_openssl', 'Build OpenSSL as a static library')
-
-DeclareBit('have_dbus_glib',
- 'Whether the build system has the dbus-glib-1 package')
-DeclareBit('have_libpulse',
- 'Whether the build system has the libpulse package')
-
-
-# List all the locales we localize to.
-root_env.AppendUnique(locales = [
- 'af', 'am', 'ar', 'bg', 'bn', 'ca', 'cs', 'da', 'de', 'el', 'en', 'en-GB',
- 'es', 'es-419', 'et', 'eu', 'fa', 'fi', 'fil', 'fr', 'fr-CA', 'gl', 'gu',
- 'hi', 'hr', 'hu', 'id', 'is', 'it', 'iw', 'ja', 'kn', 'ko', 'lt', 'lv',
- 'ml', 'mr', 'ms', 'nl', 'no', 'or', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru',
- 'sk', 'sl', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tl', 'tr', 'uk', 'ur',
- 'vi', 'zh-CN', 'zh-HK', 'zh-TW', 'zu'])
-
-AddTargetGroup('all_breakpads', 'breakpad files can be built')
-
-AddTargetGroup('all_dsym', 'dsym debug packages can be built')
-
-#-------------------------------------------------------------------------------
-# W I N D O W S
-#
-win_env = root_env.Clone(
- tools = [
- 'atlmfc_vc80',
- #'code_signing',
- 'component_targets_msvs',
- 'directx_9_0_c',
- #'grid_builder',
- 'midl',
- 'target_platform_windows'
- ],
- # Don't use default vc80 midl.exe. It doesn't understand vista_sdk idl files.
- MIDL = '$PLATFORM_SDK_VISTA_6_0_DIR/Bin/midl.exe ',
- WIX_DIR = '$GOOGLECLIENT/third_party/wix/v3_0_2925/files',
- # Flags for debug and optimization are added to CCFLAGS instead
- CCPDBFLAGS = '',
- CCFLAGS_DEBUG = '',
- CCFLAGS_OPTIMIZED = '',
- # We force a x86 target even when building on x64 Windows platforms.
- TARGET_ARCH = 'x86',
-)
-
-
-win_env.Decider('MD5-timestamp')
-win_env.Append(
- COMPONENT_LIBRARY_PUBLISH = True, # Put dlls in output dir too
- CCFLAGS = [
- '/Fd${TARGET}.pdb', # pdb per object allows --jobs=
- '/WX', # warnings are errors
- '/Zc:forScope', # handle 'for (int i = 0 ...)' right
- '/EHs-c-', # disable C++ EH
- '/GR-', # disable RTTI
- '/Gy', # enable function level linking
- '/wd4996', # ignore POSIX deprecated warnings
-
- # promote certain level 4 warnings
- '/w14701', # potentially uninitialized var
- '/w14702', # unreachable code
- '/w14706', # assignment within a conditional
- '/w14709', # comma operator within array index
- '/w14063', # case 'identifier' is not a valid value for switch of enum
- '/w14064', # switch of incomplete enum 'enumeration'
- '/w14057', # 'identifier1' indirection to slightly different base
- # types from 'identifier2'
- '/w14263', # member function does not override any base class virtual
- # member function
- '/w14266', # no override available for virtual memberfunction from base
- # 'type'; function is hidden
- '/w14296', # expression is always false
- '/w14355', # 'this' : used in base member initializer list
- ],
- CPPDEFINES = [
- '_ATL_CSTRING_EXPLICIT_CONSTRUCTORS',
- # TODO(dape): encapsulate all string operations that are not based
- # on std::string/std::wstring and make sure we use the safest versions
- # available on all platforms.
- '_CRT_SECURE_NO_WARNINGS',
- '_USE_32BIT_TIME_T',
- '_UNICODE',
- 'UNICODE',
- '_HAS_EXCEPTIONS=0',
- 'WIN32',
- # TODO(dape): remove this from logging.cc and enable here instead.
- #'WIN32_LEAN_AND_MEAN',
-
- 'WINVER=0x0500',
- '_WIN32_WINNT=0x0501',
- '_WIN32_IE=0x0501',
- # The Vista platform SDK 6.0 needs at least
- # this NTDDI version or else the headers
- # that LMI includes from it won't compile.
- 'NTDDI_VERSION=NTDDI_WINXP',
-
- # npapi.h requires the following:
- '_WINDOWS',
- ],
- CPPPATH = [
- '$THIRD_PARTY/wtl_71/include',
- '$PLATFORM_SDK_VISTA_6_0_DIR/Include',
- ],
- LIBPATH = [
- '$PLATFORM_SDK_VISTA_6_0_DIR/Lib'
- ],
- LINKFLAGS = [
- '-manifest', # TODO(thaloun): Why do we need this?
- # Some of the third-party libraries we link in don't have public symbols, so
- # ignore that linker warning.
- '/ignore:4221',
- '/nxcompat', # Binary was tested to be be compatible with Windows DEP.
- '/dynamicbase', # Use ASLR to dynamically rebase at load-time.
- '/fixed:no', # Binary can be loaded at any base-address.
- ],
- MIDLFLAGS = [
- '/win32',
- '/I$PLATFORM_SDK_VISTA_6_0_DIR/include'
- ]
-)
-
-# TODO(dape): Figure out what this does; found it in
-# omaha/main.scons. This fixes the problem with redefinition
-# of OS_WINDOWS symbol.
-win_env.FilterOut(CPPDEFINES = ['OS_WINDOWS=OS_WINDOWS'])
-
-# Set up digital signing
-DeclareBit('test_signing', 'Sign binaries with the test certificate')
-win_env.SetBitFromOption('test_signing', False)
-if win_env.Bit('test_signing'):
- win_env.Replace(
- CERTIFICATE_PATH = win_env.File(
- '$GOOGLECLIENT/tools/test_key/testkey.pfx').abspath,
- CERTIFICATE_PASSWORD = 'test',
- )
-AddTargetGroup('signed_binaries', 'digitally signed binaries can be built')
-
-win_dbg_env = win_env.Clone(
- BUILD_TYPE = 'dbg',
- BUILD_TYPE_DESCRIPTION = 'Windows debug build',
- BUILD_GROUPS = ['default', 'all'],
- tools = ['target_debug'],
-)
-
-win_dbg_env.Prepend(
- CCFLAGS = [
- '/ZI', # enable debugging
- '/Od', # disable optimizations
- '/MTd', # link with LIBCMTD.LIB debug lib
- '/RTC1', # enable runtime checks
- ],
-)
-
-envs.append(win_dbg_env)
-
-win_dbg64_env = win_dbg_env.Clone(
- BUILD_TYPE = 'dbg64',
- BUILD_TYPE_DESCRIPTION = 'Windows debug 64bit build',
- BUILD_GROUPS = ['all'],
-)
-
-win_dbg64_env.FilterOut(CCFLAGS = ['/ZI'])
-
-win_dbg64_env.Append(
- CCFLAGS = [
- '/Zi', # enable debugging that is 64 bit compatible.
- # TODO(fbarchard): fix warnings and remove these disables.
- '/wd4244', # disable cast warning
- '/wd4267', # disable cast warning
- ],
- ARFLAGS = [
- '/MACHINE:x64',
- ],
- CPPDEFINES = [
- 'WIN64',
- 'ARCH_CPU_64_BITS',
- ],
- LIBFLAGS = [
- '/MACHINE:x64',
- ],
- LINKFLAGS = [
- '/MACHINE:x64',
- ],
-)
-
-win_dbg64_env.FilterOut(CPPDEFINES = ['_USE_32BIT_TIME_T'])
-
-win_dbg64_env.Prepend(
- LIBPATH = [
- '$VC80_DIR/vc/lib/amd64',
- '$ATLMFC_VC80_DIR/lib/amd64',
- '$PLATFORM_SDK_VISTA_6_0_DIR/Lib/x64',
- ],
-)
-win_dbg64_env.PrependENVPath(
- 'PATH',
- win_dbg64_env.Dir('$VC80_DIR/vc/bin/x86_amd64'))
-
-win_dbg64_env.SetBits('host_platform_64bit')
-
-envs.append(win_dbg64_env)
-
-win_coverage_env = win_dbg_env.Clone(
- tools = ['code_coverage'],
- BUILD_TYPE = 'coverage',
- BUILD_TYPE_DESCRIPTION = 'Windows code coverage build',
- BUILD_GROUPS = ['all'],
-)
-
-win_coverage_env.Append(
- CPPDEFINES = [
- 'COVERAGE_ENABLED',
- ],
-)
-
-envs.append(win_coverage_env)
-
-win_opt_env = win_env.Clone(
- BUILD_TYPE = 'opt',
- BUILD_TYPE_DESCRIPTION = 'Windows opt build',
- BUILD_GROUPS = ['all'],
- tools = ['target_optimized'],
-)
-
-win_opt_env.Prepend(
- CCFLAGS=[
- '/Zi', # enable debugging
- '/O1', # optimize for size
- '/fp:fast', # float faster but less precise
- '/MT', # link with LIBCMT.LIB (multi-threaded, static linked crt)
- '/GS', # enable security checks
- ],
- LINKFLAGS = [
- '/safeseh', # protect against attacks against exception handlers
- '/opt:ref', # Remove unused references (functions/data).
- ],
-)
-
-envs.append(win_opt_env)
-
-#-------------------------------------------------------------------------------
-# P O S I X
-#
-posix_env = root_env.Clone()
-posix_env.Append(
- CPPDEFINES = [
- 'HASHNAMESPACE=__gnu_cxx',
- 'HASH_NAMESPACE=__gnu_cxx',
- 'POSIX',
- 'DISABLE_DYNAMIC_CAST',
- # The POSIX standard says we have to define this.
- '_REENTRANT',
- ],
- CCFLAGS = [
- '-Wall',
- '-Werror',
- '-Wno-switch',
- '-fno-exceptions',
- # Needed for a clean ABI and for link-time dead-code removal to work
- # properly.
- '-fvisibility=hidden',
- # Generate debugging info in the DWARF2 format.
- '-gdwarf-2',
- # Generate maximal debugging information. (It is stripped from what we ship
- # to users, so we want it for both dbg and opt.)
- # Note that hammer automatically supplies "-g" for mac/linux dbg, so that
- # flag must be filtered out of linux_dbg and mac_dbg envs below.
- '-g3',
- ],
- CXXFLAGS = [
- '-Wno-non-virtual-dtor',
- '-Wno-ctor-dtor-privacy',
- '-fno-rtti',
- ],
-)
-
-# Switch-hit between NSS and OpenSSL
-if 'NSS_BUILD_PLATFORM' in root_env['ENV']:
- posix_env.AppendUnique(CPPDEFINES=['HAVE_NSS_SSL_H=1',
- 'NSS_SSL_RELATIVE_PATH'])
-else:
- posix_env.AppendUnique(CPPDEFINES=['HAVE_OPENSSL_SSL_H=1'])
-
-
-#-------------------------------------------------------------------------------
-# M A C OSX
-#
-mac_env = posix_env.Clone(
- tools = [
- 'target_platform_mac',
- #'talk_mac',
- #'fill_plist',
- ],
-)
-# Use static OpenSSL on mac so that we can use the latest APIs on all
-# supported mac platforms (10.5+).
-mac_env.SetBits('use_static_openssl')
-
-# For libjingle we don't specify a sysroot or minimum OS version.
-mac_osx_version_min_32 = ""
-mac_osx_version_min_64 = ""
-
-# Generic mac environment common to all targets
-mac_env.Append(
- CPPDEFINES = [
- 'OSX',
- ],
- CCFLAGS = [
- '-arch', 'i386',
- '-fasm-blocks',
- ],
- LINKFLAGS = [
- '-Wl,-search_paths_first',
- # This flag makes all members of a static library be included in the
- # final exe - that increases the size of the exe, but without it
- # Obj-C categories aren't properly included in the exe.
- # TODO(thaloun): consider only defining for libs that actually have objc.
- '-ObjC',
- '-arch', 'i386',
- '-dead_strip',
- ],
- FRAMEWORKS = [
- 'CoreServices',
- 'Security',
- 'SystemConfiguration',
- 'OpenGL',
- 'CoreAudio',
- 'Quartz',
- 'Cocoa',
- 'QTKit',
- ]
-)
-
-if 'NSS_BUILD_PLATFORM' in root_env['ENV']:
- mac_env.AppendUnique(LINKFLAGS = ['-Lthird_party/mozilla/dist/' + root_env['ENV']['NSS_BUILD_PLATFORM'] + '/lib'])
-else:
- mac_env.AppendUnique(LINKFLAGS = ['-Lthird_party/openssl'])
-
-
-# add debug flags to environment
-def mac_debug_include(env):
- env.Append(
- CCFLAGS = [
- '-O0',
- ],
- CPPDEFINES = [
- 'DEBUG=1',
- ],
- )
- # Remove -g set by hammer, which is not what we want (we have set -g3 above).
- env.FilterOut(CCFLAGS = ['-g'])
-
-# add 32/64 bit specific options to specified environment
-def mac_common_include_x86_32(env):
- env.Append(
- CCFLAGS = [
- '-m32',
- ],
- LINKFLAGS = [
- '-m32',
- ],
- FRAMEWORKS = [
- 'Carbon',
- 'QuickTime',
- ],
- )
- envs.append(env)
-
-def mac_common_include_x86_64(env):
- env.Append(
- CCFLAGS = [
- '-m64',
- '-fPIC',
- ],
- CPPDEFINES = [
- 'ARCH_CPU_64_BITS',
- 'CARBON_DEPRECATED',
- ],
- LINKFLAGS = [
- '-m64',
- ],
- FRAMEWORKS = [
- 'AppKit',
- ],
- )
- env.SetBits('host_platform_64bit')
- envs.append(env)
-
-def mac_osx_version_min(env, ver):
- if ver != "":
- sdk_path = '/Developer/SDKs/MacOSX%s.sdk' % ver
- env.Append(
- CCFLAGS = [
- '-mmacosx-version-min=' + ver,
- '-isysroot', sdk_path,
- ],
- LINKFLAGS = [
- '-mmacosx-version-min=' + ver,
- '-isysroot', sdk_path,
- ],
- osx_sdk_path = sdk_path,
- osx_version_min = ver,
- )
-
-# Create all environments
-mac_dbg_env = mac_env.Clone(
- BUILD_TYPE = 'dbg',
- BUILD_TYPE_DESCRIPTION = 'Mac debug build',
- BUILD_GROUPS = ['default', 'all'],
- tools = ['target_debug'],
-)
-
-mac_opt_env = mac_env.Clone(
- BUILD_TYPE = 'opt',
- BUILD_TYPE_DESCRIPTION = 'Mac opt build',
- BUILD_GROUPS = ['all'],
- tools = ['target_optimized'],
-)
-
-mac_dbg64_env = mac_dbg_env.Clone(
- BUILD_TYPE = 'dbg64',
- BUILD_TYPE_DESCRIPTION = 'Mac debug 64bit build',
- BUILD_GROUPS = ['all'],
-)
-
-mac_opt64_env = mac_opt_env.Clone(
- BUILD_TYPE = 'opt64',
- BUILD_TYPE_DESCRIPTION = 'Mac opt 64bit build',
- BUILD_GROUPS = ['all'],
-)
-
-mac_debug_include(mac_dbg_env)
-mac_debug_include(mac_dbg64_env)
-mac_common_include_x86_32(mac_dbg_env)
-mac_common_include_x86_32(mac_opt_env)
-mac_common_include_x86_64(mac_dbg64_env)
-mac_common_include_x86_64(mac_opt64_env)
-mac_osx_version_min(mac_dbg_env, mac_osx_version_min_32)
-mac_osx_version_min(mac_opt_env, mac_osx_version_min_32)
-mac_osx_version_min(mac_dbg64_env, mac_osx_version_min_64)
-mac_osx_version_min(mac_opt64_env, mac_osx_version_min_64)
-
-
-#-------------------------------------------------------------------------------
-# L I N U X
-#
-linux_common_env = posix_env.Clone(
- tools = [
- 'target_platform_linux',
- 'talk_linux',
- ],
-)
-
-linux_common_env.Append(
- CPPDEFINES = [
- 'LINUX',
- ],
- CCFLAGS = [
- # Needed for link-time dead-code removal to work properly.
- '-ffunction-sections',
- '-fdata-sections',
- ],
- LINKFLAGS = [
- # Enable dead-code removal.
- '-Wl,--gc-sections',
- # Elide dependencies on shared libraries that we're not actually using.
- '-Wl,--as-needed',
- '-Wl,--start-group',
- ],
- _LIBFLAGS = ['-Wl,--end-group'],
-)
-
-# Remove default rpath set by Hammer. Hammer sets it to LIB_DIR, which is wrong.
-# The rpath is the _run-time_ library search path for the resulting binary, i.e.
-# the one used by ld.so at load time. Setting it equal to the path to build
-# output on the build machine is nonsense.
-linux_common_env.Replace(
- RPATH = [],
-)
-
-# Enable the optional DBus-GLib code if the build machine has the required
-# dependency.
-linux_common_env.EnableFeatureWherePackagePresent('have_dbus_glib',
- 'HAVE_DBUS_GLIB',
- 'dbus-glib-1')
-
-def linux_common_include_x86_32(env):
- """Include x86-32 settings into an env based on linux_common."""
- env.Append(
- CCFLAGS = [
- '-m32',
- ],
- LINKFLAGS = [
- '-m32',
- ],
- )
-
-def linux_common_include_x86_64(env):
- """Include x86-64 settings into an env based on linux_common."""
- env.Append(
- CCFLAGS = [
- '-m64',
- '-fPIC',
- ],
- LINKFLAGS = [
- '-m64',
- ],
- )
- env.SetBits('host_platform_64bit')
-
-#-------------------------------------------------------------------------------
-# L I N U X -- C R O S S -- B U I L D
-
-# Cross build requires the following tool names be provided by the environment:
-linux_cross_common_env = linux_common_env.Clone(
- AR = os.environ.get("AR"),
- AS = os.environ.get("AS"),
- LD = os.environ.get("LD"),
- NM = os.environ.get("NM"),
- RANLIB = os.environ.get("RANLIB"),
- CC = str(os.environ.get("CC")) +
- ' --sysroot=' + str(os.environ.get("SYSROOT")),
- CXX = str(os.environ.get("CXX")) +
- ' --sysroot=' + str(os.environ.get("SYSROOT")),
-)
-linux_cross_common_env.SetBits('cross_compile')
-
-# The rest of these paths and flags are optional:
-if os.environ.get("CPPPATH"):
- linux_cross_common_env.Append(
- CPPPATH = os.environ.get("CPPPATH").split(':'),
- )
-if os.environ.get("LIBPATH"):
- linux_cross_common_env.Append(
- LIBPATH = os.environ.get("LIBPATH").split(':'),
- )
-if os.environ.get("CFLAGS"):
- linux_cross_common_env.Append(
- CFLAGS = os.environ.get("CFLAGS").split(' '),
- )
-if os.environ.get("CCFLAGS"):
- linux_cross_common_env.Append(
- CCFLAGS = os.environ.get("CCFLAGS").split(' '),
- )
-if os.environ.get("CXXFLAGS"):
- linux_cross_common_env.Append(
- CXXFLAGS = os.environ.get("CXXFLAGS").split(' '),
- )
-if os.environ.get("LIBFLAGS"):
- linux_cross_common_env.Append(
- _LIBFLAGS = os.environ.get("LIBFLAGS").split(' '),
- )
-if os.environ.get("LINKFLAGS"):
- linux_cross_common_env.Prepend(
- LINKFLAGS = os.environ.get("LINKFLAGS").split(' '),
- )
-
-#-------------------------------------------------------------------------------
-# L I N U X -- T R A D I T I O N A L -- X 8 6
-#
-# Settings that are specific to our desktop Linux x86 targets.
-def linux_common_include_traditional(env):
- """Include traditional Linux settings into an env based on linux_common."""
- # OpenSSL has infamously poor ABI stability, so that building against one
- # version and running against a different one often will not work. Since our
- # non-ChromeOS Linux builds are used on many different distros and distro
- # versions, this means we can't safely dynamically link to OpenSSL because the
- # product would end up being broken on any computer with a different version
- # installed. So instead we build it ourself and statically link to it.
- env.SetBits('use_static_openssl')
- # Enable the optional PulseAudio code if the build machine has the required
- # dependency.
- # TODO(?): This belongs in linux_common_env, but we can't safely move it there
- # yet because pkg-config is not being used properly with ChromeOS builds (see
- # TODO below).
- env.EnableFeatureWherePackagePresent('have_libpulse',
- 'HAVE_LIBPULSE',
- 'libpulse')
-
-def linux_traditional_include_dbg(env):
- """Include traditional Linux dbg settings into an env based on the above."""
- # Remove -g set by hammer, which is not what we want (we have set -g3 above).
- env.FilterOut(CCFLAGS = ['-g'])
-
-def linux_traditional_include_opt(env):
- """Include traditional Linux opt settings into an env based on the above."""
- # Remove -O2 set by hammer, which is not what we want.
- env.FilterOut(CCFLAGS = ['-O2'])
- env.Append(CCFLAGS = ['-Os'])
-
-def gen_linux_nonhermetic(linux_env, type_suffix, desc_suffix):
- groups = ['nonhermetic']
- if not linux_env.CrossArch():
- groups = groups + ['nonhermetic-native']
- # The non-hermetic, native-arch dbg build is the default.
- dbg_groups = groups + ['default']
- native_desc = ', native '
- # No suffix for native modes.
- type_suffix = ''
- else:
- groups = groups + ['nonhermetic-cross']
- dbg_groups = groups
- native_desc = ', cross-built for '
-
- linux_dbg_env = linux_env.Clone(
- BUILD_TYPE = 'dbg' + type_suffix,
- BUILD_TYPE_DESCRIPTION = 'Linux debug build%s%s' % (native_desc,
- desc_suffix),
- BUILD_GROUPS = dbg_groups,
- tools = ['target_debug'],
- )
- linux_traditional_include_dbg(linux_dbg_env)
- envs.append(linux_dbg_env)
-
- linux_opt_env = linux_env.Clone(
- BUILD_TYPE = 'opt' + type_suffix,
- BUILD_TYPE_DESCRIPTION = 'Linux optimized build%s%s' % (native_desc,
- desc_suffix),
- BUILD_GROUPS = groups,
- tools = ['target_optimized'],
- )
- linux_traditional_include_opt(linux_opt_env)
- envs.append(linux_opt_env)
-
-linux_nonhermetic_common_env = linux_common_env.Clone()
-linux_common_include_traditional(linux_nonhermetic_common_env)
-
-linux_nonhermetic_x86_32_env = linux_nonhermetic_common_env.Clone()
-linux_common_include_x86_32(linux_nonhermetic_x86_32_env)
-gen_linux_nonhermetic(linux_nonhermetic_x86_32_env, '32', '32-bit')
-
-linux_nonhermetic_x86_64_env = linux_nonhermetic_common_env.Clone()
-linux_common_include_x86_64(linux_nonhermetic_x86_64_env)
-gen_linux_nonhermetic(linux_nonhermetic_x86_64_env, '64', '64-bit')
-
-def gen_linux_hermetic(linux_env, type_suffix, desc):
- groups = ['hermetic']
-
- linux_dbg_env = linux_env.Clone(
- BUILD_TYPE = 'hermetic-dbg' + type_suffix,
- BUILD_TYPE_DESCRIPTION = 'Hermetic %s Linux debug build' % desc,
- BUILD_GROUPS = groups,
- tools = ['target_debug'],
- )
- linux_traditional_include_dbg(linux_dbg_env)
- envs.append(linux_dbg_env)
-
- linux_opt_env = linux_env.Clone(
- BUILD_TYPE = 'hermetic-opt' + type_suffix,
- BUILD_TYPE_DESCRIPTION = 'Hermetic %s Linux optimized build' % desc,
- BUILD_GROUPS = groups,
- tools = ['target_optimized'],
- )
- linux_traditional_include_opt(linux_opt_env)
- envs.append(linux_opt_env)
-
-linux_hermetic_common_env = linux_cross_common_env.Clone()
-linux_common_include_traditional(linux_hermetic_common_env)
-
-linux_hermetic_x86_32_env = linux_hermetic_common_env.Clone()
-linux_common_include_x86_32(linux_hermetic_x86_32_env)
-gen_linux_hermetic(linux_hermetic_x86_32_env, '32', '32-bit')
-
-linux_hermetic_x86_64_env = linux_hermetic_common_env.Clone()
-linux_common_include_x86_64(linux_hermetic_x86_64_env)
-gen_linux_hermetic(linux_hermetic_x86_64_env, '64', '64-bit')
-
-#-------------------------------------------------------------------------------
-# L I N U X -- C R O S S -- B U I L D -- A R M
-
-# TODO(noahric): All the following Linux builds are running against a sysroot
-# but improperly using the host machine's pkg-config environment. The ChromeOS
-# ones should probably be using
-# https://cs.corp.google.com/#chrome/src/build/linux/pkg-config-wrapper.
-
-linux_cross_arm_env = linux_cross_common_env.Clone()
-linux_cross_arm_env.Append(
- CPPDEFINES = [
- 'NACL_BUILD_ARCH=arm',
- 'DISABLE_EFFECTS=1',
- ],
- CCFLAGS = [
- '-fPIC',
- ],
-)
-DeclareBit('arm', 'ARM build')
-linux_cross_arm_env.SetBits('arm')
-
-# Detect NEON support from the -mfpu build flag.
-DeclareBit('arm_neon', 'ARM supporting neon')
-if '-mfpu=neon' in linux_cross_arm_env['CFLAGS'] or \
- '-mfpu=neon' in linux_cross_arm_env['CCFLAGS'] or \
- '-mfpu=neon' in linux_cross_arm_env['CXXFLAGS']:
- print "Building with ARM NEON support."
- linux_cross_arm_env.SetBits('arm_neon')
-
-# Detect hardfp from the -mfloat-abi build flag
-DeclareBit('arm_hardfp', 'ARM supporting hardfp')
-if '-mfloat-abi=hard' in linux_cross_arm_env['CFLAGS'] or \
- '-mfloat-abi=hard' in linux_cross_arm_env['CCFLAGS'] or \
- '-mfloat-abi=hard' in linux_cross_arm_env['CXXFLAGS']:
- print "Building with hard floating point support."
- linux_cross_arm_env.SetBits('arm_hardfp')
-
-linux_cross_arm_dbg_env = linux_cross_arm_env.Clone(
- BUILD_TYPE = 'arm-dbg',
- BUILD_TYPE_DESCRIPTION = 'Cross-compiled ARM debug build',
- BUILD_GROUPS = ['arm'],
- tools = ['target_debug'],
-)
-envs.append(linux_cross_arm_dbg_env)
-
-linux_cross_arm_opt_env = linux_cross_arm_env.Clone(
- BUILD_TYPE = 'arm-opt',
- BUILD_TYPE_DESCRIPTION = 'Cross-compiled ARM optimized build',
- BUILD_GROUPS = ['arm'],
- tools = ['target_optimized'],
-)
-envs.append(linux_cross_arm_opt_env)
-
-
-
-# Create a group for installers
-AddTargetGroup('all_installers', 'installers that can be built')
-
-# Parse child .scons files
-BuildEnvironments(envs)
-
-# Explicitly set which targets to build when not stated on commandline
-Default(None)
-# Build the following, which excludes unit test output (ie running them)
-# To run unittests, specify the test to run, or run_all_tests. See -h option.
-Default(['all_libraries', 'all_programs', 'all_test_programs'])
-
-# .sln creation code lifted from googleclient/bar/main.scons. Must be after
-# the call to BuildEnvironments for all_foo aliases to be defined.
-# Run 'hammer --mode=all --vsproj' to generate
-DeclareBit('vsproj', 'Generate Visual Studio projects and solution files.')
-win_env.SetBitFromOption('vsproj', False)
-
-if win_env.Bit('vsproj'):
- vs_env = win_env.Clone()
- vs_env.Append(
- COMPONENT_VS_SOURCE_SUFFIXES = [
- '.def',
- '.grd',
- '.html',
- '.idl',
- '.mk',
- '.txt',
- '.py',
- '.scons',
- '.wxs.template',
- ]
- )
-
- # Source project
- p = vs_env.ComponentVSDirProject(
- 'flute_source',
- ['$MAIN_DIR',
- ],
- COMPONENT_VS_SOURCE_FOLDERS = [
- # Files are assigned to first matching folder. Folder names of None
- # are filters.
- (None, '$DESTINATION_ROOT'),
- ('flute', '$MAIN_DIR'),
- ('google3', '$GOOGLE3'),
- ('third_party', '$THIRD_PARTY'),
- ],
- # Force source project to main dir, so that Visual Studio can find the
- # source files corresponding to build errors.
- COMPONENT_VS_PROJECT_DIR = '$MAIN_DIR',
- )
- vs_env.AlwaysBuild(p)
-
- # Solution and target projects
- s = vs_env.ComponentVSSolution(
- # 'libjingle', # Please uncomment this line if you build VS proj files.
- ['all_libraries', 'all_programs', 'all_test_programs'],
- projects = [p],
- )
-
- print '***Unfortunately the vsproj creator isn\'t smart enough to '
- print '***automatically get the correct output locations. It is very easy'
- print '***though to change it in the properties pane to the following'
- print '***$(SolutionDir)/build/<foo>/staging/<bar>.exe'
- Default(None)
- Default([s])
diff --git a/chromium/third_party/libjingle/source/talk/media/base/audiorenderer.h b/chromium/third_party/libjingle/source/talk/media/base/audiorenderer.h
index 273312fab35..155331820f4 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/audiorenderer.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/audiorenderer.h
@@ -30,18 +30,42 @@
namespace cricket {
-// Abstract interface for holding the voice channel IDs.
+// Abstract interface for rendering the audio data.
class AudioRenderer {
public:
+ class Sink {
+ public:
+ // Callback to receive data from the AudioRenderer.
+ virtual void OnData(const void* audio_data,
+ int bits_per_sample,
+ int sample_rate,
+ int number_of_channels,
+ int number_of_frames) = 0;
+
+ // Called when the AudioRenderer is going away.
+ virtual void OnClose() = 0;
+
+ protected:
+ virtual ~Sink() {}
+ };
+
+ // Sets a sink to the AudioRenderer. There can be only one sink connected
+ // to the renderer at a time.
+ virtual void SetSink(Sink* sink) {}
+
// Add the WebRtc VoE channel to the renderer.
// For local stream, multiple WebRtc VoE channels can be connected to the
// renderer. While for remote stream, only one WebRtc VoE channel can be
// connected to the renderer.
- virtual void AddChannel(int channel_id) = 0;
+ // TODO(xians): Remove this interface after Chrome switches to the
+ // AudioRenderer::Sink interface.
+ virtual void AddChannel(int channel_id) {}
// Remove the WebRtc VoE channel from the renderer.
// This method is called when the VoE channel is going away.
- virtual void RemoveChannel(int channel_id) = 0;
+ // TODO(xians): Remove this interface after Chrome switches to the
+ // AudioRenderer::Sink interface.
+ virtual void RemoveChannel(int channel_id) {}
protected:
virtual ~AudioRenderer() {}
diff --git a/chromium/third_party/libjingle/source/talk/media/base/codec.cc b/chromium/third_party/libjingle/source/talk/media/base/codec.cc
index 2d54c9907a4..6e65560c2ec 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/codec.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/codec.cc
@@ -31,6 +31,7 @@
#include <sstream>
#include "talk/base/common.h"
+#include "talk/base/logging.h"
#include "talk/base/stringencode.h"
#include "talk/base/stringutils.h"
@@ -160,6 +161,55 @@ std::string VideoCodec::ToString() const {
return os.str();
}
+VideoCodec VideoCodec::CreateRtxCodec(int rtx_payload_type,
+ int associated_payload_type) {
+ VideoCodec rtx_codec(rtx_payload_type, kRtxCodecName, 0, 0, 0, 0);
+ rtx_codec.SetParam(kCodecParamAssociatedPayloadType, associated_payload_type);
+ return rtx_codec;
+}
+
+VideoCodec::CodecType VideoCodec::GetCodecType() const {
+ const char* payload_name = name.c_str();
+ if (_stricmp(payload_name, kRedCodecName) == 0) {
+ return CODEC_RED;
+ }
+ if (_stricmp(payload_name, kUlpfecCodecName) == 0) {
+ return CODEC_ULPFEC;
+ }
+ if (_stricmp(payload_name, kRtxCodecName) == 0) {
+ return CODEC_RTX;
+ }
+
+ return CODEC_VIDEO;
+}
+
+bool VideoCodec::ValidateCodecFormat() const {
+ if (id < 0 || id > 127) {
+ LOG(LS_ERROR) << "Codec with invalid payload type: " << ToString();
+ return false;
+ }
+ if (GetCodecType() != CODEC_VIDEO) {
+ return true;
+ }
+
+ // Video validation from here on.
+
+ if (width <= 0 || height <= 0) {
+ LOG(LS_ERROR) << "Codec with invalid dimensions: " << ToString();
+ return false;
+ }
+ int min_bitrate = -1;
+ int max_bitrate = -1;
+ if (GetParam(kCodecParamMinBitrate, &min_bitrate) &&
+ GetParam(kCodecParamMaxBitrate, &max_bitrate)) {
+ if (max_bitrate < min_bitrate) {
+ LOG(LS_ERROR) << "Codec with max < min bitrate: " << ToString();
+ return false;
+ }
+ }
+ return true;
+}
+
std::string DataCodec::ToString() const {
std::ostringstream os;
os << "DataCodec[" << id << ":" << name << "]";
diff --git a/chromium/third_party/libjingle/source/talk/media/base/codec.h b/chromium/third_party/libjingle/source/talk/media/base/codec.h
index 56fc975adb2..0e9bf3ca073 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/codec.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/codec.h
@@ -120,6 +120,8 @@ struct Codec {
name = c.name;
clockrate = c.clockrate;
preference = c.preference;
+ params = c.params;
+ feedback_params = c.feedback_params;
return *this;
}
@@ -127,7 +129,9 @@ struct Codec {
return this->id == c.id && // id is reserved in objective-c
name == c.name &&
clockrate == c.clockrate &&
- preference == c.preference;
+ preference == c.preference &&
+ params == c.params &&
+ feedback_params == c.feedback_params;
}
bool operator!=(const Codec& c) const {
@@ -242,6 +246,22 @@ struct VideoCodec : public Codec {
bool operator!=(const VideoCodec& c) const {
return !(*this == c);
}
+
+ static VideoCodec CreateRtxCodec(int rtx_payload_type,
+ int associated_payload_type);
+
+ enum CodecType {
+ CODEC_VIDEO,
+ CODEC_RED,
+ CODEC_ULPFEC,
+ CODEC_RTX,
+ };
+
+ CodecType GetCodecType() const;
+ // Validates a VideoCodec's payload type, dimensions and bitrates etc. If they
+ // don't make sense (such as max < min bitrate), and error is logged and
+ // ValidateCodecFormat returns false.
+ bool ValidateCodecFormat() const;
};
struct DataCodec : public Codec {
diff --git a/chromium/third_party/libjingle/source/talk/media/base/codec_unittest.cc b/chromium/third_party/libjingle/source/talk/media/base/codec_unittest.cc
index f0ffd8f5a1b..35d1ab76133 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/codec_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/codec_unittest.cc
@@ -34,12 +34,52 @@ using cricket::DataCodec;
using cricket::FeedbackParam;
using cricket::VideoCodec;
using cricket::VideoEncoderConfig;
+using cricket::kCodecParamAssociatedPayloadType;
+using cricket::kCodecParamMaxBitrate;
+using cricket::kCodecParamMinBitrate;
class CodecTest : public testing::Test {
public:
CodecTest() {}
};
+TEST_F(CodecTest, TestCodecOperators) {
+ Codec c0(96, "D", 1000, 0);
+ c0.SetParam("a", 1);
+
+ Codec c1 = c0;
+ EXPECT_TRUE(c1 == c0);
+
+ int param_value0;
+ int param_value1;
+ EXPECT_TRUE(c0.GetParam("a", &param_value0));
+ EXPECT_TRUE(c1.GetParam("a", &param_value1));
+ EXPECT_EQ(param_value0, param_value1);
+
+ c1.id = 86;
+ EXPECT_TRUE(c0 != c1);
+
+ c1 = c0;
+ c1.name = "x";
+ EXPECT_TRUE(c0 != c1);
+
+ c1 = c0;
+ c1.clockrate = 2000;
+ EXPECT_TRUE(c0 != c1);
+
+ c1 = c0;
+ c1.preference = 1;
+ EXPECT_TRUE(c0 != c1);
+
+ c1 = c0;
+ c1.SetParam("a", 2);
+ EXPECT_TRUE(c0 != c1);
+
+ Codec c5;
+ Codec c6(0, "", 0, 0);
+ EXPECT_TRUE(c5 == c6);
+}
+
TEST_F(CodecTest, TestAudioCodecOperators) {
AudioCodec c0(96, "A", 44100, 20000, 2, 3);
AudioCodec c1(95, "A", 44100, 20000, 2, 3);
@@ -238,23 +278,6 @@ TEST_F(CodecTest, TestDataCodecMatches) {
EXPECT_FALSE(c1.Matches(DataCodec(95, "D", 0)));
}
-TEST_F(CodecTest, TestDataCodecOperators) {
- DataCodec c0(96, "D", 3);
- DataCodec c1(95, "D", 3);
- DataCodec c2(96, "x", 3);
- DataCodec c3(96, "D", 1);
- EXPECT_TRUE(c0 != c1);
- EXPECT_TRUE(c0 != c2);
- EXPECT_TRUE(c0 != c3);
-
- DataCodec c4;
- DataCodec c5(0, "", 0);
- DataCodec c6 = c0;
- EXPECT_TRUE(c5 == c4);
- EXPECT_TRUE(c6 != c4);
- EXPECT_TRUE(c6 == c0);
-}
-
TEST_F(CodecTest, TestSetParamAndGetParam) {
AudioCodec codec;
codec.SetParam("a", "1");
@@ -292,3 +315,81 @@ TEST_F(CodecTest, TestIntersectFeedbackParams) {
EXPECT_FALSE(c1.HasFeedbackParam(b2));
EXPECT_FALSE(c1.HasFeedbackParam(c3));
}
+
+TEST_F(CodecTest, TestGetCodecType) {
+ // Codec type comparison should be case insenstive on names.
+ const VideoCodec codec(96, "V", 320, 200, 30, 3);
+ const VideoCodec rtx_codec(96, "rTx", 320, 200, 30, 3);
+ const VideoCodec ulpfec_codec(96, "ulpFeC", 320, 200, 30, 3);
+ const VideoCodec red_codec(96, "ReD", 320, 200, 30, 3);
+ EXPECT_EQ(VideoCodec::CODEC_VIDEO, codec.GetCodecType());
+ EXPECT_EQ(VideoCodec::CODEC_RTX, rtx_codec.GetCodecType());
+ EXPECT_EQ(VideoCodec::CODEC_ULPFEC, ulpfec_codec.GetCodecType());
+ EXPECT_EQ(VideoCodec::CODEC_RED, red_codec.GetCodecType());
+}
+
+TEST_F(CodecTest, TestCreateRtxCodec) {
+ VideoCodec rtx_codec = VideoCodec::CreateRtxCodec(96, 120);
+ EXPECT_EQ(96, rtx_codec.id);
+ EXPECT_EQ(VideoCodec::CODEC_RTX, rtx_codec.GetCodecType());
+ int associated_payload_type;
+ ASSERT_TRUE(rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
+ &associated_payload_type));
+ EXPECT_EQ(120, associated_payload_type);
+}
+
+TEST_F(CodecTest, TestValidateCodecFormat) {
+ const VideoCodec codec(96, "V", 320, 200, 30, 3);
+ ASSERT_TRUE(codec.ValidateCodecFormat());
+
+ // Accept 0-127 as payload types.
+ VideoCodec low_payload_type = codec;
+ low_payload_type.id = 0;
+ VideoCodec high_payload_type = codec;
+ high_payload_type.id = 127;
+ ASSERT_TRUE(low_payload_type.ValidateCodecFormat());
+ EXPECT_TRUE(high_payload_type.ValidateCodecFormat());
+
+ // Reject negative payloads.
+ VideoCodec negative_payload_type = codec;
+ negative_payload_type.id = -1;
+ EXPECT_FALSE(negative_payload_type.ValidateCodecFormat());
+
+ // Reject too-high payloads.
+ VideoCodec too_high_payload_type = codec;
+ too_high_payload_type.id = 128;
+ EXPECT_FALSE(too_high_payload_type.ValidateCodecFormat());
+
+ // Reject zero-width codecs.
+ VideoCodec zero_width = codec;
+ zero_width.width = 0;
+ EXPECT_FALSE(zero_width.ValidateCodecFormat());
+
+ // Reject zero-height codecs.
+ VideoCodec zero_height = codec;
+ zero_height.height = 0;
+ EXPECT_FALSE(zero_height.ValidateCodecFormat());
+
+ // Accept non-video codecs with zero dimensions.
+ VideoCodec zero_width_rtx_codec = VideoCodec::CreateRtxCodec(96, 120);
+ zero_width_rtx_codec.width = 0;
+ EXPECT_TRUE(zero_width_rtx_codec.ValidateCodecFormat());
+
+ // Reject codecs with min bitrate > max bitrate.
+ VideoCodec incorrect_bitrates = codec;
+ incorrect_bitrates.params[kCodecParamMinBitrate] = "100";
+ incorrect_bitrates.params[kCodecParamMaxBitrate] = "80";
+ EXPECT_FALSE(incorrect_bitrates.ValidateCodecFormat());
+
+ // Accept min bitrate == max bitrate.
+ VideoCodec equal_bitrates = codec;
+ equal_bitrates.params[kCodecParamMinBitrate] = "100";
+ equal_bitrates.params[kCodecParamMaxBitrate] = "100";
+ EXPECT_TRUE(equal_bitrates.ValidateCodecFormat());
+
+ // Accept min bitrate < max bitrate.
+ VideoCodec different_bitrates = codec;
+ different_bitrates.params[kCodecParamMinBitrate] = "99";
+ different_bitrates.params[kCodecParamMaxBitrate] = "100";
+ EXPECT_TRUE(different_bitrates.ValidateCodecFormat());
+}
diff --git a/chromium/third_party/libjingle/source/talk/media/base/constants.cc b/chromium/third_party/libjingle/source/talk/media/base/constants.cc
index 9162ce4fd12..cd10ef75f3c 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/constants.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/constants.cc
@@ -40,6 +40,8 @@ const float kLowSystemCpuThreshold = 0.65f;
const float kProcessCpuThreshold = 0.10f;
const char kRtxCodecName[] = "rtx";
+const char kRedCodecName[] = "red";
+const char kUlpfecCodecName[] = "ulpfec";
// RTP payload type is in the 0-127 range. Use 128 to indicate "all" payload
// types.
@@ -78,12 +80,14 @@ const int kPreferredStereo = 0;
const int kPreferredUseInbandFec = 0;
const char kRtcpFbParamNack[] = "nack";
+const char kRtcpFbNackParamPli[] = "pli";
const char kRtcpFbParamRemb[] = "goog-remb";
const char kRtcpFbParamCcm[] = "ccm";
const char kRtcpFbCcmParamFir[] = "fir";
const char kCodecParamMaxBitrate[] = "x-google-max-bitrate";
const char kCodecParamMinBitrate[] = "x-google-min-bitrate";
+const char kCodecParamStartBitrate[] = "x-google-start-bitrate";
const char kCodecParamMaxQuantization[] = "x-google-max-quantization";
const char kCodecParamPort[] = "x-google-port";
@@ -95,4 +99,20 @@ const char kGoogleSctpDataCodecName[] = "google-sctp-data";
const char kComfortNoiseCodecName[] = "CN";
+const int kRtpAudioLevelHeaderExtensionDefaultId = 1;
+const char kRtpAudioLevelHeaderExtension[] =
+ "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
+
+const int kRtpTimestampOffsetHeaderExtensionDefaultId = 2;
+const char kRtpTimestampOffsetHeaderExtension[] =
+ "urn:ietf:params:rtp-hdrext:toffset";
+
+const int kRtpAbsoluteSenderTimeHeaderExtensionDefaultId = 3;
+const char kRtpAbsoluteSenderTimeHeaderExtension[] =
+ "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
+
+const int kNumDefaultUnsignalledVideoRecvStreams = 0;
+
+
} // namespace cricket
+
diff --git a/chromium/third_party/libjingle/source/talk/media/base/constants.h b/chromium/third_party/libjingle/source/talk/media/base/constants.h
index b80c0fc106c..dc5405d1729 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/constants.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/constants.h
@@ -44,6 +44,9 @@ extern const float kLowSystemCpuThreshold;
extern const float kProcessCpuThreshold;
extern const char kRtxCodecName[];
+extern const char kRedCodecName[];
+extern const char kUlpfecCodecName[];
+
// Codec parameters
extern const int kWildcardPayloadType;
@@ -89,6 +92,7 @@ extern const int kPreferredUseInbandFec;
// rtcp-fb messages according to RFC 4585
extern const char kRtcpFbParamNack[];
+extern const char kRtcpFbNackParamPli[];
// rtcp-fb messages according to
// http://tools.ietf.org/html/draft-alvestrand-rmcat-remb-00
extern const char kRtcpFbParamRemb[];
@@ -98,6 +102,7 @@ extern const char kRtcpFbCcmParamFir[];
// Google specific parameters
extern const char kCodecParamMaxBitrate[];
extern const char kCodecParamMinBitrate[];
+extern const char kCodecParamStartBitrate[];
extern const char kCodecParamMaxQuantization[];
extern const char kCodecParamPort[];
@@ -115,6 +120,23 @@ extern const char kGoogleSctpDataCodecName[];
extern const char kComfortNoiseCodecName[];
+// Extension header for audio levels, as defined in
+// http://tools.ietf.org/html/draft-ietf-avtext-client-to-mixer-audio-level-03
+extern const int kRtpAudioLevelHeaderExtensionDefaultId;
+extern const char kRtpAudioLevelHeaderExtension[];
+
+// Extension header for RTP timestamp offset, see RFC 5450 for details:
+// http://tools.ietf.org/html/rfc5450
+extern const int kRtpTimestampOffsetHeaderExtensionDefaultId;
+extern const char kRtpTimestampOffsetHeaderExtension[];
+
+// Extension header for absolute send time, see url for details:
+// http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
+extern const int kRtpAbsoluteSenderTimeHeaderExtensionDefaultId;
+extern const char kRtpAbsoluteSenderTimeHeaderExtension[];
+
+extern const int kNumDefaultUnsignalledVideoRecvStreams;
} // namespace cricket
#endif // TALK_MEDIA_BASE_CONSTANTS_H_
+
diff --git a/chromium/third_party/libjingle/source/talk/media/base/fakemediaengine.h b/chromium/third_party/libjingle/source/talk/media/base/fakemediaengine.h
index 1a4e8aba897..27fbeb094e5 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/fakemediaengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/fakemediaengine.h
@@ -281,7 +281,8 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
}
return set_sending(flag != SEND_NOTHING);
}
- virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
+ virtual bool SetStartSendBandwidth(int bps) { return true; }
+ virtual bool SetMaxSendBandwidth(int bps) { return true; }
virtual bool AddRecvStream(const StreamParams& sp) {
if (!RtpHelper<VoiceMediaChannel>::AddRecvStream(sp))
return false;
@@ -315,17 +316,18 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
return true;
}
virtual bool SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer) {
- std::map<uint32, AudioRenderer*>::iterator it = local_renderers_.find(ssrc);
+ std::map<uint32, VoiceChannelAudioSink*>::iterator it =
+ local_renderers_.find(ssrc);
if (renderer) {
if (it != local_renderers_.end()) {
- ASSERT(it->second == renderer);
+ ASSERT(it->second->renderer() == renderer);
} else {
- local_renderers_.insert(std::make_pair(ssrc, renderer));
- renderer->AddChannel(0);
+ local_renderers_.insert(std::make_pair(
+ ssrc, new VoiceChannelAudioSink(renderer)));
}
} else {
if (it != local_renderers_.end()) {
- it->second->RemoveChannel(0);
+ delete it->second;
local_renderers_.erase(it);
} else {
return false;
@@ -418,6 +420,34 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
double left, right;
};
+ class VoiceChannelAudioSink : public AudioRenderer::Sink {
+ public:
+ explicit VoiceChannelAudioSink(AudioRenderer* renderer)
+ : renderer_(renderer) {
+ renderer_->AddChannel(0);
+ renderer_->SetSink(this);
+ }
+ virtual ~VoiceChannelAudioSink() {
+ if (renderer_) {
+ renderer_->RemoveChannel(0);
+ renderer_->SetSink(NULL);
+ }
+ }
+ virtual void OnData(const void* audio_data,
+ int bits_per_sample,
+ int sample_rate,
+ int number_of_channels,
+ int number_of_frames) OVERRIDE {}
+ virtual void OnClose() OVERRIDE {
+ renderer_ = NULL;
+ }
+ AudioRenderer* renderer() const { return renderer_; }
+
+ private:
+ AudioRenderer* renderer_;
+ };
+
+
FakeVoiceEngine* engine_;
std::vector<AudioCodec> recv_codecs_;
std::vector<AudioCodec> send_codecs_;
@@ -429,7 +459,7 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
bool ringback_tone_loop_;
int time_since_last_typing_;
AudioOptions options_;
- std::map<uint32, AudioRenderer*> local_renderers_;
+ std::map<uint32, VoiceChannelAudioSink*> local_renderers_;
std::map<uint32, AudioRenderer*> remote_renderers_;
};
@@ -446,7 +476,9 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> {
explicit FakeVideoMediaChannel(FakeVideoEngine* engine)
: engine_(engine),
sent_intra_frame_(false),
- requested_intra_frame_(false) {}
+ requested_intra_frame_(false),
+ start_bps_(-1),
+ max_bps_(-1) {}
~FakeVideoMediaChannel();
const std::vector<VideoCodec>& recv_codecs() const { return recv_codecs_; }
@@ -457,6 +489,8 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> {
const std::map<uint32, VideoRenderer*>& renderers() const {
return renderers_;
}
+ int start_bps() const { return start_bps_; }
+ int max_bps() const { return max_bps_; }
bool GetSendStreamFormat(uint32 ssrc, VideoFormat* format) {
if (send_formats_.find(ssrc) == send_formats_.end()) {
return false;
@@ -534,7 +568,14 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> {
bool HasCapturer(uint32 ssrc) const {
return capturers_.find(ssrc) != capturers_.end();
}
- virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
+ virtual bool SetStartSendBandwidth(int bps) {
+ start_bps_ = bps;
+ return true;
+ }
+ virtual bool SetMaxSendBandwidth(int bps) {
+ max_bps_ = bps;
+ return true;
+ }
virtual bool AddRecvStream(const StreamParams& sp) {
if (!RtpHelper<VideoMediaChannel>::AddRecvStream(sp))
return false;
@@ -548,7 +589,8 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> {
return true;
}
- virtual bool GetStats(VideoMediaInfo* info) { return false; }
+ virtual bool GetStats(const StatsOptions& options,
+ VideoMediaInfo* info) { return false; }
virtual bool SendIntraFrame() {
sent_intra_frame_ = true;
return true;
@@ -591,6 +633,8 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> {
bool sent_intra_frame_;
bool requested_intra_frame_;
VideoOptions options_;
+ int start_bps_;
+ int max_bps_;
};
class FakeSoundclipMedia : public SoundclipMedia {
@@ -601,12 +645,11 @@ class FakeSoundclipMedia : public SoundclipMedia {
class FakeDataMediaChannel : public RtpHelper<DataMediaChannel> {
public:
explicit FakeDataMediaChannel(void* unused)
- : auto_bandwidth_(false), send_blocked_(false), max_bps_(-1) {}
+ : send_blocked_(false), max_bps_(-1) {}
~FakeDataMediaChannel() {}
const std::vector<DataCodec>& recv_codecs() const { return recv_codecs_; }
const std::vector<DataCodec>& send_codecs() const { return send_codecs_; }
const std::vector<DataCodec>& codecs() const { return send_codecs(); }
- bool auto_bandwidth() const { return auto_bandwidth_; }
int max_bps() const { return max_bps_; }
virtual bool SetRecvCodecs(const std::vector<DataCodec>& codecs) {
@@ -630,8 +673,8 @@ class FakeDataMediaChannel : public RtpHelper<DataMediaChannel> {
set_playout(receive);
return true;
}
- virtual bool SetSendBandwidth(bool autobw, int bps) {
- auto_bandwidth_ = autobw;
+ virtual bool SetStartSendBandwidth(int bps) { return true; }
+ virtual bool SetMaxSendBandwidth(int bps) {
max_bps_ = bps;
return true;
}
@@ -669,7 +712,6 @@ class FakeDataMediaChannel : public RtpHelper<DataMediaChannel> {
std::vector<DataCodec> send_codecs_;
SendDataParams last_sent_data_params_;
std::string last_sent_data_;
- bool auto_bandwidth_;
bool send_blocked_;
int max_bps_;
};
@@ -695,6 +737,10 @@ class FakeBaseEngine {
const std::vector<RtpHeaderExtension>& rtp_header_extensions() const {
return rtp_header_extensions_;
}
+ void set_rtp_header_extensions(
+ const std::vector<RtpHeaderExtension>& extensions) {
+ rtp_header_extensions_ = extensions;
+ }
protected:
int loglevel_;
@@ -778,6 +824,8 @@ class FakeVoiceEngine : public FakeBaseEngine {
bool SetLocalMonitor(bool enable) { return true; }
+ bool StartAecDump(talk_base::PlatformFile file) { return false; }
+
bool RegisterProcessor(uint32 ssrc, VoiceProcessor* voice_processor,
MediaProcessorDirection direction) {
if (direction == MPD_RX) {
@@ -915,18 +963,25 @@ class FakeMediaEngine :
}
virtual ~FakeMediaEngine() {}
- virtual void SetAudioCodecs(const std::vector<AudioCodec> codecs) {
+ void SetAudioCodecs(const std::vector<AudioCodec>& codecs) {
voice_.SetCodecs(codecs);
}
-
- virtual void SetVideoCodecs(const std::vector<VideoCodec> codecs) {
+ void SetVideoCodecs(const std::vector<VideoCodec>& codecs) {
video_.SetCodecs(codecs);
}
+ void SetAudioRtpHeaderExtensions(
+ const std::vector<RtpHeaderExtension>& extensions) {
+ voice_.set_rtp_header_extensions(extensions);
+ }
+ void SetVideoRtpHeaderExtensions(
+ const std::vector<RtpHeaderExtension>& extensions) {
+ video_.set_rtp_header_extensions(extensions);
+ }
+
FakeVoiceMediaChannel* GetVoiceChannel(size_t index) {
return voice_.GetChannel(index);
}
-
FakeVideoMediaChannel* GetVideoChannel(size_t index) {
return video_.GetChannel(index);
}
diff --git a/chromium/third_party/libjingle/source/talk/media/base/fakevideorenderer.h b/chromium/third_party/libjingle/source/talk/media/base/fakevideorenderer.h
index 362e592951e..cab77dda720 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/fakevideorenderer.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/fakevideorenderer.h
@@ -48,6 +48,7 @@ class FakeVideoRenderer : public VideoRenderer {
}
virtual bool SetSize(int width, int height, int reserved) {
+ talk_base::CritScope cs(&crit_);
width_ = width;
height_ = height;
++num_set_sizes_;
@@ -56,6 +57,7 @@ class FakeVideoRenderer : public VideoRenderer {
}
virtual bool RenderFrame(const VideoFrame* frame) {
+ talk_base::CritScope cs(&crit_);
// TODO(zhurunz) Check with VP8 team to see if we can remove this
// tolerance on Y values.
black_frame_ = CheckFrameColorYuv(6, 48, 128, 128, 128, 128, frame);
@@ -79,11 +81,26 @@ class FakeVideoRenderer : public VideoRenderer {
}
int errors() const { return errors_; }
- int width() const { return width_; }
- int height() const { return height_; }
- int num_set_sizes() const { return num_set_sizes_; }
- int num_rendered_frames() const { return num_rendered_frames_; }
- bool black_frame() const { return black_frame_; }
+ int width() const {
+ talk_base::CritScope cs(&crit_);
+ return width_;
+ }
+ int height() const {
+ talk_base::CritScope cs(&crit_);
+ return height_;
+ }
+ int num_set_sizes() const {
+ talk_base::CritScope cs(&crit_);
+ return num_set_sizes_;
+ }
+ int num_rendered_frames() const {
+ talk_base::CritScope cs(&crit_);
+ return num_rendered_frames_;
+ }
+ bool black_frame() const {
+ talk_base::CritScope cs(&crit_);
+ return black_frame_;
+ }
sigslot::signal3<int, int, int> SignalSetSize;
sigslot::signal1<const VideoFrame*> SignalRenderFrame;
@@ -143,6 +160,7 @@ class FakeVideoRenderer : public VideoRenderer {
int num_set_sizes_;
int num_rendered_frames_;
bool black_frame_;
+ mutable talk_base::CriticalSection crit_;
};
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/media/base/filemediaengine.cc b/chromium/third_party/libjingle/source/talk/media/base/filemediaengine.cc
index dfec607d286..e8c356e4fb5 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/filemediaengine.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/filemediaengine.cc
@@ -25,7 +25,7 @@
#include "talk/media/base/filemediaengine.h"
-#include <climits>
+#include <limits.h>
#include "talk/base/buffer.h"
#include "talk/base/event.h"
diff --git a/chromium/third_party/libjingle/source/talk/media/base/filemediaengine.h b/chromium/third_party/libjingle/source/talk/media/base/filemediaengine.h
index dfdb037ab38..6656cdfa181 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/filemediaengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/filemediaengine.h
@@ -133,6 +133,7 @@ class FileMediaEngine : public MediaEngineInterface {
virtual bool FindVideoCodec(const VideoCodec& codec) { return true; }
virtual void SetVoiceLogging(int min_sev, const char* filter) {}
virtual void SetVideoLogging(int min_sev, const char* filter) {}
+ virtual bool StartAecDump(talk_base::PlatformFile) { return false; }
virtual bool RegisterVideoProcessor(VideoProcessor* processor) {
return true;
@@ -242,7 +243,8 @@ class FileVoiceChannel : public VoiceMediaChannel {
virtual bool AddRecvStream(const StreamParams& sp) { return true; }
virtual bool RemoveRecvStream(uint32 ssrc) { return true; }
virtual bool MuteStream(uint32 ssrc, bool on) { return false; }
- virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
+ virtual bool SetStartSendBandwidth(int bps) { return true; }
+ virtual bool SetMaxSendBandwidth(int bps) { return true; }
virtual bool SetOptions(const AudioOptions& options) {
options_ = options;
return true;
@@ -295,7 +297,9 @@ class FileVideoChannel : public VideoMediaChannel {
virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
return false;
}
- virtual bool GetStats(VideoMediaInfo* info) { return true; }
+ virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info) {
+ return true;
+ }
virtual bool SendIntraFrame() { return false; }
virtual bool RequestIntraFrame() { return false; }
@@ -310,7 +314,8 @@ class FileVideoChannel : public VideoMediaChannel {
virtual bool AddRecvStream(const StreamParams& sp) { return true; }
virtual bool RemoveRecvStream(uint32 ssrc) { return true; }
virtual bool MuteStream(uint32 ssrc, bool on) { return false; }
- virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
+ virtual bool SetStartSendBandwidth(int bps) { return true; }
+ virtual bool SetMaxSendBandwidth(int bps) { return true; }
virtual bool SetOptions(const VideoOptions& options) {
options_ = options;
return true;
diff --git a/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine.cc b/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine.cc
index 6863311f2dd..8e992f0abfe 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine.cc
@@ -183,9 +183,12 @@ bool HybridVideoMediaChannel::SetSendRtpHeaderExtensions(
active_channel_->SetSendRtpHeaderExtensions(extensions);
}
-bool HybridVideoMediaChannel::SetSendBandwidth(bool autobw, int bps) {
- return active_channel_ &&
- active_channel_->SetSendBandwidth(autobw, bps);
+bool HybridVideoMediaChannel::SetStartSendBandwidth(int bps) {
+ return active_channel_ && active_channel_->SetStartSendBandwidth(bps);
+}
+
+bool HybridVideoMediaChannel::SetMaxSendBandwidth(int bps) {
+ return active_channel_ && active_channel_->SetMaxSendBandwidth(bps);
}
bool HybridVideoMediaChannel::SetSend(bool send) {
@@ -270,10 +273,11 @@ bool HybridVideoMediaChannel::RequestIntraFrame() {
active_channel_->RequestIntraFrame();
}
-bool HybridVideoMediaChannel::GetStats(VideoMediaInfo* info) {
+bool HybridVideoMediaChannel::GetStats(
+ const StatsOptions& options, VideoMediaInfo* info) {
// TODO(juberti): Ensure that returning no stats until SetSendCodecs is OK.
return active_channel_ &&
- active_channel_->GetStats(info);
+ active_channel_->GetStats(options, info);
}
void HybridVideoMediaChannel::OnPacketReceived(
diff --git a/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine.h b/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine.h
index a49a1aa2c88..8cfb884f12f 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine.h
@@ -75,7 +75,8 @@ class HybridVideoMediaChannel : public VideoMediaChannel {
virtual bool SetSendStreamFormat(uint32 ssrc, const VideoFormat& format);
virtual bool SetSendRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions);
- virtual bool SetSendBandwidth(bool autobw, int bps);
+ virtual bool SetStartSendBandwidth(int bps);
+ virtual bool SetMaxSendBandwidth(int bps);
virtual bool SetSend(bool send);
virtual bool AddRecvStream(const StreamParams& sp);
@@ -85,7 +86,7 @@ class HybridVideoMediaChannel : public VideoMediaChannel {
virtual bool SendIntraFrame();
virtual bool RequestIntraFrame();
- virtual bool GetStats(VideoMediaInfo* info);
+ virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info);
virtual void OnPacketReceived(talk_base::Buffer* packet,
const talk_base::PacketTime& packet_time);
diff --git a/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine_unittest.cc b/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine_unittest.cc
new file mode 100644
index 00000000000..aa9d4ac2070
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/base/hybridvideoengine_unittest.cc
@@ -0,0 +1,486 @@
+/*
+ * libjingle
+ * Copyright 2004 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/gunit.h"
+#include "talk/media/base/fakemediaengine.h"
+#include "talk/media/base/fakenetworkinterface.h"
+#include "talk/media/base/fakevideocapturer.h"
+#include "talk/media/base/hybridvideoengine.h"
+#include "talk/media/base/mediachannel.h"
+#include "talk/media/base/testutils.h"
+
+static const cricket::VideoCodec kGenericCodec(97, "Generic", 640, 360, 30, 0);
+static const cricket::VideoCodec kVp8Codec(100, "VP8", 640, 360, 30, 0);
+static const cricket::VideoCodec kCodecsVp8Only[] = { kVp8Codec };
+static const cricket::VideoCodec kCodecsGenericOnly[] = { kGenericCodec };
+static const cricket::VideoCodec kCodecsVp8First[] = { kVp8Codec,
+ kGenericCodec };
+static const cricket::VideoCodec kCodecsGenericFirst[] = { kGenericCodec,
+ kVp8Codec };
+
+using cricket::StreamParams;
+
+class FakeVp8VideoEngine : public cricket::FakeVideoEngine {
+ public:
+ FakeVp8VideoEngine() {
+ SetCodecs(MAKE_VECTOR(kCodecsVp8Only));
+ }
+};
+class FakeGenericVideoEngine : public cricket::FakeVideoEngine {
+ public:
+ FakeGenericVideoEngine() {
+ SetCodecs(MAKE_VECTOR(kCodecsGenericOnly));
+ }
+
+ // For testing purposes, mimic the behavior of a media engine that throws out
+ // resolutions that don't match the codec list. A width or height of 0
+ // trivially will never match the codec list, so this is sufficient for
+ // testing the case we want (0x0).
+ virtual bool FindCodec(const cricket::VideoCodec& codec) {
+ if (codec.width == 0 || codec.height == 0) {
+ return false;
+ } else {
+ return cricket::FakeVideoEngine::FindCodec(codec);
+ }
+ }
+};
+class HybridVideoEngineForTest : public cricket::HybridVideoEngine<
+ FakeVp8VideoEngine, FakeGenericVideoEngine> {
+ public:
+ HybridVideoEngineForTest()
+ :
+ num_ch1_send_on_(0),
+ num_ch1_send_off_(0),
+ send_width_(0),
+ send_height_(0) { }
+ cricket::FakeVideoEngine* sub_engine1() { return &video1_; }
+ cricket::FakeVideoEngine* sub_engine2() { return &video2_; }
+
+ // From base class HybridVideoEngine.
+ void OnSendChange1(cricket::VideoMediaChannel* channel1, bool send) {
+ if (send) {
+ ++num_ch1_send_on_;
+ } else {
+ ++num_ch1_send_off_;
+ }
+ }
+ // From base class HybridVideoEngine
+ void OnNewSendResolution(int width, int height) {
+ send_width_ = width;
+ send_height_ = height;
+ }
+
+ int num_ch1_send_on() const { return num_ch1_send_on_; }
+ int num_ch1_send_off() const { return num_ch1_send_off_; }
+
+ int send_width() const { return send_width_; }
+ int send_height() const { return send_height_; }
+
+ private:
+ int num_ch1_send_on_;
+ int num_ch1_send_off_;
+
+ int send_width_;
+ int send_height_;
+};
+
+class HybridVideoEngineTest : public testing::Test {
+ public:
+ HybridVideoEngineTest() : sub_channel1_(NULL), sub_channel2_(NULL) {
+ }
+ ~HybridVideoEngineTest() {
+ engine_.Terminate();
+ }
+ bool SetupEngine() {
+ bool result = engine_.Init(talk_base::Thread::Current());
+ if (result) {
+ channel_.reset(engine_.CreateChannel(NULL));
+ result = (channel_.get() != NULL);
+ sub_channel1_ = engine_.sub_engine1()->GetChannel(0);
+ sub_channel2_ = engine_.sub_engine2()->GetChannel(0);
+ }
+ return result;
+ }
+ bool SetupRenderAndAddStream(const StreamParams& sp) {
+ if (!SetupEngine())
+ return false;
+ channel_->SetInterface(transport_.get());
+ return channel_->SetRecvCodecs(engine_.codecs()) &&
+ channel_->AddSendStream(sp) &&
+ channel_->SetRender(true);
+ }
+ void DeliverPacket(const void* data, int len) {
+ talk_base::Buffer packet(data, len);
+ channel_->OnPacketReceived(&packet, talk_base::CreatePacketTime(0));
+ }
+ void DeliverRtcp(const void* data, int len) {
+ talk_base::Buffer packet(data, len);
+ channel_->OnRtcpReceived(&packet, talk_base::CreatePacketTime(0));
+ }
+
+ protected:
+ void TestSetSendCodecs(cricket::FakeVideoEngine* sub_engine,
+ const std::vector<cricket::VideoCodec>& codecs) {
+ EXPECT_TRUE(SetupRenderAndAddStream(StreamParams::CreateLegacy(1234)));
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ cricket::FakeVideoMediaChannel* sub_channel = sub_engine->GetChannel(0);
+ ASSERT_EQ(1U, sub_channel->send_codecs().size());
+ EXPECT_EQ(codecs[0], sub_channel->send_codecs()[0]);
+ EXPECT_TRUE(channel_->SetSend(true));
+ EXPECT_TRUE(sub_channel->sending());
+ }
+ void TestSetSendBandwidth(cricket::FakeVideoEngine* sub_engine,
+ const std::vector<cricket::VideoCodec>& codecs,
+ int start_bitrate,
+ int max_bitrate) {
+ EXPECT_TRUE(SetupRenderAndAddStream(StreamParams::CreateLegacy(1234)));
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(channel_->SetStartSendBandwidth(start_bitrate));
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(max_bitrate));
+ cricket::FakeVideoMediaChannel* sub_channel = sub_engine->GetChannel(0);
+ EXPECT_EQ(start_bitrate, sub_channel->start_bps());
+ EXPECT_EQ(max_bitrate, sub_channel->max_bps());
+ }
+ HybridVideoEngineForTest engine_;
+ talk_base::scoped_ptr<cricket::HybridVideoMediaChannel> channel_;
+ talk_base::scoped_ptr<cricket::FakeNetworkInterface> transport_;
+ cricket::FakeVideoMediaChannel* sub_channel1_;
+ cricket::FakeVideoMediaChannel* sub_channel2_;
+};
+
+TEST_F(HybridVideoEngineTest, StartupShutdown) {
+ EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
+ engine_.Terminate();
+}
+
+// Tests that SetDefaultVideoEncoderConfig passes down to both engines.
+TEST_F(HybridVideoEngineTest, SetDefaultVideoEncoderConfig) {
+ cricket::VideoEncoderConfig config(
+ cricket::VideoCodec(105, "", 640, 400, 30, 0), 1, 2);
+ EXPECT_TRUE(engine_.SetDefaultEncoderConfig(config));
+
+ cricket::VideoEncoderConfig config_1 = config;
+ config_1.max_codec.name = kCodecsVp8Only[0].name;
+ EXPECT_EQ(config_1, engine_.sub_engine1()->default_encoder_config());
+
+ cricket::VideoEncoderConfig config_2 = config;
+ config_2.max_codec.name = kCodecsGenericOnly[0].name;
+ EXPECT_EQ(config_2, engine_.sub_engine2()->default_encoder_config());
+}
+
+// Tests that GetDefaultVideoEncoderConfig picks a meaningful encoder config
+// based on the underlying engine config and then after a call to
+// SetDefaultEncoderConfig on the hybrid engine.
+TEST_F(HybridVideoEngineTest, SetDefaultVideoEncoderConfigDefaultValue) {
+ cricket::VideoEncoderConfig blank_config;
+ cricket::VideoEncoderConfig meaningful_config1(
+ cricket::VideoCodec(111, "abcd", 320, 240, 30, 0), 1, 2);
+ cricket::VideoEncoderConfig meaningful_config2(
+ cricket::VideoCodec(111, "abcd", 1280, 720, 30, 0), 1, 2);
+ cricket::VideoEncoderConfig meaningful_config3(
+ cricket::VideoCodec(111, "abcd", 640, 360, 30, 0), 1, 2);
+ engine_.sub_engine1()->SetDefaultEncoderConfig(blank_config);
+ engine_.sub_engine2()->SetDefaultEncoderConfig(blank_config);
+ EXPECT_EQ(blank_config, engine_.GetDefaultEncoderConfig());
+
+ engine_.sub_engine2()->SetDefaultEncoderConfig(meaningful_config2);
+ EXPECT_EQ(meaningful_config2, engine_.GetDefaultEncoderConfig());
+
+ engine_.sub_engine1()->SetDefaultEncoderConfig(meaningful_config1);
+ EXPECT_EQ(meaningful_config1, engine_.GetDefaultEncoderConfig());
+
+ EXPECT_TRUE(engine_.SetDefaultEncoderConfig(meaningful_config3));
+ // The overall config should now match, though the codec name will have been
+ // rewritten for the first media engine.
+ meaningful_config3.max_codec.name = kCodecsVp8Only[0].name;
+ EXPECT_EQ(meaningful_config3, engine_.GetDefaultEncoderConfig());
+}
+
+// Tests that our engine has the right codecs in the right order.
+TEST_F(HybridVideoEngineTest, CheckCodecs) {
+ const std::vector<cricket::VideoCodec>& c = engine_.codecs();
+ ASSERT_EQ(2U, c.size());
+ EXPECT_EQ(kVp8Codec, c[0]);
+ EXPECT_EQ(kGenericCodec, c[1]);
+}
+
+// Tests that our engine has the right caps.
+TEST_F(HybridVideoEngineTest, CheckCaps) {
+ EXPECT_EQ(cricket::VIDEO_SEND | cricket::VIDEO_RECV,
+ engine_.GetCapabilities());
+}
+
+// Tests that we can create and destroy a channel.
+TEST_F(HybridVideoEngineTest, CreateChannel) {
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(sub_channel1_ != NULL);
+ EXPECT_TRUE(sub_channel2_ != NULL);
+}
+
+// Tests that we properly handle failures in CreateChannel.
+TEST_F(HybridVideoEngineTest, CreateChannelFail) {
+ engine_.sub_engine1()->set_fail_create_channel(true);
+ EXPECT_FALSE(SetupEngine());
+ EXPECT_TRUE(channel_.get() == NULL);
+ EXPECT_TRUE(sub_channel1_ == NULL);
+ EXPECT_TRUE(sub_channel2_ == NULL);
+ engine_.sub_engine1()->set_fail_create_channel(false);
+ engine_.sub_engine2()->set_fail_create_channel(true);
+ EXPECT_FALSE(SetupEngine());
+ EXPECT_TRUE(channel_.get() == NULL);
+ EXPECT_TRUE(sub_channel1_ == NULL);
+ EXPECT_TRUE(sub_channel2_ == NULL);
+}
+
+// Test that we set our inbound codecs and settings properly.
+TEST_F(HybridVideoEngineTest, SetLocalDescription) {
+ EXPECT_TRUE(SetupEngine());
+ channel_->SetInterface(transport_.get());
+ EXPECT_TRUE(channel_->SetRecvCodecs(engine_.codecs()));
+ ASSERT_EQ(1U, sub_channel1_->recv_codecs().size());
+ ASSERT_EQ(1U, sub_channel2_->recv_codecs().size());
+ EXPECT_EQ(kVp8Codec, sub_channel1_->recv_codecs()[0]);
+ EXPECT_EQ(kGenericCodec, sub_channel2_->recv_codecs()[0]);
+ StreamParams stream;
+ stream.id = "TestStream";
+ stream.ssrcs.push_back(1234);
+ stream.cname = "5678";
+ EXPECT_TRUE(channel_->AddSendStream(stream));
+ EXPECT_EQ(1234U, sub_channel1_->send_ssrc());
+ EXPECT_EQ(1234U, sub_channel2_->send_ssrc());
+ EXPECT_EQ("5678", sub_channel1_->rtcp_cname());
+ EXPECT_EQ("5678", sub_channel2_->rtcp_cname());
+ EXPECT_TRUE(channel_->SetRender(true));
+ // We've called SetRender, so we should be playing out, but not yet sending.
+ EXPECT_TRUE(sub_channel1_->playout());
+ EXPECT_TRUE(sub_channel2_->playout());
+ EXPECT_FALSE(sub_channel1_->sending());
+ EXPECT_FALSE(sub_channel2_->sending());
+ // We may get SetSend(false) calls during call setup.
+ // Since this causes no change in state, they should no-op and return true.
+ EXPECT_TRUE(channel_->SetSend(false));
+ EXPECT_FALSE(sub_channel1_->sending());
+ EXPECT_FALSE(sub_channel2_->sending());
+}
+
+TEST_F(HybridVideoEngineTest, OnNewSendResolution) {
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsVp8First)));
+ EXPECT_EQ(640, engine_.send_width());
+ EXPECT_EQ(360, engine_.send_height());
+}
+
+// Test that we converge to the active channel for engine 1.
+TEST_F(HybridVideoEngineTest, SetSendCodecs1) {
+ // This will nuke the object that sub_channel2_ points to.
+ TestSetSendCodecs(engine_.sub_engine1(), MAKE_VECTOR(kCodecsVp8First));
+ EXPECT_TRUE(engine_.sub_engine2()->GetChannel(0) == NULL);
+}
+
+// Test that we converge to the active channel for engine 2.
+TEST_F(HybridVideoEngineTest, SetSendCodecs2) {
+ // This will nuke the object that sub_channel1_ points to.
+ TestSetSendCodecs(engine_.sub_engine2(), MAKE_VECTOR(kCodecsGenericFirst));
+ EXPECT_TRUE(engine_.sub_engine1()->GetChannel(0) == NULL);
+}
+
+// Test that we don't accidentally eat 0x0 in SetSendCodecs
+TEST_F(HybridVideoEngineTest, SetSendCodecs0x0) {
+ EXPECT_TRUE(SetupRenderAndAddStream(StreamParams::CreateLegacy(1234)));
+ // Send using generic codec, but with 0x0 resolution.
+ std::vector<cricket::VideoCodec> codecs(MAKE_VECTOR(kCodecsGenericFirst));
+ codecs.resize(1);
+ codecs[0].width = 0;
+ codecs[0].height = 0;
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+}
+
+// Test setting the send bandwidth for VP8.
+TEST_F(HybridVideoEngineTest, SetSendBandwidth1) {
+ TestSetSendBandwidth(engine_.sub_engine1(),
+ MAKE_VECTOR(kCodecsVp8First),
+ 100000,
+ 384000);
+}
+
+// Test setting the send bandwidth for a generic codec.
+TEST_F(HybridVideoEngineTest, SetSendBandwidth2) {
+ TestSetSendBandwidth(engine_.sub_engine2(),
+ MAKE_VECTOR(kCodecsGenericFirst),
+ 100001,
+ 384002);
+}
+
+// Test that we dump RTP packets that arrive early.
+TEST_F(HybridVideoEngineTest, HandleEarlyRtp) {
+ static const uint8 kPacket[1024] = { 0 };
+ static const uint8 kRtcp[1024] = { 1 };
+ EXPECT_TRUE(SetupRenderAndAddStream(StreamParams::CreateLegacy(1234)));
+ DeliverPacket(kPacket, sizeof(kPacket));
+ DeliverRtcp(kRtcp, sizeof(kRtcp));
+ EXPECT_TRUE(sub_channel1_->CheckNoRtp());
+ EXPECT_TRUE(sub_channel2_->CheckNoRtp());
+ EXPECT_TRUE(sub_channel1_->CheckNoRtcp());
+ EXPECT_TRUE(sub_channel2_->CheckNoRtcp());
+}
+
+// Test that we properly pass on normal RTP packets.
+TEST_F(HybridVideoEngineTest, HandleRtp) {
+ static const uint8 kPacket[1024] = { 0 };
+ static const uint8 kRtcp[1024] = { 1 };
+ EXPECT_TRUE(SetupRenderAndAddStream(StreamParams::CreateLegacy(1234)));
+ EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsVp8First)));
+ EXPECT_TRUE(channel_->SetSend(true));
+ DeliverPacket(kPacket, sizeof(kPacket));
+ DeliverRtcp(kRtcp, sizeof(kRtcp));
+ EXPECT_TRUE(sub_channel1_->CheckRtp(kPacket, sizeof(kPacket)));
+ EXPECT_TRUE(sub_channel1_->CheckRtcp(kRtcp, sizeof(kRtcp)));
+}
+
+// Test that we properly connect media error signal.
+TEST_F(HybridVideoEngineTest, MediaErrorSignal) {
+ cricket::VideoMediaErrorCatcher catcher;
+
+ // Verify no signal from either channel before the active channel is set.
+ EXPECT_TRUE(SetupEngine());
+ channel_->SignalMediaError.connect(&catcher,
+ &cricket::VideoMediaErrorCatcher::OnError);
+ sub_channel1_->SignalMediaError(1, cricket::VideoMediaChannel::ERROR_OTHER);
+ EXPECT_EQ(0U, catcher.ssrc());
+ sub_channel2_->SignalMediaError(2,
+ cricket::VideoMediaChannel::ERROR_REC_DEVICE_OPEN_FAILED);
+ EXPECT_EQ(0U, catcher.ssrc());
+
+ // Set vp8 as active channel and verify that a signal comes from it.
+ EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsVp8First)));
+ sub_channel1_->SignalMediaError(1, cricket::VideoMediaChannel::ERROR_OTHER);
+ EXPECT_EQ(cricket::VideoMediaChannel::ERROR_OTHER, catcher.error());
+ EXPECT_EQ(1U, catcher.ssrc());
+
+ // Set generic codec as active channel and verify that a signal comes from it.
+ EXPECT_TRUE(SetupEngine());
+ channel_->SignalMediaError.connect(&catcher,
+ &cricket::VideoMediaErrorCatcher::OnError);
+ EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsGenericFirst)));
+ sub_channel2_->SignalMediaError(2,
+ cricket::VideoMediaChannel::ERROR_REC_DEVICE_OPEN_FAILED);
+ EXPECT_EQ(cricket::VideoMediaChannel::ERROR_REC_DEVICE_OPEN_FAILED,
+ catcher.error());
+ EXPECT_EQ(2U, catcher.ssrc());
+}
+
+// Test that SetSend doesn't re-enter.
+TEST_F(HybridVideoEngineTest, RepeatSetSend) {
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsVp8First)));
+
+ // Verify initial status.
+ EXPECT_FALSE(channel_->sending());
+ EXPECT_FALSE(sub_channel1_->sending());
+ EXPECT_EQ(0, engine_.num_ch1_send_on());
+ EXPECT_EQ(0, engine_.num_ch1_send_off());
+
+ // Verfiy SetSend(true) works correctly.
+ EXPECT_TRUE(channel_->SetSend(true));
+ EXPECT_TRUE(channel_->sending());
+ EXPECT_TRUE(sub_channel1_->sending());
+ EXPECT_EQ(1, engine_.num_ch1_send_on());
+ EXPECT_EQ(0, engine_.num_ch1_send_off());
+
+ // SetSend(true) again and verify nothing changes.
+ EXPECT_TRUE(channel_->SetSend(true));
+ EXPECT_TRUE(channel_->sending());
+ EXPECT_TRUE(sub_channel1_->sending());
+ EXPECT_EQ(1, engine_.num_ch1_send_on());
+ EXPECT_EQ(0, engine_.num_ch1_send_off());
+
+ // Verify SetSend(false) works correctly.
+ EXPECT_TRUE(channel_->SetSend(false));
+ EXPECT_FALSE(channel_->sending());
+ EXPECT_FALSE(sub_channel1_->sending());
+ EXPECT_EQ(1, engine_.num_ch1_send_on());
+ EXPECT_EQ(1, engine_.num_ch1_send_off());
+
+ // SetSend(false) again and verfiy nothing changes.
+ EXPECT_TRUE(channel_->SetSend(false));
+ EXPECT_FALSE(channel_->sending());
+ EXPECT_FALSE(sub_channel1_->sending());
+ EXPECT_EQ(1, engine_.num_ch1_send_on());
+ EXPECT_EQ(1, engine_.num_ch1_send_off());
+}
+
+// Test that SetOptions.
+TEST_F(HybridVideoEngineTest, SetOptions) {
+ cricket::VideoOptions vmo;
+ vmo.video_high_bitrate.Set(true);
+ vmo.system_low_adaptation_threshhold.Set(0.10f);
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->SetOptions(vmo));
+
+ bool high_bitrate;
+ float low;
+ EXPECT_TRUE(sub_channel1_->GetOptions(&vmo));
+ EXPECT_TRUE(vmo.video_high_bitrate.Get(&high_bitrate));
+ EXPECT_TRUE(high_bitrate);
+ EXPECT_TRUE(vmo.system_low_adaptation_threshhold.Get(&low));
+ EXPECT_EQ(0.10f, low);
+ EXPECT_TRUE(sub_channel2_->GetOptions(&vmo));
+ EXPECT_TRUE(vmo.video_high_bitrate.Get(&high_bitrate));
+ EXPECT_TRUE(high_bitrate);
+ EXPECT_TRUE(vmo.system_low_adaptation_threshhold.Get(&low));
+ EXPECT_EQ(0.10f, low);
+
+ vmo.video_high_bitrate.Set(false);
+ vmo.system_low_adaptation_threshhold.Set(0.50f);
+
+ EXPECT_TRUE(channel_->SetOptions(vmo));
+ EXPECT_TRUE(sub_channel1_->GetOptions(&vmo));
+ EXPECT_TRUE(vmo.video_high_bitrate.Get(&high_bitrate));
+ EXPECT_FALSE(high_bitrate);
+ EXPECT_TRUE(vmo.system_low_adaptation_threshhold.Get(&low));
+ EXPECT_EQ(0.50f, low);
+ EXPECT_TRUE(sub_channel2_->GetOptions(&vmo));
+ EXPECT_TRUE(vmo.video_high_bitrate.Get(&high_bitrate));
+ EXPECT_FALSE(high_bitrate);
+ EXPECT_TRUE(vmo.system_low_adaptation_threshhold.Get(&low));
+ EXPECT_EQ(0.50f, low);
+}
+
+TEST_F(HybridVideoEngineTest, SetCapturer) {
+ EXPECT_TRUE(SetupEngine());
+ // Set vp8 as active channel and verify that capturer can be set.
+ EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsVp8First)));
+ cricket::FakeVideoCapturer fake_video_capturer;
+ EXPECT_TRUE(channel_->SetCapturer(0, &fake_video_capturer));
+ EXPECT_TRUE(channel_->SetCapturer(0, NULL));
+
+ // Set generic codec active channel and verify that capturer can be set.
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsGenericFirst)));
+ EXPECT_TRUE(channel_->SetCapturer(0, &fake_video_capturer));
+ EXPECT_TRUE(channel_->SetCapturer(0, NULL));
+}
diff --git a/chromium/third_party/libjingle/source/talk/media/base/mediachannel.h b/chromium/third_party/libjingle/source/talk/media/base/mediachannel.h
index 94ae03f8d80..34d2deff709 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/mediachannel.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/mediachannel.h
@@ -50,10 +50,6 @@ class RateLimiter;
class Timing;
}
-namespace webrtc {
-struct DataChannelInit;
-}
-
namespace cricket {
class AudioRenderer;
@@ -66,6 +62,7 @@ class VideoRenderer;
const int kMinRtpHeaderExtensionId = 1;
const int kMaxRtpHeaderExtensionId = 255;
const int kScreencastDefaultFps = 5;
+const int kHighStartBitrate = 1500;
// Used in AudioOptions and VideoOptions to signify "unset" values.
template <class T>
@@ -172,8 +169,8 @@ struct AudioOptions {
adjust_agc_delta.SetFrom(change.adjust_agc_delta);
experimental_agc.SetFrom(change.experimental_agc);
experimental_aec.SetFrom(change.experimental_aec);
+ experimental_ns.SetFrom(change.experimental_ns);
aec_dump.SetFrom(change.aec_dump);
- experimental_acm.SetFrom(change.experimental_acm);
tx_agc_target_dbov.SetFrom(change.tx_agc_target_dbov);
tx_agc_digital_compression_gain.SetFrom(
change.tx_agc_digital_compression_gain);
@@ -185,6 +182,7 @@ struct AudioOptions {
recording_sample_rate.SetFrom(change.recording_sample_rate);
playout_sample_rate.SetFrom(change.playout_sample_rate);
dscp.SetFrom(change.dscp);
+ opus_fec.SetFrom(change.opus_fec);
}
bool operator==(const AudioOptions& o) const {
@@ -199,9 +197,9 @@ struct AudioOptions {
conference_mode == o.conference_mode &&
experimental_agc == o.experimental_agc &&
experimental_aec == o.experimental_aec &&
+ experimental_ns == o.experimental_ns &&
adjust_agc_delta == o.adjust_agc_delta &&
aec_dump == o.aec_dump &&
- experimental_acm == o.experimental_acm &&
tx_agc_target_dbov == o.tx_agc_target_dbov &&
tx_agc_digital_compression_gain == o.tx_agc_digital_compression_gain &&
tx_agc_limiter == o.tx_agc_limiter &&
@@ -210,7 +208,8 @@ struct AudioOptions {
rx_agc_limiter == o.rx_agc_limiter &&
recording_sample_rate == o.recording_sample_rate &&
playout_sample_rate == o.playout_sample_rate &&
- dscp == o.dscp;
+ dscp == o.dscp &&
+ opus_fec == o.opus_fec;
}
std::string ToString() const {
@@ -228,8 +227,8 @@ struct AudioOptions {
ost << ToStringIfSet("agc_delta", adjust_agc_delta);
ost << ToStringIfSet("experimental_agc", experimental_agc);
ost << ToStringIfSet("experimental_aec", experimental_aec);
+ ost << ToStringIfSet("experimental_ns", experimental_ns);
ost << ToStringIfSet("aec_dump", aec_dump);
- ost << ToStringIfSet("experimental_acm", experimental_acm);
ost << ToStringIfSet("tx_agc_target_dbov", tx_agc_target_dbov);
ost << ToStringIfSet("tx_agc_digital_compression_gain",
tx_agc_digital_compression_gain);
@@ -241,6 +240,7 @@ struct AudioOptions {
ost << ToStringIfSet("recording_sample_rate", recording_sample_rate);
ost << ToStringIfSet("playout_sample_rate", playout_sample_rate);
ost << ToStringIfSet("dscp", dscp);
+ ost << ToStringIfSet("opus_fec", opus_fec);
ost << "}";
return ost.str();
}
@@ -265,8 +265,8 @@ struct AudioOptions {
Settable<int> adjust_agc_delta;
Settable<bool> experimental_agc;
Settable<bool> experimental_aec;
+ Settable<bool> experimental_ns;
Settable<bool> aec_dump;
- Settable<bool> experimental_acm;
// Note that tx_agc_* only applies to non-experimental AGC.
Settable<uint16> tx_agc_target_dbov;
Settable<uint16> tx_agc_digital_compression_gain;
@@ -278,6 +278,8 @@ struct AudioOptions {
Settable<uint32> playout_sample_rate;
// Set DSCP value for packet sent from audio channel.
Settable<bool> dscp;
+ // Set Opus FEC
+ Settable<bool> opus_fec;
};
// Options that can be applied to a VideoMediaChannel or a VideoMediaEngine.
@@ -285,10 +287,17 @@ struct AudioOptions {
// We are moving all of the setting of options to structs like this,
// but some things currently still use flags.
struct VideoOptions {
+ enum HighestBitrate {
+ NORMAL,
+ HIGH,
+ VERY_HIGH
+ };
+
VideoOptions() {
process_adaptation_threshhold.Set(kProcessCpuThreshold);
system_low_adaptation_threshhold.Set(kLowSystemCpuThreshold);
system_high_adaptation_threshhold.Set(kHighSystemCpuThreshold);
+ unsignalled_recv_stream_limit.Set(kNumDefaultUnsignalledVideoRecvStreams);
}
void SetAll(const VideoOptions& change) {
@@ -300,13 +309,21 @@ struct VideoOptions {
video_noise_reduction.SetFrom(change.video_noise_reduction);
video_one_layer_screencast.SetFrom(change.video_one_layer_screencast);
video_high_bitrate.SetFrom(change.video_high_bitrate);
- video_watermark.SetFrom(change.video_watermark);
+ video_start_bitrate.SetFrom(change.video_start_bitrate);
video_temporal_layer_screencast.SetFrom(
change.video_temporal_layer_screencast);
video_temporal_layer_realtime.SetFrom(
change.video_temporal_layer_realtime);
video_leaky_bucket.SetFrom(change.video_leaky_bucket);
+ video_highest_bitrate.SetFrom(change.video_highest_bitrate);
cpu_overuse_detection.SetFrom(change.cpu_overuse_detection);
+ cpu_underuse_threshold.SetFrom(change.cpu_underuse_threshold);
+ cpu_overuse_threshold.SetFrom(change.cpu_overuse_threshold);
+ cpu_underuse_encode_rsd_threshold.SetFrom(
+ change.cpu_underuse_encode_rsd_threshold);
+ cpu_overuse_encode_rsd_threshold.SetFrom(
+ change.cpu_overuse_encode_rsd_threshold);
+ cpu_overuse_encode_usage.SetFrom(change.cpu_overuse_encode_usage);
conference_mode.SetFrom(change.conference_mode);
process_adaptation_threshhold.SetFrom(change.process_adaptation_threshhold);
system_low_adaptation_threshhold.SetFrom(
@@ -317,6 +334,13 @@ struct VideoOptions {
lower_min_bitrate.SetFrom(change.lower_min_bitrate);
dscp.SetFrom(change.dscp);
suspend_below_min_bitrate.SetFrom(change.suspend_below_min_bitrate);
+ unsignalled_recv_stream_limit.SetFrom(change.unsignalled_recv_stream_limit);
+ use_simulcast_adapter.SetFrom(change.use_simulcast_adapter);
+ skip_encoding_unused_streams.SetFrom(change.skip_encoding_unused_streams);
+ screencast_min_bitrate.SetFrom(change.screencast_min_bitrate);
+ use_improved_wifi_bandwidth_estimator.SetFrom(
+ change.use_improved_wifi_bandwidth_estimator);
+ use_payload_padding.SetFrom(change.use_payload_padding);
}
bool operator==(const VideoOptions& o) const {
@@ -328,11 +352,19 @@ struct VideoOptions {
video_noise_reduction == o.video_noise_reduction &&
video_one_layer_screencast == o.video_one_layer_screencast &&
video_high_bitrate == o.video_high_bitrate &&
- video_watermark == o.video_watermark &&
+ video_start_bitrate == o.video_start_bitrate &&
video_temporal_layer_screencast == o.video_temporal_layer_screencast &&
video_temporal_layer_realtime == o.video_temporal_layer_realtime &&
video_leaky_bucket == o.video_leaky_bucket &&
+ video_highest_bitrate == o.video_highest_bitrate &&
cpu_overuse_detection == o.cpu_overuse_detection &&
+ cpu_underuse_threshold == o.cpu_underuse_threshold &&
+ cpu_overuse_threshold == o.cpu_overuse_threshold &&
+ cpu_underuse_encode_rsd_threshold ==
+ o.cpu_underuse_encode_rsd_threshold &&
+ cpu_overuse_encode_rsd_threshold ==
+ o.cpu_overuse_encode_rsd_threshold &&
+ cpu_overuse_encode_usage == o.cpu_overuse_encode_usage &&
conference_mode == o.conference_mode &&
process_adaptation_threshhold == o.process_adaptation_threshhold &&
system_low_adaptation_threshhold ==
@@ -342,7 +374,14 @@ struct VideoOptions {
buffered_mode_latency == o.buffered_mode_latency &&
lower_min_bitrate == o.lower_min_bitrate &&
dscp == o.dscp &&
- suspend_below_min_bitrate == o.suspend_below_min_bitrate;
+ suspend_below_min_bitrate == o.suspend_below_min_bitrate &&
+ unsignalled_recv_stream_limit == o.unsignalled_recv_stream_limit &&
+ use_simulcast_adapter == o.use_simulcast_adapter &&
+ skip_encoding_unused_streams == o.skip_encoding_unused_streams &&
+ screencast_min_bitrate == o.screencast_min_bitrate &&
+ use_improved_wifi_bandwidth_estimator ==
+ o.use_improved_wifi_bandwidth_estimator &&
+ use_payload_padding == o.use_payload_padding;
}
std::string ToString() const {
@@ -356,13 +395,22 @@ struct VideoOptions {
ost << ToStringIfSet("noise reduction", video_noise_reduction);
ost << ToStringIfSet("1 layer screencast", video_one_layer_screencast);
ost << ToStringIfSet("high bitrate", video_high_bitrate);
- ost << ToStringIfSet("watermark", video_watermark);
+ ost << ToStringIfSet("start bitrate", video_start_bitrate);
ost << ToStringIfSet("video temporal layer screencast",
video_temporal_layer_screencast);
ost << ToStringIfSet("video temporal layer realtime",
video_temporal_layer_realtime);
ost << ToStringIfSet("leaky bucket", video_leaky_bucket);
+ ost << ToStringIfSet("highest video bitrate", video_highest_bitrate);
ost << ToStringIfSet("cpu overuse detection", cpu_overuse_detection);
+ ost << ToStringIfSet("cpu underuse threshold", cpu_underuse_threshold);
+ ost << ToStringIfSet("cpu overuse threshold", cpu_overuse_threshold);
+ ost << ToStringIfSet("cpu underuse encode rsd threshold",
+ cpu_underuse_encode_rsd_threshold);
+ ost << ToStringIfSet("cpu overuse encode rsd threshold",
+ cpu_overuse_encode_rsd_threshold);
+ ost << ToStringIfSet("cpu overuse encode usage",
+ cpu_overuse_encode_usage);
ost << ToStringIfSet("conference mode", conference_mode);
ost << ToStringIfSet("process", process_adaptation_threshhold);
ost << ToStringIfSet("low", system_low_adaptation_threshhold);
@@ -372,6 +420,15 @@ struct VideoOptions {
ost << ToStringIfSet("dscp", dscp);
ost << ToStringIfSet("suspend below min bitrate",
suspend_below_min_bitrate);
+ ost << ToStringIfSet("num channels for early receive",
+ unsignalled_recv_stream_limit);
+ ost << ToStringIfSet("use simulcast adapter", use_simulcast_adapter);
+ ost << ToStringIfSet("skip encoding unused streams",
+ skip_encoding_unused_streams);
+ ost << ToStringIfSet("screencast min bitrate", screencast_min_bitrate);
+ ost << ToStringIfSet("improved wifi bwe",
+ use_improved_wifi_bandwidth_estimator);
+ ost << ToStringIfSet("payload padding", use_payload_padding);
ost << "}";
return ost.str();
}
@@ -392,18 +449,38 @@ struct VideoOptions {
Settable<bool> video_one_layer_screencast;
// Experimental: Enable WebRtc higher bitrate?
Settable<bool> video_high_bitrate;
- // Experimental: Add watermark to the rendered video image.
- Settable<bool> video_watermark;
+ // Experimental: Enable WebRtc higher start bitrate?
+ Settable<int> video_start_bitrate;
// Experimental: Enable WebRTC layered screencast.
Settable<bool> video_temporal_layer_screencast;
// Experimental: Enable WebRTC temporal layer strategy for realtime video.
Settable<bool> video_temporal_layer_realtime;
// Enable WebRTC leaky bucket when sending media packets.
Settable<bool> video_leaky_bucket;
+ // Set highest bitrate mode for video.
+ Settable<HighestBitrate> video_highest_bitrate;
// Enable WebRTC Cpu Overuse Detection, which is a new version of the CPU
// adaptation algorithm. So this option will override the
// |adapt_input_to_cpu_usage|.
Settable<bool> cpu_overuse_detection;
+ // Low threshold (t1) for cpu overuse adaptation. (Adapt up)
+ // Metric: encode usage (m1). m1 < t1 => underuse.
+ Settable<int> cpu_underuse_threshold;
+ // High threshold (t1) for cpu overuse adaptation. (Adapt down)
+ // Metric: encode usage (m1). m1 > t1 => overuse.
+ Settable<int> cpu_overuse_threshold;
+ // Low threshold (t2) for cpu overuse adaptation. (Adapt up)
+ // Metric: relative standard deviation of encode time (m2).
+ // Optional threshold. If set, (m1 < t1 && m2 < t2) => underuse.
+ // Note: t2 will have no effect if t1 is not set.
+ Settable<int> cpu_underuse_encode_rsd_threshold;
+ // High threshold (t2) for cpu overuse adaptation. (Adapt down)
+ // Metric: relative standard deviation of encode time (m2).
+ // Optional threshold. If set, (m1 > t1 || m2 > t2) => overuse.
+ // Note: t2 will have no effect if t1 is not set.
+ Settable<int> cpu_overuse_encode_rsd_threshold;
+ // Use encode usage for cpu detection.
+ Settable<bool> cpu_overuse_encode_usage;
// Use conference mode?
Settable<bool> conference_mode;
// Threshhold for process cpu adaptation. (Process limit)
@@ -421,6 +498,19 @@ struct VideoOptions {
// Enable WebRTC suspension of video. No video frames will be sent when the
// bitrate is below the configured minimum bitrate.
Settable<bool> suspend_below_min_bitrate;
+ // Limit on the number of early receive channels that can be created.
+ Settable<int> unsignalled_recv_stream_limit;
+ // Enable use of simulcast adapter.
+ Settable<bool> use_simulcast_adapter;
+ // Enables the encoder to skip encoding stream not actually sent due to too
+ // low available bit rate.
+ Settable<bool> skip_encoding_unused_streams;
+ // Force screencast to use a minimum bitrate
+ Settable<int> screencast_min_bitrate;
+ // Enable improved bandwidth estiamtor on wifi.
+ Settable<bool> use_improved_wifi_bandwidth_estimator;
+ // Enable payload padding.
+ Settable<bool> use_payload_padding;
};
// A class for playing out soundclips.
@@ -539,8 +629,14 @@ class MediaChannel : public sigslot::has_slots<> {
const std::vector<RtpHeaderExtension>& extensions) = 0;
virtual bool SetSendRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) = 0;
- // Sets the rate control to use when sending data.
- virtual bool SetSendBandwidth(bool autobw, int bps) = 0;
+ // Returns the absoulte sendtime extension id value from media channel.
+ virtual int GetRtpSendTimeExtnId() const {
+ return -1;
+ }
+ // Sets the initial bandwidth to use when sending starts.
+ virtual bool SetStartSendBandwidth(int bps) = 0;
+ // Sets the maximum allowed bandwidth to use when sending data.
+ virtual bool SetMaxSendBandwidth(int bps) = 0;
// Base method to send packet using NetworkInterface.
bool SendPacket(talk_base::Buffer* packet) {
@@ -671,6 +767,20 @@ struct MediaSenderInfo {
std::vector<SsrcReceiverInfo> remote_stats;
};
+template<class T>
+struct VariableInfo {
+ VariableInfo()
+ : min_val(),
+ mean(0.0),
+ max_val(),
+ variance(0.0) {
+ }
+ T min_val;
+ double mean;
+ T max_val;
+ double variance;
+};
+
struct MediaReceiverInfo {
MediaReceiverInfo()
: bytes_rcvd(0),
@@ -711,6 +821,7 @@ struct MediaReceiverInfo {
int packets_rcvd;
int packets_lost;
float fraction_lost;
+ std::string codec_name;
std::vector<SsrcReceiverInfo> local_stats;
std::vector<SsrcSenderInfo> remote_stats;
};
@@ -747,7 +858,14 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
jitter_buffer_preferred_ms(0),
delay_estimate_ms(0),
audio_level(0),
- expand_rate(0) {
+ expand_rate(0),
+ decoding_calls_to_silence_generator(0),
+ decoding_calls_to_neteq(0),
+ decoding_normal(0),
+ decoding_plc(0),
+ decoding_cng(0),
+ decoding_plc_cng(0),
+ capture_start_ntp_time_ms(-1) {
}
int ext_seqnum;
@@ -758,15 +876,26 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
int audio_level;
// fraction of synthesized speech inserted through pre-emptive expansion
float expand_rate;
+ int decoding_calls_to_silence_generator;
+ int decoding_calls_to_neteq;
+ int decoding_normal;
+ int decoding_plc;
+ int decoding_cng;
+ int decoding_plc_cng;
+ // Estimated capture start time in NTP time in ms.
+ int64 capture_start_ntp_time_ms;
};
struct VideoSenderInfo : public MediaSenderInfo {
VideoSenderInfo()
: packets_cached(0),
firs_rcvd(0),
+ plis_rcvd(0),
nacks_rcvd(0),
- frame_width(0),
- frame_height(0),
+ input_frame_width(0),
+ input_frame_height(0),
+ send_frame_width(0),
+ send_frame_height(0),
framerate_input(0),
framerate_sent(0),
nominal_bitrate(0),
@@ -775,15 +904,19 @@ struct VideoSenderInfo : public MediaSenderInfo {
capture_jitter_ms(0),
avg_encode_ms(0),
encode_usage_percent(0),
+ encode_rsd(0),
capture_queue_delay_ms_per_s(0) {
}
std::vector<SsrcGroup> ssrc_groups;
int packets_cached;
int firs_rcvd;
+ int plis_rcvd;
int nacks_rcvd;
- int frame_width;
- int frame_height;
+ int input_frame_width;
+ int input_frame_height;
+ int send_frame_width;
+ int send_frame_height;
int framerate_input;
int framerate_sent;
int nominal_bitrate;
@@ -792,13 +925,18 @@ struct VideoSenderInfo : public MediaSenderInfo {
int capture_jitter_ms;
int avg_encode_ms;
int encode_usage_percent;
+ int encode_rsd;
int capture_queue_delay_ms_per_s;
+ VariableInfo<int> adapt_frame_drops;
+ VariableInfo<int> effects_frame_drops;
+ VariableInfo<double> capturer_frame_time;
};
struct VideoReceiverInfo : public MediaReceiverInfo {
VideoReceiverInfo()
: packets_concealed(0),
firs_sent(0),
+ plis_sent(0),
nacks_sent(0),
frame_width(0),
frame_height(0),
@@ -813,12 +951,14 @@ struct VideoReceiverInfo : public MediaReceiverInfo {
min_playout_delay_ms(0),
render_delay_ms(0),
target_delay_ms(0),
- current_delay_ms(0) {
+ current_delay_ms(0),
+ capture_start_ntp_time_ms(-1) {
}
std::vector<SsrcGroup> ssrc_groups;
int packets_concealed;
int firs_sent;
+ int plis_sent;
int nacks_sent;
int frame_width;
int frame_height;
@@ -849,6 +989,9 @@ struct VideoReceiverInfo : public MediaReceiverInfo {
int target_delay_ms;
// Current overall delay, possibly ramping towards target_delay_ms.
int current_delay_ms;
+
+ // Estimated capture start time in NTP time in ms.
+ int64 capture_start_ntp_time_ms;
};
struct DataSenderInfo : public MediaSenderInfo {
@@ -875,7 +1018,8 @@ struct BandwidthEstimationInfo {
actual_enc_bitrate(0),
retransmit_bitrate(0),
transmit_bitrate(0),
- bucket_delay(0) {
+ bucket_delay(0),
+ total_received_propagation_delta_ms(0) {
}
int available_send_bandwidth;
@@ -885,6 +1029,11 @@ struct BandwidthEstimationInfo {
int retransmit_bitrate;
int transmit_bitrate;
int bucket_delay;
+ // The following stats are only valid when
+ // StatsOptions::include_received_propagation_stats is true.
+ int total_received_propagation_delta_ms;
+ std::vector<int> recent_received_propagation_delta_ms;
+ std::vector<int64> recent_received_packet_group_arrival_time_ms;
};
struct VoiceMediaInfo {
@@ -916,6 +1065,12 @@ struct DataMediaInfo {
std::vector<DataReceiverInfo> receivers;
};
+struct StatsOptions {
+ StatsOptions() : include_received_propagation_stats(false) {}
+
+ bool include_received_propagation_stats;
+};
+
class VoiceMediaChannel : public MediaChannel {
public:
enum Error {
@@ -1034,7 +1189,12 @@ class VideoMediaChannel : public MediaChannel {
// |capturer|. If |ssrc| is non zero create a new stream with |ssrc| as SSRC.
virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer) = 0;
// Gets quality stats for the channel.
- virtual bool GetStats(VideoMediaInfo* info) = 0;
+ virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info) = 0;
+ // This is needed for MediaMonitor to use the same template for voice, video
+ // and data MediaChannels.
+ bool GetStats(VideoMediaInfo* info) {
+ return GetStats(StatsOptions(), info);
+ }
// Send an intra frame to the receivers.
virtual bool SendIntraFrame() = 0;
@@ -1157,11 +1317,8 @@ class DataMediaChannel : public MediaChannel {
// Signal when the media channel is ready to send the stream. Arguments are:
// writable(bool)
sigslot::signal1<bool> SignalReadyToSend;
- // Signal for notifying when a new stream is added from the remote side. Used
- // for the in-band negotioation through the OPEN message for SCTP data
- // channel.
- sigslot::signal2<const std::string&, const webrtc::DataChannelInit&>
- SignalNewStreamReceived;
+ // Signal for notifying that the remote side has closed the DataChannel.
+ sigslot::signal1<uint32> SignalStreamClosedRemotely;
};
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/media/base/mediaengine.cc b/chromium/third_party/libjingle/source/talk/media/base/mediaengine.cc
index 021cf81f1c2..289f2290a47 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/mediaengine.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/mediaengine.cc
@@ -42,6 +42,13 @@ const int MediaEngineInterface::kDefaultAudioDelayOffset = 0;
#if defined(HAVE_WEBRTC_VIDEO)
#include "talk/media/webrtc/webrtcvideoengine.h"
#endif // HAVE_WEBRTC_VIDEO
+#if defined(HAVE_LMI)
+#include "talk/media/base/hybridvideoengine.h"
+#include "talk/media/lmi/lmimediaengine.h"
+#endif // HAVE_LMI
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG
namespace cricket {
#if defined(HAVE_WEBRTC_VOICE)
@@ -51,22 +58,59 @@ namespace cricket {
#endif
#if defined(HAVE_WEBRTC_VIDEO)
+#if !defined(HAVE_LMI)
template<>
CompositeMediaEngine<WebRtcVoiceEngine, WebRtcVideoEngine>::
CompositeMediaEngine() {
video_.SetVoiceEngine(&voice_);
}
#define VIDEO_ENG_NAME WebRtcVideoEngine
+#else
+// If we have both WebRtcVideoEngine and LmiVideoEngine, enable dual-stack.
+// This small class here allows us to hook the WebRtcVideoChannel up to
+// the capturer owned by the LMI engine, without infecting the rest of the
+// HybridVideoEngine classes with this abstraction violation.
+class WebRtcLmiHybridVideoEngine
+ : public HybridVideoEngine<WebRtcVideoEngine, LmiVideoEngine> {
+ public:
+ void SetVoiceEngine(WebRtcVoiceEngine* engine) {
+ video1_.SetVoiceEngine(engine);
+ }
+};
+template<>
+CompositeMediaEngine<WebRtcVoiceEngine, WebRtcLmiHybridVideoEngine>::
+ CompositeMediaEngine() {
+ video_.SetVoiceEngine(&voice_);
+}
+#define VIDEO_ENG_NAME WebRtcLmiHybridVideoEngine
+#endif
+#elif defined(HAVE_LMI)
+#define VIDEO_ENG_NAME LmiVideoEngine
+#else
+#define VIDEO_ENG_NAME NullVideoEngine
#endif
+MediaEngineFactory::MediaEngineCreateFunction
+ MediaEngineFactory::create_function_ = NULL;
+MediaEngineFactory::MediaEngineCreateFunction
+ MediaEngineFactory::SetCreateFunction(MediaEngineCreateFunction function) {
+ MediaEngineCreateFunction old_function = create_function_;
+ create_function_ = function;
+ return old_function;
+};
+
MediaEngineInterface* MediaEngineFactory::Create() {
+ if (create_function_) {
+ return create_function_();
+ } else {
#if defined(HAVE_LINPHONE)
- return new LinphoneMediaEngine("", "");
+ return new LinphoneMediaEngine("", "");
#elif defined(AUDIO_ENG_NAME) && defined(VIDEO_ENG_NAME)
- return new CompositeMediaEngine<AUDIO_ENG_NAME, VIDEO_ENG_NAME>();
+ return new CompositeMediaEngine<AUDIO_ENG_NAME, VIDEO_ENG_NAME>();
#else
- return new NullMediaEngine();
+ return new NullMediaEngine();
#endif
+ }
}
}; // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/media/base/mediaengine.h b/chromium/third_party/libjingle/source/talk/media/base/mediaengine.h
index f9165728dde..326b722bd00 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/mediaengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/mediaengine.h
@@ -32,10 +32,12 @@
#include <CoreAudio/CoreAudio.h>
#endif
-#include <climits>
+#include <limits.h>
+
#include <string>
#include <vector>
+#include "talk/base/fileutils.h"
#include "talk/base/sigslotrepeater.h"
#include "talk/media/base/codec.h"
#include "talk/media/base/mediachannel.h"
@@ -135,6 +137,9 @@ class MediaEngineInterface {
virtual void SetVoiceLogging(int min_sev, const char* filter) = 0;
virtual void SetVideoLogging(int min_sev, const char* filter) = 0;
+ // Starts AEC dump using existing file.
+ virtual bool StartAecDump(talk_base::PlatformFile file) = 0;
+
// Voice processors for effects.
virtual bool RegisterVoiceProcessor(uint32 ssrc,
VoiceProcessor* video_processor,
@@ -153,7 +158,18 @@ class MediaEngineInterface {
#if !defined(DISABLE_MEDIA_ENGINE_FACTORY)
class MediaEngineFactory {
public:
+ typedef cricket::MediaEngineInterface* (*MediaEngineCreateFunction)();
+ // Creates a media engine, using either the compiled system default or the
+ // creation function specified in SetCreateFunction, if specified.
static MediaEngineInterface* Create();
+ // Sets the function used when calling Create. If unset, the compiled system
+ // default will be used. Returns the old create function, or NULL if one
+ // wasn't set. Likewise, NULL can be used as the |function| parameter to
+ // reset to the default behavior.
+ static MediaEngineCreateFunction SetCreateFunction(
+ MediaEngineCreateFunction function);
+ private:
+ static MediaEngineCreateFunction create_function_;
};
#endif
@@ -253,6 +269,10 @@ class CompositeMediaEngine : public MediaEngineInterface {
video_.SetLogging(min_sev, filter);
}
+ virtual bool StartAecDump(talk_base::PlatformFile file) {
+ return voice_.StartAecDump(file);
+ }
+
virtual bool RegisterVoiceProcessor(uint32 ssrc,
VoiceProcessor* processor,
MediaProcessorDirection direction) {
@@ -309,6 +329,7 @@ class NullVoiceEngine {
return rtp_header_extensions_;
}
void SetLogging(int min_sev, const char* filter) {}
+ bool StartAecDump(talk_base::PlatformFile file) { return false; }
bool RegisterProcessor(uint32 ssrc,
VoiceProcessor* voice_processor,
MediaProcessorDirection direction) { return true; }
diff --git a/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine.cc b/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine.cc
index 0f84c836fc6..3d0efc43b0e 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine.cc
@@ -290,8 +290,8 @@ void RtpDataMediaChannel::OnPacketReceived(
SignalDataReceived(params, data, data_len);
}
-bool RtpDataMediaChannel::SetSendBandwidth(bool autobw, int bps) {
- if (autobw || bps <= 0) {
+bool RtpDataMediaChannel::SetMaxSendBandwidth(int bps) {
+ if (bps <= 0) {
bps = kDataMaxBandwidth;
}
send_limiter_.reset(new talk_base::RateLimiter(bps / 8, 1.0));
diff --git a/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine.h b/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine.h
index 59e6589532d..d5abeef68a4 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine.h
@@ -96,7 +96,8 @@ class RtpDataMediaChannel : public DataMediaChannel {
timing_ = timing;
}
- virtual bool SetSendBandwidth(bool autobw, int bps);
+ virtual bool SetStartSendBandwidth(int bps) { return true; }
+ virtual bool SetMaxSendBandwidth(int bps);
virtual bool SetRecvRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) { return true; }
virtual bool SetSendRtpHeaderExtensions(
diff --git a/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine_unittest.cc b/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine_unittest.cc
index a86ab3b3125..640c18dbfcc 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/rtpdataengine_unittest.cc
@@ -31,6 +31,7 @@
#include "talk/base/gunit.h"
#include "talk/base/helpers.h"
#include "talk/base/scoped_ptr.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/timing.h"
#include "talk/media/base/constants.h"
#include "talk/media/base/fakenetworkinterface.h"
@@ -82,6 +83,14 @@ class FakeDataReceiver : public sigslot::has_slots<> {
class RtpDataMediaChannelTest : public testing::Test {
protected:
+ static void SetUpTestCase() {
+ talk_base::InitializeSSL();
+ }
+
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
+ }
+
virtual void SetUp() {
// Seed needed for each test to satisfy expectations.
iface_.reset(new cricket::FakeNetworkInterface());
@@ -387,7 +396,7 @@ TEST_F(RtpDataMediaChannelTest, SendDataRate) {
// With rtp overhead of 32 bytes, each one of our packets is 36
// bytes, or 288 bits. So, a limit of 872bps will allow 3 packets,
// but not four.
- dmc->SetSendBandwidth(false, 872);
+ dmc->SetMaxSendBandwidth(872);
EXPECT_TRUE(dmc->SendData(params, payload, &result));
EXPECT_TRUE(dmc->SendData(params, payload, &result));
diff --git a/chromium/third_party/libjingle/source/talk/media/base/rtpdump.h b/chromium/third_party/libjingle/source/talk/media/base/rtpdump.h
index 9d7b679d589..ceacab2cda7 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/rtpdump.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/rtpdump.h
@@ -28,7 +28,8 @@
#ifndef TALK_MEDIA_BASE_RTPDUMP_H_
#define TALK_MEDIA_BASE_RTPDUMP_H_
-#include <cstring>
+#include <string.h>
+
#include <string>
#include <vector>
diff --git a/chromium/third_party/libjingle/source/talk/media/base/testutils.cc b/chromium/third_party/libjingle/source/talk/media/base/testutils.cc
index 9b1b16d21fc..73206138413 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/testutils.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/testutils.cc
@@ -35,6 +35,7 @@
#include "talk/base/pathutils.h"
#include "talk/base/stream.h"
#include "talk/base/stringutils.h"
+#include "talk/base/testutils.h"
#include "talk/media/base/rtpdump.h"
#include "talk/media/base/videocapturer.h"
#include "talk/media/base/videoframe.h"
@@ -254,7 +255,7 @@ void VideoCapturerListener::OnFrameCaptured(VideoCapturer* capturer,
// Returns the absolute path to a file in the testdata/ directory.
std::string GetTestFilePath(const std::string& filename) {
// Locate test data directory.
- talk_base::Pathname path = GetTalkDirectory();
+ talk_base::Pathname path = testing::GetTalkDirectory();
EXPECT_FALSE(path.empty()); // must be run from inside "talk"
path.AppendFolder("media");
path.AppendFolder("testdata");
diff --git a/chromium/third_party/libjingle/source/talk/media/base/videoadapter.cc b/chromium/third_party/libjingle/source/talk/media/base/videoadapter.cc
index 22b1f7d8ddb..76ec52775c0 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/videoadapter.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/videoadapter.cc
@@ -30,15 +30,16 @@
#include "talk/base/logging.h"
#include "talk/base/timeutils.h"
#include "talk/media/base/constants.h"
+#include "talk/media/base/videocommon.h"
#include "talk/media/base/videoframe.h"
namespace cricket {
// TODO(fbarchard): Make downgrades settable
static const int kMaxCpuDowngrades = 2; // Downgrade at most 2 times for CPU.
-// The number of milliseconds of data to require before acting on cpu sampling
-// information.
-static const size_t kCpuLoadMinSampleTime = 5000;
+// The number of cpu samples to require before adapting. This value depends on
+// the cpu monitor sampling frequency being 2000ms.
+static const int kCpuLoadMinSamples = 3;
// The amount of weight to give to each new cpu load sample. The lower the
// value, the slower we'll adapt to changing cpu conditions.
static const float kCpuLoadWeightCoefficient = 0.4f;
@@ -162,8 +163,9 @@ float VideoAdapter::FindLowerScale(int width, int height,
VideoAdapter::VideoAdapter()
: output_num_pixels_(INT_MAX),
scale_third_(false),
- frames_(0),
- adapted_frames_(0),
+ frames_in_(0),
+ frames_out_(0),
+ frames_scaled_(0),
adaption_changes_(0),
previous_width_(0),
previous_height_(0),
@@ -177,9 +179,14 @@ VideoAdapter::~VideoAdapter() {
void VideoAdapter::SetInputFormat(const VideoFormat& format) {
talk_base::CritScope cs(&critical_section_);
+ int64 old_input_interval = input_format_.interval;
input_format_ = format;
output_format_.interval = talk_base::_max(
output_format_.interval, input_format_.interval);
+ if (old_input_interval != input_format_.interval) {
+ LOG(LS_INFO) << "VAdapt input interval changed from "
+ << old_input_interval << " to " << input_format_.interval;
+ }
}
void CoordinatedVideoAdapter::SetInputFormat(const VideoFormat& format) {
@@ -205,12 +212,23 @@ void CoordinatedVideoAdapter::SetInputFormat(const VideoFormat& format) {
}
}
+void CoordinatedVideoAdapter::set_cpu_smoothing(bool enable) {
+ LOG(LS_INFO) << "CPU smoothing is now "
+ << (enable ? "enabled" : "disabled");
+ cpu_smoothing_ = enable;
+}
+
void VideoAdapter::SetOutputFormat(const VideoFormat& format) {
talk_base::CritScope cs(&critical_section_);
+ int64 old_output_interval = output_format_.interval;
output_format_ = format;
output_num_pixels_ = output_format_.width * output_format_.height;
output_format_.interval = talk_base::_max(
output_format_.interval, input_format_.interval);
+ if (old_output_interval != output_format_.interval) {
+ LOG(LS_INFO) << "VAdapt output interval changed from "
+ << old_output_interval << " to " << output_format_.interval;
+ }
}
const VideoFormat& VideoAdapter::input_format() {
@@ -218,6 +236,10 @@ const VideoFormat& VideoAdapter::input_format() {
return input_format_;
}
+bool VideoAdapter::drops_all_frames() const {
+ return output_num_pixels_ == 0;
+}
+
const VideoFormat& VideoAdapter::output_format() {
talk_base::CritScope cs(&critical_section_);
return output_format_;
@@ -239,13 +261,13 @@ int VideoAdapter::GetOutputNumPixels() const {
// TODO(fbarchard): Add AdaptFrameRate function that only drops frames but
// not resolution.
-bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
+bool VideoAdapter::AdaptFrame(VideoFrame* in_frame,
VideoFrame** out_frame) {
+ talk_base::CritScope cs(&critical_section_);
if (!in_frame || !out_frame) {
return false;
}
- talk_base::CritScope cs(&critical_section_);
- ++frames_;
+ ++frames_in_;
// Update input to actual frame dimensions.
VideoFormat format(static_cast<int>(in_frame->GetWidth()),
@@ -273,12 +295,25 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
}
}
if (should_drop) {
+ // Show VAdapt log every 90 frames dropped. (3 seconds)
+ if ((frames_in_ - frames_out_) % 90 == 0) {
+ // TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
+ // in default calls.
+ LOG(LS_INFO) << "VAdapt Drop Frame: scaled " << frames_scaled_
+ << " / out " << frames_out_
+ << " / in " << frames_in_
+ << " Changes: " << adaption_changes_
+ << " Input: " << in_frame->GetWidth()
+ << "x" << in_frame->GetHeight()
+ << " i" << input_format_.interval
+ << " Output: i" << output_format_.interval;
+ }
*out_frame = NULL;
return true;
}
float scale = 1.f;
- if (output_num_pixels_) {
+ if (output_num_pixels_ < input_format_.width * input_format_.height) {
scale = VideoAdapter::FindClosestViewScale(
static_cast<int>(in_frame->GetWidth()),
static_cast<int>(in_frame->GetHeight()),
@@ -286,22 +321,35 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
output_format_.width = static_cast<int>(in_frame->GetWidth() * scale + .5f);
output_format_.height = static_cast<int>(in_frame->GetHeight() * scale +
.5f);
+ } else {
+ output_format_.width = static_cast<int>(in_frame->GetWidth());
+ output_format_.height = static_cast<int>(in_frame->GetHeight());
}
- if (!StretchToOutputFrame(in_frame)) {
- return false;
- }
+ if (!black_output_ &&
+ in_frame->GetWidth() == static_cast<size_t>(output_format_.width) &&
+ in_frame->GetHeight() == static_cast<size_t>(output_format_.height)) {
+ // The dimensions are correct and we aren't muting, so use the input frame.
+ *out_frame = in_frame;
+ } else {
+ if (!StretchToOutputFrame(in_frame)) {
+ LOG(LS_VERBOSE) << "VAdapt Stretch Failed.";
+ return false;
+ }
- *out_frame = output_frame_.get();
+ *out_frame = output_frame_.get();
+ }
- // Show VAdapt log every 300 frames. (10 seconds)
- // TODO(fbarchard): Consider GetLogSeverity() to change interval to less
- // for LS_VERBOSE and more for LS_INFO.
- bool show = frames_ % 300 == 0;
+ ++frames_out_;
if (in_frame->GetWidth() != (*out_frame)->GetWidth() ||
in_frame->GetHeight() != (*out_frame)->GetHeight()) {
- ++adapted_frames_;
+ ++frames_scaled_;
}
+ // Show VAdapt log every 90 frames output. (3 seconds)
+ // TODO(fbarchard): Consider GetLogSeverity() to change interval to less
+ // for LS_VERBOSE and more for LS_INFO.
+ bool show = (frames_out_) % 90 == 0;
+
// TODO(fbarchard): LOG the previous output resolution and track input
// resolution changes as well. Consider dropping the statistics into their
// own class which could be queried publically.
@@ -315,14 +363,17 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
if (show) {
// TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
// in default calls.
- LOG(LS_INFO) << "VAdapt Frame: " << adapted_frames_
- << " / " << frames_
+ LOG(LS_INFO) << "VAdapt Frame: scaled " << frames_scaled_
+ << " / out " << frames_out_
+ << " / in " << frames_in_
<< " Changes: " << adaption_changes_
<< " Input: " << in_frame->GetWidth()
<< "x" << in_frame->GetHeight()
+ << " i" << input_format_.interval
<< " Scale: " << scale
<< " Output: " << (*out_frame)->GetWidth()
<< "x" << (*out_frame)->GetHeight()
+ << " i" << output_format_.interval
<< " Changed: " << (changed ? "true" : "false");
}
previous_width_ = (*out_frame)->GetWidth();
@@ -331,6 +382,12 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
return true;
}
+void VideoAdapter::set_scale_third(bool enable) {
+ LOG(LS_INFO) << "Video Adapter third scaling is now "
+ << (enable ? "enabled" : "disabled");
+ scale_third_ = enable;
+}
+
// Scale or Blacken the frame. Returns true if successful.
bool VideoAdapter::StretchToOutputFrame(const VideoFrame* in_frame) {
int output_width = output_format_.width;
@@ -382,7 +439,8 @@ CoordinatedVideoAdapter::CoordinatedVideoAdapter()
view_adaptation_(true),
view_switch_(false),
cpu_downgrade_count_(0),
- cpu_adapt_wait_time_(0),
+ cpu_load_min_samples_(kCpuLoadMinSamples),
+ cpu_load_num_samples_(0),
high_system_threshold_(kHighSystemCpuThreshold),
low_system_threshold_(kLowSystemCpuThreshold),
process_threshold_(kProcessCpuThreshold),
@@ -390,7 +448,7 @@ CoordinatedVideoAdapter::CoordinatedVideoAdapter()
view_desired_interval_(0),
encoder_desired_num_pixels_(INT_MAX),
cpu_desired_num_pixels_(INT_MAX),
- adapt_reason_(0),
+ adapt_reason_(ADAPTREASON_NONE),
system_load_average_(kCpuLoadInitialAverage) {
}
@@ -450,6 +508,48 @@ void CoordinatedVideoAdapter::OnOutputFormatRequest(const VideoFormat& format) {
<< " To: " << new_width << "x" << new_height;
}
+void CoordinatedVideoAdapter::set_cpu_load_min_samples(
+ int cpu_load_min_samples) {
+ if (cpu_load_min_samples_ != cpu_load_min_samples) {
+ LOG(LS_INFO) << "VAdapt Change Cpu Adapt Min Samples from: "
+ << cpu_load_min_samples_ << " to "
+ << cpu_load_min_samples;
+ cpu_load_min_samples_ = cpu_load_min_samples;
+ }
+}
+
+void CoordinatedVideoAdapter::set_high_system_threshold(
+ float high_system_threshold) {
+ ASSERT(high_system_threshold <= 1.0f);
+ ASSERT(high_system_threshold >= 0.0f);
+ if (high_system_threshold_ != high_system_threshold) {
+ LOG(LS_INFO) << "VAdapt Change High System Threshold from: "
+ << high_system_threshold_ << " to " << high_system_threshold;
+ high_system_threshold_ = high_system_threshold;
+ }
+}
+
+void CoordinatedVideoAdapter::set_low_system_threshold(
+ float low_system_threshold) {
+ ASSERT(low_system_threshold <= 1.0f);
+ ASSERT(low_system_threshold >= 0.0f);
+ if (low_system_threshold_ != low_system_threshold) {
+ LOG(LS_INFO) << "VAdapt Change Low System Threshold from: "
+ << low_system_threshold_ << " to " << low_system_threshold;
+ low_system_threshold_ = low_system_threshold;
+ }
+}
+
+void CoordinatedVideoAdapter::set_process_threshold(float process_threshold) {
+ ASSERT(process_threshold <= 1.0f);
+ ASSERT(process_threshold >= 0.0f);
+ if (process_threshold_ != process_threshold) {
+ LOG(LS_INFO) << "VAdapt Change High Process Threshold from: "
+ << process_threshold_ << " to " << process_threshold;
+ process_threshold_ = process_threshold;
+ }
+}
+
// A Bandwidth GD request for new resolution
void CoordinatedVideoAdapter::OnEncoderResolutionRequest(
int width, int height, AdaptRequest request) {
@@ -552,22 +652,18 @@ void CoordinatedVideoAdapter::OnCpuLoadUpdated(
// we'll still calculate this information, in case smoothing is later enabled.
system_load_average_ = kCpuLoadWeightCoefficient * system_load +
(1.0f - kCpuLoadWeightCoefficient) * system_load_average_;
+ ++cpu_load_num_samples_;
if (cpu_smoothing_) {
system_load = system_load_average_;
}
- // If we haven't started taking samples yet, wait until we have at least
- // the correct number of samples per the wait time.
- if (cpu_adapt_wait_time_ == 0) {
- cpu_adapt_wait_time_ = talk_base::TimeAfter(kCpuLoadMinSampleTime);
- }
AdaptRequest request = FindCpuRequest(current_cpus, max_cpus,
process_load, system_load);
// Make sure we're not adapting too quickly.
if (request != KEEP) {
- if (talk_base::TimeIsLater(talk_base::Time(),
- cpu_adapt_wait_time_)) {
+ if (cpu_load_num_samples_ < cpu_load_min_samples_) {
LOG(LS_VERBOSE) << "VAdapt CPU load high/low but do not adapt until "
- << talk_base::TimeUntil(cpu_adapt_wait_time_) << " ms";
+ << (cpu_load_min_samples_ - cpu_load_num_samples_)
+ << " more samples";
request = KEEP;
}
}
@@ -609,7 +705,7 @@ bool CoordinatedVideoAdapter::AdaptToMinimumFormat(int* new_width,
}
int old_num_pixels = GetOutputNumPixels();
int min_num_pixels = INT_MAX;
- adapt_reason_ = 0;
+ adapt_reason_ = ADAPTREASON_NONE;
// Reduce resolution based on encoder bandwidth (GD).
if (encoder_desired_num_pixels_ &&
@@ -650,7 +746,7 @@ bool CoordinatedVideoAdapter::AdaptToMinimumFormat(int* new_width,
static_cast<int>(input.height * scale + .5f);
}
if (scale == 1.0f) {
- adapt_reason_ = 0;
+ adapt_reason_ = ADAPTREASON_NONE;
}
*new_width = new_output.width = static_cast<int>(input.width * scale + .5f);
*new_height = new_output.height = static_cast<int>(input.height * scale +
@@ -688,7 +784,7 @@ bool CoordinatedVideoAdapter::AdaptToMinimumFormat(int* new_width,
if (changed) {
// When any adaptation occurs, historic CPU load levels are no longer
// accurate. Clear out our state so we can re-learn at the new normal.
- cpu_adapt_wait_time_ = talk_base::TimeAfter(kCpuLoadMinSampleTime);
+ cpu_load_num_samples_ = 0;
system_load_average_ = kCpuLoadInitialAverage;
}
diff --git a/chromium/third_party/libjingle/source/talk/media/base/videoadapter.h b/chromium/third_party/libjingle/source/talk/media/base/videoadapter.h
index 12be4fab1ab..0634942d9be 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/videoadapter.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/videoadapter.h
@@ -28,7 +28,6 @@
#include "talk/base/common.h" // For ASSERT
#include "talk/base/criticalsection.h"
-#include "talk/base/logging.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/sigslot.h"
#include "talk/media/base/videocommon.h"
@@ -52,6 +51,8 @@ class VideoAdapter {
int GetOutputNumPixels() const;
const VideoFormat& input_format();
+ // Returns true if the adapter is dropping frames in calls to AdaptFrame.
+ bool drops_all_frames() const;
const VideoFormat& output_format();
// If the parameter black is true, the adapted frames will be black.
void SetBlackOutput(bool black);
@@ -60,15 +61,15 @@ class VideoAdapter {
// true and set the output frame to NULL if the input frame is dropped. Return
// true and set the out frame to output_frame_ if the input frame is adapted
// successfully. Return false otherwise.
- // output_frame_ is owned by the VideoAdapter that has the best knowledge on
- // the output frame.
- bool AdaptFrame(const VideoFrame* in_frame, VideoFrame** out_frame);
-
- void set_scale_third(bool enable) {
- LOG(LS_INFO) << "Video Adapter third scaling is now "
- << (enable ? "enabled" : "disabled");
- scale_third_ = enable;
- }
+ // Note that, if no adaptation is required, |out_frame| will refer directly
+ // in_frame. If a copy is always required, the caller must do an explicit
+ // copy.
+ // If a copy has taken place, |output_frame_| is owned by the VideoAdapter
+ // and will remain usable until the adapter is destroyed or AdaptFrame is
+ // called again.
+ bool AdaptFrame(VideoFrame* in_frame, VideoFrame** out_frame);
+
+ void set_scale_third(bool enable);
bool scale_third() const { return scale_third_; }
protected:
@@ -87,8 +88,9 @@ class VideoAdapter {
VideoFormat output_format_;
int output_num_pixels_;
bool scale_third_; // True if adapter allows scaling to 1/3 and 2/3.
- int frames_; // Number of input frames.
- int adapted_frames_; // Number of frames scaled.
+ int frames_in_; // Number of input frames.
+ int frames_out_; // Number of output frames.
+ int frames_scaled_; // Number of frames scaled.
int adaption_changes_; // Number of changes in scale factor.
size_t previous_width_; // Previous adapter output width.
size_t previous_height_; // Previous adapter output height.
@@ -110,6 +112,7 @@ class CoordinatedVideoAdapter
public:
enum AdaptRequest { UPGRADE, KEEP, DOWNGRADE };
enum AdaptReasonEnum {
+ ADAPTREASON_NONE = 0,
ADAPTREASON_CPU = 1,
ADAPTREASON_BANDWIDTH = 2,
ADAPTREASON_VIEW = 4
@@ -127,11 +130,7 @@ class CoordinatedVideoAdapter
// Enable or disable smoothing when doing CPU adaptation. When smoothing is
// enabled, system CPU load is tracked using an exponential weighted
// average.
- void set_cpu_smoothing(bool enable) {
- LOG(LS_INFO) << "CPU smoothing is now "
- << (enable ? "enabled" : "disabled");
- cpu_smoothing_ = enable;
- }
+ void set_cpu_smoothing(bool enable);
bool cpu_smoothing() const { return cpu_smoothing_; }
// Enable or disable video adaptation due to the change of the GD
void set_gd_adaptation(bool enable) { gd_adaptation_ = enable; }
@@ -149,46 +148,16 @@ class CoordinatedVideoAdapter
// When the video is decreased, set the waiting time for CPU adaptation to
// decrease video again.
- void set_cpu_adapt_wait_time(uint32 cpu_adapt_wait_time) {
- if (cpu_adapt_wait_time_ != static_cast<int>(cpu_adapt_wait_time)) {
- LOG(LS_INFO) << "VAdapt Change Cpu Adapt Wait Time from: "
- << cpu_adapt_wait_time_ << " to "
- << cpu_adapt_wait_time;
- cpu_adapt_wait_time_ = static_cast<int>(cpu_adapt_wait_time);
- }
- }
+ void set_cpu_load_min_samples(int cpu_load_min_samples);
+ int cpu_load_min_samples() const { return cpu_load_min_samples_; }
// CPU system load high threshold for reducing resolution. e.g. 0.85f
- void set_high_system_threshold(float high_system_threshold) {
- ASSERT(high_system_threshold <= 1.0f);
- ASSERT(high_system_threshold >= 0.0f);
- if (high_system_threshold_ != high_system_threshold) {
- LOG(LS_INFO) << "VAdapt Change High System Threshold from: "
- << high_system_threshold_ << " to " << high_system_threshold;
- high_system_threshold_ = high_system_threshold;
- }
- }
+ void set_high_system_threshold(float high_system_threshold);
float high_system_threshold() const { return high_system_threshold_; }
// CPU system load low threshold for increasing resolution. e.g. 0.70f
- void set_low_system_threshold(float low_system_threshold) {
- ASSERT(low_system_threshold <= 1.0f);
- ASSERT(low_system_threshold >= 0.0f);
- if (low_system_threshold_ != low_system_threshold) {
- LOG(LS_INFO) << "VAdapt Change Low System Threshold from: "
- << low_system_threshold_ << " to " << low_system_threshold;
- low_system_threshold_ = low_system_threshold;
- }
- }
+ void set_low_system_threshold(float low_system_threshold);
float low_system_threshold() const { return low_system_threshold_; }
// CPU process load threshold for reducing resolution. e.g. 0.10f
- void set_process_threshold(float process_threshold) {
- ASSERT(process_threshold <= 1.0f);
- ASSERT(process_threshold >= 0.0f);
- if (process_threshold_ != process_threshold) {
- LOG(LS_INFO) << "VAdapt Change High Process Threshold from: "
- << process_threshold_ << " to " << process_threshold;
- process_threshold_ = process_threshold;
- }
- }
+ void set_process_threshold(float process_threshold);
float process_threshold() const { return process_threshold_; }
// Handle the format request from the server via Jingle update message.
@@ -220,7 +189,8 @@ class CoordinatedVideoAdapter
bool view_adaptation_; // True if view adaptation is enabled.
bool view_switch_; // True if view switch is enabled.
int cpu_downgrade_count_;
- int cpu_adapt_wait_time_;
+ int cpu_load_min_samples_;
+ int cpu_load_num_samples_;
// cpu system load thresholds relative to max cpus.
float high_system_threshold_;
float low_system_threshold_;
diff --git a/chromium/third_party/libjingle/source/talk/media/base/videocapturer.cc b/chromium/third_party/libjingle/source/talk/media/base/videocapturer.cc
index 26fcfa9fbb4..59860a40ceb 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/videocapturer.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/videocapturer.cc
@@ -59,10 +59,16 @@ enum {
};
static const int64 kMaxDistance = ~(static_cast<int64>(1) << 63);
+#ifdef LINUX
static const int kYU12Penalty = 16; // Needs to be higher than MJPG index.
+#endif
static const int kDefaultScreencastFps = 5;
typedef talk_base::TypedMessageData<CaptureState> StateChangeParams;
+// Limit stats data collections to ~20 seconds of 30fps data before dropping
+// old data in case stats aren't reset for long periods of time.
+static const size_t kMaxAccumulatorSize = 600;
+
} // namespace
/////////////////////////////////////////////////////////////////////
@@ -92,11 +98,19 @@ bool CapturedFrame::GetDataSize(uint32* size) const {
/////////////////////////////////////////////////////////////////////
// Implementation of class VideoCapturer
/////////////////////////////////////////////////////////////////////
-VideoCapturer::VideoCapturer() : thread_(talk_base::Thread::Current()) {
+VideoCapturer::VideoCapturer()
+ : thread_(talk_base::Thread::Current()),
+ adapt_frame_drops_data_(kMaxAccumulatorSize),
+ effect_frame_drops_data_(kMaxAccumulatorSize),
+ frame_time_data_(kMaxAccumulatorSize) {
Construct();
}
-VideoCapturer::VideoCapturer(talk_base::Thread* thread) : thread_(thread) {
+VideoCapturer::VideoCapturer(talk_base::Thread* thread)
+ : thread_(thread),
+ adapt_frame_drops_data_(kMaxAccumulatorSize),
+ effect_frame_drops_data_(kMaxAccumulatorSize),
+ frame_time_data_(kMaxAccumulatorSize) {
Construct();
}
@@ -111,6 +125,10 @@ void VideoCapturer::Construct() {
screencast_max_pixels_ = 0;
muted_ = false;
black_frame_count_down_ = kNumBlackFramesOnMute;
+ enable_video_adapter_ = true;
+ adapt_frame_drops_ = 0;
+ effect_frame_drops_ = 0;
+ previous_frame_time_ = 0.0;
}
const std::vector<VideoFormat>* VideoCapturer::GetSupportedFormats() const {
@@ -118,6 +136,7 @@ const std::vector<VideoFormat>* VideoCapturer::GetSupportedFormats() const {
}
bool VideoCapturer::StartCapturing(const VideoFormat& capture_format) {
+ previous_frame_time_ = frame_length_time_reporter_.TimerNow();
CaptureState result = Start(capture_format);
const bool success = (result == CS_RUNNING) || (result == CS_STARTING);
if (!success) {
@@ -257,7 +276,7 @@ bool VideoCapturer::GetBestCaptureFormat(const VideoFormat& format,
best_format->width = best->width;
best_format->height = best->height;
best_format->fourcc = best->fourcc;
- best_format->interval = talk_base::_max(format.interval, best->interval);
+ best_format->interval = best->interval;
LOG(LS_INFO) << " Best " << best_format->ToString() << " Interval "
<< best_format->interval << " distance " << best_distance;
}
@@ -301,10 +320,25 @@ std::string VideoCapturer::ToString(const CapturedFrame* captured_frame) const {
std::ostringstream ss;
ss << fourcc_name << captured_frame->width << "x" << captured_frame->height
- << "x" << VideoFormat::IntervalToFps(captured_frame->elapsed_time);
+ << "x" << VideoFormat::IntervalToFpsFloat(captured_frame->elapsed_time);
return ss.str();
}
+void VideoCapturer::GetStats(VariableInfo<int>* adapt_drops_stats,
+ VariableInfo<int>* effect_drops_stats,
+ VariableInfo<double>* frame_time_stats,
+ VideoFormat* last_captured_frame_format) {
+ talk_base::CritScope cs(&frame_stats_crit_);
+ GetVariableSnapshot(adapt_frame_drops_data_, adapt_drops_stats);
+ GetVariableSnapshot(effect_frame_drops_data_, effect_drops_stats);
+ GetVariableSnapshot(frame_time_data_, frame_time_stats);
+ *last_captured_frame_format = last_captured_frame_format_;
+
+ adapt_frame_drops_data_.Reset();
+ effect_frame_drops_data_.Reset();
+ frame_time_data_.Reset();
+}
+
void VideoCapturer::OnFrameCaptured(VideoCapturer*,
const CapturedFrame* captured_frame) {
if (muted_) {
@@ -477,23 +511,29 @@ void VideoCapturer::OnFrameCaptured(VideoCapturer*,
}
VideoFrame* adapted_frame = &i420_frame;
- if (!SignalAdaptFrame.is_empty() && !IsScreencast()) {
+ if (enable_video_adapter_ && !IsScreencast()) {
VideoFrame* out_frame = NULL;
- SignalAdaptFrame(this, adapted_frame, &out_frame);
+ video_adapter_.AdaptFrame(adapted_frame, &out_frame);
if (!out_frame) {
- return; // VideoAdapter dropped the frame.
+ // VideoAdapter dropped the frame.
+ ++adapt_frame_drops_;
+ return;
}
adapted_frame = out_frame;
}
if (!muted_ && !ApplyProcessors(adapted_frame)) {
// Processor dropped the frame.
+ ++effect_frame_drops_;
return;
}
if (muted_) {
adapted_frame->SetToBlack();
}
SignalVideoFrame(this, adapted_frame);
+
+ UpdateStats(captured_frame);
+
#endif // VIDEO_FRAME_NAME
}
@@ -577,9 +617,9 @@ int64 VideoCapturer::GetFormatDistance(const VideoFormat& desired,
int desired_width = desired.width;
int desired_height = desired.height;
int64 delta_w = supported.width - desired_width;
- int64 supported_fps = VideoFormat::IntervalToFps(supported.interval);
- int64 delta_fps =
- supported_fps - VideoFormat::IntervalToFps(desired.interval);
+ float supported_fps = VideoFormat::IntervalToFpsFloat(supported.interval);
+ float delta_fps =
+ supported_fps - VideoFormat::IntervalToFpsFloat(desired.interval);
// Check height of supported height compared to height we would like it to be.
int64 aspect_h =
desired_width ? supported.width * desired_height / desired_width
@@ -606,9 +646,9 @@ int64 VideoCapturer::GetFormatDistance(const VideoFormat& desired,
// Require camera fps to be at least 96% of what is requested, or higher,
// if resolution differs. 96% allows for slight variations in fps. e.g. 29.97
if (delta_fps < 0) {
- int64 min_desirable_fps = delta_w ?
- VideoFormat::IntervalToFps(desired.interval) * 29 / 30 :
- VideoFormat::IntervalToFps(desired.interval) * 24 / 30;
+ float min_desirable_fps = delta_w ?
+ VideoFormat::IntervalToFpsFloat(desired.interval) * 28.f / 30.f :
+ VideoFormat::IntervalToFpsFloat(desired.interval) * 23.f / 30.f;
delta_fps = -delta_fps;
if (supported_fps < min_desirable_fps) {
distance |= static_cast<int64>(1) << 62;
@@ -616,10 +656,11 @@ int64 VideoCapturer::GetFormatDistance(const VideoFormat& desired,
distance |= static_cast<int64>(1) << 15;
}
}
+ int64 idelta_fps = static_cast<int>(delta_fps);
// 12 bits for width and height and 8 bits for fps and fourcc.
distance |=
- (delta_w << 28) | (delta_h << 16) | (delta_fps << 8) | delta_fourcc;
+ (delta_w << 28) | (delta_h << 16) | (idelta_fps << 8) | delta_fourcc;
return distance;
}
@@ -667,4 +708,35 @@ bool VideoCapturer::ShouldFilterFormat(const VideoFormat& format) const {
format.height > max_format_->height;
}
+void VideoCapturer::UpdateStats(const CapturedFrame* captured_frame) {
+ // Update stats protected from fetches from different thread.
+ talk_base::CritScope cs(&frame_stats_crit_);
+
+ last_captured_frame_format_.width = captured_frame->width;
+ last_captured_frame_format_.height = captured_frame->height;
+ // TODO(ronghuawu): Useful to report interval as well?
+ last_captured_frame_format_.interval = 0;
+ last_captured_frame_format_.fourcc = captured_frame->fourcc;
+
+ double time_now = frame_length_time_reporter_.TimerNow();
+ if (previous_frame_time_ != 0.0) {
+ adapt_frame_drops_data_.AddSample(adapt_frame_drops_);
+ effect_frame_drops_data_.AddSample(effect_frame_drops_);
+ frame_time_data_.AddSample(time_now - previous_frame_time_);
+ }
+ previous_frame_time_ = time_now;
+ effect_frame_drops_ = 0;
+ adapt_frame_drops_ = 0;
+}
+
+template<class T>
+void VideoCapturer::GetVariableSnapshot(
+ const talk_base::RollingAccumulator<T>& data,
+ VariableInfo<T>* stats) {
+ stats->max_val = data.ComputeMax();
+ stats->mean = data.ComputeMean();
+ stats->min_val = data.ComputeMin();
+ stats->variance = data.ComputeVariance();
+}
+
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/media/base/videocapturer.h b/chromium/third_party/libjingle/source/talk/media/base/videocapturer.h
index 2bd68bca162..6b1c46ddd35 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/videocapturer.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/videocapturer.h
@@ -34,9 +34,13 @@
#include "talk/base/basictypes.h"
#include "talk/base/criticalsection.h"
#include "talk/base/messagehandler.h"
+#include "talk/base/rollingaccumulator.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/sigslot.h"
#include "talk/base/thread.h"
+#include "talk/base/timing.h"
+#include "talk/media/base/mediachannel.h"
+#include "talk/media/base/videoadapter.h"
#include "talk/media/base/videocommon.h"
#include "talk/media/devices/devicemanager.h"
@@ -97,12 +101,10 @@ struct CapturedFrame {
// capturing. The subclasses implement the video capturer for various types of
// capturers and various platforms.
//
-// The captured frames may need to be adapted (for example, cropping). Adaptors
-// can be registered to the capturer or applied externally to the capturer.
-// If the adaptor is needed, it acts as the downstream of VideoCapturer, adapts
-// the captured frames, and delivers the adapted frames to other components
-// such as the encoder. Effects can also be registered to the capturer or
-// applied externally.
+// The captured frames may need to be adapted (for example, cropping).
+// Video adaptation is built into and enabled by default. After a frame has
+// been captured from the device, it is sent to the video adapter, then video
+// processors, then out to the encoder.
//
// Programming model:
// Create an object of a subclass of VideoCapturer
@@ -111,6 +113,7 @@ struct CapturedFrame {
// SignalFrameCaptured.connect()
// Find the capture format for Start() by either calling GetSupportedFormats()
// and selecting one of the supported or calling GetBestCaptureFormat().
+// video_adapter()->OnOutputFormatRequest(desired_encoding_format)
// Start()
// GetCaptureFormat() optionally
// Stop()
@@ -255,12 +258,8 @@ class VideoCapturer
// Signal the captured frame to downstream.
sigslot::signal2<VideoCapturer*, const CapturedFrame*,
sigslot::multi_threaded_local> SignalFrameCaptured;
- // If slots are connected to SignalAdaptFrame, this signals with parameters
- // of this capturer instance, the input video frame and output frame
- // pointer, respectively.
- sigslot::signal3<VideoCapturer*, const VideoFrame*, VideoFrame**,
- sigslot::multi_threaded_local> SignalAdaptFrame;
- // Signal the captured frame converted to I420 to downstream.
+ // Signal the captured and possibly adapted frame to downstream consumers
+ // such as the encoder.
sigslot::signal2<VideoCapturer*, const VideoFrame*,
sigslot::multi_threaded_local> SignalVideoFrame;
@@ -277,6 +276,27 @@ class VideoCapturer
screencast_max_pixels_ = talk_base::_max(0, p);
}
+ // If true, run video adaptation. By default, video adaptation is enabled
+ // and users must call video_adapter()->OnOutputFormatRequest()
+ // to receive frames.
+ bool enable_video_adapter() const { return enable_video_adapter_; }
+ void set_enable_video_adapter(bool enable_video_adapter) {
+ enable_video_adapter_ = enable_video_adapter;
+ }
+
+ CoordinatedVideoAdapter* video_adapter() { return &video_adapter_; }
+ const CoordinatedVideoAdapter* video_adapter() const {
+ return &video_adapter_;
+ }
+
+ // Gets statistics for tracked variables recorded since the last call to
+ // GetStats. Note that calling GetStats resets any gathered data so it
+ // should be called only periodically to log statistics.
+ void GetStats(VariableInfo<int>* adapt_drop_stats,
+ VariableInfo<int>* effect_drop_stats,
+ VariableInfo<double>* frame_time_stats,
+ VideoFormat* last_captured_frame_format);
+
protected:
// Callback attached to SignalFrameCaptured where SignalVideoFrames is called.
void OnFrameCaptured(VideoCapturer* video_capturer,
@@ -297,6 +317,12 @@ class VideoCapturer
void SetCaptureFormat(const VideoFormat* format) {
capture_format_.reset(format ? new VideoFormat(*format) : NULL);
+ if (capture_format_) {
+ ASSERT(capture_format_->interval > 0 &&
+ "Capture format expected to have positive interval.");
+ // Video adapter really only cares about capture format interval.
+ video_adapter_.SetInputFormat(*capture_format_);
+ }
}
void SetSupportedFormats(const std::vector<VideoFormat>& formats);
@@ -323,6 +349,15 @@ class VideoCapturer
// Returns true if format doesn't fulfill all applied restrictions.
bool ShouldFilterFormat(const VideoFormat& format) const;
+ void UpdateStats(const CapturedFrame* captured_frame);
+
+ // Helper function to save statistics on the current data from a
+ // RollingAccumulator into stats.
+ template<class T>
+ static void GetVariableSnapshot(
+ const talk_base::RollingAccumulator<T>& data,
+ VariableInfo<T>* stats);
+
talk_base::Thread* thread_;
std::string id_;
CaptureState capture_state_;
@@ -341,6 +376,21 @@ class VideoCapturer
bool muted_;
int black_frame_count_down_;
+ bool enable_video_adapter_;
+ CoordinatedVideoAdapter video_adapter_;
+
+ talk_base::Timing frame_length_time_reporter_;
+ talk_base::CriticalSection frame_stats_crit_;
+
+ int adapt_frame_drops_;
+ talk_base::RollingAccumulator<int> adapt_frame_drops_data_;
+ int effect_frame_drops_;
+ talk_base::RollingAccumulator<int> effect_frame_drops_data_;
+ double previous_frame_time_;
+ talk_base::RollingAccumulator<double> frame_time_data_;
+ // The captured frame format before potential adapation.
+ VideoFormat last_captured_frame_format_;
+
talk_base::CriticalSection crit_;
VideoProcessors video_processors_;
diff --git a/chromium/third_party/libjingle/source/talk/media/base/videocapturer_unittest.cc b/chromium/third_party/libjingle/source/talk/media/base/videocapturer_unittest.cc
index 82a95fb637d..9f025e37bb8 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/videocapturer_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/videocapturer_unittest.cc
@@ -31,6 +31,12 @@ const int kMsCallbackWait = 500;
const int kMinHdHeight = 720;
const uint32 kTimeout = 5000U;
+void NormalizeVideoSize(int* expected_width, int* expected_height) {
+ // WebRtcVideoFrame truncates the frame size to a multiple of 4.
+ *expected_width = *expected_width & ~3;
+ *expected_height = *expected_height & ~3;
+}
+
} // namespace
// Sets the elapsed time in the video frame to 0.
@@ -94,6 +100,7 @@ class VideoCapturerTest
};
TEST_F(VideoCapturerTest, CaptureState) {
+ EXPECT_TRUE(capturer_.enable_video_adapter());
EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
640,
480,
@@ -227,6 +234,59 @@ TEST_F(VideoCapturerTest, ScreencastScaledMaxPixels) {
EXPECT_EQ(2, renderer_.num_rendered_frames());
}
+TEST_F(VideoCapturerTest, ScreencastScaledOddWidth) {
+ capturer_.SetScreencast(true);
+
+ int kWidth = 1281;
+ int kHeight = 720;
+
+ std::vector<cricket::VideoFormat> formats;
+ formats.push_back(cricket::VideoFormat(kWidth, kHeight,
+ cricket::VideoFormat::FpsToInterval(5), cricket::FOURCC_ARGB));
+ capturer_.ResetSupportedFormats(formats);
+
+ EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
+ kWidth,
+ kHeight,
+ cricket::VideoFormat::FpsToInterval(30),
+ cricket::FOURCC_ARGB)));
+ EXPECT_TRUE(capturer_.IsRunning());
+ EXPECT_EQ(0, renderer_.num_rendered_frames());
+ int expected_width = kWidth;
+ int expected_height = kHeight;
+ NormalizeVideoSize(&expected_width, &expected_height);
+ renderer_.SetSize(expected_width, expected_height, 0);
+ EXPECT_TRUE(capturer_.CaptureFrame());
+ EXPECT_EQ(1, renderer_.num_rendered_frames());
+}
+
+TEST_F(VideoCapturerTest, ScreencastScaledSuperLarge) {
+ capturer_.SetScreencast(true);
+
+ const int kMaxWidth = 4096;
+ const int kMaxHeight = 3072;
+ int kWidth = kMaxWidth + 4;
+ int kHeight = kMaxHeight + 4;
+
+ std::vector<cricket::VideoFormat> formats;
+ formats.push_back(cricket::VideoFormat(kWidth, kHeight,
+ cricket::VideoFormat::FpsToInterval(5), cricket::FOURCC_ARGB));
+ capturer_.ResetSupportedFormats(formats);
+
+ EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
+ kWidth,
+ kHeight,
+ cricket::VideoFormat::FpsToInterval(30),
+ cricket::FOURCC_ARGB)));
+ EXPECT_TRUE(capturer_.IsRunning());
+ EXPECT_EQ(0, renderer_.num_rendered_frames());
+ int expected_width = 2050;
+ int expected_height = 1538;
+ NormalizeVideoSize(&expected_width, &expected_height);
+ renderer_.SetSize(expected_width, expected_height, 0);
+ EXPECT_TRUE(capturer_.CaptureFrame());
+ EXPECT_EQ(1, renderer_.num_rendered_frames());
+}
TEST_F(VideoCapturerTest, TestFourccMatch) {
cricket::VideoFormat desired(640, 480,
@@ -507,23 +567,23 @@ TEST_F(VideoCapturerTest, TestFpsFormats) {
cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_ANY));
cricket::VideoFormat best;
- // expect 30 fps to choose 30 fps format
+ // Expect 30 fps to choose 30 fps format.
EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[0], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(400, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
- // expect 20 fps to choose 20 fps format
+ // Expect 20 fps to choose 30 fps format.
EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[1], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(400, best.height);
- EXPECT_EQ(cricket::VideoFormat::FpsToInterval(20), best.interval);
+ EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
- // expect 10 fps to choose 15 fps format but set fps to 10
+ // Expect 10 fps to choose 15 fps format and set fps to 15.
EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[2], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
- EXPECT_EQ(cricket::VideoFormat::FpsToInterval(10), best.interval);
+ EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);
// We have VGA 60 fps and 15 fps. Choose best fps.
supported_formats.clear();
@@ -539,23 +599,23 @@ TEST_F(VideoCapturerTest, TestFpsFormats) {
cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
capturer_.ResetSupportedFormats(supported_formats);
- // expect 30 fps to choose 60 fps format, but will set best fps to 30
+ // Expect 30 fps to choose 60 fps format and will set best fps to 60.
EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[0], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
- EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
+ EXPECT_EQ(cricket::VideoFormat::FpsToInterval(60), best.interval);
- // expect 20 fps to choose 60 fps format, but will set best fps to 20
+ // Expect 20 fps to choose 60 fps format, and will set best fps to 60.
EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[1], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
- EXPECT_EQ(cricket::VideoFormat::FpsToInterval(20), best.interval);
+ EXPECT_EQ(cricket::VideoFormat::FpsToInterval(60), best.interval);
- // expect 10 fps to choose 10 fps
+ // Expect 10 fps to choose 15 fps.
EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[2], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
- EXPECT_EQ(cricket::VideoFormat::FpsToInterval(10), best.interval);
+ EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);
}
TEST_F(VideoCapturerTest, TestRequest16x10_9) {
diff --git a/chromium/third_party/libjingle/source/talk/media/base/videocommon.cc b/chromium/third_party/libjingle/source/talk/media/base/videocommon.cc
index b051d526a3c..12d0ee71015 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/videocommon.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/videocommon.cc
@@ -236,7 +236,8 @@ std::string VideoFormat::ToString() const {
}
std::ostringstream ss;
- ss << fourcc_name << width << "x" << height << "x" << IntervalToFps(interval);
+ ss << fourcc_name << width << "x" << height << "x"
+ << IntervalToFpsFloat(interval);
return ss.str();
}
diff --git a/chromium/third_party/libjingle/source/talk/media/base/videocommon.h b/chromium/third_party/libjingle/source/talk/media/base/videocommon.h
index cf24f6fbb39..c83a3d8d13a 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/videocommon.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/videocommon.h
@@ -212,11 +212,20 @@ struct VideoFormat : VideoFormatPod {
}
static int IntervalToFps(int64 interval) {
- // Normalize the interval first.
- interval = talk_base::_max(interval, kMinimumInterval);
+ if (!interval) {
+ return 0;
+ }
return static_cast<int>(talk_base::kNumNanosecsPerSec / interval);
}
+ static float IntervalToFpsFloat(int64 interval) {
+ if (!interval) {
+ return 0.f;
+ }
+ return static_cast<float>(talk_base::kNumNanosecsPerSec) /
+ static_cast<float>(interval);
+ }
+
bool operator==(const VideoFormat& format) const {
return width == format.width && height == format.height &&
interval == format.interval && fourcc == format.fourcc;
diff --git a/chromium/third_party/libjingle/source/talk/media/base/videocommon_unittest.cc b/chromium/third_party/libjingle/source/talk/media/base/videocommon_unittest.cc
index 455a47b79a0..90bcd0aeceb 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/videocommon_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/videocommon_unittest.cc
@@ -57,6 +57,7 @@ TEST(VideoCommonTest, TestVideoFormatFps) {
EXPECT_EQ(VideoFormat::kMinimumInterval, VideoFormat::FpsToInterval(0));
EXPECT_EQ(talk_base::kNumNanosecsPerSec / 20, VideoFormat::FpsToInterval(20));
EXPECT_EQ(20, VideoFormat::IntervalToFps(talk_base::kNumNanosecsPerSec / 20));
+ EXPECT_EQ(0, VideoFormat::IntervalToFps(0));
}
// Test IsSize0x0
@@ -70,7 +71,7 @@ TEST(VideoCommonTest, TestVideoFormatIsSize0x0) {
// Test ToString: print fourcc when it is printable.
TEST(VideoCommonTest, TestVideoFormatToString) {
VideoFormat format;
- EXPECT_EQ("0x0x10000", format.ToString());
+ EXPECT_EQ("0x0x0", format.ToString());
format.fourcc = FOURCC_I420;
format.width = 640;
diff --git a/chromium/third_party/libjingle/source/talk/media/base/videoengine_unittest.h b/chromium/third_party/libjingle/source/talk/media/base/videoengine_unittest.h
index d9266f2c4b4..382fb775e85 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/videoengine_unittest.h
+++ b/chromium/third_party/libjingle/source/talk/media/base/videoengine_unittest.h
@@ -474,17 +474,29 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(format));
EXPECT_TRUE(channel_->SetCapturer(kSsrc, video_capturer_.get()));
}
+ // Utility method to setup an additional stream to send and receive video.
+ // Used to test send and recv between two streams.
void SetUpSecondStream() {
- EXPECT_TRUE(channel_->AddRecvStream(
- cricket::StreamParams::CreateLegacy(kSsrc)));
+ SetUpSecondStreamWithNoRecv();
+ // Setup recv for second stream.
EXPECT_TRUE(channel_->AddRecvStream(
cricket::StreamParams::CreateLegacy(kSsrc + 2)));
+ // Make the second renderer available for use by a new stream.
+ EXPECT_TRUE(channel_->SetRenderer(kSsrc + 2, &renderer2_));
+ }
+ // Setup an additional stream just to send video. Defer add recv stream.
+ // This is required if you want to test unsignalled recv of video rtp packets.
+ void SetUpSecondStreamWithNoRecv() {
// SetUp() already added kSsrc make sure duplicate SSRCs cant be added.
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc)));
EXPECT_FALSE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrc)));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrc + 2)));
+ // We dont add recv for the second stream.
+ // Setup the receive and renderer for second stream after send.
video_capturer_2_.reset(new cricket::FakeVideoCapturer());
cricket::VideoFormat format(640, 480,
cricket::VideoFormat::FpsToInterval(30),
@@ -492,8 +504,6 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_2_->Start(format));
EXPECT_TRUE(channel_->SetCapturer(kSsrc + 2, video_capturer_2_.get()));
- // Make the second renderer available for use by a new stream.
- EXPECT_TRUE(channel_->SetRenderer(kSsrc + 2, &renderer2_));
}
virtual void TearDown() {
channel_.reset();
@@ -524,7 +534,6 @@ class VideoMediaChannelTest : public testing::Test,
if (video_capturer_) {
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(capture_format));
}
-
if (video_capturer_2_) {
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_2_->Start(capture_format));
}
@@ -540,6 +549,12 @@ class VideoMediaChannelTest : public testing::Test,
bool SetSend(bool send) {
return channel_->SetSend(send);
}
+ bool SetSendStreamFormat(uint32 ssrc, const cricket::VideoCodec& codec) {
+ return channel_->SetSendStreamFormat(ssrc, cricket::VideoFormat(
+ codec.width, codec.height,
+ cricket::VideoFormat::FpsToInterval(codec.framerate),
+ cricket::FOURCC_ANY));
+ }
int DrainOutgoingPackets() {
int packets = 0;
do {
@@ -777,21 +792,53 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_FRAME_WAIT(3, codec.width, codec.height, kTimeout);
EXPECT_EQ(2, renderer_.num_set_sizes());
}
+ void SendReceiveManyAndGetStats(const cricket::VideoCodec& codec,
+ int duration_sec, int fps) {
+ EXPECT_TRUE(SetOneCodec(codec));
+ EXPECT_TRUE(SetSend(true));
+ EXPECT_TRUE(channel_->SetRender(true));
+ EXPECT_EQ(0, renderer_.num_rendered_frames());
+ for (int i = 0; i < duration_sec; ++i) {
+ for (int frame = 1; frame <= fps; ++frame) {
+ EXPECT_TRUE(WaitAndSendFrame(1000 / fps));
+ EXPECT_FRAME_WAIT(frame + i * fps, codec.width, codec.height, kTimeout);
+ }
+ cricket::VideoMediaInfo info;
+ EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
+ // For webrtc, |framerate_sent| and |framerate_rcvd| depend on periodic
+ // callbacks (1 sec).
+ // Received |fraction_lost| and |packets_lost| are from sent RTCP packet.
+ // One sent packet needed (sent about once per second).
+ // |framerate_input|, |framerate_decoded| and |framerate_output| are using
+ // RateTracker. RateTracker needs to be called twice (with >1 second in
+ // b/w calls) before a framerate is calculated.
+ // Therefore insert frames (and call GetStats each sec) for a few seconds
+ // before testing stats.
+ }
+ talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtpPacket(0));
+ EXPECT_EQ(codec.id, GetPayloadType(p.get()));
+ }
+
// Test that stats work properly for a 1-1 call.
void GetStats() {
- SendAndReceive(DefaultCodec());
+ const int kDurationSec = 3;
+ const int kFps = 10;
+ SendReceiveManyAndGetStats(DefaultCodec(), kDurationSec, kFps);
+
cricket::VideoMediaInfo info;
- EXPECT_TRUE(channel_->GetStats(&info));
+ EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.senders.size());
// TODO(whyuan): bytes_sent and bytes_rcvd are different. Are both payload?
+ // For webrtc, bytes_sent does not include the RTP header length.
EXPECT_GT(info.senders[0].bytes_sent, 0);
EXPECT_EQ(NumRtpPackets(), info.senders[0].packets_sent);
EXPECT_EQ(0.0, info.senders[0].fraction_lost);
EXPECT_EQ(0, info.senders[0].firs_rcvd);
+ EXPECT_EQ(0, info.senders[0].plis_rcvd);
EXPECT_EQ(0, info.senders[0].nacks_rcvd);
- EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
- EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
+ EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
+ EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
EXPECT_GT(info.senders[0].framerate_input, 0);
EXPECT_GT(info.senders[0].framerate_sent, 0);
@@ -803,8 +850,10 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_EQ(NumRtpPackets(), info.receivers[0].packets_rcvd);
EXPECT_EQ(0.0, info.receivers[0].fraction_lost);
EXPECT_EQ(0, info.receivers[0].packets_lost);
- EXPECT_EQ(0, info.receivers[0].packets_concealed);
+ // TODO(asapersson): Not set for webrtc. Handle missing stats.
+ // EXPECT_EQ(0, info.receivers[0].packets_concealed);
EXPECT_EQ(0, info.receivers[0].firs_sent);
+ EXPECT_EQ(0, info.receivers[0].plis_sent);
EXPECT_EQ(0, info.receivers[0].nacks_sent);
EXPECT_EQ(DefaultCodec().width, info.receivers[0].frame_width);
EXPECT_EQ(DefaultCodec().height, info.receivers[0].frame_height);
@@ -839,19 +888,15 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_FRAME_ON_RENDERER_WAIT(
renderer2, 1, DefaultCodec().width, DefaultCodec().height, kTimeout);
cricket::VideoMediaInfo info;
- EXPECT_TRUE(channel_->GetStats(&info));
+ EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.senders.size());
// TODO(whyuan): bytes_sent and bytes_rcvd are different. Are both payload?
+ // For webrtc, bytes_sent does not include the RTP header length.
EXPECT_GT(info.senders[0].bytes_sent, 0);
EXPECT_EQ(NumRtpPackets(), info.senders[0].packets_sent);
- EXPECT_EQ(0.0, info.senders[0].fraction_lost);
- EXPECT_EQ(0, info.senders[0].firs_rcvd);
- EXPECT_EQ(0, info.senders[0].nacks_rcvd);
- EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
- EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
- EXPECT_GT(info.senders[0].framerate_input, 0);
- EXPECT_GT(info.senders[0].framerate_sent, 0);
+ EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
+ EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
ASSERT_EQ(2U, info.receivers.size());
for (size_t i = 0; i < info.receivers.size(); ++i) {
@@ -859,16 +904,8 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_EQ(i + 1, info.receivers[i].ssrcs()[0]);
EXPECT_EQ(NumRtpBytes(), info.receivers[i].bytes_rcvd);
EXPECT_EQ(NumRtpPackets(), info.receivers[i].packets_rcvd);
- EXPECT_EQ(0.0, info.receivers[i].fraction_lost);
- EXPECT_EQ(0, info.receivers[i].packets_lost);
- EXPECT_EQ(0, info.receivers[i].packets_concealed);
- EXPECT_EQ(0, info.receivers[i].firs_sent);
- EXPECT_EQ(0, info.receivers[i].nacks_sent);
EXPECT_EQ(DefaultCodec().width, info.receivers[i].frame_width);
EXPECT_EQ(DefaultCodec().height, info.receivers[i].frame_height);
- EXPECT_GT(info.receivers[i].framerate_rcvd, 0);
- EXPECT_GT(info.receivers[i].framerate_decoded, 0);
- EXPECT_GT(info.receivers[i].framerate_output, 0);
}
}
// Test that stats work properly for a conf call with multiple send streams.
@@ -893,8 +930,11 @@ class VideoMediaChannelTest : public testing::Test,
talk_base::scoped_ptr<cricket::FakeVideoCapturer> capturer(
new cricket::FakeVideoCapturer);
capturer->SetScreencast(true);
- cricket::VideoFormat format(1024, 768,
- cricket::VideoFormat::FpsToInterval(5), 0);
+ const int kTestWidth = 160;
+ const int kTestHeight = 120;
+ cricket::VideoFormat format(kTestWidth, kTestHeight,
+ cricket::VideoFormat::FpsToInterval(5),
+ cricket::FOURCC_I420);
EXPECT_EQ(cricket::CS_RUNNING, capturer->Start(format));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(5678)));
@@ -902,37 +942,39 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_TRUE(channel_->AddRecvStream(
cricket::StreamParams::CreateLegacy(5678)));
EXPECT_TRUE(channel_->SetRenderer(5678, &renderer1));
- EXPECT_TRUE(capturer->CaptureCustomFrame(1024, 768, cricket::FOURCC_I420));
- EXPECT_FRAME_ON_RENDERER_WAIT(renderer1, 1, 1024, 768, kTimeout);
+ EXPECT_TRUE(capturer->CaptureCustomFrame(
+ kTestWidth, kTestHeight, cricket::FOURCC_I420));
+ EXPECT_FRAME_ON_RENDERER_WAIT(
+ renderer1, 1, kTestWidth, kTestHeight, kTimeout);
// Get stats, and make sure they are correct for two senders.
cricket::VideoMediaInfo info;
- EXPECT_TRUE(channel_->GetStats(&info));
+ EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(2U, info.senders.size());
EXPECT_EQ(NumRtpPackets(),
info.senders[0].packets_sent + info.senders[1].packets_sent);
EXPECT_EQ(1U, info.senders[0].ssrcs().size());
EXPECT_EQ(1234U, info.senders[0].ssrcs()[0]);
- EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
- EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
+ EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
+ EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
EXPECT_EQ(1U, info.senders[1].ssrcs().size());
EXPECT_EQ(5678U, info.senders[1].ssrcs()[0]);
- EXPECT_EQ(1024, info.senders[1].frame_width);
- EXPECT_EQ(768, info.senders[1].frame_height);
+ EXPECT_EQ(kTestWidth, info.senders[1].send_frame_width);
+ EXPECT_EQ(kTestHeight, info.senders[1].send_frame_height);
// The capturer must be unregistered here as it runs out of it's scope next.
EXPECT_TRUE(channel_->SetCapturer(5678, NULL));
}
- // Test that we can set the bandwidth to auto or a specific value.
+ // Test that we can set the bandwidth.
void SetSendBandwidth() {
- EXPECT_TRUE(channel_->SetSendBandwidth(true, -1));
- EXPECT_TRUE(channel_->SetSendBandwidth(true, 128 * 1024));
- EXPECT_TRUE(channel_->SetSendBandwidth(false, -1));
- EXPECT_TRUE(channel_->SetSendBandwidth(false, 128 * 1024));
+ EXPECT_TRUE(channel_->SetStartSendBandwidth(64 * 1024));
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(-1)); // <= 0 means unlimited.
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(128 * 1024));
}
// Test that we can set the SSRC for the default send source.
void SetSendSsrc() {
EXPECT_TRUE(SetDefaultCodec());
+ EXPECT_TRUE(SetSendStreamFormat(kSsrc, DefaultCodec()));
EXPECT_TRUE(SetSend(true));
EXPECT_TRUE(SendFrame());
EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout);
@@ -954,6 +996,7 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(999)));
EXPECT_TRUE(channel_->SetCapturer(999u, video_capturer_.get()));
+ EXPECT_TRUE(SetSendStreamFormat(999u, DefaultCodec()));
EXPECT_TRUE(SetSend(true));
EXPECT_TRUE(WaitAndSendFrame(0));
EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout);
@@ -1180,6 +1223,8 @@ class VideoMediaChannelTest : public testing::Test,
// some (e.g. 1) of these 3 frames after the renderer is set again.
EXPECT_GT_FRAME_ON_RENDERER_WAIT(
renderer1, 2, DefaultCodec().width, DefaultCodec().height, kTimeout);
+ // Detach |renderer1| before exit as there might be frames come late.
+ EXPECT_TRUE(channel_->SetRenderer(kSsrc, NULL));
}
// Tests the behavior of incoming streams in a conference scenario.
@@ -1221,9 +1266,11 @@ class VideoMediaChannelTest : public testing::Test,
// Tests that we can add and remove capturers and frames are sent out properly
void AddRemoveCapturer() {
- const cricket::VideoCodec codec(DefaultCodec());
+ cricket::VideoCodec codec = DefaultCodec();
+ codec.width = 320;
+ codec.height = 240;
const int time_between_send = TimeBetweenSend(codec);
- EXPECT_TRUE(SetDefaultCodec());
+ EXPECT_TRUE(SetOneCodec(codec));
EXPECT_TRUE(SetSend(true));
EXPECT_TRUE(channel_->SetRender(true));
EXPECT_EQ(0, renderer_.num_rendered_frames());
@@ -1232,8 +1279,9 @@ class VideoMediaChannelTest : public testing::Test,
talk_base::scoped_ptr<cricket::FakeVideoCapturer> capturer(
new cricket::FakeVideoCapturer);
capturer->SetScreencast(true);
- cricket::VideoFormat format(1024, 768,
- cricket::VideoFormat::FpsToInterval(30), 0);
+ cricket::VideoFormat format(480, 360,
+ cricket::VideoFormat::FpsToInterval(30),
+ cricket::FOURCC_I420);
EXPECT_EQ(cricket::CS_RUNNING, capturer->Start(format));
// All capturers start generating frames with the same timestamp. ViE does
// not allow the same timestamp to be used. Capture one frame before
@@ -1305,11 +1353,6 @@ class VideoMediaChannelTest : public testing::Test,
void AddRemoveCapturerMultipleSources() {
// WebRTC implementation will drop frames if pushed to quickly. Wait the
// interval time to avoid that.
- const cricket::VideoFormat send_format(
- 1024,
- 768,
- cricket::VideoFormat::FpsToInterval(30),
- 0);
// WebRTC implementation will drop frames if pushed to quickly. Wait the
// interval time to avoid that.
// Set up the stream associated with the engine.
@@ -1352,11 +1395,17 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_TRUE(SetSend(true));
EXPECT_TRUE(channel_->SetRender(true));
// Test capturer associated with engine.
- EXPECT_TRUE(capturer1->CaptureCustomFrame(1024, 768, cricket::FOURCC_I420));
- EXPECT_FRAME_ON_RENDERER_WAIT(renderer1, 1, 1024, 768, kTimeout);
+ const int kTestWidth = 160;
+ const int kTestHeight = 120;
+ EXPECT_TRUE(capturer1->CaptureCustomFrame(
+ kTestWidth, kTestHeight, cricket::FOURCC_I420));
+ EXPECT_FRAME_ON_RENDERER_WAIT(
+ renderer1, 1, kTestWidth, kTestHeight, kTimeout);
// Capture a frame with additional capturer2, frames should be received
- EXPECT_TRUE(capturer2->CaptureCustomFrame(1024, 768, cricket::FOURCC_I420));
- EXPECT_FRAME_ON_RENDERER_WAIT(renderer2, 1, 1024, 768, kTimeout);
+ EXPECT_TRUE(capturer2->CaptureCustomFrame(
+ kTestWidth, kTestHeight, cricket::FOURCC_I420));
+ EXPECT_FRAME_ON_RENDERER_WAIT(
+ renderer2, 1, kTestWidth, kTestHeight, kTimeout);
// Successfully remove the capturer.
EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL));
// Fail to re-remove the capturer.
@@ -1533,6 +1582,7 @@ class VideoMediaChannelTest : public testing::Test,
// frames being dropped.
void SetSendStreamFormat0x0() {
EXPECT_TRUE(SetOneCodec(DefaultCodec()));
+ EXPECT_TRUE(SetSendStreamFormat(kSsrc, DefaultCodec()));
EXPECT_TRUE(SetSend(true));
EXPECT_TRUE(channel_->SetRender(true));
EXPECT_EQ(0, renderer_.num_rendered_frames());
@@ -1635,33 +1685,156 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_EQ(1, renderer2_.num_rendered_frames());
}
- // Disconnect the first stream and re-use it with another SSRC
+ // Set up 2 streams where the first stream uses the default channel.
+ // Then disconnect the first stream and verify default channel becomes
+ // available.
+ // Then add a new stream with |new_ssrc|. The new stream should re-use the
+ // default channel.
void TwoStreamsReUseFirstStream(const cricket::VideoCodec& codec) {
SetUpSecondStream();
+ // Default channel used by the first stream.
+ EXPECT_EQ(kSsrc, channel_->GetDefaultChannelSsrc());
EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc));
EXPECT_FALSE(channel_->RemoveRecvStream(kSsrc));
- // SSRC 0 should map to the "default" stream. I.e. the first added stream.
- EXPECT_TRUE(channel_->RemoveSendStream(0));
- // Make sure that the first added stream was indeed the "default" stream.
+ EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
EXPECT_FALSE(channel_->RemoveSendStream(kSsrc));
- // Make sure that the "default" stream is indeed removed and that removing
- // the default stream has an effect.
- EXPECT_FALSE(channel_->RemoveSendStream(0));
-
+ // Default channel is no longer used by a stream.
+ EXPECT_EQ(0u, channel_->GetDefaultChannelSsrc());
SetRendererAsDefault();
+ uint32 new_ssrc = kSsrc + 100;
EXPECT_TRUE(channel_->AddSendStream(
- cricket::StreamParams::CreateLegacy(kSsrc)));
+ cricket::StreamParams::CreateLegacy(new_ssrc)));
+ // Re-use default channel.
+ EXPECT_EQ(new_ssrc, channel_->GetDefaultChannelSsrc());
EXPECT_FALSE(channel_->AddSendStream(
- cricket::StreamParams::CreateLegacy(kSsrc)));
+ cricket::StreamParams::CreateLegacy(new_ssrc)));
EXPECT_TRUE(channel_->AddRecvStream(
- cricket::StreamParams::CreateLegacy(kSsrc)));
+ cricket::StreamParams::CreateLegacy(new_ssrc)));
EXPECT_FALSE(channel_->AddRecvStream(
- cricket::StreamParams::CreateLegacy(kSsrc)));
+ cricket::StreamParams::CreateLegacy(new_ssrc)));
- EXPECT_TRUE(channel_->SetCapturer(kSsrc, video_capturer_.get()));
+ EXPECT_TRUE(channel_->SetCapturer(new_ssrc, video_capturer_.get()));
SendAndReceive(codec);
- EXPECT_TRUE(channel_->RemoveSendStream(0));
+ EXPECT_TRUE(channel_->RemoveSendStream(new_ssrc));
+ EXPECT_EQ(0u, channel_->GetDefaultChannelSsrc());
+ }
+
+ // Tests that we can send and receive frames with early receive.
+ void TwoStreamsSendAndUnsignalledRecv(const cricket::VideoCodec& codec) {
+ cricket::VideoOptions vmo;
+ vmo.conference_mode.Set(true);
+ vmo.unsignalled_recv_stream_limit.Set(1);
+ EXPECT_TRUE(channel_->SetOptions(vmo));
+ SetUpSecondStreamWithNoRecv();
+ // Test sending and receiving on first stream.
+ EXPECT_TRUE(channel_->SetRender(true));
+ Send(codec);
+ EXPECT_EQ_WAIT(2, NumRtpPackets(), kTimeout);
+ EXPECT_EQ_WAIT(1, renderer_.num_rendered_frames(), kTimeout);
+ // The first send is not expected to yield frames, because the ssrc
+ // is not signalled yet. With unsignalled recv enabled, we will drop frames
+ // instead of packets.
+ EXPECT_EQ(0, renderer2_.num_rendered_frames());
+ // Give a chance for the decoder to process before adding the receiver.
+ talk_base::Thread::Current()->ProcessMessages(100);
+ // Test sending and receiving on second stream.
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc + 2)));
+ EXPECT_TRUE(channel_->SetRenderer(kSsrc + 2, &renderer2_));
+ SendFrame();
+ EXPECT_EQ_WAIT(2, renderer_.num_rendered_frames(), kTimeout);
+ EXPECT_EQ(4, NumRtpPackets());
+ // The second send is expected to yield frame as the ssrc is signalled now.
+ // Decode should succeed here, though we received the key frame earlier.
+ // Without early recv, we would have dropped it and decoding would have
+ // failed.
+ EXPECT_EQ_WAIT(1, renderer2_.num_rendered_frames(), kTimeout);
+ }
+
+ // Tests that we cannot receive key frames with unsignalled recv disabled.
+ void TwoStreamsSendAndFailUnsignalledRecv(const cricket::VideoCodec& codec) {
+ cricket::VideoOptions vmo;
+ vmo.conference_mode.Set(true);
+ vmo.unsignalled_recv_stream_limit.Set(0);
+ EXPECT_TRUE(channel_->SetOptions(vmo));
+ SetUpSecondStreamWithNoRecv();
+ // Test sending and receiving on first stream.
+ EXPECT_TRUE(channel_->SetRender(true));
+ Send(codec);
+ EXPECT_EQ_WAIT(2, NumRtpPackets(), kTimeout);
+ talk_base::Thread::Current()->ProcessMessages(100);
+ EXPECT_EQ_WAIT(1, renderer_.num_rendered_frames(), kTimeout);
+ EXPECT_EQ_WAIT(0, renderer2_.num_rendered_frames(), kTimeout);
+ // Give a chance for the decoder to process before adding the receiver.
+ talk_base::Thread::Current()->ProcessMessages(10);
+ // Test sending and receiving on second stream.
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc + 2)));
+ EXPECT_TRUE(channel_->SetRenderer(kSsrc + 2, &renderer2_));
+ SendFrame();
+ EXPECT_TRUE_WAIT(renderer_.num_rendered_frames() >= 1, kTimeout);
+ EXPECT_EQ_WAIT(4, NumRtpPackets(), kTimeout);
+ // We dont expect any frames here, because the key frame would have been
+ // lost in the earlier packet. This is the case we want to solve with early
+ // receive.
+ EXPECT_EQ(0, renderer2_.num_rendered_frames());
+ }
+
+ // Tests that we drop key frames when conference mode is disabled and we
+ // receive rtp packets on unsignalled streams.
+ void TwoStreamsSendAndFailUnsignalledRecvInOneToOne(
+ const cricket::VideoCodec& codec) {
+ cricket::VideoOptions vmo;
+ vmo.conference_mode.Set(false);
+ vmo.unsignalled_recv_stream_limit.Set(1);
+ EXPECT_TRUE(channel_->SetOptions(vmo));
+ SetUpSecondStreamWithNoRecv();
+ // Test sending and receiving on first stream.
+ EXPECT_TRUE(channel_->SetRender(true));
+ Send(codec);
+ EXPECT_EQ_WAIT(2, NumRtpPackets(), kTimeout);
+ // In one-to-one mode, we deliver frames to the default channel if there
+ // is no registered recv channel for the ssrc.
+ EXPECT_TRUE_WAIT(renderer_.num_rendered_frames() >= 1, kTimeout);
+ // Give a chance for the decoder to process before adding the receiver.
+ talk_base::Thread::Current()->ProcessMessages(100);
+ // Test sending and receiving on second stream.
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc + 2)));
+ EXPECT_TRUE(channel_->SetRenderer(kSsrc + 2, &renderer2_));
+ SendFrame();
+ EXPECT_TRUE_WAIT(renderer_.num_rendered_frames() >= 1, kTimeout);
+ EXPECT_EQ_WAIT(4, NumRtpPackets(), kTimeout);
+ // We dont expect any frames here, because the key frame would have been
+ // delivered to default channel.
+ EXPECT_EQ(0, renderer2_.num_rendered_frames());
+ }
+
+ // Tests that we drop key frames when conference mode is enabled and we
+ // receive rtp packets on unsignalled streams. Removal of a unsignalled recv
+ // stream is successful.
+ void TwoStreamsAddAndRemoveUnsignalledRecv(
+ const cricket::VideoCodec& codec) {
+ cricket::VideoOptions vmo;
+ vmo.conference_mode.Set(true);
+ vmo.unsignalled_recv_stream_limit.Set(1);
+ EXPECT_TRUE(channel_->SetOptions(vmo));
+ SetUpSecondStreamWithNoRecv();
+ // Sending and receiving on first stream.
+ EXPECT_TRUE(channel_->SetRender(true));
+ Send(codec);
+ EXPECT_EQ_WAIT(2, NumRtpPackets(), kTimeout);
+ EXPECT_EQ_WAIT(1, renderer_.num_rendered_frames(), kTimeout);
+ // The first send is not expected to yield frames, because the ssrc
+ // is no signalled yet. With unsignalled recv enabled, we will drop frames
+ // instead of packets.
+ EXPECT_EQ(0, renderer2_.num_rendered_frames());
+ // Give a chance for the decoder to process before adding the receiver.
+ talk_base::Thread::Current()->ProcessMessages(100);
+ // Ensure that we can remove the unsignalled recv stream that was created
+ // when the first video packet with unsignalled recv ssrc is received.
+ EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc + 2));
}
VideoEngineOverride<E> engine_;
diff --git a/chromium/third_party/libjingle/source/talk/media/base/videoframe.cc b/chromium/third_party/libjingle/source/talk/media/base/videoframe.cc
index 7a82305f55f..cf5f852fc95 100644
--- a/chromium/third_party/libjingle/source/talk/media/base/videoframe.cc
+++ b/chromium/third_party/libjingle/source/talk/media/base/videoframe.cc
@@ -27,7 +27,7 @@
#include "talk/media/base/videoframe.h"
-#include <cstring>
+#include <string.h>
#if !defined(DISABLE_YUV)
#include "libyuv/compare.h"
diff --git a/chromium/third_party/libjingle/source/talk/media/base/yuvframegenerator.cc b/chromium/third_party/libjingle/source/talk/media/base/yuvframegenerator.cc
new file mode 100644
index 00000000000..57b5314361a
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/base/yuvframegenerator.cc
@@ -0,0 +1,262 @@
+#include "talk/media/base/yuvframegenerator.h"
+
+#include <string.h>
+#include <sstream>
+
+#include "talk/base/basictypes.h"
+#include "talk/base/common.h"
+
+namespace cricket {
+
+// These values were figured out by trial and error. If you change any
+// basic parameters e.g. unit-bar size or bars-x-offset, you may need to change
+// background-width/background-height.
+const int kBarcodeBackgroundWidth = 160;
+const int kBarcodeBackgroundHeight = 100;
+const int kBarsXOffset = 12;
+const int kBarsYOffset = 4;
+const int kUnitBarSize = 2;
+const int kBarcodeNormalBarHeight = 80;
+const int kBarcodeGuardBarHeight = 96;
+const int kBarcodeMaxEncodableDigits = 7;
+
+YuvFrameGenerator::YuvFrameGenerator(int width, int height,
+ bool enable_barcode) {
+ width_ = width;
+ height_ = height;
+ frame_index_ = 0;
+ int size = width_ * height_;
+ int qsize = size / 4;
+ frame_data_size_ = size + 2 * qsize;
+ y_data_ = new uint8[size];
+ u_data_ = new uint8[qsize];
+ v_data_ = new uint8[qsize];
+ if (enable_barcode) {
+ ASSERT(width_ >= kBarcodeBackgroundWidth);
+ ASSERT(height_>= kBarcodeBackgroundHeight);
+ barcode_start_x_ = 0;
+ barcode_start_y_ = height_ - kBarcodeBackgroundHeight;
+ } else {
+ barcode_start_x_ = -1;
+ barcode_start_y_ = -1;
+ }
+}
+
+YuvFrameGenerator::~YuvFrameGenerator() {
+ delete y_data_;
+ delete u_data_;
+ delete v_data_;
+}
+
+void YuvFrameGenerator::GenerateNextFrame(uint8* frame_buffer,
+ int32 barcode_value) {
+ int size = width_ * height_;
+ int qsize = size / 4;
+ memset(y_data_, 0, size);
+ memset(u_data_, 0, qsize);
+ memset(v_data_, 0, qsize);
+
+ DrawLandscape(y_data_, width_, height_);
+ DrawGradientX(u_data_, width_/2, height_/2);
+ DrawGradientY(v_data_, width_/2, height_/2);
+ DrawMovingLineX(u_data_, width_/2, height_/2, frame_index_);
+ DrawMovingLineY(v_data_, width_/2, height_/2, frame_index_);
+ DrawBouncingCube(y_data_, width_, height_, frame_index_);
+
+ if (barcode_value >= 0) {
+ ASSERT(barcode_start_x_ != -1);
+ DrawBarcode(barcode_value);
+ }
+
+ memcpy(frame_buffer, y_data_, size);
+ frame_buffer += size;
+ memcpy(frame_buffer, u_data_, qsize);
+ frame_buffer += qsize;
+ memcpy(frame_buffer, v_data_, qsize);
+
+ frame_index_ = (frame_index_ + 1) & 0x0000FFFF;
+}
+
+void YuvFrameGenerator::DrawLandscape(uint8 *p, int w, int h) {
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ p[x + y * w] = x % (y+1);
+ if (((x > w / 2 - (w / 32)) && (x < w / 2 + (w / 32))) ||
+ ((y > h / 2 - (h / 32)) && (y < h / 2 + (h / 32)))) {
+ p[x + y * w] = (((x + y) / 8 % 2)) ? 255 : 0;
+ }
+ }
+ }
+}
+
+void YuvFrameGenerator::DrawGradientX(uint8 *p, int w, int h) {
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ p[x + y * w] = (x << 8) / w;
+ }
+ }
+}
+
+void YuvFrameGenerator::DrawGradientY(uint8 *p, int w, int h) {
+ int x, y;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ p[x + y * w] = (y << 8) / h;
+ }
+ }
+}
+
+void YuvFrameGenerator::DrawMovingLineX(uint8 *p, int w, int h, int n) {
+ int x, y;
+ x = n % (w * 2);
+ if (x >= w) x = w + w - x - 1;
+ for (y = 0; y < h; y++) {
+ p[x + y * w] = 255;
+ }
+}
+
+void YuvFrameGenerator::DrawMovingLineY(uint8 *p, int w, int h, int n) {
+ int x, y;
+ y = n % (h * 2);
+ if (y >= h) y = h + h - y - 1;
+ for (x = 0; x < w; x++) {
+ p[x + y * w] = 255;
+ }
+}
+
+void YuvFrameGenerator::DrawBouncingCube(uint8 *p, int w, int h, int n) {
+ int x, y, pw, ph, px, py;
+ pw = w / 16;
+ ph = h / 16;
+ px = n % (w * 2);
+ py = n % (h * 2);
+ if (px >= w) px = w + w - px - 1;
+ if (py >= h) py = h + h - py - 1;
+ for (y = py - ph; y < py + ph; y++) {
+ if (y >=0 && y < h) {
+ for (x = px - pw; x < px + pw; x++) {
+ if (x >= 0 && x < w) {
+ p[x + y * w] = 255;
+ }
+ }
+ }
+ }
+}
+
+void YuvFrameGenerator::GetBarcodeBounds(int* top, int* left,
+ int* width, int* height) {
+ ASSERT(barcode_start_x_ != -1);
+ *top = barcode_start_y_;
+ *left = barcode_start_x_;
+ *width = kBarcodeBackgroundWidth;
+ *height = kBarcodeBackgroundHeight;
+}
+
+static void ComputeBarcodeDigits(uint32 value, std::stringstream* result) {
+ // Serialize |value| as 7-char string, padded with 0's to the left.
+ result->width(kBarcodeMaxEncodableDigits);
+ result->fill('0');
+ *result << value;
+
+ // Compute check-digit and append to result. Steps described here:
+ // http://en.wikipedia.org/wiki/European_Article_Number#Calculation_of_checksum_digit
+ int sum = 0;
+ for (int pos = 1; pos <= kBarcodeMaxEncodableDigits; pos++) {
+ char next_char;
+ result->get(next_char);
+ uint8 digit = next_char - '0';
+ sum += digit * (pos % 2 ? 3 : 1);
+ }
+ uint8 check_digit = sum % 10;
+ if (check_digit != 0) {
+ check_digit = 10 - check_digit;
+ }
+
+ *result << static_cast<int>(check_digit);
+ result->seekg(0);
+}
+
+void YuvFrameGenerator::DrawBarcode(uint32 value) {
+ std::stringstream value_str_stream;
+ ComputeBarcodeDigits(value, &value_str_stream);
+
+ // Draw white filled rectangle as background to barcode.
+ DrawBlockRectangle(y_data_, barcode_start_x_, barcode_start_y_,
+ kBarcodeBackgroundWidth, kBarcodeBackgroundHeight,
+ width_, 255);
+ DrawBlockRectangle(u_data_, barcode_start_x_ / 2, barcode_start_y_ / 2,
+ kBarcodeBackgroundWidth / 2, kBarcodeBackgroundHeight / 2,
+ width_ / 2, 128);
+ DrawBlockRectangle(v_data_, barcode_start_x_ / 2, barcode_start_y_ / 2,
+ kBarcodeBackgroundWidth / 2, kBarcodeBackgroundHeight / 2,
+ width_ / 2, 128);
+
+ // Scan through chars (digits) and draw black bars.
+ int x = barcode_start_x_ + kBarsXOffset;
+ int y = barcode_start_y_ + kBarsYOffset;
+ int pos = 0;
+ x = DrawSideGuardBars(x, y, kBarcodeGuardBarHeight);
+ while (true) {
+ char next_char;
+ value_str_stream.get(next_char);
+ if (!value_str_stream.good()) {
+ break;
+ }
+ if (pos++ == 4) {
+ x = DrawMiddleGuardBars(x, y, kBarcodeGuardBarHeight);
+ }
+ uint8 digit = next_char - '0';
+ x = DrawEanEncodedDigit(digit, x, y, kBarcodeNormalBarHeight, pos > 4);
+ }
+ x = DrawSideGuardBars(x, y, kBarcodeGuardBarHeight);
+}
+
+int YuvFrameGenerator::DrawMiddleGuardBars(int x, int y, int height) {
+ x += kUnitBarSize;
+ DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0);
+ x += (kUnitBarSize * 2);
+ DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0);
+ return x + (kUnitBarSize * 2);
+}
+
+int YuvFrameGenerator::DrawSideGuardBars(int x, int y, int height) {
+ DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0);
+ x += (kUnitBarSize * 2);
+ DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0);
+ return x + kUnitBarSize;
+}
+
+// For each digit: 0-9, |kEanEncodings| contains a bit-mask indicating
+// which bars are black (1) and which are blank (0). These are for the L-code
+// only. R-code values are bitwise negation of these. Reference:
+// http://en.wikipedia.org/wiki/European_Article_Number#Binary_encoding_of_data_digits_into_EAN-13_barcode // NOLINT
+const uint8 kEanEncodings[] = { 13, 25, 19, 61, 35, 49, 47, 59, 55, 11 };
+
+int YuvFrameGenerator::DrawEanEncodedDigit(int digit, int x, int y,
+ int height, bool flip) {
+ uint8 ean_encoding = kEanEncodings[digit];
+ if (flip) {
+ ean_encoding = ~ean_encoding;
+ }
+ uint8 mask = 0x40;
+ for (int i = 6; i >= 0; i--, mask >>= 1) {
+ if (ean_encoding & mask) {
+ DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0);
+ }
+ x += kUnitBarSize;
+ }
+ return x;
+}
+
+void YuvFrameGenerator::DrawBlockRectangle(uint8* p,
+ int x_start, int y_start, int width, int height, int pitch, uint8 value) {
+ for (int x = x_start; x < x_start + width; x++) {
+ for (int y = y_start; y < y_start + height; y++) {
+ p[x + y * pitch] = value;
+ }
+ }
+}
+
+} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/media/base/yuvframegenerator.h b/chromium/third_party/libjingle/source/talk/media/base/yuvframegenerator.h
new file mode 100644
index 00000000000..4adf971f640
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/base/yuvframegenerator.h
@@ -0,0 +1,78 @@
+// Generates YUV420 frames with a "landscape with striped crosshair" in the
+// Y-plane, plus a horizontal gradient in the U-plane and a vertical one in the
+// V-plane. This makes for a nice mix of colours that is suited for both
+// catching visual errors and making sure e.g. YUV->RGB/BGR conversion looks
+// the same on different platforms.
+// There is also a solid box bouncing around in the Y-plane, and two differently
+// coloured lines bouncing horizontally and vertically in the U and V plane.
+// This helps illustrating how the frame boundary goes, and can aid as a quite
+// handy visual help for noticing e.g. packet loss if the frames are encoded
+// and sent over the network.
+
+#ifndef TALK_MEDIA_BASE_YUVFRAMEGENERATOR_H_
+#define TALK_MEDIA_BASE_YUVFRAMEGENERATOR_H_
+
+#include "talk/base/basictypes.h"
+
+namespace cricket {
+
+class YuvFrameGenerator {
+ public:
+ // Constructs a frame-generator that produces frames of size |width|x|height|.
+ // If |enable_barcode| is specified, barcodes can be included in the frames
+ // when calling |GenerateNextFrame(uint8*, uint32)|. If |enable_barcode| is
+ // |true| then |width|x|height| should be at least 160x100; otherwise this
+ // constructor will abort.
+ YuvFrameGenerator(int width, int height, bool enable_barcode);
+ ~YuvFrameGenerator();
+
+ int GetFrameSize() { return frame_data_size_; }
+
+ // Generate the next frame and return it in the provided |frame_buffer|. If
+ // barcode_value is not |nullptr| the value referred by it will be encoded
+ // into a barcode in the frame. The value should in the range:
+ // [0..9,999,999]. If the value exceeds this range or barcodes were not
+ // requested in the constructor, this function will abort.
+ void GenerateNextFrame(uint8* frame_buffer, int32 barcode_value);
+
+ int GetHeight() { return height_; }
+ int GetWidth() { return width_; }
+
+ // Fetch the bounds of the barcode from the generator. The barcode will
+ // always be at this location. This function will abort if barcodes were not
+ // requested in the constructor.
+ void GetBarcodeBounds(int* top, int* left, int* width, int* height);
+
+ private:
+ void DrawLandscape(uint8 *p, int w, int h);
+ void DrawGradientX(uint8 *p, int w, int h);
+ void DrawGradientY(uint8 *p, int w, int h);
+ void DrawMovingLineX(uint8 *p, int w, int h, int n);
+ void DrawMovingLineY(uint8 *p, int w, int h, int n);
+ void DrawBouncingCube(uint8 *p, int w, int h, int n);
+
+ void DrawBarcode(uint32 value);
+ int DrawSideGuardBars(int x, int y, int height);
+ int DrawMiddleGuardBars(int x, int y, int height);
+ int DrawEanEncodedDigit(int digit, int x, int y, int height, bool r_code);
+ void DrawBlockRectangle(uint8* p, int x_start, int y_start,
+ int width, int height, int pitch, uint8 value);
+
+ private:
+ int width_;
+ int height_;
+ int frame_index_;
+ int frame_data_size_;
+ uint8* y_data_;
+ uint8* u_data_;
+ uint8* v_data_;
+
+ int barcode_start_x_;
+ int barcode_start_y_;
+
+ DISALLOW_COPY_AND_ASSIGN(YuvFrameGenerator);
+};
+
+} // namespace cricket
+
+#endif // TALK_MEDIA_BASE_YUVFRAMEGENERATOR_H_
diff --git a/chromium/third_party/libjingle/source/talk/media/devices/devicemanager.cc b/chromium/third_party/libjingle/source/talk/media/devices/devicemanager.cc
index 150b55855d9..75b935ce592 100644
--- a/chromium/third_party/libjingle/source/talk/media/devices/devicemanager.cc
+++ b/chromium/third_party/libjingle/source/talk/media/devices/devicemanager.cc
@@ -37,8 +37,7 @@
#include "talk/media/base/mediacommon.h"
#include "talk/media/devices/deviceinfo.h"
#include "talk/media/devices/filevideocapturer.h"
-
-#if !defined(IOS)
+#include "talk/media/devices/yuvframescapturer.h"
#if defined(HAVE_WEBRTC_VIDEO)
#include "talk/media/webrtc/webrtcvideocapturer.h"
@@ -50,8 +49,6 @@
#endif
-#endif
-
namespace {
bool StringMatchWithWildcard(
@@ -67,7 +64,6 @@ namespace cricket {
// Initialize to empty string.
const char DeviceManagerInterface::kDefaultDeviceName[] = "";
-
class DefaultVideoCapturerFactory : public VideoCapturerFactory {
public:
DefaultVideoCapturerFactory() {}
@@ -180,12 +176,27 @@ bool DeviceManager::GetVideoCaptureDevice(const std::string& name,
}
}
- // If |name| is a valid name for a file, return a file video capturer device.
+ // If |name| is a valid name for a file or yuvframedevice,
+ // return a fake video capturer device.
+ if (GetFakeVideoCaptureDevice(name, out)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool DeviceManager::GetFakeVideoCaptureDevice(const std::string& name,
+ Device* out) const {
if (talk_base::Filesystem::IsFile(name)) {
*out = FileVideoCapturer::CreateFileVideoCapturerDevice(name);
return true;
}
+ if (name == YuvFramesCapturer::kYuvFrameDeviceName) {
+ *out = YuvFramesCapturer::CreateYuvFramesCapturerDevice();
+ return true;
+ }
+
return false;
}
@@ -201,23 +212,12 @@ void DeviceManager::ClearVideoCaptureDeviceMaxFormat(
}
VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const {
-#if defined(IOS)
- LOG_F(LS_ERROR) << " should never be called!";
- return NULL;
-#else
- // TODO(hellner): Throw out the creation of a file video capturer once the
- // refactoring is completed.
- if (FileVideoCapturer::IsFileVideoCapturerDevice(device)) {
- FileVideoCapturer* capturer = new FileVideoCapturer;
- if (!capturer->Init(device)) {
- delete capturer;
- return NULL;
- }
- LOG(LS_INFO) << "Created file video capturer " << device.name;
- capturer->set_repeat(talk_base::kForever);
+ VideoCapturer* capturer = ConstructFakeVideoCapturer(device);
+ if (capturer) {
return capturer;
}
- VideoCapturer* capturer = device_video_capturer_factory_->Create(device);
+
+ capturer = device_video_capturer_factory_->Create(device);
if (!capturer) {
return NULL;
}
@@ -229,7 +229,29 @@ VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const {
capturer->ConstrainSupportedFormats(video_format);
}
return capturer;
-#endif
+}
+
+VideoCapturer* DeviceManager::ConstructFakeVideoCapturer(
+ const Device& device) const {
+ // TODO(hellner): Throw out the creation of a file video capturer once the
+ // refactoring is completed.
+ if (FileVideoCapturer::IsFileVideoCapturerDevice(device)) {
+ FileVideoCapturer* capturer = new FileVideoCapturer;
+ if (!capturer->Init(device)) {
+ delete capturer;
+ return NULL;
+ }
+ LOG(LS_INFO) << "Created file video capturer " << device.name;
+ capturer->set_repeat(talk_base::kForever);
+ return capturer;
+ }
+
+ if (YuvFramesCapturer::IsYuvFramesCapturerDevice(device)) {
+ YuvFramesCapturer* capturer = new YuvFramesCapturer();
+ capturer->Init();
+ return capturer;
+ }
+ return NULL;
}
bool DeviceManager::GetWindows(
diff --git a/chromium/third_party/libjingle/source/talk/media/devices/devicemanager.h b/chromium/third_party/libjingle/source/talk/media/devices/devicemanager.h
index 90da89157f8..f6099f36d23 100644
--- a/chromium/third_party/libjingle/source/talk/media/devices/devicemanager.h
+++ b/chromium/third_party/libjingle/source/talk/media/devices/devicemanager.h
@@ -201,6 +201,8 @@ class DeviceManager : public DeviceManagerInterface {
// The exclusion_list MUST be a NULL terminated list.
static bool ShouldDeviceBeIgnored(const std::string& device_name,
const char* const exclusion_list[]);
+ bool GetFakeVideoCaptureDevice(const std::string& name, Device* out) const;
+ VideoCapturer* ConstructFakeVideoCapturer(const Device& device) const;
bool initialized_;
talk_base::scoped_ptr<VideoCapturerFactory> device_video_capturer_factory_;
diff --git a/chromium/third_party/libjingle/source/talk/media/devices/filevideocapturer.cc b/chromium/third_party/libjingle/source/talk/media/devices/filevideocapturer.cc
index f5c078d3fa4..e79783faacd 100644
--- a/chromium/third_party/libjingle/source/talk/media/devices/filevideocapturer.cc
+++ b/chromium/third_party/libjingle/source/talk/media/devices/filevideocapturer.cc
@@ -209,8 +209,14 @@ bool FileVideoCapturer::Init(const Device& device) {
std::vector<VideoFormat> supported;
supported.push_back(format);
+ // TODO(thorcarpenter): Report the actual file video format as the supported
+ // format. Do not use kMinimumInterval as it conflicts with video adaptation.
SetId(device.id);
SetSupportedFormats(supported);
+
+ // TODO(wuwang): Design an E2E integration test for video adaptation,
+ // then remove the below call to disable the video adapter.
+ set_enable_video_adapter(false);
return true;
}
diff --git a/chromium/third_party/libjingle/source/talk/media/devices/linuxdevicemanager.cc b/chromium/third_party/libjingle/source/talk/media/devices/linuxdevicemanager.cc
index e3e55ff7959..8e58d99da19 100644
--- a/chromium/third_party/libjingle/source/talk/media/devices/linuxdevicemanager.cc
+++ b/chromium/third_party/libjingle/source/talk/media/devices/linuxdevicemanager.cc
@@ -302,6 +302,12 @@ LinuxDeviceWatcher::LinuxDeviceWatcher(DeviceManagerInterface* dm)
LinuxDeviceWatcher::~LinuxDeviceWatcher() {
}
+static talk_base::PhysicalSocketServer* CurrentSocketServer() {
+ talk_base::SocketServer* ss =
+ talk_base::ThreadManager::Instance()->WrapCurrentThread()->socketserver();
+ return reinterpret_cast<talk_base::PhysicalSocketServer*>(ss);
+}
+
bool LinuxDeviceWatcher::Start() {
// We deliberately return true in the failure paths here because libudev is
// not a critical component of a Linux system so it may not be present/usable,
@@ -341,16 +347,14 @@ bool LinuxDeviceWatcher::Start() {
LOG_ERR(LS_ERROR) << "udev_monitor_enable_receiving()";
return true;
}
- static_cast<talk_base::PhysicalSocketServer*>(
- talk_base::Thread::Current()->socketserver())->Add(this);
+ CurrentSocketServer()->Add(this);
registered_ = true;
return true;
}
void LinuxDeviceWatcher::Stop() {
if (registered_) {
- static_cast<talk_base::PhysicalSocketServer*>(
- talk_base::Thread::Current()->socketserver())->Remove(this);
+ CurrentSocketServer()->Remove(this);
registered_ = false;
}
if (udev_monitor_) {
@@ -380,8 +384,7 @@ void LinuxDeviceWatcher::OnEvent(uint32 ff, int err) {
LOG_ERR(LS_WARNING) << "udev_monitor_receive_device()";
// Stop listening to avoid potential livelock (an fd with EOF in it is
// always considered readable).
- static_cast<talk_base::PhysicalSocketServer*>(
- talk_base::Thread::Current()->socketserver())->Remove(this);
+ CurrentSocketServer()->Remove(this);
registered_ = false;
return;
}
diff --git a/chromium/third_party/libjingle/source/talk/media/devices/macdevicemanager.cc b/chromium/third_party/libjingle/source/talk/media/devices/macdevicemanager.cc
index e92408e416c..805558836d6 100644
--- a/chromium/third_party/libjingle/source/talk/media/devices/macdevicemanager.cc
+++ b/chromium/third_party/libjingle/source/talk/media/devices/macdevicemanager.cc
@@ -65,7 +65,6 @@ static const char* const kFilteredVideoDevicesName[] = {
"Sonix SN9C201p", // Crashes in OpenAComponent and CloseComponent
NULL,
};
-static const int kVideoDeviceOpenAttempts = 3;
static const UInt32 kAudioDeviceNameLength = 64;
// Obj-C functions defined in macdevicemanagermm.mm
// TODO(ronghuawu): have a shared header for these function defines.
diff --git a/chromium/third_party/libjingle/source/talk/media/devices/macdevicemanagermm.mm b/chromium/third_party/libjingle/source/talk/media/devices/macdevicemanagermm.mm
index 8cc77518cf4..fdde91fa526 100644
--- a/chromium/third_party/libjingle/source/talk/media/devices/macdevicemanagermm.mm
+++ b/chromium/third_party/libjingle/source/talk/media/devices/macdevicemanagermm.mm
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2010, Google Inc.
+ * Copyright 2010, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -27,7 +27,7 @@
// support GCC compiler
#ifndef __has_feature
-# define __has_feature(x) 0
+#define __has_feature(x) 0
#endif
#include "talk/media/devices/devicemanager.h"
@@ -42,7 +42,7 @@
cricket::DeviceManagerInterface* manager_;
}
- (id)init:(cricket::DeviceManagerInterface*)manager;
-- (void)onDevicesChanged:(NSNotification *)notification;
+- (void)onDevicesChanged:(NSNotification*)notification;
@end
@implementation DeviceWatcherImpl
@@ -50,14 +50,16 @@
if ((self = [super init])) {
assert(manager != NULL);
manager_ = manager;
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(onDevicesChanged:)
- name:QTCaptureDeviceWasConnectedNotification
- object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(onDevicesChanged:)
- name:QTCaptureDeviceWasDisconnectedNotification
- object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(onDevicesChanged:)
+ name:QTCaptureDeviceWasConnectedNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(onDevicesChanged:)
+ name:QTCaptureDeviceWasDisconnectedNotification
+ object:nil];
}
return self;
}
@@ -68,7 +70,7 @@
[super dealloc];
#endif
}
-- (void)onDevicesChanged:(NSNotification *)notification {
+- (void)onDevicesChanged:(NSNotification*)notification {
manager_->SignalDevicesChange();
}
@end
@@ -83,9 +85,7 @@ DeviceWatcherImpl* CreateDeviceWatcherCallback(
#else
@autoreleasepool
#endif
- {
- impl = [[DeviceWatcherImpl alloc] init:manager];
- }
+ { impl = [[DeviceWatcherImpl alloc] init:manager]; }
#if !__has_feature(objc_arc)
[pool drain];
#endif
@@ -115,20 +115,19 @@ bool GetQTKitVideoDevices(std::vector<Device>* devices) {
static NSString* const kFormat = @"localizedDisplayName: \"%@\", "
@"modelUniqueID: \"%@\", uniqueID \"%@\", isConnected: %d, "
@"isOpen: %d, isInUseByAnotherApplication: %d";
- NSString* info = [NSString stringWithFormat:kFormat,
- [qt_capture_device localizedDisplayName],
- [qt_capture_device modelUniqueID],
- [qt_capture_device uniqueID],
- [qt_capture_device isConnected],
- [qt_capture_device isOpen],
- [qt_capture_device isInUseByAnotherApplication]];
+ NSString* info = [NSString
+ stringWithFormat:kFormat,
+ [qt_capture_device localizedDisplayName],
+ [qt_capture_device modelUniqueID],
+ [qt_capture_device uniqueID],
+ [qt_capture_device isConnected],
+ [qt_capture_device isOpen],
+ [qt_capture_device isInUseByAnotherApplication]];
LOG(LS_INFO) << [info UTF8String];
- std::string name([[qt_capture_device localizedDisplayName]
- UTF8String]);
- devices->push_back(Device(name,
- [[qt_capture_device uniqueID]
- UTF8String]));
+ std::string name([[qt_capture_device localizedDisplayName] UTF8String]);
+ devices->push_back(
+ Device(name, [[qt_capture_device uniqueID] UTF8String]));
}
}
#if !__has_feature(objc_arc)
diff --git a/chromium/third_party/libjingle/source/talk/media/devices/v4llookup.cc b/chromium/third_party/libjingle/source/talk/media/devices/v4llookup.cc
index ff128a4ae3b..76eafa71692 100644
--- a/chromium/third_party/libjingle/source/talk/media/devices/v4llookup.cc
+++ b/chromium/third_party/libjingle/source/talk/media/devices/v4llookup.cc
@@ -12,13 +12,12 @@
#include <fcntl.h>
#include <linux/types.h>
#include <linux/videodev2.h>
+#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <cstring>
-
#include "talk/base/logging.h"
namespace cricket {
@@ -50,10 +49,10 @@ bool V4LLookup::CheckIsV4L2Device(const std::string& device_path) {
is_v4l2 = true;
} else {
- LOG(LS_ERROR) << "VIDIOC_QUERYCAP failed for " << device_path;
+ LOG_ERRNO(LS_ERROR) << "VIDIOC_QUERYCAP failed for " << device_path;
}
} else {
- LOG(LS_ERROR) << "Failed to open " << device_path;
+ LOG_ERRNO(LS_ERROR) << "Failed to open " << device_path;
}
}
}
diff --git a/chromium/third_party/libjingle/source/talk/media/devices/yuvframescapturer.cc b/chromium/third_party/libjingle/source/talk/media/devices/yuvframescapturer.cc
new file mode 100644
index 00000000000..648094bf43a
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/devices/yuvframescapturer.cc
@@ -0,0 +1,173 @@
+#include "talk/media/devices/yuvframescapturer.h"
+
+#include "talk/base/bytebuffer.h"
+#include "talk/base/criticalsection.h"
+#include "talk/base/logging.h"
+#include "talk/base/thread.h"
+
+#include "webrtc/system_wrappers/interface/clock.h"
+
+namespace cricket {
+///////////////////////////////////////////////////////////////////////
+// Definition of private class YuvFramesThread that periodically generates
+// frames.
+///////////////////////////////////////////////////////////////////////
+class YuvFramesCapturer::YuvFramesThread
+ : public talk_base::Thread, public talk_base::MessageHandler {
+ public:
+ explicit YuvFramesThread(YuvFramesCapturer* capturer)
+ : capturer_(capturer),
+ finished_(false) {
+ }
+
+ virtual ~YuvFramesThread() {
+ Stop();
+ }
+
+ // Override virtual method of parent Thread. Context: Worker Thread.
+ virtual void Run() {
+ // Read the first frame and start the message pump. The pump runs until
+ // Stop() is called externally or Quit() is called by OnMessage().
+ int waiting_time_ms = 0;
+ if (capturer_) {
+ capturer_->ReadFrame(true);
+ PostDelayed(waiting_time_ms, this);
+ Thread::Run();
+ }
+
+ talk_base::CritScope cs(&crit_);
+ finished_ = true;
+ }
+
+ // Override virtual method of parent MessageHandler. Context: Worker Thread.
+ virtual void OnMessage(talk_base::Message* /*pmsg*/) {
+ int waiting_time_ms = 0;
+ if (capturer_) {
+ capturer_->ReadFrame(false);
+ PostDelayed(waiting_time_ms, this);
+ } else {
+ Quit();
+ }
+ }
+
+ // Check if Run() is finished.
+ bool Finished() const {
+ talk_base::CritScope cs(&crit_);
+ return finished_;
+ }
+
+ private:
+ YuvFramesCapturer* capturer_;
+ mutable talk_base::CriticalSection crit_;
+ bool finished_;
+
+ DISALLOW_COPY_AND_ASSIGN(YuvFramesThread);
+};
+
+/////////////////////////////////////////////////////////////////////
+// Implementation of class YuvFramesCapturer.
+/////////////////////////////////////////////////////////////////////
+
+const char* YuvFramesCapturer::kYuvFrameDeviceName = "YuvFramesGenerator";
+
+// TODO(shaowei): allow width_ and height_ to be configurable.
+YuvFramesCapturer::YuvFramesCapturer()
+ : frames_generator_thread(NULL),
+ width_(640),
+ height_(480),
+ frame_index_(0),
+ barcode_interval_(1) {
+}
+
+YuvFramesCapturer::~YuvFramesCapturer() {
+ Stop();
+ delete[] static_cast<char*>(captured_frame_.data);
+}
+
+void YuvFramesCapturer::Init() {
+ int size = width_ * height_;
+ int qsize = size / 4;
+ frame_generator_ = new YuvFrameGenerator(width_, height_, true);
+ frame_data_size_ = size + 2 * qsize;
+ captured_frame_.data = new char[frame_data_size_];
+ captured_frame_.fourcc = FOURCC_IYUV;
+ captured_frame_.pixel_height = 1;
+ captured_frame_.pixel_width = 1;
+ captured_frame_.width = width_;
+ captured_frame_.height = height_;
+ captured_frame_.data_size = frame_data_size_;
+
+ // Enumerate the supported formats. We have only one supported format.
+ VideoFormat format(width_, height_, VideoFormat::kMinimumInterval,
+ FOURCC_IYUV);
+ std::vector<VideoFormat> supported;
+ supported.push_back(format);
+ SetSupportedFormats(supported);
+}
+
+CaptureState YuvFramesCapturer::Start(const VideoFormat& capture_format) {
+ if (IsRunning()) {
+ LOG(LS_ERROR) << "Yuv Frame Generator is already running";
+ return CS_FAILED;
+ }
+ SetCaptureFormat(&capture_format);
+
+ barcode_reference_timestamp_millis_ =
+ static_cast<int64>(talk_base::Time()) * 1000;
+ // Create a thread to generate frames.
+ frames_generator_thread = new YuvFramesThread(this);
+ bool ret = frames_generator_thread->Start();
+ if (ret) {
+ LOG(LS_INFO) << "Yuv Frame Generator started";
+ return CS_RUNNING;
+ } else {
+ LOG(LS_ERROR) << "Yuv Frame Generator failed to start";
+ return CS_FAILED;
+ }
+}
+
+bool YuvFramesCapturer::IsRunning() {
+ return frames_generator_thread && !frames_generator_thread->Finished();
+}
+
+void YuvFramesCapturer::Stop() {
+ if (frames_generator_thread) {
+ frames_generator_thread->Stop();
+ frames_generator_thread = NULL;
+ LOG(LS_INFO) << "Yuv Frame Generator stopped";
+ }
+ SetCaptureFormat(NULL);
+}
+
+bool YuvFramesCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs) {
+ if (!fourccs) {
+ return false;
+ }
+ fourccs->push_back(GetSupportedFormats()->at(0).fourcc);
+ return true;
+}
+
+// Executed in the context of YuvFramesThread.
+void YuvFramesCapturer::ReadFrame(bool first_frame) {
+ // 1. Signal the previously read frame to downstream.
+ if (!first_frame) {
+ SignalFrameCaptured(this, &captured_frame_);
+ }
+ uint8* buffer = new uint8[frame_data_size_];
+ frame_generator_->GenerateNextFrame(buffer, GetBarcodeValue());
+ frame_index_++;
+ memmove(captured_frame_.data, buffer, frame_data_size_);
+ delete[] buffer;
+}
+
+
+int32 YuvFramesCapturer::GetBarcodeValue() {
+ if (barcode_reference_timestamp_millis_ == -1 ||
+ frame_index_ % barcode_interval_ != 0) {
+ return -1;
+ }
+ int64 now_millis = static_cast<int64>(talk_base::Time()) * 1000;
+ return static_cast<int32>(now_millis - barcode_reference_timestamp_millis_);
+}
+
+} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/media/devices/yuvframescapturer.h b/chromium/third_party/libjingle/source/talk/media/devices/yuvframescapturer.h
new file mode 100644
index 00000000000..78865258409
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/devices/yuvframescapturer.h
@@ -0,0 +1,71 @@
+#ifndef TALK_MEDIA_DEVICES_YUVFRAMESCAPTURER_H_
+#define TALK_MEDIA_DEVICES_YUVFRAMESCAPTURER_H_
+
+#include <string>
+#include <vector>
+
+#include "talk/base/stream.h"
+#include "talk/base/stringutils.h"
+#include "talk/media/base/videocapturer.h"
+#include "talk/media/base/yuvframegenerator.h"
+
+
+namespace talk_base {
+class FileStream;
+}
+
+namespace cricket {
+
+
+// Simulated video capturer that periodically reads frames from a file.
+class YuvFramesCapturer : public VideoCapturer {
+ public:
+ YuvFramesCapturer();
+ YuvFramesCapturer(int width, int height);
+ virtual ~YuvFramesCapturer();
+
+ static const char* kYuvFrameDeviceName;
+ static Device CreateYuvFramesCapturerDevice() {
+ std::stringstream id;
+ id << kYuvFrameDeviceName;
+ return Device(id.str(), id.str());
+ }
+ static bool IsYuvFramesCapturerDevice(const Device& device) {
+ return talk_base::starts_with(device.id.c_str(), kYuvFrameDeviceName);
+ }
+
+ void Init();
+ // Override virtual methods of parent class VideoCapturer.
+ virtual CaptureState Start(const VideoFormat& capture_format);
+ virtual void Stop();
+ virtual bool IsRunning();
+ virtual bool IsScreencast() const { return false; }
+
+ protected:
+ // Override virtual methods of parent class VideoCapturer.
+ virtual bool GetPreferredFourccs(std::vector<uint32>* fourccs);
+
+ // Read a frame and determine how long to wait for the next frame.
+ void ReadFrame(bool first_frame);
+
+ private:
+ class YuvFramesThread; // Forward declaration, defined in .cc.
+
+ YuvFrameGenerator* frame_generator_;
+ CapturedFrame captured_frame_;
+ YuvFramesThread* frames_generator_thread;
+ int width_;
+ int height_;
+ uint32 frame_data_size_;
+ uint32 frame_index_;
+
+ int64 barcode_reference_timestamp_millis_;
+ int32 barcode_interval_;
+ int32 GetBarcodeValue();
+
+ DISALLOW_COPY_AND_ASSIGN(YuvFramesCapturer);
+};
+
+} // namespace cricket
+
+#endif // TALK_MEDIA_DEVICES_YUVFRAMESCAPTURER_H_
diff --git a/chromium/third_party/libjingle/source/talk/media/other/linphonemediaengine.h b/chromium/third_party/libjingle/source/talk/media/other/linphonemediaengine.h
index 69b2d2f6a7a..db3e69f6bcc 100644
--- a/chromium/third_party/libjingle/source/talk/media/other/linphonemediaengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/other/linphonemediaengine.h
@@ -145,7 +145,8 @@ class LinphoneVoiceChannel : public VoiceMediaChannel {
virtual void SetSendSsrc(uint32 id) {} // TODO: change RTP packet?
virtual bool SetRtcpCName(const std::string& cname) { return true; }
virtual bool Mute(bool on) { return mute_; }
- virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
+ virtual bool SetStartSendBandwidth(int bps) { return true; }
+ virtual bool SetMaxSendBandwidth(int bps) { return true; }
virtual bool SetOptions(int options) { return true; }
virtual bool SetRecvRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) { return true; }
diff --git a/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine.cc b/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine.cc
index 653273bd2e3..3647d212923 100644
--- a/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine.cc
+++ b/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine.cc
@@ -29,26 +29,82 @@
#include <stdarg.h>
#include <stdio.h>
+#include <sstream>
#include <vector>
-#include "talk/app/webrtc/datachannelinterface.h"
#include "talk/base/buffer.h"
#include "talk/base/helpers.h"
#include "talk/base/logging.h"
+#include "talk/base/safe_conversions.h"
#include "talk/media/base/codec.h"
#include "talk/media/base/constants.h"
#include "talk/media/base/streamparams.h"
-#include "talk/media/sctp/sctputils.h"
#include "usrsctplib/usrsctp.h"
+namespace {
+typedef cricket::SctpDataMediaChannel::StreamSet StreamSet;
+// Returns a comma-separated, human-readable list of the stream IDs in 's'
+std::string ListStreams(const StreamSet& s) {
+ std::stringstream result;
+ bool first = true;
+ for (StreamSet::const_iterator it = s.begin(); it != s.end(); ++it) {
+ if (!first) {
+ result << ", " << *it;
+ } else {
+ result << *it;
+ first = false;
+ }
+ }
+ return result.str();
+}
+
+// Returns a pipe-separated, human-readable list of the SCTP_STREAM_RESET
+// flags in 'flags'
+std::string ListFlags(int flags) {
+ std::stringstream result;
+ bool first = true;
+ // Skip past the first 12 chars (strlen("SCTP_STREAM_"))
+#define MAKEFLAG(X) { X, #X + 12}
+ struct flaginfo_t {
+ int value;
+ const char* name;
+ } flaginfo[] = {
+ MAKEFLAG(SCTP_STREAM_RESET_INCOMING_SSN),
+ MAKEFLAG(SCTP_STREAM_RESET_OUTGOING_SSN),
+ MAKEFLAG(SCTP_STREAM_RESET_DENIED),
+ MAKEFLAG(SCTP_STREAM_RESET_FAILED),
+ MAKEFLAG(SCTP_STREAM_CHANGE_DENIED)
+ };
+#undef MAKEFLAG
+ for (int i = 0; i < ARRAY_SIZE(flaginfo); ++i) {
+ if (flags & flaginfo[i].value) {
+ if (!first) result << " | ";
+ result << flaginfo[i].name;
+ first = false;
+ }
+ }
+ return result.str();
+}
+
+// Returns a comma-separated, human-readable list of the integers in 'array'.
+// All 'num_elems' of them.
+std::string ListArray(const uint16* array, int num_elems) {
+ std::stringstream result;
+ for (int i = 0; i < num_elems; ++i) {
+ if (i) {
+ result << ", " << array[i];
+ } else {
+ result << array[i];
+ }
+ }
+ return result.str();
+}
+} // namespace
+
namespace cricket {
+typedef talk_base::ScopedMessageData<SctpInboundPacket> InboundPacketMessage;
+typedef talk_base::ScopedMessageData<talk_base::Buffer> OutboundPacketMessage;
-// This is the SCTP port to use. It is passed along the wire and the listener
-// and connector must be using the same port. It is not related to the ports at
-// the IP level. (Corresponds to: sockaddr_conn.sconn_port in usrsctp.h)
-//
-// TODO(ldixon): Allow port to be set from higher level code.
-static const int kSctpDefaultPort = 5001;
// TODO(ldixon): Find where this is defined, and also check is Sctp really
// respects this.
static const size_t kSctpMtu = 1280;
@@ -130,9 +186,9 @@ static int OnSctpOutboundPacket(void* addr, void* data, size_t length,
<< "; tos: " << std::hex << static_cast<int>(tos)
<< "; set_df: " << std::hex << static_cast<int>(set_df);
// Note: We have to copy the data; the caller will delete it.
- talk_base::Buffer* buffer = new talk_base::Buffer(data, length);
- channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET,
- talk_base::WrapMessageData(buffer));
+ OutboundPacketMessage* msg =
+ new OutboundPacketMessage(new talk_base::Buffer(data, length));
+ channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg);
return 0;
}
@@ -164,8 +220,9 @@ static int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr,
packet->params.timestamp = rcv.rcv_tsn;
packet->params.type = type;
packet->flags = flags;
- channel->worker_thread()->Post(channel, MSG_SCTPINBOUNDPACKET,
- talk_base::WrapMessageData(packet));
+ // The ownership of |packet| transfers to |msg|.
+ InboundPacketMessage* msg = new InboundPacketMessage(packet);
+ channel->worker_thread()->Post(channel, MSG_SCTPINBOUNDPACKET, msg);
}
free(data);
return 1;
@@ -214,24 +271,26 @@ SctpDataEngine::SctpDataEngine() {
}
usrsctp_engines_count++;
- // We don't put in a codec because we don't want one offered when we
- // use the hybrid data engine.
- // codecs_.push_back(cricket::DataCodec( kGoogleSctpDataCodecId,
- // kGoogleSctpDataCodecName, 0));
+ cricket::DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, 0);
+ codec.SetParam(kCodecParamPort, kSctpDefaultPort);
+ codecs_.push_back(codec);
}
SctpDataEngine::~SctpDataEngine() {
- // TODO(ldixon): There is currently a bug in teardown of usrsctp that blocks
- // indefintely if a finish call made too soon after close calls. So teardown
- // has been skipped. Once the bug is fixed, retest and enable teardown.
- //
- // usrsctp_engines_count--;
- // LOG(LS_VERBOSE) << "usrsctp_engines_count:" << usrsctp_engines_count;
- // if (usrsctp_engines_count == 0) {
- // if (usrsctp_finish() != 0) {
- // LOG(LS_WARNING) << "usrsctp_finish.";
- // }
- // }
+ usrsctp_engines_count--;
+ LOG(LS_VERBOSE) << "usrsctp_engines_count:" << usrsctp_engines_count;
+
+ if (usrsctp_engines_count == 0) {
+ // usrsctp_finish() may fail if it's called too soon after the channels are
+ // closed. Wait and try again until it succeeds for up to 3 seconds.
+ for (size_t i = 0; i < 300; ++i) {
+ if (usrsctp_finish() == 0)
+ return;
+
+ talk_base::Thread::SleepMs(10);
+ }
+ LOG(LS_ERROR) << "Failed to shutdown usrsctp.";
+ }
}
DataMediaChannel* SctpDataEngine::CreateChannel(
@@ -244,8 +303,8 @@ DataMediaChannel* SctpDataEngine::CreateChannel(
SctpDataMediaChannel::SctpDataMediaChannel(talk_base::Thread* thread)
: worker_thread_(thread),
- local_port_(-1),
- remote_port_(-1),
+ local_port_(kSctpDefaultPort),
+ remote_port_(kSctpDefaultPort),
sock_(NULL),
sending_(false),
receiving_(false),
@@ -300,6 +359,18 @@ bool SctpDataMediaChannel::OpenSctpSocket() {
return false;
}
+ // Enable stream ID resets.
+ struct sctp_assoc_value stream_rst;
+ stream_rst.assoc_id = SCTP_ALL_ASSOC;
+ stream_rst.assoc_value = 1;
+ if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET,
+ &stream_rst, sizeof(stream_rst))) {
+ LOG_ERRNO(LS_ERROR) << debug_name_
+ << "Failed to set SCTP_ENABLE_STREAM_RESET.";
+ return false;
+ }
+
+ // Nagle.
uint32_t nodelay = 1;
if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay,
sizeof(nodelay))) {
@@ -311,7 +382,8 @@ bool SctpDataMediaChannel::OpenSctpSocket() {
int event_types[] = {SCTP_ASSOC_CHANGE,
SCTP_PEER_ADDR_CHANGE,
SCTP_SEND_FAILED_EVENT,
- SCTP_SENDER_DRY_EVENT};
+ SCTP_SENDER_DRY_EVENT,
+ SCTP_STREAM_RESET_EVENT};
struct sctp_event event = {0};
event.se_assoc_id = SCTP_ALL_ASSOC;
event.se_on = 1;
@@ -346,12 +418,6 @@ void SctpDataMediaChannel::CloseSctpSocket() {
bool SctpDataMediaChannel::Connect() {
LOG(LS_VERBOSE) << debug_name_ << "->Connect().";
- if (remote_port_ < 0) {
- remote_port_ = kSctpDefaultPort;
- }
- if (local_port_ < 0) {
- local_port_ = kSctpDefaultPort;
- }
// If we already have a socket connection, just return.
if (sock_) {
@@ -412,59 +478,24 @@ bool SctpDataMediaChannel::SetReceive(bool receive) {
}
bool SctpDataMediaChannel::AddSendStream(const StreamParams& stream) {
- if (!stream.has_ssrcs()) {
- return false;
- }
-
- StreamParams found_stream;
- // TODO(lally): Consider keeping this sorted.
- if (GetStreamBySsrc(streams_, stream.first_ssrc(), &found_stream)) {
- LOG(LS_WARNING) << debug_name_ << "->AddSendStream(...): "
- << "Not adding data send stream '" << stream.id
- << "' with ssrc=" << stream.first_ssrc()
- << " because stream already exists.";
- return false;
- }
-
- streams_.push_back(stream);
- return true;
+ return AddStream(stream);
}
bool SctpDataMediaChannel::RemoveSendStream(uint32 ssrc) {
- StreamParams found_stream;
- if (!GetStreamBySsrc(streams_, ssrc, &found_stream)) {
- return false;
- }
-
- RemoveStreamBySsrc(&streams_, ssrc);
- return true;
+ return ResetStream(ssrc);
}
-// Note: expects exactly one ssrc. If none are given, it will fail. If more
-// than one are given, it will use the first.
bool SctpDataMediaChannel::AddRecvStream(const StreamParams& stream) {
- if (!stream.has_ssrcs()) {
- return false;
- }
-
- StreamParams found_stream;
- if (GetStreamBySsrc(streams_, stream.first_ssrc(), &found_stream)) {
- LOG(LS_WARNING) << debug_name_ << "->AddRecvStream(...): "
- << "Not adding data recv stream '" << stream.id
- << "' with ssrc=" << stream.first_ssrc()
- << " because stream already exists.";
- return false;
- }
-
- streams_.push_back(stream);
- LOG(LS_VERBOSE) << debug_name_ << "->AddRecvStream(...): "
- << "Added data recv stream '" << stream.id
- << "' with ssrc=" << stream.first_ssrc();
+ // SCTP DataChannels are always bi-directional and calling AddSendStream will
+ // enable both sending and receiving on the stream. So AddRecvStream is a
+ // no-op.
return true;
}
bool SctpDataMediaChannel::RemoveRecvStream(uint32 ssrc) {
- RemoveStreamBySsrc(&streams_, ssrc);
+ // SCTP DataChannels are always bi-directional and calling RemoveSendStream
+ // will disable both sending and receiving on the stream. So RemoveRecvStream
+ // is a no-op.
return true;
}
@@ -485,9 +516,8 @@ bool SctpDataMediaChannel::SendData(
return false;
}
- StreamParams found_stream;
if (params.type != cricket::DMT_CONTROL &&
- !GetStreamBySsrc(streams_, params.ssrc, &found_stream)) {
+ open_streams_.find(params.ssrc) == open_streams_.end()) {
LOG(LS_WARNING) << debug_name_ << "->SendData(...): "
<< "Not sending data because ssrc is unknown: "
<< params.ssrc;
@@ -521,10 +551,10 @@ bool SctpDataMediaChannel::SendData(
send_res = usrsctp_sendv(sock_, payload.data(),
static_cast<size_t>(payload.length()),
NULL, 0, &spa,
- static_cast<socklen_t>(sizeof(spa)),
+ talk_base::checked_cast<socklen_t>(sizeof(spa)),
SCTP_SENDV_SPA, 0);
if (send_res < 0) {
- if (errno == EWOULDBLOCK) {
+ if (errno == SCTP_EWOULDBLOCK) {
*result = SDR_BLOCK;
LOG(LS_INFO) << debug_name_ << "->SendData(...): EWOULDBLOCK returned";
} else {
@@ -584,36 +614,12 @@ void SctpDataMediaChannel::OnInboundPacketFromSctpToChannel(
void SctpDataMediaChannel::OnDataFromSctpToChannel(
const ReceiveDataParams& params, talk_base::Buffer* buffer) {
- StreamParams found_stream;
- if (!GetStreamBySsrc(streams_, params.ssrc, &found_stream)) {
- if (params.type == DMT_CONTROL) {
- std::string label;
- webrtc::DataChannelInit config;
- if (ParseDataChannelOpenMessage(*buffer, &label, &config)) {
- config.id = params.ssrc;
- // Do not send the OPEN message for this data channel.
- config.negotiated = true;
- SignalNewStreamReceived(label, config);
-
- // Add the stream immediately.
- cricket::StreamParams sparams =
- cricket::StreamParams::CreateLegacy(params.ssrc);
- AddSendStream(sparams);
- AddRecvStream(sparams);
- } else {
- LOG(LS_ERROR) << debug_name_ << "->OnDataFromSctpToChannel(...): "
- << "Received malformed control message";
- }
- } else {
- LOG(LS_WARNING) << debug_name_ << "->OnDataFromSctpToChannel(...): "
- << "Received packet for unknown ssrc: " << params.ssrc;
- }
- return;
- }
-
if (receiving_) {
LOG(LS_VERBOSE) << debug_name_ << "->OnDataFromSctpToChannel(...): "
- << "Posting with length: " << buffer->length();
+ << "Posting with length: " << buffer->length()
+ << " on stream " << params.ssrc;
+ // Reports all received messages to upper layers, no matter whether the sid
+ // is known.
SignalDataReceived(params, buffer->data(), buffer->length());
} else {
LOG(LS_WARNING) << debug_name_ << "->OnDataFromSctpToChannel(...): "
@@ -623,6 +629,59 @@ void SctpDataMediaChannel::OnDataFromSctpToChannel(
}
}
+bool SctpDataMediaChannel::AddStream(const StreamParams& stream) {
+ if (!stream.has_ssrcs()) {
+ return false;
+ }
+
+ const uint32 ssrc = stream.first_ssrc();
+ if (open_streams_.find(ssrc) != open_streams_.end()) {
+ LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
+ << "Not adding data stream '" << stream.id
+ << "' with ssrc=" << ssrc
+ << " because stream is already open.";
+ return false;
+ } else if (queued_reset_streams_.find(ssrc) != queued_reset_streams_.end()
+ || sent_reset_streams_.find(ssrc) != sent_reset_streams_.end()) {
+ LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
+ << "Not adding data stream '" << stream.id
+ << "' with ssrc=" << ssrc
+ << " because stream is still closing.";
+ return false;
+ }
+
+ open_streams_.insert(ssrc);
+ return true;
+}
+
+bool SctpDataMediaChannel::ResetStream(uint32 ssrc) {
+ // We typically get this called twice for the same stream, once each for
+ // Send and Recv.
+ StreamSet::iterator found = open_streams_.find(ssrc);
+
+ if (found == open_streams_.end()) {
+ LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << ssrc << "): "
+ << "stream not found.";
+ return false;
+ } else {
+ LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << ssrc << "): "
+ << "Removing and queuing RE-CONFIG chunk.";
+ open_streams_.erase(found);
+ }
+
+ // SCTP won't let you have more than one stream reset pending at a time, but
+ // you can close multiple streams in a single reset. So, we keep an internal
+ // queue of streams-to-reset, and send them as one reset message in
+ // SendQueuedStreamResets().
+ queued_reset_streams_.insert(ssrc);
+
+ // Signal our stream-reset logic that it should try to send now, if it can.
+ SendQueuedStreamResets();
+
+ // The stream will actually get removed when we get the acknowledgment.
+ return true;
+}
+
void SctpDataMediaChannel::OnNotificationFromSctp(talk_base::Buffer* buffer) {
const sctp_notification& notification =
reinterpret_cast<const sctp_notification&>(*buffer->data());
@@ -641,7 +700,7 @@ void SctpDataMediaChannel::OnNotificationFromSctp(talk_base::Buffer* buffer) {
LOG(LS_INFO) << "SCTP_SHUTDOWN_EVENT";
break;
case SCTP_ADAPTATION_INDICATION:
- LOG(LS_INFO) << "SCTP_ADAPTATION_INIDICATION";
+ LOG(LS_INFO) << "SCTP_ADAPTATION_INDICATION";
break;
case SCTP_PARTIAL_DELIVERY_EVENT:
LOG(LS_INFO) << "SCTP_PARTIAL_DELIVERY_EVENT";
@@ -650,7 +709,7 @@ void SctpDataMediaChannel::OnNotificationFromSctp(talk_base::Buffer* buffer) {
LOG(LS_INFO) << "SCTP_AUTHENTICATION_EVENT";
break;
case SCTP_SENDER_DRY_EVENT:
- LOG(LS_INFO) << "SCTP_SENDER_DRY_EVENT";
+ LOG(LS_VERBOSE) << "SCTP_SENDER_DRY_EVENT";
SignalReadyToSend(true);
break;
// TODO(ldixon): Unblock after congestion.
@@ -661,15 +720,18 @@ void SctpDataMediaChannel::OnNotificationFromSctp(talk_base::Buffer* buffer) {
LOG(LS_INFO) << "SCTP_SEND_FAILED_EVENT";
break;
case SCTP_STREAM_RESET_EVENT:
- LOG(LS_INFO) << "SCTP_STREAM_RESET_EVENT";
- // TODO(ldixon): Notify up to channel that stream resent has happened,
- // and write unit test for this case.
+ OnStreamResetEvent(&notification.sn_strreset_event);
break;
case SCTP_ASSOC_RESET_EVENT:
LOG(LS_INFO) << "SCTP_ASSOC_RESET_EVENT";
break;
case SCTP_STREAM_CHANGE_EVENT:
LOG(LS_INFO) << "SCTP_STREAM_CHANGE_EVENT";
+ // An acknowledgment we get after our stream resets have gone through,
+ // if they've failed. We log the message, but don't react -- we don't
+ // keep around the last-transmitted set of SSIDs we wanted to close for
+ // error recovery. It doesn't seem likely to occur, and if so, likely
+ // harmless within the lifetime of a single SCTP association.
break;
default:
LOG(LS_WARNING) << "Unknown SCTP event: "
@@ -702,6 +764,86 @@ void SctpDataMediaChannel::OnNotificationAssocChange(
}
}
+void SctpDataMediaChannel::OnStreamResetEvent(
+ const struct sctp_stream_reset_event* evt) {
+ // A stream reset always involves two RE-CONFIG chunks for us -- we always
+ // simultaneously reset a sid's sequence number in both directions. The
+ // requesting side transmits a RE-CONFIG chunk and waits for the peer to send
+ // one back. Both sides get this SCTP_STREAM_RESET_EVENT when they receive
+ // RE-CONFIGs.
+ const int num_ssrcs = (evt->strreset_length - sizeof(*evt)) /
+ sizeof(evt->strreset_stream_list[0]);
+ LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
+ << "): Flags = 0x"
+ << std::hex << evt->strreset_flags << " ("
+ << ListFlags(evt->strreset_flags) << ")";
+ LOG(LS_VERBOSE) << "Assoc = " << evt->strreset_assoc_id << ", Streams = ["
+ << ListArray(evt->strreset_stream_list, num_ssrcs)
+ << "], Open: ["
+ << ListStreams(open_streams_) << "], Q'd: ["
+ << ListStreams(queued_reset_streams_) << "], Sent: ["
+ << ListStreams(sent_reset_streams_) << "]";
+
+ // If both sides try to reset some streams at the same time (even if they're
+ // disjoint sets), we can get reset failures.
+ if (evt->strreset_flags & SCTP_STREAM_RESET_FAILED) {
+ // OK, just try again. The stream IDs sent over when the RESET_FAILED flag
+ // is set seem to be garbage values. Ignore them.
+ queued_reset_streams_.insert(
+ sent_reset_streams_.begin(),
+ sent_reset_streams_.end());
+ sent_reset_streams_.clear();
+
+ } else if (evt->strreset_flags & SCTP_STREAM_RESET_INCOMING_SSN) {
+ // Each side gets an event for each direction of a stream. That is,
+ // closing sid k will make each side receive INCOMING and OUTGOING reset
+ // events for k. As per RFC6525, Section 5, paragraph 2, each side will
+ // get an INCOMING event first.
+ for (int i = 0; i < num_ssrcs; i++) {
+ const int stream_id = evt->strreset_stream_list[i];
+
+ // See if this stream ID was closed by our peer or ourselves.
+ StreamSet::iterator it = sent_reset_streams_.find(stream_id);
+
+ // The reset was requested locally.
+ if (it != sent_reset_streams_.end()) {
+ LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
+ << "): local sid " << stream_id << " acknowledged.";
+ sent_reset_streams_.erase(it);
+
+ } else if ((it = open_streams_.find(stream_id))
+ != open_streams_.end()) {
+ // The peer requested the reset.
+ LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
+ << "): closing sid " << stream_id;
+ open_streams_.erase(it);
+ SignalStreamClosedRemotely(stream_id);
+
+ } else if ((it = queued_reset_streams_.find(stream_id))
+ != queued_reset_streams_.end()) {
+ // The peer requested the reset, but there was a local reset
+ // queued.
+ LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
+ << "): double-sided close for sid " << stream_id;
+ // Both sides want the stream closed, and the peer got to send the
+ // RE-CONFIG first. Treat it like the local Remove(Send|Recv)Stream
+ // finished quickly.
+ queued_reset_streams_.erase(it);
+
+ } else {
+ // This stream is unknown. Sometimes this can be from an
+ // RESET_FAILED-related retransmit.
+ LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
+ << "): Unknown sid " << stream_id;
+ }
+ }
+ }
+
+ // Always try to send the queued RESET because this call indicates that the
+ // last local RESET or remote RESET has made some progress.
+ SendQueuedStreamResets();
+}
+
// Puts the specified |param| from the codec identified by |id| into |dest|
// and returns true. Or returns false if it wasn't there, leaving |dest|
// untouched.
@@ -739,31 +881,66 @@ void SctpDataMediaChannel::OnPacketFromSctpToNetwork(
talk_base::Buffer* buffer) {
if (buffer->length() > kSctpMtu) {
LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): "
- << "SCTP seems to have made a poacket that is bigger "
+ << "SCTP seems to have made a packet that is bigger "
"than its official MTU.";
}
MediaChannel::SendPacket(buffer);
}
+bool SctpDataMediaChannel::SendQueuedStreamResets() {
+ if (!sent_reset_streams_.empty() || queued_reset_streams_.empty())
+ return true;
+
+ LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending ["
+ << ListStreams(queued_reset_streams_) << "], Open: ["
+ << ListStreams(open_streams_) << "], Sent: ["
+ << ListStreams(sent_reset_streams_) << "]";
+
+ const size_t num_streams = queued_reset_streams_.size();
+ const size_t num_bytes = sizeof(struct sctp_reset_streams)
+ + (num_streams * sizeof(uint16));
+
+ std::vector<uint8> reset_stream_buf(num_bytes, 0);
+ struct sctp_reset_streams* resetp = reinterpret_cast<sctp_reset_streams*>(
+ &reset_stream_buf[0]);
+ resetp->srs_assoc_id = SCTP_ALL_ASSOC;
+ resetp->srs_flags = SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_OUTGOING;
+ resetp->srs_number_streams = talk_base::checked_cast<uint16_t>(num_streams);
+ int result_idx = 0;
+ for (StreamSet::iterator it = queued_reset_streams_.begin();
+ it != queued_reset_streams_.end(); ++it) {
+ resetp->srs_stream_list[result_idx++] = *it;
+ }
+
+ int ret = usrsctp_setsockopt(
+ sock_, IPPROTO_SCTP, SCTP_RESET_STREAMS, resetp,
+ talk_base::checked_cast<socklen_t>(reset_stream_buf.size()));
+ if (ret < 0) {
+ LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to send a stream reset for "
+ << num_streams << " streams";
+ return false;
+ }
+
+ // sent_reset_streams_ is empty, and all the queued_reset_streams_ go into
+ // it now.
+ queued_reset_streams_.swap(sent_reset_streams_);
+ return true;
+}
+
void SctpDataMediaChannel::OnMessage(talk_base::Message* msg) {
switch (msg->message_id) {
case MSG_SCTPINBOUNDPACKET: {
- SctpInboundPacket* packet =
- static_cast<talk_base::TypedMessageData<SctpInboundPacket*>*>(
- msg->pdata)->data();
- OnInboundPacketFromSctpToChannel(packet);
- delete packet;
+ talk_base::scoped_ptr<InboundPacketMessage> pdata(
+ static_cast<InboundPacketMessage*>(msg->pdata));
+ OnInboundPacketFromSctpToChannel(pdata->data().get());
break;
}
case MSG_SCTPOUTBOUNDPACKET: {
- talk_base::Buffer* buffer =
- static_cast<talk_base::TypedMessageData<talk_base::Buffer*>*>(
- msg->pdata)->data();
- OnPacketFromSctpToNetwork(buffer);
- delete buffer;
+ talk_base::scoped_ptr<OutboundPacketMessage> pdata(
+ static_cast<OutboundPacketMessage*>(msg->pdata));
+ OnPacketFromSctpToNetwork(pdata->data().get());
break;
}
}
}
-
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine.h b/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine.h
index 4d05cf36e02..2e8beecd137 100644
--- a/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine.h
@@ -50,14 +50,20 @@ enum PreservedErrno {
// Defined by "usrsctplib/usrsctp.h"
struct sockaddr_conn;
struct sctp_assoc_change;
+struct sctp_stream_reset_event;
// Defined by <sys/socket.h>
struct socket;
-
namespace cricket {
// The highest stream ID (Sid) that SCTP allows, and the number of streams we
// tell SCTP we're going to use.
const uint32 kMaxSctpSid = 1023;
+// This is the default SCTP port to use. It is passed along the wire and the
+// connectee and connector must be using the same port. It is not related to the
+// ports at the IP level. (Corresponds to: sockaddr_conn.sconn_port in
+// usrsctp.h)
+const int kSctpDefaultPort = 5000;
+
// A DataEngine that interacts with usrsctp.
//
// From channel calls, data flows like this:
@@ -122,6 +128,8 @@ class SctpDataMediaChannel : public DataMediaChannel,
PPID_TEXT_LAST = 51
};
+ typedef std::set<uint32> StreamSet;
+
// Given a thread which will be used to post messages (received data) to this
// SctpDataMediaChannel instance.
explicit SctpDataMediaChannel(talk_base::Thread* thread);
@@ -164,7 +172,8 @@ class SctpDataMediaChannel : public DataMediaChannel,
// TODO(pthatcher): Cleanup MediaChannel interface, or at least
// don't try calling these and return false. Right now, things
// don't work if we return false.
- virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
+ virtual bool SetStartSendBandwidth(int bps) { return true; }
+ virtual bool SetMaxSendBandwidth(int bps) { return true; }
virtual bool SetRecvRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) { return true; }
virtual bool SetSendRtpHeaderExtensions(
@@ -195,6 +204,14 @@ class SctpDataMediaChannel : public DataMediaChannel,
// Sets sending_ to false and sock_ to NULL.
void CloseSctpSocket();
+ // Sends a SCTP_RESET_STREAM for all streams in closing_ssids_.
+ bool SendQueuedStreamResets();
+
+ // Adds a stream.
+ bool AddStream(const StreamParams &sp);
+ // Queues a stream for reset.
+ bool ResetStream(uint32 ssrc);
+
// Called by OnMessage to send packet on the network.
void OnPacketFromSctpToNetwork(talk_base::Buffer* buffer);
// Called by OnMessage to decide what to do with the packet.
@@ -204,6 +221,8 @@ class SctpDataMediaChannel : public DataMediaChannel,
void OnNotificationFromSctp(talk_base::Buffer* buffer);
void OnNotificationAssocChange(const sctp_assoc_change& change);
+ void OnStreamResetEvent(const struct sctp_stream_reset_event* evt);
+
// Responsible for marshalling incoming data to the channels listeners, and
// outgoing data to the network interface.
talk_base::Thread* worker_thread_;
@@ -219,8 +238,17 @@ class SctpDataMediaChannel : public DataMediaChannel,
bool sending_;
// receiving_ controls whether inbound packets are thrown away.
bool receiving_;
- // Unified send/receive streams, as each is bidirectional.
- std::vector<StreamParams> streams_;
+
+ // When a data channel opens a stream, it goes into open_streams_. When we
+ // want to close it, the stream's ID goes into queued_reset_streams_. When
+ // we actually transmit a RE-CONFIG chunk with that stream ID, the ID goes
+ // into sent_reset_streams_. When we get a response RE-CONFIG chunk back
+ // acknowledging the reset, we remove the stream ID from
+ // sent_reset_streams_. We use sent_reset_streams_ to differentiate
+ // between acknowledgment RE-CONFIG and peer-initiated RE-CONFIGs.
+ StreamSet open_streams_;
+ StreamSet queued_reset_streams_;
+ StreamSet sent_reset_streams_;
// A human-readable name for debugging messages.
std::string debug_name_;
diff --git a/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine_unittest.cc b/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine_unittest.cc
index b4ad6ce33e2..cf410e5acae 100644
--- a/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/media/sctp/sctpdataengine_unittest.cc
@@ -29,8 +29,9 @@
#include <stdarg.h>
#include <stdio.h>
#include <string>
+#include <vector>
-#include "talk/app/webrtc/datachannelinterface.h"
+#include "talk/base/bind.h"
#include "talk/base/buffer.h"
#include "talk/base/criticalsection.h"
#include "talk/base/gunit.h"
@@ -38,11 +39,11 @@
#include "talk/base/messagehandler.h"
#include "talk/base/messagequeue.h"
#include "talk/base/scoped_ptr.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/thread.h"
#include "talk/media/base/constants.h"
#include "talk/media/base/mediachannel.h"
#include "talk/media/sctp/sctpdataengine.h"
-#include "talk/media/sctp/sctputils.h"
enum {
MSG_PACKET = 1,
@@ -80,13 +81,13 @@ class SctpFakeNetworkInterface : public cricket::MediaChannel::NetworkInterface,
// an SCTP packet.
virtual void OnMessage(talk_base::Message* msg) {
LOG(LS_VERBOSE) << "SctpFakeNetworkInterface::OnMessage";
- talk_base::Buffer* buffer =
+ talk_base::scoped_ptr<talk_base::Buffer> buffer(
static_cast<talk_base::TypedMessageData<talk_base::Buffer*>*>(
- msg->pdata)->data();
+ msg->pdata)->data());
if (dest_) {
- dest_->OnPacketReceived(buffer, talk_base::PacketTime());
+ dest_->OnPacketReceived(buffer.get(), talk_base::PacketTime());
}
- delete buffer;
+ delete msg->pdata;
}
// Unsupported functions required to exist by NetworkInterface.
@@ -162,10 +163,69 @@ class SignalReadyToSendObserver : public sigslot::has_slots<> {
bool writable_;
};
+class SignalChannelClosedObserver : public sigslot::has_slots<> {
+ public:
+ SignalChannelClosedObserver() {}
+ void BindSelf(cricket::SctpDataMediaChannel* channel) {
+ channel->SignalStreamClosedRemotely.connect(
+ this, &SignalChannelClosedObserver::OnStreamClosed);
+ }
+ void OnStreamClosed(uint32 stream) {
+ streams_.push_back(stream);
+ }
+
+ int StreamCloseCount(uint32 stream) {
+ return std::count(streams_.begin(), streams_.end(), stream);
+ }
+
+ bool WasStreamClosed(uint32 stream) {
+ return std::find(streams_.begin(), streams_.end(), stream)
+ != streams_.end();
+ }
+
+ private:
+ std::vector<uint32> streams_;
+};
+
+class SignalChannelClosedReopener : public sigslot::has_slots<> {
+ public:
+ SignalChannelClosedReopener(cricket::SctpDataMediaChannel* channel,
+ cricket::SctpDataMediaChannel* peer)
+ : channel_(channel), peer_(peer) {}
+
+ void OnStreamClosed(int stream) {
+ cricket::StreamParams p(cricket::StreamParams::CreateLegacy(stream));
+ channel_->AddSendStream(p);
+ channel_->AddRecvStream(p);
+ peer_->AddSendStream(p);
+ peer_->AddRecvStream(p);
+ streams_.push_back(stream);
+ }
+
+ int StreamCloseCount(int stream) {
+ return std::count(streams_.begin(), streams_.end(), stream);
+ }
+
+ private:
+ cricket::SctpDataMediaChannel* channel_;
+ cricket::SctpDataMediaChannel* peer_;
+ std::vector<int> streams_;
+};
+
// SCTP Data Engine testing framework.
class SctpDataMediaChannelTest : public testing::Test,
public sigslot::has_slots<> {
protected:
+ // usrsctp uses the NSS random number generator on non-Android platforms,
+ // so we need to initialize SSL.
+ static void SetUpTestCase() {
+ talk_base::InitializeSSL();
+ }
+
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
+ }
+
virtual void SetUp() {
engine_.reset(new cricket::SctpDataEngine());
}
@@ -184,11 +244,8 @@ class SctpDataMediaChannelTest : public testing::Test,
net2_->SetDestination(chan1_.get());
LOG(LS_VERBOSE) << "Channel setup ----------------------------- ";
- chan1_->AddSendStream(cricket::StreamParams::CreateLegacy(1));
- chan2_->AddRecvStream(cricket::StreamParams::CreateLegacy(1));
-
- chan2_->AddSendStream(cricket::StreamParams::CreateLegacy(2));
- chan1_->AddRecvStream(cricket::StreamParams::CreateLegacy(2));
+ AddStream(1);
+ AddStream(2);
LOG(LS_VERBOSE) << "Connect the channels -----------------------------";
// chan1 wants to setup a data connection.
@@ -206,8 +263,21 @@ class SctpDataMediaChannelTest : public testing::Test,
chan1_->SetSend(true);
}
+ virtual void TearDown() {
+ channel1()->SetSend(false);
+ channel2()->SetSend(false);
+ }
+
+ void AddStream(int ssrc) {
+ cricket::StreamParams p(cricket::StreamParams::CreateLegacy(ssrc));
+ chan1_->AddSendStream(p);
+ chan1_->AddRecvStream(p);
+ chan2_->AddSendStream(p);
+ chan2_->AddRecvStream(p);
+ }
+
cricket::SctpDataMediaChannel* CreateChannel(
- SctpFakeNetworkInterface* net, SctpFakeDataReceiver* recv) {
+ SctpFakeNetworkInterface* net, SctpFakeDataReceiver* recv) {
cricket::SctpDataMediaChannel* channel =
static_cast<cricket::SctpDataMediaChannel*>(engine_->CreateChannel(
cricket::DCT_SCTP));
@@ -215,8 +285,6 @@ class SctpDataMediaChannelTest : public testing::Test,
// When data is received, pass it to the SctpFakeDataReceiver.
channel->SignalDataReceived.connect(
recv, &SctpFakeDataReceiver::OnDataReceived);
- channel->SignalNewStreamReceived.connect(
- this, &SctpDataMediaChannelTest::OnNewStreamReceived);
return channel;
}
@@ -225,7 +293,9 @@ class SctpDataMediaChannelTest : public testing::Test,
cricket::SendDataResult* result) {
cricket::SendDataParams params;
params.ssrc = ssrc;
- return chan->SendData(params, talk_base::Buffer(msg.data(), msg.length()), result);
+
+ return chan->SendData(params, talk_base::Buffer(
+ &msg[0], msg.length()), result);
}
bool ReceivedData(const SctpFakeDataReceiver* recv, uint32 ssrc,
@@ -251,14 +321,6 @@ class SctpDataMediaChannelTest : public testing::Test,
SctpFakeDataReceiver* receiver1() { return recv1_.get(); }
SctpFakeDataReceiver* receiver2() { return recv2_.get(); }
- void OnNewStreamReceived(const std::string& label,
- const webrtc::DataChannelInit& init) {
- last_label_ = label;
- last_dc_init_ = init;
- }
- std::string last_label() { return last_label_; }
- webrtc::DataChannelInit last_dc_init() { return last_dc_init_; }
-
private:
talk_base::scoped_ptr<cricket::SctpDataEngine> engine_;
talk_base::scoped_ptr<SctpFakeNetworkInterface> net1_;
@@ -267,8 +329,6 @@ class SctpDataMediaChannelTest : public testing::Test,
talk_base::scoped_ptr<SctpFakeDataReceiver> recv2_;
talk_base::scoped_ptr<cricket::SctpDataMediaChannel> chan1_;
talk_base::scoped_ptr<cricket::SctpDataMediaChannel> chan2_;
- std::string last_label_;
- webrtc::DataChannelInit last_dc_init_;
};
// Verifies that SignalReadyToSend is fired.
@@ -304,57 +364,139 @@ TEST_F(SctpDataMediaChannelTest, SendData) {
EXPECT_EQ(cricket::SDR_SUCCESS, result);
EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
LOG(LS_VERBOSE) << "recv2.received=" << receiver2()->received()
- << "recv2.last_params.ssrc="
+ << ", recv2.last_params.ssrc="
<< receiver2()->last_params().ssrc
- << "recv2.last_params.timestamp="
+ << ", recv2.last_params.timestamp="
<< receiver2()->last_params().ssrc
- << "recv2.last_params.seq_num="
+ << ", recv2.last_params.seq_num="
<< receiver2()->last_params().seq_num
- << "recv2.last_data=" << receiver2()->last_data();
+ << ", recv2.last_data=" << receiver2()->last_data();
LOG(LS_VERBOSE) << "chan2 sending: 'hi chan1' -----------------------------";
ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
EXPECT_EQ(cricket::SDR_SUCCESS, result);
EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
LOG(LS_VERBOSE) << "recv1.received=" << receiver1()->received()
- << "recv1.last_params.ssrc="
+ << ", recv1.last_params.ssrc="
<< receiver1()->last_params().ssrc
- << "recv1.last_params.timestamp="
+ << ", recv1.last_params.timestamp="
<< receiver1()->last_params().ssrc
- << "recv1.last_params.seq_num="
+ << ", recv1.last_params.seq_num="
<< receiver1()->last_params().seq_num
- << "recv1.last_data=" << receiver1()->last_data();
+ << ", recv1.last_data=" << receiver1()->last_data();
+}
+
+// Sends a lot of large messages at once and verifies SDR_BLOCK is returned.
+TEST_F(SctpDataMediaChannelTest, SendDataBlocked) {
+ SetupConnectedChannels();
+
+ cricket::SendDataResult result;
+ cricket::SendDataParams params;
+ params.ssrc = 1;
+
+ std::vector<char> buffer(1024 * 64, 0);
+
+ for (size_t i = 0; i < 100; ++i) {
+ channel1()->SendData(
+ params, talk_base::Buffer(&buffer[0], buffer.size()), &result);
+ if (result == cricket::SDR_BLOCK)
+ break;
+ }
+
+ EXPECT_EQ(cricket::SDR_BLOCK, result);
+}
+
+TEST_F(SctpDataMediaChannelTest, ClosesRemoteStream) {
+ SetupConnectedChannels();
+ SignalChannelClosedObserver chan_1_sig_receiver, chan_2_sig_receiver;
+ chan_1_sig_receiver.BindSelf(channel1());
+ chan_2_sig_receiver.BindSelf(channel2());
+
+ cricket::SendDataResult result;
+ ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
+ EXPECT_EQ(cricket::SDR_SUCCESS, result);
+ EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
+ ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
+ EXPECT_EQ(cricket::SDR_SUCCESS, result);
+ EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
- LOG(LS_VERBOSE) << "Closing down. -----------------------------";
- // Disconnects and closes socket, including setting receiving to false.
- channel1()->SetSend(false);
- channel2()->SetSend(false);
- LOG(LS_VERBOSE) << "Cleaning up. -----------------------------";
+ // Close channel 1. Channel 2 should notify us.
+ channel1()->RemoveSendStream(1);
+ EXPECT_TRUE_WAIT(chan_2_sig_receiver.WasStreamClosed(1), 1000);
}
-TEST_F(SctpDataMediaChannelTest, SendReceiveOpenMessage) {
+TEST_F(SctpDataMediaChannelTest, ClosesTwoRemoteStreams) {
SetupConnectedChannels();
+ AddStream(3);
+ SignalChannelClosedObserver chan_1_sig_receiver, chan_2_sig_receiver;
+ chan_1_sig_receiver.BindSelf(channel1());
+ chan_2_sig_receiver.BindSelf(channel2());
- std::string label("x");
- webrtc::DataChannelInit config;
- config.id = 10;
+ cricket::SendDataResult result;
+ ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
+ EXPECT_EQ(cricket::SDR_SUCCESS, result);
+ EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
+ ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
+ EXPECT_EQ(cricket::SDR_SUCCESS, result);
+ EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
- // Send the OPEN message on a unknown ssrc.
- channel1()->AddSendStream(cricket::StreamParams::CreateLegacy(config.id));
- cricket::SendDataParams params;
- params.ssrc = config.id;
- params.type = cricket::DMT_CONTROL;
+ // Close two streams on one side.
+ channel2()->RemoveSendStream(2);
+ channel2()->RemoveSendStream(3);
+ EXPECT_TRUE_WAIT(chan_1_sig_receiver.WasStreamClosed(2), 1000);
+ EXPECT_TRUE_WAIT(chan_1_sig_receiver.WasStreamClosed(3), 1000);
+}
+
+TEST_F(SctpDataMediaChannelTest, ClosesStreamsOnBothSides) {
+ SetupConnectedChannels();
+ AddStream(3);
+ AddStream(4);
+ SignalChannelClosedObserver chan_1_sig_receiver, chan_2_sig_receiver;
+ chan_1_sig_receiver.BindSelf(channel1());
+ chan_2_sig_receiver.BindSelf(channel2());
+
+ cricket::SendDataResult result;
+ ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
+ EXPECT_EQ(cricket::SDR_SUCCESS, result);
+ EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
+ ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
+ EXPECT_EQ(cricket::SDR_SUCCESS, result);
+ EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
+
+ // Close one stream on channel1(), while closing three streams on
+ // channel2(). They will conflict (only one side can close anything at a
+ // time, apparently). Test the resolution of the conflict.
+ channel1()->RemoveSendStream(1);
+
+ channel2()->RemoveSendStream(2);
+ channel2()->RemoveSendStream(3);
+ channel2()->RemoveSendStream(4);
+ EXPECT_TRUE_WAIT(chan_2_sig_receiver.WasStreamClosed(1), 1000);
+ EXPECT_TRUE_WAIT(chan_1_sig_receiver.WasStreamClosed(2), 1000);
+ EXPECT_TRUE_WAIT(chan_1_sig_receiver.WasStreamClosed(3), 1000);
+ EXPECT_TRUE_WAIT(chan_1_sig_receiver.WasStreamClosed(4), 1000);
+}
+
+TEST_F(SctpDataMediaChannelTest, ReusesAStream) {
+ // Shut down channel 1, then open it up again for reuse.
+ SetupConnectedChannels();
cricket::SendDataResult result;
- talk_base::Buffer buffer;
- ASSERT_TRUE(cricket::WriteDataChannelOpenMessage(label, config, &buffer));
- ASSERT_TRUE(channel1()->SendData(params, buffer, &result));
- // Send data on the new ssrc immediately after sending the OPEN message.
- ASSERT_TRUE(SendData(channel1(), config.id, "hi chan2", &result));
-
- // Verifies the received OPEN message.
- EXPECT_TRUE_WAIT(last_label() == label, 1000);
- EXPECT_EQ(config.id, last_dc_init().id);
- EXPECT_EQ(true, last_dc_init().negotiated);
- // Verifies the received data.
- EXPECT_TRUE_WAIT(ReceivedData(receiver2(), config.id, "hi chan2"), 1000);
+ SignalChannelClosedObserver chan_2_sig_receiver;
+ chan_2_sig_receiver.BindSelf(channel2());
+
+ ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
+ EXPECT_EQ(cricket::SDR_SUCCESS, result);
+ EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
+
+ channel1()->RemoveSendStream(1);
+ EXPECT_TRUE_WAIT(chan_2_sig_receiver.WasStreamClosed(1), 1000);
+ // Channel 1 is gone now.
+
+ // Create a new channel 1.
+ AddStream(1);
+ ASSERT_TRUE(SendData(channel1(), 1, "hi?", &result));
+ EXPECT_EQ(cricket::SDR_SUCCESS, result);
+ EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hi?"), 1000);
+ channel1()->RemoveSendStream(1);
+ EXPECT_TRUE_WAIT(chan_2_sig_receiver.StreamCloseCount(1) == 2, 1000);
}
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/OWNERS b/chromium/third_party/libjingle/source/talk/media/webrtc/OWNERS
new file mode 100644
index 00000000000..9a3546ef8b8
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/OWNERS
@@ -0,0 +1,3 @@
+mflodman@webrtc.org
+pthatcher@webrtc.org
+wu@webrtc.org
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvideocapturemodule.h b/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvideocapturemodule.h
index b823bc18fe6..347e4b713ed 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvideocapturemodule.h
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvideocapturemodule.h
@@ -59,21 +59,24 @@ class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule {
id_ = id;
return 0;
}
- virtual int32_t RegisterCaptureDataCallback(
+ virtual void RegisterCaptureDataCallback(
webrtc::VideoCaptureDataCallback& callback) {
callback_ = &callback;
- return 0;
}
- virtual int32_t DeRegisterCaptureDataCallback() {
- callback_ = NULL;
- return 0;
+ virtual void DeRegisterCaptureDataCallback() { callback_ = NULL; }
+ virtual void RegisterCaptureCallback(webrtc::VideoCaptureFeedBack& callback) {
+ // Not implemented.
}
- virtual int32_t RegisterCaptureCallback(
- webrtc::VideoCaptureFeedBack& callback) {
- return -1; // not implemented
+ virtual void DeRegisterCaptureCallback() {
+ // Not implemented.
}
- virtual int32_t DeRegisterCaptureCallback() {
- return 0;
+ virtual void SetCaptureDelay(int32_t delay) { delay_ = delay; }
+ virtual int32_t CaptureDelay() { return delay_; }
+ virtual void EnableFrameRateCallback(const bool enable) {
+ // not implemented
+ }
+ virtual void EnableNoPictureAlarm(const bool enable) {
+ // not implemented
}
virtual int32_t StartCapture(
const webrtc::VideoCaptureCapability& cap) {
@@ -98,13 +101,7 @@ class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule {
settings = cap_;
return 0;
}
- virtual int32_t SetCaptureDelay(int32_t delay) {
- delay_ = delay;
- return 0;
- }
- virtual int32_t CaptureDelay() {
- return delay_;
- }
+
virtual int32_t SetCaptureRotation(
webrtc::VideoCaptureRotation rotation) {
return -1; // not implemented
@@ -113,12 +110,6 @@ class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule {
const webrtc::VideoCodec& codec) {
return NULL; // not implemented
}
- virtual int32_t EnableFrameRateCallback(const bool enable) {
- return -1; // not implemented
- }
- virtual int32_t EnableNoPictureAlarm(const bool enable) {
- return -1; // not implemented
- }
virtual int32_t AddRef() {
return 0;
}
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvideoengine.h b/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvideoengine.h
index bb75c2a7feb..85c59d83860 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvideoengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvideoengine.h
@@ -41,14 +41,6 @@
#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
#include "talk/media/webrtc/webrtcvie.h"
-namespace webrtc {
-
-bool operator==(const webrtc::VideoCodec& c1, const webrtc::VideoCodec& c2) {
- return memcmp(&c1, &c2, sizeof(c1)) == 0;
-}
-
-}
-
namespace cricket {
#define WEBRTC_CHECK_CAPTURER(capturer) \
@@ -279,15 +271,16 @@ class FakeWebRtcVideoEngine
can_transmit_(true),
remote_rtx_ssrc_(-1),
rtx_send_payload_type(-1),
+ rtx_recv_payload_type(-1),
rtcp_status_(webrtc::kRtcpNone),
key_frame_request_method_(webrtc::kViEKeyFrameRequestNone),
tmmbr_(false),
remb_contribute_(false),
remb_bw_partition_(false),
- rtp_offset_send_id_(0),
- rtp_offset_receive_id_(0),
- rtp_absolute_send_time_send_id_(0),
- rtp_absolute_send_time_receive_id_(0),
+ rtp_offset_send_id_(-1),
+ rtp_offset_receive_id_(-1),
+ rtp_absolute_send_time_send_id_(-1),
+ rtp_absolute_send_time_receive_id_(-1),
sender_target_delay_(0),
receiver_target_delay_(0),
transmission_smoothing_(false),
@@ -297,9 +290,14 @@ class FakeWebRtcVideoEngine
send_fec_bitrate_(0),
send_nack_bitrate_(0),
send_bandwidth_(0),
- receive_bandwidth_(0) {
+ receive_bandwidth_(0),
+ reserved_transmit_bitrate_bps_(0),
+ suspend_below_min_bitrate_(false),
+ overuse_observer_(NULL),
+ last_recvd_payload_type_(-1) {
ssrcs_[0] = 0; // default ssrc.
memset(&send_codec, 0, sizeof(send_codec));
+ memset(&overuse_options_, 0, sizeof(overuse_options_));
}
int capture_id_;
int original_channel_id_;
@@ -312,6 +310,7 @@ class FakeWebRtcVideoEngine
std::map<int, int> rtx_ssrcs_;
int remote_rtx_ssrc_;
int rtx_send_payload_type;
+ int rtx_recv_payload_type;
std::string cname_;
webrtc::ViERTCPMode rtcp_status_;
webrtc::ViEKeyFrameRequestMethod key_frame_request_method_;
@@ -336,6 +335,11 @@ class FakeWebRtcVideoEngine
unsigned int send_nack_bitrate_;
unsigned int send_bandwidth_;
unsigned int receive_bandwidth_;
+ unsigned int reserved_transmit_bitrate_bps_;
+ bool suspend_below_min_bitrate_;
+ webrtc::CpuOveruseObserver* overuse_observer_;
+ webrtc::CpuOveruseOptions overuse_options_;
+ int last_recvd_payload_type_;
};
class Capturer : public webrtc::ViEExternalCapture {
public:
@@ -425,7 +429,7 @@ class FakeWebRtcVideoEngine
void set_fail_alloc_capturer(bool fail_alloc_capturer) {
fail_alloc_capturer_ = fail_alloc_capturer;
}
- int num_set_send_codecs() const { return num_set_send_codecs_; }
+ int GetNumSetSendCodecs() const { return num_set_send_codecs_; }
int GetCaptureId(int channel) const {
WEBRTC_ASSERT_CHANNEL(channel);
@@ -447,6 +451,10 @@ class FakeWebRtcVideoEngine
WEBRTC_ASSERT_CHANNEL(channel);
return channels_.find(channel)->second->send;
}
+ bool GetReceive(int channel) const {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ return channels_.find(channel)->second->receive_;
+ }
int GetCaptureChannelId(int capture_id) const {
WEBRTC_ASSERT_CAPTURER(capture_id);
return capturers_.find(capture_id)->second->channel_id();
@@ -479,21 +487,24 @@ class FakeWebRtcVideoEngine
WEBRTC_ASSERT_CHANNEL(channel);
return channels_.find(channel)->second->remb_contribute_;
}
- int GetSendRtpTimestampOffsetExtensionId(int channel) {
- WEBRTC_ASSERT_CHANNEL(channel);
- return channels_.find(channel)->second->rtp_offset_send_id_;
- }
- int GetReceiveRtpTimestampOffsetExtensionId(int channel) {
+ int GetSendRtpExtensionId(int channel, const std::string& extension) {
WEBRTC_ASSERT_CHANNEL(channel);
- return channels_.find(channel)->second->rtp_offset_receive_id_;
- }
- int GetSendAbsoluteSendTimeExtensionId(int channel) {
- WEBRTC_ASSERT_CHANNEL(channel);
- return channels_.find(channel)->second->rtp_absolute_send_time_send_id_;
+ if (extension == kRtpTimestampOffsetHeaderExtension) {
+ return channels_.find(channel)->second->rtp_offset_send_id_;
+ } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) {
+ return channels_.find(channel)->second->rtp_absolute_send_time_send_id_;
+ }
+ return -1;
}
- int GetReceiveAbsoluteSendTimeExtensionId(int channel) {
+ int GetReceiveRtpExtensionId(int channel, const std::string& extension) {
WEBRTC_ASSERT_CHANNEL(channel);
- return channels_.find(channel)->second->rtp_absolute_send_time_receive_id_;
+ if (extension == kRtpTimestampOffsetHeaderExtension) {
+ return channels_.find(channel)->second->rtp_offset_receive_id_;
+ } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) {
+ return
+ channels_.find(channel)->second->rtp_absolute_send_time_receive_id_;
+ }
+ return -1;
}
bool GetTransmissionSmoothingStatus(int channel) {
WEBRTC_ASSERT_CHANNEL(channel);
@@ -529,6 +540,14 @@ class FakeWebRtcVideoEngine
WEBRTC_ASSERT_CHANNEL(channel);
return channels_.find(channel)->second->can_transmit_;
}
+ webrtc::CpuOveruseObserver* GetCpuOveruseObserver(int channel) const {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ return channels_.find(channel)->second->overuse_observer_;
+ }
+ webrtc::CpuOveruseOptions GetCpuOveruseOptions(int channel) const {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ return channels_.find(channel)->second->overuse_options_;
+ }
int GetRtxSsrc(int channel, int simulcast_idx) const {
WEBRTC_ASSERT_CHANNEL(channel);
if (channels_.find(channel)->second->rtx_ssrcs_.find(simulcast_idx) ==
@@ -583,21 +602,38 @@ class FakeWebRtcVideoEngine
}
void SetSendBandwidthEstimate(int channel, unsigned int send_bandwidth) {
WEBRTC_ASSERT_CHANNEL(channel);
- channels_[channel]->send_bandwidth_ = send_bandwidth;
+ channels_[GetOriginalChannelId(channel)]->send_bandwidth_ = send_bandwidth;
}
void SetReceiveBandwidthEstimate(int channel,
unsigned int receive_bandwidth) {
WEBRTC_ASSERT_CHANNEL(channel);
- channels_[channel]->receive_bandwidth_ = receive_bandwidth;
+ channels_[GetOriginalChannelId(channel)]->receive_bandwidth_ =
+ receive_bandwidth;
};
int GetRtxSendPayloadType(int channel) {
WEBRTC_CHECK_CHANNEL(channel);
return channels_[channel]->rtx_send_payload_type;
}
+ int GetRtxRecvPayloadType(int channel) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ return channels_[channel]->rtx_recv_payload_type;
+ }
int GetRemoteRtxSsrc(int channel) {
WEBRTC_CHECK_CHANNEL(channel);
return channels_.find(channel)->second->remote_rtx_ssrc_;
}
+ bool GetSuspendBelowMinBitrateStatus(int channel) {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ return channels_.find(channel)->second->suspend_below_min_bitrate_;
+ }
+ int GetLastRecvdPayloadType(int channel) const {
+ WEBRTC_CHECK_CHANNEL(channel);
+ return channels_.find(channel)->second->last_recvd_payload_type_;
+ }
+ unsigned int GetReservedTransmitBitrate(int channel) {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ return channels_.find(channel)->second->reserved_transmit_bitrate_bps_;
+ }
WEBRTC_STUB(Release, ());
@@ -615,7 +651,11 @@ class FakeWebRtcVideoEngine
return -1;
}
Channel* ch = new Channel();
- channels_[++last_channel_] = ch;
+ ++last_channel_;
+ // The original channel of the first channel in a group refers to itself
+ // for code simplicity.
+ ch->original_channel_id_ = last_channel_;
+ channels_[last_channel_] = ch;
channel = last_channel_;
return 0;
};
@@ -638,11 +678,19 @@ class FakeWebRtcVideoEngine
channels_.erase(channel);
return 0;
}
- WEBRTC_STUB(RegisterCpuOveruseObserver,
- (int channel, webrtc::CpuOveruseObserver* observer));
-#ifdef USE_WEBRTC_DEV_BRANCH
+ WEBRTC_FUNC(RegisterCpuOveruseObserver,
+ (int channel, webrtc::CpuOveruseObserver* observer)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ channels_[channel]->overuse_observer_ = observer;
+ return 0;
+ }
WEBRTC_STUB(CpuOveruseMeasures, (int, int*, int*, int*, int*));
-#endif
+ WEBRTC_FUNC(SetCpuOveruseOptions,
+ (int channel, const webrtc::CpuOveruseOptions& options)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ channels_[channel]->overuse_options_ = options;
+ return 0;
+ }
WEBRTC_STUB(ConnectAudioChannel, (const int, const int));
WEBRTC_STUB(DisconnectAudioChannel, (const int));
WEBRTC_FUNC(StartSend, (const int channel)) {
@@ -760,7 +808,10 @@ class FakeWebRtcVideoEngine
WEBRTC_STUB(WaitForFirstKeyFrame, (const int, const bool));
WEBRTC_STUB(StartDebugRecording, (int, const char*));
WEBRTC_STUB(StopDebugRecording, (int));
- WEBRTC_VOID_STUB(SuspendBelowMinBitrate, (int));
+ WEBRTC_VOID_FUNC(SuspendBelowMinBitrate, (int channel)) {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ channels_[channel]->suspend_below_min_bitrate_ = true;
+ }
// webrtc::ViECapture
WEBRTC_STUB(NumberOfCaptureDevices, ());
@@ -827,16 +878,24 @@ class FakeWebRtcVideoEngine
}
WEBRTC_STUB(RegisterSendTransport, (const int, webrtc::Transport&));
WEBRTC_STUB(DeregisterSendTransport, (const int));
-#ifdef USE_WEBRTC_DEV_BRANCH
- WEBRTC_STUB(ReceivedRTPPacket, (const int, const void*, const int,
- const webrtc::PacketTime&));
-#else
- WEBRTC_STUB(ReceivedRTPPacket, (const int, const void*, const int));
-#endif
+
+ WEBRTC_FUNC(ReceivedRTPPacket, (const int channel,
+ const void* packet,
+ const int length,
+ const webrtc::PacketTime& packet_time)) {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ ASSERT(length > 1);
+ uint8_t payload_type = static_cast<const uint8_t*>(packet)[1] & 0x7F;
+ channels_[channel]->last_recvd_payload_type_ = payload_type;
+ return 0;
+ }
+
WEBRTC_STUB(ReceivedRTCPPacket, (const int, const void*, const int));
// Not using WEBRTC_STUB due to bool return value
virtual bool IsIPv6Enabled(int channel) { return true; }
WEBRTC_STUB(SetMTU, (int, unsigned int));
+ WEBRTC_STUB(ReceivedBWEPacket, (const int, int64_t, int,
+ const webrtc::RTPHeader&));
// webrtc::ViERender
WEBRTC_STUB(RegisterVideoRenderModule, (webrtc::VideoRender&));
@@ -940,7 +999,17 @@ class FakeWebRtcVideoEngine
channels_[channel]->rtx_send_payload_type = payload_type;
return 0;
}
- WEBRTC_STUB(SetRtxReceivePayloadType, (const int, const uint8));
+
+#ifdef USE_WEBRTC_DEV_BRANCH
+ WEBRTC_STUB(SetPadWithRedundantPayloads, (int, bool));
+#endif
+
+ WEBRTC_FUNC(SetRtxReceivePayloadType, (const int channel,
+ const uint8 payload_type)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ channels_[channel]->rtx_recv_payload_type = payload_type;
+ return 0;
+ }
WEBRTC_STUB(SetStartSequenceNumber, (const int, unsigned short));
WEBRTC_FUNC(SetRTCPStatus,
@@ -1019,35 +1088,42 @@ class FakeWebRtcVideoEngine
WEBRTC_FUNC(SetSendTimestampOffsetStatus, (int channel, bool enable,
int id)) {
WEBRTC_CHECK_CHANNEL(channel);
- channels_[channel]->rtp_offset_send_id_ = (enable) ? id : 0;
+ channels_[channel]->rtp_offset_send_id_ = (enable) ? id : -1;
return 0;
}
WEBRTC_FUNC(SetReceiveTimestampOffsetStatus, (int channel, bool enable,
int id)) {
WEBRTC_CHECK_CHANNEL(channel);
- channels_[channel]->rtp_offset_receive_id_ = (enable) ? id : 0;
+ channels_[channel]->rtp_offset_receive_id_ = (enable) ? id : -1;
return 0;
}
WEBRTC_FUNC(SetSendAbsoluteSendTimeStatus, (int channel, bool enable,
int id)) {
WEBRTC_CHECK_CHANNEL(channel);
- channels_[channel]->rtp_absolute_send_time_send_id_ = (enable) ? id : 0;
+ channels_[channel]->rtp_absolute_send_time_send_id_ = (enable) ? id : -1;
return 0;
}
WEBRTC_FUNC(SetReceiveAbsoluteSendTimeStatus, (int channel, bool enable,
int id)) {
WEBRTC_CHECK_CHANNEL(channel);
- channels_[channel]->rtp_absolute_send_time_receive_id_ = (enable) ? id : 0;
+ channels_[channel]->rtp_absolute_send_time_receive_id_ = (enable) ? id : -1;
return 0;
}
-#ifdef USE_WEBRTC_DEV_BRANCH
WEBRTC_STUB(SetRtcpXrRrtrStatus, (int, bool));
-#endif
WEBRTC_FUNC(SetTransmissionSmoothingStatus, (int channel, bool enable)) {
WEBRTC_CHECK_CHANNEL(channel);
channels_[channel]->transmission_smoothing_ = enable;
return 0;
}
+ WEBRTC_FUNC(SetReservedTransmitBitrate, (int channel,
+ unsigned int reserved_transmit_bitrate_bps)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ channels_[channel]->reserved_transmit_bitrate_bps_ =
+ reserved_transmit_bitrate_bps;
+ return 0;
+ }
+ WEBRTC_STUB_CONST(GetRtcpPacketTypeCounters, (int,
+ webrtc::RtcpPacketTypeCounter*, webrtc::RtcpPacketTypeCounter*));
WEBRTC_STUB_CONST(GetReceivedRTCPStatistics, (const int, unsigned short&,
unsigned int&, unsigned int&, unsigned int&, int&));
WEBRTC_STUB_CONST(GetSentRTCPStatistics, (const int, unsigned short&,
@@ -1084,6 +1160,7 @@ class FakeWebRtcVideoEngine
std::map<int, Channel*>::const_iterator it = channels_.find(channel);
// Assume the current video, fec and nack bitrate sums up to our estimate.
if (it->second->send) {
+ it = channels_.find(GetOriginalChannelId(channel));
*send_bandwidth_estimate = it->second->send_bandwidth_;
} else {
*send_bandwidth_estimate = 0;
@@ -1095,7 +1172,7 @@ class FakeWebRtcVideoEngine
WEBRTC_CHECK_CHANNEL(channel);
std::map<int, Channel*>::const_iterator it = channels_.find(channel);
if (it->second->receive_) {
- // For simplicity, assume all channels receive half of max send rate.
+ it = channels_.find(GetOriginalChannelId(channel));
*receive_bandwidth_estimate = it->second->receive_bandwidth_;
} else {
*receive_bandwidth_estimate = 0;
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvoiceengine.h b/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvoiceengine.h
index a68d65ef750..25c952d33ec 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvoiceengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/fakewebrtcvoiceengine.h
@@ -32,16 +32,18 @@
#include <map>
#include <vector>
-
#include "talk/base/basictypes.h"
#include "talk/base/gunit.h"
#include "talk/base/stringutils.h"
#include "talk/media/base/codec.h"
+#include "talk/media/base/rtputils.h"
#include "talk/media/base/voiceprocessor.h"
#include "talk/media/webrtc/fakewebrtccommon.h"
#include "talk/media/webrtc/webrtcvoe.h"
-#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
-#include "webrtc/common.h"
+
+namespace webrtc {
+class ViENetwork;
+}
namespace cricket {
@@ -59,6 +61,14 @@ static const int kFakeDeviceId = 0;
static const int kFakeDeviceId = 1;
#endif
+// Verify the header extension ID, if enabled, is within the bounds specified in
+// [RFC5285]: 1-14 inclusive.
+#define WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id) \
+ do { \
+ if (enable && (id < 1 || id > 14)) { \
+ return -1; \
+ } \
+ } while (0);
class FakeWebRtcVoiceEngine
: public webrtc::VoEAudioProcessing,
@@ -78,7 +88,7 @@ class FakeWebRtcVoiceEngine
int dtmf_length_ms;
};
struct Channel {
- explicit Channel(bool use_experimental_acm)
+ explicit Channel()
: external_transport(false),
send(false),
playout(false),
@@ -87,7 +97,8 @@ class FakeWebRtcVoiceEngine
volume_pan_right(1.0),
file(false),
vad(false),
- fec(false),
+ codec_fec(false),
+ red(false),
nack(false),
media_processor_registered(false),
rx_agc_enabled(false),
@@ -95,11 +106,15 @@ class FakeWebRtcVoiceEngine
cn8_type(13),
cn16_type(105),
dtmf_type(106),
- fec_type(117),
+ red_type(117),
nack_max_packets(0),
+ vie_network(NULL),
+ video_channel(-1),
send_ssrc(0),
- level_header_ext_(-1),
- using_experimental_acm(use_experimental_acm) {
+ send_audio_level_ext_(-1),
+ receive_audio_level_ext_(-1),
+ send_absolute_sender_time_ext_(-1),
+ receive_absolute_sender_time_ext_(-1) {
memset(&send_codec, 0, sizeof(send_codec));
memset(&rx_agc_config, 0, sizeof(rx_agc_config));
}
@@ -111,7 +126,8 @@ class FakeWebRtcVoiceEngine
float volume_pan_right;
bool file;
bool vad;
- bool fec;
+ bool codec_fec;
+ bool red;
bool nack;
bool media_processor_registered;
bool rx_agc_enabled;
@@ -120,15 +136,20 @@ class FakeWebRtcVoiceEngine
int cn8_type;
int cn16_type;
int dtmf_type;
- int fec_type;
+ int red_type;
int nack_max_packets;
+ webrtc::ViENetwork* vie_network;
+ int video_channel;
uint32 send_ssrc;
- int level_header_ext_;
+ int send_audio_level_ext_;
+ int receive_audio_level_ext_;
+ int send_absolute_sender_time_ext_;
+ int receive_absolute_sender_time_ext_;
DtmfInfo dtmf_info;
std::vector<webrtc::CodecInst> recv_codecs;
webrtc::CodecInst send_codec;
+ webrtc::PacketTime last_rtp_packet_time;
std::list<std::string> packets;
- bool using_experimental_acm;
};
FakeWebRtcVoiceEngine(const cricket::AudioCodec* const* codecs,
@@ -138,6 +159,7 @@ class FakeWebRtcVoiceEngine
fail_create_channel_(false),
codecs_(codecs),
num_codecs_(num_codecs),
+ num_set_send_codecs_(0),
ec_enabled_(false),
ec_metrics_enabled_(false),
cng_enabled_(false),
@@ -195,8 +217,11 @@ class FakeWebRtcVoiceEngine
bool GetVAD(int channel) {
return channels_[channel]->vad;
}
- bool GetFEC(int channel) {
- return channels_[channel]->fec;
+ bool GetRED(int channel) {
+ return channels_[channel]->red;
+ }
+ bool GetCodecFEC(int channel) {
+ return channels_[channel]->codec_fec;
}
bool GetNACK(int channel) {
return channels_[channel]->nack;
@@ -204,9 +229,17 @@ class FakeWebRtcVoiceEngine
int GetNACKMaxPackets(int channel) {
return channels_[channel]->nack_max_packets;
}
- bool IsUsingExperimentalAcm(int channel) {
+ webrtc::ViENetwork* GetViENetwork(int channel) {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ return channels_[channel]->vie_network;
+ }
+ int GetVideoChannel(int channel) {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ return channels_[channel]->video_channel;
+ }
+ const webrtc::PacketTime& GetLastRtpPacketTime(int channel) {
WEBRTC_ASSERT_CHANNEL(channel);
- return channels_[channel]->using_experimental_acm;
+ return channels_[channel]->last_rtp_packet_time;
}
int GetSendCNPayloadType(int channel, bool wideband) {
return (wideband) ?
@@ -216,8 +249,8 @@ class FakeWebRtcVoiceEngine
int GetSendTelephoneEventPayloadType(int channel) {
return channels_[channel]->dtmf_type;
}
- int GetSendFECPayloadType(int channel) {
- return channels_[channel]->fec_type;
+ int GetSendREDPayloadType(int channel) {
+ return channels_[channel]->red_type;
}
bool CheckPacket(int channel, const void* data, size_t len) {
bool result = !CheckNoPacket(channel);
@@ -261,11 +294,11 @@ class FakeWebRtcVoiceEngine
true);
}
}
- int AddChannel(bool use_experimental_acm) {
+ int AddChannel() {
if (fail_create_channel_) {
return -1;
}
- Channel* ch = new Channel(use_experimental_acm);
+ Channel* ch = new Channel();
for (int i = 0; i < NumOfCodecs(); ++i) {
webrtc::CodecInst codec;
GetCodec(i, codec);
@@ -274,6 +307,26 @@ class FakeWebRtcVoiceEngine
channels_[++last_channel_] = ch;
return last_channel_;
}
+ int GetSendRtpExtensionId(int channel, const std::string& extension) {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ if (extension == kRtpAudioLevelHeaderExtension) {
+ return channels_[channel]->send_audio_level_ext_;
+ } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) {
+ return channels_[channel]->send_absolute_sender_time_ext_;
+ }
+ return -1;
+ }
+ int GetReceiveRtpExtensionId(int channel, const std::string& extension) {
+ WEBRTC_ASSERT_CHANNEL(channel);
+ if (extension == kRtpAudioLevelHeaderExtension) {
+ return channels_[channel]->receive_audio_level_ext_;
+ } else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) {
+ return channels_[channel]->receive_absolute_sender_time_ext_;
+ }
+ return -1;
+ }
+
+ int GetNumSetSendCodecs() const { return num_set_send_codecs_; }
WEBRTC_STUB(Release, ());
@@ -297,13 +350,10 @@ class FakeWebRtcVoiceEngine
return NULL;
}
WEBRTC_FUNC(CreateChannel, ()) {
- return AddChannel(false);
+ return AddChannel();
}
- WEBRTC_FUNC(CreateChannel, (const webrtc::Config& config)) {
- talk_base::scoped_ptr<webrtc::AudioCodingModule> acm(
- config.Get<webrtc::AudioCodingModuleFactory>().Create(0));
- return AddChannel(strcmp(acm->Version(), webrtc::kExperimentalAcmVersion)
- == 0);
+ WEBRTC_FUNC(CreateChannel, (const webrtc::Config& /*config*/)) {
+ return AddChannel();
}
WEBRTC_FUNC(DeleteChannel, (int channel)) {
WEBRTC_CHECK_CHANNEL(channel);
@@ -371,7 +421,15 @@ class FakeWebRtcVoiceEngine
}
WEBRTC_FUNC(SetSendCodec, (int channel, const webrtc::CodecInst& codec)) {
WEBRTC_CHECK_CHANNEL(channel);
+ // To match the behavior of the real implementation.
+ if (_stricmp(codec.plname, "telephone-event") == 0 ||
+ _stricmp(codec.plname, "audio/telephone-event") == 0 ||
+ _stricmp(codec.plname, "CN") == 0 ||
+ _stricmp(codec.plname, "red") == 0 ) {
+ return -1;
+ }
channels_[channel]->send_codec = codec;
+ ++num_set_send_codecs_;
return 0;
}
WEBRTC_FUNC(GetSendCodec, (int channel, webrtc::CodecInst& codec)) {
@@ -385,7 +443,26 @@ class FakeWebRtcVoiceEngine
WEBRTC_STUB(RemoveSecondarySendCodec, (int channel));
WEBRTC_STUB(GetSecondarySendCodec, (int channel,
webrtc::CodecInst& codec));
- WEBRTC_STUB(GetRecCodec, (int channel, webrtc::CodecInst& codec));
+ WEBRTC_FUNC(GetRecCodec, (int channel, webrtc::CodecInst& codec)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ const Channel* c = channels_[channel];
+ for (std::list<std::string>::const_iterator it_packet = c->packets.begin();
+ it_packet != c->packets.end(); ++it_packet) {
+ int pltype;
+ if (!GetRtpPayloadType(it_packet->data(), it_packet->length(), &pltype)) {
+ continue;
+ }
+ for (std::vector<webrtc::CodecInst>::const_iterator it_codec =
+ c->recv_codecs.begin(); it_codec != c->recv_codecs.end();
+ ++it_codec) {
+ if (it_codec->pltype == pltype) {
+ codec = *it_codec;
+ return 0;
+ }
+ }
+ }
+ return -1;
+ }
WEBRTC_STUB(SetAMREncFormat, (int channel, webrtc::AmrMode mode));
WEBRTC_STUB(SetAMRDecFormat, (int channel, webrtc::AmrMode mode));
WEBRTC_STUB(SetAMRWbEncFormat, (int channel, webrtc::AmrMode mode));
@@ -459,6 +536,18 @@ class FakeWebRtcVoiceEngine
}
WEBRTC_STUB(GetVADStatus, (int channel, bool& enabled,
webrtc::VadModes& mode, bool& disabledDTX));
+#ifdef USE_WEBRTC_DEV_BRANCH
+ WEBRTC_FUNC(SetFECStatus, (int channel, bool enable)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ channels_[channel]->codec_fec = enable;
+ return 0;
+ }
+ WEBRTC_FUNC(GetFECStatus, (int channel, bool& enable)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ enable = channels_[channel]->codec_fec;
+ return 0;
+ }
+#endif // USE_WEBRTC_DEV_BRANCH
// webrtc::VoEDtmf
WEBRTC_FUNC(SendTelephoneEvent, (int channel, int event_code,
@@ -482,7 +571,6 @@ class FakeWebRtcVoiceEngine
WEBRTC_STUB(SetDtmfPlayoutStatus, (int channel, bool enable));
WEBRTC_STUB(GetDtmfPlayoutStatus, (int channel, bool& enabled));
-
WEBRTC_FUNC(PlayDtmfTone,
(int event_code, int length_ms = 200, int attenuation_db = 10)) {
dtmf_info_.dtmf_event_code = event_code;
@@ -631,13 +719,11 @@ class FakeWebRtcVoiceEngine
// webrtc::VoENetEqStats
WEBRTC_STUB(GetNetworkStatistics, (int, webrtc::NetworkStatistics&));
-#ifdef USE_WEBRTC_DEV_BRANCH
WEBRTC_FUNC_CONST(GetDecodingCallStatistics, (int channel,
webrtc::AudioDecodingCallStats*)) {
WEBRTC_CHECK_CHANNEL(channel);
return 0;
}
-#endif
// webrtc::VoENetwork
WEBRTC_FUNC(RegisterExternalTransport, (int channel,
@@ -659,6 +745,17 @@ class FakeWebRtcVoiceEngine
std::string(static_cast<const char*>(data), length));
return 0;
}
+ WEBRTC_FUNC(ReceivedRTPPacket, (int channel, const void* data,
+ unsigned int length,
+ const webrtc::PacketTime& packet_time)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ if (ReceivedRTPPacket(channel, data, length) == -1) {
+ return -1;
+ }
+ channels_[channel]->last_rtp_packet_time = packet_time;
+ return 0;
+ }
+
WEBRTC_STUB(ReceivedRTCPPacket, (int channel, const void* data,
unsigned int length));
@@ -680,24 +777,37 @@ class FakeWebRtcVoiceEngine
return 0;
}
WEBRTC_STUB(GetRemoteSSRC, (int channel, unsigned int& ssrc));
- WEBRTC_FUNC(SetRTPAudioLevelIndicationStatus, (int channel, bool enable,
+ WEBRTC_FUNC(SetSendAudioLevelIndicationStatus, (int channel, bool enable,
unsigned char id)) {
WEBRTC_CHECK_CHANNEL(channel);
- if (enable && (id < 1 || id > 14)) {
- // [RFC5285] The 4-bit ID is the local identifier of this element in
- // the range 1-14 inclusive.
- return -1;
- }
- channels_[channel]->level_header_ext_ = (enable) ? id : -1;
+ WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id);
+ channels_[channel]->send_audio_level_ext_ = (enable) ? id : -1;
+ return 0;
+ }
+#ifdef USE_WEBRTC_DEV_BRANCH
+ WEBRTC_FUNC(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable,
+ unsigned char id)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id);
+ channels_[channel]->receive_audio_level_ext_ = (enable) ? id : -1;
+ return 0;
+ }
+#endif // USE_WEBRTC_DEV_BRANCH
+ WEBRTC_FUNC(SetSendAbsoluteSenderTimeStatus, (int channel, bool enable,
+ unsigned char id)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id);
+ channels_[channel]->send_absolute_sender_time_ext_ = (enable) ? id : -1;
return 0;
}
- WEBRTC_FUNC(GetRTPAudioLevelIndicationStatus, (int channel, bool& enabled,
- unsigned char& id)) {
+ WEBRTC_FUNC(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable,
+ unsigned char id)) {
WEBRTC_CHECK_CHANNEL(channel);
- enabled = (channels_[channel]->level_header_ext_ != -1);
- id = channels_[channel]->level_header_ext_;
+ WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id);
+ channels_[channel]->receive_absolute_sender_time_ext_ = (enable) ? id : -1;
return 0;
}
+
WEBRTC_STUB(GetRemoteCSRCs, (int channel, unsigned int arrCSRC[15]));
WEBRTC_STUB(SetRTCPStatus, (int channel, bool enable));
WEBRTC_STUB(GetRTCPStatus, (int channel, bool& enabled));
@@ -750,16 +860,24 @@ class FakeWebRtcVoiceEngine
stats.packetsReceived = kIntStatValue;
return 0;
}
+#ifdef USE_WEBRTC_DEV_BRANCH
+ WEBRTC_FUNC(SetREDStatus, (int channel, bool enable, int redPayloadtype)) {
+#else
WEBRTC_FUNC(SetFECStatus, (int channel, bool enable, int redPayloadtype)) {
+#endif // USE_WEBRTC_DEV_BRANCH
WEBRTC_CHECK_CHANNEL(channel);
- channels_[channel]->fec = enable;
- channels_[channel]->fec_type = redPayloadtype;
+ channels_[channel]->red = enable;
+ channels_[channel]->red_type = redPayloadtype;
return 0;
}
+#ifdef USE_WEBRTC_DEV_BRANCH
+ WEBRTC_FUNC(GetREDStatus, (int channel, bool& enable, int& redPayloadtype)) {
+#else
WEBRTC_FUNC(GetFECStatus, (int channel, bool& enable, int& redPayloadtype)) {
+#endif // USE_WEBRTC_DEV_BRANCH
WEBRTC_CHECK_CHANNEL(channel);
- enable = channels_[channel]->fec;
- redPayloadtype = channels_[channel]->fec_type;
+ enable = channels_[channel]->red;
+ redPayloadtype = channels_[channel]->red_type;
return 0;
}
WEBRTC_FUNC(SetNACKStatus, (int channel, bool enable, int maxNoPackets)) {
@@ -777,6 +895,14 @@ class FakeWebRtcVoiceEngine
unsigned short payloadSize));
WEBRTC_STUB(GetLastRemoteTimeStamp, (int channel,
uint32_t* lastRemoteTimeStamp));
+ WEBRTC_FUNC(SetVideoEngineBWETarget, (int channel,
+ webrtc::ViENetwork* vie_network,
+ int video_channel)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ channels_[channel]->vie_network = vie_network;
+ channels_[channel]->video_channel = video_channel;
+ return 0;
+ }
// webrtc::VoEVideoSync
WEBRTC_STUB(GetPlayoutBufferSize, (int& bufferMs));
@@ -923,9 +1049,7 @@ class FakeWebRtcVoiceEngine
WEBRTC_STUB(GetEcDelayMetrics, (int& delay_median, int& delay_std));
WEBRTC_STUB(StartDebugRecording, (const char* fileNameUTF8));
-#ifdef USE_WEBRTC_DEV_BRANCH
WEBRTC_STUB(StartDebugRecording, (FILE* handle));
-#endif
WEBRTC_STUB(StopDebugRecording, ());
WEBRTC_FUNC(SetTypingDetectionStatus, (bool enable)) {
@@ -1041,6 +1165,7 @@ class FakeWebRtcVoiceEngine
bool fail_create_channel_;
const cricket::AudioCodec* const* codecs_;
int num_codecs_;
+ int num_set_send_codecs_; // how many times we call SetSendCodec().
bool ec_enabled_;
bool ec_metrics_enabled_;
bool cng_enabled_;
@@ -1065,6 +1190,8 @@ class FakeWebRtcVoiceEngine
webrtc::VoEMediaProcess* media_processor_;
};
+#undef WEBRTC_CHECK_HEADER_EXTENSION_ID
+
} // namespace cricket
#endif // TALK_SESSION_PHONE_FAKEWEBRTCVOICEENGINE_H_
diff --git a/chromium/third_party/libjingle/source/talk/examples/chat/textchatreceivetask.cc b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcmediaengine.cc
index cbd019c7e35..445564c82ae 100644
--- a/chromium/third_party/libjingle/source/talk/examples/chat/textchatreceivetask.cc
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcmediaengine.cc
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2013, Google Inc.
+ * Copyright 2014 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,42 +25,34 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "talk/examples/chat/textchatreceivetask.h"
-
-#include "talk/xmpp/constants.h"
-
-namespace buzz {
-
-TextChatReceiveTask::TextChatReceiveTask(XmppTaskParentInterface* parent)
- : XmppTask(parent, XmppEngine::HL_TYPE) {
-}
-
-TextChatReceiveTask::~TextChatReceiveTask() {
- Stop();
-}
-
-bool TextChatReceiveTask::HandleStanza(const XmlElement* stanza) {
- // Make sure that this stanza is a message
- if (stanza->Name() != QN_MESSAGE) {
- return false;
+#include "talk/media/webrtc/webrtcmediaengine.h"
+#include "webrtc/system_wrappers/interface/field_trial.h"
+
+WRME_EXPORT
+cricket::MediaEngineInterface* CreateWebRtcMediaEngine(
+ webrtc::AudioDeviceModule* adm,
+ webrtc::AudioDeviceModule* adm_sc,
+ cricket::WebRtcVideoEncoderFactory* encoder_factory,
+ cricket::WebRtcVideoDecoderFactory* decoder_factory) {
+#ifdef WEBRTC_CHROMIUM_BUILD
+ if (webrtc::field_trial::FindFullName("WebRTC-NewVideoAPI") == "Enabled") {
+ return new cricket::WebRtcMediaEngine2(
+ adm, adm_sc, encoder_factory, decoder_factory);
}
-
- // see if there is any body
- const XmlElement* message_body = stanza->FirstNamed(QN_BODY);
- if (message_body == NULL) {
- return false;
- }
-
- // Looks good, so send the message text along.
- SignalTextChatReceived(Jid(stanza->Attr(QN_FROM)), Jid(stanza->Attr(QN_TO)),
- message_body->BodyText());
-
- return true;
+#endif // WEBRTC_CHROMIUM_BUILD
+ return new cricket::WebRtcMediaEngine(
+ adm, adm_sc, encoder_factory, decoder_factory);
}
-int TextChatReceiveTask::ProcessStart() {
- // not queuing messages, so just block.
- return STATE_BLOCKED;
+WRME_EXPORT
+void DestroyWebRtcMediaEngine(cricket::MediaEngineInterface* media_engine) {
+#ifdef WEBRTC_CHROMIUM_BUILD
+ if (webrtc::field_trial::FindFullName("WebRTC-NewVideoAPI") == "Enabled") {
+ delete static_cast<cricket::WebRtcMediaEngine2*>(media_engine);
+ } else {
+#endif // WEBRTC_CHROMIUM_BUILD
+ delete static_cast<cricket::WebRtcMediaEngine*>(media_engine);
+#ifdef WEBRTC_CHROMIUM_BUILD
+ }
+#endif // WEBRTC_CHROMIUM_BUILD
}
-
-} // namespace buzz
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcmediaengine.h b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcmediaengine.h
index 94e7a99d826..6ca39e7dcf0 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcmediaengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcmediaengine.h
@@ -145,6 +145,9 @@ class WebRtcMediaEngine : public cricket::MediaEngineInterface {
virtual void SetVideoLogging(int min_sev, const char* filter) OVERRIDE {
delegate_->SetVideoLogging(min_sev, filter);
}
+ virtual bool StartAecDump(talk_base::PlatformFile file) OVERRIDE {
+ return delegate_->StartAecDump(file);
+ }
virtual bool RegisterVoiceProcessor(
uint32 ssrc, VoiceProcessor* video_processor,
MediaProcessorDirection direction) OVERRIDE {
@@ -172,6 +175,9 @@ class WebRtcMediaEngine : public cricket::MediaEngineInterface {
#else
#include "talk/media/webrtc/webrtcvideoengine.h"
+#ifdef WEBRTC_CHROMIUM_BUILD
+#include "talk/media/webrtc/webrtcvideoengine2.h"
+#endif
#include "talk/media/webrtc/webrtcvoiceengine.h"
namespace cricket {
@@ -192,6 +198,23 @@ class WebRtcMediaEngine : public WebRtcCompositeMediaEngine {
}
};
+#ifdef WEBRTC_CHROMIUM_BUILD
+typedef CompositeMediaEngine<WebRtcVoiceEngine, WebRtcVideoEngine2>
+ WebRtcCompositeMediaEngine2;
+
+class WebRtcMediaEngine2 : public WebRtcCompositeMediaEngine2 {
+ public:
+ WebRtcMediaEngine2(webrtc::AudioDeviceModule* adm,
+ webrtc::AudioDeviceModule* adm_sc,
+ WebRtcVideoEncoderFactory* encoder_factory,
+ WebRtcVideoDecoderFactory* decoder_factory) {
+ voice_.SetAudioDeviceModule(adm, adm_sc);
+ video_.SetVoiceEngine(&voice_);
+ video_.EnableTimedRender();
+ }
+};
+#endif
+
} // namespace cricket
#endif // !defined(LIBPEERCONNECTION_LIB) &&
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideocapturer.cc b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideocapturer.cc
index 6e81b401613..d7fc1b2f242 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideocapturer.cc
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideocapturer.cc
@@ -32,6 +32,7 @@
#endif
#ifdef HAVE_WEBRTC_VIDEO
+#include "talk/base/criticalsection.h"
#include "talk/base/logging.h"
#include "talk/base/thread.h"
#include "talk/base/timeutils.h"
@@ -189,11 +190,15 @@ bool WebRtcVideoCapturer::Init(const Device& device) {
}
}
factory_->DestroyDeviceInfo(info);
+// TODO(fischman): Remove the following check
+// when capabilities for iOS are implemented
+// https://code.google.com/p/webrtc/issues/detail?id=2968
+#if !defined(IOS)
if (supported.empty()) {
LOG(LS_ERROR) << "Failed to find usable formats for id: " << device.id;
return false;
}
-
+#endif
module_ = factory_->Create(0, vcm_id);
if (!module_) {
LOG(LS_ERROR) << "Failed to create capturer for id: " << device.id;
@@ -247,6 +252,7 @@ CaptureState WebRtcVideoCapturer::Start(const VideoFormat& capture_format) {
return CS_NO_DEVICE;
}
+ talk_base::CritScope cs(&critical_section_stopping_);
// TODO(hellner): weird to return failure when it is in fact actually running.
if (IsRunning()) {
LOG(LS_ERROR) << "The capturer is already running";
@@ -263,8 +269,8 @@ CaptureState WebRtcVideoCapturer::Start(const VideoFormat& capture_format) {
std::string camera_id(GetId());
uint32 start = talk_base::Time();
- if (module_->RegisterCaptureDataCallback(*this) != 0 ||
- module_->StartCapture(cap) != 0) {
+ module_->RegisterCaptureDataCallback(*this);
+ if (module_->StartCapture(cap) != 0) {
LOG(LS_ERROR) << "Camera '" << camera_id << "' failed to start";
return CS_FAILED;
}
@@ -278,7 +284,13 @@ CaptureState WebRtcVideoCapturer::Start(const VideoFormat& capture_format) {
return CS_STARTING;
}
+// Critical section blocks Stop from shutting down during callbacks from capture
+// thread to OnIncomingCapturedFrame. Note that the crit is try-locked in
+// OnFrameCaptured, as the lock ordering between this and the system component
+// controlling the camera is reversed: system frame -> OnIncomingCapturedFrame;
+// Stop -> system stop camera).
void WebRtcVideoCapturer::Stop() {
+ talk_base::CritScope cs(&critical_section_stopping_);
if (IsRunning()) {
talk_base::Thread::Current()->Clear(this);
module_->StopCapture();
@@ -313,7 +325,17 @@ bool WebRtcVideoCapturer::GetPreferredFourccs(
void WebRtcVideoCapturer::OnIncomingCapturedFrame(const int32_t id,
webrtc::I420VideoFrame& sample) {
- ASSERT(IsRunning());
+ // This would be a normal CritScope, except that it's possible that:
+ // (1) whatever system component producing this frame has taken a lock, and
+ // (2) Stop() probably calls back into that system component, which may take
+ // the same lock. Due to the reversed order, we have to try-lock in order to
+ // avoid a potential deadlock. Besides, if we can't enter because we're
+ // stopping, we may as well drop the frame.
+ talk_base::TryCritScope cs(&critical_section_stopping_);
+ if (!cs.locked() || !IsRunning()) {
+ // Capturer has been stopped or is in the process of stopping.
+ return;
+ }
++captured_frames_;
// Log the size and pixel aspect ratio of the first captured frame.
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideocapturer.h b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideocapturer.h
index c20a05919e0..cefad5629f0 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideocapturer.h
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideocapturer.h
@@ -31,6 +31,7 @@
#include <string>
#include <vector>
+#include "talk/base/criticalsection.h"
#include "talk/base/messagehandler.h"
#include "talk/media/base/videocapturer.h"
#include "talk/media/webrtc/webrtcvideoframe.h"
@@ -89,6 +90,9 @@ class WebRtcVideoCapturer : public VideoCapturer,
webrtc::VideoCaptureModule* module_;
int captured_frames_;
std::vector<uint8_t> capture_buffer_;
+
+ // Critical section to avoid Stop during an OnIncomingCapturedFrame callback.
+ talk_base::CriticalSection critical_section_stopping_;
};
struct WebRtcCapturedFrame : public CapturedFrame {
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideochannelfactory.h b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideochannelfactory.h
new file mode 100644
index 00000000000..646348cd55c
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideochannelfactory.h
@@ -0,0 +1,44 @@
+/*
+ * libjingle
+ * Copyright 2004 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_MEDIA_WEBRTC_WEBRTCVIDEOCHANNEL_H_
+#define TALK_MEDIA_WEBRTC_WEBRTCVIDEOCHANNEL_H_
+
+namespace cricket {
+class VoiceMediaChannel;
+class WebRtcVideoEngine2;
+class WebRtcVideoChannel2;
+
+class WebRtcVideoChannelFactory {
+ public:
+ virtual ~WebRtcVideoChannelFactory() {}
+ virtual WebRtcVideoChannel2* Create(WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel) = 0;
+};
+} // namespace cricket
+
+#endif // TALK_MEDIA_WEBRTC_WEBRTCVIDEOCHANNEL_H_
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.cc b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.cc
index 88e09fc3842..fd609e9a4db 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.cc
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.cc
@@ -60,27 +60,8 @@
#include "talk/media/webrtc/webrtcvie.h"
#include "talk/media/webrtc/webrtcvoe.h"
#include "talk/media/webrtc/webrtcvoiceengine.h"
-
-#if !defined(LIBPEERCONNECTION_LIB)
-#ifndef HAVE_WEBRTC_VIDEO
-#error Need webrtc video
-#endif
-#include "talk/media/webrtc/webrtcmediaengine.h"
-
-WRME_EXPORT
-cricket::MediaEngineInterface* CreateWebRtcMediaEngine(
- webrtc::AudioDeviceModule* adm, webrtc::AudioDeviceModule* adm_sc,
- cricket::WebRtcVideoEncoderFactory* encoder_factory,
- cricket::WebRtcVideoDecoderFactory* decoder_factory) {
- return new cricket::WebRtcMediaEngine(adm, adm_sc, encoder_factory,
- decoder_factory);
-}
-
-WRME_EXPORT
-void DestroyWebRtcMediaEngine(cricket::MediaEngineInterface* media_engine) {
- delete static_cast<cricket::WebRtcMediaEngine*>(media_engine);
-}
-#endif
+#include "webrtc/experiments.h"
+#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
namespace cricket {
@@ -91,7 +72,6 @@ static const int kDefaultLogSeverity = talk_base::LS_WARNING;
static const int kMinVideoBitrate = 50;
static const int kStartVideoBitrate = 300;
static const int kMaxVideoBitrate = 2000;
-static const int kDefaultConferenceModeMaxVideoBitrate = 500;
// Controlled by exp, try a super low minimum bitrate for poor connections.
static const int kLowerMinBitrate = 30;
@@ -106,14 +86,22 @@ static const char kFecPayloadName[] = "ulpfec";
static const int kDefaultNumberOfTemporalLayers = 1; // 1:1
-static const int kTimestampDeltaInSecondsForWarning = 2;
-
-static const int kMaxExternalVideoCodecs = 8;
static const int kExternalVideoPayloadTypeBase = 120;
+static bool BitrateIsSet(int value) {
+ return value > kAutoBandwidth;
+}
+
+static int GetBitrate(int value, int deflt) {
+ return BitrateIsSet(value) ? value : deflt;
+}
+
// Static allocation of payload type values for external video codec.
static int GetExternalVideoPayloadType(int index) {
+#if ENABLE_DEBUG
+ static const int kMaxExternalVideoCodecs = 8;
ASSERT(index >= 0 && index < kMaxExternalVideoCodecs);
+#endif
return kExternalVideoPayloadTypeBase + index;
}
@@ -145,17 +133,6 @@ static const int kCpuMonitorPeriodMs = 2000; // 2 seconds.
static const bool kNotSending = false;
-// Extension header for RTP timestamp offset, see RFC 5450 for details:
-// http://tools.ietf.org/html/rfc5450
-static const char kRtpTimestampOffsetHeaderExtension[] =
- "urn:ietf:params:rtp-hdrext:toffset";
-static const int kRtpTimeOffsetExtensionId = 2;
-
-// Extension header for absolute send time, see url for details:
-// http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
-static const char kRtpAbsoluteSendTimeHeaderExtension[] =
- "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
-static const int kRtpAbsoluteSendTimeExtensionId = 3;
// Default video dscp value.
// See http://tools.ietf.org/html/rfc2474 for details
// See also http://tools.ietf.org/html/draft-jennings-rtcweb-qos-00
@@ -182,18 +159,18 @@ struct FlushBlackFrameData : public talk_base::MessageData {
class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
public:
- explicit WebRtcRenderAdapter(VideoRenderer* renderer)
- : renderer_(renderer), width_(0), height_(0), watermark_enabled_(false) {
+ WebRtcRenderAdapter(VideoRenderer* renderer, int channel_id)
+ : renderer_(renderer),
+ channel_id_(channel_id),
+ width_(0),
+ height_(0),
+ capture_start_rtp_time_stamp_(-1),
+ capture_start_ntp_time_ms_(0) {
}
virtual ~WebRtcRenderAdapter() {
}
- void set_watermark_enabled(bool enable) {
- talk_base::CritScope cs(&crit_);
- watermark_enabled_ = enable;
- }
-
void SetRenderer(VideoRenderer* renderer) {
talk_base::CritScope cs(&crit_);
renderer_ = renderer;
@@ -205,7 +182,8 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
if (width_ > 0 && height_ > 0 && renderer_ != NULL) {
if (!renderer_->SetSize(width_, height_, 0)) {
LOG(LS_ERROR)
- << "WebRtcRenderAdapter SetRenderer failed to SetSize to: "
+ << "WebRtcRenderAdapter (channel " << channel_id_
+ << ") SetRenderer failed to SetSize to: "
<< width_ << "x" << height_;
}
}
@@ -217,53 +195,75 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
talk_base::CritScope cs(&crit_);
width_ = width;
height_ = height;
- LOG(LS_INFO) << "WebRtcRenderAdapter frame size changed to: "
+ LOG(LS_INFO) << "WebRtcRenderAdapter (channel " << channel_id_
+ << ") frame size changed to: "
<< width << "x" << height;
if (renderer_ == NULL) {
- LOG(LS_VERBOSE) << "WebRtcRenderAdapter the renderer has not been set. "
+ LOG(LS_VERBOSE) << "WebRtcRenderAdapter (channel " << channel_id_
+ << ") the renderer has not been set. "
<< "SetSize will be called later in SetRenderer.";
return 0;
}
return renderer_->SetSize(width_, height_, 0) ? 0 : -1;
}
- virtual int DeliverFrame(unsigned char* buffer, int buffer_size,
- uint32_t time_stamp, int64_t render_time,
+ virtual int DeliverFrame(unsigned char* buffer,
+ int buffer_size,
+ uint32_t rtp_time_stamp,
+#ifdef USE_WEBRTC_DEV_BRANCH
+ int64_t ntp_time_ms,
+#endif
+ int64_t render_time,
void* handle) {
talk_base::CritScope cs(&crit_);
+ if (capture_start_rtp_time_stamp_ < 0) {
+ capture_start_rtp_time_stamp_ = rtp_time_stamp;
+ }
+
+ const int kVideoCodecClockratekHz = cricket::kVideoCodecClockrate / 1000;
+
+ int64 elapsed_time_ms =
+ (rtp_ts_wraparound_handler_.Unwrap(rtp_time_stamp) -
+ capture_start_rtp_time_stamp_) / kVideoCodecClockratekHz;
+#ifdef USE_WEBRTC_DEV_BRANCH
+ if (ntp_time_ms > 0) {
+ capture_start_ntp_time_ms_ = ntp_time_ms - elapsed_time_ms;
+ }
+#endif
frame_rate_tracker_.Update(1);
if (renderer_ == NULL) {
return 0;
}
- // Convert 90K rtp timestamp to ns timestamp.
- int64 rtp_time_stamp_in_ns = (time_stamp / 90) *
- talk_base::kNumNanosecsPerMillisec;
+ // Convert elapsed_time_ms to ns timestamp.
+ int64 elapsed_time_ns =
+ elapsed_time_ms * talk_base::kNumNanosecsPerMillisec;
// Convert milisecond render time to ns timestamp.
- int64 render_time_stamp_in_ns = render_time *
+ int64 render_time_ns = render_time *
talk_base::kNumNanosecsPerMillisec;
- // Send the rtp timestamp to renderer as the VideoFrame timestamp.
- // and the render timestamp as the VideoFrame elapsed_time.
+ // Note that here we send the |elapsed_time_ns| to renderer as the
+ // cricket::VideoFrame's elapsed_time_ and the |render_time_ns| as the
+ // cricket::VideoFrame's time_stamp_.
if (handle == NULL) {
- return DeliverBufferFrame(buffer, buffer_size, render_time_stamp_in_ns,
- rtp_time_stamp_in_ns);
+ return DeliverBufferFrame(buffer, buffer_size, render_time_ns,
+ elapsed_time_ns);
} else {
- return DeliverTextureFrame(handle, render_time_stamp_in_ns,
- rtp_time_stamp_in_ns);
+ return DeliverTextureFrame(handle, render_time_ns,
+ elapsed_time_ns);
}
}
virtual bool IsTextureSupported() { return true; }
int DeliverBufferFrame(unsigned char* buffer, int buffer_size,
- int64 elapsed_time, int64 time_stamp) {
+ int64 time_stamp, int64 elapsed_time) {
WebRtcVideoFrame video_frame;
video_frame.Alias(buffer, buffer_size, width_, height_,
1, 1, elapsed_time, time_stamp, 0);
-
// Sanity check on decoded frame size.
if (buffer_size != static_cast<int>(VideoFrame::SizeOf(width_, height_))) {
- LOG(LS_WARNING) << "WebRtcRenderAdapter received a strange frame size: "
+ LOG(LS_WARNING) << "WebRtcRenderAdapter (channel " << channel_id_
+ << ") received a strange frame size: "
<< buffer_size;
}
@@ -271,7 +271,7 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
return ret;
}
- int DeliverTextureFrame(void* handle, int64 elapsed_time, int64 time_stamp) {
+ int DeliverTextureFrame(void* handle, int64 time_stamp, int64 elapsed_time) {
WebRtcTextureVideoFrame video_frame(
static_cast<webrtc::NativeHandle*>(handle), width_, height_,
elapsed_time, time_stamp);
@@ -298,13 +298,21 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
return renderer_;
}
+ int64 capture_start_ntp_time_ms() {
+ talk_base::CritScope cs(&crit_);
+ return capture_start_ntp_time_ms_;
+ }
+
private:
talk_base::CriticalSection crit_;
VideoRenderer* renderer_;
+ int channel_id_;
unsigned int width_;
unsigned int height_;
talk_base::RateTracker frame_rate_tracker_;
- bool watermark_enabled_;
+ talk_base::TimestampWrapAroundHandler rtp_ts_wraparound_handler_;
+ int64 capture_start_rtp_time_stamp_;
+ int64 capture_start_ntp_time_ms_;
};
class WebRtcDecoderObserver : public webrtc::ViEDecoderObserver {
@@ -319,8 +327,7 @@ class WebRtcDecoderObserver : public webrtc::ViEDecoderObserver {
target_delay_ms_(0),
jitter_buffer_ms_(0),
min_playout_delay_ms_(0),
- render_delay_ms_(0),
- firs_requested_(0) {
+ render_delay_ms_(0) {
}
// virtual functions from VieDecoderObserver.
@@ -352,16 +359,11 @@ class WebRtcDecoderObserver : public webrtc::ViEDecoderObserver {
render_delay_ms_ = render_delay_ms;
}
- virtual void RequestNewKeyFrame(const int videoChannel) {
- talk_base::CritScope cs(&crit_);
- ASSERT(video_channel_ == videoChannel);
- ++firs_requested_;
- }
+ virtual void RequestNewKeyFrame(const int videoChannel) {}
// Populate |rinfo| based on previously-set data in |*this|.
void ExportTo(VideoReceiverInfo* rinfo) {
talk_base::CritScope cs(&crit_);
- rinfo->firs_sent = firs_requested_;
rinfo->framerate_rcvd = framerate_;
rinfo->decode_ms = decode_ms_;
rinfo->max_decode_ms = max_decode_ms_;
@@ -384,7 +386,6 @@ class WebRtcDecoderObserver : public webrtc::ViEDecoderObserver {
int jitter_buffer_ms_;
int min_playout_delay_ms_;
int render_delay_ms_;
- int firs_requested_;
};
class WebRtcEncoderObserver : public webrtc::ViEEncoderObserver {
@@ -497,7 +498,7 @@ class WebRtcVideoChannelRecvInfo {
typedef std::map<int, webrtc::VideoDecoder*> DecoderMap; // key: payload type
explicit WebRtcVideoChannelRecvInfo(int channel_id)
: channel_id_(channel_id),
- render_adapter_(NULL),
+ render_adapter_(NULL, channel_id),
decoder_observer_(channel_id) {
}
int channel_id() { return channel_id_; }
@@ -557,10 +558,13 @@ class WebRtcOveruseObserver : public webrtc::CpuOveruseObserver {
}
void Enable(bool enable) {
+ LOG(LS_INFO) << "WebRtcOveruseObserver enable: " << enable;
talk_base::CritScope cs(&crit_);
enabled_ = enable;
}
+ bool enabled() const { return enabled_; }
+
private:
CoordinatedVideoAdapter* video_adapter_;
bool enabled_;
@@ -583,14 +587,7 @@ class WebRtcVideoChannelSendInfo : public sigslot::has_slots<> {
external_capture_(external_capture),
capturer_updated_(false),
interval_(0),
- video_adapter_(new CoordinatedVideoAdapter),
cpu_monitor_(cpu_monitor) {
- overuse_observer_.reset(new WebRtcOveruseObserver(video_adapter_.get()));
- SignalCpuAdaptationUnable.repeat(video_adapter_->SignalCpuAdaptationUnable);
- if (cpu_monitor) {
- cpu_monitor->SignalUpdate.connect(
- video_adapter_.get(), &CoordinatedVideoAdapter::OnCpuLoadUpdated);
- }
}
int channel_id() const { return channel_id_; }
@@ -599,7 +596,7 @@ class WebRtcVideoChannelSendInfo : public sigslot::has_slots<> {
bool sending() const { return sending_; }
void set_muted(bool on) {
// TODO(asapersson): add support.
- // video_adapter_->SetBlackOutput(on);
+ // video_adapter_.SetBlackOutput(on);
muted_ = on;
}
bool muted() {return muted_; }
@@ -614,7 +611,10 @@ class WebRtcVideoChannelSendInfo : public sigslot::has_slots<> {
if (video_format_ != cricket::VideoFormat()) {
interval_ = video_format_.interval;
}
- video_adapter_->OnOutputFormatRequest(video_format_);
+ CoordinatedVideoAdapter* adapter = video_adapter();
+ if (adapter) {
+ adapter->OnOutputFormatRequest(video_format_);
+ }
}
void set_interval(int64 interval) {
if (video_format() == cricket::VideoFormat()) {
@@ -623,20 +623,12 @@ class WebRtcVideoChannelSendInfo : public sigslot::has_slots<> {
}
int64 interval() { return interval_; }
- void InitializeAdapterOutputFormat(const webrtc::VideoCodec& codec) {
- VideoFormat format(codec.width, codec.height,
- VideoFormat::FpsToInterval(codec.maxFramerate),
- FOURCC_I420);
- if (video_adapter_->output_format().IsSize0x0()) {
- video_adapter_->SetOutputFormat(format);
- }
- }
-
int CurrentAdaptReason() const {
- return video_adapter_->adapt_reason();
- }
- webrtc::CpuOveruseObserver* overuse_observer() {
- return overuse_observer_.get();
+ const CoordinatedVideoAdapter* adapter = video_adapter();
+ if (!adapter) {
+ return CoordinatedVideoAdapter::ADAPTREASON_NONE;
+ }
+ return video_adapter()->adapt_reason();
}
StreamParams* stream_params() { return stream_params_.get(); }
@@ -654,65 +646,127 @@ class WebRtcVideoChannelSendInfo : public sigslot::has_slots<> {
VideoCapturer* video_capturer() {
return video_capturer_;
}
- void set_video_capturer(VideoCapturer* video_capturer) {
+ void set_video_capturer(VideoCapturer* video_capturer,
+ ViEWrapper* vie_wrapper) {
if (video_capturer == video_capturer_) {
return;
}
+
+ CoordinatedVideoAdapter* old_video_adapter = video_adapter();
+ if (old_video_adapter) {
+ // Disconnect signals from old video adapter.
+ SignalCpuAdaptationUnable.disconnect(old_video_adapter);
+ if (cpu_monitor_) {
+ cpu_monitor_->SignalUpdate.disconnect(old_video_adapter);
+ }
+ }
+
capturer_updated_ = true;
video_capturer_ = video_capturer;
- if (video_capturer && !video_capturer->IsScreencast()) {
- const VideoFormat* capture_format = video_capturer->GetCaptureFormat();
- if (capture_format) {
- // TODO(thorcarpenter): This is broken. Video capturer doesn't have
- // a capture format until the capturer is started. So, if
- // the capturer is started immediately after calling set_video_capturer
- // video adapter may not have the input format set, the interval may
- // be zero, and all frames may be dropped.
- // Consider fixing this by having video_adapter keep a pointer to the
- // video capturer.
- video_adapter_->SetInputFormat(*capture_format);
- }
- // TODO(thorcarpenter): When the adapter supports "only frame dropping"
- // mode, also hook it up to screencast capturers.
- video_capturer->SignalAdaptFrame.connect(
- this, &WebRtcVideoChannelSendInfo::AdaptFrame);
+
+ vie_wrapper->base()->RegisterCpuOveruseObserver(channel_id_, NULL);
+ if (!video_capturer) {
+ overuse_observer_.reset();
+ return;
}
+
+ CoordinatedVideoAdapter* adapter = video_adapter();
+ ASSERT(adapter && "Video adapter should not be null here.");
+
+ UpdateAdapterCpuOptions();
+
+ overuse_observer_.reset(new WebRtcOveruseObserver(adapter));
+ vie_wrapper->base()->RegisterCpuOveruseObserver(channel_id_,
+ overuse_observer_.get());
+ // (Dis)connect the video adapter from the cpu monitor as appropriate.
+ SetCpuOveruseDetection(
+ video_options_.cpu_overuse_detection.GetWithDefaultIfUnset(false));
+
+ SignalCpuAdaptationUnable.repeat(adapter->SignalCpuAdaptationUnable);
}
- void AdaptFrame(VideoCapturer* capturer, const VideoFrame* input,
- VideoFrame** adapted) {
- video_adapter_->AdaptFrame(input, adapted);
+ CoordinatedVideoAdapter* video_adapter() {
+ if (!video_capturer_) {
+ return NULL;
+ }
+ return video_capturer_->video_adapter();
+ }
+ const CoordinatedVideoAdapter* video_adapter() const {
+ if (!video_capturer_) {
+ return NULL;
+ }
+ return video_capturer_->video_adapter();
+ }
+
+ void ApplyCpuOptions(const VideoOptions& video_options) {
+ bool cpu_overuse_detection_changed =
+ video_options.cpu_overuse_detection.IsSet() &&
+ (video_options.cpu_overuse_detection.GetWithDefaultIfUnset(false) !=
+ video_options_.cpu_overuse_detection.GetWithDefaultIfUnset(false));
+ // Use video_options_.SetAll() instead of assignment so that unset value in
+ // video_options will not overwrite the previous option value.
+ video_options_.SetAll(video_options);
+ UpdateAdapterCpuOptions();
+ if (cpu_overuse_detection_changed) {
+ SetCpuOveruseDetection(
+ video_options_.cpu_overuse_detection.GetWithDefaultIfUnset(false));
+ }
}
- void ApplyCpuOptions(const VideoOptions& options) {
- bool cpu_adapt, cpu_smoothing, adapt_third;
+ void UpdateAdapterCpuOptions() {
+ if (!video_capturer_) {
+ return;
+ }
+
+ bool cpu_smoothing, adapt_third;
float low, med, high;
- if (options.adapt_input_to_cpu_usage.Get(&cpu_adapt)) {
- video_adapter_->set_cpu_adaptation(cpu_adapt);
+ bool cpu_adapt =
+ video_options_.adapt_input_to_cpu_usage.GetWithDefaultIfUnset(false);
+ bool cpu_overuse_detection =
+ video_options_.cpu_overuse_detection.GetWithDefaultIfUnset(false);
+
+ // TODO(thorcarpenter): Have VideoAdapter be responsible for setting
+ // all these video options.
+ CoordinatedVideoAdapter* video_adapter = video_capturer_->video_adapter();
+ if (video_options_.adapt_input_to_cpu_usage.IsSet() ||
+ video_options_.cpu_overuse_detection.IsSet()) {
+ video_adapter->set_cpu_adaptation(cpu_adapt || cpu_overuse_detection);
}
- if (options.adapt_cpu_with_smoothing.Get(&cpu_smoothing)) {
- video_adapter_->set_cpu_smoothing(cpu_smoothing);
+ if (video_options_.adapt_cpu_with_smoothing.Get(&cpu_smoothing)) {
+ video_adapter->set_cpu_smoothing(cpu_smoothing);
}
- if (options.process_adaptation_threshhold.Get(&med)) {
- video_adapter_->set_process_threshold(med);
+ if (video_options_.process_adaptation_threshhold.Get(&med)) {
+ video_adapter->set_process_threshold(med);
}
- if (options.system_low_adaptation_threshhold.Get(&low)) {
- video_adapter_->set_low_system_threshold(low);
+ if (video_options_.system_low_adaptation_threshhold.Get(&low)) {
+ video_adapter->set_low_system_threshold(low);
}
- if (options.system_high_adaptation_threshhold.Get(&high)) {
- video_adapter_->set_high_system_threshold(high);
+ if (video_options_.system_high_adaptation_threshhold.Get(&high)) {
+ video_adapter->set_high_system_threshold(high);
}
- if (options.video_adapt_third.Get(&adapt_third)) {
- video_adapter_->set_scale_third(adapt_third);
+ if (video_options_.video_adapt_third.Get(&adapt_third)) {
+ video_adapter->set_scale_third(adapt_third);
}
}
void SetCpuOveruseDetection(bool enable) {
- if (cpu_monitor_ && enable) {
- cpu_monitor_->SignalUpdate.disconnect(video_adapter_.get());
+ if (overuse_observer_) {
+ overuse_observer_->Enable(enable);
+ }
+
+ // The video adapter is signaled by overuse detection if enabled; otherwise
+ // it will be signaled by cpu monitor.
+ CoordinatedVideoAdapter* adapter = video_adapter();
+ if (adapter) {
+ if (cpu_monitor_) {
+ if (enable) {
+ cpu_monitor_->SignalUpdate.disconnect(adapter);
+ } else {
+ cpu_monitor_->SignalUpdate.connect(
+ adapter, &CoordinatedVideoAdapter::OnCpuLoadUpdated);
+ }
+ }
}
- overuse_observer_->Enable(enable);
- video_adapter_->set_cpu_adaptation(enable);
}
void ProcessFrame(const VideoFrame& original_frame, bool mute,
@@ -766,9 +820,10 @@ class WebRtcVideoChannelSendInfo : public sigslot::has_slots<> {
int64 interval_;
- talk_base::scoped_ptr<CoordinatedVideoAdapter> video_adapter_;
talk_base::CpuMonitor* cpu_monitor_;
talk_base::scoped_ptr<WebRtcOveruseObserver> overuse_observer_;
+
+ VideoOptions video_options_;
};
const WebRtcVideoEngine::VideoCodecPref
@@ -817,6 +872,48 @@ static void UpdateVideoCodec(const cricket::VideoFormat& video_format,
video_format.interval);
}
+static bool GetCpuOveruseOptions(const VideoOptions& options,
+ webrtc::CpuOveruseOptions* overuse_options) {
+ int underuse_threshold = 0;
+ int overuse_threshold = 0;
+ if (!options.cpu_underuse_threshold.Get(&underuse_threshold) ||
+ !options.cpu_overuse_threshold.Get(&overuse_threshold)) {
+ return false;
+ }
+ if (underuse_threshold <= 0 || overuse_threshold <= 0) {
+ return false;
+ }
+ // Valid thresholds.
+ bool encode_usage =
+ options.cpu_overuse_encode_usage.GetWithDefaultIfUnset(false);
+ overuse_options->enable_capture_jitter_method = !encode_usage;
+ overuse_options->enable_encode_usage_method = encode_usage;
+ if (encode_usage) {
+ // Use method based on encode usage.
+ overuse_options->low_encode_usage_threshold_percent = underuse_threshold;
+ overuse_options->high_encode_usage_threshold_percent = overuse_threshold;
+#ifdef USE_WEBRTC_DEV_BRANCH
+ // Set optional thresholds, if configured.
+ int underuse_rsd_threshold = 0;
+ if (options.cpu_underuse_encode_rsd_threshold.Get(
+ &underuse_rsd_threshold)) {
+ overuse_options->low_encode_time_rsd_threshold = underuse_rsd_threshold;
+ }
+ int overuse_rsd_threshold = 0;
+ if (options.cpu_overuse_encode_rsd_threshold.Get(&overuse_rsd_threshold)) {
+ overuse_options->high_encode_time_rsd_threshold = overuse_rsd_threshold;
+ }
+#endif
+ } else {
+ // Use default method based on capture jitter.
+ overuse_options->low_capture_jitter_threshold_ms =
+ static_cast<float>(underuse_threshold);
+ overuse_options->high_capture_jitter_threshold_ms =
+ static_cast<float>(overuse_threshold);
+ }
+ return true;
+}
+
WebRtcVideoEngine::WebRtcVideoEngine() {
Construct(new ViEWrapper(), new ViETraceWrapper(), NULL,
new talk_base::CpuMonitor(NULL));
@@ -878,10 +975,10 @@ void WebRtcVideoEngine::Construct(ViEWrapper* vie_wrapper,
// Load our RTP Header extensions.
rtp_header_extensions_.push_back(
RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension,
- kRtpTimeOffsetExtensionId));
+ kRtpTimestampOffsetHeaderExtensionDefaultId));
rtp_header_extensions_.push_back(
- RtpHeaderExtension(kRtpAbsoluteSendTimeHeaderExtension,
- kRtpAbsoluteSendTimeExtensionId));
+ RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension,
+ kRtpAbsoluteSenderTimeHeaderExtensionDefaultId));
}
WebRtcVideoEngine::~WebRtcVideoEngine() {
@@ -1173,8 +1270,15 @@ static void ConvertToCricketVideoCodec(
out_codec->width = in_codec.width;
out_codec->height = in_codec.height;
out_codec->framerate = in_codec.maxFramerate;
- out_codec->SetParam(kCodecParamMinBitrate, in_codec.minBitrate);
- out_codec->SetParam(kCodecParamMaxBitrate, in_codec.maxBitrate);
+ if (BitrateIsSet(in_codec.minBitrate)) {
+ out_codec->SetParam(kCodecParamMinBitrate, in_codec.minBitrate);
+ }
+ if (BitrateIsSet(in_codec.maxBitrate)) {
+ out_codec->SetParam(kCodecParamMaxBitrate, in_codec.maxBitrate);
+ }
+ if (BitrateIsSet(in_codec.startBitrate)) {
+ out_codec->SetParam(kCodecParamStartBitrate, in_codec.startBitrate);
+ }
if (in_codec.qpMax) {
out_codec->SetParam(kCodecParamMaxQuantization, in_codec.qpMax);
}
@@ -1208,6 +1312,15 @@ bool WebRtcVideoEngine::ConvertFromCricketVideoCodec(
}
}
+ // Is this an RTX codec? Handled separately here since webrtc doesn't handle
+ // them as webrtc::VideoCodec internally.
+ if (!found && _stricmp(in_codec.name.c_str(), kRtxCodecName) == 0) {
+ talk_base::strcpyn(out_codec->plName, sizeof(out_codec->plName),
+ in_codec.name.c_str(), in_codec.name.length());
+ out_codec->plType = in_codec.id;
+ found = true;
+ }
+
if (!found) {
LOG(LS_ERROR) << "invalid codec type";
return false;
@@ -1226,18 +1339,14 @@ bool WebRtcVideoEngine::ConvertFromCricketVideoCodec(
out_codec->maxFramerate = in_codec.framerate;
// Convert bitrate parameters.
- int max_bitrate = kMaxVideoBitrate;
- int min_bitrate = kMinVideoBitrate;
- int start_bitrate = kStartVideoBitrate;
+ int max_bitrate = -1;
+ int min_bitrate = -1;
+ int start_bitrate = -1;
in_codec.GetParam(kCodecParamMinBitrate, &min_bitrate);
in_codec.GetParam(kCodecParamMaxBitrate, &max_bitrate);
+ in_codec.GetParam(kCodecParamStartBitrate, &start_bitrate);
- if (max_bitrate < min_bitrate) {
- return false;
- }
- start_bitrate = talk_base::_max(start_bitrate, min_bitrate);
- start_bitrate = talk_base::_min(start_bitrate, max_bitrate);
out_codec->minBitrate = min_bitrate;
out_codec->startBitrate = start_bitrate;
@@ -1310,6 +1419,8 @@ static void AddDefaultFeedbackParams(VideoCodec* codec) {
codec->AddFeedbackParam(kFir);
const FeedbackParam kNack(kRtcpFbParamNack, kParamValueEmpty);
codec->AddFeedbackParam(kNack);
+ const FeedbackParam kPli(kRtcpFbParamNack, kRtcpFbNackParamPli);
+ codec->AddFeedbackParam(kPli);
const FeedbackParam kRemb(kRtcpFbParamRemb, kParamValueEmpty);
codec->AddFeedbackParam(kRemb);
}
@@ -1509,12 +1620,10 @@ WebRtcVideoMediaChannel::WebRtcVideoMediaChannel(
remb_enabled_(false),
render_started_(false),
first_receive_ssrc_(0),
+ num_unsignalled_recv_channels_(0),
send_rtx_type_(-1),
send_red_type_(-1),
send_fec_type_(-1),
- send_min_bitrate_(kMinVideoBitrate),
- send_start_bitrate_(kStartVideoBitrate),
- send_max_bitrate_(kMaxVideoBitrate),
sending_(false),
ratio_w_(0),
ratio_h_(0) {
@@ -1543,7 +1652,7 @@ WebRtcVideoMediaChannel::~WebRtcVideoMediaChannel() {
// Remove all receive streams and the default channel.
while (!recv_channels_.empty()) {
- RemoveRecvStream(recv_channels_.begin()->first);
+ RemoveRecvStreamInternal(recv_channels_.begin()->first);
}
// Unregister the channel from the engine.
@@ -1556,12 +1665,17 @@ WebRtcVideoMediaChannel::~WebRtcVideoMediaChannel() {
bool WebRtcVideoMediaChannel::SetRecvCodecs(
const std::vector<VideoCodec>& codecs) {
receive_codecs_.clear();
+ associated_payload_types_.clear();
for (std::vector<VideoCodec>::const_iterator iter = codecs.begin();
iter != codecs.end(); ++iter) {
if (engine()->FindCodec(*iter)) {
webrtc::VideoCodec wcodec;
if (engine()->ConvertFromCricketVideoCodec(*iter, &wcodec)) {
receive_codecs_.push_back(wcodec);
+ int apt;
+ if (iter->GetParam(cricket::kCodecParamAssociatedPayloadType, &apt)) {
+ associated_payload_types_[wcodec.plType] = apt;
+ }
}
} else {
LOG(LS_INFO) << "Unknown codec " << iter->name;
@@ -1587,6 +1701,8 @@ bool WebRtcVideoMediaChannel::SetSendCodecs(
ConvertToCricketVideoCodec(*send_codec_, &current);
}
std::map<int, int> primary_rtx_pt_mapping;
+ bool nack_enabled = nack_enabled_;
+ bool remb_enabled = remb_enabled_;
for (std::vector<VideoCodec>::const_iterator iter = codecs.begin();
iter != codecs.end(); ++iter) {
if (_stricmp(iter->name.c_str(), kRedPayloadName) == 0) {
@@ -1603,8 +1719,8 @@ bool WebRtcVideoMediaChannel::SetSendCodecs(
webrtc::VideoCodec wcodec;
if (engine()->ConvertFromCricketVideoCodec(checked_codec, &wcodec)) {
if (send_codecs.empty()) {
- nack_enabled_ = IsNackEnabled(checked_codec);
- remb_enabled_ = IsRembEnabled(checked_codec);
+ nack_enabled = IsNackEnabled(checked_codec);
+ remb_enabled = IsRembEnabled(checked_codec);
}
send_codecs.push_back(wcodec);
}
@@ -1620,35 +1736,43 @@ bool WebRtcVideoMediaChannel::SetSendCodecs(
}
// Recv protection.
- for (RecvChannelMap::iterator it = recv_channels_.begin();
- it != recv_channels_.end(); ++it) {
- int channel_id = it->second->channel_id();
- if (!SetNackFec(channel_id, send_red_type_, send_fec_type_,
- nack_enabled_)) {
- return false;
- }
- if (engine_->vie()->rtp()->SetRembStatus(channel_id,
- kNotSending,
- remb_enabled_) != 0) {
- LOG_RTCERR3(SetRembStatus, channel_id, kNotSending, remb_enabled_);
- return false;
+ // Do not update if the status is same as previously configured.
+ if (nack_enabled_ != nack_enabled) {
+ for (RecvChannelMap::iterator it = recv_channels_.begin();
+ it != recv_channels_.end(); ++it) {
+ int channel_id = it->second->channel_id();
+ if (!SetNackFec(channel_id, send_red_type_, send_fec_type_,
+ nack_enabled)) {
+ return false;
+ }
+ if (engine_->vie()->rtp()->SetRembStatus(channel_id,
+ kNotSending,
+ remb_enabled_) != 0) {
+ LOG_RTCERR3(SetRembStatus, channel_id, kNotSending, remb_enabled_);
+ return false;
+ }
}
+ nack_enabled_ = nack_enabled;
}
// Send settings.
- for (SendChannelMap::iterator iter = send_channels_.begin();
- iter != send_channels_.end(); ++iter) {
- int channel_id = iter->second->channel_id();
- if (!SetNackFec(channel_id, send_red_type_, send_fec_type_,
- nack_enabled_)) {
- return false;
- }
- if (engine_->vie()->rtp()->SetRembStatus(channel_id,
- remb_enabled_,
- remb_enabled_) != 0) {
- LOG_RTCERR3(SetRembStatus, channel_id, remb_enabled_, remb_enabled_);
- return false;
+ // Do not update if the status is same as previously configured.
+ if (remb_enabled_ != remb_enabled) {
+ for (SendChannelMap::iterator iter = send_channels_.begin();
+ iter != send_channels_.end(); ++iter) {
+ int channel_id = iter->second->channel_id();
+ if (!SetNackFec(channel_id, send_red_type_, send_fec_type_,
+ nack_enabled_)) {
+ return false;
+ }
+ if (engine_->vie()->rtp()->SetRembStatus(channel_id,
+ remb_enabled,
+ remb_enabled) != 0) {
+ LOG_RTCERR3(SetRembStatus, channel_id, remb_enabled, remb_enabled);
+ return false;
+ }
}
+ remb_enabled_ = remb_enabled;
}
// Select the first matched codec.
@@ -1662,15 +1786,20 @@ bool WebRtcVideoMediaChannel::SetSendCodecs(
send_rtx_type_ = rtx_it->second;
}
- if (!SetSendCodec(
- codec, codec.minBitrate, codec.startBitrate, codec.maxBitrate)) {
+ if (BitrateIsSet(codec.minBitrate) && BitrateIsSet(codec.maxBitrate) &&
+ codec.minBitrate > codec.maxBitrate) {
+ // TODO(pthatcher): This behavior contradicts other behavior in
+ // this file which will cause min > max to push the min down to
+ // the max. There are unit tests for both behaviors. We should
+ // pick one and do that.
+ LOG(LS_INFO) << "Rejecting codec with min bitrate ("
+ << codec.minBitrate << ") larger than max ("
+ << codec.maxBitrate << "). ";
return false;
}
- for (SendChannelMap::iterator iter = send_channels_.begin();
- iter != send_channels_.end(); ++iter) {
- WebRtcVideoChannelSendInfo* send_channel = iter->second;
- send_channel->InitializeAdapterOutputFormat(codec);
+ if (!SetSendCodec(codec)) {
+ return false;
}
LogSendCodecChange("SetSendCodecs()");
@@ -1688,10 +1817,6 @@ bool WebRtcVideoMediaChannel::GetSendCodec(VideoCodec* send_codec) {
bool WebRtcVideoMediaChannel::SetSendStreamFormat(uint32 ssrc,
const VideoFormat& format) {
- if (!send_codec_) {
- LOG(LS_ERROR) << "The send codec has not been set yet.";
- return false;
- }
WebRtcVideoChannelSendInfo* send_channel = GetSendChannel(ssrc);
if (!send_channel) {
LOG(LS_ERROR) << "The specified ssrc " << ssrc << " is not in use.";
@@ -1761,6 +1886,11 @@ bool WebRtcVideoMediaChannel::SetSend(bool send) {
}
bool WebRtcVideoMediaChannel::AddSendStream(const StreamParams& sp) {
+ if (sp.first_ssrc() == 0) {
+ LOG(LS_ERROR) << "AddSendStream with 0 ssrc is not supported.";
+ return false;
+ }
+
LOG(LS_INFO) << "AddSendStream " << sp.ToString();
if (!IsOneSsrcStream(sp) && !IsSimulcastStream(sp)) {
@@ -1828,8 +1958,7 @@ bool WebRtcVideoMediaChannel::AddSendStream(const StreamParams& sp) {
// Reset send codec after stream parameters changed.
if (send_codec_) {
- if (!SetSendCodec(send_channel, *send_codec_, send_min_bitrate_,
- send_start_bitrate_, send_max_bitrate_)) {
+ if (!SetSendCodec(send_channel, *send_codec_)) {
return false;
}
LogSendCodecChange("SetSendStreamFormat()");
@@ -1842,6 +1971,11 @@ bool WebRtcVideoMediaChannel::AddSendStream(const StreamParams& sp) {
}
bool WebRtcVideoMediaChannel::RemoveSendStream(uint32 ssrc) {
+ if (ssrc == 0) {
+ LOG(LS_ERROR) << "RemoveSendStream with 0 ssrc is not supported.";
+ return false;
+ }
+
uint32 ssrc_key;
if (!GetSendChannelKey(ssrc, &ssrc_key)) {
LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
@@ -1882,6 +2016,11 @@ bool WebRtcVideoMediaChannel::RemoveSendStream(uint32 ssrc) {
}
bool WebRtcVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
+ if (sp.first_ssrc() == 0) {
+ LOG(LS_ERROR) << "AddRecvStream with 0 ssrc is not supported.";
+ return false;
+ }
+
// TODO(zhurunz) Remove this once BWE works properly across different send
// and receive channels.
// Reuse default channel for recv stream in 1:1 call.
@@ -1890,6 +2029,9 @@ bool WebRtcVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
<< " reuse default channel #"
<< vie_channel_;
first_receive_ssrc_ = sp.first_ssrc();
+ if (!MaybeSetRtxSsrc(sp, vie_channel_)) {
+ return false;
+ }
if (render_started_) {
if (engine()->vie()->render()->StartRender(vie_channel_) !=0) {
LOG_RTCERR1(StartRender, vie_channel_);
@@ -1898,36 +2040,37 @@ bool WebRtcVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
return true;
}
- if (recv_channels_.find(sp.first_ssrc()) != recv_channels_.end() ||
- first_receive_ssrc_ == sp.first_ssrc()) {
- LOG(LS_ERROR) << "Stream already exists";
- return false;
- }
-
- // TODO(perkj): Implement recv media from multiple media SSRCs per stream.
- // NOTE: We have two SSRCs per stream when RTX is enabled.
- if (!IsOneSsrcStream(sp)) {
- LOG(LS_ERROR) << "WebRtcVideoMediaChannel supports one primary SSRC per"
- << " stream and one FID SSRC per primary SSRC.";
- return false;
- }
-
- // Create a new channel for receiving video data.
- // In order to get the bandwidth estimation work fine for
- // receive only channels, we connect all receiving channels
- // to our master send channel.
int channel_id = -1;
- if (!CreateChannel(sp.first_ssrc(), MD_RECV, &channel_id)) {
- return false;
+ RecvChannelMap::iterator channel_iterator =
+ recv_channels_.find(sp.first_ssrc());
+ if (channel_iterator == recv_channels_.end() &&
+ first_receive_ssrc_ != sp.first_ssrc()) {
+ // TODO(perkj): Implement recv media from multiple media SSRCs per stream.
+ // NOTE: We have two SSRCs per stream when RTX is enabled.
+ if (!IsOneSsrcStream(sp)) {
+ LOG(LS_ERROR) << "WebRtcVideoMediaChannel supports one primary SSRC per"
+ << " stream and one FID SSRC per primary SSRC.";
+ return false;
+ }
+
+ // Create a new channel for receiving video data.
+ // In order to get the bandwidth estimation work fine for
+ // receive only channels, we connect all receiving channels
+ // to our master send channel.
+ if (!CreateChannel(sp.first_ssrc(), MD_RECV, &channel_id)) {
+ return false;
+ }
+ } else {
+ // Already exists.
+ if (first_receive_ssrc_ == sp.first_ssrc()) {
+ return false;
+ }
+ // Early receive added channel.
+ channel_id = (*channel_iterator).second->channel_id();
}
+ channel_iterator = recv_channels_.find(sp.first_ssrc());
- // Set the corresponding RTX SSRC.
- uint32 rtx_ssrc;
- bool has_rtx = sp.GetFidSsrc(sp.first_ssrc(), &rtx_ssrc);
- if (has_rtx && engine()->vie()->rtp()->SetRemoteSSRCType(
- channel_id, webrtc::kViEStreamTypeRtx, rtx_ssrc) != 0) {
- LOG_RTCERR3(SetRemoteSSRCType, channel_id, webrtc::kViEStreamTypeRtx,
- rtx_ssrc);
+ if (!MaybeSetRtxSsrc(sp, channel_id)) {
return false;
}
@@ -1957,9 +2100,34 @@ bool WebRtcVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
return true;
}
+bool WebRtcVideoMediaChannel::MaybeSetRtxSsrc(const StreamParams& sp,
+ int channel_id) {
+ uint32 rtx_ssrc;
+ bool has_rtx = sp.GetFidSsrc(sp.first_ssrc(), &rtx_ssrc);
+ if (has_rtx) {
+ LOG(LS_INFO) << "Setting rtx ssrc " << rtx_ssrc << " for stream "
+ << sp.first_ssrc();
+ if (engine()->vie()->rtp()->SetRemoteSSRCType(
+ channel_id, webrtc::kViEStreamTypeRtx, rtx_ssrc) != 0) {
+ LOG_RTCERR3(SetRemoteSSRCType, channel_id, webrtc::kViEStreamTypeRtx,
+ rtx_ssrc);
+ return false;
+ }
+ rtx_to_primary_ssrc_[rtx_ssrc] = sp.first_ssrc();
+ }
+ return true;
+}
+
bool WebRtcVideoMediaChannel::RemoveRecvStream(uint32 ssrc) {
- RecvChannelMap::iterator it = recv_channels_.find(ssrc);
+ if (ssrc == 0) {
+ LOG(LS_ERROR) << "RemoveRecvStream with 0 ssrc is not supported.";
+ return false;
+ }
+ return RemoveRecvStreamInternal(ssrc);
+}
+bool WebRtcVideoMediaChannel::RemoveRecvStreamInternal(uint32 ssrc) {
+ RecvChannelMap::iterator it = recv_channels_.find(ssrc);
if (it == recv_channels_.end()) {
// TODO(perkj): Remove this once BWE works properly across different send
// and receive channels.
@@ -1979,6 +2147,17 @@ bool WebRtcVideoMediaChannel::RemoveRecvStream(uint32 ssrc) {
return false;
}
WebRtcVideoChannelRecvInfo* info = it->second;
+
+ // Remove any RTX SSRC mappings to this stream.
+ SsrcMap::iterator rtx_it = rtx_to_primary_ssrc_.begin();
+ while (rtx_it != rtx_to_primary_ssrc_.end()) {
+ if (rtx_it->second == ssrc) {
+ rtx_to_primary_ssrc_.erase(rtx_it++);
+ } else {
+ ++rtx_it;
+ }
+ }
+
int channel_id = info->channel_id();
if (engine()->vie()->render()->RemoveRenderer(channel_id) != 0) {
LOG_RTCERR1(RemoveRenderer, channel_id);
@@ -2175,7 +2354,7 @@ bool WebRtcVideoMediaChannel::DeleteSendChannel(uint32 ssrc_key) {
}
WebRtcVideoChannelSendInfo* send_channel = send_channels_[ssrc_key];
MaybeDisconnectCapturer(send_channel->video_capturer());
- send_channel->set_video_capturer(NULL);
+ send_channel->set_video_capturer(NULL, engine()->vie());
int channel_id = send_channel->channel_id();
int capture_id = send_channel->capture_id();
@@ -2215,7 +2394,7 @@ bool WebRtcVideoMediaChannel::RemoveCapturer(uint32 ssrc) {
return false;
}
MaybeDisconnectCapturer(capturer);
- send_channel->set_video_capturer(NULL);
+ send_channel->set_video_capturer(NULL, engine()->vie());
const int64 timestamp = send_channel->local_stream_info()->time_stamp();
if (send_codec_) {
QueueBlackFrame(ssrc, timestamp, send_codec_->maxFramerate);
@@ -2244,7 +2423,8 @@ bool WebRtcVideoMediaChannel::SetRenderer(uint32 ssrc,
return true;
}
-bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
+bool WebRtcVideoMediaChannel::GetStats(const StatsOptions& options,
+ VideoMediaInfo* info) {
// Get sender statistics and build VideoSenderInfo.
unsigned int total_bitrate_sent = 0;
unsigned int video_bitrate_sent = 0;
@@ -2288,22 +2468,58 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
sinfo.packets_cached = -1;
sinfo.packets_lost = -1;
sinfo.fraction_lost = -1;
- sinfo.firs_rcvd = -1;
- sinfo.nacks_rcvd = -1;
sinfo.rtt_ms = -1;
- sinfo.frame_width = static_cast<int>(channel_stream_info->width());
- sinfo.frame_height = static_cast<int>(channel_stream_info->height());
+
+ VideoCapturer* video_capturer = send_channel->video_capturer();
+ if (video_capturer) {
+ VideoFormat last_captured_frame_format;
+ video_capturer->GetStats(&sinfo.adapt_frame_drops,
+ &sinfo.effects_frame_drops,
+ &sinfo.capturer_frame_time,
+ &last_captured_frame_format);
+ sinfo.input_frame_width = last_captured_frame_format.width;
+ sinfo.input_frame_height = last_captured_frame_format.height;
+ } else {
+ sinfo.input_frame_width = 0;
+ sinfo.input_frame_height = 0;
+ }
+
+ webrtc::VideoCodec vie_codec;
+ if (!video_capturer || video_capturer->IsMuted()) {
+ sinfo.send_frame_width = 0;
+ sinfo.send_frame_height = 0;
+ } else if (engine()->vie()->codec()->GetSendCodec(channel_id,
+ vie_codec) == 0) {
+ sinfo.send_frame_width = vie_codec.width;
+ sinfo.send_frame_height = vie_codec.height;
+ } else {
+ sinfo.send_frame_width = -1;
+ sinfo.send_frame_height = -1;
+ LOG_RTCERR1(GetSendCodec, channel_id);
+ }
sinfo.framerate_input = channel_stream_info->framerate();
sinfo.framerate_sent = send_channel->encoder_observer()->framerate();
sinfo.nominal_bitrate = send_channel->encoder_observer()->bitrate();
- sinfo.preferred_bitrate = send_max_bitrate_;
+ if (send_codec_) {
+ sinfo.preferred_bitrate = GetBitrate(
+ send_codec_->maxBitrate, kMaxVideoBitrate);
+ }
sinfo.adapt_reason = send_channel->CurrentAdaptReason();
+
+#ifdef USE_WEBRTC_DEV_BRANCH
+ webrtc::CpuOveruseMetrics metrics;
+ engine()->vie()->base()->GetCpuOveruseMetrics(channel_id, &metrics);
+ sinfo.capture_jitter_ms = metrics.capture_jitter_ms;
+ sinfo.avg_encode_ms = metrics.avg_encode_time_ms;
+ sinfo.encode_usage_percent = metrics.encode_usage_percent;
+ sinfo.encode_rsd = metrics.encode_rsd;
+ sinfo.capture_queue_delay_ms_per_s = metrics.capture_queue_delay_ms_per_s;
+#else
sinfo.capture_jitter_ms = -1;
sinfo.avg_encode_ms = -1;
sinfo.encode_usage_percent = -1;
sinfo.capture_queue_delay_ms_per_s = -1;
-#ifdef USE_WEBRTC_DEV_BRANCH
int capture_jitter_ms = 0;
int avg_encode_time_ms = 0;
int encode_usage_percent = 0;
@@ -2321,6 +2537,20 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
}
#endif
+ webrtc::RtcpPacketTypeCounter rtcp_sent;
+ webrtc::RtcpPacketTypeCounter rtcp_received;
+ if (engine()->vie()->rtp()->GetRtcpPacketTypeCounters(
+ channel_id, &rtcp_sent, &rtcp_received) == 0) {
+ sinfo.firs_rcvd = rtcp_received.fir_packets;
+ sinfo.plis_rcvd = rtcp_received.pli_packets;
+ sinfo.nacks_rcvd = rtcp_received.nack_packets;
+ } else {
+ sinfo.firs_rcvd = -1;
+ sinfo.plis_rcvd = -1;
+ sinfo.nacks_rcvd = -1;
+ LOG_RTCERR1(GetRtcpPacketTypeCounters, channel_id);
+ }
+
// Get received RTCP statistics for the sender (reported by the remote
// client in a RTCP packet), if available.
// It's not a fatal error if we can't, since RTCP may not have arrived
@@ -2355,13 +2585,6 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
LOG_RTCERR1(GetBandwidthUsage, channel_id);
}
- unsigned int estimated_stream_send_bandwidth = 0;
- if (engine_->vie()->rtp()->GetEstimatedSendBandwidth(
- channel_id, &estimated_stream_send_bandwidth) == 0) {
- estimated_send_bandwidth += estimated_stream_send_bandwidth;
- } else {
- LOG_RTCERR1(GetEstimatedSendBandwidth, channel_id);
- }
unsigned int target_enc_stream_bitrate = 0;
if (engine_->vie()->codec()->GetCodecTargetBitrate(
channel_id, &target_enc_stream_bitrate) == 0) {
@@ -2370,21 +2593,27 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
LOG_RTCERR1(GetCodecTargetBitrate, channel_id);
}
}
+ if (!send_channels_.empty()) {
+ // GetEstimatedSendBandwidth returns the estimated bandwidth for all video
+ // engine channels in a channel group. Any valid channel id will do as it
+ // is only used to access the right group of channels.
+ const int channel_id = send_channels_.begin()->second->channel_id();
+ // Get the send bandwidth available for this MediaChannel.
+ if (engine_->vie()->rtp()->GetEstimatedSendBandwidth(
+ channel_id, &estimated_send_bandwidth) != 0) {
+ LOG_RTCERR1(GetEstimatedSendBandwidth, channel_id);
+ }
+ }
} else {
LOG(LS_WARNING) << "GetStats: sender information not ready.";
}
// Get the SSRC and stats for each receiver, based on our own calculations.
- unsigned int estimated_recv_bandwidth = 0;
for (RecvChannelMap::const_iterator it = recv_channels_.begin();
it != recv_channels_.end(); ++it) {
- // Don't report receive statistics from the default channel if we have
- // specified receive channels.
- if (it->first == 0 && recv_channels_.size() > 1)
- continue;
WebRtcVideoChannelRecvInfo* channel = it->second;
- unsigned int ssrc;
+ unsigned int ssrc = 0;
// Get receiver statistics and build VideoReceiverInfo, if we have data.
// Skip the default channel (ssrc == 0).
if (engine_->vie()->rtp()->GetRemoteSSRC(
@@ -2406,14 +2635,29 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
rinfo.packets_lost = -1;
rinfo.packets_concealed = -1;
rinfo.fraction_lost = -1; // from SentRTCP
- rinfo.nacks_sent = -1;
rinfo.frame_width = channel->render_adapter()->width();
rinfo.frame_height = channel->render_adapter()->height();
int fps = channel->render_adapter()->framerate();
rinfo.framerate_decoded = fps;
rinfo.framerate_output = fps;
+ rinfo.capture_start_ntp_time_ms =
+ channel->render_adapter()->capture_start_ntp_time_ms();
channel->decoder_observer()->ExportTo(&rinfo);
+ webrtc::RtcpPacketTypeCounter rtcp_sent;
+ webrtc::RtcpPacketTypeCounter rtcp_received;
+ if (engine()->vie()->rtp()->GetRtcpPacketTypeCounters(
+ channel->channel_id(), &rtcp_sent, &rtcp_received) == 0) {
+ rinfo.firs_sent = rtcp_sent.fir_packets;
+ rinfo.plis_sent = rtcp_sent.pli_packets;
+ rinfo.nacks_sent = rtcp_sent.nack_packets;
+ } else {
+ rinfo.firs_sent = -1;
+ rinfo.plis_sent = -1;
+ rinfo.nacks_sent = -1;
+ LOG_RTCERR1(GetRtcpPacketTypeCounters, channel->channel_id());
+ }
+
// Get our locally created statistics of the received RTP stream.
webrtc::RtcpStatistics incoming_stream_rtcp_stats;
int incoming_stream_rtt_ms;
@@ -2427,13 +2671,17 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
incoming_stream_rtcp_stats.fraction_lost) / (1 << 8);
}
info->receivers.push_back(rinfo);
-
- unsigned int estimated_recv_stream_bandwidth = 0;
+ }
+ unsigned int estimated_recv_bandwidth = 0;
+ if (!recv_channels_.empty()) {
+ // GetEstimatedReceiveBandwidth returns the estimated bandwidth for all
+ // video engine channels in a channel group. Any valid channel id will do as
+ // it is only used to access the right group of channels.
+ const int channel_id = recv_channels_.begin()->second->channel_id();
+ // Gets the estimated receive bandwidth for the MediaChannel.
if (engine_->vie()->rtp()->GetEstimatedReceiveBandwidth(
- channel->channel_id(), &estimated_recv_stream_bandwidth) == 0) {
- estimated_recv_bandwidth += estimated_recv_stream_bandwidth;
- } else {
- LOG_RTCERR1(GetEstimatedReceiveBandwidth, channel->channel_id());
+ channel_id, &estimated_recv_bandwidth) != 0) {
+ LOG_RTCERR1(GetEstimatedReceiveBandwidth, channel_id);
}
}
@@ -2441,6 +2689,26 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
// TODO(zhurunz): Add real unittest for this.
BandwidthEstimationInfo bwe;
+ // TODO(jiayl): remove the condition when the necessary changes are available
+ // outside the dev branch.
+ if (options.include_received_propagation_stats) {
+ webrtc::ReceiveBandwidthEstimatorStats additional_stats;
+ // Only call for the default channel because the returned stats are
+ // collected for all the channels using the same estimator.
+ if (engine_->vie()->rtp()->GetReceiveBandwidthEstimatorStats(
+ recv_channels_[0]->channel_id(), &additional_stats) == 0) {
+ bwe.total_received_propagation_delta_ms =
+ additional_stats.total_propagation_time_delta_ms;
+ bwe.recent_received_propagation_delta_ms.swap(
+ additional_stats.recent_propagation_time_delta_ms);
+ bwe.recent_received_packet_group_arrival_time_ms.swap(
+ additional_stats.recent_arrival_time_ms);
+ }
+ }
+
+ engine_->vie()->rtp()->GetPacerQueuingDelayMs(
+ recv_channels_[0]->channel_id(), &bwe.bucket_delay);
+
// Calculations done above per send/receive stream.
bwe.actual_enc_bitrate = video_bitrate_sent;
bwe.transmit_bitrate = total_bitrate_sent;
@@ -2467,7 +2735,7 @@ bool WebRtcVideoMediaChannel::SetCapturer(uint32 ssrc,
VideoCapturer* old_capturer = send_channel->video_capturer();
MaybeDisconnectCapturer(old_capturer);
- send_channel->set_video_capturer(capturer);
+ send_channel->set_video_capturer(capturer, engine()->vie());
MaybeConnectCapturer(capturer);
if (!capturer->IsScreencast() && ratio_w_ != 0 && ratio_h_ != 0) {
capturer->UpdateAspectRatio(ratio_w_, ratio_h_);
@@ -2493,20 +2761,24 @@ void WebRtcVideoMediaChannel::OnPacketReceived(
uint32 ssrc = 0;
if (!GetRtpSsrc(packet->data(), packet->length(), &ssrc))
return;
- int which_channel = GetRecvChannelNum(ssrc);
- if (which_channel == -1) {
- which_channel = video_channel();
+ int processing_channel = GetRecvChannelNum(ssrc);
+ if (processing_channel == -1) {
+ // Allocate an unsignalled recv channel for processing in conference mode.
+ if (!InConferenceMode()) {
+ // If we can't find or allocate one, use the default.
+ processing_channel = video_channel();
+ } else if (!CreateUnsignalledRecvChannel(ssrc, &processing_channel)) {
+ // If we can't create an unsignalled recv channel, drop the packet in
+ // conference mode.
+ return;
+ }
}
engine()->vie()->network()->ReceivedRTPPacket(
- which_channel,
+ processing_channel,
packet->data(),
-#ifdef USE_WEBRTC_DEV_BRANCH
static_cast<int>(packet->length()),
webrtc::PacketTime(packet_time.timestamp, packet_time.not_before));
-#else
- static_cast<int>(packet->length()));
-#endif
}
void WebRtcVideoMediaChannel::OnRtcpReceived(
@@ -2570,12 +2842,11 @@ bool WebRtcVideoMediaChannel::SetRecvRtpHeaderExtensions(
if (receive_extensions_ == extensions) {
return true;
}
- receive_extensions_ = extensions;
const RtpHeaderExtension* offset_extension =
FindHeaderExtension(extensions, kRtpTimestampOffsetHeaderExtension);
const RtpHeaderExtension* send_time_extension =
- FindHeaderExtension(extensions, kRtpAbsoluteSendTimeHeaderExtension);
+ FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
// Loop through all receive channels and enable/disable the extensions.
for (RecvChannelMap::iterator channel_it = recv_channels_.begin();
@@ -2592,17 +2863,21 @@ bool WebRtcVideoMediaChannel::SetRecvRtpHeaderExtensions(
return false;
}
}
+
+ receive_extensions_ = extensions;
return true;
}
bool WebRtcVideoMediaChannel::SetSendRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) {
- send_extensions_ = extensions;
+ if (send_extensions_ == extensions) {
+ return true;
+ }
const RtpHeaderExtension* offset_extension =
FindHeaderExtension(extensions, kRtpTimestampOffsetHeaderExtension);
const RtpHeaderExtension* send_time_extension =
- FindHeaderExtension(extensions, kRtpAbsoluteSendTimeHeaderExtension);
+ FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
// Loop through all send channels and enable/disable the extensions.
for (SendChannelMap::iterator channel_it = send_channels_.begin();
@@ -2619,44 +2894,64 @@ bool WebRtcVideoMediaChannel::SetSendRtpHeaderExtensions(
return false;
}
}
+
+ if (send_time_extension) {
+ // For video RTP packets, we would like to update AbsoluteSendTimeHeader
+ // Extension closer to the network, @ socket level before sending.
+ // Pushing the extension id to socket layer.
+ MediaChannel::SetOption(NetworkInterface::ST_RTP,
+ talk_base::Socket::OPT_RTP_SENDTIME_EXTN_ID,
+ send_time_extension->id);
+ }
+
+ send_extensions_ = extensions;
return true;
}
-bool WebRtcVideoMediaChannel::SetSendBandwidth(bool autobw, int bps) {
- LOG(LS_INFO) << "WebRtcVideoMediaChanne::SetSendBandwidth";
+int WebRtcVideoMediaChannel::GetRtpSendTimeExtnId() const {
+ const RtpHeaderExtension* send_time_extension = FindHeaderExtension(
+ send_extensions_, kRtpAbsoluteSenderTimeHeaderExtension);
+ if (send_time_extension) {
+ return send_time_extension->id;
+ }
+ return -1;
+}
- if (InConferenceMode()) {
- LOG(LS_INFO) << "Conference mode ignores SetSendBandWidth";
+bool WebRtcVideoMediaChannel::SetStartSendBandwidth(int bps) {
+ LOG(LS_INFO) << "WebRtcVideoMediaChannel::SetStartSendBandwidth";
+
+ if (!send_codec_) {
+ LOG(LS_INFO) << "The send codec has not been set up yet";
return true;
}
+ // On success, SetSendCodec() will reset |send_start_bitrate_| to |bps/1000|,
+ // by calling MaybeChangeBitrates. That method will also clamp the
+ // start bitrate between min and max, consistent with the override behavior
+ // in SetMaxSendBandwidth.
+ webrtc::VideoCodec new_codec = *send_codec_;
+ if (BitrateIsSet(bps)) {
+ new_codec.startBitrate = bps / 1000;
+ }
+ return SetSendCodec(new_codec);
+}
+
+bool WebRtcVideoMediaChannel::SetMaxSendBandwidth(int bps) {
+ LOG(LS_INFO) << "WebRtcVideoMediaChannel::SetMaxSendBandwidth";
+
if (!send_codec_) {
LOG(LS_INFO) << "The send codec has not been set up yet";
return true;
}
- int min_bitrate;
- int start_bitrate;
- int max_bitrate;
- if (autobw) {
- // Use the default values for min bitrate.
- min_bitrate = send_min_bitrate_;
- // Use the default value or the bps for the max
- max_bitrate = (bps <= 0) ? send_max_bitrate_ : (bps / 1000);
- // Maximum start bitrate can be kStartVideoBitrate.
- start_bitrate = talk_base::_min(kStartVideoBitrate, max_bitrate);
- } else {
- // Use the default start or the bps as the target bitrate.
- int target_bitrate = (bps <= 0) ? kStartVideoBitrate : (bps / 1000);
- min_bitrate = target_bitrate;
- start_bitrate = target_bitrate;
- max_bitrate = target_bitrate;
+ webrtc::VideoCodec new_codec = *send_codec_;
+ if (BitrateIsSet(bps)) {
+ new_codec.maxBitrate = bps / 1000;
}
-
- if (!SetSendCodec(*send_codec_, min_bitrate, start_bitrate, max_bitrate)) {
+ if (!SetSendCodec(new_codec)) {
return false;
}
- LogSendCodecChange("SetSendBandwidth()");
+ LogSendCodecChange("SetMaxSendBandwidth()");
return true;
}
@@ -2678,9 +2973,6 @@ bool WebRtcVideoMediaChannel::SetOptions(const VideoOptions &options) {
bool buffer_latency_changed = options.buffered_mode_latency.IsSet() &&
(options_.buffered_mode_latency != options.buffered_mode_latency);
- bool cpu_overuse_detection_changed = options.cpu_overuse_detection.IsSet() &&
- (options_.cpu_overuse_detection != options.cpu_overuse_detection);
-
bool dscp_option_changed = (options_.dscp != options.dscp);
bool suspend_below_min_bitrate_changed =
@@ -2694,6 +2986,17 @@ bool WebRtcVideoMediaChannel::SetOptions(const VideoOptions &options) {
conference_mode_turned_off = true;
}
+ bool improved_wifi_bwe_changed =
+ options.use_improved_wifi_bandwidth_estimator.IsSet() &&
+ options_.use_improved_wifi_bandwidth_estimator !=
+ options.use_improved_wifi_bandwidth_estimator;
+
+#ifdef USE_WEBRTC_DEV_BRANCH
+ bool payload_padding_changed = options.use_payload_padding.IsSet() &&
+ options_.use_payload_padding != options.use_payload_padding;
+#endif
+
+
// Save the options, to be interpreted where appropriate.
// Use options_.SetAll() instead of assignment so that unset value in options
// will not overwrite the previous option value.
@@ -2706,48 +3009,52 @@ bool WebRtcVideoMediaChannel::SetOptions(const VideoOptions &options) {
send_channel->ApplyCpuOptions(options_);
}
- // Adjust send codec bitrate if needed.
- int conf_max_bitrate = kDefaultConferenceModeMaxVideoBitrate;
+ if (send_codec_) {
+ bool reset_send_codec_needed = denoiser_changed;
+ webrtc::VideoCodec new_codec = *send_codec_;
+
+ // TODO(pthatcher): Remove this. We don't need 4 ways to set bitrates.
+ bool lower_min_bitrate;
+ if (options.lower_min_bitrate.Get(&lower_min_bitrate)) {
+ new_codec.minBitrate = kLowerMinBitrate;
+ reset_send_codec_needed = true;
+ }
- // Save altered min_bitrate level and apply if necessary.
- bool adjusted_min_bitrate = false;
- if (options.lower_min_bitrate.IsSet()) {
- bool lower;
- options.lower_min_bitrate.Get(&lower);
+ if (conference_mode_turned_off) {
+ // This is a special case for turning conference mode off.
+ // Max bitrate should go back to the default maximum value instead
+ // of the current maximum.
+ new_codec.maxBitrate = kAutoBandwidth;
+ reset_send_codec_needed = true;
+ }
- int new_send_min_bitrate = lower ? kLowerMinBitrate : kMinVideoBitrate;
- adjusted_min_bitrate = (new_send_min_bitrate != send_min_bitrate_);
- send_min_bitrate_ = new_send_min_bitrate;
- }
+ // TODO(pthatcher): Remove this. We don't need 4 ways to set bitrates.
+ int new_start_bitrate;
+ if (options.video_start_bitrate.Get(&new_start_bitrate)) {
+ new_codec.startBitrate = new_start_bitrate;
+ reset_send_codec_needed = true;
+ }
- int expected_bitrate = send_max_bitrate_;
- if (InConferenceMode()) {
- expected_bitrate = conf_max_bitrate;
- } else if (conference_mode_turned_off) {
- // This is a special case for turning conference mode off.
- // Max bitrate should go back to the default maximum value instead
- // of the current maximum.
- expected_bitrate = kMaxVideoBitrate;
- }
-
- if (send_codec_ &&
- (send_max_bitrate_ != expected_bitrate || denoiser_changed ||
- adjusted_min_bitrate)) {
- // On success, SetSendCodec() will reset send_max_bitrate_ to
- // expected_bitrate.
- if (!SetSendCodec(*send_codec_,
- send_min_bitrate_,
- send_start_bitrate_,
- expected_bitrate)) {
- return false;
+
+ LOG(LS_INFO) << "Reset send codec needed is enabled? "
+ << reset_send_codec_needed;
+ if (reset_send_codec_needed) {
+ if (!SetSendCodec(new_codec)) {
+ return false;
+ }
+ LogSendCodecChange("SetOptions()");
}
- LogSendCodecChange("SetOptions()");
}
+
if (leaky_bucket_changed) {
bool enable_leaky_bucket =
- options_.video_leaky_bucket.GetWithDefaultIfUnset(false);
+ options_.video_leaky_bucket.GetWithDefaultIfUnset(true);
+ LOG(LS_INFO) << "Leaky bucket is enabled? " << enable_leaky_bucket;
for (SendChannelMap::iterator it = send_channels_.begin();
it != send_channels_.end(); ++it) {
+ // TODO(holmer): This API will be removed as we move to the new
+ // webrtc::Call API. We should clean up this experiment when that is
+ // happening.
if (engine()->vie()->rtp()->SetTransmissionSmoothingStatus(
it->second->channel_id(), enable_leaky_bucket) != 0) {
LOG_RTCERR2(SetTransmissionSmoothingStatus, it->second->channel_id(),
@@ -2759,6 +3066,7 @@ bool WebRtcVideoMediaChannel::SetOptions(const VideoOptions &options) {
int buffer_latency =
options_.buffered_mode_latency.GetWithDefaultIfUnset(
cricket::kBufferedModeDisabled);
+ LOG(LS_INFO) << "Buffer latency is " << buffer_latency;
for (SendChannelMap::iterator it = send_channels_.begin();
it != send_channels_.end(); ++it) {
if (engine()->vie()->rtp()->SetSenderBufferingMode(
@@ -2776,25 +3084,18 @@ bool WebRtcVideoMediaChannel::SetOptions(const VideoOptions &options) {
}
}
}
- if (cpu_overuse_detection_changed) {
- bool cpu_overuse_detection =
- options_.cpu_overuse_detection.GetWithDefaultIfUnset(false);
- for (SendChannelMap::iterator iter = send_channels_.begin();
- iter != send_channels_.end(); ++iter) {
- WebRtcVideoChannelSendInfo* send_channel = iter->second;
- send_channel->SetCpuOveruseDetection(cpu_overuse_detection);
- }
- }
if (dscp_option_changed) {
talk_base::DiffServCodePoint dscp = talk_base::DSCP_DEFAULT;
- if (options.dscp.GetWithDefaultIfUnset(false))
+ if (options_.dscp.GetWithDefaultIfUnset(false))
dscp = kVideoDscpValue;
+ LOG(LS_INFO) << "DSCP is " << dscp;
if (MediaChannel::SetDscp(dscp) != 0) {
LOG(LS_WARNING) << "Failed to set DSCP settings for video channel";
}
}
if (suspend_below_min_bitrate_changed) {
if (options_.suspend_below_min_bitrate.GetWithDefaultIfUnset(false)) {
+ LOG(LS_INFO) << "Suspend below min bitrate enabled.";
for (SendChannelMap::iterator it = send_channels_.begin();
it != send_channels_.end(); ++it) {
engine()->vie()->codec()->SuspendBelowMinBitrate(
@@ -2804,6 +3105,39 @@ bool WebRtcVideoMediaChannel::SetOptions(const VideoOptions &options) {
LOG(LS_WARNING) << "Cannot disable video suspension once it is enabled";
}
}
+ if (improved_wifi_bwe_changed) {
+ LOG(LS_INFO) << "Improved WIFI BWE called.";
+ webrtc::Config config;
+ config.Set(new webrtc::AimdRemoteRateControl(
+ options_.use_improved_wifi_bandwidth_estimator
+ .GetWithDefaultIfUnset(false)));
+ for (SendChannelMap::iterator it = send_channels_.begin();
+ it != send_channels_.end(); ++it) {
+ engine()->vie()->network()->SetBandwidthEstimationConfig(
+ it->second->channel_id(), config);
+ }
+ }
+#ifdef USE_WEBRTC_DEV_BRANCH
+ if (payload_padding_changed) {
+ LOG(LS_INFO) << "Payload-based padding called.";
+ for (SendChannelMap::iterator it = send_channels_.begin();
+ it != send_channels_.end(); ++it) {
+ engine()->vie()->rtp()->SetPadWithRedundantPayloads(
+ it->second->channel_id(),
+ options_.use_payload_padding.GetWithDefaultIfUnset(false));
+ }
+ }
+#endif
+ webrtc::CpuOveruseOptions overuse_options;
+ if (GetCpuOveruseOptions(options_, &overuse_options)) {
+ for (SendChannelMap::iterator it = send_channels_.begin();
+ it != send_channels_.end(); ++it) {
+ if (engine()->vie()->base()->SetCpuOveruseOptions(
+ it->second->channel_id(), overuse_options) != 0) {
+ LOG_RTCERR1(SetCpuOveruseOptions, it->second->channel_id());
+ }
+ }
+ }
return true;
}
@@ -2858,6 +3192,16 @@ bool WebRtcVideoMediaChannel::GetRenderer(uint32 ssrc,
return true;
}
+bool WebRtcVideoMediaChannel::GetVideoAdapter(
+ uint32 ssrc, CoordinatedVideoAdapter** video_adapter) {
+ SendChannelMap::iterator it = send_channels_.find(ssrc);
+ if (it == send_channels_.end()) {
+ return false;
+ }
+ *video_adapter = it->second->video_adapter();
+ return true;
+}
+
void WebRtcVideoMediaChannel::SendFrame(VideoCapturer* capturer,
const VideoFrame* frame) {
// If the |capturer| is registered to any send channel, then send the frame
@@ -2939,6 +3283,8 @@ bool WebRtcVideoMediaChannel::SendFrame(
// TODO(justinlin): Reenable after Windows issues with clock drift are fixed.
// Currently reverted to old behavior of discarding capture timestamp.
#if 0
+ static const int kTimestampDeltaInSecondsForWarning = 2;
+
// If the frame timestamp is 0, we will use the deliver time.
const int64 frame_timestamp = frame->GetTimeStamp();
if (frame_timestamp != 0) {
@@ -3007,6 +3353,22 @@ bool WebRtcVideoMediaChannel::CreateChannel(uint32 ssrc_key,
return true;
}
+bool WebRtcVideoMediaChannel::CreateUnsignalledRecvChannel(
+ uint32 ssrc_key, int* out_channel_id) {
+ int unsignalled_recv_channel_limit =
+ options_.unsignalled_recv_stream_limit.GetWithDefaultIfUnset(
+ kNumDefaultUnsignalledVideoRecvStreams);
+ if (num_unsignalled_recv_channels_ >= unsignalled_recv_channel_limit) {
+ return false;
+ }
+ if (!CreateChannel(ssrc_key, MD_RECV, out_channel_id)) {
+ return false;
+ }
+ // TODO(tvsriram): Support dynamic sizing of unsignalled recv channels.
+ num_unsignalled_recv_channels_++;
+ return true;
+}
+
bool WebRtcVideoMediaChannel::ConfigureChannel(int channel_id,
MediaDirection direction,
uint32 ssrc_key) {
@@ -3055,6 +3417,13 @@ bool WebRtcVideoMediaChannel::ConfigureChannel(int channel_id,
}
}
+ // Start receiving for both receive and send channels so that we get incoming
+ // RTP (if receiving) as well as RTCP feedback (if sending).
+ if (engine()->vie()->base()->StartReceive(channel_id) != 0) {
+ LOG_RTCERR1(StartReceive, channel_id);
+ return false;
+ }
+
return true;
}
@@ -3104,10 +3473,9 @@ bool WebRtcVideoMediaChannel::ConfigureReceiving(int channel_id,
channel_id, receive_extensions_, kRtpTimestampOffsetHeaderExtension)) {
return false;
}
-
if (!SetHeaderExtension(
&webrtc::ViERTP_RTCP::SetReceiveAbsoluteSendTimeStatus, channel_id,
- receive_extensions_, kRtpAbsoluteSendTimeHeaderExtension)) {
+ receive_extensions_, kRtpAbsoluteSenderTimeHeaderExtension)) {
return false;
}
@@ -3196,17 +3564,16 @@ bool WebRtcVideoMediaChannel::ConfigureSending(int channel_id,
new WebRtcVideoChannelSendInfo(channel_id, vie_capture,
external_capture,
engine()->cpu_monitor()));
- if (engine()->vie()->base()->RegisterCpuOveruseObserver(
- channel_id, send_channel->overuse_observer())) {
- LOG_RTCERR1(RegisterCpuOveruseObserver, channel_id);
- return false;
- }
send_channel->ApplyCpuOptions(options_);
send_channel->SignalCpuAdaptationUnable.connect(this,
&WebRtcVideoMediaChannel::OnCpuAdaptationUnable);
- if (options_.cpu_overuse_detection.GetWithDefaultIfUnset(false)) {
- send_channel->SetCpuOveruseDetection(true);
+ webrtc::CpuOveruseOptions overuse_options;
+ if (GetCpuOveruseOptions(options_, &overuse_options)) {
+ if (engine()->vie()->base()->SetCpuOveruseOptions(channel_id,
+ overuse_options) != 0) {
+ LOG_RTCERR1(SetCpuOveruseOptions, channel_id);
+ }
}
// Register encoder observer for outgoing framerate and bitrate.
@@ -3222,11 +3589,11 @@ bool WebRtcVideoMediaChannel::ConfigureSending(int channel_id,
}
if (!SetHeaderExtension(&webrtc::ViERTP_RTCP::SetSendAbsoluteSendTimeStatus,
- channel_id, send_extensions_, kRtpAbsoluteSendTimeHeaderExtension)) {
+ channel_id, send_extensions_, kRtpAbsoluteSenderTimeHeaderExtension)) {
return false;
}
- if (options_.video_leaky_bucket.GetWithDefaultIfUnset(false)) {
+ if (options_.video_leaky_bucket.GetWithDefaultIfUnset(true)) {
if (engine()->vie()->rtp()->SetTransmissionSmoothingStatus(channel_id,
true) != 0) {
LOG_RTCERR2(SetTransmissionSmoothingStatus, channel_id, true);
@@ -3243,6 +3610,11 @@ bool WebRtcVideoMediaChannel::ConfigureSending(int channel_id,
LOG_RTCERR2(SetSenderBufferingMode, channel_id, buffer_latency);
}
}
+
+ if (options_.suspend_below_min_bitrate.GetWithDefaultIfUnset(false)) {
+ engine()->vie()->codec()->SuspendBelowMinBitrate(channel_id);
+ }
+
// The remb status direction correspond to the RTP stream (and not the RTCP
// stream). I.e. if send remb is enabled it means it is receiving remote
// rembs and should use them to estimate bandwidth. Receive remb mean that
@@ -3291,32 +3663,24 @@ bool WebRtcVideoMediaChannel::SetNackFec(int channel_id,
return true;
}
-bool WebRtcVideoMediaChannel::SetSendCodec(const webrtc::VideoCodec& codec,
- int min_bitrate,
- int start_bitrate,
- int max_bitrate) {
+bool WebRtcVideoMediaChannel::SetSendCodec(const webrtc::VideoCodec& codec) {
bool ret_val = true;
for (SendChannelMap::iterator iter = send_channels_.begin();
iter != send_channels_.end(); ++iter) {
WebRtcVideoChannelSendInfo* send_channel = iter->second;
- ret_val = SetSendCodec(send_channel, codec, min_bitrate, start_bitrate,
- max_bitrate) && ret_val;
+ ret_val = SetSendCodec(send_channel, codec) && ret_val;
}
if (ret_val) {
// All SetSendCodec calls were successful. Update the global state
// accordingly.
send_codec_.reset(new webrtc::VideoCodec(codec));
- send_min_bitrate_ = min_bitrate;
- send_start_bitrate_ = start_bitrate;
- send_max_bitrate_ = max_bitrate;
} else {
// At least one SetSendCodec call failed, rollback.
for (SendChannelMap::iterator iter = send_channels_.begin();
iter != send_channels_.end(); ++iter) {
WebRtcVideoChannelSendInfo* send_channel = iter->second;
if (send_codec_) {
- SetSendCodec(send_channel, *send_codec_.get(), send_min_bitrate_,
- send_start_bitrate_, send_max_bitrate_);
+ SetSendCodec(send_channel, *send_codec_);
}
}
}
@@ -3325,19 +3689,14 @@ bool WebRtcVideoMediaChannel::SetSendCodec(const webrtc::VideoCodec& codec,
bool WebRtcVideoMediaChannel::SetSendCodec(
WebRtcVideoChannelSendInfo* send_channel,
- const webrtc::VideoCodec& codec,
- int min_bitrate,
- int start_bitrate,
- int max_bitrate) {
+ const webrtc::VideoCodec& codec) {
if (!send_channel) {
return false;
}
+
const int channel_id = send_channel->channel_id();
// Make a copy of the codec
webrtc::VideoCodec target_codec = codec;
- target_codec.startBitrate = start_bitrate;
- target_codec.minBitrate = min_bitrate;
- target_codec.maxBitrate = max_bitrate;
// Set the default number of temporal layers for VP8.
if (webrtc::kVideoCodecVP8 == codec.codecType) {
@@ -3348,7 +3707,7 @@ bool WebRtcVideoMediaChannel::SetSendCodec(
target_codec.codecSpecific.VP8.resilience = webrtc::kResilienceOff;
bool enable_denoising =
- options_.video_noise_reduction.GetWithDefaultIfUnset(false);
+ options_.video_noise_reduction.GetWithDefaultIfUnset(true);
target_codec.codecSpecific.VP8.denoisingOn = enable_denoising;
}
@@ -3377,7 +3736,16 @@ bool WebRtcVideoMediaChannel::SetSendCodec(
LOG(LS_INFO) << "0x0 resolution selected. Captured frames will be dropped "
<< "for ssrc: " << ssrc << ".";
} else {
- MaybeChangeStartBitrate(channel_id, &target_codec);
+ MaybeChangeBitrates(channel_id, &target_codec);
+ webrtc::VideoCodec current_codec;
+ if (!engine()->vie()->codec()->GetSendCodec(channel_id, current_codec)) {
+ // Compare against existing configured send codec.
+ if (current_codec == target_codec) {
+ // Codec is already configured on channel. no need to apply.
+ return true;
+ }
+ }
+
if (0 != engine()->vie()->codec()->SetSendCodec(channel_id, target_codec)) {
LOG_RTCERR2(SetSendCodec, channel_id, target_codec.plName);
return false;
@@ -3477,6 +3845,13 @@ bool WebRtcVideoMediaChannel::SetReceiveCodecs(
int red_type = -1;
int fec_type = -1;
int channel_id = info->channel_id();
+ // Build a map from payload types to video codecs so that we easily can find
+ // out if associated payload types are referring to valid codecs.
+ std::map<int, webrtc::VideoCodec*> pt_to_codec;
+ for (std::vector<webrtc::VideoCodec>::iterator it = receive_codecs_.begin();
+ it != receive_codecs_.end(); ++it) {
+ pt_to_codec[it->plType] = &(*it);
+ }
for (std::vector<webrtc::VideoCodec>::iterator it = receive_codecs_.begin();
it != receive_codecs_.end(); ++it) {
if (it->codecType == webrtc::kVideoCodecRED) {
@@ -3484,6 +3859,32 @@ bool WebRtcVideoMediaChannel::SetReceiveCodecs(
} else if (it->codecType == webrtc::kVideoCodecULPFEC) {
fec_type = it->plType;
}
+ // If this is an RTX codec we have to verify that it is associated with
+ // a valid video codec which we have RTX support for.
+ if (_stricmp(it->plName, kRtxCodecName) == 0) {
+ std::map<int, int>::iterator apt_it = associated_payload_types_.find(
+ it->plType);
+ bool valid_apt = false;
+ if (apt_it != associated_payload_types_.end()) {
+ std::map<int, webrtc::VideoCodec*>::iterator codec_it =
+ pt_to_codec.find(apt_it->second);
+ // We currently only support RTX associated with VP8 due to limitations
+ // in webrtc where only one RTX payload type can be registered.
+ valid_apt = codec_it != pt_to_codec.end() &&
+ _stricmp(codec_it->second->plName, kVp8PayloadName) == 0;
+ }
+ if (!valid_apt) {
+ LOG(LS_ERROR) << "The RTX codec isn't associated with a known and "
+ "supported payload type";
+ return false;
+ }
+ if (engine()->vie()->rtp()->SetRtxReceivePayloadType(
+ channel_id, it->plType) != 0) {
+ LOG_RTCERR2(SetRtxReceivePayloadType, channel_id, it->plType);
+ return false;
+ }
+ continue;
+ }
if (engine()->vie()->codec()->SetReceiveCodec(channel_id, *it) != 0) {
LOG_RTCERR2(SetReceiveCodec, channel_id, it->plName);
return false;
@@ -3504,14 +3905,6 @@ bool WebRtcVideoMediaChannel::SetReceiveCodecs(
}
}
}
-
- // Start receiving packets if at least one receive codec has been set.
- if (!receive_codecs_.empty()) {
- if (engine()->vie()->base()->StartReceive(channel_id) != 0) {
- LOG_RTCERR1(StartReceive, channel_id);
- return false;
- }
- }
return true;
}
@@ -3519,14 +3912,32 @@ int WebRtcVideoMediaChannel::GetRecvChannelNum(uint32 ssrc) {
if (ssrc == first_receive_ssrc_) {
return vie_channel_;
}
+ int recv_channel = -1;
RecvChannelMap::iterator it = recv_channels_.find(ssrc);
- return (it != recv_channels_.end()) ? it->second->channel_id() : -1;
+ if (it == recv_channels_.end()) {
+ // Check if we have an RTX stream registered on this SSRC.
+ SsrcMap::iterator rtx_it = rtx_to_primary_ssrc_.find(ssrc);
+ if (rtx_it != rtx_to_primary_ssrc_.end()) {
+ if (rtx_it->second == first_receive_ssrc_) {
+ recv_channel = vie_channel_;
+ } else {
+ it = recv_channels_.find(rtx_it->second);
+ assert(it != recv_channels_.end());
+ recv_channel = it->second->channel_id();
+ }
+ }
+ } else {
+ recv_channel = it->second->channel_id();
+ }
+ return recv_channel;
}
// If the new frame size is different from the send codec size we set on vie,
// we need to reset the send codec on vie.
// The new send codec size should not exceed send_codec_ which is controlled
// only by the 'jec' logic.
+// TODO(pthatcher): Get rid of this function, so we only ever set up
+// codecs in a single place.
bool WebRtcVideoMediaChannel::MaybeResetVieSendCodec(
WebRtcVideoChannelSendInfo* send_channel,
int new_width,
@@ -3538,7 +3949,7 @@ bool WebRtcVideoMediaChannel::MaybeResetVieSendCodec(
}
ASSERT(send_codec_.get() != NULL);
- webrtc::VideoCodec target_codec = *send_codec_.get();
+ webrtc::VideoCodec target_codec = *send_codec_;
const VideoFormat& video_format = send_channel->video_format();
UpdateVideoCodec(video_format, &target_codec);
@@ -3569,14 +3980,21 @@ bool WebRtcVideoMediaChannel::MaybeResetVieSendCodec(
// Turn off VP8 frame dropping when screensharing as the current model does
// not work well at low fps.
bool vp8_frame_dropping = !is_screencast;
- // Disable denoising for screencasting.
+ // TODO(pbos): Remove |video_noise_reduction| and enable it for all
+ // non-screencast.
bool enable_denoising =
- options_.video_noise_reduction.GetWithDefaultIfUnset(false);
- bool denoising = !is_screencast && enable_denoising;
+ options_.video_noise_reduction.GetWithDefaultIfUnset(true);
+ // Disable denoising for screencasting.
+ if (is_screencast) {
+ enable_denoising = false;
+ }
+ int screencast_min_bitrate =
+ options_.screencast_min_bitrate.GetWithDefaultIfUnset(0);
+ bool leaky_bucket = options_.video_leaky_bucket.GetWithDefaultIfUnset(true);
bool reset_send_codec =
target_width != cur_width || target_height != cur_height ||
automatic_resize != vie_codec.codecSpecific.VP8.automaticResizeOn ||
- denoising != vie_codec.codecSpecific.VP8.denoisingOn ||
+ enable_denoising != vie_codec.codecSpecific.VP8.denoisingOn ||
vp8_frame_dropping != vie_codec.codecSpecific.VP8.frameDroppingOn;
if (reset_send_codec) {
@@ -3585,18 +4003,34 @@ bool WebRtcVideoMediaChannel::MaybeResetVieSendCodec(
vie_codec.height = target_height;
vie_codec.maxFramerate = target_codec.maxFramerate;
vie_codec.startBitrate = target_codec.startBitrate;
+ vie_codec.minBitrate = target_codec.minBitrate;
+ vie_codec.maxBitrate = target_codec.maxBitrate;
+ vie_codec.targetBitrate = 0;
vie_codec.codecSpecific.VP8.automaticResizeOn = automatic_resize;
- vie_codec.codecSpecific.VP8.denoisingOn = denoising;
+ vie_codec.codecSpecific.VP8.denoisingOn = enable_denoising;
vie_codec.codecSpecific.VP8.frameDroppingOn = vp8_frame_dropping;
- // TODO(mflodman): Remove 'is_screencast' check when screen cast settings
- // are treated correctly in WebRTC.
- if (!is_screencast)
- MaybeChangeStartBitrate(channel_id, &vie_codec);
+ MaybeChangeBitrates(channel_id, &vie_codec);
if (engine()->vie()->codec()->SetSendCodec(channel_id, vie_codec) != 0) {
LOG_RTCERR1(SetSendCodec, channel_id);
return false;
}
+
+ if (is_screencast) {
+ engine()->vie()->rtp()->SetMinTransmitBitrate(channel_id,
+ screencast_min_bitrate);
+ // If screencast and min bitrate set, force enable pacer.
+ if (screencast_min_bitrate > 0) {
+ engine()->vie()->rtp()->SetTransmissionSmoothingStatus(channel_id,
+ true);
+ }
+ } else {
+ // In case of switching from screencast to regular capture, set
+ // min bitrate padding and pacer back to defaults.
+ engine()->vie()->rtp()->SetMinTransmitBitrate(channel_id, 0);
+ engine()->vie()->rtp()->SetTransmissionSmoothingStatus(channel_id,
+ leaky_bucket);
+ }
if (reset) {
*reset = true;
}
@@ -3606,12 +4040,28 @@ bool WebRtcVideoMediaChannel::MaybeResetVieSendCodec(
return true;
}
-void WebRtcVideoMediaChannel::MaybeChangeStartBitrate(
- int channel_id, webrtc::VideoCodec* video_codec) {
- if (video_codec->startBitrate < video_codec->minBitrate) {
- video_codec->startBitrate = video_codec->minBitrate;
- } else if (video_codec->startBitrate > video_codec->maxBitrate) {
- video_codec->startBitrate = video_codec->maxBitrate;
+void WebRtcVideoMediaChannel::MaybeChangeBitrates(
+ int channel_id, webrtc::VideoCodec* codec) {
+ codec->minBitrate = GetBitrate(codec->minBitrate, kMinVideoBitrate);
+ codec->startBitrate = GetBitrate(codec->startBitrate, kStartVideoBitrate);
+ codec->maxBitrate = GetBitrate(codec->maxBitrate, kMaxVideoBitrate);
+
+ if (codec->minBitrate > codec->maxBitrate) {
+ LOG(LS_INFO) << "Decreasing codec min bitrate to the max ("
+ << codec->maxBitrate << ") because the min ("
+ << codec->minBitrate << ") exceeds the max.";
+ codec->minBitrate = codec->maxBitrate;
+ }
+ if (codec->startBitrate < codec->minBitrate) {
+ LOG(LS_INFO) << "Increasing codec start bitrate to the min ("
+ << codec->minBitrate << ") because the start ("
+ << codec->startBitrate << ") is less than the min.";
+ codec->startBitrate = codec->minBitrate;
+ } else if (codec->startBitrate > codec->maxBitrate) {
+ LOG(LS_INFO) << "Decreasing codec start bitrate to the max ("
+ << codec->maxBitrate << ") because the start ("
+ << codec->startBitrate << ") exceeds the max.";
+ codec->startBitrate = codec->maxBitrate;
}
// Use a previous target bitrate, if there is one.
@@ -3620,11 +4070,11 @@ void WebRtcVideoMediaChannel::MaybeChangeStartBitrate(
channel_id, &current_target_bitrate) == 0) {
// Convert to kbps.
current_target_bitrate /= 1000;
- if (current_target_bitrate > video_codec->maxBitrate) {
- current_target_bitrate = video_codec->maxBitrate;
+ if (current_target_bitrate > codec->maxBitrate) {
+ current_target_bitrate = codec->maxBitrate;
}
- if (current_target_bitrate > video_codec->startBitrate) {
- video_codec->startBitrate = current_target_bitrate;
+ if (current_target_bitrate > codec->startBitrate) {
+ codec->startBitrate = current_target_bitrate;
}
}
}
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.h b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.h
index 289903a0722..775f4e46de1 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine.h
@@ -45,6 +45,7 @@
#error "Bogus include."
#endif
+
namespace webrtc {
class VideoCaptureModule;
class VideoDecoder;
@@ -60,12 +61,13 @@ class CpuMonitor;
namespace cricket {
+class CoordinatedVideoAdapter;
+class ViETraceWrapper;
+class ViEWrapper;
class VideoCapturer;
class VideoFrame;
class VideoProcessor;
class VideoRenderer;
-class ViETraceWrapper;
-class ViEWrapper;
class VoiceMediaChannel;
class WebRtcDecoderObserver;
class WebRtcEncoderObserver;
@@ -199,6 +201,7 @@ class WebRtcVideoEngine : public sigslot::has_slots<>,
void SetTraceFilter(int filter);
void SetTraceOptions(const std::string& options);
bool InitVideoEngine();
+ bool VerifyApt(const VideoCodec& in, int expected_apt) const;
// webrtc::TraceCallback implementation.
virtual void Print(webrtc::TraceLevel level, const char* trace, int length);
@@ -227,10 +230,6 @@ class WebRtcVideoEngine : public sigslot::has_slots<>,
int local_renderer_h_;
VideoRenderer* local_renderer_;
- // Critical section to protect the media processor register/unregister
- // while processing a frame
- talk_base::CriticalSection signal_media_critical_;
-
talk_base::scoped_ptr<talk_base::CpuMonitor> cpu_monitor_;
};
@@ -248,6 +247,9 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
int video_channel() const { return vie_channel_; }
bool sending() const { return sending_; }
+ // Public for testing purpose.
+ uint32 GetDefaultChannelSsrc();
+
// VideoMediaChannel implementation
virtual bool SetRecvCodecs(const std::vector<VideoCodec> &codecs);
virtual bool SetSendCodecs(const std::vector<VideoCodec> &codecs);
@@ -261,7 +263,7 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
virtual bool AddRecvStream(const StreamParams& sp);
virtual bool RemoveRecvStream(uint32 ssrc);
virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer);
- virtual bool GetStats(VideoMediaInfo* info);
+ virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info);
virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer);
virtual bool SendIntraFrame();
virtual bool RequestIntraFrame();
@@ -276,7 +278,9 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
const std::vector<RtpHeaderExtension>& extensions);
virtual bool SetSendRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions);
- virtual bool SetSendBandwidth(bool autobw, int bps);
+ virtual int GetRtpSendTimeExtnId() const;
+ virtual bool SetStartSendBandwidth(int bps);
+ virtual bool SetMaxSendBandwidth(int bps);
virtual bool SetOptions(const VideoOptions &options);
virtual bool GetOptions(VideoOptions *options) const {
*options = options_;
@@ -288,6 +292,7 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
// Public functions for use by tests and other specialized code.
uint32 send_ssrc() const { return 0; }
bool GetRenderer(uint32 ssrc, VideoRenderer** renderer);
+ bool GetVideoAdapter(uint32 ssrc, CoordinatedVideoAdapter** video_adapter);
void SendFrame(VideoCapturer* capturer, const VideoFrame* frame);
bool SendFrame(WebRtcVideoChannelSendInfo* channel_info,
const VideoFrame* frame, bool is_screencast);
@@ -309,6 +314,7 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
private:
typedef std::map<uint32, WebRtcVideoChannelRecvInfo*> RecvChannelMap;
typedef std::map<uint32, WebRtcVideoChannelSendInfo*> SendChannelMap;
+ typedef std::map<uint32, uint32> SsrcMap;
typedef int (webrtc::ViERTP_RTCP::* ExtensionSetterFunction)(int, bool, int);
enum MediaDirection { MD_RECV, MD_SEND, MD_SENDRECV };
@@ -323,32 +329,32 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
// returning false.
bool CreateChannel(uint32 ssrc_key, MediaDirection direction,
int* channel_id);
+ bool CreateUnsignalledRecvChannel(uint32 ssrc_key, int* channel_id);
bool ConfigureChannel(int channel_id, MediaDirection direction,
uint32 ssrc_key);
bool ConfigureReceiving(int channel_id, uint32 remote_ssrc_key);
bool ConfigureSending(int channel_id, uint32 local_ssrc_key);
bool SetNackFec(int channel_id, int red_payload_type, int fec_payload_type,
bool nack_enabled);
- bool SetSendCodec(const webrtc::VideoCodec& codec, int min_bitrate,
- int start_bitrate, int max_bitrate);
+ bool SetSendCodec(const webrtc::VideoCodec& codec);
bool SetSendCodec(WebRtcVideoChannelSendInfo* send_channel,
- const webrtc::VideoCodec& codec, int min_bitrate,
- int start_bitrate, int max_bitrate);
+ const webrtc::VideoCodec& codec);
void LogSendCodecChange(const std::string& reason);
// Prepares the channel with channel id |info->channel_id()| to receive all
// codecs in |receive_codecs_| and start receive packets.
bool SetReceiveCodecs(WebRtcVideoChannelRecvInfo* info);
// Returns the channel number that receives the stream with SSRC |ssrc|.
int GetRecvChannelNum(uint32 ssrc);
+ bool MaybeSetRtxSsrc(const StreamParams& sp, int channel_id);
// Given captured video frame size, checks if we need to reset vie send codec.
// |reset| is set to whether resetting has happened on vie or not.
// Returns false on error.
bool MaybeResetVieSendCodec(WebRtcVideoChannelSendInfo* send_channel,
int new_width, int new_height, bool is_screencast,
bool* reset);
- // Checks the current bitrate estimate and modifies the start bitrate
- // accordingly.
- void MaybeChangeStartBitrate(int channel_id, webrtc::VideoCodec* video_codec);
+ // Checks the current bitrate estimate and modifies the bitrates
+ // accordingly, including converting kAutoBandwidth to the correct defaults.
+ void MaybeChangeBitrates(int channel_id, webrtc::VideoCodec* video_codec);
// Helper function for starting the sending of media on all channels or
// |channel_id|. Note that these two function do not change |sending_|.
bool StartSend();
@@ -376,7 +382,6 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
bool IsDefaultChannel(int channel_id) const {
return channel_id == vie_channel_;
}
- uint32 GetDefaultChannelSsrc();
bool DeleteSendChannel(uint32 ssrc_key);
@@ -412,6 +417,8 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
// to one send channel, i.e. the last send channel.
void MaybeDisconnectCapturer(VideoCapturer* capturer);
+ bool RemoveRecvStreamInternal(uint32 ssrc);
+
// Global state.
WebRtcVideoEngine* engine_;
VoiceMediaChannel* voice_channel_;
@@ -427,10 +434,20 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
// work properly), resides in both recv_channels_ and send_channels_ with the
// ssrc key 0.
RecvChannelMap recv_channels_; // Contains all receive channels.
+ // A map from the SSRCs on which RTX packets are received to the media SSRCs
+ // the RTX packets are associated with. RTX packets will be delivered to the
+ // streams matching the primary SSRC.
+ SsrcMap rtx_to_primary_ssrc_;
std::vector<webrtc::VideoCodec> receive_codecs_;
+ // A map from codec payload types to their associated payload types, if any.
+ // TODO(holmer): This is a temporary solution until webrtc::VideoCodec has
+ // an associated payload type member, when it does we can rely on
+ // receive_codecs_.
+ std::map<int, int> associated_payload_types_;
bool render_started_;
uint32 first_receive_ssrc_;
std::vector<RtpHeaderExtension> receive_extensions_;
+ int num_unsignalled_recv_channels_;
// Global send side state.
SendChannelMap send_channels_;
@@ -438,9 +455,6 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
int send_rtx_type_;
int send_red_type_;
int send_fec_type_;
- int send_min_bitrate_;
- int send_start_bitrate_;
- int send_max_bitrate_;
bool sending_;
std::vector<RtpHeaderExtension> send_extensions_;
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2.cc b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2.cc
new file mode 100644
index 00000000000..716c5a88554
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2.cc
@@ -0,0 +1,1778 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_WEBRTC_VIDEO
+#include "talk/media/webrtc/webrtcvideoengine2.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+
+#include <string>
+
+#include "libyuv/convert_from.h"
+#include "talk/base/buffer.h"
+#include "talk/base/logging.h"
+#include "talk/base/stringutils.h"
+#include "talk/media/base/videocapturer.h"
+#include "talk/media/base/videorenderer.h"
+#include "talk/media/webrtc/webrtcvideocapturer.h"
+#include "talk/media/webrtc/webrtcvideoframe.h"
+#include "talk/media/webrtc/webrtcvoiceengine.h"
+#include "webrtc/call.h"
+// TODO(pbos): Move codecs out of modules (webrtc:3070).
+#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
+
+#define UNIMPLEMENTED \
+ LOG(LS_ERROR) << "Call to unimplemented function " << __FUNCTION__; \
+ ASSERT(false)
+
+namespace cricket {
+
+static const int kCpuMonitorPeriodMs = 2000; // 2 seconds.
+
+// This constant is really an on/off, lower-level configurable NACK history
+// duration hasn't been implemented.
+static const int kNackHistoryMs = 1000;
+
+static const int kDefaultFramerate = 30;
+static const int kMinVideoBitrate = 50;
+static const int kMaxVideoBitrate = 2000;
+
+static const int kVideoMtu = 1200;
+static const int kVideoRtpBufferSize = 65536;
+
+static const char kVp8PayloadName[] = "VP8";
+
+static const int kDefaultRtcpReceiverReportSsrc = 1;
+
+struct VideoCodecPref {
+ int payload_type;
+ const char* name;
+ int rtx_payload_type;
+} kDefaultVideoCodecPref = {100, kVp8PayloadName, 96};
+
+VideoCodecPref kRedPref = {116, kRedCodecName, -1};
+VideoCodecPref kUlpfecPref = {117, kUlpfecCodecName, -1};
+
+// The formats are sorted by the descending order of width. We use the order to
+// find the next format for CPU and bandwidth adaptation.
+const VideoFormatPod kDefaultVideoFormat = {
+ 640, 400, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY};
+const VideoFormatPod kVideoFormats[] = {
+ {1280, 800, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {1280, 720, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {960, 600, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {960, 540, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ kDefaultVideoFormat,
+ {640, 360, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {640, 480, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {480, 300, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {480, 270, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {480, 360, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {320, 200, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {320, 180, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {320, 240, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {240, 150, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {240, 135, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {240, 180, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {160, 100, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {160, 90, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
+ {160, 120, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY}, };
+
+static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs,
+ const VideoCodec& requested_codec,
+ VideoCodec* matching_codec) {
+ for (size_t i = 0; i < codecs.size(); ++i) {
+ if (requested_codec.Matches(codecs[i])) {
+ *matching_codec = codecs[i];
+ return true;
+ }
+ }
+ return false;
+}
+static bool FindBestVideoFormat(int max_width,
+ int max_height,
+ int aspect_width,
+ int aspect_height,
+ VideoFormat* video_format) {
+ assert(max_width > 0);
+ assert(max_height > 0);
+ assert(aspect_width > 0);
+ assert(aspect_height > 0);
+ VideoFormat best_format;
+ for (int i = 0; i < ARRAY_SIZE(kVideoFormats); ++i) {
+ const VideoFormat format(kVideoFormats[i]);
+
+ // Skip any format that is larger than the local or remote maximums, or
+ // smaller than the current best match
+ if (format.width > max_width || format.height > max_height ||
+ (format.width < best_format.width &&
+ format.height < best_format.height)) {
+ continue;
+ }
+
+ // If we don't have any matches yet, this is the best so far.
+ if (best_format.width == 0) {
+ best_format = format;
+ continue;
+ }
+
+ // Prefer closer aspect ratios i.e:
+ // |format| aspect - requested aspect <
+ // |best_format| aspect - requested aspect
+ if (abs(format.width * aspect_height * best_format.height -
+ aspect_width * format.height * best_format.height) <
+ abs(best_format.width * aspect_height * format.height -
+ aspect_width * format.height * best_format.height)) {
+ best_format = format;
+ }
+ }
+ if (best_format.width != 0) {
+ *video_format = best_format;
+ return true;
+ }
+ return false;
+}
+
+static void AddDefaultFeedbackParams(VideoCodec* codec) {
+ const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir);
+ codec->AddFeedbackParam(kFir);
+ const FeedbackParam kNack(kRtcpFbParamNack, kParamValueEmpty);
+ codec->AddFeedbackParam(kNack);
+ const FeedbackParam kPli(kRtcpFbParamNack, kRtcpFbNackParamPli);
+ codec->AddFeedbackParam(kPli);
+ const FeedbackParam kRemb(kRtcpFbParamRemb, kParamValueEmpty);
+ codec->AddFeedbackParam(kRemb);
+}
+
+static bool IsNackEnabled(const VideoCodec& codec) {
+ return codec.HasFeedbackParam(
+ FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
+}
+
+static VideoCodec DefaultVideoCodec() {
+ VideoCodec default_codec(kDefaultVideoCodecPref.payload_type,
+ kDefaultVideoCodecPref.name,
+ kDefaultVideoFormat.width,
+ kDefaultVideoFormat.height,
+ kDefaultFramerate,
+ 0);
+ AddDefaultFeedbackParams(&default_codec);
+ return default_codec;
+}
+
+static VideoCodec DefaultRedCodec() {
+ return VideoCodec(kRedPref.payload_type, kRedPref.name, 0, 0, 0, 0);
+}
+
+static VideoCodec DefaultUlpfecCodec() {
+ return VideoCodec(kUlpfecPref.payload_type, kUlpfecPref.name, 0, 0, 0, 0);
+}
+
+static std::vector<VideoCodec> DefaultVideoCodecs() {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(DefaultVideoCodec());
+ codecs.push_back(DefaultRedCodec());
+ codecs.push_back(DefaultUlpfecCodec());
+ if (kDefaultVideoCodecPref.rtx_payload_type != -1) {
+ codecs.push_back(
+ VideoCodec::CreateRtxCodec(kDefaultVideoCodecPref.rtx_payload_type,
+ kDefaultVideoCodecPref.payload_type));
+ }
+ return codecs;
+}
+
+WebRtcVideoEncoderFactory2::~WebRtcVideoEncoderFactory2() {
+}
+
+std::vector<webrtc::VideoStream> WebRtcVideoEncoderFactory2::CreateVideoStreams(
+ const VideoCodec& codec,
+ const VideoOptions& options,
+ size_t num_streams) {
+ assert(SupportsCodec(codec));
+ if (num_streams != 1) {
+ LOG(LS_ERROR) << "Unsupported number of streams: " << num_streams;
+ return std::vector<webrtc::VideoStream>();
+ }
+
+ webrtc::VideoStream stream;
+ stream.width = codec.width;
+ stream.height = codec.height;
+ stream.max_framerate =
+ codec.framerate != 0 ? codec.framerate : kDefaultFramerate;
+
+ int min_bitrate = kMinVideoBitrate;
+ codec.GetParam(kCodecParamMinBitrate, &min_bitrate);
+ int max_bitrate = kMaxVideoBitrate;
+ codec.GetParam(kCodecParamMaxBitrate, &max_bitrate);
+ stream.min_bitrate_bps = min_bitrate * 1000;
+ stream.target_bitrate_bps = stream.max_bitrate_bps = max_bitrate * 1000;
+
+ int max_qp = 56;
+ codec.GetParam(kCodecParamMaxQuantization, &max_qp);
+ stream.max_qp = max_qp;
+ std::vector<webrtc::VideoStream> streams;
+ streams.push_back(stream);
+ return streams;
+}
+
+webrtc::VideoEncoder* WebRtcVideoEncoderFactory2::CreateVideoEncoder(
+ const VideoCodec& codec,
+ const VideoOptions& options) {
+ assert(SupportsCodec(codec));
+ return webrtc::VP8Encoder::Create();
+}
+
+bool WebRtcVideoEncoderFactory2::SupportsCodec(const VideoCodec& codec) {
+ return _stricmp(codec.name.c_str(), kVp8PayloadName) == 0;
+}
+
+WebRtcVideoEngine2::WebRtcVideoEngine2() {
+ // Construct without a factory or voice engine.
+ Construct(NULL, NULL, new talk_base::CpuMonitor(NULL));
+}
+
+WebRtcVideoEngine2::WebRtcVideoEngine2(
+ WebRtcVideoChannelFactory* channel_factory) {
+ // Construct without a voice engine.
+ Construct(channel_factory, NULL, new talk_base::CpuMonitor(NULL));
+}
+
+void WebRtcVideoEngine2::Construct(WebRtcVideoChannelFactory* channel_factory,
+ WebRtcVoiceEngine* voice_engine,
+ talk_base::CpuMonitor* cpu_monitor) {
+ LOG(LS_INFO) << "WebRtcVideoEngine2::WebRtcVideoEngine2";
+ worker_thread_ = NULL;
+ voice_engine_ = voice_engine;
+ initialized_ = false;
+ capture_started_ = false;
+ cpu_monitor_.reset(cpu_monitor);
+ channel_factory_ = channel_factory;
+
+ video_codecs_ = DefaultVideoCodecs();
+ default_codec_format_ = VideoFormat(kDefaultVideoFormat);
+
+ rtp_header_extensions_.push_back(
+ RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension,
+ kRtpTimestampOffsetHeaderExtensionDefaultId));
+ rtp_header_extensions_.push_back(
+ RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension,
+ kRtpAbsoluteSenderTimeHeaderExtensionDefaultId));
+}
+
+WebRtcVideoEngine2::~WebRtcVideoEngine2() {
+ LOG(LS_INFO) << "WebRtcVideoEngine2::~WebRtcVideoEngine2";
+
+ if (initialized_) {
+ Terminate();
+ }
+}
+
+bool WebRtcVideoEngine2::Init(talk_base::Thread* worker_thread) {
+ LOG(LS_INFO) << "WebRtcVideoEngine2::Init";
+ worker_thread_ = worker_thread;
+ ASSERT(worker_thread_ != NULL);
+
+ cpu_monitor_->set_thread(worker_thread_);
+ if (!cpu_monitor_->Start(kCpuMonitorPeriodMs)) {
+ LOG(LS_ERROR) << "Failed to start CPU monitor.";
+ cpu_monitor_.reset();
+ }
+
+ initialized_ = true;
+ return true;
+}
+
+void WebRtcVideoEngine2::Terminate() {
+ LOG(LS_INFO) << "WebRtcVideoEngine2::Terminate";
+
+ cpu_monitor_->Stop();
+
+ initialized_ = false;
+}
+
+int WebRtcVideoEngine2::GetCapabilities() { return VIDEO_RECV | VIDEO_SEND; }
+
+bool WebRtcVideoEngine2::SetOptions(const VideoOptions& options) {
+ // TODO(pbos): Do we need this? This is a no-op in the existing
+ // WebRtcVideoEngine implementation.
+ LOG(LS_VERBOSE) << "SetOptions: " << options.ToString();
+ // options_ = options;
+ return true;
+}
+
+bool WebRtcVideoEngine2::SetDefaultEncoderConfig(
+ const VideoEncoderConfig& config) {
+ // TODO(pbos): Implement. Should be covered by corresponding unit tests.
+ LOG(LS_VERBOSE) << "SetDefaultEncoderConfig()";
+ return true;
+}
+
+VideoEncoderConfig WebRtcVideoEngine2::GetDefaultEncoderConfig() const {
+ return VideoEncoderConfig(DefaultVideoCodec());
+}
+
+WebRtcVideoChannel2* WebRtcVideoEngine2::CreateChannel(
+ VoiceMediaChannel* voice_channel) {
+ LOG(LS_INFO) << "CreateChannel: "
+ << (voice_channel != NULL ? "With" : "Without")
+ << " voice channel.";
+ WebRtcVideoChannel2* channel =
+ channel_factory_ != NULL
+ ? channel_factory_->Create(this, voice_channel)
+ : new WebRtcVideoChannel2(
+ this, voice_channel, GetVideoEncoderFactory());
+ if (!channel->Init()) {
+ delete channel;
+ return NULL;
+ }
+ channel->SetRecvCodecs(video_codecs_);
+ return channel;
+}
+
+const std::vector<VideoCodec>& WebRtcVideoEngine2::codecs() const {
+ return video_codecs_;
+}
+
+const std::vector<RtpHeaderExtension>&
+WebRtcVideoEngine2::rtp_header_extensions() const {
+ return rtp_header_extensions_;
+}
+
+void WebRtcVideoEngine2::SetLogging(int min_sev, const char* filter) {
+ // TODO(pbos): Set up logging.
+ LOG(LS_VERBOSE) << "SetLogging: " << min_sev << '"' << filter << '"';
+ // if min_sev == -1, we keep the current log level.
+ if (min_sev < 0) {
+ assert(min_sev == -1);
+ return;
+ }
+}
+
+bool WebRtcVideoEngine2::EnableTimedRender() {
+ // TODO(pbos): Figure out whether this can be removed.
+ return true;
+}
+
+bool WebRtcVideoEngine2::SetLocalRenderer(VideoRenderer* renderer) {
+ // TODO(pbos): Implement or remove. Unclear which stream should be rendered
+ // locally even.
+ return true;
+}
+
+// Checks to see whether we comprehend and could receive a particular codec
+bool WebRtcVideoEngine2::FindCodec(const VideoCodec& in) {
+ // TODO(pbos): Probe encoder factory to figure out that the codec is supported
+ // if supported by the encoder factory. Add a corresponding test that fails
+ // with this code (that doesn't ask the factory).
+ for (int i = 0; i < ARRAY_SIZE(kVideoFormats); ++i) {
+ const VideoFormat fmt(kVideoFormats[i]);
+ if ((in.width != 0 || in.height != 0) &&
+ (fmt.width != in.width || fmt.height != in.height)) {
+ continue;
+ }
+ for (size_t j = 0; j < video_codecs_.size(); ++j) {
+ VideoCodec codec(video_codecs_[j].id, video_codecs_[j].name, 0, 0, 0, 0);
+ if (codec.Matches(in)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// Tells whether the |requested| codec can be transmitted or not. If it can be
+// transmitted |out| is set with the best settings supported. Aspect ratio will
+// be set as close to |current|'s as possible. If not set |requested|'s
+// dimensions will be used for aspect ratio matching.
+bool WebRtcVideoEngine2::CanSendCodec(const VideoCodec& requested,
+ const VideoCodec& current,
+ VideoCodec* out) {
+ assert(out != NULL);
+ // TODO(pbos): Implement.
+
+ if (requested.width != requested.height &&
+ (requested.height == 0 || requested.width == 0)) {
+ // 0xn and nx0 are invalid resolutions.
+ return false;
+ }
+
+ VideoCodec matching_codec;
+ if (!FindFirstMatchingCodec(video_codecs_, requested, &matching_codec)) {
+ // Codec not supported.
+ return false;
+ }
+
+ // Pick the best quality that is within their and our bounds and has the
+ // correct aspect ratio.
+ VideoFormat format;
+ if (requested.width == 0 && requested.height == 0) {
+ // Special case with resolution 0. The channel should not send frames.
+ } else {
+ int max_width = talk_base::_min(requested.width, matching_codec.width);
+ int max_height = talk_base::_min(requested.height, matching_codec.height);
+ int aspect_width = max_width;
+ int aspect_height = max_height;
+ if (current.width > 0 && current.height > 0) {
+ aspect_width = current.width;
+ aspect_height = current.height;
+ }
+ if (!FindBestVideoFormat(
+ max_width, max_height, aspect_width, aspect_height, &format)) {
+ return false;
+ }
+ }
+
+ out->id = requested.id;
+ out->name = requested.name;
+ out->preference = requested.preference;
+ out->params = requested.params;
+ out->framerate =
+ talk_base::_min(requested.framerate, matching_codec.framerate);
+ out->width = format.width;
+ out->height = format.height;
+ out->params = requested.params;
+ out->feedback_params = requested.feedback_params;
+ return true;
+}
+
+bool WebRtcVideoEngine2::SetVoiceEngine(WebRtcVoiceEngine* voice_engine) {
+ if (initialized_) {
+ LOG(LS_WARNING) << "SetVoiceEngine can not be called after Init";
+ return false;
+ }
+ voice_engine_ = voice_engine;
+ return true;
+}
+
+// Ignore spammy trace messages, mostly from the stats API when we haven't
+// gotten RTCP info yet from the remote side.
+bool WebRtcVideoEngine2::ShouldIgnoreTrace(const std::string& trace) {
+ static const char* const kTracesToIgnore[] = {NULL};
+ for (const char* const* p = kTracesToIgnore; *p; ++p) {
+ if (trace.find(*p) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+WebRtcVideoEncoderFactory2* WebRtcVideoEngine2::GetVideoEncoderFactory() {
+ return &default_video_encoder_factory_;
+}
+
+// Thin map between VideoFrame and an existing webrtc::I420VideoFrame
+// to avoid having to copy the rendered VideoFrame prematurely.
+// This implementation is only safe to use in a const context and should never
+// be written to.
+class WebRtcVideoRenderFrame : public VideoFrame {
+ public:
+ explicit WebRtcVideoRenderFrame(const webrtc::I420VideoFrame* frame)
+ : frame_(frame) {}
+
+ virtual bool InitToBlack(int w,
+ int h,
+ size_t pixel_width,
+ size_t pixel_height,
+ int64 elapsed_time,
+ int64 time_stamp) OVERRIDE {
+ UNIMPLEMENTED;
+ return false;
+ }
+
+ virtual bool Reset(uint32 fourcc,
+ int w,
+ int h,
+ int dw,
+ int dh,
+ uint8* sample,
+ size_t sample_size,
+ size_t pixel_width,
+ size_t pixel_height,
+ int64 elapsed_time,
+ int64 time_stamp,
+ int rotation) OVERRIDE {
+ UNIMPLEMENTED;
+ return false;
+ }
+
+ virtual size_t GetWidth() const OVERRIDE {
+ return static_cast<size_t>(frame_->width());
+ }
+ virtual size_t GetHeight() const OVERRIDE {
+ return static_cast<size_t>(frame_->height());
+ }
+
+ virtual const uint8* GetYPlane() const OVERRIDE {
+ return frame_->buffer(webrtc::kYPlane);
+ }
+ virtual const uint8* GetUPlane() const OVERRIDE {
+ return frame_->buffer(webrtc::kUPlane);
+ }
+ virtual const uint8* GetVPlane() const OVERRIDE {
+ return frame_->buffer(webrtc::kVPlane);
+ }
+
+ virtual uint8* GetYPlane() OVERRIDE {
+ UNIMPLEMENTED;
+ return NULL;
+ }
+ virtual uint8* GetUPlane() OVERRIDE {
+ UNIMPLEMENTED;
+ return NULL;
+ }
+ virtual uint8* GetVPlane() OVERRIDE {
+ UNIMPLEMENTED;
+ return NULL;
+ }
+
+ virtual int32 GetYPitch() const OVERRIDE {
+ return frame_->stride(webrtc::kYPlane);
+ }
+ virtual int32 GetUPitch() const OVERRIDE {
+ return frame_->stride(webrtc::kUPlane);
+ }
+ virtual int32 GetVPitch() const OVERRIDE {
+ return frame_->stride(webrtc::kVPlane);
+ }
+
+ virtual void* GetNativeHandle() const OVERRIDE { return NULL; }
+
+ virtual size_t GetPixelWidth() const OVERRIDE { return 1; }
+ virtual size_t GetPixelHeight() const OVERRIDE { return 1; }
+
+ virtual int64 GetElapsedTime() const OVERRIDE {
+ // Convert millisecond render time to ns timestamp.
+ return frame_->render_time_ms() * talk_base::kNumNanosecsPerMillisec;
+ }
+ virtual int64 GetTimeStamp() const OVERRIDE {
+ // Convert 90K rtp timestamp to ns timestamp.
+ return (frame_->timestamp() / 90) * talk_base::kNumNanosecsPerMillisec;
+ }
+ virtual void SetElapsedTime(int64 elapsed_time) OVERRIDE { UNIMPLEMENTED; }
+ virtual void SetTimeStamp(int64 time_stamp) OVERRIDE { UNIMPLEMENTED; }
+
+ virtual int GetRotation() const OVERRIDE {
+ UNIMPLEMENTED;
+ return ROTATION_0;
+ }
+
+ virtual VideoFrame* Copy() const OVERRIDE {
+ UNIMPLEMENTED;
+ return NULL;
+ }
+
+ virtual bool MakeExclusive() OVERRIDE {
+ UNIMPLEMENTED;
+ return false;
+ }
+
+ virtual size_t CopyToBuffer(uint8* buffer, size_t size) const {
+ UNIMPLEMENTED;
+ return 0;
+ }
+
+ // TODO(fbarchard): Refactor into base class and share with LMI
+ virtual size_t ConvertToRgbBuffer(uint32 to_fourcc,
+ uint8* buffer,
+ size_t size,
+ int stride_rgb) const OVERRIDE {
+ size_t width = GetWidth();
+ size_t height = GetHeight();
+ size_t needed = (stride_rgb >= 0 ? stride_rgb : -stride_rgb) * height;
+ if (size < needed) {
+ LOG(LS_WARNING) << "RGB buffer is not large enough";
+ return needed;
+ }
+
+ if (libyuv::ConvertFromI420(GetYPlane(),
+ GetYPitch(),
+ GetUPlane(),
+ GetUPitch(),
+ GetVPlane(),
+ GetVPitch(),
+ buffer,
+ stride_rgb,
+ static_cast<int>(width),
+ static_cast<int>(height),
+ to_fourcc)) {
+ LOG(LS_ERROR) << "RGB type not supported: " << to_fourcc;
+ return 0; // 0 indicates error
+ }
+ return needed;
+ }
+
+ protected:
+ virtual VideoFrame* CreateEmptyFrame(int w,
+ int h,
+ size_t pixel_width,
+ size_t pixel_height,
+ int64 elapsed_time,
+ int64 time_stamp) const OVERRIDE {
+ // TODO(pbos): Remove WebRtcVideoFrame dependency, and have a non-const
+ // version of I420VideoFrame wrapped.
+ WebRtcVideoFrame* frame = new WebRtcVideoFrame();
+ frame->InitToBlack(
+ w, h, pixel_width, pixel_height, elapsed_time, time_stamp);
+ return frame;
+ }
+
+ private:
+ const webrtc::I420VideoFrame* const frame_;
+};
+
+WebRtcVideoRenderer::WebRtcVideoRenderer()
+ : last_width_(-1), last_height_(-1), renderer_(NULL) {}
+
+void WebRtcVideoRenderer::RenderFrame(const webrtc::I420VideoFrame& frame,
+ int time_to_render_ms) {
+ talk_base::CritScope crit(&lock_);
+ if (renderer_ == NULL) {
+ LOG(LS_WARNING) << "VideoReceiveStream not connected to a VideoRenderer.";
+ return;
+ }
+
+ if (frame.width() != last_width_ || frame.height() != last_height_) {
+ SetSize(frame.width(), frame.height());
+ }
+
+ LOG(LS_VERBOSE) << "RenderFrame: (" << frame.width() << "x" << frame.height()
+ << ")";
+
+ const WebRtcVideoRenderFrame render_frame(&frame);
+ renderer_->RenderFrame(&render_frame);
+}
+
+void WebRtcVideoRenderer::SetRenderer(cricket::VideoRenderer* renderer) {
+ talk_base::CritScope crit(&lock_);
+ renderer_ = renderer;
+ if (renderer_ != NULL && last_width_ != -1) {
+ SetSize(last_width_, last_height_);
+ }
+}
+
+VideoRenderer* WebRtcVideoRenderer::GetRenderer() {
+ talk_base::CritScope crit(&lock_);
+ return renderer_;
+}
+
+void WebRtcVideoRenderer::SetSize(int width, int height) {
+ talk_base::CritScope crit(&lock_);
+ if (!renderer_->SetSize(width, height, 0)) {
+ LOG(LS_ERROR) << "Could not set renderer size.";
+ }
+ last_width_ = width;
+ last_height_ = height;
+}
+
+// WebRtcVideoChannel2
+
+WebRtcVideoChannel2::WebRtcVideoChannel2(
+ WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel,
+ WebRtcVideoEncoderFactory2* encoder_factory)
+ : encoder_factory_(encoder_factory) {
+ // TODO(pbos): Connect the video and audio with |voice_channel|.
+ webrtc::Call::Config config(this);
+ Construct(webrtc::Call::Create(config), engine);
+}
+
+WebRtcVideoChannel2::WebRtcVideoChannel2(
+ webrtc::Call* call,
+ WebRtcVideoEngine2* engine,
+ WebRtcVideoEncoderFactory2* encoder_factory)
+ : encoder_factory_(encoder_factory) {
+ Construct(call, engine);
+}
+
+void WebRtcVideoChannel2::Construct(webrtc::Call* call,
+ WebRtcVideoEngine2* engine) {
+ rtcp_receiver_report_ssrc_ = kDefaultRtcpReceiverReportSsrc;
+ sending_ = false;
+ call_.reset(call);
+ default_renderer_ = NULL;
+ default_send_ssrc_ = 0;
+ default_recv_ssrc_ = 0;
+}
+
+WebRtcVideoChannel2::~WebRtcVideoChannel2() {
+ for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
+ send_streams_.begin();
+ it != send_streams_.end();
+ ++it) {
+ delete it->second;
+ }
+
+ for (std::map<uint32, webrtc::VideoReceiveStream*>::iterator it =
+ receive_streams_.begin();
+ it != receive_streams_.end();
+ ++it) {
+ assert(it->second != NULL);
+ call_->DestroyVideoReceiveStream(it->second);
+ }
+
+ for (std::map<uint32, WebRtcVideoRenderer*>::iterator it = renderers_.begin();
+ it != renderers_.end();
+ ++it) {
+ assert(it->second != NULL);
+ delete it->second;
+ }
+}
+
+bool WebRtcVideoChannel2::Init() { return true; }
+
+namespace {
+
+static std::string CodecVectorToString(const std::vector<VideoCodec>& codecs) {
+ std::stringstream out;
+ out << '{';
+ for (size_t i = 0; i < codecs.size(); ++i) {
+ out << codecs[i].ToString();
+ if (i != codecs.size() - 1) {
+ out << ", ";
+ }
+ }
+ out << '}';
+ return out.str();
+}
+
+static bool ValidateCodecFormats(const std::vector<VideoCodec>& codecs) {
+ bool has_video = false;
+ for (size_t i = 0; i < codecs.size(); ++i) {
+ if (!codecs[i].ValidateCodecFormat()) {
+ return false;
+ }
+ if (codecs[i].GetCodecType() == VideoCodec::CODEC_VIDEO) {
+ has_video = true;
+ }
+ }
+ if (!has_video) {
+ LOG(LS_ERROR) << "Setting codecs without a video codec is invalid: "
+ << CodecVectorToString(codecs);
+ return false;
+ }
+ return true;
+}
+
+static std::string RtpExtensionsToString(
+ const std::vector<RtpHeaderExtension>& extensions) {
+ std::stringstream out;
+ out << '{';
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ out << "{" << extensions[i].uri << ": " << extensions[i].id << "}";
+ if (i != extensions.size() - 1) {
+ out << ", ";
+ }
+ }
+ out << '}';
+ return out.str();
+}
+
+} // namespace
+
+bool WebRtcVideoChannel2::SetRecvCodecs(const std::vector<VideoCodec>& codecs) {
+ // TODO(pbos): Must these receive codecs propagate to existing receive
+ // streams?
+ LOG(LS_INFO) << "SetRecvCodecs: " << CodecVectorToString(codecs);
+ if (!ValidateCodecFormats(codecs)) {
+ return false;
+ }
+
+ const std::vector<VideoCodecSettings> mapped_codecs = MapCodecs(codecs);
+ if (mapped_codecs.empty()) {
+ LOG(LS_ERROR) << "SetRecvCodecs called without video codec payloads.";
+ return false;
+ }
+
+ // TODO(pbos): Add a decoder factory which controls supported codecs.
+ // Blocked on webrtc:2854.
+ for (size_t i = 0; i < mapped_codecs.size(); ++i) {
+ if (_stricmp(mapped_codecs[i].codec.name.c_str(), kVp8PayloadName) != 0) {
+ LOG(LS_ERROR) << "SetRecvCodecs called with unsupported codec: '"
+ << mapped_codecs[i].codec.name << "'";
+ return false;
+ }
+ }
+
+ recv_codecs_ = mapped_codecs;
+ return true;
+}
+
+bool WebRtcVideoChannel2::SetSendCodecs(const std::vector<VideoCodec>& codecs) {
+ LOG(LS_INFO) << "SetSendCodecs: " << CodecVectorToString(codecs);
+ if (!ValidateCodecFormats(codecs)) {
+ return false;
+ }
+
+ const std::vector<VideoCodecSettings> supported_codecs =
+ FilterSupportedCodecs(MapCodecs(codecs));
+
+ if (supported_codecs.empty()) {
+ LOG(LS_ERROR) << "No video codecs supported by encoder factory.";
+ return false;
+ }
+
+ send_codec_.Set(supported_codecs.front());
+ LOG(LS_INFO) << "Using codec: " << supported_codecs.front().codec.ToString();
+
+ SetCodecForAllSendStreams(supported_codecs.front());
+
+ return true;
+}
+
+bool WebRtcVideoChannel2::GetSendCodec(VideoCodec* codec) {
+ VideoCodecSettings codec_settings;
+ if (!send_codec_.Get(&codec_settings)) {
+ LOG(LS_VERBOSE) << "GetSendCodec: No send codec set.";
+ return false;
+ }
+ *codec = codec_settings.codec;
+ return true;
+}
+
+bool WebRtcVideoChannel2::SetSendStreamFormat(uint32 ssrc,
+ const VideoFormat& format) {
+ LOG(LS_VERBOSE) << "SetSendStreamFormat:" << ssrc << " -> "
+ << format.ToString();
+ if (send_streams_.find(ssrc) == send_streams_.end()) {
+ return false;
+ }
+ return send_streams_[ssrc]->SetVideoFormat(format);
+}
+
+bool WebRtcVideoChannel2::SetRender(bool render) {
+ // TODO(pbos): Implement. Or refactor away as it shouldn't be needed.
+ LOG(LS_VERBOSE) << "SetRender: " << (render ? "true" : "false");
+ return true;
+}
+
+bool WebRtcVideoChannel2::SetSend(bool send) {
+ LOG(LS_VERBOSE) << "SetSend: " << (send ? "true" : "false");
+ if (send && !send_codec_.IsSet()) {
+ LOG(LS_ERROR) << "SetSend(true) called before setting codec.";
+ return false;
+ }
+ if (send) {
+ StartAllSendStreams();
+ } else {
+ StopAllSendStreams();
+ }
+ sending_ = send;
+ return true;
+}
+
+static bool ConfigureSendSsrcs(webrtc::VideoSendStream::Config* config,
+ const StreamParams& sp) {
+ if (!sp.has_ssrc_groups()) {
+ config->rtp.ssrcs = sp.ssrcs;
+ return true;
+ }
+
+ if (sp.get_ssrc_group(kFecSsrcGroupSemantics) != NULL) {
+ LOG(LS_ERROR) << "Standalone FEC SSRCs not supported.";
+ return false;
+ }
+
+ // Map RTX SSRCs.
+ std::vector<uint32_t> ssrcs;
+ std::vector<uint32_t> rtx_ssrcs;
+ const SsrcGroup* sim_group = sp.get_ssrc_group(kSimSsrcGroupSemantics);
+ if (sim_group == NULL) {
+ ssrcs.push_back(sp.first_ssrc());
+ uint32_t rtx_ssrc;
+ if (!sp.GetFidSsrc(sp.first_ssrc(), &rtx_ssrc)) {
+ LOG(LS_ERROR) << "Could not find FID ssrc for primary SSRC '"
+ << sp.first_ssrc() << "':" << sp.ToString();
+ return false;
+ }
+ rtx_ssrcs.push_back(rtx_ssrc);
+ } else {
+ ssrcs = sim_group->ssrcs;
+ for (size_t i = 0; i < sim_group->ssrcs.size(); ++i) {
+ uint32_t rtx_ssrc;
+ if (!sp.GetFidSsrc(sim_group->ssrcs[i], &rtx_ssrc)) {
+ continue;
+ }
+ rtx_ssrcs.push_back(rtx_ssrc);
+ }
+ }
+ if (!rtx_ssrcs.empty() && ssrcs.size() != rtx_ssrcs.size()) {
+ LOG(LS_ERROR)
+ << "RTX SSRCs exist, but don't cover all SSRCs (unsupported): "
+ << sp.ToString();
+ return false;
+ }
+ config->rtp.rtx.ssrcs = rtx_ssrcs;
+ config->rtp.ssrcs = ssrcs;
+ return true;
+}
+
+bool WebRtcVideoChannel2::AddSendStream(const StreamParams& sp) {
+ LOG(LS_INFO) << "AddSendStream: " << sp.ToString();
+ if (sp.ssrcs.empty()) {
+ LOG(LS_ERROR) << "No SSRCs in stream parameters.";
+ return false;
+ }
+
+ uint32 ssrc = sp.first_ssrc();
+ assert(ssrc != 0);
+ // TODO(pbos): Make sure none of sp.ssrcs are used, not just the identifying
+ // ssrc.
+ if (send_streams_.find(ssrc) != send_streams_.end()) {
+ LOG(LS_ERROR) << "Send stream with ssrc '" << ssrc << "' already exists.";
+ return false;
+ }
+
+ webrtc::VideoSendStream::Config config = call_->GetDefaultSendConfig();
+
+ if (!ConfigureSendSsrcs(&config, sp)) {
+ return false;
+ }
+
+ VideoCodecSettings codec_settings;
+ if (!send_codec_.Get(&codec_settings)) {
+ // TODO(pbos): Set up a temporary fake encoder for VideoSendStream instead
+ // of setting default codecs not to break CreateEncoderSettings.
+ SetSendCodecs(DefaultVideoCodecs());
+ assert(send_codec_.IsSet());
+ send_codec_.Get(&codec_settings);
+ // This is only to bring up defaults to make VideoSendStream setup easier
+ // and avoid complexity. We still don't want to allow sending with the
+ // default codec.
+ send_codec_.Clear();
+ }
+
+ // CreateEncoderSettings will allocate a suitable VideoEncoder instance
+ // matching current settings.
+ std::vector<webrtc::VideoStream> video_streams =
+ encoder_factory_->CreateVideoStreams(
+ codec_settings.codec, options_, config.rtp.ssrcs.size());
+ if (video_streams.empty()) {
+ return false;
+ }
+
+ config.encoder_settings.encoder =
+ encoder_factory_->CreateVideoEncoder(codec_settings.codec, options_);
+ config.encoder_settings.payload_name = codec_settings.codec.name;
+ config.encoder_settings.payload_type = codec_settings.codec.id;
+ config.rtp.c_name = sp.cname;
+ config.rtp.fec = codec_settings.fec;
+ if (!config.rtp.rtx.ssrcs.empty()) {
+ config.rtp.rtx.payload_type = codec_settings.rtx_payload_type;
+ }
+
+ config.rtp.extensions = send_rtp_extensions_;
+
+ if (IsNackEnabled(codec_settings.codec)) {
+ config.rtp.nack.rtp_history_ms = kNackHistoryMs;
+ }
+ config.rtp.max_packet_size = kVideoMtu;
+
+ WebRtcVideoSendStream* stream =
+ new WebRtcVideoSendStream(call_.get(),
+ config,
+ options_,
+ codec_settings.codec,
+ video_streams,
+ encoder_factory_);
+ send_streams_[ssrc] = stream;
+
+ if (rtcp_receiver_report_ssrc_ == kDefaultRtcpReceiverReportSsrc) {
+ rtcp_receiver_report_ssrc_ = ssrc;
+ }
+ if (default_send_ssrc_ == 0) {
+ default_send_ssrc_ = ssrc;
+ }
+ if (sending_) {
+ stream->Start();
+ }
+
+ return true;
+}
+
+bool WebRtcVideoChannel2::RemoveSendStream(uint32 ssrc) {
+ LOG(LS_INFO) << "RemoveSendStream: " << ssrc;
+
+ if (ssrc == 0) {
+ if (default_send_ssrc_ == 0) {
+ LOG(LS_ERROR) << "No default send stream active.";
+ return false;
+ }
+
+ LOG(LS_VERBOSE) << "Removing default stream: " << default_send_ssrc_;
+ ssrc = default_send_ssrc_;
+ }
+
+ std::map<uint32, WebRtcVideoSendStream*>::iterator it =
+ send_streams_.find(ssrc);
+ if (it == send_streams_.end()) {
+ return false;
+ }
+
+ delete it->second;
+ send_streams_.erase(it);
+
+ if (ssrc == default_send_ssrc_) {
+ default_send_ssrc_ = 0;
+ }
+
+ return true;
+}
+
+bool WebRtcVideoChannel2::AddRecvStream(const StreamParams& sp) {
+ LOG(LS_INFO) << "AddRecvStream: " << sp.ToString();
+ assert(sp.ssrcs.size() > 0);
+
+ uint32 ssrc = sp.first_ssrc();
+ assert(ssrc != 0); // TODO(pbos): Is this ever valid?
+ if (default_recv_ssrc_ == 0) {
+ default_recv_ssrc_ = ssrc;
+ }
+
+ // TODO(pbos): Check if any of the SSRCs overlap.
+ if (receive_streams_.find(ssrc) != receive_streams_.end()) {
+ LOG(LS_ERROR) << "Receive stream for SSRC " << ssrc << "already exists.";
+ return false;
+ }
+
+ webrtc::VideoReceiveStream::Config config = call_->GetDefaultReceiveConfig();
+ config.rtp.remote_ssrc = ssrc;
+ config.rtp.local_ssrc = rtcp_receiver_report_ssrc_;
+
+ if (IsNackEnabled(recv_codecs_.begin()->codec)) {
+ config.rtp.nack.rtp_history_ms = kNackHistoryMs;
+ }
+ config.rtp.remb = true;
+ config.rtp.extensions = recv_rtp_extensions_;
+ // TODO(pbos): This protection is against setting the same local ssrc as
+ // remote which is not permitted by the lower-level API. RTCP requires a
+ // corresponding sender SSRC. Figure out what to do when we don't have
+ // (receive-only) or know a good local SSRC.
+ if (config.rtp.remote_ssrc == config.rtp.local_ssrc) {
+ if (config.rtp.local_ssrc != kDefaultRtcpReceiverReportSsrc) {
+ config.rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc;
+ } else {
+ config.rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc + 1;
+ }
+ }
+ bool default_renderer_used = false;
+ for (std::map<uint32, WebRtcVideoRenderer*>::iterator it = renderers_.begin();
+ it != renderers_.end();
+ ++it) {
+ if (it->second->GetRenderer() == default_renderer_) {
+ default_renderer_used = true;
+ break;
+ }
+ }
+
+ assert(renderers_[ssrc] == NULL);
+ renderers_[ssrc] = new WebRtcVideoRenderer();
+ if (!default_renderer_used) {
+ renderers_[ssrc]->SetRenderer(default_renderer_);
+ }
+ config.renderer = renderers_[ssrc];
+
+ {
+ // TODO(pbos): Base receive codecs off recv_codecs_ and set up using a
+ // DecoderFactory similar to send side. Pending webrtc:2854.
+ // Also set up default codecs if there's nothing in recv_codecs_.
+ webrtc::VideoCodec codec;
+ memset(&codec, 0, sizeof(codec));
+
+ codec.plType = kDefaultVideoCodecPref.payload_type;
+ strcpy(codec.plName, kDefaultVideoCodecPref.name);
+ codec.codecType = webrtc::kVideoCodecVP8;
+ codec.codecSpecific.VP8.resilience = webrtc::kResilientStream;
+ codec.codecSpecific.VP8.numberOfTemporalLayers = 1;
+ codec.codecSpecific.VP8.denoisingOn = true;
+ codec.codecSpecific.VP8.errorConcealmentOn = false;
+ codec.codecSpecific.VP8.automaticResizeOn = false;
+ codec.codecSpecific.VP8.frameDroppingOn = true;
+ codec.codecSpecific.VP8.keyFrameInterval = 3000;
+ // Bitrates don't matter and are ignored for the receiver. This is put in to
+ // have the current underlying implementation accept the VideoCodec.
+ codec.minBitrate = codec.startBitrate = codec.maxBitrate = 300;
+ config.codecs.push_back(codec);
+ for (size_t i = 0; i < recv_codecs_.size(); ++i) {
+ if (recv_codecs_[i].codec.id == codec.plType) {
+ config.rtp.fec = recv_codecs_[i].fec;
+ uint32 rtx_ssrc;
+ if (recv_codecs_[i].rtx_payload_type != -1 &&
+ sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
+ config.rtp.rtx[codec.plType].ssrc = rtx_ssrc;
+ config.rtp.rtx[codec.plType].payload_type =
+ recv_codecs_[i].rtx_payload_type;
+ }
+ break;
+ }
+ }
+ }
+
+ webrtc::VideoReceiveStream* receive_stream =
+ call_->CreateVideoReceiveStream(config);
+ assert(receive_stream != NULL);
+
+ receive_streams_[ssrc] = receive_stream;
+ receive_stream->Start();
+
+ return true;
+}
+
+bool WebRtcVideoChannel2::RemoveRecvStream(uint32 ssrc) {
+ LOG(LS_INFO) << "RemoveRecvStream: " << ssrc;
+ if (ssrc == 0) {
+ ssrc = default_recv_ssrc_;
+ }
+
+ std::map<uint32, webrtc::VideoReceiveStream*>::iterator stream =
+ receive_streams_.find(ssrc);
+ if (stream == receive_streams_.end()) {
+ LOG(LS_ERROR) << "Stream not found for ssrc: " << ssrc;
+ return false;
+ }
+ call_->DestroyVideoReceiveStream(stream->second);
+ receive_streams_.erase(stream);
+
+ std::map<uint32, WebRtcVideoRenderer*>::iterator renderer =
+ renderers_.find(ssrc);
+ assert(renderer != renderers_.end());
+ delete renderer->second;
+ renderers_.erase(renderer);
+
+ if (ssrc == default_recv_ssrc_) {
+ default_recv_ssrc_ = 0;
+ }
+
+ return true;
+}
+
+bool WebRtcVideoChannel2::SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
+ LOG(LS_INFO) << "SetRenderer: ssrc:" << ssrc << " "
+ << (renderer ? "(ptr)" : "NULL");
+ bool is_default_ssrc = false;
+ if (ssrc == 0) {
+ is_default_ssrc = true;
+ ssrc = default_recv_ssrc_;
+ default_renderer_ = renderer;
+ }
+
+ std::map<uint32, WebRtcVideoRenderer*>::iterator it = renderers_.find(ssrc);
+ if (it == renderers_.end()) {
+ return is_default_ssrc;
+ }
+
+ it->second->SetRenderer(renderer);
+ return true;
+}
+
+bool WebRtcVideoChannel2::GetRenderer(uint32 ssrc, VideoRenderer** renderer) {
+ if (ssrc == 0) {
+ if (default_renderer_ == NULL) {
+ return false;
+ }
+ *renderer = default_renderer_;
+ return true;
+ }
+
+ std::map<uint32, WebRtcVideoRenderer*>::iterator it = renderers_.find(ssrc);
+ if (it == renderers_.end()) {
+ return false;
+ }
+ *renderer = it->second->GetRenderer();
+ return true;
+}
+
+bool WebRtcVideoChannel2::GetStats(const StatsOptions& options,
+ VideoMediaInfo* info) {
+ // TODO(pbos): Implement.
+ return true;
+}
+
+bool WebRtcVideoChannel2::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
+ LOG(LS_INFO) << "SetCapturer: " << ssrc << " -> "
+ << (capturer != NULL ? "(capturer)" : "NULL");
+ assert(ssrc != 0);
+ if (send_streams_.find(ssrc) == send_streams_.end()) {
+ LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc;
+ return false;
+ }
+ return send_streams_[ssrc]->SetCapturer(capturer);
+}
+
+bool WebRtcVideoChannel2::SendIntraFrame() {
+ // TODO(pbos): Implement.
+ LOG(LS_VERBOSE) << "SendIntraFrame().";
+ return true;
+}
+
+bool WebRtcVideoChannel2::RequestIntraFrame() {
+ // TODO(pbos): Implement.
+ LOG(LS_VERBOSE) << "SendIntraFrame().";
+ return true;
+}
+
+void WebRtcVideoChannel2::OnPacketReceived(
+ talk_base::Buffer* packet,
+ const talk_base::PacketTime& packet_time) {
+ const webrtc::PacketReceiver::DeliveryStatus delivery_result =
+ call_->Receiver()->DeliverPacket(
+ reinterpret_cast<const uint8_t*>(packet->data()), packet->length());
+ switch (delivery_result) {
+ case webrtc::PacketReceiver::DELIVERY_OK:
+ return;
+ case webrtc::PacketReceiver::DELIVERY_PACKET_ERROR:
+ return;
+ case webrtc::PacketReceiver::DELIVERY_UNKNOWN_SSRC:
+ break;
+ }
+
+ uint32 ssrc = 0;
+ if (default_recv_ssrc_ != 0) { // Already one default stream.
+ LOG(LS_WARNING) << "Unknown SSRC, but default receive stream already set.";
+ return;
+ }
+
+ if (!GetRtpSsrc(packet->data(), packet->length(), &ssrc)) {
+ return;
+ }
+
+ StreamParams sp;
+ sp.ssrcs.push_back(ssrc);
+ LOG(LS_INFO) << "Creating default receive stream for SSRC=" << ssrc << ".";
+ AddRecvStream(sp);
+
+ if (call_->Receiver()->DeliverPacket(
+ reinterpret_cast<const uint8_t*>(packet->data()), packet->length()) !=
+ webrtc::PacketReceiver::DELIVERY_OK) {
+ LOG(LS_WARNING) << "Failed to deliver RTP packet after creating default "
+ "receiver.";
+ return;
+ }
+}
+
+void WebRtcVideoChannel2::OnRtcpReceived(
+ talk_base::Buffer* packet,
+ const talk_base::PacketTime& packet_time) {
+ if (call_->Receiver()->DeliverPacket(
+ reinterpret_cast<const uint8_t*>(packet->data()), packet->length()) !=
+ webrtc::PacketReceiver::DELIVERY_OK) {
+ LOG(LS_WARNING) << "Failed to deliver RTCP packet.";
+ }
+}
+
+void WebRtcVideoChannel2::OnReadyToSend(bool ready) {
+ LOG(LS_VERBOSE) << "OnReadySend: " << (ready ? "Ready." : "Not ready.");
+}
+
+bool WebRtcVideoChannel2::MuteStream(uint32 ssrc, bool mute) {
+ LOG(LS_VERBOSE) << "MuteStream: " << ssrc << " -> "
+ << (mute ? "mute" : "unmute");
+ assert(ssrc != 0);
+ if (send_streams_.find(ssrc) == send_streams_.end()) {
+ LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc;
+ return false;
+ }
+ return send_streams_[ssrc]->MuteStream(mute);
+}
+
+bool WebRtcVideoChannel2::SetRecvRtpHeaderExtensions(
+ const std::vector<RtpHeaderExtension>& extensions) {
+ LOG(LS_INFO) << "SetRecvRtpHeaderExtensions: "
+ << RtpExtensionsToString(extensions);
+ std::vector<webrtc::RtpExtension> webrtc_extensions;
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ // TODO(pbos): Make sure we don't pass unsupported extensions!
+ webrtc::RtpExtension webrtc_extension(extensions[i].uri.c_str(),
+ extensions[i].id);
+ webrtc_extensions.push_back(webrtc_extension);
+ }
+ recv_rtp_extensions_ = webrtc_extensions;
+ return true;
+}
+
+bool WebRtcVideoChannel2::SetSendRtpHeaderExtensions(
+ const std::vector<RtpHeaderExtension>& extensions) {
+ LOG(LS_INFO) << "SetSendRtpHeaderExtensions: "
+ << RtpExtensionsToString(extensions);
+ std::vector<webrtc::RtpExtension> webrtc_extensions;
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ // TODO(pbos): Make sure we don't pass unsupported extensions!
+ webrtc::RtpExtension webrtc_extension(extensions[i].uri.c_str(),
+ extensions[i].id);
+ webrtc_extensions.push_back(webrtc_extension);
+ }
+ send_rtp_extensions_ = webrtc_extensions;
+ return true;
+}
+
+bool WebRtcVideoChannel2::SetStartSendBandwidth(int bps) {
+ // TODO(pbos): Implement.
+ LOG(LS_VERBOSE) << "SetStartSendBandwidth: " << bps;
+ return true;
+}
+
+bool WebRtcVideoChannel2::SetMaxSendBandwidth(int bps) {
+ // TODO(pbos): Implement.
+ LOG(LS_VERBOSE) << "SetMaxSendBandwidth: " << bps;
+ return true;
+}
+
+bool WebRtcVideoChannel2::SetOptions(const VideoOptions& options) {
+ LOG(LS_VERBOSE) << "SetOptions: " << options.ToString();
+ options_.SetAll(options);
+ return true;
+}
+
+void WebRtcVideoChannel2::SetInterface(NetworkInterface* iface) {
+ MediaChannel::SetInterface(iface);
+ // Set the RTP recv/send buffer to a bigger size
+ MediaChannel::SetOption(NetworkInterface::ST_RTP,
+ talk_base::Socket::OPT_RCVBUF,
+ kVideoRtpBufferSize);
+
+ // TODO(sriniv): Remove or re-enable this.
+ // As part of b/8030474, send-buffer is size now controlled through
+ // portallocator flags.
+ // network_interface_->SetOption(NetworkInterface::ST_RTP,
+ // talk_base::Socket::OPT_SNDBUF,
+ // kVideoRtpBufferSize);
+}
+
+void WebRtcVideoChannel2::UpdateAspectRatio(int ratio_w, int ratio_h) {
+ // TODO(pbos): Implement.
+}
+
+void WebRtcVideoChannel2::OnMessage(talk_base::Message* msg) {
+ // Ignored.
+}
+
+bool WebRtcVideoChannel2::SendRtp(const uint8_t* data, size_t len) {
+ talk_base::Buffer packet(data, len, kMaxRtpPacketLen);
+ return MediaChannel::SendPacket(&packet);
+}
+
+bool WebRtcVideoChannel2::SendRtcp(const uint8_t* data, size_t len) {
+ talk_base::Buffer packet(data, len, kMaxRtpPacketLen);
+ return MediaChannel::SendRtcp(&packet);
+}
+
+void WebRtcVideoChannel2::StartAllSendStreams() {
+ for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
+ send_streams_.begin();
+ it != send_streams_.end();
+ ++it) {
+ it->second->Start();
+ }
+}
+
+void WebRtcVideoChannel2::StopAllSendStreams() {
+ for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
+ send_streams_.begin();
+ it != send_streams_.end();
+ ++it) {
+ it->second->Stop();
+ }
+}
+
+void WebRtcVideoChannel2::SetCodecForAllSendStreams(
+ const WebRtcVideoChannel2::VideoCodecSettings& codec) {
+ for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
+ send_streams_.begin();
+ it != send_streams_.end();
+ ++it) {
+ assert(it->second != NULL);
+ it->second->SetCodec(options_, codec);
+ }
+}
+
+WebRtcVideoChannel2::WebRtcVideoSendStream::VideoSendStreamParameters::
+ VideoSendStreamParameters(
+ const webrtc::VideoSendStream::Config& config,
+ const VideoOptions& options,
+ const VideoCodec& codec,
+ const std::vector<webrtc::VideoStream>& video_streams)
+ : config(config),
+ options(options),
+ codec(codec),
+ video_streams(video_streams) {
+}
+
+WebRtcVideoChannel2::WebRtcVideoSendStream::WebRtcVideoSendStream(
+ webrtc::Call* call,
+ const webrtc::VideoSendStream::Config& config,
+ const VideoOptions& options,
+ const VideoCodec& codec,
+ const std::vector<webrtc::VideoStream>& video_streams,
+ WebRtcVideoEncoderFactory2* encoder_factory)
+ : call_(call),
+ parameters_(config, options, codec, video_streams),
+ encoder_factory_(encoder_factory),
+ capturer_(NULL),
+ stream_(NULL),
+ sending_(false),
+ muted_(false),
+ format_(static_cast<int>(video_streams.back().height),
+ static_cast<int>(video_streams.back().width),
+ VideoFormat::FpsToInterval(video_streams.back().max_framerate),
+ FOURCC_I420) {
+ RecreateWebRtcStream();
+}
+
+WebRtcVideoChannel2::WebRtcVideoSendStream::~WebRtcVideoSendStream() {
+ DisconnectCapturer();
+ call_->DestroyVideoSendStream(stream_);
+ delete parameters_.config.encoder_settings.encoder;
+}
+
+static void SetWebRtcFrameToBlack(webrtc::I420VideoFrame* video_frame) {
+ assert(video_frame != NULL);
+ memset(video_frame->buffer(webrtc::kYPlane),
+ 16,
+ video_frame->allocated_size(webrtc::kYPlane));
+ memset(video_frame->buffer(webrtc::kUPlane),
+ 128,
+ video_frame->allocated_size(webrtc::kUPlane));
+ memset(video_frame->buffer(webrtc::kVPlane),
+ 128,
+ video_frame->allocated_size(webrtc::kVPlane));
+}
+
+static void CreateBlackFrame(webrtc::I420VideoFrame* video_frame,
+ int width,
+ int height) {
+ video_frame->CreateEmptyFrame(
+ width, height, width, (width + 1) / 2, (width + 1) / 2);
+ SetWebRtcFrameToBlack(video_frame);
+}
+
+static void ConvertToI420VideoFrame(const VideoFrame& frame,
+ webrtc::I420VideoFrame* i420_frame) {
+ i420_frame->CreateFrame(
+ static_cast<int>(frame.GetYPitch() * frame.GetHeight()),
+ frame.GetYPlane(),
+ static_cast<int>(frame.GetUPitch() * ((frame.GetHeight() + 1) / 2)),
+ frame.GetUPlane(),
+ static_cast<int>(frame.GetVPitch() * ((frame.GetHeight() + 1) / 2)),
+ frame.GetVPlane(),
+ static_cast<int>(frame.GetWidth()),
+ static_cast<int>(frame.GetHeight()),
+ static_cast<int>(frame.GetYPitch()),
+ static_cast<int>(frame.GetUPitch()),
+ static_cast<int>(frame.GetVPitch()));
+}
+
+void WebRtcVideoChannel2::WebRtcVideoSendStream::InputFrame(
+ VideoCapturer* capturer,
+ const VideoFrame* frame) {
+ LOG(LS_VERBOSE) << "InputFrame: " << frame->GetWidth() << "x"
+ << frame->GetHeight();
+ bool is_screencast = capturer->IsScreencast();
+ // Lock before copying, can be called concurrently when swapping input source.
+ talk_base::CritScope frame_cs(&frame_lock_);
+ if (!muted_) {
+ ConvertToI420VideoFrame(*frame, &video_frame_);
+ } else {
+ // Create a tiny black frame to transmit instead.
+ CreateBlackFrame(&video_frame_, 1, 1);
+ is_screencast = false;
+ }
+ talk_base::CritScope cs(&lock_);
+ if (format_.width == 0) { // Dropping frames.
+ assert(format_.height == 0);
+ LOG(LS_VERBOSE) << "VideoFormat 0x0 set, Dropping frame.";
+ return;
+ }
+ // Reconfigure codec if necessary.
+ if (is_screencast) {
+ SetDimensions(video_frame_.width(), video_frame_.height());
+ }
+ LOG(LS_VERBOSE) << "SwapFrame: " << video_frame_.width() << "x"
+ << video_frame_.height() << " -> (codec) "
+ << parameters_.video_streams.back().width << "x"
+ << parameters_.video_streams.back().height;
+ stream_->Input()->SwapFrame(&video_frame_);
+}
+
+bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetCapturer(
+ VideoCapturer* capturer) {
+ if (!DisconnectCapturer() && capturer == NULL) {
+ return false;
+ }
+
+ {
+ talk_base::CritScope cs(&lock_);
+
+ if (capturer == NULL) {
+ LOG(LS_VERBOSE) << "Disabling capturer, sending black frame.";
+ webrtc::I420VideoFrame black_frame;
+
+ int width = format_.width;
+ int height = format_.height;
+ int half_width = (width + 1) / 2;
+ black_frame.CreateEmptyFrame(
+ width, height, width, half_width, half_width);
+ SetWebRtcFrameToBlack(&black_frame);
+ SetDimensions(width, height);
+ stream_->Input()->SwapFrame(&black_frame);
+
+ capturer_ = NULL;
+ return true;
+ }
+
+ capturer_ = capturer;
+ }
+ // Lock cannot be held while connecting the capturer to prevent lock-order
+ // violations.
+ capturer->SignalVideoFrame.connect(this, &WebRtcVideoSendStream::InputFrame);
+ return true;
+}
+
+bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetVideoFormat(
+ const VideoFormat& format) {
+ if ((format.width == 0 || format.height == 0) &&
+ format.width != format.height) {
+ LOG(LS_ERROR) << "Can't set VideoFormat, width or height is zero (but not "
+ "both, 0x0 drops frames).";
+ return false;
+ }
+
+ talk_base::CritScope cs(&lock_);
+ if (format.width == 0 && format.height == 0) {
+ LOG(LS_INFO)
+ << "0x0 resolution selected. Captured frames will be dropped for ssrc: "
+ << parameters_.config.rtp.ssrcs[0] << ".";
+ } else {
+ // TODO(pbos): Fix me, this only affects the last stream!
+ parameters_.video_streams.back().max_framerate =
+ VideoFormat::IntervalToFps(format.interval);
+ SetDimensions(format.width, format.height);
+ }
+
+ format_ = format;
+ return true;
+}
+
+bool WebRtcVideoChannel2::WebRtcVideoSendStream::MuteStream(bool mute) {
+ talk_base::CritScope cs(&lock_);
+ bool was_muted = muted_;
+ muted_ = mute;
+ return was_muted != mute;
+}
+
+bool WebRtcVideoChannel2::WebRtcVideoSendStream::DisconnectCapturer() {
+ talk_base::CritScope cs(&lock_);
+ if (capturer_ == NULL) {
+ return false;
+ }
+ capturer_->SignalVideoFrame.disconnect(this);
+ capturer_ = NULL;
+ return true;
+}
+
+void WebRtcVideoChannel2::WebRtcVideoSendStream::SetCodec(
+ const VideoOptions& options,
+ const VideoCodecSettings& codec) {
+ talk_base::CritScope cs(&lock_);
+
+ std::vector<webrtc::VideoStream> video_streams =
+ encoder_factory_->CreateVideoStreams(
+ codec.codec, options, parameters_.video_streams.size());
+ if (video_streams.empty()) {
+ return;
+ }
+ parameters_.video_streams = video_streams;
+ format_ = VideoFormat(codec.codec.width,
+ codec.codec.height,
+ VideoFormat::FpsToInterval(30),
+ FOURCC_I420);
+
+ webrtc::VideoEncoder* old_encoder =
+ parameters_.config.encoder_settings.encoder;
+ parameters_.config.encoder_settings.encoder =
+ encoder_factory_->CreateVideoEncoder(codec.codec, options);
+ parameters_.config.rtp.fec = codec.fec;
+ // TODO(pbos): Should changing RTX payload type be allowed?
+ parameters_.codec = codec.codec;
+ parameters_.options = options;
+ RecreateWebRtcStream();
+ delete old_encoder;
+}
+
+void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions(int width,
+ int height) {
+ assert(!parameters_.video_streams.empty());
+ LOG(LS_VERBOSE) << "SetDimensions: " << width << "x" << height;
+ if (parameters_.video_streams.back().width == width &&
+ parameters_.video_streams.back().height == height) {
+ return;
+ }
+
+ // TODO(pbos): Fix me, this only affects the last stream!
+ parameters_.video_streams.back().width = width;
+ parameters_.video_streams.back().height = height;
+
+ // TODO(pbos): Wire up encoder_parameters, webrtc:3424.
+ if (!stream_->ReconfigureVideoEncoder(parameters_.video_streams, NULL)) {
+ LOG(LS_WARNING) << "Failed to reconfigure video encoder for dimensions: "
+ << width << "x" << height;
+ return;
+ }
+}
+
+void WebRtcVideoChannel2::WebRtcVideoSendStream::Start() {
+ talk_base::CritScope cs(&lock_);
+ stream_->Start();
+ sending_ = true;
+}
+
+void WebRtcVideoChannel2::WebRtcVideoSendStream::Stop() {
+ talk_base::CritScope cs(&lock_);
+ stream_->Stop();
+ sending_ = false;
+}
+
+void WebRtcVideoChannel2::WebRtcVideoSendStream::RecreateWebRtcStream() {
+ if (stream_ != NULL) {
+ call_->DestroyVideoSendStream(stream_);
+ }
+
+ // TODO(pbos): Wire up encoder_parameters, webrtc:3424.
+ stream_ = call_->CreateVideoSendStream(
+ parameters_.config, parameters_.video_streams, NULL);
+ if (sending_) {
+ stream_->Start();
+ }
+}
+
+WebRtcVideoChannel2::VideoCodecSettings::VideoCodecSettings()
+ : rtx_payload_type(-1) {}
+
+std::vector<WebRtcVideoChannel2::VideoCodecSettings>
+WebRtcVideoChannel2::MapCodecs(const std::vector<VideoCodec>& codecs) {
+ assert(!codecs.empty());
+
+ std::vector<VideoCodecSettings> video_codecs;
+ std::map<int, bool> payload_used;
+ std::map<int, VideoCodec::CodecType> payload_codec_type;
+ std::map<int, int> rtx_mapping; // video payload type -> rtx payload type.
+
+ webrtc::FecConfig fec_settings;
+
+ for (size_t i = 0; i < codecs.size(); ++i) {
+ const VideoCodec& in_codec = codecs[i];
+ int payload_type = in_codec.id;
+
+ if (payload_used[payload_type]) {
+ LOG(LS_ERROR) << "Payload type already registered: "
+ << in_codec.ToString();
+ return std::vector<VideoCodecSettings>();
+ }
+ payload_used[payload_type] = true;
+ payload_codec_type[payload_type] = in_codec.GetCodecType();
+
+ switch (in_codec.GetCodecType()) {
+ case VideoCodec::CODEC_RED: {
+ // RED payload type, should not have duplicates.
+ assert(fec_settings.red_payload_type == -1);
+ fec_settings.red_payload_type = in_codec.id;
+ continue;
+ }
+
+ case VideoCodec::CODEC_ULPFEC: {
+ // ULPFEC payload type, should not have duplicates.
+ assert(fec_settings.ulpfec_payload_type == -1);
+ fec_settings.ulpfec_payload_type = in_codec.id;
+ continue;
+ }
+
+ case VideoCodec::CODEC_RTX: {
+ int associated_payload_type;
+ if (!in_codec.GetParam(kCodecParamAssociatedPayloadType,
+ &associated_payload_type)) {
+ LOG(LS_ERROR) << "RTX codec without associated payload type: "
+ << in_codec.ToString();
+ return std::vector<VideoCodecSettings>();
+ }
+ rtx_mapping[associated_payload_type] = in_codec.id;
+ continue;
+ }
+
+ case VideoCodec::CODEC_VIDEO:
+ break;
+ }
+
+ video_codecs.push_back(VideoCodecSettings());
+ video_codecs.back().codec = in_codec;
+ }
+
+ // One of these codecs should have been a video codec. Only having FEC
+ // parameters into this code is a logic error.
+ assert(!video_codecs.empty());
+
+ for (std::map<int, int>::const_iterator it = rtx_mapping.begin();
+ it != rtx_mapping.end();
+ ++it) {
+ if (!payload_used[it->first]) {
+ LOG(LS_ERROR) << "RTX mapped to payload not in codec list.";
+ return std::vector<VideoCodecSettings>();
+ }
+ if (payload_codec_type[it->first] != VideoCodec::CODEC_VIDEO) {
+ LOG(LS_ERROR) << "RTX not mapped to regular video codec.";
+ return std::vector<VideoCodecSettings>();
+ }
+ }
+
+ // TODO(pbos): Write tests that figure out that I have not verified that RTX
+ // codecs aren't mapped to bogus payloads.
+ for (size_t i = 0; i < video_codecs.size(); ++i) {
+ video_codecs[i].fec = fec_settings;
+ if (rtx_mapping[video_codecs[i].codec.id] != 0) {
+ video_codecs[i].rtx_payload_type = rtx_mapping[video_codecs[i].codec.id];
+ }
+ }
+
+ return video_codecs;
+}
+
+std::vector<WebRtcVideoChannel2::VideoCodecSettings>
+WebRtcVideoChannel2::FilterSupportedCodecs(
+ const std::vector<WebRtcVideoChannel2::VideoCodecSettings>& mapped_codecs) {
+ std::vector<VideoCodecSettings> supported_codecs;
+ for (size_t i = 0; i < mapped_codecs.size(); ++i) {
+ if (encoder_factory_->SupportsCodec(mapped_codecs[i].codec)) {
+ supported_codecs.push_back(mapped_codecs[i]);
+ }
+ }
+ return supported_codecs;
+}
+
+} // namespace cricket
+
+#endif // HAVE_WEBRTC_VIDEO
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2.h b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2.h
new file mode 100644
index 00000000000..81466eb6579
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2.h
@@ -0,0 +1,367 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_H_
+#define TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_H_
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "talk/base/cpumonitor.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/media/base/mediaengine.h"
+#include "talk/media/webrtc/webrtcvideochannelfactory.h"
+#include "webrtc/common_video/interface/i420_video_frame.h"
+#include "webrtc/system_wrappers/interface/thread_annotations.h"
+#include "webrtc/transport.h"
+#include "webrtc/video_renderer.h"
+#include "webrtc/video_send_stream.h"
+
+namespace webrtc {
+class Call;
+class VideoCaptureModule;
+class VideoDecoder;
+class VideoEncoder;
+class VideoRender;
+class VideoSendStreamInput;
+class VideoReceiveStream;
+}
+
+namespace talk_base {
+class CpuMonitor;
+class Thread;
+} // namespace talk_base
+
+namespace cricket {
+
+class VideoCapturer;
+class VideoFrame;
+class VideoProcessor;
+class VideoRenderer;
+class VoiceMediaChannel;
+class WebRtcVideoChannel2;
+class WebRtcDecoderObserver;
+class WebRtcEncoderObserver;
+class WebRtcLocalStreamInfo;
+class WebRtcRenderAdapter;
+class WebRtcVideoChannelRecvInfo;
+class WebRtcVideoChannelSendInfo;
+class WebRtcVideoDecoderFactory;
+class WebRtcVoiceEngine;
+
+struct CapturedFrame;
+struct Device;
+
+class WebRtcVideoEngine2;
+class WebRtcVideoChannel2;
+
+class WebRtcVideoEncoderFactory2 {
+ public:
+ virtual ~WebRtcVideoEncoderFactory2();
+ virtual std::vector<webrtc::VideoStream> CreateVideoStreams(
+ const VideoCodec& codec,
+ const VideoOptions& options,
+ size_t num_streams);
+
+ virtual webrtc::VideoEncoder* CreateVideoEncoder(
+ const VideoCodec& codec,
+ const VideoOptions& options);
+
+ virtual bool SupportsCodec(const cricket::VideoCodec& codec);
+};
+
+// WebRtcVideoEngine2 is used for the new native WebRTC Video API (webrtc:1667).
+class WebRtcVideoEngine2 : public sigslot::has_slots<> {
+ public:
+ // Creates the WebRtcVideoEngine2 with internal VideoCaptureModule.
+ WebRtcVideoEngine2();
+ // Custom WebRtcVideoChannelFactory for testing purposes.
+ explicit WebRtcVideoEngine2(WebRtcVideoChannelFactory* channel_factory);
+ ~WebRtcVideoEngine2();
+
+ // Basic video engine implementation.
+ bool Init(talk_base::Thread* worker_thread);
+ void Terminate();
+
+ int GetCapabilities();
+ bool SetOptions(const VideoOptions& options);
+ bool SetDefaultEncoderConfig(const VideoEncoderConfig& config);
+ VideoEncoderConfig GetDefaultEncoderConfig() const;
+
+ WebRtcVideoChannel2* CreateChannel(VoiceMediaChannel* voice_channel);
+
+ const std::vector<VideoCodec>& codecs() const;
+ const std::vector<RtpHeaderExtension>& rtp_header_extensions() const;
+ void SetLogging(int min_sev, const char* filter);
+
+ bool EnableTimedRender();
+ // No-op, never used.
+ bool SetLocalRenderer(VideoRenderer* renderer);
+ // This is currently ignored.
+ sigslot::repeater2<VideoCapturer*, CaptureState> SignalCaptureStateChange;
+
+ // Set the VoiceEngine for A/V sync. This can only be called before Init.
+ bool SetVoiceEngine(WebRtcVoiceEngine* voice_engine);
+
+ // Functions called by WebRtcVideoChannel2.
+ const VideoFormat& default_codec_format() const {
+ return default_codec_format_;
+ }
+
+ bool FindCodec(const VideoCodec& in);
+ bool CanSendCodec(const VideoCodec& in,
+ const VideoCodec& current,
+ VideoCodec* out);
+ // Check whether the supplied trace should be ignored.
+ bool ShouldIgnoreTrace(const std::string& trace);
+
+ VideoFormat GetStartCaptureFormat() const { return default_codec_format_; }
+
+ talk_base::CpuMonitor* cpu_monitor() { return cpu_monitor_.get(); }
+
+ virtual WebRtcVideoEncoderFactory2* GetVideoEncoderFactory();
+
+ private:
+ void Construct(WebRtcVideoChannelFactory* channel_factory,
+ WebRtcVoiceEngine* voice_engine,
+ talk_base::CpuMonitor* cpu_monitor);
+
+ talk_base::Thread* worker_thread_;
+ WebRtcVoiceEngine* voice_engine_;
+ std::vector<VideoCodec> video_codecs_;
+ std::vector<RtpHeaderExtension> rtp_header_extensions_;
+ VideoFormat default_codec_format_;
+
+ bool initialized_;
+
+ bool capture_started_;
+
+ // Critical section to protect the media processor register/unregister
+ // while processing a frame
+ talk_base::CriticalSection signal_media_critical_;
+
+ talk_base::scoped_ptr<talk_base::CpuMonitor> cpu_monitor_;
+ WebRtcVideoChannelFactory* channel_factory_;
+ WebRtcVideoEncoderFactory2 default_video_encoder_factory_;
+};
+
+// Adapter between webrtc::VideoRenderer and cricket::VideoRenderer.
+// The webrtc::VideoRenderer is set once, whereas the cricket::VideoRenderer can
+// be set after initialization. This adapter will also convert the incoming
+// webrtc::I420VideoFrame to a frame type that cricket::VideoRenderer can
+// render.
+class WebRtcVideoRenderer : public webrtc::VideoRenderer {
+ public:
+ WebRtcVideoRenderer();
+
+ virtual void RenderFrame(const webrtc::I420VideoFrame& frame,
+ int time_to_render_ms) OVERRIDE;
+
+ void SetRenderer(cricket::VideoRenderer* renderer);
+ cricket::VideoRenderer* GetRenderer();
+
+ private:
+ void SetSize(int width, int height);
+ int last_width_;
+ int last_height_;
+ talk_base::CriticalSection lock_;
+ cricket::VideoRenderer* renderer_ GUARDED_BY(lock_);
+};
+
+class WebRtcVideoChannel2 : public talk_base::MessageHandler,
+ public VideoMediaChannel,
+ public webrtc::newapi::Transport {
+ public:
+ WebRtcVideoChannel2(WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel,
+ WebRtcVideoEncoderFactory2* encoder_factory);
+ // For testing purposes insert a pre-constructed call to verify that
+ // WebRtcVideoChannel2 calls the correct corresponding methods.
+ WebRtcVideoChannel2(webrtc::Call* call,
+ WebRtcVideoEngine2* engine,
+ WebRtcVideoEncoderFactory2* encoder_factory);
+ ~WebRtcVideoChannel2();
+ bool Init();
+
+ // VideoMediaChannel implementation
+ virtual bool SetRecvCodecs(const std::vector<VideoCodec>& codecs) OVERRIDE;
+ virtual bool SetSendCodecs(const std::vector<VideoCodec>& codecs) OVERRIDE;
+ virtual bool GetSendCodec(VideoCodec* send_codec) OVERRIDE;
+ virtual bool SetSendStreamFormat(uint32 ssrc,
+ const VideoFormat& format) OVERRIDE;
+ virtual bool SetRender(bool render) OVERRIDE;
+ virtual bool SetSend(bool send) OVERRIDE;
+
+ virtual bool AddSendStream(const StreamParams& sp) OVERRIDE;
+ virtual bool RemoveSendStream(uint32 ssrc) OVERRIDE;
+ virtual bool AddRecvStream(const StreamParams& sp) OVERRIDE;
+ virtual bool RemoveRecvStream(uint32 ssrc) OVERRIDE;
+ virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer) OVERRIDE;
+ virtual bool GetStats(const StatsOptions& options,
+ VideoMediaInfo* info) OVERRIDE;
+ virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer) OVERRIDE;
+ virtual bool SendIntraFrame() OVERRIDE;
+ virtual bool RequestIntraFrame() OVERRIDE;
+
+ virtual void OnPacketReceived(talk_base::Buffer* packet,
+ const talk_base::PacketTime& packet_time)
+ OVERRIDE;
+ virtual void OnRtcpReceived(talk_base::Buffer* packet,
+ const talk_base::PacketTime& packet_time)
+ OVERRIDE;
+ virtual void OnReadyToSend(bool ready) OVERRIDE;
+ virtual bool MuteStream(uint32 ssrc, bool mute) OVERRIDE;
+
+ // Set send/receive RTP header extensions. This must be done before creating
+ // streams as it only has effect on future streams.
+ virtual bool SetRecvRtpHeaderExtensions(
+ const std::vector<RtpHeaderExtension>& extensions) OVERRIDE;
+ virtual bool SetSendRtpHeaderExtensions(
+ const std::vector<RtpHeaderExtension>& extensions) OVERRIDE;
+ virtual bool SetStartSendBandwidth(int bps) OVERRIDE;
+ virtual bool SetMaxSendBandwidth(int bps) OVERRIDE;
+ virtual bool SetOptions(const VideoOptions& options) OVERRIDE;
+ virtual bool GetOptions(VideoOptions* options) const OVERRIDE {
+ *options = options_;
+ return true;
+ }
+ virtual void SetInterface(NetworkInterface* iface) OVERRIDE;
+ virtual void UpdateAspectRatio(int ratio_w, int ratio_h) OVERRIDE;
+
+ virtual void OnMessage(talk_base::Message* msg) OVERRIDE;
+
+ // Implemented for VideoMediaChannelTest.
+ bool sending() const { return sending_; }
+ uint32 GetDefaultChannelSsrc() { return default_send_ssrc_; }
+ bool GetRenderer(uint32 ssrc, VideoRenderer** renderer);
+
+ private:
+ struct VideoCodecSettings {
+ VideoCodecSettings();
+
+ VideoCodec codec;
+ webrtc::FecConfig fec;
+ int rtx_payload_type;
+ };
+
+ class WebRtcVideoSendStream : public sigslot::has_slots<> {
+ public:
+ WebRtcVideoSendStream(webrtc::Call* call,
+ const webrtc::VideoSendStream::Config& config,
+ const VideoOptions& options,
+ const VideoCodec& codec,
+ const std::vector<webrtc::VideoStream>& video_streams,
+ WebRtcVideoEncoderFactory2* encoder_factory);
+ ~WebRtcVideoSendStream();
+ void SetCodec(const VideoOptions& options, const VideoCodecSettings& codec);
+
+ void InputFrame(VideoCapturer* capturer, const VideoFrame* frame);
+ bool SetCapturer(VideoCapturer* capturer);
+ bool SetVideoFormat(const VideoFormat& format);
+ bool MuteStream(bool mute);
+ bool DisconnectCapturer();
+
+ void Start();
+ void Stop();
+
+ private:
+ // Parameters needed to reconstruct the underlying stream.
+ // webrtc::VideoSendStream doesn't support setting a lot of options on the
+ // fly, so when those need to be changed we tear down and reconstruct with
+ // similar parameters depending on which options changed etc.
+ struct VideoSendStreamParameters {
+ VideoSendStreamParameters(
+ const webrtc::VideoSendStream::Config& config,
+ const VideoOptions& options,
+ const VideoCodec& codec,
+ const std::vector<webrtc::VideoStream>& video_streams);
+ webrtc::VideoSendStream::Config config;
+ VideoOptions options;
+ VideoCodec codec;
+ // Sent resolutions + bitrates etc. by the underlying VideoSendStream,
+ // typically changes when setting a new resolution or reconfiguring
+ // bitrates.
+ std::vector<webrtc::VideoStream> video_streams;
+ };
+
+ void RecreateWebRtcStream();
+ void SetDimensions(int width, int height);
+
+ webrtc::Call* const call_;
+ WebRtcVideoEncoderFactory2* const encoder_factory_;
+
+ talk_base::CriticalSection lock_;
+ webrtc::VideoSendStream* stream_ GUARDED_BY(lock_);
+ VideoSendStreamParameters parameters_ GUARDED_BY(lock_);
+
+ VideoCapturer* capturer_ GUARDED_BY(lock_);
+ bool sending_ GUARDED_BY(lock_);
+ bool muted_ GUARDED_BY(lock_);
+ VideoFormat format_ GUARDED_BY(lock_);
+
+ talk_base::CriticalSection frame_lock_;
+ webrtc::I420VideoFrame video_frame_ GUARDED_BY(frame_lock_);
+ };
+
+ void Construct(webrtc::Call* call, WebRtcVideoEngine2* engine);
+
+ virtual bool SendRtp(const uint8_t* data, size_t len) OVERRIDE;
+ virtual bool SendRtcp(const uint8_t* data, size_t len) OVERRIDE;
+
+ void StartAllSendStreams();
+ void StopAllSendStreams();
+ void SetCodecForAllSendStreams(const VideoCodecSettings& codec);
+ static std::vector<VideoCodecSettings> MapCodecs(
+ const std::vector<VideoCodec>& codecs);
+ std::vector<VideoCodecSettings> FilterSupportedCodecs(
+ const std::vector<VideoCodecSettings>& mapped_codecs);
+
+ uint32_t rtcp_receiver_report_ssrc_;
+ bool sending_;
+ talk_base::scoped_ptr<webrtc::Call> call_;
+ std::map<uint32, WebRtcVideoRenderer*> renderers_;
+ VideoRenderer* default_renderer_;
+ uint32_t default_send_ssrc_;
+ uint32_t default_recv_ssrc_;
+
+ // Using primary-ssrc (first ssrc) as key.
+ std::map<uint32, WebRtcVideoSendStream*> send_streams_;
+ std::map<uint32, webrtc::VideoReceiveStream*> receive_streams_;
+
+ Settable<VideoCodecSettings> send_codec_;
+ std::vector<webrtc::RtpExtension> send_rtp_extensions_;
+
+ WebRtcVideoEncoderFactory2* const encoder_factory_;
+ std::vector<VideoCodecSettings> recv_codecs_;
+ std::vector<webrtc::RtpExtension> recv_rtp_extensions_;
+ VideoOptions options_;
+};
+
+} // namespace cricket
+
+#endif // TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_H_
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2_unittest.cc
new file mode 100644
index 00000000000..6886300234d
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2_unittest.cc
@@ -0,0 +1,1367 @@
+/*
+ * libjingle
+ * Copyright 2004 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <map>
+#include <vector>
+
+#include "talk/base/gunit.h"
+#include "talk/media/base/testutils.h"
+#include "talk/media/base/videoengine_unittest.h"
+#include "talk/media/webrtc/webrtcvideoengine2.h"
+#include "talk/media/webrtc/webrtcvideoengine2_unittest.h"
+#include "talk/media/webrtc/webrtcvideochannelfactory.h"
+
+namespace {
+static const cricket::VideoCodec kVp8Codec720p(100, "VP8", 1280, 720, 30, 0);
+static const cricket::VideoCodec kVp8Codec360p(100, "VP8", 640, 360, 30, 0);
+static const cricket::VideoCodec kVp8Codec270p(100, "VP8", 480, 270, 30, 0);
+static const cricket::VideoCodec kVp8Codec180p(100, "VP8", 320, 180, 30, 0);
+
+static const cricket::VideoCodec kVp8Codec(100, "VP8", 640, 400, 30, 0);
+static const cricket::VideoCodec kVp9Codec(101, "VP9", 640, 400, 30, 0);
+static const cricket::VideoCodec kRedCodec(116, "red", 0, 0, 0, 0);
+static const cricket::VideoCodec kUlpfecCodec(117, "ulpfec", 0, 0, 0, 0);
+
+static const uint32 kSsrcs1[] = {1};
+static const uint32 kRtxSsrcs1[] = {4};
+
+void VerifyCodecHasDefaultFeedbackParams(const cricket::VideoCodec& codec) {
+ EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
+ cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
+ EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
+ cricket::kRtcpFbParamNack, cricket::kRtcpFbNackParamPli)));
+ EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
+ cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty)));
+ EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
+ cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir)));
+}
+
+} // namespace
+
+namespace cricket {
+FakeVideoSendStream::FakeVideoSendStream(
+ const webrtc::VideoSendStream::Config& config,
+ const std::vector<webrtc::VideoStream>& video_streams)
+ : sending_(false), config_(config), video_streams_(video_streams) {
+}
+
+webrtc::VideoSendStream::Config FakeVideoSendStream::GetConfig() {
+ return config_;
+}
+
+std::vector<webrtc::VideoStream> FakeVideoSendStream::GetVideoStreams() {
+ return video_streams_;
+}
+
+bool FakeVideoSendStream::IsSending() {
+ return sending_;
+}
+
+webrtc::VideoSendStream::Stats FakeVideoSendStream::GetStats() const {
+ return webrtc::VideoSendStream::Stats();
+}
+
+bool FakeVideoSendStream::ReconfigureVideoEncoder(
+ const std::vector<webrtc::VideoStream>& streams,
+ const void* encoder_specific) {
+ video_streams_ = streams;
+ return true;
+}
+
+webrtc::VideoSendStreamInput* FakeVideoSendStream::Input() {
+ // TODO(pbos): Fix.
+ return NULL;
+}
+
+void FakeVideoSendStream::Start() {
+ sending_ = true;
+}
+
+void FakeVideoSendStream::Stop() {
+ sending_ = false;
+}
+
+FakeVideoReceiveStream::FakeVideoReceiveStream(
+ const webrtc::VideoReceiveStream::Config& config)
+ : config_(config), receiving_(false) {
+}
+
+webrtc::VideoReceiveStream::Config FakeVideoReceiveStream::GetConfig() {
+ return config_;
+}
+
+webrtc::VideoReceiveStream::Stats FakeVideoReceiveStream::GetStats() const {
+ return webrtc::VideoReceiveStream::Stats();
+}
+
+void FakeVideoReceiveStream::Start() {
+ receiving_ = true;
+}
+void FakeVideoReceiveStream::Stop() {
+ receiving_ = false;
+}
+void FakeVideoReceiveStream::GetCurrentReceiveCodec(webrtc::VideoCodec* codec) {
+}
+
+FakeCall::FakeCall() { SetVideoCodecs(GetDefaultVideoCodecs()); }
+
+FakeCall::~FakeCall() {
+ EXPECT_EQ(0u, video_send_streams_.size());
+ EXPECT_EQ(0u, video_receive_streams_.size());
+}
+
+void FakeCall::SetVideoCodecs(const std::vector<webrtc::VideoCodec> codecs) {
+ codecs_ = codecs;
+}
+
+std::vector<FakeVideoSendStream*> FakeCall::GetVideoSendStreams() {
+ return video_send_streams_;
+}
+
+std::vector<FakeVideoReceiveStream*> FakeCall::GetVideoReceiveStreams() {
+ return video_receive_streams_;
+}
+
+webrtc::VideoCodec FakeCall::GetEmptyVideoCodec() {
+ webrtc::VideoCodec codec;
+ codec.minBitrate = 300;
+ codec.startBitrate = 800;
+ codec.maxBitrate = 1500;
+ codec.maxFramerate = 10;
+ codec.width = 640;
+ codec.height = 480;
+ codec.qpMax = 56;
+
+ return codec;
+}
+
+webrtc::VideoCodec FakeCall::GetVideoCodecVp8() {
+ webrtc::VideoCodec vp8_codec = GetEmptyVideoCodec();
+ vp8_codec.codecType = webrtc::kVideoCodecVP8;
+ strcpy(vp8_codec.plName, kVp8Codec.name.c_str());
+ vp8_codec.plType = kVp8Codec.id;
+
+ return vp8_codec;
+}
+
+webrtc::VideoCodec FakeCall::GetVideoCodecVp9() {
+ webrtc::VideoCodec vp9_codec = GetEmptyVideoCodec();
+ // TODO(pbos): Add a correct codecType when webrtc has one.
+ vp9_codec.codecType = webrtc::kVideoCodecVP8;
+ strcpy(vp9_codec.plName, kVp9Codec.name.c_str());
+ vp9_codec.plType = kVp9Codec.id;
+
+ return vp9_codec;
+}
+
+std::vector<webrtc::VideoCodec> FakeCall::GetDefaultVideoCodecs() {
+ std::vector<webrtc::VideoCodec> codecs;
+ codecs.push_back(GetVideoCodecVp8());
+ // codecs.push_back(GetVideoCodecVp9());
+
+ return codecs;
+}
+
+webrtc::VideoSendStream::Config FakeCall::GetDefaultSendConfig() {
+ webrtc::VideoSendStream::Config config;
+ // TODO(pbos): Encoder settings.
+ // config.codec = GetVideoCodecVp8();
+ return config;
+}
+
+webrtc::VideoSendStream* FakeCall::CreateVideoSendStream(
+ const webrtc::VideoSendStream::Config& config,
+ const std::vector<webrtc::VideoStream>& video_streams,
+ const void* encoder_settings) {
+ FakeVideoSendStream* fake_stream =
+ new FakeVideoSendStream(config, video_streams);
+ video_send_streams_.push_back(fake_stream);
+ return fake_stream;
+}
+
+void FakeCall::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
+ FakeVideoSendStream* fake_stream =
+ static_cast<FakeVideoSendStream*>(send_stream);
+ for (size_t i = 0; i < video_send_streams_.size(); ++i) {
+ if (video_send_streams_[i] == fake_stream) {
+ delete video_send_streams_[i];
+ video_send_streams_.erase(video_send_streams_.begin() + i);
+ return;
+ }
+ }
+ ADD_FAILURE() << "DestroyVideoSendStream called with unknown paramter.";
+}
+
+webrtc::VideoReceiveStream::Config FakeCall::GetDefaultReceiveConfig() {
+ return webrtc::VideoReceiveStream::Config();
+}
+
+webrtc::VideoReceiveStream* FakeCall::CreateVideoReceiveStream(
+ const webrtc::VideoReceiveStream::Config& config) {
+ video_receive_streams_.push_back(new FakeVideoReceiveStream(config));
+ return video_receive_streams_[video_receive_streams_.size() - 1];
+}
+
+void FakeCall::DestroyVideoReceiveStream(
+ webrtc::VideoReceiveStream* receive_stream) {
+ FakeVideoReceiveStream* fake_stream =
+ static_cast<FakeVideoReceiveStream*>(receive_stream);
+ for (size_t i = 0; i < video_receive_streams_.size(); ++i) {
+ if (video_receive_streams_[i] == fake_stream) {
+ delete video_receive_streams_[i];
+ video_receive_streams_.erase(video_receive_streams_.begin() + i);
+ return;
+ }
+ }
+ ADD_FAILURE() << "DestroyVideoReceiveStream called with unknown paramter.";
+}
+
+webrtc::PacketReceiver* FakeCall::Receiver() {
+ // TODO(pbos): Fix this.
+ return NULL;
+}
+
+uint32_t FakeCall::SendBitrateEstimate() {
+ return 0;
+}
+
+uint32_t FakeCall::ReceiveBitrateEstimate() {
+ return 0;
+}
+
+FakeWebRtcVideoChannel2::FakeWebRtcVideoChannel2(
+ FakeCall* call,
+ WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel)
+ : WebRtcVideoChannel2(call, engine, engine->GetVideoEncoderFactory()),
+ fake_call_(call),
+ voice_channel_(voice_channel) {
+}
+
+FakeWebRtcVideoChannel2::~FakeWebRtcVideoChannel2() {
+}
+
+VoiceMediaChannel* FakeWebRtcVideoChannel2::GetVoiceChannel() {
+ return voice_channel_;
+}
+FakeCall* FakeWebRtcVideoChannel2::GetFakeCall() {
+ return fake_call_;
+}
+
+FakeWebRtcVideoChannel2* FakeWebRtcVideoMediaChannelFactory::GetFakeChannel(
+ VideoMediaChannel* channel) {
+ return channel_map_[channel];
+}
+
+WebRtcVideoChannel2* FakeWebRtcVideoMediaChannelFactory::Create(
+ WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel) {
+ FakeWebRtcVideoChannel2* channel =
+ new FakeWebRtcVideoChannel2(new FakeCall(), engine, voice_channel);
+ channel_map_[channel] = channel;
+ return channel;
+}
+
+class WebRtcVideoEngine2Test : public testing::Test {
+ public:
+ WebRtcVideoEngine2Test() : engine_(&factory_) {
+ std::vector<VideoCodec> engine_codecs = engine_.codecs();
+ assert(!engine_codecs.empty());
+ bool codec_set = false;
+ for (size_t i = 0; i < engine_codecs.size(); ++i) {
+ if (engine_codecs[i].name == "red") {
+ default_red_codec_ = engine_codecs[i];
+ } else if (engine_codecs[i].name == "ulpfec") {
+ default_ulpfec_codec_ = engine_codecs[i];
+ } else if (engine_codecs[i].name == "rtx") {
+ default_rtx_codec_ = engine_codecs[i];
+ } else if (!codec_set) {
+ default_codec_ = engine_codecs[i];
+ codec_set = true;
+ }
+ }
+
+ assert(codec_set);
+ }
+
+ protected:
+ FakeWebRtcVideoMediaChannelFactory factory_;
+ WebRtcVideoEngine2 engine_;
+ VideoCodec default_codec_;
+ VideoCodec default_red_codec_;
+ VideoCodec default_ulpfec_codec_;
+ VideoCodec default_rtx_codec_;
+};
+
+TEST_F(WebRtcVideoEngine2Test, CreateChannel) {
+ talk_base::scoped_ptr<VideoMediaChannel> channel(engine_.CreateChannel(NULL));
+ ASSERT_TRUE(channel.get() != NULL) << "Could not create channel.";
+ EXPECT_TRUE(factory_.GetFakeChannel(channel.get()) != NULL)
+ << "Channel not created through factory.";
+}
+
+TEST_F(WebRtcVideoEngine2Test, CreateChannelWithVoiceEngine) {
+ VoiceMediaChannel* voice_channel = reinterpret_cast<VoiceMediaChannel*>(0x42);
+ talk_base::scoped_ptr<VideoMediaChannel> channel(
+ engine_.CreateChannel(voice_channel));
+ ASSERT_TRUE(channel.get() != NULL) << "Could not create channel.";
+
+ FakeWebRtcVideoChannel2* fake_channel =
+ factory_.GetFakeChannel(channel.get());
+ ASSERT_TRUE(fake_channel != NULL) << "Channel not created through factory.";
+
+ EXPECT_TRUE(fake_channel->GetVoiceChannel() != NULL)
+ << "VoiceChannel not set.";
+ EXPECT_EQ(voice_channel, fake_channel->GetVoiceChannel())
+ << "Different VoiceChannel set than the provided one.";
+}
+
+TEST_F(WebRtcVideoEngine2Test, FindCodec) {
+ const std::vector<cricket::VideoCodec>& c = engine_.codecs();
+ EXPECT_EQ(4U, c.size());
+
+ cricket::VideoCodec vp8(104, "VP8", 320, 200, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(vp8));
+
+ cricket::VideoCodec vp8_ci(104, "vp8", 320, 200, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(vp8));
+
+ cricket::VideoCodec vp8_diff_fr_diff_pref(104, "VP8", 320, 200, 50, 50);
+ EXPECT_TRUE(engine_.FindCodec(vp8_diff_fr_diff_pref));
+
+ cricket::VideoCodec vp8_diff_id(95, "VP8", 320, 200, 30, 0);
+ EXPECT_FALSE(engine_.FindCodec(vp8_diff_id));
+ vp8_diff_id.id = 97;
+ EXPECT_TRUE(engine_.FindCodec(vp8_diff_id));
+
+ cricket::VideoCodec vp8_diff_res(104, "VP8", 320, 111, 30, 0);
+ EXPECT_FALSE(engine_.FindCodec(vp8_diff_res));
+
+ // PeerConnection doesn't negotiate the resolution at this point.
+ // Test that FindCodec can handle the case when width/height is 0.
+ cricket::VideoCodec vp8_zero_res(104, "VP8", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(vp8_zero_res));
+
+ cricket::VideoCodec red(101, "RED", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(red));
+
+ cricket::VideoCodec red_ci(101, "red", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(red));
+
+ cricket::VideoCodec fec(102, "ULPFEC", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(fec));
+
+ cricket::VideoCodec fec_ci(102, "ulpfec", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(fec));
+
+ cricket::VideoCodec rtx(96, "rtx", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(rtx));
+}
+
+TEST_F(WebRtcVideoEngine2Test, DefaultRtxCodecHasAssociatedPayloadTypeSet) {
+ std::vector<VideoCodec> engine_codecs = engine_.codecs();
+ for (size_t i = 0; i < engine_codecs.size(); ++i) {
+ if (engine_codecs[i].name != kRtxCodecName)
+ continue;
+ int associated_payload_type;
+ EXPECT_TRUE(engine_codecs[i].GetParam(kCodecParamAssociatedPayloadType,
+ &associated_payload_type));
+ EXPECT_EQ(default_codec_.id, associated_payload_type);
+ return;
+ }
+ FAIL() << "No RTX codec found among default codecs.";
+}
+
+TEST_F(WebRtcVideoEngine2Test, SupportsTimestampOffsetHeaderExtension) {
+ std::vector<RtpHeaderExtension> extensions = engine_.rtp_header_extensions();
+ ASSERT_FALSE(extensions.empty());
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ if (extensions[i].uri == kRtpTimestampOffsetHeaderExtension) {
+ EXPECT_EQ(kRtpTimestampOffsetHeaderExtensionDefaultId, extensions[i].id);
+ return;
+ }
+ }
+ FAIL() << "Timestamp offset extension not in header-extension list.";
+}
+
+TEST_F(WebRtcVideoEngine2Test, SupportsAbsoluteSenderTimeHeaderExtension) {
+ std::vector<RtpHeaderExtension> extensions = engine_.rtp_header_extensions();
+ ASSERT_FALSE(extensions.empty());
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ if (extensions[i].uri == kRtpAbsoluteSenderTimeHeaderExtension) {
+ EXPECT_EQ(kRtpAbsoluteSenderTimeHeaderExtensionDefaultId,
+ extensions[i].id);
+ return;
+ }
+ }
+ FAIL() << "Absolute Sender Time extension not in header-extension list.";
+}
+
+class WebRtcVideoChannel2BaseTest
+ : public VideoMediaChannelTest<WebRtcVideoEngine2, WebRtcVideoChannel2> {
+ protected:
+ virtual cricket::VideoCodec DefaultCodec() OVERRIDE { return kVp8Codec; }
+ typedef VideoMediaChannelTest<WebRtcVideoEngine2, WebRtcVideoChannel2> Base;
+};
+
+// TODO(pbos): Fix WebRtcVideoEngine2BaseTest, where we want CheckCoInitialize.
+#if 0
+// TODO(juberti): Figure out why ViE is munging the COM refcount.
+#ifdef WIN32
+TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_CheckCoInitialize) {
+ Base::CheckCoInitialize();
+}
+#endif
+#endif
+
+TEST_F(WebRtcVideoChannel2BaseTest, SetSend) { Base::SetSend(); }
+
+TEST_F(WebRtcVideoChannel2BaseTest, SetSendWithoutCodecs) {
+ Base::SetSendWithoutCodecs();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, SetSendSetsTransportBufferSizes) {
+ Base::SetSendSetsTransportBufferSizes();
+}
+
+// TODO(juberti): Fix this test to tolerate missing stats.
+TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_GetStats) { Base::GetStats(); }
+
+// TODO(juberti): Fix this test to tolerate missing stats.
+TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_GetStatsMultipleRecvStreams) {
+ Base::GetStatsMultipleRecvStreams();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_GetStatsMultipleSendStreams) {
+ Base::GetStatsMultipleSendStreams();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, SetSendBandwidth) {
+ Base::SetSendBandwidth();
+}
+TEST_F(WebRtcVideoChannel2BaseTest, SetSendSsrc) { Base::SetSendSsrc(); }
+TEST_F(WebRtcVideoChannel2BaseTest, SetSendSsrcAfterSetCodecs) {
+ Base::SetSendSsrcAfterSetCodecs();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, SetRenderer) { Base::SetRenderer(); }
+
+TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveRecvStreams) {
+ Base::AddRemoveRecvStreams();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_AddRemoveRecvStreamAndRender) {
+ Base::AddRemoveRecvStreamAndRender();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveRecvStreamsNoConference) {
+ Base::AddRemoveRecvStreamsNoConference();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveSendStreams) {
+ Base::AddRemoveSendStreams();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, SimulateConference) {
+ Base::SimulateConference();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveCapturer) {
+ Base::AddRemoveCapturer();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, RemoveCapturerWithoutAdd) {
+ Base::RemoveCapturerWithoutAdd();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveCapturerMultipleSources) {
+ Base::AddRemoveCapturerMultipleSources();
+}
+
+// TODO(pbos): Figure out why this fails so often.
+TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_HighAspectHighHeightCapturer) {
+ Base::HighAspectHighHeightCapturer();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, RejectEmptyStreamParams) {
+ Base::RejectEmptyStreamParams();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, AdaptResolution16x10) {
+ Base::AdaptResolution16x10();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, AdaptResolution4x3) {
+ Base::AdaptResolution4x3();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, MuteStream) { Base::MuteStream(); }
+
+TEST_F(WebRtcVideoChannel2BaseTest, MultipleSendStreams) {
+ Base::MultipleSendStreams();
+}
+
+// TODO(juberti): Restore this test once we support sending 0 fps.
+TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_AdaptDropAllFrames) {
+ Base::AdaptDropAllFrames();
+}
+// TODO(juberti): Understand why we get decode errors on this test.
+TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_AdaptFramerate) {
+ Base::AdaptFramerate();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, SetSendStreamFormat0x0) {
+ Base::SetSendStreamFormat0x0();
+}
+
+// TODO(zhurunz): Fix the flakey test.
+TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_SetSendStreamFormat) {
+ Base::SetSendStreamFormat();
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, TwoStreamsSendAndReceive) {
+ Base::TwoStreamsSendAndReceive(kVp8Codec);
+}
+
+TEST_F(WebRtcVideoChannel2BaseTest, TwoStreamsReUseFirstStream) {
+ Base::TwoStreamsReUseFirstStream(kVp8Codec);
+}
+
+class WebRtcVideoChannel2Test : public WebRtcVideoEngine2Test {
+ public:
+ virtual void SetUp() OVERRIDE {
+ channel_.reset(engine_.CreateChannel(NULL));
+ fake_channel_ = factory_.GetFakeChannel(channel_.get());
+ last_ssrc_ = 123;
+ ASSERT_TRUE(fake_channel_ != NULL)
+ << "Channel not created through factory.";
+ }
+
+ protected:
+ FakeVideoSendStream* AddSendStream() {
+ return AddSendStream(StreamParams::CreateLegacy(last_ssrc_++));
+ }
+
+ FakeVideoSendStream* AddSendStream(const StreamParams& sp) {
+ size_t num_streams =
+ fake_channel_->GetFakeCall()->GetVideoSendStreams().size();
+ EXPECT_TRUE(channel_->AddSendStream(sp));
+ std::vector<FakeVideoSendStream*> streams =
+ fake_channel_->GetFakeCall()->GetVideoSendStreams();
+ EXPECT_EQ(num_streams + 1, streams.size());
+ return streams[streams.size() - 1];
+ }
+
+ std::vector<FakeVideoSendStream*> GetFakeSendStreams() {
+ return fake_channel_->GetFakeCall()->GetVideoSendStreams();
+ }
+
+ FakeVideoReceiveStream* AddRecvStream() {
+ return AddRecvStream(StreamParams::CreateLegacy(last_ssrc_++));
+ }
+
+ FakeVideoReceiveStream* AddRecvStream(const StreamParams& sp) {
+ size_t num_streams =
+ fake_channel_->GetFakeCall()->GetVideoReceiveStreams().size();
+ EXPECT_TRUE(channel_->AddRecvStream(sp));
+ std::vector<FakeVideoReceiveStream*> streams =
+ fake_channel_->GetFakeCall()->GetVideoReceiveStreams();
+ EXPECT_EQ(num_streams + 1, streams.size());
+ return streams[streams.size() - 1];
+ }
+
+ void SetSendCodecsShouldWorkForBitrates(const char* min_bitrate,
+ const char* max_bitrate) {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ codecs[0].params[kCodecParamMinBitrate] = min_bitrate;
+ codecs[0].params[kCodecParamMaxBitrate] = max_bitrate;
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+
+ FakeVideoSendStream* stream = AddSendStream();
+
+ std::vector<webrtc::VideoStream> video_streams = stream->GetVideoStreams();
+ ASSERT_EQ(1u, video_streams.size());
+ EXPECT_EQ(atoi(min_bitrate), video_streams.back().min_bitrate_bps / 1000);
+ EXPECT_EQ(atoi(max_bitrate), video_streams.back().max_bitrate_bps / 1000);
+
+ VideoCodec codec;
+ EXPECT_TRUE(channel_->GetSendCodec(&codec));
+ EXPECT_EQ(min_bitrate, codec.params[kCodecParamMinBitrate]);
+ EXPECT_EQ(max_bitrate, codec.params[kCodecParamMaxBitrate]);
+ }
+
+ void ExpectEqualCodecs(const VideoCodec video_codec,
+ const webrtc::VideoCodec& webrtc_codec) {
+ EXPECT_STREQ(video_codec.name.c_str(), webrtc_codec.plName);
+ EXPECT_EQ(video_codec.id, webrtc_codec.plType);
+ EXPECT_EQ(video_codec.width, webrtc_codec.width);
+ EXPECT_EQ(video_codec.height, webrtc_codec.height);
+ EXPECT_EQ(video_codec.framerate, webrtc_codec.maxFramerate);
+ }
+
+ void TestSetSendRtpHeaderExtensions(const std::string& cricket_ext,
+ const std::string& webrtc_ext) {
+ // Enable extension.
+ const int id = 1;
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(cricket_ext, id));
+ EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
+
+ FakeVideoSendStream* send_stream =
+ AddSendStream(cricket::StreamParams::CreateLegacy(123));
+
+ // Verify the send extension id.
+ ASSERT_EQ(1u, send_stream->GetConfig().rtp.extensions.size());
+ EXPECT_EQ(id, send_stream->GetConfig().rtp.extensions[0].id);
+ EXPECT_EQ(webrtc_ext, send_stream->GetConfig().rtp.extensions[0].name);
+ // Verify call with same set of extensions returns true.
+ EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
+ // Verify that SetSendRtpHeaderExtensions doesn't implicitly add them for
+ // receivers.
+ EXPECT_TRUE(AddRecvStream(cricket::StreamParams::CreateLegacy(123))
+ ->GetConfig()
+ .rtp.extensions.empty());
+
+ // Remove the extension id, verify that this doesn't reset extensions as
+ // they should be set before creating channels.
+ std::vector<cricket::RtpHeaderExtension> empty_extensions;
+ EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(empty_extensions));
+ EXPECT_FALSE(send_stream->GetConfig().rtp.extensions.empty());
+ }
+
+ void TestSetRecvRtpHeaderExtensions(const std::string& cricket_ext,
+ const std::string& webrtc_ext) {
+ // Enable extension.
+ const int id = 1;
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(cricket_ext, id));
+ EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+
+ FakeVideoReceiveStream* recv_stream =
+ AddRecvStream(cricket::StreamParams::CreateLegacy(123));
+
+ // Verify the recv extension id.
+ ASSERT_EQ(1u, recv_stream->GetConfig().rtp.extensions.size());
+ EXPECT_EQ(id, recv_stream->GetConfig().rtp.extensions[0].id);
+ EXPECT_EQ(webrtc_ext, recv_stream->GetConfig().rtp.extensions[0].name);
+ // Verify call with same set of extensions returns true.
+ EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+ // Verify that SetRecvRtpHeaderExtensions doesn't implicitly add them for
+ // senders.
+ EXPECT_TRUE(AddSendStream(cricket::StreamParams::CreateLegacy(123))
+ ->GetConfig()
+ .rtp.extensions.empty());
+
+ // Remove the extension id, verify that this doesn't reset extensions as
+ // they should be set before creating channels.
+ std::vector<cricket::RtpHeaderExtension> empty_extensions;
+ EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(empty_extensions));
+ EXPECT_FALSE(recv_stream->GetConfig().rtp.extensions.empty());
+ }
+
+ talk_base::scoped_ptr<VideoMediaChannel> channel_;
+ FakeWebRtcVideoChannel2* fake_channel_;
+ uint32 last_ssrc_;
+};
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_MaxBitrateResetsWithConferenceMode) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_StartSendBitrate) {
+ // TODO(pbos): Is this test testing vie_ ? this is confusing. No API to set
+ // start send bitrate from outside? Add defaults here that should be kept?
+ std::vector<cricket::VideoCodec> codec_list;
+ codec_list.push_back(kVp8Codec);
+ EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
+ const unsigned int kVideoMinSendBitrateKbps = 50;
+ const unsigned int kVideoTargetSendBitrateKbps = 300;
+ const unsigned int kVideoMaxSendBitrateKbps = 2000;
+ FakeVideoSendStream* stream = AddSendStream();
+ std::vector<webrtc::VideoStream> video_streams = stream->GetVideoStreams();
+ ASSERT_EQ(1u, video_streams.size());
+ EXPECT_EQ(kVideoMinSendBitrateKbps,
+ video_streams.back().min_bitrate_bps / 1000);
+ EXPECT_EQ(kVideoTargetSendBitrateKbps,
+ video_streams.back().target_bitrate_bps / 1000);
+ EXPECT_EQ(kVideoMaxSendBitrateKbps,
+ video_streams.back().max_bitrate_bps / 1000);
+#if 0
+ // TODO(pbos): un-#if
+ VerifyVP8SendCodec(send_channel, kVP8Codec.width, kVP8Codec.height, 0,
+ kVideoMaxSendBitrateKbps, kVideoMinSendBitrateKbps,
+ kVideoDefaultStartSendBitrateKbps);
+ EXPECT_EQ(0, vie_.StartSend(send_channel));
+
+ // Increase the send bitrate and verify it is used as start bitrate.
+ const unsigned int kVideoSendBitrateBps = 768000;
+ vie_.SetSendBitrates(send_channel, kVideoSendBitrateBps, 0, 0);
+ EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
+ VerifyVP8SendCodec(send_channel, kVP8Codec.width, kVP8Codec.height, 0,
+ kVideoMaxSendBitrateKbps, kVideoMinSendBitrateKbps,
+ kVideoSendBitrateBps / 1000);
+
+ // Never set a start bitrate higher than the max bitrate.
+ vie_.SetSendBitrates(send_channel, kVideoMaxSendBitrateKbps + 500, 0, 0);
+ EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
+ VerifyVP8SendCodec(send_channel, kVP8Codec.width, kVP8Codec.height, 0,
+ kVideoMaxSendBitrateKbps, kVideoMinSendBitrateKbps,
+ kVideoDefaultStartSendBitrateKbps);
+
+ // Use the default start bitrate if the send bitrate is lower.
+ vie_.SetSendBitrates(send_channel, kVideoDefaultStartSendBitrateKbps - 50, 0,
+ 0);
+ EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
+ VerifyVP8SendCodec(send_channel, kVP8Codec.width, kVP8Codec.height, 0,
+ kVideoMaxSendBitrateKbps, kVideoMinSendBitrateKbps,
+ kVideoDefaultStartSendBitrateKbps);
+#endif
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_RtcpEnabled) {
+ // Note(pbos): This is a receiver-side setting, dumbo.
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_KeyFrameRequestEnabled) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, RembIsEnabledByDefault) {
+ FakeVideoReceiveStream* stream = AddRecvStream();
+ EXPECT_TRUE(stream->GetConfig().rtp.remb);
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_RembEnabledOnReceiveChannels) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, RecvStreamWithSimAndRtx) {
+ EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
+ EXPECT_TRUE(channel_->SetSend(true));
+ cricket::VideoOptions options;
+ options.conference_mode.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options));
+
+ // Send side.
+ const std::vector<uint32> ssrcs = MAKE_VECTOR(kSsrcs1);
+ const std::vector<uint32> rtx_ssrcs = MAKE_VECTOR(kRtxSsrcs1);
+ FakeVideoSendStream* send_stream = AddSendStream(
+ cricket::CreateSimWithRtxStreamParams("cname", ssrcs, rtx_ssrcs));
+
+ ASSERT_EQ(rtx_ssrcs.size(), send_stream->GetConfig().rtp.rtx.ssrcs.size());
+ for (size_t i = 0; i < rtx_ssrcs.size(); ++i)
+ EXPECT_EQ(rtx_ssrcs[i], send_stream->GetConfig().rtp.rtx.ssrcs[i]);
+
+ // Receiver side.
+ FakeVideoReceiveStream* recv_stream = AddRecvStream(
+ cricket::CreateSimWithRtxStreamParams("cname", ssrcs, rtx_ssrcs));
+ ASSERT_GT(recv_stream->GetConfig().rtp.rtx.size(), 0u)
+ << "No SSRCs for RTX configured by AddRecvStream.";
+ ASSERT_EQ(1u, recv_stream->GetConfig().rtp.rtx.size())
+ << "This test only works with one receive codec. Please update the test.";
+ EXPECT_EQ(rtx_ssrcs[0],
+ recv_stream->GetConfig().rtp.rtx.begin()->second.ssrc);
+ // TODO(pbos): Make sure we set the RTX for correct payloads etc.
+}
+
+TEST_F(WebRtcVideoChannel2Test, RecvStreamWithRtx) {
+ // Setup one channel with an associated RTX stream.
+ cricket::StreamParams params =
+ cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
+ params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
+ FakeVideoReceiveStream* recv_stream = AddRecvStream(params);
+ ASSERT_EQ(1u, recv_stream->GetConfig().rtp.rtx.size());
+ EXPECT_EQ(kRtxSsrcs1[0],
+ recv_stream->GetConfig().rtp.rtx.begin()->second.ssrc);
+}
+
+TEST_F(WebRtcVideoChannel2Test, RecvStreamNoRtx) {
+ // Setup one channel without an associated RTX stream.
+ cricket::StreamParams params =
+ cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
+ FakeVideoReceiveStream* recv_stream = AddRecvStream(params);
+ ASSERT_TRUE(recv_stream->GetConfig().rtp.rtx.empty());
+}
+
+TEST_F(WebRtcVideoChannel2Test, NoHeaderExtesionsByDefault) {
+ FakeVideoSendStream* send_stream =
+ AddSendStream(cricket::StreamParams::CreateLegacy(kSsrcs1[0]));
+ ASSERT_TRUE(send_stream->GetConfig().rtp.extensions.empty());
+
+ FakeVideoReceiveStream* recv_stream =
+ AddRecvStream(cricket::StreamParams::CreateLegacy(kSsrcs1[0]));
+ ASSERT_TRUE(recv_stream->GetConfig().rtp.extensions.empty());
+}
+
+// Test support for RTP timestamp offset header extension.
+TEST_F(WebRtcVideoChannel2Test, SendRtpTimestampOffsetHeaderExtensions) {
+ TestSetSendRtpHeaderExtensions(kRtpTimestampOffsetHeaderExtension,
+ webrtc::RtpExtension::kTOffset);
+}
+TEST_F(WebRtcVideoChannel2Test, RecvRtpTimestampOffsetHeaderExtensions) {
+ TestSetRecvRtpHeaderExtensions(kRtpTimestampOffsetHeaderExtension,
+ webrtc::RtpExtension::kTOffset);
+}
+
+// Test support for absolute send time header extension.
+TEST_F(WebRtcVideoChannel2Test, SendAbsoluteSendTimeHeaderExtensions) {
+ TestSetSendRtpHeaderExtensions(kRtpAbsoluteSenderTimeHeaderExtension,
+ webrtc::RtpExtension::kAbsSendTime);
+}
+TEST_F(WebRtcVideoChannel2Test, RecvAbsoluteSendTimeHeaderExtensions) {
+ TestSetRecvRtpHeaderExtensions(kRtpAbsoluteSenderTimeHeaderExtension,
+ webrtc::RtpExtension::kAbsSendTime);
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_LeakyBucketTest) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_BufferedModeLatency) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_AdditiveVideoOptions) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, AddRecvStreamOnlyUsesOneReceiveStream) {
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
+ EXPECT_EQ(1u, fake_channel_->GetFakeCall()->GetVideoReceiveStreams().size());
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_NoRembChangeAfterAddRecvStream) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_RembOnOff) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, NackIsEnabledByDefault) {
+ VerifyCodecHasDefaultFeedbackParams(default_codec_);
+
+ EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
+ EXPECT_TRUE(channel_->SetSend(true));
+
+ // Send side.
+ FakeVideoSendStream* send_stream =
+ AddSendStream(cricket::StreamParams::CreateLegacy(1));
+ EXPECT_GT(send_stream->GetConfig().rtp.nack.rtp_history_ms, 0);
+
+ // Receiver side.
+ FakeVideoReceiveStream* recv_stream =
+ AddRecvStream(cricket::StreamParams::CreateLegacy(1));
+ EXPECT_GT(recv_stream->GetConfig().rtp.nack.rtp_history_ms, 0);
+
+ // Nack history size should match between sender and receiver.
+ EXPECT_EQ(send_stream->GetConfig().rtp.nack.rtp_history_ms,
+ recv_stream->GetConfig().rtp.nack.rtp_history_ms);
+}
+
+TEST_F(WebRtcVideoChannel2Test, NackCanBeDisabled) {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+
+ // Send side.
+ ASSERT_TRUE(channel_->SetSendCodecs(codecs));
+ FakeVideoSendStream* send_stream =
+ AddSendStream(cricket::StreamParams::CreateLegacy(1));
+ EXPECT_EQ(0, send_stream->GetConfig().rtp.nack.rtp_history_ms);
+
+ // Receiver side.
+ ASSERT_TRUE(channel_->SetRecvCodecs(codecs));
+ FakeVideoReceiveStream* recv_stream =
+ AddRecvStream(cricket::StreamParams::CreateLegacy(1));
+ EXPECT_EQ(0, recv_stream->GetConfig().rtp.nack.rtp_history_ms);
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_VideoProtectionInterop) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_VideoProtectionInteropReversed) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_HybridNackFecConference) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_AddRemoveRecvStreamConference) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetRender) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetBandwidthAuto) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetBandwidthAutoCapped) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetBandwidthFixed) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetBandwidthInConference) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetBandwidthScreencast) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetSendSsrcAndCname) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ DISABLED_SetSendSsrcAfterCreatingReceiveChannel) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetOptionsWithDenoising) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_MultipleSendStreamsWithOneCapturer) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_DISABLED_SendReceiveBitratesStats) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_TestSetAdaptInputToCpuUsage) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_TestSetCpuThreshold) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_TestSetInvalidCpuThreshold) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_WebRtcShouldLog) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_WebRtcShouldNotLog) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetDefaultSendCodecs) {
+ ASSERT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
+
+ VideoCodec codec;
+ EXPECT_TRUE(channel_->GetSendCodec(&codec));
+ EXPECT_TRUE(codec.Matches(engine_.codecs()[0]));
+
+ // Using a RTX setup to verify that the default RTX payload type is good.
+ const std::vector<uint32> ssrcs = MAKE_VECTOR(kSsrcs1);
+ const std::vector<uint32> rtx_ssrcs = MAKE_VECTOR(kRtxSsrcs1);
+ FakeVideoSendStream* stream = AddSendStream(
+ cricket::CreateSimWithRtxStreamParams("cname", ssrcs, rtx_ssrcs));
+ webrtc::VideoSendStream::Config config = stream->GetConfig();
+ // TODO(pbos): Replace ExpectEqualCodecs.
+ // ExpectEqualCodecs(engine_.codecs()[0], config.codec);
+
+ // Make sure NACK and FEC are enabled on the correct payload types.
+ EXPECT_EQ(1000, config.rtp.nack.rtp_history_ms);
+ EXPECT_EQ(default_ulpfec_codec_.id, config.rtp.fec.ulpfec_payload_type);
+ EXPECT_EQ(default_red_codec_.id, config.rtp.fec.red_payload_type);
+ // TODO(pbos): Verify that the rtx ssrc is set, correct, not taken by anything
+ // else.
+ // ASSERT_EQ(1u, config.rtp.rtx.ssrcs.size());
+ EXPECT_EQ(static_cast<int>(default_rtx_codec_.id),
+ config.rtp.rtx.payload_type);
+ // TODO(juberti): Check RTCP, PLI, TMMBR.
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithoutFec) {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ ASSERT_TRUE(channel_->SetSendCodecs(codecs));
+
+ FakeVideoSendStream* stream = AddSendStream();
+ webrtc::VideoSendStream::Config config = stream->GetConfig();
+
+ EXPECT_EQ(-1, config.rtp.fec.ulpfec_payload_type);
+ EXPECT_EQ(-1, config.rtp.fec.red_payload_type);
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ DISABLED_SetSendCodecRejectsRtxWithoutAssociatedPayloadType) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ DISABLED_SetSendCodecRejectsRtxWithoutMatchingVideoCodec) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ DISABLED_SetCodecsWithoutFecDisablesCurrentFec) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetSendCodecsChangesExistingStreams) {
+ FAIL(); // TODO(pbos): Implement, make sure that it's changing running
+ // streams. Should it?
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ DISABLED_ConstrainsSetCodecsAccordingToEncoderConfig) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithMinMaxBitrate) {
+ SetSendCodecsShouldWorkForBitrates("10", "20");
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetSendCodecsRejectsMaxLessThanMinBitrate) {
+ std::vector<VideoCodec> video_codecs = engine_.codecs();
+ video_codecs[0].params[kCodecParamMinBitrate] = "30";
+ video_codecs[0].params[kCodecParamMaxBitrate] = "20";
+ EXPECT_FALSE(channel_->SetSendCodecs(video_codecs));
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetSendCodecsAcceptLargeMinMaxBitrate) {
+ SetSendCodecsShouldWorkForBitrates("1000", "2000");
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithMaxQuantization) {
+ static const char* kMaxQuantization = "21";
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ codecs[0].params[kCodecParamMaxQuantization] = kMaxQuantization;
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_EQ(static_cast<unsigned int>(atoi(kMaxQuantization)),
+ AddSendStream()->GetVideoStreams().back().max_qp);
+
+ VideoCodec codec;
+ EXPECT_TRUE(channel_->GetSendCodec(&codec));
+ EXPECT_EQ(kMaxQuantization, codec.params[kCodecParamMaxQuantization]);
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetSendCodecsRejectBadDimensions) {
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+
+ codecs[0].width = 0;
+ EXPECT_FALSE(channel_->SetSendCodecs(codecs))
+ << "Codec set though codec width is zero.";
+
+ codecs[0].width = kVp8Codec.width;
+ codecs[0].height = 0;
+ EXPECT_FALSE(channel_->SetSendCodecs(codecs))
+ << "Codec set though codec height is zero.";
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetSendCodecsRejectBadPayloadTypes) {
+ // TODO(pbos): Should we only allow the dynamic range?
+ static const size_t kNumIncorrectPayloads = 4;
+ static const int kIncorrectPayloads[kNumIncorrectPayloads] = {-2, -1, 128,
+ 129};
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ for (size_t i = 0; i < kNumIncorrectPayloads; ++i) {
+ int payload_type = kIncorrectPayloads[i];
+ codecs[0].id = payload_type;
+ EXPECT_FALSE(channel_->SetSendCodecs(codecs))
+ << "Bad payload type '" << payload_type << "' accepted.";
+ }
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetSendCodecsAcceptAllValidPayloadTypes) {
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ for (int payload_type = 0; payload_type <= 127; ++payload_type) {
+ codecs[0].id = payload_type;
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs))
+ << "Payload type '" << payload_type << "' rejected.";
+ }
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_ResetVieSendCodecOnNewFrameSize) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithOnlyVp8) {
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+}
+
+// Test that we set our inbound RTX codecs properly.
+TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithRtx) {
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
+ codecs.push_back(rtx_codec);
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs))
+ << "RTX codec without associated payload should be rejected.";
+
+ codecs[1].SetParam("apt", kVp8Codec.id + 1);
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs))
+ << "RTX codec with invalid associated payload type should be rejected.";
+
+ codecs[1].SetParam("apt", kVp8Codec.id);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+
+ cricket::VideoCodec rtx_codec2(97, "rtx", 0, 0, 0, 0);
+ rtx_codec2.SetParam("apt", rtx_codec.id);
+ codecs.push_back(rtx_codec2);
+
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs)) << "RTX codec with another RTX "
+ "as associated payload type "
+ "should be rejected.";
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsDifferentPayloadType) {
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ codecs[0].id = 99;
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetRecvCodecsAcceptDefaultCodecs) {
+ EXPECT_TRUE(channel_->SetRecvCodecs(engine_.codecs()));
+ // (I've added this one.) Make sure they propagate down to VideoReceiveStream!
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsRejectUnsupportedCodec) {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ codecs.push_back(VideoCodec(101, "WTF3", 640, 400, 30, 0));
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
+}
+
+// TODO(pbos): Enable VP9 through external codec support
+TEST_F(WebRtcVideoChannel2Test,
+ DISABLED_SetRecvCodecsAcceptsMultipleVideoCodecs) {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ codecs.push_back(kVp9Codec);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ DISABLED_SetRecvCodecsSetsFecForAllVideoCodecs) {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ codecs.push_back(kVp9Codec);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+ FAIL(); // TODO(pbos): Verify that the FEC parameters are set for all codecs.
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetSendCodecsRejectDuplicateFecPayloads) {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ codecs.push_back(kRedCodec);
+ codecs[1].id = codecs[0].id;
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsRejectDuplicateCodecPayloads) {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ codecs.push_back(kVp9Codec);
+ codecs[1].id = codecs[0].id;
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ SetRecvCodecsAcceptSameCodecOnMultiplePayloadTypes) {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ codecs.push_back(kVp8Codec);
+ codecs[1].id += 1;
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+}
+
+TEST_F(WebRtcVideoChannel2Test, SendStreamNotSendingByDefault) {
+ EXPECT_FALSE(AddSendStream()->IsSending());
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_ReceiveStreamReceivingByDefault) {
+ // Is this test correct though? Auto-receive? Enable receive on first packet?
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, SetSend) {
+ AddSendStream();
+ EXPECT_FALSE(channel_->SetSend(true))
+ << "Channel should not start without codecs.";
+ EXPECT_TRUE(channel_->SetSend(false))
+ << "Channel should be stoppable even without set codecs.";
+
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ channel_->SetSendCodecs(codecs);
+ std::vector<FakeVideoSendStream*> streams = GetFakeSendStreams();
+ ASSERT_EQ(1u, streams.size());
+ FakeVideoSendStream* stream = streams.back();
+
+ EXPECT_FALSE(stream->IsSending());
+
+ // false->true
+ EXPECT_TRUE(channel_->SetSend(true));
+ EXPECT_TRUE(stream->IsSending());
+ // true->true
+ EXPECT_TRUE(channel_->SetSend(true));
+ EXPECT_TRUE(stream->IsSending());
+ // true->false
+ EXPECT_TRUE(channel_->SetSend(false));
+ EXPECT_FALSE(stream->IsSending());
+ // false->false
+ EXPECT_TRUE(channel_->SetSend(false));
+ EXPECT_FALSE(stream->IsSending());
+
+ EXPECT_TRUE(channel_->SetSend(true));
+ FakeVideoSendStream* new_stream = AddSendStream();
+ EXPECT_TRUE(new_stream->IsSending())
+ << "Send stream created after SetSend(true) not sending initially.";
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SendAndReceiveVp8Vga) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SendAndReceiveVp8Qvga) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SendAndReceiveH264SvcQqvga) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SendManyResizeOnce) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SendVp8HdAndReceiveAdaptedVp8Vga) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_TestSetDscpOptions) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetOptionsWithMaxBitrate) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetOptionsWithLoweredBitrate) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_SetOptionsSucceedsWhenSending) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_ResetCodecOnScreencast) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_DontResetCodecOnSendFrame) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ DISABLED_DontRegisterDecoderIfFactoryIsNotGiven) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_RegisterDecoderIfFactoryIsGiven) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_DontRegisterDecoderMultipleTimes) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_DontRegisterDecoderForNonVP8) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ DISABLED_DontRegisterEncoderIfFactoryIsNotGiven) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_RegisterEncoderIfFactoryIsGiven) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_DontRegisterEncoderMultipleTimes) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test,
+ DISABLED_RegisterEncoderWithMultipleSendStreams) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_DontRegisterEncoderForNonVP8) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_FeedbackParamsForNonVP8) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_ExternalCodecAddedToTheEnd) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_ExternalCodecIgnored) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_UpdateEncoderCodecsAfterSetFactory) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_OnReadyToSend) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+
+TEST_F(WebRtcVideoChannel2Test, DISABLED_CaptureFrameTimestampToNtpTimestamp) {
+ FAIL() << "Not implemented."; // TODO(pbos): Implement.
+}
+} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2_unittest.h b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2_unittest.h
new file mode 100644
index 00000000000..879b4f40448
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine2_unittest.h
@@ -0,0 +1,157 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_UNITTEST_H_
+#define TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_UNITTEST_H_
+
+#include <map>
+#include <vector>
+
+#include "webrtc/call.h"
+#include "webrtc/video_receive_stream.h"
+#include "webrtc/video_send_stream.h"
+
+namespace cricket {
+class FakeVideoSendStream : public webrtc::VideoSendStream {
+ public:
+ FakeVideoSendStream(const webrtc::VideoSendStream::Config& config,
+ const std::vector<webrtc::VideoStream>& video_streams);
+ webrtc::VideoSendStream::Config GetConfig();
+ std::vector<webrtc::VideoStream> GetVideoStreams();
+
+ bool IsSending();
+
+ private:
+ virtual webrtc::VideoSendStream::Stats GetStats() const OVERRIDE;
+
+ virtual bool ReconfigureVideoEncoder(
+ const std::vector<webrtc::VideoStream>& streams,
+ const void* encoder_specific);
+
+ virtual webrtc::VideoSendStreamInput* Input() OVERRIDE;
+
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+
+ bool sending_;
+ webrtc::VideoSendStream::Config config_;
+ std::vector<webrtc::VideoStream> video_streams_;
+};
+
+class FakeVideoReceiveStream : public webrtc::VideoReceiveStream {
+ public:
+ explicit FakeVideoReceiveStream(
+ const webrtc::VideoReceiveStream::Config& config);
+
+ webrtc::VideoReceiveStream::Config GetConfig();
+
+ private:
+ virtual webrtc::VideoReceiveStream::Stats GetStats() const OVERRIDE;
+
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+ virtual void GetCurrentReceiveCodec(webrtc::VideoCodec* codec);
+
+ webrtc::VideoReceiveStream::Config config_;
+ bool receiving_;
+};
+
+class FakeCall : public webrtc::Call {
+ public:
+ FakeCall();
+ ~FakeCall();
+
+ void SetVideoCodecs(const std::vector<webrtc::VideoCodec> codecs);
+
+ std::vector<FakeVideoSendStream*> GetVideoSendStreams();
+ std::vector<FakeVideoReceiveStream*> GetVideoReceiveStreams();
+
+ webrtc::VideoCodec GetEmptyVideoCodec();
+
+ webrtc::VideoCodec GetVideoCodecVp8();
+ webrtc::VideoCodec GetVideoCodecVp9();
+
+ std::vector<webrtc::VideoCodec> GetDefaultVideoCodecs();
+
+ private:
+ virtual webrtc::VideoSendStream::Config GetDefaultSendConfig() OVERRIDE;
+
+ virtual webrtc::VideoSendStream* CreateVideoSendStream(
+ const webrtc::VideoSendStream::Config& config,
+ const std::vector<webrtc::VideoStream>& video_streams,
+ const void* encoder_settings) OVERRIDE;
+
+ virtual void DestroyVideoSendStream(
+ webrtc::VideoSendStream* send_stream) OVERRIDE;
+
+ virtual webrtc::VideoReceiveStream::Config GetDefaultReceiveConfig() OVERRIDE;
+
+ virtual webrtc::VideoReceiveStream* CreateVideoReceiveStream(
+ const webrtc::VideoReceiveStream::Config& config) OVERRIDE;
+
+ virtual void DestroyVideoReceiveStream(
+ webrtc::VideoReceiveStream* receive_stream) OVERRIDE;
+ virtual webrtc::PacketReceiver* Receiver() OVERRIDE;
+
+ virtual uint32_t SendBitrateEstimate() OVERRIDE;
+ virtual uint32_t ReceiveBitrateEstimate() OVERRIDE;
+
+ std::vector<webrtc::VideoCodec> codecs_;
+ std::vector<FakeVideoSendStream*> video_send_streams_;
+ std::vector<FakeVideoReceiveStream*> video_receive_streams_;
+};
+
+class FakeWebRtcVideoChannel2 : public WebRtcVideoChannel2 {
+ public:
+ FakeWebRtcVideoChannel2(FakeCall* call,
+ WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel);
+ virtual ~FakeWebRtcVideoChannel2();
+
+ VoiceMediaChannel* GetVoiceChannel();
+ FakeCall* GetFakeCall();
+
+ private:
+ FakeCall* fake_call_;
+ VoiceMediaChannel* voice_channel_;
+};
+
+class FakeWebRtcVideoMediaChannelFactory : public WebRtcVideoChannelFactory {
+ public:
+ FakeWebRtcVideoChannel2* GetFakeChannel(VideoMediaChannel* channel);
+
+ private:
+ virtual WebRtcVideoChannel2* Create(
+ WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel) OVERRIDE;
+
+ std::map<VideoMediaChannel*, FakeWebRtcVideoChannel2*> channel_map_;
+};
+
+
+} // namespace cricket
+#endif // TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_UNITTEST_H_
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine_unittest.cc b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine_unittest.cc
index d5886a13822..307e594b926 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoengine_unittest.cc
@@ -36,6 +36,7 @@
#include "talk/media/base/fakevideorenderer.h"
#include "talk/media/base/mediachannel.h"
#include "talk/media/base/testutils.h"
+#include "talk/media/base/videoadapter.h"
#include "talk/media/base/videoengine_unittest.h"
#include "talk/media/webrtc/fakewebrtcvideocapturemodule.h"
#include "talk/media/webrtc/fakewebrtcvideoengine.h"
@@ -49,6 +50,9 @@
// Tests for the WebRtcVideoEngine/VideoChannel code.
+using cricket::kRtpTimestampOffsetHeaderExtension;
+using cricket::kRtpAbsoluteSenderTimeHeaderExtension;
+
static const cricket::VideoCodec kVP8Codec720p(100, "VP8", 1280, 720, 30, 0);
static const cricket::VideoCodec kVP8Codec360p(100, "VP8", 640, 360, 30, 0);
static const cricket::VideoCodec kVP8Codec270p(100, "VP8", 480, 270, 30, 0);
@@ -63,16 +67,14 @@ static const cricket::VideoCodec* const kVideoCodecs[] = {
&kUlpFecCodec
};
-static const unsigned int kMinBandwidthKbps = 50;
static const unsigned int kStartBandwidthKbps = 300;
+static const unsigned int kMinBandwidthKbps = 50;
static const unsigned int kMaxBandwidthKbps = 2000;
-static const unsigned int kNumberOfTemporalLayers = 1;
-
static const uint32 kSsrcs1[] = {1};
static const uint32 kSsrcs2[] = {1, 2};
static const uint32 kSsrcs3[] = {1, 2, 3};
-static const uint32 kRtxSsrc1[] = {4};
+static const uint32 kRtxSsrcs1[] = {4};
static const uint32 kRtxSsrcs3[] = {4, 5, 6};
@@ -147,6 +149,90 @@ class WebRtcVideoEngineTestFake : public testing::Test,
channel_->SendFrame(&capturer, &frame);
return true;
}
+ void TestSetSendRtpHeaderExtensions(const std::string& ext) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = vie_.GetLastChannel();
+
+ // Verify extensions are off by default.
+ EXPECT_EQ(-1, vie_.GetSendRtpExtensionId(channel_num, ext));
+
+ // Enable extension.
+ const int id = 1;
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(ext, id));
+
+ // Verify the send extension id.
+ EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
+ EXPECT_EQ(id, vie_.GetSendRtpExtensionId(channel_num, ext));
+ // Verify call with same set of extensions returns true.
+ EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
+ EXPECT_EQ(id, vie_.GetSendRtpExtensionId(channel_num, ext));
+
+ // Add a new send stream and verify the extension is set.
+ // The first send stream to occupy the default channel.
+ EXPECT_TRUE(
+ channel_->AddSendStream(cricket::StreamParams::CreateLegacy(123)));
+ EXPECT_TRUE(
+ channel_->AddSendStream(cricket::StreamParams::CreateLegacy(234)));
+ int new_send_channel_num = vie_.GetLastChannel();
+ EXPECT_NE(channel_num, new_send_channel_num);
+ EXPECT_EQ(id, vie_.GetSendRtpExtensionId(new_send_channel_num, ext));
+
+ // Remove the extension id.
+ std::vector<cricket::RtpHeaderExtension> empty_extensions;
+ EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(empty_extensions));
+ EXPECT_EQ(-1, vie_.GetSendRtpExtensionId(channel_num, ext));
+ EXPECT_EQ(-1, vie_.GetSendRtpExtensionId(new_send_channel_num, ext));
+ }
+ void TestSetRecvRtpHeaderExtensions(const std::string& ext) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = vie_.GetLastChannel();
+
+ // Verify extensions are off by default.
+ EXPECT_EQ(-1, vie_.GetReceiveRtpExtensionId(channel_num, ext));
+
+ // Enable extension.
+ const int id = 2;
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(ext, id));
+
+ // Verify receive extension id.
+ EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+ EXPECT_EQ(id, vie_.GetReceiveRtpExtensionId(channel_num, ext));
+ // Verify call with same set of extensions returns true.
+ EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+ EXPECT_EQ(id, vie_.GetReceiveRtpExtensionId(channel_num, ext));
+
+ // Add a new receive stream and verify the extension is set.
+ // The first send stream to occupy the default channel.
+ EXPECT_TRUE(
+ channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(345)));
+ EXPECT_TRUE(
+ channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(456)));
+ int new_recv_channel_num = vie_.GetLastChannel();
+ EXPECT_NE(channel_num, new_recv_channel_num);
+ EXPECT_EQ(id, vie_.GetReceiveRtpExtensionId(new_recv_channel_num, ext));
+
+ // Remove the extension id.
+ std::vector<cricket::RtpHeaderExtension> empty_extensions;
+ EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(empty_extensions));
+ EXPECT_EQ(-1, vie_.GetReceiveRtpExtensionId(channel_num, ext));
+ EXPECT_EQ(-1, vie_.GetReceiveRtpExtensionId(new_recv_channel_num, ext));
+ }
+ void VerifyCodecFeedbackParams(const cricket::VideoCodec& codec) {
+ EXPECT_TRUE(codec.HasFeedbackParam(
+ cricket::FeedbackParam(cricket::kRtcpFbParamNack,
+ cricket::kParamValueEmpty)));
+ EXPECT_TRUE(codec.HasFeedbackParam(
+ cricket::FeedbackParam(cricket::kRtcpFbParamNack,
+ cricket::kRtcpFbNackParamPli)));
+ EXPECT_TRUE(codec.HasFeedbackParam(
+ cricket::FeedbackParam(cricket::kRtcpFbParamRemb,
+ cricket::kParamValueEmpty)));
+ EXPECT_TRUE(codec.HasFeedbackParam(
+ cricket::FeedbackParam(cricket::kRtcpFbParamCcm,
+ cricket::kRtcpFbCcmParamFir)));
+ }
void VerifyVP8SendCodec(int channel_num,
unsigned int width,
unsigned int height,
@@ -237,8 +323,10 @@ TEST_F(WebRtcVideoEngineTest, WebRtcShouldLog) {
EXPECT_EQ(talk_base::LS_INFO, talk_base::LogMessage::GetLogToStream(&stream));
webrtc::Trace::Add(webrtc::kTraceStateInfo, webrtc::kTraceUndefined, 0,
webrtc_log);
- EXPECT_TRUE_WAIT(std::string::npos != str.find(webrtc_log), 10);
+ talk_base::Thread::Current()->ProcessMessages(100);
talk_base::LogMessage::RemoveLogToStream(&stream);
+ // Access |str| after LogMessage is done with it to avoid data racing.
+ EXPECT_NE(std::string::npos, str.find(webrtc_log));
}
// Tests that webrtc logs are not logged when they should't be.
@@ -296,9 +384,28 @@ TEST_F(WebRtcVideoEngineTestFake, SetSendCodecs) {
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(vie_.GetHybridNackFecStatus(channel_num));
EXPECT_FALSE(vie_.GetNackStatus(channel_num));
+ EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
// TODO(juberti): Check RTCP, PLI, TMMBR.
}
+// Test that ViE Channel doesn't call SetSendCodec again if same codec is tried
+// to apply.
+TEST_F(WebRtcVideoEngineTestFake, DontResetSetSendCodec) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = vie_.GetLastChannel();
+ std::vector<cricket::VideoCodec> codecs(engine_.codecs());
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
+ EXPECT_TRUE(vie_.GetHybridNackFecStatus(channel_num));
+ EXPECT_FALSE(vie_.GetNackStatus(channel_num));
+ EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
+ // Try setting same code again.
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ // Since it's exact same codec which is already set, media channel shouldn't
+ // send the codec to ViE.
+ EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
+}
+
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithMinMaxBitrate) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
@@ -316,6 +423,40 @@ TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithMinMaxBitrate) {
EXPECT_EQ("20", codec.params[cricket::kCodecParamMaxBitrate]);
}
+TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithStartBitrate) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = vie_.GetLastChannel();
+ std::vector<cricket::VideoCodec> codecs(engine_.codecs());
+ codecs[0].params[cricket::kCodecParamStartBitrate] = "450";
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+
+ VerifyVP8SendCodec(
+ channel_num, kVP8Codec.width, kVP8Codec.height, 0, 2000, 50, 450);
+
+ cricket::VideoCodec codec;
+ EXPECT_TRUE(channel_->GetSendCodec(&codec));
+ EXPECT_EQ("450", codec.params[cricket::kCodecParamStartBitrate]);
+}
+
+TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithMinMaxStartBitrate) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = vie_.GetLastChannel();
+ std::vector<cricket::VideoCodec> codecs(engine_.codecs());
+ codecs[0].params[cricket::kCodecParamMinBitrate] = "10";
+ codecs[0].params[cricket::kCodecParamMaxBitrate] = "20";
+ codecs[0].params[cricket::kCodecParamStartBitrate] = "14";
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+
+ VerifyVP8SendCodec(
+ channel_num, kVP8Codec.width, kVP8Codec.height, 0, 20, 10, 14);
+
+ cricket::VideoCodec codec;
+ EXPECT_TRUE(channel_->GetSendCodec(&codec));
+ EXPECT_EQ("10", codec.params[cricket::kCodecParamMinBitrate]);
+ EXPECT_EQ("20", codec.params[cricket::kCodecParamMaxBitrate]);
+ EXPECT_EQ("14", codec.params[cricket::kCodecParamStartBitrate]);
+}
+
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithMinMaxBitrateInvalid) {
EXPECT_TRUE(SetupEngine());
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
@@ -415,7 +556,7 @@ TEST_F(WebRtcVideoEngineTestFake, MaxBitrateResetWithConferenceMode) {
EXPECT_TRUE(channel_->SetOptions(options));
VerifyVP8SendCodec(
channel_num, kVP8Codec.width, kVP8Codec.height, 0,
- kMaxBandwidthKbps, 10, 20);
+ kMaxBandwidthKbps, 10, kStartBandwidthKbps);
}
// Verify the current send bitrate is used as start bitrate when reconfiguring
@@ -576,6 +717,112 @@ TEST_F(WebRtcVideoEngineTestFake, SetRecvCodecs) {
EXPECT_TRUE(vie_.ReceiveCodecRegistered(channel_num, wcodec));
}
+// Test that we set our inbound RTX codecs properly.
+TEST_F(WebRtcVideoEngineTestFake, SetRecvCodecsWithRtx) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = vie_.GetLastChannel();
+
+ std::vector<cricket::VideoCodec> codecs;
+ cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
+ codecs.push_back(rtx_codec);
+ // Should fail since there's no associated payload type set.
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
+
+ codecs[0].SetParam("apt", 97);
+ // Should still fail since the we don't support RTX on this APT.
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
+
+ codecs[0].SetParam("apt", kVP8Codec.id);
+ // Should still fail since the associated payload type is unknown.
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
+
+ codecs.push_back(kVP8Codec);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+
+ webrtc::VideoCodec wcodec;
+ // Should not have been registered as a WebRTC codec.
+ EXPECT_TRUE(engine_.ConvertFromCricketVideoCodec(rtx_codec, &wcodec));
+ EXPECT_STREQ("rtx", wcodec.plName);
+ EXPECT_FALSE(vie_.ReceiveCodecRegistered(channel_num, wcodec));
+
+ // The RTX payload type should have been set.
+ EXPECT_EQ(rtx_codec.id, vie_.GetRtxRecvPayloadType(channel_num));
+}
+
+// Test that RTX packets are routed to the default video channel if
+// there's only one recv stream.
+TEST_F(WebRtcVideoEngineTestFake, TestReceiveRtxOneStream) {
+ EXPECT_TRUE(SetupEngine());
+
+ // Setup one channel with an associated RTX stream.
+ cricket::StreamParams params =
+ cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
+ params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
+ EXPECT_TRUE(channel_->AddRecvStream(params));
+ int channel_num = vie_.GetLastChannel();
+ EXPECT_EQ(static_cast<int>(kRtxSsrcs1[0]),
+ vie_.GetRemoteRtxSsrc(channel_num));
+
+ // Register codecs.
+ std::vector<cricket::VideoCodec> codec_list;
+ codec_list.push_back(kVP8Codec720p);
+ cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
+ rtx_codec.SetParam("apt", kVP8Codec.id);
+ codec_list.push_back(rtx_codec);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codec_list));
+
+ // Construct a fake RTX packet and verify that it is passed to the
+ // right WebRTC channel.
+ const size_t kDataLength = 12;
+ uint8_t data[kDataLength];
+ memset(data, 0, sizeof(data));
+ data[0] = 0x80;
+ data[1] = rtx_codec.id;
+ talk_base::SetBE32(&data[8], kRtxSsrcs1[0]);
+ talk_base::Buffer packet(data, kDataLength);
+ talk_base::PacketTime packet_time;
+ channel_->OnPacketReceived(&packet, packet_time);
+ EXPECT_EQ(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num));
+}
+
+// Test that RTX packets are routed to the correct video channel.
+TEST_F(WebRtcVideoEngineTestFake, TestReceiveRtxThreeStreams) {
+ EXPECT_TRUE(SetupEngine());
+
+ // Setup three channels with associated RTX streams.
+ int channel_num[ARRAY_SIZE(kSsrcs3)];
+ for (size_t i = 0; i < ARRAY_SIZE(kSsrcs3); ++i) {
+ cricket::StreamParams params =
+ cricket::StreamParams::CreateLegacy(kSsrcs3[i]);
+ params.AddFidSsrc(kSsrcs3[i], kRtxSsrcs3[i]);
+ EXPECT_TRUE(channel_->AddRecvStream(params));
+ channel_num[i] = vie_.GetLastChannel();
+ }
+
+ // Register codecs.
+ std::vector<cricket::VideoCodec> codec_list;
+ codec_list.push_back(kVP8Codec720p);
+ cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
+ rtx_codec.SetParam("apt", kVP8Codec.id);
+ codec_list.push_back(rtx_codec);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codec_list));
+
+ // Construct a fake RTX packet and verify that it is passed to the
+ // right WebRTC channel.
+ const size_t kDataLength = 12;
+ uint8_t data[kDataLength];
+ memset(data, 0, sizeof(data));
+ data[0] = 0x80;
+ data[1] = rtx_codec.id;
+ talk_base::SetBE32(&data[8], kRtxSsrcs3[1]);
+ talk_base::Buffer packet(data, kDataLength);
+ talk_base::PacketTime packet_time;
+ channel_->OnPacketReceived(&packet, packet_time);
+ EXPECT_NE(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num[0]));
+ EXPECT_EQ(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num[1]));
+ EXPECT_NE(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num[2]));
+}
+
// Test that channel connects and disconnects external capturer correctly.
TEST_F(WebRtcVideoEngineTestFake, HasExternalCapturer) {
EXPECT_TRUE(SetupEngine());
@@ -669,7 +916,7 @@ TEST_F(WebRtcVideoEngineTestFake, RecvStreamWithRtx) {
EXPECT_TRUE(channel_->AddRecvStream(
cricket::CreateSimWithRtxStreamParams("cname",
MAKE_VECTOR(kSsrcs1),
- MAKE_VECTOR(kRtxSsrc1))));
+ MAKE_VECTOR(kRtxSsrcs1))));
int new_channel_num = vie_.GetLastChannel();
EXPECT_NE(default_channel, new_channel_num);
EXPECT_EQ(4, vie_.GetRemoteRtxSsrc(new_channel_num));
@@ -694,105 +941,35 @@ TEST_F(WebRtcVideoEngineTestFake, RecvStreamNoRtx) {
}
// Test support for RTP timestamp offset header extension.
-TEST_F(WebRtcVideoEngineTestFake, RtpTimestampOffsetHeaderExtensions) {
- EXPECT_TRUE(SetupEngine());
- int channel_num = vie_.GetLastChannel();
- cricket::VideoOptions options;
- options.conference_mode.Set(true);
- EXPECT_TRUE(channel_->SetOptions(options));
-
- // Verify extensions are off by default.
- EXPECT_EQ(0, vie_.GetSendRtpTimestampOffsetExtensionId(channel_num));
- EXPECT_EQ(0, vie_.GetReceiveRtpTimestampOffsetExtensionId(channel_num));
-
- // Enable RTP timestamp extension.
- const int id = 14;
- std::vector<cricket::RtpHeaderExtension> extensions;
- extensions.push_back(cricket::RtpHeaderExtension(
- "urn:ietf:params:rtp-hdrext:toffset", id));
-
- // Verify the send extension id.
- EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
- EXPECT_EQ(id, vie_.GetSendRtpTimestampOffsetExtensionId(channel_num));
-
- // Remove the extension id.
- std::vector<cricket::RtpHeaderExtension> empty_extensions;
- EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(empty_extensions));
- EXPECT_EQ(0, vie_.GetSendRtpTimestampOffsetExtensionId(channel_num));
-
- // Verify receive extension id.
- EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
- EXPECT_EQ(id, vie_.GetReceiveRtpTimestampOffsetExtensionId(channel_num));
-
- // Add a new receive stream and verify the extension is set.
- EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
- int new_channel_num = vie_.GetLastChannel();
- EXPECT_NE(channel_num, new_channel_num);
- EXPECT_EQ(id, vie_.GetReceiveRtpTimestampOffsetExtensionId(new_channel_num));
-
- // Remove the extension id.
- EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(empty_extensions));
- EXPECT_EQ(0, vie_.GetReceiveRtpTimestampOffsetExtensionId(channel_num));
- EXPECT_EQ(0, vie_.GetReceiveRtpTimestampOffsetExtensionId(new_channel_num));
+TEST_F(WebRtcVideoEngineTestFake, SendRtpTimestampOffsetHeaderExtensions) {
+ TestSetSendRtpHeaderExtensions(kRtpTimestampOffsetHeaderExtension);
+}
+TEST_F(WebRtcVideoEngineTestFake, RecvRtpTimestampOffsetHeaderExtensions) {
+ TestSetRecvRtpHeaderExtensions(kRtpTimestampOffsetHeaderExtension);
}
// Test support for absolute send time header extension.
-TEST_F(WebRtcVideoEngineTestFake, AbsoluteSendTimeHeaderExtensions) {
- EXPECT_TRUE(SetupEngine());
- int channel_num = vie_.GetLastChannel();
- cricket::VideoOptions options;
- options.conference_mode.Set(true);
- EXPECT_TRUE(channel_->SetOptions(options));
-
- // Verify extensions are off by default.
- EXPECT_EQ(0, vie_.GetSendAbsoluteSendTimeExtensionId(channel_num));
- EXPECT_EQ(0, vie_.GetReceiveAbsoluteSendTimeExtensionId(channel_num));
-
- // Enable RTP timestamp extension.
- const int id = 12;
- std::vector<cricket::RtpHeaderExtension> extensions;
- extensions.push_back(cricket::RtpHeaderExtension(
- "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time", id));
-
- // Verify the send extension id.
- EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
- EXPECT_EQ(id, vie_.GetSendAbsoluteSendTimeExtensionId(channel_num));
-
- // Remove the extension id.
- std::vector<cricket::RtpHeaderExtension> empty_extensions;
- EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(empty_extensions));
- EXPECT_EQ(0, vie_.GetSendAbsoluteSendTimeExtensionId(channel_num));
-
- // Verify receive extension id.
- EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
- EXPECT_EQ(id, vie_.GetReceiveAbsoluteSendTimeExtensionId(channel_num));
-
- // Add a new receive stream and verify the extension is set.
- EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
- int new_channel_num = vie_.GetLastChannel();
- EXPECT_NE(channel_num, new_channel_num);
- EXPECT_EQ(id, vie_.GetReceiveAbsoluteSendTimeExtensionId(new_channel_num));
-
- // Remove the extension id.
- EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(empty_extensions));
- EXPECT_EQ(0, vie_.GetReceiveAbsoluteSendTimeExtensionId(channel_num));
- EXPECT_EQ(0, vie_.GetReceiveAbsoluteSendTimeExtensionId(new_channel_num));
+TEST_F(WebRtcVideoEngineTestFake, SendAbsoluteSendTimeHeaderExtensions) {
+ TestSetSendRtpHeaderExtensions(kRtpAbsoluteSenderTimeHeaderExtension);
+}
+TEST_F(WebRtcVideoEngineTestFake, RecvAbsoluteSendTimeHeaderExtensions) {
+ TestSetRecvRtpHeaderExtensions(kRtpAbsoluteSenderTimeHeaderExtension);
}
TEST_F(WebRtcVideoEngineTestFake, LeakyBucketTest) {
EXPECT_TRUE(SetupEngine());
- // Verify this is off by default.
+ // Verify this is on by default.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
int first_send_channel = vie_.GetLastChannel();
- EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+ EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
- // Enable the experiment and verify.
+ // Disable the experiment and verify.
cricket::VideoOptions options;
options.conference_mode.Set(true);
- options.video_leaky_bucket.Set(true);
+ options.video_leaky_bucket.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
- EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+ EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
// Add a receive channel and verify leaky bucket isn't enabled.
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
@@ -800,13 +977,41 @@ TEST_F(WebRtcVideoEngineTestFake, LeakyBucketTest) {
EXPECT_NE(first_send_channel, recv_channel_num);
EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(recv_channel_num));
- // Add a new send stream and verify leaky bucket is enabled from start.
+ // Add a new send stream and verify leaky bucket is disabled from start.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
int second_send_channel = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, second_send_channel);
+ EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(second_send_channel));
+
+ // Reenable leaky bucket.
+ options.video_leaky_bucket.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(second_send_channel));
}
+// Verify that SuspendBelowMinBitrate is enabled if it is set in the options.
+TEST_F(WebRtcVideoEngineTestFake, SuspendBelowMinBitrateTest) {
+ EXPECT_TRUE(SetupEngine());
+
+ // Verify this is off by default.
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
+ int first_send_channel = vie_.GetLastChannel();
+ EXPECT_FALSE(vie_.GetSuspendBelowMinBitrateStatus(first_send_channel));
+
+ // Enable the experiment and verify.
+ cricket::VideoOptions options;
+ options.suspend_below_min_bitrate.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ EXPECT_TRUE(vie_.GetSuspendBelowMinBitrateStatus(first_send_channel));
+
+ // Add a new send stream and verify suspend_below_min_bitrate is enabled.
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(2)));
+ int second_send_channel = vie_.GetLastChannel();
+ EXPECT_NE(first_send_channel, second_send_channel);
+ EXPECT_TRUE(vie_.GetSuspendBelowMinBitrateStatus(second_send_channel));
+}
+
TEST_F(WebRtcVideoEngineTestFake, BufferedModeLatency) {
EXPECT_TRUE(SetupEngine());
@@ -863,12 +1068,12 @@ TEST_F(WebRtcVideoEngineTestFake, AdditiveVideoOptions) {
EXPECT_TRUE(channel_->SetOptions(options1));
EXPECT_EQ(100, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(100, vie_.GetReceiverTargetDelay(first_send_channel));
- EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+ EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
cricket::VideoOptions options2;
- options2.video_leaky_bucket.Set(true);
+ options2.video_leaky_bucket.Set(false);
EXPECT_TRUE(channel_->SetOptions(options2));
- EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+ EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
// The buffered_mode_latency still takes effect.
EXPECT_EQ(100, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(100, vie_.GetReceiverTargetDelay(first_send_channel));
@@ -878,7 +1083,169 @@ TEST_F(WebRtcVideoEngineTestFake, AdditiveVideoOptions) {
EXPECT_EQ(50, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(50, vie_.GetReceiverTargetDelay(first_send_channel));
// The video_leaky_bucket still takes effect.
- EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+ EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+}
+
+TEST_F(WebRtcVideoEngineTestFake, SetCpuOveruseOptionsWithCaptureJitterMethod) {
+ EXPECT_TRUE(SetupEngine());
+
+ // Verify this is off by default.
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
+ int first_send_channel = vie_.GetLastChannel();
+ webrtc::CpuOveruseOptions cpu_option =
+ vie_.GetCpuOveruseOptions(first_send_channel);
+ EXPECT_EQ(0, cpu_option.low_capture_jitter_threshold_ms);
+ EXPECT_EQ(0, cpu_option.high_capture_jitter_threshold_ms);
+ EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
+ EXPECT_FALSE(cpu_option.enable_encode_usage_method);
+
+ // Set low and high threshold and verify that cpu options are set.
+ cricket::VideoOptions options;
+ options.conference_mode.Set(true);
+ options.cpu_underuse_threshold.Set(10);
+ options.cpu_overuse_threshold.Set(20);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ cpu_option = vie_.GetCpuOveruseOptions(first_send_channel);
+ EXPECT_EQ(10, cpu_option.low_capture_jitter_threshold_ms);
+ EXPECT_EQ(20, cpu_option.high_capture_jitter_threshold_ms);
+ EXPECT_TRUE(cpu_option.enable_capture_jitter_method);
+ EXPECT_FALSE(cpu_option.enable_encode_usage_method);
+
+ // Add a receive channel and verify that cpu options are not set.
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
+ int recv_channel_num = vie_.GetLastChannel();
+ EXPECT_NE(first_send_channel, recv_channel_num);
+ cpu_option = vie_.GetCpuOveruseOptions(recv_channel_num);
+ EXPECT_EQ(0, cpu_option.low_capture_jitter_threshold_ms);
+ EXPECT_EQ(0, cpu_option.high_capture_jitter_threshold_ms);
+ EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
+ EXPECT_FALSE(cpu_option.enable_encode_usage_method);
+
+ // Add a new send stream and verify that cpu options are set from start.
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
+ int second_send_channel = vie_.GetLastChannel();
+ EXPECT_NE(first_send_channel, second_send_channel);
+ cpu_option = vie_.GetCpuOveruseOptions(second_send_channel);
+ EXPECT_EQ(10, cpu_option.low_capture_jitter_threshold_ms);
+ EXPECT_EQ(20, cpu_option.high_capture_jitter_threshold_ms);
+ EXPECT_TRUE(cpu_option.enable_capture_jitter_method);
+ EXPECT_FALSE(cpu_option.enable_encode_usage_method);
+}
+
+TEST_F(WebRtcVideoEngineTestFake, SetInvalidCpuOveruseThresholds) {
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
+ int channel_num = vie_.GetLastChannel();
+
+ // Only low threshold set. Verify that cpu options are not set.
+ cricket::VideoOptions options;
+ options.conference_mode.Set(true);
+ options.cpu_underuse_threshold.Set(10);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ webrtc::CpuOveruseOptions cpu_option = vie_.GetCpuOveruseOptions(channel_num);
+ EXPECT_EQ(0, cpu_option.low_capture_jitter_threshold_ms);
+ EXPECT_EQ(0, cpu_option.high_capture_jitter_threshold_ms);
+ EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
+ EXPECT_FALSE(cpu_option.enable_encode_usage_method);
+
+ // Set high threshold to a negative value. Verify that options are not set.
+ options.cpu_overuse_threshold.Set(-1);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ cpu_option = vie_.GetCpuOveruseOptions(channel_num);
+ EXPECT_EQ(0, cpu_option.low_capture_jitter_threshold_ms);
+ EXPECT_EQ(0, cpu_option.high_capture_jitter_threshold_ms);
+ EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
+ EXPECT_FALSE(cpu_option.enable_encode_usage_method);
+
+ // Low and high threshold valid. Verify that cpu options are set.
+ options.cpu_overuse_threshold.Set(20);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ cpu_option = vie_.GetCpuOveruseOptions(channel_num);
+ EXPECT_EQ(10, cpu_option.low_capture_jitter_threshold_ms);
+ EXPECT_EQ(20, cpu_option.high_capture_jitter_threshold_ms);
+ EXPECT_TRUE(cpu_option.enable_capture_jitter_method);
+ EXPECT_FALSE(cpu_option.enable_encode_usage_method);
+}
+
+TEST_F(WebRtcVideoEngineTestFake, SetCpuOveruseOptionsWithEncodeUsageMethod) {
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
+ int first_send_channel = vie_.GetLastChannel();
+
+ // Set low and high threshold and enable encode usage method.
+ // Verify that cpu options are set.
+ cricket::VideoOptions options;
+ options.conference_mode.Set(true);
+ options.cpu_underuse_threshold.Set(10);
+ options.cpu_overuse_threshold.Set(20);
+ options.cpu_overuse_encode_usage.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ webrtc::CpuOveruseOptions cpu_option =
+ vie_.GetCpuOveruseOptions(first_send_channel);
+ EXPECT_EQ(10, cpu_option.low_encode_usage_threshold_percent);
+ EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
+ EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
+ EXPECT_TRUE(cpu_option.enable_encode_usage_method);
+#ifdef USE_WEBRTC_DEV_BRANCH
+ // Verify that optional encode rsd thresholds are not set.
+ EXPECT_EQ(-1, cpu_option.low_encode_time_rsd_threshold);
+ EXPECT_EQ(-1, cpu_option.high_encode_time_rsd_threshold);
+#endif
+
+ // Add a new send stream and verify that cpu options are set from start.
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
+ int second_send_channel = vie_.GetLastChannel();
+ EXPECT_NE(first_send_channel, second_send_channel);
+ cpu_option = vie_.GetCpuOveruseOptions(second_send_channel);
+ EXPECT_EQ(10, cpu_option.low_encode_usage_threshold_percent);
+ EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
+ EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
+ EXPECT_TRUE(cpu_option.enable_encode_usage_method);
+#ifdef USE_WEBRTC_DEV_BRANCH
+ // Verify that optional encode rsd thresholds are not set.
+ EXPECT_EQ(-1, cpu_option.low_encode_time_rsd_threshold);
+ EXPECT_EQ(-1, cpu_option.high_encode_time_rsd_threshold);
+#endif
+}
+
+TEST_F(WebRtcVideoEngineTestFake, SetCpuOveruseOptionsWithEncodeRsdThresholds) {
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
+ int first_send_channel = vie_.GetLastChannel();
+
+ // Set optional encode rsd thresholds and verify cpu options.
+ cricket::VideoOptions options;
+ options.conference_mode.Set(true);
+ options.cpu_underuse_threshold.Set(10);
+ options.cpu_overuse_threshold.Set(20);
+ options.cpu_underuse_encode_rsd_threshold.Set(30);
+ options.cpu_overuse_encode_rsd_threshold.Set(40);
+ options.cpu_overuse_encode_usage.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ webrtc::CpuOveruseOptions cpu_option =
+ vie_.GetCpuOveruseOptions(first_send_channel);
+ EXPECT_EQ(10, cpu_option.low_encode_usage_threshold_percent);
+ EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
+ EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
+ EXPECT_TRUE(cpu_option.enable_encode_usage_method);
+#ifdef USE_WEBRTC_DEV_BRANCH
+ EXPECT_EQ(30, cpu_option.low_encode_time_rsd_threshold);
+ EXPECT_EQ(40, cpu_option.high_encode_time_rsd_threshold);
+#endif
+
+ // Add a new send stream and verify that cpu options are set from start.
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
+ int second_send_channel = vie_.GetLastChannel();
+ EXPECT_NE(first_send_channel, second_send_channel);
+ cpu_option = vie_.GetCpuOveruseOptions(second_send_channel);
+ EXPECT_EQ(10, cpu_option.low_encode_usage_threshold_percent);
+ EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
+ EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
+ EXPECT_TRUE(cpu_option.enable_encode_usage_method);
+#ifdef USE_WEBRTC_DEV_BRANCH
+ EXPECT_EQ(30, cpu_option.low_encode_time_rsd_threshold);
+ EXPECT_EQ(40, cpu_option.high_encode_time_rsd_threshold);
+#endif
}
// Test that AddRecvStream doesn't create new channel for 1:1 call.
@@ -889,6 +1256,17 @@ TEST_F(WebRtcVideoEngineTestFake, AddRecvStream1On1) {
EXPECT_EQ(channel_num, vie_.GetLastChannel());
}
+// Test that NACK, PLI and REMB are enabled for internal codec.
+TEST_F(WebRtcVideoEngineTestFake, InternalCodecFeedbackParams) {
+ EXPECT_TRUE(SetupEngine());
+
+ std::vector<cricket::VideoCodec> codecs(engine_.codecs());
+ // Vp8 will appear at the beginning.
+ size_t pos = 0;
+ EXPECT_EQ("VP8", codecs[pos].name);
+ VerifyCodecFeedbackParams(codecs[pos]);
+}
+
// Test that AddRecvStream doesn't change remb for 1:1 call.
TEST_F(WebRtcVideoEngineTestFake, NoRembChangeAfterAddRecvStream) {
EXPECT_TRUE(SetupEngine());
@@ -1029,6 +1407,24 @@ TEST_F(WebRtcVideoEngineTestFake, AddRemoveRecvStreamConference) {
EXPECT_FALSE(vie_.IsChannel(receive_channel_num));
}
+// Test that adding/removing stream with 0 ssrc should fail (and not crash).
+// For crbug/351699 and 350988.
+TEST_F(WebRtcVideoEngineTestFake, AddRemoveRecvStreamWith0Ssrc) {
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
+ EXPECT_FALSE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(0)));
+ EXPECT_FALSE(channel_->RemoveRecvStream(0));
+ EXPECT_TRUE(channel_->RemoveRecvStream(1));
+}
+
+TEST_F(WebRtcVideoEngineTestFake, AddRemoveSendStreamWith0Ssrc) {
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
+ EXPECT_FALSE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(0)));
+ EXPECT_FALSE(channel_->RemoveSendStream(0));
+ EXPECT_TRUE(channel_->RemoveSendStream(1));
+}
+
// Test that we can create a channel and start/stop rendering out on it.
TEST_F(WebRtcVideoEngineTestFake, SetRender) {
EXPECT_TRUE(SetupEngine());
@@ -1049,6 +1445,8 @@ TEST_F(WebRtcVideoEngineTestFake, SetRender) {
TEST_F(WebRtcVideoEngineTestFake, SetSend) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
+ // Verify receiving is also started.
+ EXPECT_TRUE(vie_.GetReceive(channel_num));
// Set send codecs on the channel.
std::vector<cricket::VideoCodec> codecs;
@@ -1073,30 +1471,84 @@ TEST_F(WebRtcVideoEngineTestFake, SetBandwidthAuto) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
- EXPECT_TRUE(channel_->SetSendBandwidth(true, cricket::kAutoBandwidth));
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(cricket::kAutoBandwidth));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
}
// Test that we set bandwidth properly when using auto with upper bound.
-TEST_F(WebRtcVideoEngineTestFake, SetBandwidthAutoCapped) {
+TEST_F(WebRtcVideoEngineTestFake, SetBandwidthCapped) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
- EXPECT_TRUE(channel_->SetSendBandwidth(true, 768000));
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(768000));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0, 768U);
}
-// Test that we set bandwidth properly when using a fixed bandwidth.
-TEST_F(WebRtcVideoEngineTestFake, SetBandwidthFixed) {
+// Test that we reduce the start bandwidth when the requested max is less than
+// the default start bandwidth.
+TEST_F(WebRtcVideoEngineTestFake, SetMaxBandwidthBelowDefaultStart) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
- EXPECT_TRUE(channel_->SetSendBandwidth(false, 768000));
+ int max_bandwidth_kbps = (kMinBandwidthKbps + kStartBandwidthKbps) / 2;
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(max_bandwidth_kbps * 1000));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
- 768U, 768U, 768U);
+ max_bandwidth_kbps, kMinBandwidthKbps, max_bandwidth_kbps);
}
-// Test that SetSendBandwidth is ignored in conference mode.
+// Test that we reduce the min bandwidth when the requested max is less than
+// the min bandwidth.
+TEST_F(WebRtcVideoEngineTestFake, SetMaxBandwidthBelowMin) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = vie_.GetLastChannel();
+ EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
+ int max_bandwidth_kbps = kMinBandwidthKbps / 2;
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(max_bandwidth_kbps * 1000));
+ VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
+ max_bandwidth_kbps, max_bandwidth_kbps, max_bandwidth_kbps);
+}
+
+// Test that the start bandwidth can be controlled separately from the max
+// bandwidth.
+TEST_F(WebRtcVideoEngineTestFake, SetStartBandwidth) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = vie_.GetLastChannel();
+ EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
+ int start_bandwidth_kbps = kStartBandwidthKbps + 1;
+ EXPECT_TRUE(channel_->SetStartSendBandwidth(start_bandwidth_kbps * 1000));
+ VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
+ kMaxBandwidthKbps, kMinBandwidthKbps, start_bandwidth_kbps);
+
+ // Check that SetMaxSendBandwidth doesn't overwrite the start bandwidth.
+ int max_bandwidth_kbps = kMaxBandwidthKbps + 1;
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(max_bandwidth_kbps * 1000));
+ VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
+ max_bandwidth_kbps, kMinBandwidthKbps, start_bandwidth_kbps);
+}
+
+// Test that the start bandwidth can be controlled by experiment.
+TEST_F(WebRtcVideoEngineTestFake, SetStartBandwidthOption) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = vie_.GetLastChannel();
+ EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
+ int start_bandwidth_kbps = kStartBandwidthKbps;
+ EXPECT_TRUE(channel_->SetStartSendBandwidth(start_bandwidth_kbps * 1000));
+ VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
+ kMaxBandwidthKbps, kMinBandwidthKbps, start_bandwidth_kbps);
+
+ // Set the start bitrate option.
+ start_bandwidth_kbps = 1000;
+ cricket::VideoOptions options;
+ options.video_start_bitrate.Set(
+ start_bandwidth_kbps);
+ EXPECT_TRUE(channel_->SetOptions(options));
+
+ // Check that start bitrate has changed to the new value.
+ VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
+ kMaxBandwidthKbps, kMinBandwidthKbps, start_bandwidth_kbps);
+}
+
+// Test that SetMaxSendBandwidth works as expected in conference mode.
TEST_F(WebRtcVideoEngineTestFake, SetBandwidthInConference) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
@@ -1107,19 +1559,14 @@ TEST_F(WebRtcVideoEngineTestFake, SetBandwidthInConference) {
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
// Set send bandwidth.
- EXPECT_TRUE(channel_->SetSendBandwidth(false, 768000));
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(768000));
- // Verify bitrate not changed.
- webrtc::VideoCodec gcodec;
- EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
- EXPECT_EQ(kMinBandwidthKbps, gcodec.minBitrate);
- EXPECT_EQ(kStartBandwidthKbps, gcodec.startBitrate);
- EXPECT_EQ(kMaxBandwidthKbps, gcodec.maxBitrate);
- EXPECT_NE(768U, gcodec.minBitrate);
- EXPECT_NE(768U, gcodec.startBitrate);
- EXPECT_NE(768U, gcodec.maxBitrate);
+ // Verify that the max bitrate has changed.
+ VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
+ 768, kMinBandwidthKbps, kStartBandwidthKbps);
}
+
// Test that sending screencast frames doesn't change bitrate.
TEST_F(WebRtcVideoEngineTestFake, SetBandwidthScreencast) {
EXPECT_TRUE(SetupEngine());
@@ -1132,12 +1579,11 @@ TEST_F(WebRtcVideoEngineTestFake, SetBandwidthScreencast) {
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(123)));
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
- EXPECT_TRUE(channel_->SetSendBandwidth(false, 111000));
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(111000));
EXPECT_TRUE(channel_->SetSend(true));
SendI420ScreencastFrame(kVP8Codec.width, kVP8Codec.height);
- VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
- 111, 111, 111);
+ VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0, 111);
}
@@ -1239,12 +1685,20 @@ TEST_F(WebRtcVideoEngineTestFake, MultipleSendStreamsWithOneCapturer) {
ASSERT_NE(-1, channel1);
ASSERT_NE(channel0, channel1);
+ // Both channels should have started receiving after created.
+ EXPECT_TRUE(vie_.GetReceive(channel0));
+ EXPECT_TRUE(vie_.GetReceive(channel1));
+
// Set send codec.
std::vector<cricket::VideoCodec> codecs;
cricket::VideoCodec send_codec(100, "VP8", 640, 480, 30, 0);
codecs.push_back(send_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(channel_->SetSend(true));
+ EXPECT_TRUE(vie_.GetSend(channel0));
+ EXPECT_TRUE(vie_.GetSend(channel1));
+
EXPECT_TRUE(capturer.CaptureFrame());
EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel0));
EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel1));
@@ -1264,31 +1718,33 @@ TEST_F(WebRtcVideoEngineTestFake, MultipleSendStreamsWithOneCapturer) {
}
-// Disabled since its flaky: b/11288120
-TEST_F(WebRtcVideoEngineTestFake, DISABLED_SendReceiveBitratesStats) {
+TEST_F(WebRtcVideoEngineTestFake, SendReceiveBitratesStats) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(1)));
- int send_channel = vie_.GetLastChannel();
+ int first_send_channel = vie_.GetLastChannel();
+ EXPECT_TRUE(channel_->AddSendStream(
+ cricket::StreamParams::CreateLegacy(2)));
+ int second_send_channel = vie_.GetLastChannel();
cricket::VideoCodec codec(kVP8Codec720p);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->AddRecvStream(
- cricket::StreamParams::CreateLegacy(2)));
+ cricket::StreamParams::CreateLegacy(3)));
int first_receive_channel = vie_.GetLastChannel();
- EXPECT_NE(send_channel, first_receive_channel);
+ EXPECT_NE(first_send_channel, first_receive_channel);
EXPECT_TRUE(channel_->AddRecvStream(
- cricket::StreamParams::CreateLegacy(3)));
+ cricket::StreamParams::CreateLegacy(4)));
int second_receive_channel = vie_.GetLastChannel();
EXPECT_NE(first_receive_channel, second_receive_channel);
cricket::VideoMediaInfo info;
- EXPECT_TRUE(channel_->GetStats(&info));
+ EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.bw_estimations.size());
ASSERT_EQ(0, info.bw_estimations[0].actual_enc_bitrate);
ASSERT_EQ(0, info.bw_estimations[0].transmit_bitrate);
@@ -1298,49 +1754,48 @@ TEST_F(WebRtcVideoEngineTestFake, DISABLED_SendReceiveBitratesStats) {
ASSERT_EQ(0, info.bw_estimations[0].target_enc_bitrate);
// Start sending and receiving on one of the channels and verify bitrates.
- EXPECT_EQ(0, vie_.StartSend(send_channel));
+ EXPECT_EQ(0, vie_.StartSend(first_send_channel));
int send_video_bitrate = 800;
int send_fec_bitrate = 100;
int send_nack_bitrate = 20;
int send_total_bitrate = send_video_bitrate + send_fec_bitrate +
send_nack_bitrate;
- int send_bandwidth = 950;
- vie_.SetSendBitrates(send_channel, send_video_bitrate, send_fec_bitrate,
+ int send_bandwidth = 1900;
+ vie_.SetSendBitrates(first_send_channel, send_video_bitrate, send_fec_bitrate,
send_nack_bitrate);
- vie_.SetSendBandwidthEstimate(send_channel, send_bandwidth);
+ vie_.SetSendBandwidthEstimate(first_send_channel, send_bandwidth);
EXPECT_EQ(0, vie_.StartReceive(first_receive_channel));
- int first_channel_receive_bandwidth = 600;
- vie_.SetReceiveBandwidthEstimate(first_receive_channel,
- first_channel_receive_bandwidth);
+ int receive_bandwidth = 600;
+ vie_.SetReceiveBandwidthEstimate(first_receive_channel, receive_bandwidth);
info.Clear();
- EXPECT_TRUE(channel_->GetStats(&info));
+ EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.bw_estimations.size());
ASSERT_EQ(send_video_bitrate, info.bw_estimations[0].actual_enc_bitrate);
ASSERT_EQ(send_total_bitrate, info.bw_estimations[0].transmit_bitrate);
ASSERT_EQ(send_nack_bitrate, info.bw_estimations[0].retransmit_bitrate);
ASSERT_EQ(send_bandwidth, info.bw_estimations[0].available_send_bandwidth);
- ASSERT_EQ(first_channel_receive_bandwidth,
- info.bw_estimations[0].available_recv_bandwidth);
+ ASSERT_EQ(receive_bandwidth, info.bw_estimations[0].available_recv_bandwidth);
ASSERT_EQ(send_video_bitrate, info.bw_estimations[0].target_enc_bitrate);
// Start receiving on the second channel and verify received rate.
+ EXPECT_EQ(0, vie_.StartSend(second_send_channel));
+ vie_.SetSendBitrates(second_send_channel,
+ send_video_bitrate,
+ send_fec_bitrate,
+ send_nack_bitrate);
EXPECT_EQ(0, vie_.StartReceive(second_receive_channel));
- int second_channel_receive_bandwidth = 100;
- vie_.SetReceiveBandwidthEstimate(second_receive_channel,
- second_channel_receive_bandwidth);
info.Clear();
- EXPECT_TRUE(channel_->GetStats(&info));
+ EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.bw_estimations.size());
- ASSERT_EQ(send_video_bitrate, info.bw_estimations[0].actual_enc_bitrate);
- ASSERT_EQ(send_total_bitrate, info.bw_estimations[0].transmit_bitrate);
- ASSERT_EQ(send_nack_bitrate, info.bw_estimations[0].retransmit_bitrate);
+ ASSERT_EQ(2 * send_video_bitrate, info.bw_estimations[0].actual_enc_bitrate);
+ ASSERT_EQ(2 * send_total_bitrate, info.bw_estimations[0].transmit_bitrate);
+ ASSERT_EQ(2 * send_nack_bitrate, info.bw_estimations[0].retransmit_bitrate);
ASSERT_EQ(send_bandwidth, info.bw_estimations[0].available_send_bandwidth);
- ASSERT_EQ(first_channel_receive_bandwidth + second_channel_receive_bandwidth,
- info.bw_estimations[0].available_recv_bandwidth);
- ASSERT_EQ(send_video_bitrate, info.bw_estimations[0].target_enc_bitrate);
+ ASSERT_EQ(receive_bandwidth, info.bw_estimations[0].available_recv_bandwidth);
+ ASSERT_EQ(2 * send_video_bitrate, info.bw_estimations[0].target_enc_bitrate);
}
TEST_F(WebRtcVideoEngineTestFake, TestSetAdaptInputToCpuUsage) {
@@ -1395,309 +1850,6 @@ TEST_F(WebRtcVideoEngineTestFake, TestSetInvalidCpuThreshold) {
}
-/////////////////////////
-// Tests with real ViE //
-/////////////////////////
-
-// Tests that we can find codecs by name or id.
-TEST_F(WebRtcVideoEngineTest, FindCodec) {
- // We should not need to init engine in order to get codecs.
- const std::vector<cricket::VideoCodec>& c = engine_.codecs();
- EXPECT_EQ(4U, c.size());
-
- cricket::VideoCodec vp8(104, "VP8", 320, 200, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(vp8));
-
- cricket::VideoCodec vp8_ci(104, "vp8", 320, 200, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(vp8));
-
- cricket::VideoCodec vp8_diff_fr_diff_pref(104, "VP8", 320, 200, 50, 50);
- EXPECT_TRUE(engine_.FindCodec(vp8_diff_fr_diff_pref));
-
- cricket::VideoCodec vp8_diff_id(95, "VP8", 320, 200, 30, 0);
- EXPECT_FALSE(engine_.FindCodec(vp8_diff_id));
- vp8_diff_id.id = 97;
- EXPECT_TRUE(engine_.FindCodec(vp8_diff_id));
-
- cricket::VideoCodec vp8_diff_res(104, "VP8", 320, 111, 30, 0);
- EXPECT_FALSE(engine_.FindCodec(vp8_diff_res));
-
- // PeerConnection doesn't negotiate the resolution at this point.
- // Test that FindCodec can handle the case when width/height is 0.
- cricket::VideoCodec vp8_zero_res(104, "VP8", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(vp8_zero_res));
-
- cricket::VideoCodec red(101, "RED", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(red));
-
- cricket::VideoCodec red_ci(101, "red", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(red));
-
- cricket::VideoCodec fec(102, "ULPFEC", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(fec));
-
- cricket::VideoCodec fec_ci(102, "ulpfec", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(fec));
-
- cricket::VideoCodec rtx(96, "rtx", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(rtx));
-}
-
-TEST_F(WebRtcVideoEngineTest, RtxCodecHasAptSet) {
- std::vector<cricket::VideoCodec>::const_iterator it;
- bool apt_checked = false;
- for (it = engine_.codecs().begin(); it != engine_.codecs().end(); ++it) {
- if (_stricmp(cricket::kRtxCodecName, it->name.c_str()) && it->id != 96) {
- continue;
- }
- int apt;
- EXPECT_TRUE(it->GetParam("apt", &apt));
- EXPECT_EQ(100, apt);
- apt_checked = true;
- }
- EXPECT_TRUE(apt_checked);
-}
-
-TEST_F(WebRtcVideoEngineTest, StartupShutdown) {
- EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
- engine_.Terminate();
-}
-
-TEST_PRE_VIDEOENGINE_INIT(WebRtcVideoEngineTest, ConstrainNewCodec)
-TEST_POST_VIDEOENGINE_INIT(WebRtcVideoEngineTest, ConstrainNewCodec)
-
-TEST_PRE_VIDEOENGINE_INIT(WebRtcVideoEngineTest, ConstrainRunningCodec)
-TEST_POST_VIDEOENGINE_INIT(WebRtcVideoEngineTest, ConstrainRunningCodec)
-
-// TODO(juberti): Figure out why ViE is munging the COM refcount.
-#ifdef WIN32
-TEST_F(WebRtcVideoEngineTest, DISABLED_CheckCoInitialize) {
- Base::CheckCoInitialize();
-}
-#endif
-
-TEST_F(WebRtcVideoEngineTest, CreateChannel) {
- EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
- cricket::VideoMediaChannel* channel = engine_.CreateChannel(NULL);
- EXPECT_TRUE(channel != NULL);
- delete channel;
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, SetRecvCodecs) {
- std::vector<cricket::VideoCodec> codecs;
- codecs.push_back(kVP8Codec);
- EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
-}
-TEST_F(WebRtcVideoMediaChannelTest, SetRecvCodecsWrongPayloadType) {
- std::vector<cricket::VideoCodec> codecs;
- codecs.push_back(kVP8Codec);
- codecs[0].id = 99;
- EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
-}
-TEST_F(WebRtcVideoMediaChannelTest, SetRecvCodecsUnsupportedCodec) {
- std::vector<cricket::VideoCodec> codecs;
- codecs.push_back(kVP8Codec);
- codecs.push_back(cricket::VideoCodec(101, "VP1", 640, 400, 30, 0));
- EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, SetSend) {
- Base::SetSend();
-}
-TEST_F(WebRtcVideoMediaChannelTest, SetSendWithoutCodecs) {
- Base::SetSendWithoutCodecs();
-}
-TEST_F(WebRtcVideoMediaChannelTest, SetSendSetsTransportBufferSizes) {
- Base::SetSendSetsTransportBufferSizes();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, SendAndReceiveVp8Vga) {
- SendAndReceive(cricket::VideoCodec(100, "VP8", 640, 400, 30, 0));
-}
-TEST_F(WebRtcVideoMediaChannelTest, SendAndReceiveVp8Qvga) {
- SendAndReceive(cricket::VideoCodec(100, "VP8", 320, 200, 30, 0));
-}
-TEST_F(WebRtcVideoMediaChannelTest, SendAndReceiveH264SvcQqvga) {
- SendAndReceive(cricket::VideoCodec(100, "VP8", 160, 100, 30, 0));
-}
-TEST_F(WebRtcVideoMediaChannelTest, SendManyResizeOnce) {
- SendManyResizeOnce();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, SendVp8HdAndReceiveAdaptedVp8Vga) {
- EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL));
- channel_->UpdateAspectRatio(1280, 720);
- video_capturer_.reset(new cricket::FakeVideoCapturer);
- const std::vector<cricket::VideoFormat>* formats =
- video_capturer_->GetSupportedFormats();
- cricket::VideoFormat capture_format_hd = (*formats)[0];
- EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(capture_format_hd));
- EXPECT_TRUE(channel_->SetCapturer(kSsrc, video_capturer_.get()));
-
- // Capture format HD -> adapt (OnOutputFormatRequest VGA) -> VGA.
- cricket::VideoCodec codec(100, "VP8", 1280, 720, 30, 0);
- EXPECT_TRUE(SetOneCodec(codec));
- codec.width /= 2;
- codec.height /= 2;
- EXPECT_TRUE(channel_->SetSendStreamFormat(kSsrc, cricket::VideoFormat(
- codec.width, codec.height,
- cricket::VideoFormat::FpsToInterval(codec.framerate),
- cricket::FOURCC_ANY)));
- EXPECT_TRUE(SetSend(true));
- EXPECT_TRUE(channel_->SetRender(true));
- EXPECT_EQ(0, renderer_.num_rendered_frames());
- EXPECT_TRUE(SendFrame());
- EXPECT_FRAME_WAIT(1, codec.width, codec.height, kTimeout);
-}
-
-// TODO(juberti): Fix this test to tolerate missing stats.
-TEST_F(WebRtcVideoMediaChannelTest, DISABLED_GetStats) {
- Base::GetStats();
-}
-
-// TODO(juberti): Fix this test to tolerate missing stats.
-TEST_F(WebRtcVideoMediaChannelTest, DISABLED_GetStatsMultipleRecvStreams) {
- Base::GetStatsMultipleRecvStreams();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, GetStatsMultipleSendStreams) {
- Base::GetStatsMultipleSendStreams();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, SetSendBandwidth) {
- Base::SetSendBandwidth();
-}
-TEST_F(WebRtcVideoMediaChannelTest, SetSendSsrc) {
- Base::SetSendSsrc();
-}
-TEST_F(WebRtcVideoMediaChannelTest, SetSendSsrcAfterSetCodecs) {
- Base::SetSendSsrcAfterSetCodecs();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, SetRenderer) {
- Base::SetRenderer();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, AddRemoveRecvStreams) {
- Base::AddRemoveRecvStreams();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, AddRemoveRecvStreamAndRender) {
- Base::AddRemoveRecvStreamAndRender();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, AddRemoveRecvStreamsNoConference) {
- Base::AddRemoveRecvStreamsNoConference();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, AddRemoveSendStreams) {
- Base::AddRemoveSendStreams();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, SimulateConference) {
- Base::SimulateConference();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, AddRemoveCapturer) {
- Base::AddRemoveCapturer();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, RemoveCapturerWithoutAdd) {
- Base::RemoveCapturerWithoutAdd();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, AddRemoveCapturerMultipleSources) {
- Base::AddRemoveCapturerMultipleSources();
-}
-
-// This test verifies DSCP settings are properly applied on video media channel.
-TEST_F(WebRtcVideoMediaChannelTest, TestSetDscpOptions) {
- talk_base::scoped_ptr<cricket::FakeNetworkInterface> network_interface(
- new cricket::FakeNetworkInterface);
- channel_->SetInterface(network_interface.get());
- cricket::VideoOptions options;
- options.dscp.Set(true);
- EXPECT_TRUE(channel_->SetOptions(options));
- EXPECT_EQ(talk_base::DSCP_AF41, network_interface->dscp());
- options.dscp.Set(false);
- EXPECT_TRUE(channel_->SetOptions(options));
- EXPECT_EQ(talk_base::DSCP_DEFAULT, network_interface->dscp());
- channel_->SetInterface(NULL);
-}
-
-
-TEST_F(WebRtcVideoMediaChannelTest, SetOptionsSucceedsWhenSending) {
- cricket::VideoOptions options;
- options.conference_mode.Set(true);
- EXPECT_TRUE(channel_->SetOptions(options));
-
- // Verify SetOptions returns true on a different options.
- cricket::VideoOptions options2;
- options2.adapt_input_to_cpu_usage.Set(true);
- EXPECT_TRUE(channel_->SetOptions(options2));
-
- // Set send codecs on the channel and start sending.
- std::vector<cricket::VideoCodec> codecs;
- codecs.push_back(kVP8Codec);
- EXPECT_TRUE(channel_->SetSendCodecs(codecs));
- EXPECT_TRUE(channel_->SetSend(true));
-
- // Verify SetOptions returns true if channel is already sending.
- cricket::VideoOptions options3;
- options3.conference_mode.Set(true);
- EXPECT_TRUE(channel_->SetOptions(options3));
-}
-
-// Tests empty StreamParams is rejected.
-TEST_F(WebRtcVideoMediaChannelTest, RejectEmptyStreamParams) {
- Base::RejectEmptyStreamParams();
-}
-
-
-TEST_F(WebRtcVideoMediaChannelTest, AdaptResolution16x10) {
- Base::AdaptResolution16x10();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, AdaptResolution4x3) {
- Base::AdaptResolution4x3();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, MuteStream) {
- Base::MuteStream();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, MultipleSendStreams) {
- Base::MultipleSendStreams();
-}
-
-// TODO(juberti): Restore this test once we support sending 0 fps.
-TEST_F(WebRtcVideoMediaChannelTest, DISABLED_AdaptDropAllFrames) {
- Base::AdaptDropAllFrames();
-}
-// TODO(juberti): Understand why we get decode errors on this test.
-TEST_F(WebRtcVideoMediaChannelTest, DISABLED_AdaptFramerate) {
- Base::AdaptFramerate();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, SetSendStreamFormat0x0) {
- Base::SetSendStreamFormat0x0();
-}
-
-// TODO(zhurunz): Fix the flakey test.
-TEST_F(WebRtcVideoMediaChannelTest, DISABLED_SetSendStreamFormat) {
- Base::SetSendStreamFormat();
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, TwoStreamsSendAndReceive) {
- Base::TwoStreamsSendAndReceive(cricket::VideoCodec(100, "VP8", 640, 400, 30,
- 0));
-}
-
-TEST_F(WebRtcVideoMediaChannelTest, TwoStreamsReUseFirstStream) {
- Base::TwoStreamsReUseFirstStream(cricket::VideoCodec(100, "VP8", 640, 400, 30,
- 0));
-}
-
TEST_F(WebRtcVideoEngineTestFake, ResetCodecOnScreencast) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
@@ -1712,7 +1864,7 @@ TEST_F(WebRtcVideoEngineTestFake, ResetCodecOnScreencast) {
cricket::StreamParams::CreateLegacy(123)));
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->SetSend(true));
- EXPECT_EQ(1, vie_.num_set_send_codecs());
+ EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
webrtc::VideoCodec gcodec;
memset(&gcodec, 0, sizeof(gcodec));
@@ -1723,7 +1875,7 @@ TEST_F(WebRtcVideoEngineTestFake, ResetCodecOnScreencast) {
// Send a screencast frame with the same size.
// Verify that denoising is turned off.
SendI420ScreencastFrame(kVP8Codec.width, kVP8Codec.height);
- EXPECT_EQ(2, vie_.num_set_send_codecs());
+ EXPECT_EQ(2, vie_.GetNumSetSendCodecs());
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
EXPECT_FALSE(gcodec.codecSpecific.VP8.denoisingOn);
}
@@ -1834,11 +1986,9 @@ TEST_F(WebRtcVideoEngineTestFake, DontRegisterEncoderMultipleTimes) {
EXPECT_TRUE(vie_.ExternalEncoderRegistered(channel_num, 100));
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
- EXPECT_EQ(1, encoder_factory_.GetNumCreatedEncoders());
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
- EXPECT_EQ(1, encoder_factory_.GetNumCreatedEncoders());
// Remove stream previously added to free the external encoder instance.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
@@ -1898,8 +2048,8 @@ TEST_F(WebRtcVideoEngineTestFake, DontRegisterEncoderForNonVP8) {
EXPECT_EQ(0, vie_.GetNumExternalEncoderRegistered(channel_num));
}
-// Test that NACK and REMB are enabled for external codec.
-TEST_F(WebRtcVideoEngineTestFake, FeedbackParamsForNonVP8) {
+// Test that NACK, PLI and REMB are enabled for external codec.
+TEST_F(WebRtcVideoEngineTestFake, ExternalCodecFeedbackParams) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecGeneric,
"GENERIC");
engine_.SetExternalEncoderFactory(&encoder_factory_);
@@ -1910,15 +2060,7 @@ TEST_F(WebRtcVideoEngineTestFake, FeedbackParamsForNonVP8) {
// The external codec will appear at last.
size_t pos = codecs.size() - 1;
EXPECT_EQ("GENERIC", codecs[pos].name);
- EXPECT_TRUE(codecs[pos].HasFeedbackParam(
- cricket::FeedbackParam(cricket::kRtcpFbParamNack,
- cricket::kParamValueEmpty)));
- EXPECT_TRUE(codecs[pos].HasFeedbackParam(
- cricket::FeedbackParam(cricket::kRtcpFbParamRemb,
- cricket::kParamValueEmpty)));
- EXPECT_TRUE(codecs[pos].HasFeedbackParam(
- cricket::FeedbackParam(cricket::kRtcpFbParamCcm,
- cricket::kRtcpFbCcmParamFir)));
+ VerifyCodecFeedbackParams(codecs[pos]);
}
// Test external codec with be added to the end of the supported codec list.
@@ -1978,7 +2120,6 @@ TEST_F(WebRtcVideoEngineTestFake, UpdateEncoderCodecsAfterSetFactory) {
EXPECT_TRUE(vie_.ExternalEncoderRegistered(channel_num, 100));
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
- EXPECT_EQ(1, encoder_factory_.GetNumCreatedEncoders());
// Remove stream previously added to free the external encoder instance.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
@@ -2021,3 +2162,350 @@ TEST_F(WebRtcVideoEngineTestFake, CaptureFrameTimestampToNtpTimestamp) {
EXPECT_EQ(0, vie_.GetCaptureLastTimestamp(capture_id));
}
#endif
+
+/////////////////////////
+// Tests with real ViE //
+/////////////////////////
+
+// Tests that we can find codecs by name or id.
+TEST_F(WebRtcVideoEngineTest, FindCodec) {
+ // We should not need to init engine in order to get codecs.
+ const std::vector<cricket::VideoCodec>& c = engine_.codecs();
+ EXPECT_EQ(4U, c.size());
+
+ cricket::VideoCodec vp8(104, "VP8", 320, 200, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(vp8));
+
+ cricket::VideoCodec vp8_ci(104, "vp8", 320, 200, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(vp8));
+
+ cricket::VideoCodec vp8_diff_fr_diff_pref(104, "VP8", 320, 200, 50, 50);
+ EXPECT_TRUE(engine_.FindCodec(vp8_diff_fr_diff_pref));
+
+ cricket::VideoCodec vp8_diff_id(95, "VP8", 320, 200, 30, 0);
+ EXPECT_FALSE(engine_.FindCodec(vp8_diff_id));
+ vp8_diff_id.id = 97;
+ EXPECT_TRUE(engine_.FindCodec(vp8_diff_id));
+
+ cricket::VideoCodec vp8_diff_res(104, "VP8", 320, 111, 30, 0);
+ EXPECT_FALSE(engine_.FindCodec(vp8_diff_res));
+
+ // PeerConnection doesn't negotiate the resolution at this point.
+ // Test that FindCodec can handle the case when width/height is 0.
+ cricket::VideoCodec vp8_zero_res(104, "VP8", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(vp8_zero_res));
+
+ cricket::VideoCodec red(101, "RED", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(red));
+
+ cricket::VideoCodec red_ci(101, "red", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(red));
+
+ cricket::VideoCodec fec(102, "ULPFEC", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(fec));
+
+ cricket::VideoCodec fec_ci(102, "ulpfec", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(fec));
+
+ cricket::VideoCodec rtx(96, "rtx", 0, 0, 30, 0);
+ rtx.SetParam("apt", kVP8Codec.id);
+ EXPECT_TRUE(engine_.FindCodec(rtx));
+}
+
+TEST_F(WebRtcVideoEngineTest, RtxCodecHasAptSet) {
+ std::vector<cricket::VideoCodec>::const_iterator it;
+ bool apt_checked = false;
+ for (it = engine_.codecs().begin(); it != engine_.codecs().end(); ++it) {
+ if (_stricmp(cricket::kRtxCodecName, it->name.c_str()) && it->id != 96) {
+ continue;
+ }
+ int apt;
+ EXPECT_TRUE(it->GetParam("apt", &apt));
+ EXPECT_EQ(100, apt);
+ apt_checked = true;
+ }
+ EXPECT_TRUE(apt_checked);
+}
+
+TEST_F(WebRtcVideoEngineTest, StartupShutdown) {
+ EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
+ engine_.Terminate();
+}
+
+TEST_PRE_VIDEOENGINE_INIT(WebRtcVideoEngineTest, ConstrainNewCodec)
+TEST_POST_VIDEOENGINE_INIT(WebRtcVideoEngineTest, ConstrainNewCodec)
+
+TEST_PRE_VIDEOENGINE_INIT(WebRtcVideoEngineTest, ConstrainRunningCodec)
+TEST_POST_VIDEOENGINE_INIT(WebRtcVideoEngineTest, ConstrainRunningCodec)
+
+// TODO(juberti): Figure out why ViE is munging the COM refcount.
+#ifdef WIN32
+TEST_F(WebRtcVideoEngineTest, DISABLED_CheckCoInitialize) {
+ Base::CheckCoInitialize();
+}
+#endif
+
+TEST_F(WebRtcVideoEngineTest, CreateChannel) {
+ EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
+ cricket::VideoMediaChannel* channel = engine_.CreateChannel(NULL);
+ EXPECT_TRUE(channel != NULL);
+ delete channel;
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, SetRecvCodecs) {
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVP8Codec);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+}
+TEST_F(WebRtcVideoMediaChannelTest, SetRecvCodecsWrongPayloadType) {
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVP8Codec);
+ codecs[0].id = 99;
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+}
+TEST_F(WebRtcVideoMediaChannelTest, SetRecvCodecsUnsupportedCodec) {
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVP8Codec);
+ codecs.push_back(cricket::VideoCodec(101, "VP1", 640, 400, 30, 0));
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, GetRtpSendTimeExtension) {
+ // Enable RTP timestamp extension.
+ const int id = 12;
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ extensions.push_back(cricket::RtpHeaderExtension(
+ "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time", id));
+
+ // Verify the send extension id.
+ EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
+ EXPECT_EQ(id, channel_->GetRtpSendTimeExtnId());
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, SetSend) {
+ Base::SetSend();
+}
+TEST_F(WebRtcVideoMediaChannelTest, SetSendWithoutCodecs) {
+ Base::SetSendWithoutCodecs();
+}
+TEST_F(WebRtcVideoMediaChannelTest, SetSendSetsTransportBufferSizes) {
+ Base::SetSendSetsTransportBufferSizes();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, SendAndReceiveVp8Vga) {
+ SendAndReceive(cricket::VideoCodec(100, "VP8", 640, 400, 30, 0));
+}
+TEST_F(WebRtcVideoMediaChannelTest, SendAndReceiveVp8Qvga) {
+ SendAndReceive(cricket::VideoCodec(100, "VP8", 320, 200, 30, 0));
+}
+TEST_F(WebRtcVideoMediaChannelTest, SendAndReceiveH264SvcQqvga) {
+ SendAndReceive(cricket::VideoCodec(100, "VP8", 160, 100, 30, 0));
+}
+TEST_F(WebRtcVideoMediaChannelTest, SendManyResizeOnce) {
+ SendManyResizeOnce();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, DISABLED_SendVp8HdAndReceiveAdaptedVp8Vga) {
+ EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL));
+ channel_->UpdateAspectRatio(1280, 720);
+ video_capturer_.reset(new cricket::FakeVideoCapturer);
+ const std::vector<cricket::VideoFormat>* formats =
+ video_capturer_->GetSupportedFormats();
+ cricket::VideoFormat capture_format_hd = (*formats)[0];
+ EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(capture_format_hd));
+ EXPECT_TRUE(channel_->SetCapturer(kSsrc, video_capturer_.get()));
+
+ // Capture format HD -> adapt (OnOutputFormatRequest VGA) -> VGA.
+ cricket::VideoCodec codec(100, "VP8", 1280, 720, 30, 0);
+ EXPECT_TRUE(SetOneCodec(codec));
+ codec.width /= 2;
+ codec.height /= 2;
+ EXPECT_TRUE(SetSend(true));
+ EXPECT_TRUE(channel_->SetRender(true));
+ EXPECT_EQ(0, renderer_.num_rendered_frames());
+ EXPECT_TRUE(SendFrame());
+ EXPECT_FRAME_WAIT(1, codec.width, codec.height, kTimeout);
+}
+
+#ifdef USE_WEBRTC_DEV_BRANCH
+TEST_F(WebRtcVideoMediaChannelTest, GetStats) {
+#else
+TEST_F(WebRtcVideoMediaChannelTest, DISABLED_GetStats) {
+#endif
+ Base::GetStats();
+}
+
+#ifdef USE_WEBRTC_DEV_BRANCH
+TEST_F(WebRtcVideoMediaChannelTest, GetStatsMultipleRecvStreams) {
+#else
+TEST_F(WebRtcVideoMediaChannelTest, DISABLED_GetStatsMultipleRecvStreams) {
+#endif
+ Base::GetStatsMultipleRecvStreams();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, GetStatsMultipleSendStreams) {
+ Base::GetStatsMultipleSendStreams();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, SetSendBandwidth) {
+ Base::SetSendBandwidth();
+}
+TEST_F(WebRtcVideoMediaChannelTest, SetSendSsrc) {
+ Base::SetSendSsrc();
+}
+TEST_F(WebRtcVideoMediaChannelTest, SetSendSsrcAfterSetCodecs) {
+ Base::SetSendSsrcAfterSetCodecs();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, SetRenderer) {
+ Base::SetRenderer();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, AddRemoveRecvStreams) {
+ Base::AddRemoveRecvStreams();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, AddRemoveRecvStreamAndRender) {
+ Base::AddRemoveRecvStreamAndRender();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, AddRemoveRecvStreamsNoConference) {
+ Base::AddRemoveRecvStreamsNoConference();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, AddRemoveSendStreams) {
+ Base::AddRemoveSendStreams();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, SimulateConference) {
+ Base::SimulateConference();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, AddRemoveCapturer) {
+ Base::AddRemoveCapturer();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, RemoveCapturerWithoutAdd) {
+ Base::RemoveCapturerWithoutAdd();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, AddRemoveCapturerMultipleSources) {
+ Base::AddRemoveCapturerMultipleSources();
+}
+
+// This test verifies DSCP settings are properly applied on video media channel.
+TEST_F(WebRtcVideoMediaChannelTest, TestSetDscpOptions) {
+ talk_base::scoped_ptr<cricket::FakeNetworkInterface> network_interface(
+ new cricket::FakeNetworkInterface);
+ channel_->SetInterface(network_interface.get());
+ cricket::VideoOptions options;
+ options.dscp.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ EXPECT_EQ(talk_base::DSCP_AF41, network_interface->dscp());
+ // Verify previous value is not modified if dscp option is not set.
+ cricket::VideoOptions options1;
+ EXPECT_TRUE(channel_->SetOptions(options1));
+ EXPECT_EQ(talk_base::DSCP_AF41, network_interface->dscp());
+ options.dscp.Set(false);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ EXPECT_EQ(talk_base::DSCP_DEFAULT, network_interface->dscp());
+ channel_->SetInterface(NULL);
+}
+
+
+TEST_F(WebRtcVideoMediaChannelTest, SetOptionsSucceedsWhenSending) {
+ cricket::VideoOptions options;
+ options.conference_mode.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options));
+
+ // Verify SetOptions returns true on a different options.
+ cricket::VideoOptions options2;
+ options2.adapt_input_to_cpu_usage.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options2));
+
+ // Set send codecs on the channel and start sending.
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVP8Codec);
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(channel_->SetSend(true));
+
+ // Verify SetOptions returns true if channel is already sending.
+ cricket::VideoOptions options3;
+ options3.conference_mode.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options3));
+}
+
+// Tests empty StreamParams is rejected.
+TEST_F(WebRtcVideoMediaChannelTest, RejectEmptyStreamParams) {
+ Base::RejectEmptyStreamParams();
+}
+
+
+TEST_F(WebRtcVideoMediaChannelTest, AdaptResolution16x10) {
+ Base::AdaptResolution16x10();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, AdaptResolution4x3) {
+ Base::AdaptResolution4x3();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, MuteStream) {
+ Base::MuteStream();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, MultipleSendStreams) {
+ Base::MultipleSendStreams();
+}
+
+// TODO(juberti): Restore this test once we support sending 0 fps.
+TEST_F(WebRtcVideoMediaChannelTest, DISABLED_AdaptDropAllFrames) {
+ Base::AdaptDropAllFrames();
+}
+// TODO(juberti): Understand why we get decode errors on this test.
+TEST_F(WebRtcVideoMediaChannelTest, DISABLED_AdaptFramerate) {
+ Base::AdaptFramerate();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, SetSendStreamFormat0x0) {
+ Base::SetSendStreamFormat0x0();
+}
+
+// TODO(zhurunz): Fix the flakey test.
+TEST_F(WebRtcVideoMediaChannelTest, DISABLED_SetSendStreamFormat) {
+ Base::SetSendStreamFormat();
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, TwoStreamsSendAndReceive) {
+ Base::TwoStreamsSendAndReceive(cricket::VideoCodec(100, "VP8", 640, 400, 30,
+ 0));
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, TwoStreamsReUseFirstStream) {
+ Base::TwoStreamsReUseFirstStream(cricket::VideoCodec(100, "VP8", 640, 400, 30,
+ 0));
+}
+
+TEST_F(WebRtcVideoMediaChannelTest, DISABLED_TwoStreamsSendAndUnsignalledRecv) {
+ Base::TwoStreamsSendAndUnsignalledRecv(cricket::VideoCodec(100, "VP8", 640,
+ 400, 30, 0));
+}
+
+TEST_F(WebRtcVideoMediaChannelTest,
+ TwoStreamsSendAndFailUnsignalledRecv) {
+ webrtc::Trace::set_level_filter(webrtc::kTraceAll);
+ Base::TwoStreamsSendAndFailUnsignalledRecv(
+ cricket::VideoCodec(100, "VP8", 640, 400, 30, 0));
+}
+
+TEST_F(WebRtcVideoMediaChannelTest,
+ TwoStreamsSendAndFailUnsignalledRecvInOneToOne) {
+ Base::TwoStreamsSendAndFailUnsignalledRecvInOneToOne(
+ cricket::VideoCodec(100, "VP8", 640, 400, 30, 0));
+}
+
+TEST_F(WebRtcVideoMediaChannelTest,
+ TwoStreamsAddAndRemoveUnsignalledRecv) {
+ Base::TwoStreamsAddAndRemoveUnsignalledRecv(cricket::VideoCodec(100, "VP8",
+ 640, 400, 30,
+ 0));
+}
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.cc b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.cc
index 16aa4cdcebc..1cc6fe97122 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.cc
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.cc
@@ -36,12 +36,6 @@
namespace cricket {
-static const int kWatermarkWidth = 8;
-static const int kWatermarkHeight = 8;
-static const int kWatermarkOffsetFromLeft = 8;
-static const int kWatermarkOffsetFromBottom = 8;
-static const unsigned char kWatermarkMaxYValue = 64;
-
// Class that wraps ownerhip semantics of a buffer passed to it.
// * Buffers passed using Attach() become owned by this FrameBuffer and will be
// destroyed on FrameBuffer destruction.
@@ -296,29 +290,6 @@ void WebRtcVideoFrame::Attach(
rotation_ = rotation;
}
-// Add a square watermark near the left-low corner. clamp Y.
-// Returns false on error.
-bool WebRtcVideoFrame::AddWatermark() {
- size_t w = GetWidth();
- size_t h = GetHeight();
-
- if (w < kWatermarkWidth + kWatermarkOffsetFromLeft ||
- h < kWatermarkHeight + kWatermarkOffsetFromBottom) {
- return false;
- }
-
- uint8* buffer = GetYPlane();
- for (size_t x = kWatermarkOffsetFromLeft;
- x < kWatermarkOffsetFromLeft + kWatermarkWidth; ++x) {
- for (size_t y = h - kWatermarkOffsetFromBottom - kWatermarkHeight;
- y < h - kWatermarkOffsetFromBottom; ++y) {
- buffer[y * w + x] =
- talk_base::_min(buffer[y * w + x], kWatermarkMaxYValue);
- }
- }
- return true;
-}
-
webrtc::VideoFrame* WebRtcVideoFrame::frame() {
return video_buffer_->frame();
}
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.h b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.h
index 8191a58d875..4ba7ab65b57 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.h
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.h
@@ -67,7 +67,6 @@ class WebRtcVideoFrame : public VideoFrame {
size_t pixel_width, size_t pixel_height, int64 elapsed_time,
int64 time_stamp, int rotation);
- bool AddWatermark();
webrtc::VideoFrame* frame();
const webrtc::VideoFrame* frame() const;
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine.cc b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine.cc
index 51da9ac6b14..f1460a6cb8a 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine.cc
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine.cc
@@ -107,12 +107,6 @@ static const int kDefaultSoundclipDeviceId = -2;
static const int kDefaultAudioDeviceId = 0;
#endif
-// extension header for audio levels, as defined in
-// http://tools.ietf.org/html/draft-ietf-avtext-client-to-mixer-audio-level-03
-static const char kRtpAudioLevelHeaderExtension[] =
- "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
-static const int kRtpAudioLevelHeaderExtensionId = 1;
-
static const char kIsacCodecName[] = "ISAC";
static const char kL16CodecName[] = "L16";
// Codec parameters for Opus.
@@ -194,6 +188,18 @@ static bool IsCodecMultiRate(const webrtc::CodecInst& codec) {
return false;
}
+static bool IsTelephoneEventCodec(const std::string& name) {
+ return _stricmp(name.c_str(), "telephone-event") == 0;
+}
+
+static bool IsCNCodec(const std::string& name) {
+ return _stricmp(name.c_str(), "CN") == 0;
+}
+
+static bool IsRedCodec(const std::string& name) {
+ return _stricmp(name.c_str(), "red") == 0;
+}
+
static bool FindCodec(const std::vector<AudioCodec>& codecs,
const AudioCodec& codec,
AudioCodec* found_codec) {
@@ -229,8 +235,9 @@ static AudioOptions GetDefaultEngineOptions() {
options.adjust_agc_delta.Set(0);
options.experimental_agc.Set(false);
options.experimental_aec.Set(false);
+ options.experimental_ns.Set(false);
options.aec_dump.Set(false);
- options.experimental_acm.Set(false);
+ options.opus_fec.Set(false);
return options;
}
@@ -334,7 +341,6 @@ WebRtcVoiceEngine::WebRtcVoiceEngine()
log_filter_(SeverityToFilter(kDefaultLogSeverity)),
is_dumping_aec_(false),
desired_local_monitor_enable_(false),
- use_experimental_acm_(false),
tx_processor_ssrc_(0),
rx_processor_ssrc_(0) {
Construct();
@@ -352,7 +358,6 @@ WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper,
log_filter_(SeverityToFilter(kDefaultLogSeverity)),
is_dumping_aec_(false),
desired_local_monitor_enable_(false),
- use_experimental_acm_(false),
tx_processor_ssrc_(0),
rx_processor_ssrc_(0) {
Construct();
@@ -378,12 +383,11 @@ void WebRtcVoiceEngine::Construct() {
// Load our RTP Header extensions.
rtp_header_extensions_.push_back(
RtpHeaderExtension(kRtpAudioLevelHeaderExtension,
- kRtpAudioLevelHeaderExtensionId));
+ kRtpAudioLevelHeaderExtensionDefaultId));
+ rtp_header_extensions_.push_back(
+ RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension,
+ kRtpAbsoluteSenderTimeHeaderExtensionDefaultId));
options_ = GetDefaultEngineOptions();
-
- // Initialize the VoE Configuration to the default ACM.
- voe_config_.Set<webrtc::AudioCodingModuleFactory>(
- new webrtc::AudioCodingModuleFactory);
}
static bool IsOpus(const AudioCodec& codec) {
@@ -396,12 +400,8 @@ static bool IsIsac(const AudioCodec& codec) {
// True if params["stereo"] == "1"
static bool IsOpusStereoEnabled(const AudioCodec& codec) {
- CodecParameterMap::const_iterator param =
- codec.params.find(kCodecParamStereo);
- if (param == codec.params.end()) {
- return false;
- }
- return param->second == kParamValueTrue;
+ int value;
+ return codec.GetParam(kCodecParamStereo, &value) && value == 1;
}
static bool IsValidOpusBitrate(int bitrate) {
@@ -423,6 +423,22 @@ static int GetOpusBitrateFromParams(const AudioCodec& codec) {
return bitrate;
}
+// Return true params[kCodecParamUseInbandFec] == kParamValueTrue, false
+// otherwise.
+static bool IsOpusFecEnabled(const AudioCodec& codec) {
+ int value;
+ return codec.GetParam(kCodecParamUseInbandFec, &value) && value == 1;
+}
+
+// Set params[kCodecParamUseInbandFec]. Caller should make sure codec is Opus.
+static void SetOpusFec(AudioCodec *codec, bool opus_fec) {
+ if (opus_fec) {
+ codec->params[kCodecParamUseInbandFec] = kParamValueTrue;
+ } else {
+ codec->params.erase(kCodecParamUseInbandFec);
+ }
+}
+
void WebRtcVoiceEngine::ConstructCodecs() {
LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
@@ -467,6 +483,7 @@ void WebRtcVoiceEngine::ConstructCodecs() {
}
// TODO(hellner): Add ptime, sprop-stereo, stereo and useinbandfec
// when they can be set to values other than the default.
+ SetOpusFec(&codec, false);
}
codecs_.push_back(codec);
} else {
@@ -717,16 +734,11 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
options.typing_detection.Set(false);
options.experimental_agc.Set(false);
options.experimental_aec.Set(false);
+ options.experimental_ns.Set(false);
#endif
LOG(LS_INFO) << "Applying audio options: " << options.ToString();
- // Configure whether ACM1 or ACM2 is used.
- bool enable_acm2 = false;
- if (options.experimental_acm.Get(&enable_acm2)) {
- EnableExperimentalAcm(enable_acm2);
- }
-
webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing();
bool echo_cancellation;
@@ -804,8 +816,26 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
}
}
+ bool experimental_ns;
+ if (options.experimental_ns.Get(&experimental_ns)) {
+ webrtc::AudioProcessing* audioproc =
+ voe_wrapper_->base()->audio_processing();
+ // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
+ // returns NULL on audio_processing().
+ if (audioproc) {
+ if (audioproc->EnableExperimentalNs(experimental_ns) == -1) {
+ LOG_RTCERR1(EnableExperimentalNs, experimental_ns);
+ return false;
+ }
+ } else {
+ LOG(LS_VERBOSE) << "Experimental noise suppression set to "
+ << experimental_ns;
+ }
+ }
+
bool highpass_filter;
if (options.highpass_filter.Get(&highpass_filter)) {
+ LOG(LS_INFO) << "High pass filter enabled? " << highpass_filter;
if (voep->EnableHighPassFilter(highpass_filter) == -1) {
LOG_RTCERR1(SetHighpassFilterStatus, highpass_filter);
return false;
@@ -814,6 +844,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
bool stereo_swapping;
if (options.stereo_swapping.Get(&stereo_swapping)) {
+ LOG(LS_INFO) << "Stereo swapping enabled? " << stereo_swapping;
voep->EnableStereoChannelSwapping(stereo_swapping);
if (voep->IsStereoChannelSwappingEnabled() != stereo_swapping) {
LOG_RTCERR1(EnableStereoChannelSwapping, stereo_swapping);
@@ -823,6 +854,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
bool typing_detection;
if (options.typing_detection.Get(&typing_detection)) {
+ LOG(LS_INFO) << "Typing detection is enabled? " << typing_detection;
if (voep->SetTypingDetectionStatus(typing_detection) == -1) {
// In case of error, log the info and continue
LOG_RTCERR1(SetTypingDetectionStatus, typing_detection);
@@ -831,6 +863,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
int adjust_agc_delta;
if (options.adjust_agc_delta.Get(&adjust_agc_delta)) {
+ LOG(LS_INFO) << "Adjust agc delta is " << adjust_agc_delta;
if (!AdjustAgcLevel(adjust_agc_delta)) {
return false;
}
@@ -838,6 +871,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
bool aec_dump;
if (options.aec_dump.Get(&aec_dump)) {
+ LOG(LS_INFO) << "Aec dump is enabled? " << aec_dump;
if (aec_dump)
StartAecDump(kAecDumpByAudioOptionFilename);
else
@@ -846,6 +880,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
bool experimental_aec;
if (options.experimental_aec.Get(&experimental_aec)) {
+ LOG(LS_INFO) << "Experimental aec is " << experimental_aec;
webrtc::AudioProcessing* audioproc =
voe_wrapper_->base()->audio_processing();
// We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
@@ -860,6 +895,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
uint32 recording_sample_rate;
if (options.recording_sample_rate.Get(&recording_sample_rate)) {
+ LOG(LS_INFO) << "Recording sample rate is " << recording_sample_rate;
if (voe_wrapper_->hw()->SetRecordingSampleRate(recording_sample_rate)) {
LOG_RTCERR1(SetRecordingSampleRate, recording_sample_rate);
}
@@ -867,11 +903,21 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
uint32 playout_sample_rate;
if (options.playout_sample_rate.Get(&playout_sample_rate)) {
+ LOG(LS_INFO) << "Playout sample rate is " << playout_sample_rate;
if (voe_wrapper_->hw()->SetPlayoutSampleRate(playout_sample_rate)) {
LOG_RTCERR1(SetPlayoutSampleRate, playout_sample_rate);
}
}
+ bool opus_fec = false;
+ if (options.opus_fec.Get(&opus_fec)) {
+ LOG(LS_INFO) << "Opus FEC is enabled? " << opus_fec;
+ for (std::vector<AudioCodec>::iterator it = codecs_.begin();
+ it != codecs_.end(); ++it) {
+ if (IsOpus(*it))
+ SetOpusFec(&(*it), opus_fec);
+ }
+ }
return true;
}
@@ -1261,21 +1307,6 @@ bool WebRtcVoiceEngine::ShouldIgnoreTrace(const std::string& trace) {
return false;
}
-void WebRtcVoiceEngine::EnableExperimentalAcm(bool enable) {
- if (enable == use_experimental_acm_)
- return;
- if (enable) {
- LOG(LS_INFO) << "VoiceEngine is set to use new ACM (ACM2 + NetEq4).";
- voe_config_.Set<webrtc::AudioCodingModuleFactory>(
- new webrtc::NewAudioCodingModuleFactory());
- } else {
- LOG(LS_INFO) << "VoiceEngine is set to use legacy ACM (ACM1 + Neteq3).";
- voe_config_.Set<webrtc::AudioCodingModuleFactory>(
- new webrtc::AudioCodingModuleFactory());
- }
- use_experimental_acm_ = enable;
-}
-
void WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace,
int length) {
talk_base::LoggingSeverity sev = talk_base::LS_VERBOSE;
@@ -1433,6 +1464,25 @@ bool WebRtcVoiceEngine::SetAudioDeviceModule(webrtc::AudioDeviceModule* adm,
return true;
}
+bool WebRtcVoiceEngine::StartAecDump(talk_base::PlatformFile file) {
+ FILE* aec_dump_file_stream = talk_base::FdopenPlatformFileForWriting(file);
+ if (!aec_dump_file_stream) {
+ LOG(LS_ERROR) << "Could not open AEC dump file stream.";
+ if (!talk_base::ClosePlatformFile(file))
+ LOG(LS_WARNING) << "Could not close file.";
+ return false;
+ }
+ StopAecDump();
+ if (voe_wrapper_->processing()->StartDebugRecording(aec_dump_file_stream) !=
+ webrtc::AudioProcessing::kNoError) {
+ LOG_RTCERR0(StartDebugRecording);
+ fclose(aec_dump_file_stream);
+ return false;
+ }
+ is_dumping_aec_ = true;
+ return true;
+}
+
bool WebRtcVoiceEngine::RegisterProcessor(
uint32 ssrc,
VoiceProcessor* voice_processor,
@@ -1590,7 +1640,7 @@ void WebRtcVoiceEngine::StartAecDump(const std::string& filename) {
// Start dumping AEC when we are not dumping.
if (voe_wrapper_->processing()->StartDebugRecording(
filename.c_str()) != webrtc::AudioProcessing::kNoError) {
- LOG_RTCERR0(StartDebugRecording);
+ LOG_RTCERR1(StartDebugRecording, filename.c_str());
} else {
is_dumping_aec_ = true;
}
@@ -1620,17 +1670,89 @@ int WebRtcVoiceEngine::CreateSoundclipVoiceChannel() {
return CreateVoiceChannel(voe_wrapper_sc_.get());
}
-// This struct relies on the generated copy constructor and assignment operator
-// since it is used in an stl::map.
-struct WebRtcVoiceMediaChannel::WebRtcVoiceChannelInfo {
- WebRtcVoiceChannelInfo() : channel(-1), renderer(NULL) {}
- WebRtcVoiceChannelInfo(int ch, AudioRenderer* r)
- : channel(ch),
- renderer(r) {}
- ~WebRtcVoiceChannelInfo() {}
+class WebRtcVoiceMediaChannel::WebRtcVoiceChannelRenderer
+ : public AudioRenderer::Sink {
+ public:
+ WebRtcVoiceChannelRenderer(int ch,
+ webrtc::AudioTransport* voe_audio_transport)
+ : channel_(ch),
+ voe_audio_transport_(voe_audio_transport),
+ renderer_(NULL) {
+ }
+ virtual ~WebRtcVoiceChannelRenderer() {
+ Stop();
+ }
+
+ // Starts the rendering by setting a sink to the renderer to get data
+ // callback.
+ // This method is called on the libjingle worker thread.
+ // TODO(xians): Make sure Start() is called only once.
+ void Start(AudioRenderer* renderer) {
+ talk_base::CritScope lock(&lock_);
+ ASSERT(renderer != NULL);
+ if (renderer_ != NULL) {
+ ASSERT(renderer_ == renderer);
+ return;
+ }
+
+ // TODO(xians): Remove AddChannel() call after Chrome turns on APM
+ // in getUserMedia by default.
+ renderer->AddChannel(channel_);
+ renderer->SetSink(this);
+ renderer_ = renderer;
+ }
+
+ // Stops rendering by setting the sink of the renderer to NULL. No data
+ // callback will be received after this method.
+ // This method is called on the libjingle worker thread.
+ void Stop() {
+ talk_base::CritScope lock(&lock_);
+ if (renderer_ == NULL)
+ return;
+
+ renderer_->RemoveChannel(channel_);
+ renderer_->SetSink(NULL);
+ renderer_ = NULL;
+ }
+
+ // AudioRenderer::Sink implementation.
+ // This method is called on the audio thread.
+ virtual void OnData(const void* audio_data,
+ int bits_per_sample,
+ int sample_rate,
+ int number_of_channels,
+ int number_of_frames) OVERRIDE {
+ voe_audio_transport_->OnData(channel_,
+ audio_data,
+ bits_per_sample,
+ sample_rate,
+ number_of_channels,
+ number_of_frames);
+ }
+
+ // Callback from the |renderer_| when it is going away. In case Start() has
+ // never been called, this callback won't be triggered.
+ virtual void OnClose() OVERRIDE {
+ talk_base::CritScope lock(&lock_);
+ // Set |renderer_| to NULL to make sure no more callback will get into
+ // the renderer.
+ renderer_ = NULL;
+ }
+
+ // Accessor to the VoE channel ID.
+ int channel() const { return channel_; }
+
+ private:
+ const int channel_;
+ webrtc::AudioTransport* const voe_audio_transport_;
+
+ // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler.
+ // PeerConnection will make sure invalidating the pointer before the object
+ // goes away.
+ AudioRenderer* renderer_;
- int channel;
- AudioRenderer* renderer;
+ // Protects |renderer_| in Start(), Stop() and OnClose().
+ talk_base::CriticalSection lock_;
};
// WebRtcVoiceMediaChannel
@@ -1639,7 +1761,6 @@ WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine *engine)
engine,
engine->CreateMediaVoiceChannel()),
send_bw_setting_(false),
- send_autobw_(false),
send_bw_bps_(0),
options_(),
dtmf_allowed_(false),
@@ -1753,7 +1874,7 @@ bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
}
if (dscp_option_changed) {
talk_base::DiffServCodePoint dscp = talk_base::DSCP_DEFAULT;
- if (options.dscp.GetWithDefaultIfUnset(false))
+ if (options_.dscp.GetWithDefaultIfUnset(false))
dscp = kAudioDscpValue;
if (MediaChannel::SetDscp(dscp) != 0) {
LOG(LS_WARNING) << "Failed to set DSCP settings for audio channel";
@@ -1823,8 +1944,8 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs(
for (ChannelMap::iterator it = receive_channels_.begin();
it != receive_channels_.end() && ret; ++it) {
if (engine()->voe()->codec()->SetRecPayloadType(
- it->second.channel, voe_codec) == -1) {
- LOG_RTCERR2(SetRecPayloadType, it->second.channel,
+ it->second->channel(), voe_codec) == -1) {
+ LOG_RTCERR2(SetRecPayloadType, it->second->channel(),
ToString(voe_codec));
ret = false;
}
@@ -1846,24 +1967,38 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs(
bool WebRtcVoiceMediaChannel::SetSendCodecs(
int channel, const std::vector<AudioCodec>& codecs) {
- // Disable VAD, and FEC unless we know the other side wants them.
+ // Disable VAD, FEC, and RED unless we know the other side wants them.
engine()->voe()->codec()->SetVADStatus(channel, false);
engine()->voe()->rtp()->SetNACKStatus(channel, false, 0);
+#ifdef USE_WEBRTC_DEV_BRANCH
+ engine()->voe()->rtp()->SetREDStatus(channel, false);
+ engine()->voe()->codec()->SetFECStatus(channel, false);
+#else
+ // TODO(minyue): Remove code under #else case after new WebRTC roll.
engine()->voe()->rtp()->SetFECStatus(channel, false);
+#endif // USE_WEBRTC_DEV_BRANCH
// Scan through the list to figure out the codec to use for sending, along
// with the proper configuration for VAD and DTMF.
- bool first = true;
+ bool found_send_codec = false;
webrtc::CodecInst send_codec;
memset(&send_codec, 0, sizeof(send_codec));
+ bool nack_enabled = nack_enabled_;
+
+ // Set send codec (the first non-telephone-event/CN codec)
for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
it != codecs.end(); ++it) {
// Ignore codecs we don't know about. The negotiation step should prevent
// this, but double-check to be sure.
webrtc::CodecInst voe_codec;
if (!engine()->FindWebRtcCodec(*it, &voe_codec)) {
- LOG(LS_WARNING) << "Unknown codec " << ToString(voe_codec);
+ LOG(LS_WARNING) << "Unknown codec " << ToString(*it);
+ continue;
+ }
+
+ if (IsTelephoneEventCodec(it->name) || IsCNCodec(it->name)) {
+ // Skip telephone-event/CN codec, which will be handled later.
continue;
}
@@ -1900,23 +2035,99 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
if (bitrate_from_params != 0) {
voe_codec.rate = bitrate_from_params;
}
+
+ // For Opus, we also enable inband FEC if it is requested.
+ if (IsOpusFecEnabled(*it)) {
+ LOG(LS_INFO) << "Enabling Opus FEC on channel " << channel;
+#ifdef USE_WEBRTC_DEV_BRANCH
+ if (engine()->voe()->codec()->SetFECStatus(channel, true) == -1) {
+ // Enable in-band FEC of the Opus codec. Treat any failure as a fatal
+ // internal error.
+ LOG_RTCERR2(SetFECStatus, channel, true);
+ return false;
+ }
+#endif // USE_WEBRTC_DEV_BRANCH
+ }
+ }
+
+ // We'll use the first codec in the list to actually send audio data.
+ // Be sure to use the payload type requested by the remote side.
+ // "red", for RED audio, is a special case where the actual codec to be
+ // used is specified in params.
+ if (IsRedCodec(it->name)) {
+ // Parse out the RED parameters. If we fail, just ignore RED;
+ // we don't support all possible params/usage scenarios.
+ if (!GetRedSendCodec(*it, codecs, &send_codec)) {
+ continue;
+ }
+
+ // Enable redundant encoding of the specified codec. Treat any
+ // failure as a fatal internal error.
+#ifdef USE_WEBRTC_DEV_BRANCH
+ LOG(LS_INFO) << "Enabling RED on channel " << channel;
+ if (engine()->voe()->rtp()->SetREDStatus(channel, true, it->id) == -1) {
+ LOG_RTCERR3(SetREDStatus, channel, true, it->id);
+#else
+ // TODO(minyue): Remove code under #else case after new WebRTC roll.
+ LOG(LS_INFO) << "Enabling FEC";
+ if (engine()->voe()->rtp()->SetFECStatus(channel, true, it->id) == -1) {
+ LOG_RTCERR3(SetFECStatus, channel, true, it->id);
+#endif // USE_WEBRTC_DEV_BRANCH
+ return false;
+ }
+ } else {
+ send_codec = voe_codec;
+ nack_enabled = IsNackEnabled(*it);
+ }
+ found_send_codec = true;
+ break;
+ }
+
+ if (nack_enabled_ != nack_enabled) {
+ SetNack(channel, nack_enabled);
+ nack_enabled_ = nack_enabled;
+ }
+
+ if (!found_send_codec) {
+ LOG(LS_WARNING) << "Received empty list of codecs.";
+ return false;
+ }
+
+ // Set the codec immediately, since SetVADStatus() depends on whether
+ // the current codec is mono or stereo.
+ if (!SetSendCodec(channel, send_codec))
+ return false;
+
+ // Always update the |send_codec_| to the currently set send codec.
+ send_codec_.reset(new webrtc::CodecInst(send_codec));
+
+ if (send_bw_setting_) {
+ SetSendBandwidthInternal(send_bw_bps_);
+ }
+
+ // Loop through the codecs list again to config the telephone-event/CN codec.
+ for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
+ it != codecs.end(); ++it) {
+ // Ignore codecs we don't know about. The negotiation step should prevent
+ // this, but double-check to be sure.
+ webrtc::CodecInst voe_codec;
+ if (!engine()->FindWebRtcCodec(*it, &voe_codec)) {
+ LOG(LS_WARNING) << "Unknown codec " << ToString(*it);
+ continue;
}
// Find the DTMF telephone event "codec" and tell VoiceEngine channels
// about it.
- if (_stricmp(it->name.c_str(), "telephone-event") == 0 ||
- _stricmp(it->name.c_str(), "audio/telephone-event") == 0) {
+ if (IsTelephoneEventCodec(it->name)) {
if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType(
channel, it->id) == -1) {
LOG_RTCERR2(SetSendTelephoneEventPayloadType, channel, it->id);
return false;
}
- }
-
- // Turn voice activity detection/comfort noise on if supported.
- // Set the wideband CN payload type appropriately.
- // (narrowband always uses the static payload type 13).
- if (_stricmp(it->name.c_str(), "CN") == 0) {
+ } else if (IsCNCodec(it->name)) {
+ // Turn voice activity detection/comfort noise on if supported.
+ // Set the wideband CN payload type appropriately.
+ // (narrowband always uses the static payload type 13).
webrtc::PayloadFrequencies cn_freq;
switch (it->clockrate) {
case 8000:
@@ -1949,7 +2160,6 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
// send the offer.
}
}
-
// Only turn on VAD if we have a CN payload type that matches the
// clockrate for the codec we are going to use.
if (it->clockrate == send_codec.plfreq) {
@@ -1960,56 +2170,7 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
}
}
}
-
- // We'll use the first codec in the list to actually send audio data.
- // Be sure to use the payload type requested by the remote side.
- // "red", for FEC audio, is a special case where the actual codec to be
- // used is specified in params.
- if (first) {
- if (_stricmp(it->name.c_str(), "red") == 0) {
- // Parse out the RED parameters. If we fail, just ignore RED;
- // we don't support all possible params/usage scenarios.
- if (!GetRedSendCodec(*it, codecs, &send_codec)) {
- continue;
- }
-
- // Enable redundant encoding of the specified codec. Treat any
- // failure as a fatal internal error.
- LOG(LS_INFO) << "Enabling FEC";
- if (engine()->voe()->rtp()->SetFECStatus(channel, true, it->id) == -1) {
- LOG_RTCERR3(SetFECStatus, channel, true, it->id);
- return false;
- }
- } else {
- send_codec = voe_codec;
- nack_enabled_ = IsNackEnabled(*it);
- SetNack(channel, nack_enabled_);
- }
- first = false;
- // Set the codec immediately, since SetVADStatus() depends on whether
- // the current codec is mono or stereo.
- if (!SetSendCodec(channel, send_codec))
- return false;
- }
}
-
- // If we're being asked to set an empty list of codecs, due to a buggy client,
- // choose the most common format: PCMU
- if (first) {
- LOG(LS_WARNING) << "Received empty list of codecs; using PCMU/8000";
- AudioCodec codec(0, "PCMU", 8000, 0, 1, 0);
- engine()->FindWebRtcCodec(codec, &send_codec);
- if (!SetSendCodec(channel, send_codec))
- return false;
- }
-
- // Always update the |send_codec_| to the currently set send codec.
- send_codec_.reset(new webrtc::CodecInst(send_codec));
-
- if (send_bw_setting_) {
- SetSendBandwidthInternal(send_autobw_, send_bw_bps_);
- }
-
return true;
}
@@ -2029,13 +2190,13 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
send_codecs_ = codecs;
for (ChannelMap::iterator iter = send_channels_.begin();
iter != send_channels_.end(); ++iter) {
- if (!SetSendCodecs(iter->second.channel, codecs)) {
+ if (!SetSendCodecs(iter->second->channel(), codecs)) {
return false;
}
}
+ // Set nack status on receive channels and update |nack_enabled_|.
SetNack(receive_channels_, nack_enabled_);
-
return true;
}
@@ -2043,7 +2204,7 @@ void WebRtcVoiceMediaChannel::SetNack(const ChannelMap& channels,
bool nack_enabled) {
for (ChannelMap::const_iterator it = channels.begin();
it != channels.end(); ++it) {
- SetNack(it->second.channel, nack_enabled);
+ SetNack(it->second->channel(), nack_enabled);
}
}
@@ -2063,7 +2224,7 @@ bool WebRtcVoiceMediaChannel::SetSendCodec(
<< ", bitrate=" << send_codec.rate;
for (ChannelMap::iterator iter = send_channels_.begin();
iter != send_channels_.end(); ++iter) {
- if (!SetSendCodec(iter->second.channel, send_codec))
+ if (!SetSendCodec(iter->second->channel(), send_codec))
return false;
}
@@ -2075,6 +2236,13 @@ bool WebRtcVoiceMediaChannel::SetSendCodec(
LOG(LS_INFO) << "Send channel " << channel << " selected voice codec "
<< ToString(send_codec) << ", bitrate=" << send_codec.rate;
+ webrtc::CodecInst current_codec;
+ if (engine()->voe()->codec()->GetSendCodec(channel, current_codec) == 0 &&
+ (send_codec == current_codec)) {
+ // Codec is already configured, we can return without setting it again.
+ return true;
+ }
+
if (engine()->voe()->codec()->SetSendCodec(channel, send_codec) == -1) {
LOG_RTCERR2(SetSendCodec, channel, ToString(send_codec));
return false;
@@ -2084,43 +2252,96 @@ bool WebRtcVoiceMediaChannel::SetSendCodec(
bool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) {
- // We don't support any incoming extensions headers right now.
+ if (receive_extensions_ == extensions) {
+ return true;
+ }
+
+ // The default channel may or may not be in |receive_channels_|. Set the rtp
+ // header extensions for default channel regardless.
+ if (!SetChannelRecvRtpHeaderExtensions(voe_channel(), extensions)) {
+ return false;
+ }
+
+ // Loop through all receive channels and enable/disable the extensions.
+ for (ChannelMap::const_iterator channel_it = receive_channels_.begin();
+ channel_it != receive_channels_.end(); ++channel_it) {
+ if (!SetChannelRecvRtpHeaderExtensions(channel_it->second->channel(),
+ extensions)) {
+ return false;
+ }
+ }
+
+ receive_extensions_ = extensions;
+ return true;
+}
+
+bool WebRtcVoiceMediaChannel::SetChannelRecvRtpHeaderExtensions(
+ int channel_id, const std::vector<RtpHeaderExtension>& extensions) {
+#ifdef USE_WEBRTC_DEV_BRANCH
+ const RtpHeaderExtension* audio_level_extension =
+ FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension);
+ if (!SetHeaderExtension(
+ &webrtc::VoERTP_RTCP::SetReceiveAudioLevelIndicationStatus, channel_id,
+ audio_level_extension)) {
+ return false;
+ }
+#endif // USE_WEBRTC_DEV_BRANCH
+
+ const RtpHeaderExtension* send_time_extension =
+ FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
+ if (!SetHeaderExtension(
+ &webrtc::VoERTP_RTCP::SetReceiveAbsoluteSenderTimeStatus, channel_id,
+ send_time_extension)) {
+ return false;
+ }
return true;
}
bool WebRtcVoiceMediaChannel::SetSendRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) {
- // Enable the audio level extension header if requested.
- std::vector<RtpHeaderExtension>::const_iterator it;
- for (it = extensions.begin(); it != extensions.end(); ++it) {
- if (it->uri == kRtpAudioLevelHeaderExtension) {
- break;
- }
+ if (send_extensions_ == extensions) {
+ return true;
}
- bool enable = (it != extensions.end());
- int id = 0;
+ // The default channel may or may not be in |send_channels_|. Set the rtp
+ // header extensions for default channel regardless.
- if (enable) {
- id = it->id;
- if (id < kMinRtpHeaderExtensionId ||
- id > kMaxRtpHeaderExtensionId) {
- LOG(LS_WARNING) << "Invalid RTP header extension id " << id;
- return false;
- }
+ if (!SetChannelSendRtpHeaderExtensions(voe_channel(), extensions)) {
+ return false;
}
- LOG(LS_INFO) << "Enabling audio level header extension with ID " << id;
- for (ChannelMap::const_iterator iter = send_channels_.begin();
- iter != send_channels_.end(); ++iter) {
- if (engine()->voe()->rtp()->SetRTPAudioLevelIndicationStatus(
- iter->second.channel, enable, id) == -1) {
- LOG_RTCERR3(SetRTPAudioLevelIndicationStatus,
- iter->second.channel, enable, id);
+ // Loop through all send channels and enable/disable the extensions.
+ for (ChannelMap::const_iterator channel_it = send_channels_.begin();
+ channel_it != send_channels_.end(); ++channel_it) {
+ if (!SetChannelSendRtpHeaderExtensions(channel_it->second->channel(),
+ extensions)) {
return false;
}
}
+ send_extensions_ = extensions;
+ return true;
+}
+
+bool WebRtcVoiceMediaChannel::SetChannelSendRtpHeaderExtensions(
+ int channel_id, const std::vector<RtpHeaderExtension>& extensions) {
+ const RtpHeaderExtension* audio_level_extension =
+ FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension);
+
+ if (!SetHeaderExtension(
+ &webrtc::VoERTP_RTCP::SetSendAudioLevelIndicationStatus, channel_id,
+ audio_level_extension)) {
+ return false;
+ }
+
+ const RtpHeaderExtension* send_time_extension =
+ FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
+ if (!SetHeaderExtension(
+ &webrtc::VoERTP_RTCP::SetSendAbsoluteSenderTimeStatus, channel_id,
+ send_time_extension)) {
+ return false;
+ }
+
return true;
}
@@ -2150,9 +2371,9 @@ bool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) {
}
for (ChannelMap::iterator it = receive_channels_.begin();
it != receive_channels_.end() && result; ++it) {
- if (!SetPlayout(it->second.channel, playout)) {
+ if (!SetPlayout(it->second->channel(), playout)) {
LOG(LS_ERROR) << "SetPlayout " << playout << " on channel "
- << it->second.channel << " failed";
+ << it->second->channel() << " failed";
result = false;
}
}
@@ -2190,7 +2411,7 @@ bool WebRtcVoiceMediaChannel::ChangeSend(SendFlags send) {
// Change the settings on each send channel.
for (ChannelMap::iterator iter = send_channels_.begin();
iter != send_channels_.end(); ++iter) {
- if (!ChangeSend(iter->second.channel, send))
+ if (!ChangeSend(iter->second->channel(), send))
return false;
}
@@ -2224,6 +2445,7 @@ bool WebRtcVoiceMediaChannel::ChangeSend(int channel, SendFlags send) {
return true;
}
+// TODO(ronghuawu): Change this method to return bool.
void WebRtcVoiceMediaChannel::ConfigureSendChannel(int channel) {
if (engine()->voe()->network()->RegisterExternalTransport(
channel, *this) == -1) {
@@ -2235,6 +2457,9 @@ void WebRtcVoiceMediaChannel::ConfigureSendChannel(int channel) {
// Reset all recv codecs; they will be enabled via SetRecvCodecs.
ResetRecvCodecs(channel);
+
+ // Set RTP header extension for the new channel.
+ SetChannelSendRtpHeaderExtensions(channel, send_extensions_);
}
bool WebRtcVoiceMediaChannel::DeleteChannel(int channel) {
@@ -2262,7 +2487,7 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
bool default_channel_is_available = true;
for (ChannelMap::const_iterator iter = send_channels_.begin();
iter != send_channels_.end(); ++iter) {
- if (IsDefaultChannel(iter->second.channel)) {
+ if (IsDefaultChannel(iter->second->channel())) {
default_channel_is_available = false;
break;
}
@@ -2282,7 +2507,11 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
// Save the channel to send_channels_, so that RemoveSendStream() can still
// delete the channel in case failure happens below.
- send_channels_[sp.first_ssrc()] = WebRtcVoiceChannelInfo(channel, NULL);
+ webrtc::AudioTransport* audio_transport =
+ engine()->voe()->base()->audio_transport();
+ send_channels_.insert(std::make_pair(
+ sp.first_ssrc(),
+ new WebRtcVoiceChannelRenderer(channel, audio_transport)));
// Set the send (local) SSRC.
// If there are multiple send SSRCs, we can only set the first one here, and
@@ -2301,10 +2530,10 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
for (ChannelMap::const_iterator it = receive_channels_.begin();
it != receive_channels_.end(); ++it) {
// Only update the SSRC for non-default channels.
- if (!IsDefaultChannel(it->second.channel)) {
- if (engine()->voe()->rtp()->SetLocalSSRC(it->second.channel,
+ if (!IsDefaultChannel(it->second->channel())) {
+ if (engine()->voe()->rtp()->SetLocalSSRC(it->second->channel(),
sp.first_ssrc()) != 0) {
- LOG_RTCERR2(SetLocalSSRC, it->second.channel, sp.first_ssrc());
+ LOG_RTCERR2(SetLocalSSRC, it->second->channel(), sp.first_ssrc());
return false;
}
}
@@ -2331,12 +2560,13 @@ bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) {
return false;
}
- int channel = it->second.channel;
+ int channel = it->second->channel();
ChangeSend(channel, SEND_NOTHING);
- // Notify the audio renderer that the send channel is going away.
- if (it->second.renderer)
- it->second.renderer->RemoveChannel(channel);
+ // Delete the WebRtcVoiceChannelRenderer object connected to the channel,
+ // this will disconnect the audio renderer with the send channel.
+ delete it->second;
+ send_channels_.erase(it);
if (IsDefaultChannel(channel)) {
// Do not delete the default channel since the receive channels depend on
@@ -2350,7 +2580,6 @@ bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) {
return false;
}
- send_channels_.erase(it);
if (send_channels_.empty())
ChangeSend(SEND_NOTHING);
@@ -2376,12 +2605,15 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
// Reuse default channel for recv stream in non-conference mode call
// when the default channel is not being used.
+ webrtc::AudioTransport* audio_transport =
+ engine()->voe()->base()->audio_transport();
if (!InConferenceMode() && default_receive_ssrc_ == 0) {
LOG(LS_INFO) << "Recv stream " << sp.first_ssrc()
<< " reuse default channel";
default_receive_ssrc_ = sp.first_ssrc();
receive_channels_.insert(std::make_pair(
- default_receive_ssrc_, WebRtcVoiceChannelInfo(voe_channel(), NULL)));
+ default_receive_ssrc_,
+ new WebRtcVoiceChannelRenderer(voe_channel(), audio_transport)));
return SetPlayout(voe_channel(), playout_);
}
@@ -2398,7 +2630,8 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
}
receive_channels_.insert(
- std::make_pair(ssrc, WebRtcVoiceChannelInfo(channel, NULL)));
+ std::make_pair(
+ ssrc, new WebRtcVoiceChannelRenderer(channel, audio_transport)));
LOG(LS_INFO) << "New audio stream " << ssrc
<< " registered to VoiceEngine channel #"
@@ -2415,14 +2648,14 @@ bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) {
}
// Use the same SSRC as our default channel (so the RTCP reports are correct).
- unsigned int send_ssrc;
+ unsigned int send_ssrc = 0;
webrtc::VoERTP_RTCP* rtp = engine()->voe()->rtp();
if (rtp->GetLocalSSRC(voe_channel(), send_ssrc) == -1) {
- LOG_RTCERR2(GetSendSSRC, channel, send_ssrc);
+ LOG_RTCERR1(GetSendSSRC, channel);
return false;
}
if (rtp->SetLocalSSRC(channel, send_ssrc) == -1) {
- LOG_RTCERR2(SetSendSSRC, channel, send_ssrc);
+ LOG_RTCERR1(SetSendSSRC, channel);
return false;
}
@@ -2463,6 +2696,11 @@ bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) {
}
SetNack(channel, nack_enabled_);
+ // Set RTP header extension for the new channel.
+ if (!SetChannelRecvRtpHeaderExtensions(channel, receive_extensions_)) {
+ return false;
+ }
+
return SetPlayout(channel, playout_);
}
@@ -2475,34 +2713,28 @@ bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32 ssrc) {
return false;
}
+ // Delete the WebRtcVoiceChannelRenderer object connected to the channel, this
+ // will disconnect the audio renderer with the receive channel.
+ // Cache the channel before the deletion.
+ const int channel = it->second->channel();
+ delete it->second;
+ receive_channels_.erase(it);
+
if (ssrc == default_receive_ssrc_) {
- ASSERT(IsDefaultChannel(it->second.channel));
+ ASSERT(IsDefaultChannel(channel));
// Recycle the default channel is for recv stream.
if (playout_)
SetPlayout(voe_channel(), false);
- if (it->second.renderer)
- it->second.renderer->RemoveChannel(voe_channel());
-
default_receive_ssrc_ = 0;
- receive_channels_.erase(it);
return true;
}
- // Non default channel.
- // Notify the renderer that channel is going away.
- if (it->second.renderer)
- it->second.renderer->RemoveChannel(it->second.channel);
-
LOG(LS_INFO) << "Removing audio stream " << ssrc
- << " with VoiceEngine channel #" << it->second.channel << ".";
- if (!DeleteChannel(it->second.channel)) {
- // Erase the entry anyhow.
- receive_channels_.erase(it);
+ << " with VoiceEngine channel #" << channel << ".";
+ if (!DeleteChannel(channel))
return false;
- }
- receive_channels_.erase(it);
bool enable_default_channel_playout = false;
if (receive_channels_.empty()) {
// The last stream was removed. We can now enable the default
@@ -2540,19 +2772,11 @@ bool WebRtcVoiceMediaChannel::SetRemoteRenderer(uint32 ssrc,
return true;
}
- AudioRenderer* remote_renderer = it->second.renderer;
- if (renderer) {
- ASSERT(remote_renderer == NULL || remote_renderer == renderer);
- if (!remote_renderer) {
- renderer->AddChannel(it->second.channel);
- }
- } else if (remote_renderer) {
- // |renderer| == NULL, remove the channel from the renderer.
- remote_renderer->RemoveChannel(it->second.channel);
- }
+ if (renderer)
+ it->second->Start(renderer);
+ else
+ it->second->Stop();
- // Assign the new value to the struct.
- it->second.renderer = renderer;
return true;
}
@@ -2570,17 +2794,11 @@ bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32 ssrc,
return true;
}
- AudioRenderer* local_renderer = it->second.renderer;
- if (renderer) {
- ASSERT(local_renderer == NULL || local_renderer == renderer);
- if (!local_renderer)
- renderer->AddChannel(it->second.channel);
- } else if (local_renderer) {
- local_renderer->RemoveChannel(it->second.channel);
- }
+ if (renderer)
+ it->second->Start(renderer);
+ else
+ it->second->Stop();
- // Assign the new value to the struct.
- it->second.renderer = renderer;
return true;
}
@@ -2591,7 +2809,7 @@ bool WebRtcVoiceMediaChannel::GetActiveStreams(
actives->clear();
for (ChannelMap::iterator it = receive_channels_.begin();
it != receive_channels_.end(); ++it) {
- int level = GetOutputLevel(it->second.channel);
+ int level = GetOutputLevel(it->second->channel());
if (level > 0) {
actives->push_back(std::make_pair(it->first, level));
}
@@ -2604,7 +2822,7 @@ int WebRtcVoiceMediaChannel::GetOutputLevel() {
int highest = GetOutputLevel(voe_channel());
for (ChannelMap::iterator it = receive_channels_.begin();
it != receive_channels_.end(); ++it) {
- int level = GetOutputLevel(it->second.channel);
+ int level = GetOutputLevel(it->second->channel());
highest = talk_base::_max(level, highest);
}
return highest;
@@ -2647,7 +2865,7 @@ bool WebRtcVoiceMediaChannel::SetOutputScaling(
channels.push_back(voe_channel());
for (ChannelMap::const_iterator it = receive_channels_.begin();
it != receive_channels_.end(); ++it) {
- channels.push_back(it->second.channel);
+ channels.push_back(it->second->channel());
}
} else { // Collect only the channel of the specified ssrc.
int channel = GetReceiveChannelNum(ssrc);
@@ -2783,7 +3001,7 @@ bool WebRtcVoiceMediaChannel::InsertDtmf(uint32 ssrc, int event,
bool default_channel_is_inuse = false;
for (ChannelMap::const_iterator iter = send_channels_.begin();
iter != send_channels_.end(); ++iter) {
- if (IsDefaultChannel(iter->second.channel)) {
+ if (IsDefaultChannel(iter->second->channel())) {
default_channel_is_inuse = true;
break;
}
@@ -2791,7 +3009,7 @@ bool WebRtcVoiceMediaChannel::InsertDtmf(uint32 ssrc, int event,
if (default_channel_is_inuse) {
channel = voe_channel();
} else if (!send_channels_.empty()) {
- channel = send_channels_.begin()->second.channel;
+ channel = send_channels_.begin()->second->channel();
}
} else {
channel = GetSendChannelNum(ssrc);
@@ -2889,11 +3107,12 @@ void WebRtcVoiceMediaChannel::OnRtcpReceived(
for (ChannelMap::iterator iter = send_channels_.begin();
iter != send_channels_.end(); ++iter) {
// Make sure not sending the same packet to default channel more than once.
- if (IsDefaultChannel(iter->second.channel) && has_sent_to_default_channel)
+ if (IsDefaultChannel(iter->second->channel()) &&
+ has_sent_to_default_channel)
continue;
engine()->voe()->network()->ReceivedRTCPPacket(
- iter->second.channel,
+ iter->second->channel(),
packet->data(),
static_cast<unsigned int>(packet->length()));
}
@@ -2912,18 +3131,23 @@ bool WebRtcVoiceMediaChannel::MuteStream(uint32 ssrc, bool muted) {
return true;
}
-bool WebRtcVoiceMediaChannel::SetSendBandwidth(bool autobw, int bps) {
- LOG(LS_INFO) << "WebRtcVoiceMediaChanne::SetSendBandwidth.";
+bool WebRtcVoiceMediaChannel::SetStartSendBandwidth(int bps) {
+ // TODO(andresp): Add support for setting an independent start bandwidth when
+ // bandwidth estimation is enabled for voice engine.
+ return false;
+}
- send_bw_setting_ = true;
- send_autobw_ = autobw;
- send_bw_bps_ = bps;
+bool WebRtcVoiceMediaChannel::SetMaxSendBandwidth(int bps) {
+ LOG(LS_INFO) << "WebRtcVoiceMediaChanne::SetSendBandwidth.";
- return SetSendBandwidthInternal(send_autobw_, send_bw_bps_);
+ return SetSendBandwidthInternal(bps);
}
-bool WebRtcVoiceMediaChannel::SetSendBandwidthInternal(bool autobw, int bps) {
- LOG(LS_INFO) << "WebRtcVoiceMediaChanne::SetSendBandwidthInternal.";
+bool WebRtcVoiceMediaChannel::SetSendBandwidthInternal(int bps) {
+ LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetSendBandwidthInternal.";
+
+ send_bw_setting_ = true;
+ send_bw_bps_ = bps;
if (!send_codec_) {
LOG(LS_INFO) << "The send codec has not been set up yet. "
@@ -2932,7 +3156,9 @@ bool WebRtcVoiceMediaChannel::SetSendBandwidthInternal(bool autobw, int bps) {
}
// Bandwidth is auto by default.
- if (autobw || bps <= 0)
+ // TODO(bemasc): Fix this so that if SetMaxSendBandwidth(50) is followed by
+ // SetMaxSendBandwith(0), the second call removes the previous limit.
+ if (bps <= 0)
return true;
webrtc::CodecInst codec = *send_codec_;
@@ -2997,7 +3223,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
for (ChannelMap::const_iterator channel_iter = send_channels_.begin();
channel_iter != send_channels_.end(); ++channel_iter) {
- const int channel = channel_iter->second.channel;
+ const int channel = channel_iter->second->channel();
// Fill in the sender info, based on what we know, and what the
// remote side told us it got from its RTCP report.
@@ -3069,7 +3295,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
std::vector<int> channels;
for (ChannelMap::const_iterator it = receive_channels_.begin();
it != receive_channels_.end(); ++it) {
- channels.push_back(it->second.channel);
+ channels.push_back(it->second->channel());
}
if (channels.empty()) {
channels.push_back(voe_channel());
@@ -3091,6 +3317,12 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
rinfo.fraction_lost = static_cast<float>(cs.fractionLost) / (1 << 8);
rinfo.packets_lost = cs.cumulativeLost;
rinfo.ext_seqnum = cs.extendedMax;
+#ifdef USE_WEBRTC_DEV_BRANCH
+ rinfo.capture_start_ntp_time_ms = cs.capture_start_ntp_time_ms_;
+#endif
+ if (codec.pltype != -1) {
+ rinfo.codec_name = codec.plname;
+ }
// Convert samples to milliseconds.
if (codec.plfreq / 1000 > 0) {
rinfo.jitter_ms = cs.jitterSamples / (codec.plfreq / 1000);
@@ -3106,6 +3338,20 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
rinfo.expand_rate =
static_cast<float>(ns.currentExpandRate) / (1 << 14);
}
+
+ webrtc::AudioDecodingCallStats ds;
+ if (engine()->voe()->neteq() &&
+ engine()->voe()->neteq()->GetDecodingCallStatistics(
+ *it, &ds) != -1) {
+ rinfo.decoding_calls_to_silence_generator =
+ ds.calls_to_silence_generator;
+ rinfo.decoding_calls_to_neteq = ds.calls_to_neteq;
+ rinfo.decoding_normal = ds.decoded_normal;
+ rinfo.decoding_plc = ds.decoded_plc;
+ rinfo.decoding_cng = ds.decoded_cng;
+ rinfo.decoding_plc_cng = ds.decoded_plc_cng;
+ }
+
if (engine()->voe()->sync()) {
int jitter_buffer_delay_ms = 0;
int playout_buffer_delay_ms = 0;
@@ -3147,7 +3393,7 @@ bool WebRtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) {
// Check whether this is a sending channel.
for (ChannelMap::const_iterator it = send_channels_.begin();
it != send_channels_.end(); ++it) {
- if (it->second.channel == channel_num) {
+ if (it->second->channel() == channel_num) {
// This is a sending channel.
uint32 local_ssrc = 0;
if (engine()->voe()->rtp()->GetLocalSSRC(
@@ -3161,7 +3407,7 @@ bool WebRtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) {
// Check whether this is a receiving channel.
for (ChannelMap::const_iterator it = receive_channels_.begin();
it != receive_channels_.end(); ++it) {
- if (it->second.channel == channel_num) {
+ if (it->second->channel() == channel_num) {
*ssrc = it->first;
return true;
}
@@ -3189,14 +3435,14 @@ int WebRtcVoiceMediaChannel::GetOutputLevel(int channel) {
int WebRtcVoiceMediaChannel::GetReceiveChannelNum(uint32 ssrc) {
ChannelMap::iterator it = receive_channels_.find(ssrc);
if (it != receive_channels_.end())
- return it->second.channel;
+ return it->second->channel();
return (ssrc == default_receive_ssrc_) ? voe_channel() : -1;
}
int WebRtcVoiceMediaChannel::GetSendChannelNum(uint32 ssrc) {
ChannelMap::iterator it = send_channels_.find(ssrc);
if (it != send_channels_.end())
- return it->second.channel;
+ return it->second->channel();
return -1;
}
@@ -3333,6 +3579,23 @@ VoiceMediaChannel::Error
}
}
+bool WebRtcVoiceMediaChannel::SetHeaderExtension(ExtensionSetterFunction setter,
+ int channel_id, const RtpHeaderExtension* extension) {
+ bool enable = false;
+ int id = 0;
+ std::string uri;
+ if (extension) {
+ enable = true;
+ id = extension->id;
+ uri = extension->uri;
+ }
+ if ((engine()->voe()->rtp()->*setter)(channel_id, enable, id) != 0) {
+ LOG_RTCERR4(*setter, uri, channel_id, enable, id);
+ return false;
+ }
+ return true;
+}
+
int WebRtcSoundclipStream::Read(void *buf, int len) {
size_t res = 0;
mem_.Read(buf, len, &res, NULL);
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine.h b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine.h
index 23d97f5e103..efc388fc336 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine.h
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine.h
@@ -44,14 +44,12 @@
#include "talk/media/webrtc/webrtcvoe.h"
#include "talk/session/media/channel.h"
#include "webrtc/common.h"
-#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
#if !defined(LIBPEERCONNECTION_LIB) && \
!defined(LIBPEERCONNECTION_IMPLEMENTATION)
#error "Bogus include."
#endif
-
namespace cricket {
// WebRtcSoundclipStream is an adapter object that allows a memory stream to be
@@ -174,6 +172,9 @@ class WebRtcVoiceEngine
bool SetAudioDeviceModule(webrtc::AudioDeviceModule* adm,
webrtc::AudioDeviceModule* adm_sc);
+ // Starts AEC dump using existing file.
+ bool StartAecDump(talk_base::PlatformFile file);
+
// Check whether the supplied trace should be ignored.
bool ShouldIgnoreTrace(const std::string& trace);
@@ -198,9 +199,6 @@ class WebRtcVoiceEngine
// allows us to selectively turn on and off different options easily
// at any time.
bool ApplyOptions(const AudioOptions& options);
- // Configure for using ACM2, if |enable| is true, otherwise configure for
- // ACM1.
- void EnableExperimentalAcm(bool enable);
virtual void Print(webrtc::TraceLevel level, const char* trace, int length);
virtual void CallbackOnError(int channel, int errCode);
// Given the device type, name, and id, find device id. Return true and
@@ -258,7 +256,6 @@ class WebRtcVoiceEngine
webrtc::AgcConfig default_agc_config_;
webrtc::Config voe_config_;
- bool use_experimental_acm_;
bool initialized_;
// See SetOptions and SetOptionOverrides for a description of the
@@ -362,7 +359,8 @@ class WebRtcVoiceMediaChannel
const talk_base::PacketTime& packet_time);
virtual void OnReadyToSend(bool ready) {}
virtual bool MuteStream(uint32 ssrc, bool on);
- virtual bool SetSendBandwidth(bool autobw, int bps);
+ virtual bool SetStartSendBandwidth(int bps);
+ virtual bool SetMaxSendBandwidth(int bps);
virtual bool GetStats(VoiceMediaInfo* info);
// Gets last reported error from WebRtc voice engine. This should be only
// called in response a failure.
@@ -388,8 +386,13 @@ class WebRtcVoiceMediaChannel
static Error WebRtcErrorToChannelError(int err_code);
private:
- struct WebRtcVoiceChannelInfo;
- typedef std::map<uint32, WebRtcVoiceChannelInfo> ChannelMap;
+ class WebRtcVoiceChannelRenderer;
+ // Map of ssrc to WebRtcVoiceChannelRenderer object. A new object of
+ // WebRtcVoiceChannelRenderer will be created for every new stream and
+ // will be destroyed when the stream goes away.
+ typedef std::map<uint32, WebRtcVoiceChannelRenderer*> ChannelMap;
+ typedef int (webrtc::VoERTP_RTCP::* ExtensionSetterFunction)(int, bool,
+ unsigned char);
void SetNack(int channel, bool nack_enabled);
void SetNack(const ChannelMap& channels, bool nack_enabled);
@@ -408,7 +411,17 @@ class WebRtcVoiceMediaChannel
return channel_id == voe_channel();
}
bool SetSendCodecs(int channel, const std::vector<AudioCodec>& codecs);
- bool SetSendBandwidthInternal(bool autobw, int bps);
+ bool SetSendBandwidthInternal(int bps);
+
+ bool SetHeaderExtension(ExtensionSetterFunction setter, int channel_id,
+ const RtpHeaderExtension* extension);
+
+ bool SetChannelRecvRtpHeaderExtensions(
+ int channel_id,
+ const std::vector<RtpHeaderExtension>& extensions);
+ bool SetChannelSendRtpHeaderExtensions(
+ int channel_id,
+ const std::vector<RtpHeaderExtension>& extensions);
talk_base::scoped_ptr<WebRtcSoundclipStream> ringback_tone_;
std::set<int> ringback_channels_; // channels playing ringback
@@ -416,7 +429,6 @@ class WebRtcVoiceMediaChannel
std::vector<AudioCodec> send_codecs_;
talk_base::scoped_ptr<webrtc::CodecInst> send_codec_;
bool send_bw_setting_;
- bool send_autobw_;
int send_bw_bps_;
AudioOptions options_;
bool dtmf_allowed_;
@@ -431,6 +443,7 @@ class WebRtcVoiceMediaChannel
// When the default channel (voe_channel) is used for sending, it is
// contained in send_channels_, otherwise not.
ChannelMap send_channels_;
+ std::vector<RtpHeaderExtension> send_extensions_;
uint32 default_receive_ssrc_;
// Note the default channel (voe_channel()) can reside in both
// receive_channels_ and send_channels_ in non-conference mode and in that
@@ -440,6 +453,7 @@ class WebRtcVoiceMediaChannel
// the WebRtc thread must be synchronized with edits on the worker thread.
// Reads on the worker thread are ok.
//
+ std::vector<RtpHeaderExtension> receive_extensions_;
// Do not lock this on the VoE media processor thread; potential for deadlock
// exists.
mutable talk_base::CriticalSection receive_channels_cs_;
diff --git a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine_unittest.cc
index 9bb681a895c..58893b98ac5 100644
--- a/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -1,6 +1,29 @@
-// Copyright 2008 Google Inc.
-//
-// Author: Justin Uberti (juberti@google.com)
+/*
+ * libjingle
+ * Copyright 2008 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
#ifdef WIN32
#include "talk/base/win32.h"
@@ -21,6 +44,9 @@
// Tests for the WebRtcVoiceEngine/VoiceChannel code.
+using cricket::kRtpAudioLevelHeaderExtension;
+using cricket::kRtpAbsoluteSenderTimeHeaderExtension;
+
static const cricket::AudioCodec kPcmuCodec(0, "PCMU", 8000, 64000, 1, 0);
static const cricket::AudioCodec kIsacCodec(103, "ISAC", 16000, 32000, 1, 0);
static const cricket::AudioCodec kCeltCodec(110, "CELT", 32000, 64000, 2, 0);
@@ -113,17 +139,19 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
options_conference_.conference_mode.Set(true);
options_adjust_agc_.adjust_agc_delta.Set(-10);
}
- bool SetupEngine() {
- bool result = engine_.Init(talk_base::Thread::Current());
- if (result) {
- channel_ = engine_.CreateChannel();
- result = (channel_ != NULL);
+ bool SetupEngineWithoutStream() {
+ if (!engine_.Init(talk_base::Thread::Current())) {
+ return false;
}
- if (result) {
- result = channel_->AddSendStream(
- cricket::StreamParams::CreateLegacy(kSsrc1));
+ channel_ = engine_.CreateChannel();
+ return (channel_ != NULL);
+ }
+ bool SetupEngine() {
+ if (!SetupEngineWithoutStream()) {
+ return false;
}
- return result;
+ return channel_->AddSendStream(
+ cricket::StreamParams::CreateLegacy(kSsrc1));
}
void SetupForMultiSendStream() {
EXPECT_TRUE(SetupEngine());
@@ -201,81 +229,110 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
// Test that send bandwidth is set correctly.
// |codec| is the codec under test.
- // |default_bitrate| is the default bitrate for the codec.
- // |auto_bitrate| is a parameter to set to SetSendBandwidth().
- // |desired_bitrate| is a parameter to set to SetSendBandwidth().
- // |expected_result| is expected results from SetSendBandwidth().
+ // |max_bitrate| is a parameter to set to SetMaxSendBandwidth().
+ // |expected_result| is the expected result from SetMaxSendBandwidth().
+ // |expected_bitrate| is the expected audio bitrate afterward.
void TestSendBandwidth(const cricket::AudioCodec& codec,
- int default_bitrate,
- bool auto_bitrate,
- int desired_bitrate,
- bool expected_result) {
+ int max_bitrate,
+ bool expected_result,
+ int expected_bitrate) {
int channel_num = voe_.GetLastChannel();
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
- bool result = channel_->SetSendBandwidth(auto_bitrate, desired_bitrate);
+ bool result = channel_->SetMaxSendBandwidth(max_bitrate);
EXPECT_EQ(expected_result, result);
webrtc::CodecInst temp_codec;
EXPECT_FALSE(voe_.GetSendCodec(channel_num, temp_codec));
- if (result) {
- // If SetSendBandwidth() returns true then bitrate is set correctly.
- if (auto_bitrate) {
- EXPECT_EQ(default_bitrate, temp_codec.rate);
- } else {
- EXPECT_EQ(desired_bitrate, temp_codec.rate);
- }
- } else {
- // If SetSendBandwidth() returns false then bitrate is set to the
- // default value.
- EXPECT_EQ(default_bitrate, temp_codec.rate);
- }
+ EXPECT_EQ(expected_bitrate, temp_codec.rate);
}
+ void TestSetSendRtpHeaderExtensions(const std::string& ext) {
+ EXPECT_TRUE(SetupEngineWithoutStream());
+ int channel_num = voe_.GetLastChannel();
- void TestSetSendRtpHeaderExtensions(int channel_id) {
- std::vector<cricket::RtpHeaderExtension> extensions;
- bool enable = false;
- unsigned char id = 0;
-
- // Ensure audio levels are off by default.
- EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
- channel_id, enable, id));
- EXPECT_FALSE(enable);
+ // Ensure extensions are off by default.
+ EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext));
+ std::vector<cricket::RtpHeaderExtension> extensions;
// Ensure unknown extensions won't cause an error.
extensions.push_back(cricket::RtpHeaderExtension(
- "urn:ietf:params:unknowextention", 1));
+ "urn:ietf:params:unknownextention", 1));
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
- EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
- channel_id, enable, id));
- EXPECT_FALSE(enable);
+ EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext));
- // Ensure audio levels stay off with an empty list of headers.
+ // Ensure extensions stay off with an empty list of headers.
+ extensions.clear();
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
- EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
- channel_id, enable, id));
- EXPECT_FALSE(enable);
+ EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext));
- // Ensure audio levels are enabled if the audio-level header is specified.
- extensions.push_back(cricket::RtpHeaderExtension(
- "urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8));
+ // Ensure extension is set properly.
+ const int id = 1;
+ extensions.push_back(cricket::RtpHeaderExtension(ext, id));
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
- EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
- channel_id, enable, id));
- EXPECT_TRUE(enable);
- EXPECT_EQ(8, id);
+ EXPECT_EQ(id, voe_.GetSendRtpExtensionId(channel_num, ext));
+
+ // Ensure extension is set properly on new channel.
+ // The first stream to occupy the default channel.
+ EXPECT_TRUE(channel_->AddSendStream(
+ cricket::StreamParams::CreateLegacy(123)));
+ EXPECT_TRUE(channel_->AddSendStream(
+ cricket::StreamParams::CreateLegacy(234)));
+ int new_channel_num = voe_.GetLastChannel();
+ EXPECT_NE(channel_num, new_channel_num);
+ EXPECT_EQ(id, voe_.GetSendRtpExtensionId(new_channel_num, ext));
- // Ensure audio levels go back off with an empty list.
+ // Ensure all extensions go back off with an empty list.
extensions.clear();
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
- EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
- channel_id, enable, id));
- EXPECT_FALSE(enable);
+ EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(channel_num, ext));
+ EXPECT_EQ(-1, voe_.GetSendRtpExtensionId(new_channel_num, ext));
+ }
+
+ void TestSetRecvRtpHeaderExtensions(const std::string& ext) {
+ EXPECT_TRUE(SetupEngineWithoutStream());
+ int channel_num = voe_.GetLastChannel();
+
+ // Ensure extensions are off by default.
+ EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
+
+ std::vector<cricket::RtpHeaderExtension> extensions;
+ // Ensure unknown extensions won't cause an error.
+ extensions.push_back(cricket::RtpHeaderExtension(
+ "urn:ietf:params:unknownextention", 1));
+ EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+ EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
+
+ // Ensure extensions stay off with an empty list of headers.
+ extensions.clear();
+ EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+ EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
+
+ // Ensure extension is set properly.
+ const int id = 2;
+ extensions.push_back(cricket::RtpHeaderExtension(ext, id));
+ EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+ EXPECT_EQ(id, voe_.GetReceiveRtpExtensionId(channel_num, ext));
+
+ // Ensure extension is set properly on new channel.
+ // The first stream to occupy the default channel.
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(345)));
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(456)));
+ int new_channel_num = voe_.GetLastChannel();
+ EXPECT_NE(channel_num, new_channel_num);
+ EXPECT_EQ(id, voe_.GetReceiveRtpExtensionId(new_channel_num, ext));
+
+ // Ensure all extensions go back off with an empty list.
+ extensions.clear();
+ EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+ EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
+ EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(new_channel_num, ext));
}
protected:
@@ -575,47 +632,67 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendBandwidthAuto) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
- // Test that when autobw is true, bitrate is kept as the default
- // value. autobw is true for the following tests.
+ // Test that when autobw is enabled, bitrate is kept as the default
+ // value. autobw is enabled for the following tests because the target
+ // bitrate is <= 0.
// ISAC, default bitrate == 32000.
- TestSendBandwidth(kIsacCodec, 32000, true, 96000, true);
+ TestSendBandwidth(kIsacCodec, 0, true, 32000);
// PCMU, default bitrate == 64000.
- TestSendBandwidth(kPcmuCodec, 64000, true, 96000, true);
+ TestSendBandwidth(kPcmuCodec, -1, true, 64000);
// CELT, default bitrate == 64000.
- TestSendBandwidth(kCeltCodec, 64000, true, 96000, true);
+ TestSendBandwidth(kCeltCodec, 0, true, 64000);
// opus, default bitrate == 64000.
- TestSendBandwidth(kOpusCodec, 64000, true, 96000, true);
+ TestSendBandwidth(kOpusCodec, -1, true, 64000);
}
-TEST_F(WebRtcVoiceEngineTestFake, SetSendBandwidthFixedMultiRateAsCaller) {
+TEST_F(WebRtcVoiceEngineTestFake, SetMaxSendBandwidthMultiRateAsCaller) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
- // Test that we can set bitrate if a multi-rate codec is used.
- // autobw is false for the following tests.
+ // Test that the bitrate of a multi-rate codec is always the maximum.
// ISAC, default bitrate == 32000.
- TestSendBandwidth(kIsacCodec, 32000, false, 128000, true);
+ TestSendBandwidth(kIsacCodec, 128000, true, 128000);
+ TestSendBandwidth(kIsacCodec, 16000, true, 16000);
// CELT, default bitrate == 64000.
- TestSendBandwidth(kCeltCodec, 64000, false, 96000, true);
+ TestSendBandwidth(kCeltCodec, 96000, true, 96000);
+ TestSendBandwidth(kCeltCodec, 32000, true, 32000);
// opus, default bitrate == 64000.
- TestSendBandwidth(kOpusCodec, 64000, false, 96000, true);
+ TestSendBandwidth(kOpusCodec, 96000, true, 96000);
+ TestSendBandwidth(kOpusCodec, 48000, true, 48000);
}
-TEST_F(WebRtcVoiceEngineTestFake, SetSendBandwidthFixedMultiRateAsCallee) {
+TEST_F(WebRtcVoiceEngineTestFake, SetMaxSendBandwidthFixedRateAsCaller) {
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
+
+ // Test that we can only set a maximum bitrate for a fixed-rate codec
+ // if it's bigger than the fixed rate.
+
+ // PCMU, fixed bitrate == 64000.
+ TestSendBandwidth(kPcmuCodec, 0, true, 64000);
+ TestSendBandwidth(kPcmuCodec, 1, false, 64000);
+ TestSendBandwidth(kPcmuCodec, 128000, true, 64000);
+ TestSendBandwidth(kPcmuCodec, 32000, false, 64000);
+ TestSendBandwidth(kPcmuCodec, 64000, true, 64000);
+ TestSendBandwidth(kPcmuCodec, 63999, false, 64000);
+ TestSendBandwidth(kPcmuCodec, 64001, true, 64000);
+}
+
+TEST_F(WebRtcVoiceEngineTestFake, SetMaxSendBandwidthMultiRateAsCallee) {
EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
channel_ = engine_.CreateChannel();
EXPECT_TRUE(channel_ != NULL);
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
int desired_bitrate = 128000;
- EXPECT_TRUE(channel_->SetSendBandwidth(false, desired_bitrate));
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(desired_bitrate));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrc1)));
@@ -629,7 +706,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendBandwidthFixedMultiRateAsCallee) {
// Test that bitrate cannot be set for CBR codecs.
// Bitrate is ignored if it is higher than the fixed bitrate.
// Bitrate less then the fixed bitrate is an error.
-TEST_F(WebRtcVoiceEngineTestFake, SetSendBandwidthFixedCbr) {
+TEST_F(WebRtcVoiceEngineTestFake, SetMaxSendBandwidthCbr) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
@@ -642,10 +719,10 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendBandwidthFixedCbr) {
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, codec));
EXPECT_EQ(64000, codec.rate);
- EXPECT_TRUE(channel_->SetSendBandwidth(false, 128000));
+ EXPECT_TRUE(channel_->SetMaxSendBandwidth(128000));
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, codec));
EXPECT_EQ(64000, codec.rate);
- EXPECT_FALSE(channel_->SetSendBandwidth(false, 128));
+ EXPECT_FALSE(channel_->SetMaxSendBandwidth(128));
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, codec));
EXPECT_EQ(64000, codec.rate);
}
@@ -661,105 +738,98 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecs) {
codecs[0].id = 96;
codecs[0].bitrate = 48000;
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_EQ(1, voe_.GetNumSetSendCodecs());
webrtc::CodecInst gcodec;
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_EQ(48000, gcodec.rate);
EXPECT_STREQ("ISAC", gcodec.plname);
EXPECT_FALSE(voe_.GetVAD(channel_num));
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(105, voe_.GetSendCNPayloadType(channel_num, true));
EXPECT_EQ(106, voe_.GetSendTelephoneEventPayloadType(channel_num));
}
-// TODO(pthatcher): Change failure behavior to returning false rather
-// than defaulting to PCMU.
-// Test that if clockrate is not 48000 for opus, we fail by fallback to PCMU.
+// Test that VoE Channel doesn't call SetSendCodec again if same codec is tried
+// to apply.
+TEST_F(WebRtcVoiceEngineTestFake, DontResetSetSendCodec) {
+ EXPECT_TRUE(SetupEngine());
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kIsacCodec);
+ codecs.push_back(kPcmuCodec);
+ codecs.push_back(kRedCodec);
+ codecs[0].id = 96;
+ codecs[0].bitrate = 48000;
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_EQ(1, voe_.GetNumSetSendCodecs());
+ // Calling SetSendCodec again with same codec which is already set.
+ // In this case media channel shouldn't send codec to VoE.
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_EQ(1, voe_.GetNumSetSendCodecs());
+}
+
+// Test that if clockrate is not 48000 for opus, we fail.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusBadClockrate) {
EXPECT_TRUE(SetupEngine());
- int channel_num = voe_.GetLastChannel();
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kOpusCodec);
codecs[0].bitrate = 0;
codecs[0].clockrate = 50000;
- EXPECT_TRUE(channel_->SetSendCodecs(codecs));
- webrtc::CodecInst gcodec;
- EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
- EXPECT_STREQ("PCMU", gcodec.plname);
+ EXPECT_FALSE(channel_->SetSendCodecs(codecs));
}
-// Test that if channels=0 for opus, we fail by falling back to PCMU.
+// Test that if channels=0 for opus, we fail.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad0ChannelsNoStereo) {
EXPECT_TRUE(SetupEngine());
- int channel_num = voe_.GetLastChannel();
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kOpusCodec);
codecs[0].bitrate = 0;
codecs[0].channels = 0;
- EXPECT_TRUE(channel_->SetSendCodecs(codecs));
- webrtc::CodecInst gcodec;
- EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
- EXPECT_STREQ("PCMU", gcodec.plname);
+ EXPECT_FALSE(channel_->SetSendCodecs(codecs));
}
-// Test that if channels=0 for opus, we fail by falling back to PCMU.
+// Test that if channels=0 for opus, we fail.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad0Channels1Stereo) {
EXPECT_TRUE(SetupEngine());
- int channel_num = voe_.GetLastChannel();
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kOpusCodec);
codecs[0].bitrate = 0;
codecs[0].channels = 0;
codecs[0].params["stereo"] = "1";
- EXPECT_TRUE(channel_->SetSendCodecs(codecs));
- webrtc::CodecInst gcodec;
- EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
- EXPECT_STREQ("PCMU", gcodec.plname);
+ EXPECT_FALSE(channel_->SetSendCodecs(codecs));
}
// Test that if channel is 1 for opus and there's no stereo, we fail.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpus1ChannelNoStereo) {
EXPECT_TRUE(SetupEngine());
- int channel_num = voe_.GetLastChannel();
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kOpusCodec);
codecs[0].bitrate = 0;
codecs[0].channels = 1;
- EXPECT_TRUE(channel_->SetSendCodecs(codecs));
- webrtc::CodecInst gcodec;
- EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
- EXPECT_STREQ("PCMU", gcodec.plname);
+ EXPECT_FALSE(channel_->SetSendCodecs(codecs));
}
// Test that if channel is 1 for opus and stereo=0, we fail.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad1Channel0Stereo) {
EXPECT_TRUE(SetupEngine());
- int channel_num = voe_.GetLastChannel();
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kOpusCodec);
codecs[0].bitrate = 0;
codecs[0].channels = 1;
codecs[0].params["stereo"] = "0";
- EXPECT_TRUE(channel_->SetSendCodecs(codecs));
- webrtc::CodecInst gcodec;
- EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
- EXPECT_STREQ("PCMU", gcodec.plname);
+ EXPECT_FALSE(channel_->SetSendCodecs(codecs));
}
// Test that if channel is 1 for opus and stereo=1, we fail.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad1Channel1Stereo) {
EXPECT_TRUE(SetupEngine());
- int channel_num = voe_.GetLastChannel();
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kOpusCodec);
codecs[0].bitrate = 0;
codecs[0].channels = 1;
codecs[0].params["stereo"] = "1";
- EXPECT_TRUE(channel_->SetSendCodecs(codecs));
- webrtc::CodecInst gcodec;
- EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
- EXPECT_STREQ("PCMU", gcodec.plname);
+ EXPECT_FALSE(channel_->SetSendCodecs(codecs));
}
// Test that with bitrate=0 and no stereo,
@@ -1074,17 +1144,117 @@ TEST_F(WebRtcVoiceEngineTestFake, AddRecvStreamEnableNack) {
EXPECT_TRUE(voe_.GetNACK(channel_num));
}
+#ifdef USE_WEBRTC_DEV_BRANCH
+// Test that without useinbandfec, Opus FEC is off.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecNoOpusFec) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kOpusCodec);
+ codecs[0].bitrate = 0;
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_FALSE(voe_.GetCodecFEC(channel_num));
+}
+
+// Test that with useinbandfec=0, Opus FEC is off.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusDisableFec) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kOpusCodec);
+ codecs[0].bitrate = 0;
+ codecs[0].params["useinbandfec"] = "0";
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_FALSE(voe_.GetCodecFEC(channel_num));
+ webrtc::CodecInst gcodec;
+ EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
+ EXPECT_STREQ("opus", gcodec.plname);
+ EXPECT_EQ(1, gcodec.channels);
+ EXPECT_EQ(32000, gcodec.rate);
+}
+
+// Test that with useinbandfec=1, Opus FEC is on.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusEnableFec) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kOpusCodec);
+ codecs[0].bitrate = 0;
+ codecs[0].params["useinbandfec"] = "1";
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(voe_.GetCodecFEC(channel_num));
+ webrtc::CodecInst gcodec;
+ EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
+ EXPECT_STREQ("opus", gcodec.plname);
+ EXPECT_EQ(1, gcodec.channels);
+ EXPECT_EQ(32000, gcodec.rate);
+}
+
+// Test that with useinbandfec=1, stereo=1, Opus FEC is on.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusEnableFecStereo) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kOpusCodec);
+ codecs[0].bitrate = 0;
+ codecs[0].params["stereo"] = "1";
+ codecs[0].params["useinbandfec"] = "1";
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(voe_.GetCodecFEC(channel_num));
+ webrtc::CodecInst gcodec;
+ EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
+ EXPECT_STREQ("opus", gcodec.plname);
+ EXPECT_EQ(2, gcodec.channels);
+ EXPECT_EQ(64000, gcodec.rate);
+}
+
+// Test that with non-Opus, codec FEC is off.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecIsacNoFec) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kIsacCodec);
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_FALSE(voe_.GetCodecFEC(channel_num));
+}
+#endif // USE_WEBRTC_DEV_BRANCH
+
+// Test AudioOptions controls whether opus FEC is supported in codec list.
+TEST_F(WebRtcVoiceEngineTestFake, OpusFecViaOptions) {
+ EXPECT_TRUE(SetupEngine());
+ std::vector<cricket::AudioCodec> codecs = engine_.codecs();
+ int value;
+ for (std::vector<cricket::AudioCodec>::const_iterator it = codecs.begin();
+ it != codecs.end(); ++it) {
+ if (_stricmp(it->name.c_str(), cricket::kOpusCodecName) == 0) {
+ EXPECT_FALSE(it->GetParam(cricket::kCodecParamUseInbandFec, &value));
+ }
+ }
+
+ cricket::AudioOptions options;
+ options.opus_fec.Set(true);
+ EXPECT_TRUE(engine_.SetOptions(options));
+ codecs = engine_.codecs();
+ for (std::vector<cricket::AudioCodec>::const_iterator it = codecs.begin();
+ it != codecs.end(); ++it) {
+ if (_stricmp(it->name.c_str(), cricket::kOpusCodecName) == 0) {
+ EXPECT_TRUE(it->GetParam(cricket::kCodecParamUseInbandFec, &value));
+ EXPECT_EQ(1, value);
+ }
+ }
+}
+
// Test that we can apply CELT with stereo mode but fail with mono mode.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCelt) {
EXPECT_TRUE(SetupEngine());
int channel_num = voe_.GetLastChannel();
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kCeltCodec);
- codecs.push_back(kPcmuCodec);
+ codecs.push_back(kIsacCodec);
codecs[0].id = 96;
codecs[0].channels = 2;
codecs[0].bitrate = 96000;
- codecs[1].bitrate = 96000;
+ codecs[1].bitrate = 64000;
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
webrtc::CodecInst gcodec;
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
@@ -1096,10 +1266,10 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCelt) {
codecs[0].channels = 1;
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
- EXPECT_EQ(0, gcodec.pltype);
+ EXPECT_EQ(103, gcodec.pltype);
EXPECT_EQ(1, gcodec.channels);
EXPECT_EQ(64000, gcodec.rate);
- EXPECT_STREQ("PCMU", gcodec.plname);
+ EXPECT_STREQ("ISAC", gcodec.plname);
}
// Test that we can switch back and forth between CELT and ISAC with CN.
@@ -1179,21 +1349,49 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBitrate) {
EXPECT_EQ(32000, gcodec.rate);
}
-// Test that we fall back to PCMU if no codecs are specified.
+// Test that we fail if no codecs are specified.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsNoCodecs) {
EXPECT_TRUE(SetupEngine());
+ std::vector<cricket::AudioCodec> codecs;
+ EXPECT_FALSE(channel_->SetSendCodecs(codecs));
+}
+
+// Test that we can set send codecs even with telephone-event codec as the first
+// one on the list.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsDTMFOnTop) {
+ EXPECT_TRUE(SetupEngine());
int channel_num = voe_.GetLastChannel();
std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kTelephoneEventCodec);
+ codecs.push_back(kIsacCodec);
+ codecs.push_back(kPcmuCodec);
+ codecs[0].id = 98; // DTMF
+ codecs[1].id = 96;
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
webrtc::CodecInst gcodec;
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
- EXPECT_EQ(0, gcodec.pltype);
- EXPECT_STREQ("PCMU", gcodec.plname);
- EXPECT_FALSE(voe_.GetVAD(channel_num));
- EXPECT_FALSE(voe_.GetFEC(channel_num));
- EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
- EXPECT_EQ(105, voe_.GetSendCNPayloadType(channel_num, true));
- EXPECT_EQ(106, voe_.GetSendTelephoneEventPayloadType(channel_num));
+ EXPECT_EQ(96, gcodec.pltype);
+ EXPECT_STREQ("ISAC", gcodec.plname);
+ EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
+}
+
+// Test that we can set send codecs even with CN codec as the first
+// one on the list.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCNOnTop) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kCn16000Codec);
+ codecs.push_back(kIsacCodec);
+ codecs.push_back(kPcmuCodec);
+ codecs[0].id = 98; // wideband CN
+ codecs[1].id = 96;
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ webrtc::CodecInst gcodec;
+ EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
+ EXPECT_EQ(96, gcodec.pltype);
+ EXPECT_STREQ("ISAC", gcodec.plname);
+ EXPECT_EQ(98, voe_.GetSendCNPayloadType(channel_num, true));
}
// Test that we set VAD and DTMF types correctly as caller.
@@ -1217,7 +1415,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCNandDTMFAsCaller) {
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
EXPECT_TRUE(voe_.GetVAD(channel_num));
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true));
EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
@@ -1250,7 +1448,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCNandDTMFAsCallee) {
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
EXPECT_TRUE(voe_.GetVAD(channel_num));
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true));
EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
@@ -1314,13 +1512,13 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCaseInsensitive) {
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
EXPECT_TRUE(voe_.GetVAD(channel_num));
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true));
EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
}
-// Test that we set up FEC correctly as caller.
+// Test that we set up RED correctly as caller.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDAsCaller) {
EXPECT_TRUE(SetupEngine());
int channel_num = voe_.GetLastChannel();
@@ -1336,11 +1534,11 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDAsCaller) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_TRUE(voe_.GetFEC(channel_num));
- EXPECT_EQ(127, voe_.GetSendFECPayloadType(channel_num));
+ EXPECT_TRUE(voe_.GetRED(channel_num));
+ EXPECT_EQ(127, voe_.GetSendREDPayloadType(channel_num));
}
-// Test that we set up FEC correctly as callee.
+// Test that we set up RED correctly as callee.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDAsCallee) {
EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
channel_ = engine_.CreateChannel();
@@ -1361,11 +1559,11 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDAsCallee) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_TRUE(voe_.GetFEC(channel_num));
- EXPECT_EQ(127, voe_.GetSendFECPayloadType(channel_num));
+ EXPECT_TRUE(voe_.GetRED(channel_num));
+ EXPECT_EQ(127, voe_.GetSendREDPayloadType(channel_num));
}
-// Test that we set up FEC correctly if params are omitted.
+// Test that we set up RED correctly if params are omitted.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDNoParams) {
EXPECT_TRUE(SetupEngine());
int channel_num = voe_.GetLastChannel();
@@ -1380,8 +1578,8 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDNoParams) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_TRUE(voe_.GetFEC(channel_num));
- EXPECT_EQ(127, voe_.GetSendFECPayloadType(channel_num));
+ EXPECT_TRUE(voe_.GetRED(channel_num));
+ EXPECT_EQ(127, voe_.GetSendREDPayloadType(channel_num));
}
// Test that we ignore RED if the parameters aren't named the way we expect.
@@ -1400,7 +1598,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBadRED1) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
}
// Test that we ignore RED if it uses different primary/secondary encoding.
@@ -1419,7 +1617,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBadRED2) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
}
// Test that we ignore RED if it uses more than 2 encodings.
@@ -1438,7 +1636,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBadRED3) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
}
// Test that we ignore RED if it has bogus codec ids.
@@ -1457,7 +1655,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBadRED4) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
}
// Test that we ignore RED if it refers to a codec that is not present.
@@ -1476,38 +1674,25 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBadRED5) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
}
-// Test that we support setting an empty list of recv header extensions.
-TEST_F(WebRtcVoiceEngineTestFake, SetRecvRtpHeaderExtensions) {
- EXPECT_TRUE(SetupEngine());
- std::vector<cricket::RtpHeaderExtension> extensions;
- int channel_num = voe_.GetLastChannel();
- bool enable = false;
- unsigned char id = 0;
-
- // An empty list shouldn't cause audio-level headers to be enabled.
- EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
- EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
- channel_num, enable, id));
- EXPECT_FALSE(enable);
-
- // Nor should indicating we can receive the audio-level header.
- extensions.push_back(cricket::RtpHeaderExtension(
- "urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8));
- EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
- EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
- channel_num, enable, id));
- EXPECT_FALSE(enable);
+// Test support for audio level header extension.
+TEST_F(WebRtcVoiceEngineTestFake, SendAudioLevelHeaderExtensions) {
+ TestSetSendRtpHeaderExtensions(kRtpAudioLevelHeaderExtension);
+}
+#ifdef USE_WEBRTC_DEV_BRANCH
+TEST_F(WebRtcVoiceEngineTestFake, RecvAudioLevelHeaderExtensions) {
+ TestSetRecvRtpHeaderExtensions(kRtpAudioLevelHeaderExtension);
}
+#endif // USE_WEBRTC_DEV_BRANCH
-// Test that we support setting certain send header extensions.
-TEST_F(WebRtcVoiceEngineTestFake, SetSendRtpHeaderExtensions) {
- EXPECT_TRUE(SetupEngine());
- std::vector<cricket::RtpHeaderExtension> extensions;
- int channel_num = voe_.GetLastChannel();
- TestSetSendRtpHeaderExtensions(channel_num);
+// Test support for absolute send time header extension.
+TEST_F(WebRtcVoiceEngineTestFake, SendAbsoluteSendTimeHeaderExtensions) {
+ TestSetSendRtpHeaderExtensions(kRtpAbsoluteSenderTimeHeaderExtension);
+}
+TEST_F(WebRtcVoiceEngineTestFake, RecvAbsoluteSendTimeHeaderExtensions) {
+ TestSetRecvRtpHeaderExtensions(kRtpAbsoluteSenderTimeHeaderExtension);
}
// Test that we can create a channel and start sending/playing out on it.
@@ -1641,11 +1826,15 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrcs4[i])));
}
-
+ // Create a receive stream to check that none of the send streams end up in
+ // the receive stream stats.
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc2)));
// We need send codec to be set to get all stats.
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kPcmuCodec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
cricket::VoiceMediaInfo info;
EXPECT_EQ(true, channel_->GetStats(&info));
@@ -1662,29 +1851,19 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].ext_seqnum);
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].rtt_ms);
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].jitter_ms);
+ EXPECT_EQ(kPcmuCodec.name, info.senders[i].codec_name);
}
- EXPECT_EQ(1u, info.receivers.size());
-}
-
-// Test that we support setting certain send header extensions on multiple
-// send streams.
-TEST_F(WebRtcVoiceEngineTestFake,
- SetSendRtpHeaderExtensionsWithMultpleSendStreams) {
- SetupForMultiSendStream();
-
- static const uint32 kSsrcs4[] = {1, 2, 3, 4};
- // Create send streams.
- for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
- EXPECT_TRUE(channel_->AddSendStream(
- cricket::StreamParams::CreateLegacy(kSsrcs4[i])));
- }
+ EXPECT_EQ(0u, info.receivers.size());
+ DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
+ EXPECT_EQ(true, channel_->GetStats(&info));
- // Test SendRtpHeaderExtensions on each send channel.
- for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
- int channel_num = voe_.GetChannelFromLocalSsrc(kSsrcs4[i]);
- TestSetSendRtpHeaderExtensions(channel_num);
- }
+ EXPECT_EQ(1u, info.receivers.size());
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].bytes_rcvd);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_rcvd);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_lost);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].ext_seqnum);
+ EXPECT_EQ(kPcmuCodec.name, info.receivers[0].codec_name);
}
// Test that we can add and remove receive streams, and do proper send/playout.
@@ -1971,9 +2150,14 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrc) {
TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
// Setup. We need send codec to be set to get all stats.
EXPECT_TRUE(SetupEngine());
+ // SetupEngine adds a send stream with kSsrc1, so the receive stream has to
+ // use a different SSRC.
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc2)));
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kPcmuCodec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
cricket::VoiceMediaInfo info;
EXPECT_EQ(true, channel_->GetStats(&info));
@@ -1987,6 +2171,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
EXPECT_EQ(cricket::kIntStatValue, info.senders[0].ext_seqnum);
EXPECT_EQ(cricket::kIntStatValue, info.senders[0].rtt_ms);
EXPECT_EQ(cricket::kIntStatValue, info.senders[0].jitter_ms);
+ EXPECT_EQ(kPcmuCodec.name, info.senders[0].codec_name);
// TODO(sriniv): Add testing for more fields. These are not populated
// in FakeWebrtcVoiceEngine yet.
// EXPECT_EQ(cricket::kIntStatValue, info.senders[0].audio_level);
@@ -1996,8 +2181,17 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
// EXPECT_EQ(cricket::kIntStatValue,
// info.senders[0].echo_return_loss_enhancement);
+ EXPECT_EQ(0u, info.receivers.size());
+ DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
+ EXPECT_EQ(true, channel_->GetStats(&info));
EXPECT_EQ(1u, info.receivers.size());
- // TODO(sriniv): Add testing for receiver fields.
+
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].bytes_rcvd);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_rcvd);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_lost);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].ext_seqnum);
+ EXPECT_EQ(kPcmuCodec.name, info.receivers[0].codec_name);
+ // TODO(sriniv): Add testing for more receiver fields.
}
// Test that we can set the outgoing SSRC properly with multiple streams.
@@ -2586,7 +2780,6 @@ TEST_F(WebRtcVoiceEngineTestFake, InitDoesNotOverwriteDefaultAgcConfig) {
EXPECT_EQ(set_config.limiterEnable, config.limiterEnable);
}
-
TEST_F(WebRtcVoiceEngineTestFake, SetOptionOverridesViaChannels) {
EXPECT_TRUE(SetupEngine());
talk_base::scoped_ptr<cricket::VoiceMediaChannel> channel1(
@@ -2718,6 +2911,10 @@ TEST_F(WebRtcVoiceEngineTestFake, TestSetDscpOptions) {
options.dscp.Set(true);
EXPECT_TRUE(channel->SetOptions(options));
EXPECT_EQ(talk_base::DSCP_EF, network_interface->dscp());
+ // Verify previous value is not modified if dscp option is not set.
+ cricket::AudioOptions options1;
+ EXPECT_TRUE(channel->SetOptions(options1));
+ EXPECT_EQ(talk_base::DSCP_EF, network_interface->dscp());
options.dscp.Set(false);
EXPECT_TRUE(channel->SetOptions(options));
EXPECT_EQ(talk_base::DSCP_DEFAULT, network_interface->dscp());
@@ -2782,7 +2979,6 @@ TEST_F(WebRtcVoiceEngineTestFake, SetOutputScaling) {
EXPECT_DOUBLE_EQ(1, right);
}
-
// Tests for the actual WebRtc VoE library.
// Tests that the library initializes and shuts down properly.
@@ -2891,8 +3087,6 @@ TEST(WebRtcVoiceEngineTest, HasCorrectCodecs) {
EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(0, "", 0, 0, 2, 0)));
EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(0, "", 5000, 0, 1, 0)));
EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(0, "", 0, 5000, 1, 0)));
- // Check that there aren't any extra codecs lying around.
- EXPECT_EQ(13U, engine.codecs().size());
// Verify the payload id of common audio codecs, including CN, ISAC, and G722.
for (std::vector<cricket::AudioCodec>::const_iterator it =
engine.codecs().begin(); it != engine.codecs().end(); ++it) {
@@ -2983,39 +3177,3 @@ TEST(WebRtcVoiceEngineTest, CoInitialize) {
}
#endif
-
-TEST_F(WebRtcVoiceEngineTestFake, SetExperimentalAcm) {
- EXPECT_TRUE(SetupEngine());
-
- // By default experimental ACM should not be used.
- int media_channel = engine_.CreateMediaVoiceChannel();
- ASSERT_GE(media_channel, 0);
- EXPECT_FALSE(voe_.IsUsingExperimentalAcm(media_channel));
-
- int soundclip_channel = engine_.CreateSoundclipVoiceChannel();
- ASSERT_GE(soundclip_channel, 0);
- EXPECT_FALSE(voe_sc_.IsUsingExperimentalAcm(soundclip_channel));
-
- // Set options to use experimental ACM.
- cricket::AudioOptions options;
- options.experimental_acm.Set(true);
- ASSERT_TRUE(engine_.SetOptions(options));
- media_channel = engine_.CreateMediaVoiceChannel();
- ASSERT_GE(media_channel, 0);
- EXPECT_TRUE(voe_.IsUsingExperimentalAcm(media_channel));
-
- soundclip_channel = engine_.CreateSoundclipVoiceChannel();
- ASSERT_GE(soundclip_channel, 0);
- EXPECT_TRUE(voe_sc_.IsUsingExperimentalAcm(soundclip_channel));
-
- // Set option to use legacy ACM.
- options.experimental_acm.Set(false);
- ASSERT_TRUE(engine_.SetOptions(options));
- media_channel = engine_.CreateMediaVoiceChannel();
- ASSERT_GE(media_channel, 0);
- EXPECT_FALSE(voe_.IsUsingExperimentalAcm(media_channel));
-
- soundclip_channel = engine_.CreateSoundclipVoiceChannel();
- ASSERT_GE(soundclip_channel, 0);
- EXPECT_FALSE(voe_sc_.IsUsingExperimentalAcm(soundclip_channel));
-}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket.cc b/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket.cc
index 67178f4985e..8bcfa3ad272 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket.cc
@@ -27,7 +27,7 @@
#include "talk/p2p/base/asyncstuntcpsocket.h"
-#include <cstring>
+#include <string.h>
#include "talk/base/common.h"
#include "talk/base/logging.h"
@@ -65,9 +65,8 @@ AsyncStunTCPSocket::AsyncStunTCPSocket(
: talk_base::AsyncTCPSocketBase(socket, listen, kBufSize) {
}
-// TODO(mallinath) - Add support of setting DSCP code on AsyncSocket.
int AsyncStunTCPSocket::Send(const void *pv, size_t cb,
- talk_base::DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
if (cb > kBufSize || cb < kPacketLenSize + kPacketLenOffset) {
SetError(EMSGSIZE);
return -1;
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket.h b/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket.h
index ff748d1f287..bef8e980900 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket.h
@@ -48,7 +48,7 @@ class AsyncStunTCPSocket : public talk_base::AsyncTCPSocketBase {
virtual ~AsyncStunTCPSocket() {}
virtual int Send(const void* pv, size_t cb,
- talk_base::DiffServCodePoint dscp);
+ const talk_base::PacketOptions& options);
virtual void ProcessInput(char* data, size_t* len);
virtual void HandleIncomingConnection(talk_base::AsyncSocket* socket);
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket_unittest.cc
index c6a7b1b6fbc..f3261df52dc 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/asyncstuntcpsocket_unittest.cc
@@ -122,8 +122,9 @@ class AsyncStunTCPSocketTest : public testing::Test,
}
bool Send(const void* data, size_t len) {
+ talk_base::PacketOptions options;
size_t ret = send_socket_->Send(
- reinterpret_cast<const char*>(data), len, talk_base::DSCP_NO_CHANGE);
+ reinterpret_cast<const char*>(data), len, options);
vss_->ProcessMessagesUntilIdle();
return (ret == len);
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/candidate.h b/chromium/third_party/libjingle/source/talk/p2p/base/candidate.h
index 19eed8cc320..547725df830 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/candidate.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/candidate.h
@@ -28,11 +28,13 @@
#ifndef TALK_P2P_BASE_CANDIDATE_H_
#define TALK_P2P_BASE_CANDIDATE_H_
-#include <climits>
-#include <cmath>
+#include <limits.h>
+#include <math.h>
+
#include <string>
#include <sstream>
#include <iomanip>
+
#include "talk/base/basictypes.h"
#include "talk/base/socketaddress.h"
#include "talk/p2p/base/constants.h"
@@ -163,13 +165,30 @@ class Candidate {
return ToStringInternal(true);
}
- uint32 GetPriority(uint32 type_preference) const {
+ uint32 GetPriority(uint32 type_preference,
+ int network_adapter_preference) const {
// RFC 5245 - 4.1.2.1.
// priority = (2^24)*(type preference) +
// (2^8)*(local preference) +
// (2^0)*(256 - component ID)
+
+ // |local_preference| length is 2 bytes, 0-65535 inclusive.
+ // In our implemenation we will partion local_preference into
+ // 0 1
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | NIC Pref | Addr Pref |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // NIC Type - Type of the network adapter e.g. 3G/Wifi/Wired.
+ // Addr Pref - Address preference value as per RFC 3484.
+ // local preference is calculated as - NIC Type << 8 | Addr_Pref.
+
int addr_pref = IPAddressPrecedence(address_.ipaddr());
- return (type_preference << 24) | (addr_pref << 8) | (256 - component_);
+ int local_preference = (network_adapter_preference << 8) | addr_pref;
+
+ return (type_preference << 24) |
+ (local_preference << 8) |
+ (256 - component_);
}
private:
@@ -177,9 +196,9 @@ class Candidate {
std::ostringstream ost;
std::string address = sensitive ? address_.ToSensitiveString() :
address_.ToString();
- ost << "Cand[" << id_ << ":" << component_ << ":"
- << type_ << ":" << protocol_ << ":"
- << network_name_ << ":" << address << ":"
+ ost << "Cand[" << foundation_ << ":" << component_ << ":"
+ << protocol_ << ":" << priority_ << ":"
+ << address << ":" << type_ << ":" << related_address_ << ":"
<< username_ << ":" << password_ << "]";
return ost.str();
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/constants.cc b/chromium/third_party/libjingle/source/talk/p2p/base/constants.cc
index 27d43096b9d..2e57d9d18d6 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/constants.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/constants.cc
@@ -176,6 +176,10 @@ const int ICE_UFRAG_LENGTH = 16;
// Minimum password length of 22 characters as per RFC5245. We chose 24 because
// some internal systems expect password to be multiple of 4.
const int ICE_PWD_LENGTH = 24;
+const size_t ICE_UFRAG_MIN_LENGTH = 4;
+const size_t ICE_PWD_MIN_LENGTH = 22;
+const size_t ICE_UFRAG_MAX_LENGTH = 255;
+const size_t ICE_PWD_MAX_LENGTH = 256;
// TODO: This is media-specific, so might belong
// somewhere like media/base/constants.h
const int ICE_CANDIDATE_COMPONENT_RTP = 1;
@@ -202,7 +206,6 @@ const buzz::StaticQName QN_ADDRESS = { cricket::NS_EMPTY, "address" };
const buzz::StaticQName QN_USERNAME = { cricket::NS_EMPTY, "username" };
const buzz::StaticQName QN_PASSWORD = { cricket::NS_EMPTY, "password" };
const buzz::StaticQName QN_PREFERENCE = { cricket::NS_EMPTY, "preference" };
-const char GICE_CANDIDATE_TYPE_STUN[] = "stun";
const char GICE_CHANNEL_NAME_RTP[] = "rtp";
const char GICE_CHANNEL_NAME_RTCP[] = "rtcp";
const char GICE_CHANNEL_NAME_VIDEO_RTP[] = "video_rtp";
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/constants.h b/chromium/third_party/libjingle/source/talk/p2p/base/constants.h
index 99e006a0185..61dd815b381 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/constants.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/constants.h
@@ -178,6 +178,10 @@ extern const char ICE_CANDIDATE_TYPE_PEER_STUN[];
extern const char ICE_CANDIDATE_TYPE_SERVER_STUN[];
extern const int ICE_UFRAG_LENGTH;
extern const int ICE_PWD_LENGTH;
+extern const size_t ICE_UFRAG_MIN_LENGTH;
+extern const size_t ICE_PWD_MIN_LENGTH;
+extern const size_t ICE_UFRAG_MAX_LENGTH;
+extern const size_t ICE_PWD_MAX_LENGTH;
extern const int ICE_CANDIDATE_COMPONENT_RTP;
extern const int ICE_CANDIDATE_COMPONENT_RTCP;
extern const int ICE_CANDIDATE_COMPONENT_DEFAULT;
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransport.h b/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransport.h
index 7492171ee1e..6bef185ce89 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransport.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransport.h
@@ -66,8 +66,8 @@ class DtlsTransport : public Base {
return true;
}
- virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl*
- channel) {
+ virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel,
+ std::string* error_desc) {
talk_base::SSLFingerprint* local_fp =
Base::local_description()->identity_fingerprint.get();
@@ -79,30 +79,36 @@ class DtlsTransport : public Base {
identity_));
ASSERT(local_fp_tmp.get() != NULL);
if (!(*local_fp_tmp == *local_fp)) {
- LOG(LS_WARNING) << "Local fingerprint does not match identity";
- return false;
+ std::ostringstream desc;
+ desc << "Local fingerprint does not match identity. Expected: ";
+ desc << local_fp_tmp->ToString();
+ desc << " Got: " << local_fp->ToString();
+ return BadTransportDescription(desc.str(), error_desc);
}
} else {
- LOG(LS_WARNING)
- << "Local fingerprint provided but no identity available";
- return false;
+ return BadTransportDescription(
+ "Local fingerprint provided but no identity available.",
+ error_desc);
}
} else {
identity_ = NULL;
}
- if (!channel->SetLocalIdentity(identity_))
- return false;
+ if (!channel->SetLocalIdentity(identity_)) {
+ return BadTransportDescription("Failed to set local identity.",
+ error_desc);
+ }
// Apply the description in the base class.
- return Base::ApplyLocalTransportDescription_w(channel);
+ return Base::ApplyLocalTransportDescription_w(channel, error_desc);
}
- virtual bool NegotiateTransportDescription_w(ContentAction local_role) {
+ virtual bool NegotiateTransportDescription_w(ContentAction local_role,
+ std::string* error_desc) {
if (!Base::local_description() || !Base::remote_description()) {
- LOG(LS_INFO) << "Local and Remote description must be set before "
- << "transport descriptions are negotiated";
- return false;
+ const std::string msg = "Local and Remote description must be set before "
+ "transport descriptions are negotiated";
+ return BadTransportDescription(msg, error_desc);
}
talk_base::SSLFingerprint* local_fp =
@@ -144,8 +150,9 @@ class DtlsTransport : public Base {
bool is_remote_server = false;
if (local_role == CA_OFFER) {
if (local_connection_role != CONNECTIONROLE_ACTPASS) {
- LOG(LS_ERROR) << "Offerer must use actpass value for setup attribute";
- return false;
+ return BadTransportDescription(
+ "Offerer must use actpass value for setup attribute.",
+ error_desc);
}
if (remote_connection_role == CONNECTIONROLE_ACTIVE ||
@@ -153,25 +160,28 @@ class DtlsTransport : public Base {
remote_connection_role == CONNECTIONROLE_NONE) {
is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE);
} else {
- LOG(LS_ERROR) << "Answerer must use either active or passive value "
- << "for setup attribute";
- return false;
+ const std::string msg =
+ "Answerer must use either active or passive value "
+ "for setup attribute.";
+ return BadTransportDescription(msg, error_desc);
}
// If remote is NONE or ACTIVE it will act as client.
} else {
if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
remote_connection_role != CONNECTIONROLE_NONE) {
- LOG(LS_ERROR) << "Offerer must use actpass value for setup attribute";
- return false;
+ return BadTransportDescription(
+ "Offerer must use actpass value for setup attribute.",
+ error_desc);
}
if (local_connection_role == CONNECTIONROLE_ACTIVE ||
local_connection_role == CONNECTIONROLE_PASSIVE) {
is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE);
} else {
- LOG(LS_ERROR) << "Answerer must use either active or passive value "
- << "for setup attribute";
- return false;
+ const std::string msg =
+ "Answerer must use either active or passive value "
+ "for setup attribute.";
+ return BadTransportDescription(msg, error_desc);
}
// If local is passive, local will act as server.
@@ -181,9 +191,9 @@ class DtlsTransport : public Base {
talk_base::SSL_SERVER;
} else if (local_fp && (local_role == CA_ANSWER)) {
- LOG(LS_ERROR)
- << "Local fingerprint supplied when caller didn't offer DTLS";
- return false;
+ return BadTransportDescription(
+ "Local fingerprint supplied when caller didn't offer DTLS.",
+ error_desc);
} else {
// We are not doing DTLS
remote_fingerprint_.reset(new talk_base::SSLFingerprint(
@@ -191,7 +201,7 @@ class DtlsTransport : public Base {
}
// Now run the negotiation for the base class.
- return Base::NegotiateTransportDescription_w(local_role);
+ return Base::NegotiateTransportDescription_w(local_role, error_desc);
}
virtual DtlsTransportChannelWrapper* CreateTransportChannel(int component) {
@@ -216,12 +226,13 @@ class DtlsTransport : public Base {
private:
virtual bool ApplyNegotiatedTransportDescription_w(
- TransportChannelImpl* channel) {
+ TransportChannelImpl* channel,
+ std::string* error_desc) {
// Set ssl role. Role must be set before fingerprint is applied, which
// initiates DTLS setup.
if (!channel->SetSslRole(secure_role_)) {
- LOG(LS_INFO) << "Failed to set ssl role for the channel.";
- return false;
+ return BadTransportDescription("Failed to set ssl role for the channel.",
+ error_desc);
}
// Apply remote fingerprint.
if (!channel->SetRemoteFingerprint(
@@ -229,9 +240,10 @@ class DtlsTransport : public Base {
reinterpret_cast<const uint8 *>(remote_fingerprint_->
digest.data()),
remote_fingerprint_->digest.length())) {
- return false;
+ return BadTransportDescription("Failed to apply remote fingerprint.",
+ error_desc);
}
- return Base::ApplyNegotiatedTransportDescription_w(channel);
+ return Base::ApplyNegotiatedTransportDescription_w(channel, error_desc);
}
talk_base::SSLIdentity* identity_;
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel.cc b/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel.cc
index 472299959a0..416e6e93286 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel.cc
@@ -42,7 +42,6 @@ namespace cricket {
static const size_t kDtlsRecordHeaderLen = 13;
static const size_t kMaxDtlsPacketLen = 2048;
static const size_t kMinRtpPacketLen = 12;
-static const size_t kDefaultVideoAndDataCryptos = 1;
static bool IsDtlsPacket(const char* data, size_t len) {
const uint8* u = reinterpret_cast<const uint8*>(data);
@@ -71,8 +70,9 @@ talk_base::StreamResult StreamInterfaceChannel::Write(const void* data,
int* error) {
// Always succeeds, since this is an unreliable transport anyway.
// TODO: Should this block if channel_'s temporarily unwritable?
- channel_->SendPacket(
- static_cast<const char*>(data), data_len, talk_base::DSCP_NO_CHANGE);
+ talk_base::PacketOptions packet_options;
+ channel_->SendPacket(static_cast<const char*>(data), data_len,
+ packet_options);
if (written) {
*written = data_len;
}
@@ -124,6 +124,8 @@ DtlsTransportChannelWrapper::DtlsTransportChannelWrapper(
&DtlsTransportChannelWrapper::OnRoleConflict);
channel_->SignalRouteChange.connect(this,
&DtlsTransportChannelWrapper::OnRouteChange);
+ channel_->SignalConnectionRemoved.connect(this,
+ &DtlsTransportChannelWrapper::OnConnectionRemoved);
}
DtlsTransportChannelWrapper::~DtlsTransportChannelWrapper() {
@@ -154,14 +156,15 @@ void DtlsTransportChannelWrapper::Reset() {
bool DtlsTransportChannelWrapper::SetLocalIdentity(
talk_base::SSLIdentity* identity) {
- if (dtls_state_ == STATE_OPEN && identity == local_identity_) {
- return true;
- }
-
- // TODO(ekr@rtfm.com): Forbid this if Connect() has been called.
if (dtls_state_ != STATE_NONE) {
- LOG_J(LS_ERROR, this) << "Can't set DTLS local identity in this state";
- return false;
+ if (identity == local_identity_) {
+ // This may happen during renegotiation.
+ LOG_J(LS_INFO, this) << "Ignoring identical DTLS identity";
+ return true;
+ } else {
+ LOG_J(LS_ERROR, this) << "Can't change DTLS local identity in this state";
+ return false;
+ }
}
if (identity) {
@@ -208,8 +211,11 @@ bool DtlsTransportChannelWrapper::SetRemoteFingerprint(
talk_base::Buffer remote_fingerprint_value(digest, digest_len);
- if ((dtls_state_ == STATE_OPEN) &&
- (remote_fingerprint_value_ == remote_fingerprint_value)) {
+ if (dtls_state_ != STATE_NONE &&
+ remote_fingerprint_value_ == remote_fingerprint_value &&
+ !digest_alg.empty()) {
+ // This may happen during renegotiation.
+ LOG_J(LS_INFO, this) << "Ignoring identical remote DTLS fingerprint";
return true;
}
@@ -339,9 +345,9 @@ bool DtlsTransportChannelWrapper::GetSrtpCipher(std::string* cipher) {
// Called from upper layers to send a media packet.
-int DtlsTransportChannelWrapper::SendPacket(const char* data, size_t size,
- talk_base::DiffServCodePoint dscp,
- int flags) {
+int DtlsTransportChannelWrapper::SendPacket(
+ const char* data, size_t size,
+ const talk_base::PacketOptions& options, int flags) {
int result = -1;
switch (dtls_state_) {
@@ -361,11 +367,11 @@ int DtlsTransportChannelWrapper::SendPacket(const char* data, size_t size,
if (flags & PF_SRTP_BYPASS) {
ASSERT(!srtp_ciphers_.empty());
if (!IsRtpPacket(data, size)) {
- result = false;
+ result = -1;
break;
}
- result = channel_->SendPacket(data, size, dscp);
+ result = channel_->SendPacket(data, size, options);
} else {
result = (dtls_->WriteAll(data, size, NULL, NULL) ==
talk_base::SR_SUCCESS) ? static_cast<int>(size) : -1;
@@ -373,7 +379,7 @@ int DtlsTransportChannelWrapper::SendPacket(const char* data, size_t size,
break;
// Not doing DTLS.
case STATE_NONE:
- result = channel_->SendPacket(data, size, dscp);
+ result = channel_->SendPacket(data, size, options);
break;
case STATE_CLOSED: // Can't send anything when we're closed.
@@ -621,4 +627,10 @@ void DtlsTransportChannelWrapper::OnRouteChange(
SignalRouteChange(this, candidate);
}
+void DtlsTransportChannelWrapper::OnConnectionRemoved(
+ TransportChannelImpl* channel) {
+ ASSERT(channel == channel_);
+ SignalConnectionRemoved(this);
+}
+
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel.h b/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel.h
index d6b73467486..232d400c652 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel.h
@@ -127,6 +127,9 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl {
virtual IceRole GetIceRole() const {
return channel_->GetIceRole();
}
+ virtual size_t GetConnectionCount() const {
+ return channel_->GetConnectionCount();
+ }
virtual bool SetLocalIdentity(talk_base::SSLIdentity *identity);
virtual bool GetLocalIdentity(talk_base::SSLIdentity** identity) const;
@@ -137,7 +140,7 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl {
// Called to send a packet (via DTLS, if turned on).
virtual int SendPacket(const char* data, size_t size,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
int flags);
// TransportChannel calls that we forward to the wrapped transport.
@@ -193,6 +196,9 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl {
virtual void SetIceTiebreaker(uint64 tiebreaker) {
channel_->SetIceTiebreaker(tiebreaker);
}
+ virtual bool GetIceProtocolType(IceProtocolType* type) const {
+ return channel_->GetIceProtocolType(type);
+ }
virtual void SetIceProtocolType(IceProtocolType type) {
channel_->SetIceProtocolType(type);
}
@@ -236,6 +242,7 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl {
void OnCandidatesAllocationDone(TransportChannelImpl* channel);
void OnRoleConflict(TransportChannelImpl* channel);
void OnRouteChange(TransportChannel* channel, const Candidate& candidate);
+ void OnConnectionRemoved(TransportChannelImpl* channel);
Transport* transport_; // The transport_ that created us.
talk_base::Thread* worker_thread_; // Everything should occur on this thread.
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel_unittest.cc
index 1fd82d71073..5727ac4cf7b 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/dtlstransportchannel_unittest.cc
@@ -185,14 +185,14 @@ class DtlsTestClient : public sigslot::has_slots<> {
// content action is CA_ANSWER.
if (action == cricket::CA_OFFER) {
ASSERT_TRUE(transport_->SetLocalTransportDescription(
- local_desc, cricket::CA_OFFER));
+ local_desc, cricket::CA_OFFER, NULL));
ASSERT_EQ(expect_success, transport_->SetRemoteTransportDescription(
- remote_desc, cricket::CA_ANSWER));
+ remote_desc, cricket::CA_ANSWER, NULL));
} else {
ASSERT_TRUE(transport_->SetRemoteTransportDescription(
- remote_desc, cricket::CA_OFFER));
+ remote_desc, cricket::CA_OFFER, NULL));
ASSERT_EQ(expect_success, transport_->SetLocalTransportDescription(
- local_desc, cricket::CA_ANSWER));
+ local_desc, cricket::CA_ANSWER, NULL));
}
negotiated_dtls_ = (local_identity && remote_identity);
}
@@ -245,14 +245,26 @@ class DtlsTestClient : public sigslot::has_slots<> {
// Only set the bypass flag if we've activated DTLS.
int flags = (identity_.get() && srtp) ? cricket::PF_SRTP_BYPASS : 0;
+ talk_base::PacketOptions packet_options;
int rv = channels_[channel]->SendPacket(
- packet.get(), size, talk_base::DSCP_NO_CHANGE, flags);
+ packet.get(), size, packet_options, flags);
ASSERT_GT(rv, 0);
ASSERT_EQ(size, static_cast<size_t>(rv));
++sent;
} while (sent < count);
}
+ int SendInvalidSrtpPacket(size_t channel, size_t size) {
+ ASSERT(channel < channels_.size());
+ talk_base::scoped_ptr<char[]> packet(new char[size]);
+ // Fill the packet with 0 to form an invalid SRTP packet.
+ memset(packet.get(), 0, size);
+
+ talk_base::PacketOptions packet_options;
+ return channels_[channel]->SendPacket(
+ packet.get(), size, packet_options, cricket::PF_SRTP_BYPASS);
+ }
+
void ExpectPackets(size_t channel, size_t size) {
packet_size_ = size;
received_.clear();
@@ -623,6 +635,16 @@ TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtp) {
TestTransfer(0, 1000, 100, true);
}
+// Connect with DTLS-SRTP, transfer an invalid SRTP packet, and expects -1
+// returned.
+TEST_F(DtlsTransportChannelTest, TestTransferDtlsInvalidSrtpPacket) {
+ MAYBE_SKIP_TEST(HaveDtls);
+ PrepareDtls(true, true);
+ PrepareDtlsSrtp(true, true);
+ ASSERT_TRUE(Connect());
+ int result = client1_.SendInvalidSrtpPacket(0, 100);
+ ASSERT_EQ(-1, result);
+}
// Connect with DTLS. A does DTLS-SRTP but B does not.
TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtpRejected) {
@@ -754,6 +776,25 @@ TEST_F(DtlsTransportChannelTest, TestDtlsReOfferWithDifferentSetupAttr) {
TestTransfer(1, 1000, 100, true);
}
+// Test that re-negotiation can be started before the clients become connected
+// in the first negotiation.
+TEST_F(DtlsTransportChannelTest, TestRenegotiateBeforeConnect) {
+ MAYBE_SKIP_TEST(HaveDtlsSrtp);
+ SetChannelCount(2);
+ PrepareDtls(true, true);
+ PrepareDtlsSrtp(true, true);
+ Negotiate();
+
+ Renegotiate(&client1_, cricket::CONNECTIONROLE_ACTPASS,
+ cricket::CONNECTIONROLE_ACTIVE, NF_REOFFER);
+ bool rv = client1_.Connect(&client2_);
+ EXPECT_TRUE(rv);
+ EXPECT_TRUE_WAIT(client1_.writable() && client2_.writable(), 10000);
+
+ TestTransfer(0, 1000, 100, true);
+ TestTransfer(1, 1000, 100, true);
+}
+
// Test Certificates state after negotiation but before connection.
TEST_F(DtlsTransportChannelTest, TestCertificatesBeforeConnect) {
MAYBE_SKIP_TEST(HaveDtls);
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/fakesession.h b/chromium/third_party/libjingle/source/talk/p2p/base/fakesession.h
index 2615f50dffe..f2c5b84d763 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/fakesession.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/fakesession.h
@@ -73,7 +73,8 @@ class FakeTransportChannel : public TransportChannelImpl,
ice_proto_(ICEPROTO_HYBRID),
remote_ice_mode_(ICEMODE_FULL),
dtls_fingerprint_("", NULL, 0),
- ssl_role_(talk_base::SSL_CLIENT) {
+ ssl_role_(talk_base::SSL_CLIENT),
+ connection_count_(0) {
}
~FakeTransportChannel() {
Reset();
@@ -100,7 +101,12 @@ class FakeTransportChannel : public TransportChannelImpl,
virtual void SetIceRole(IceRole role) { role_ = role; }
virtual IceRole GetIceRole() const { return role_; }
+ virtual size_t GetConnectionCount() const { return connection_count_; }
virtual void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; }
+ virtual bool GetIceProtocolType(IceProtocolType* type) const {
+ *type = ice_proto_;
+ return true;
+ }
virtual void SetIceProtocolType(IceProtocolType type) { ice_proto_ = type; }
virtual void SetIceCredentials(const std::string& ice_ufrag,
const std::string& ice_pwd) {
@@ -170,8 +176,15 @@ class FakeTransportChannel : public TransportChannelImpl,
}
}
+ void SetConnectionCount(size_t connection_count) {
+ size_t old_connection_count = connection_count_;
+ connection_count_ = connection_count;
+ if (connection_count_ < old_connection_count)
+ SignalConnectionRemoved(this);
+ }
+
virtual int SendPacket(const char* data, size_t len,
- talk_base::DiffServCodePoint dscp, int flags) {
+ const talk_base::PacketOptions& options, int flags) {
if (state_ != STATE_CONNECTED) {
return -1;
}
@@ -309,6 +322,7 @@ class FakeTransportChannel : public TransportChannelImpl,
IceMode remote_ice_mode_;
talk_base::SSLFingerprint dtls_fingerprint_;
talk_base::SSLRole ssl_role_;
+ size_t connection_count_;
};
// Fake transport class, which can be passed to anything that needs a Transport.
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc b/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc
index 38cc35445ea..887fc45efae 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc
@@ -167,7 +167,7 @@ P2PTransportChannel::P2PTransportChannel(const std::string& content_name,
pending_best_connection_(NULL),
sort_dirty_(false),
was_writable_(false),
- protocol_type_(ICEPROTO_GOOGLE),
+ protocol_type_(ICEPROTO_HYBRID),
remote_ice_mode_(ICEMODE_FULL),
ice_role_(ICEROLE_UNKNOWN),
tiebreaker_(0),
@@ -237,6 +237,11 @@ void P2PTransportChannel::SetIceTiebreaker(uint64 tiebreaker) {
tiebreaker_ = tiebreaker;
}
+bool P2PTransportChannel::GetIceProtocolType(IceProtocolType* type) const {
+ *type = protocol_type_;
+ return true;
+}
+
void P2PTransportChannel::SetIceProtocolType(IceProtocolType type) {
ASSERT(worker_thread_ == talk_base::Thread::Current());
@@ -465,9 +470,8 @@ void P2PTransportChannel::OnUnknownAddress(
}
} else {
// Create a new candidate with this address.
-
std::string type;
- if (protocol_type_ == ICEPROTO_RFC5245) {
+ if (port->IceProtocol() == ICEPROTO_RFC5245) {
type = PRFLX_PORT_TYPE;
} else {
// G-ICE doesn't support prflx candidate.
@@ -488,10 +492,11 @@ void P2PTransportChannel::OnUnknownAddress(
port->Network()->name(), 0U,
talk_base::ToString<uint32>(talk_base::ComputeCrc32(id)));
new_remote_candidate.set_priority(
- new_remote_candidate.GetPriority(ICE_TYPE_PREFERENCE_SRFLX));
+ new_remote_candidate.GetPriority(ICE_TYPE_PREFERENCE_SRFLX,
+ port->Network()->preference()));
}
- if (protocol_type_ == ICEPROTO_RFC5245) {
+ if (port->IceProtocol() == ICEPROTO_RFC5245) {
// RFC 5245
// If the source transport address of the request does not match any
// existing remote candidates, it represents a new peer reflexive remote
@@ -623,7 +628,7 @@ void P2PTransportChannel::OnCandidate(const Candidate& candidate) {
// Creates connections from all of the ports that we care about to the given
// remote candidate. The return value is true if we created a connection from
// the origin port.
-bool P2PTransportChannel::CreateConnections(const Candidate &remote_candidate,
+bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate,
PortInterface* origin_port,
bool readable) {
ASSERT(worker_thread_ == talk_base::Thread::Current());
@@ -642,14 +647,25 @@ bool P2PTransportChannel::CreateConnections(const Candidate &remote_candidate,
new_remote_candidate.set_password(remote_ice_pwd_);
}
+ // If we've already seen the new remote candidate (in the current candidate
+ // generation), then we shouldn't try creating connections for it.
+ // We either already have a connection for it, or we previously created one
+ // and then later pruned it. If we don't return, the channel will again
+ // re-create any connections that were previously pruned, which will then
+ // immediately be re-pruned, churning the network for no purpose.
+ // This only applies to candidates received over signaling (i.e. origin_port
+ // is NULL).
+ if (!origin_port && IsDuplicateRemoteCandidate(new_remote_candidate)) {
+ // return true to indicate success, without creating any new connections.
+ return true;
+ }
+
// Add a new connection for this candidate to every port that allows such a
// connection (i.e., if they have compatible protocols) and that does not
// already have a connection to an equivalent candidate. We must be careful
// to make sure that the origin port is included, even if it was pruned,
// since that may be the only port that can create this connection.
-
bool created = false;
-
std::vector<PortInterface *>::reverse_iterator it;
for (it = ports_.rbegin(); it != ports_.rend(); ++it) {
if (CreateConnection(*it, new_remote_candidate, origin_port, readable)) {
@@ -684,7 +700,11 @@ bool P2PTransportChannel::CreateConnection(PortInterface* port,
// It is not legal to try to change any of the parameters of an existing
// connection; however, the other side can send a duplicate candidate.
if (!remote_candidate.IsEquivalent(connection->remote_candidate())) {
- LOG(INFO) << "Attempt to change a remote candidate";
+ LOG(INFO) << "Attempt to change a remote candidate."
+ << " Existing remote candidate: "
+ << connection->remote_candidate().ToString()
+ << "New remote candidate: "
+ << remote_candidate.ToString();
return false;
}
} else {
@@ -734,6 +754,17 @@ uint32 P2PTransportChannel::GetRemoteCandidateGeneration(
return remote_candidate_generation_;
}
+// Check if remote candidate is already cached.
+bool P2PTransportChannel::IsDuplicateRemoteCandidate(
+ const Candidate& candidate) {
+ for (uint32 i = 0; i < remote_candidates_.size(); ++i) {
+ if (remote_candidates_[i].IsEquivalent(candidate)) {
+ return true;
+ }
+ }
+ return false;
+}
+
// Maintain our remote candidate list, adding this new remote one.
void P2PTransportChannel::RememberRemoteCandidate(
const Candidate& remote_candidate, PortInterface* origin_port) {
@@ -751,12 +782,9 @@ void P2PTransportChannel::RememberRemoteCandidate(
}
// Make sure this candidate is not a duplicate.
- for (uint32 i = 0; i < remote_candidates_.size(); ++i) {
- if (remote_candidates_[i].IsEquivalent(remote_candidate)) {
- LOG(INFO) << "Duplicate candidate: "
- << remote_candidate.address().ToSensitiveString();
- return;
- }
+ if (IsDuplicateRemoteCandidate(remote_candidate)) {
+ LOG(INFO) << "Duplicate candidate: " << remote_candidate.ToString();
+ return;
}
// Try this candidate for all future ports.
@@ -789,7 +817,7 @@ int P2PTransportChannel::SetOption(talk_base::Socket::Option opt, int value) {
// Send data to the other side, using our best connection.
int P2PTransportChannel::SendPacket(const char *data, size_t len,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
int flags) {
ASSERT(worker_thread_ == talk_base::Thread::Current());
if (flags != 0) {
@@ -801,7 +829,7 @@ int P2PTransportChannel::SendPacket(const char *data, size_t len,
return -1;
}
- int sent = best_connection_->Send(data, len, dscp);
+ int sent = best_connection_->Send(data, len, options);
if (sent <= 0) {
ASSERT(sent < 0);
error_ = best_connection_->GetError();
@@ -884,6 +912,15 @@ void P2PTransportChannel::SortConnections() {
// will be sorted.
UpdateConnectionStates();
+ if (protocol_type_ == ICEPROTO_HYBRID) {
+ // If we are in hybrid mode, we are not sending any ping requests, so there
+ // is no point in sorting the connections. In hybrid state, ports can have
+ // different protocol than hybrid and protocol may differ from one another.
+ // Instead just update the state of this channel
+ UpdateChannelState();
+ return;
+ }
+
// Any changes after this point will require a re-sort.
sort_dirty_ = false;
@@ -995,8 +1032,10 @@ void P2PTransportChannel::UpdateChannelState() {
bool readable = false;
for (uint32 i = 0; i < connections_.size(); ++i) {
- if (connections_[i]->read_state() == Connection::STATE_READABLE)
+ if (connections_[i]->read_state() == Connection::STATE_READABLE) {
readable = true;
+ break;
+ }
}
set_readable(readable);
}
@@ -1209,6 +1248,8 @@ void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) {
SwitchBestConnectionTo(NULL);
RequestSort();
}
+
+ SignalConnectionRemoved(this);
}
// When a port is destroyed remove it from our list of ports to use for
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h b/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h
index 6f287f369c6..09dabd56770 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h
@@ -79,6 +79,8 @@ class P2PTransportChannel : public TransportChannelImpl,
virtual void SetIceRole(IceRole role);
virtual IceRole GetIceRole() const { return ice_role_; }
virtual void SetIceTiebreaker(uint64 tiebreaker);
+ virtual size_t GetConnectionCount() const { return connections_.size(); }
+ virtual bool GetIceProtocolType(IceProtocolType* type) const;
virtual void SetIceProtocolType(IceProtocolType type);
virtual void SetIceCredentials(const std::string& ice_ufrag,
const std::string& ice_pwd);
@@ -92,7 +94,7 @@ class P2PTransportChannel : public TransportChannelImpl,
// From TransportChannel:
virtual int SendPacket(const char *data, size_t len,
- talk_base::DiffServCodePoint dscp, int flags);
+ const talk_base::PacketOptions& options, int flags);
virtual int SetOption(talk_base::Socket::Option opt, int value);
virtual int GetError() { return error_; }
virtual bool GetStats(std::vector<ConnectionInfo>* stats);
@@ -187,6 +189,7 @@ class P2PTransportChannel : public TransportChannelImpl,
bool FindConnection(cricket::Connection* connection) const;
uint32 GetRemoteCandidateGeneration(const Candidate& candidate);
+ bool IsDuplicateRemoteCandidate(const Candidate& candidate);
void RememberRemoteCandidate(const Candidate& remote_candidate,
PortInterface* origin_port);
bool IsPingable(Connection* conn);
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel_unittest.cc
index 3c24ded632a..498fde9dcaf 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel_unittest.cc
@@ -36,11 +36,13 @@
#include "talk/base/physicalsocketserver.h"
#include "talk/base/proxyserver.h"
#include "talk/base/socketaddress.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/thread.h"
#include "talk/base/virtualsocketserver.h"
#include "talk/p2p/base/p2ptransportchannel.h"
#include "talk/p2p/base/testrelayserver.h"
#include "talk/p2p/base/teststunserver.h"
+#include "talk/p2p/base/testturnserver.h"
#include "talk/p2p/client/basicportallocator.h"
using cricket::kDefaultPortAllocatorFlags;
@@ -92,6 +94,11 @@ static const SocketAddress kRelayTcpIntAddr("99.99.99.2", 5002);
static const SocketAddress kRelayTcpExtAddr("99.99.99.3", 5003);
static const SocketAddress kRelaySslTcpIntAddr("99.99.99.2", 5004);
static const SocketAddress kRelaySslTcpExtAddr("99.99.99.3", 5005);
+// The addresses for the public turn server.
+static const SocketAddress kTurnUdpIntAddr("99.99.99.4",
+ cricket::STUN_SERVER_PORT);
+static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
+static const cricket::RelayCredentials kRelayCredentials("test", "test");
// Based on ICE_UFRAG_LENGTH
static const char* kIceUfrag[4] = {"TESTICEUFRAG0000", "TESTICEUFRAG0001",
@@ -132,6 +139,7 @@ class P2PTransportChannelTestBase : public testing::Test,
ss_(new talk_base::FirewallSocketServer(nss_.get())),
ss_scope_(ss_.get()),
stun_server_(main_, kStunAddr),
+ turn_server_(main_, kTurnUdpIntAddr, kTurnUdpExtAddr),
relay_server_(main_, kRelayUdpIntAddr, kRelayUdpExtAddr,
kRelayTcpIntAddr, kRelayTcpExtAddr,
kRelaySslTcpIntAddr, kRelaySslTcpExtAddr),
@@ -139,9 +147,11 @@ class P2PTransportChannelTestBase : public testing::Test,
ss_.get(), kSocksProxyAddrs[0]),
socks_server2_(ss_.get(), kSocksProxyAddrs[1],
ss_.get(), kSocksProxyAddrs[1]),
- clear_remote_candidates_ufrag_pwd_(false) {
+ clear_remote_candidates_ufrag_pwd_(false),
+ force_relay_(false) {
ep1_.role_ = cricket::ICEROLE_CONTROLLING;
ep2_.role_ = cricket::ICEROLE_CONTROLLED;
+
ep1_.allocator_.reset(new cricket::BasicPortAllocator(
&ep1_.network_manager_, kStunAddr, kRelayUdpIntAddr,
kRelayTcpIntAddr, kRelaySslTcpIntAddr));
@@ -237,7 +247,7 @@ class P2PTransportChannelTestBase : public testing::Test,
}
talk_base::FakeNetworkManager network_manager_;
- talk_base::scoped_ptr<cricket::PortAllocator> allocator_;
+ talk_base::scoped_ptr<cricket::BasicPortAllocator> allocator_;
ChannelData cd1_;
ChannelData cd2_;
int signaling_delay_;
@@ -354,8 +364,11 @@ class P2PTransportChannelTestBase : public testing::Test,
static const Result kPrflxTcpToLocalTcp;
static void SetUpTestCase() {
- // Ensure the RNG is inited.
- talk_base::InitRandom(NULL, 0);
+ talk_base::InitializeSSL();
+ }
+
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
}
talk_base::NATSocketServer* nat() { return nss_.get(); }
@@ -478,13 +491,14 @@ class P2PTransportChannelTestBase : public testing::Test,
// i.e. when don't match its remote type is either local or stun.
// TODO(ronghuawu): Refine the test criteria.
// https://code.google.com/p/webrtc/issues/detail?id=1953
- if (expected.remote_type2 != RemoteCandidate(ep2_ch1())->type())
+ if (expected.remote_type2 != RemoteCandidate(ep2_ch1())->type()) {
EXPECT_TRUE(expected.remote_type2 == cricket::LOCAL_PORT_TYPE ||
expected.remote_type2 == cricket::STUN_PORT_TYPE);
EXPECT_TRUE(
RemoteCandidate(ep2_ch1())->type() == cricket::LOCAL_PORT_TYPE ||
RemoteCandidate(ep2_ch1())->type() == cricket::STUN_PORT_TYPE ||
RemoteCandidate(ep2_ch1())->type() == cricket::PRFLX_PORT_TYPE);
+ }
}
converge_time = talk_base::TimeSince(converge_start);
@@ -588,12 +602,55 @@ class P2PTransportChannelTestBase : public testing::Test,
TestSendRecv(1);
}
+ void TestHybridConnectivity(cricket::IceProtocolType proto) {
+ AddAddress(0, kPublicAddrs[0]);
+ AddAddress(1, kPublicAddrs[1]);
+
+ SetAllocationStepDelay(0, kMinimumStepDelay);
+ SetAllocationStepDelay(1, kMinimumStepDelay);
+
+ SetIceRole(0, cricket::ICEROLE_CONTROLLING);
+ SetIceProtocol(0, cricket::ICEPROTO_HYBRID);
+ SetIceTiebreaker(0, kTiebreaker1);
+ SetIceRole(1, cricket::ICEROLE_CONTROLLED);
+ SetIceProtocol(1, proto);
+ SetIceTiebreaker(1, kTiebreaker2);
+
+ CreateChannels(1);
+ // When channel is in hybrid and it's controlling agent, channel will
+ // receive ping request from the remote. Hence connection is readable.
+ // Since channel is in hybrid, it will not send any pings, so no writable
+ // connection. Since channel2 is in controlled state, it will not have
+ // any connections which are readable or writable, as it didn't received
+ // pings (or none) with USE-CANDIDATE attribute.
+ EXPECT_TRUE_WAIT(ep1_ch1()->readable(), 1000);
+
+ // Set real protocol type.
+ ep1_ch1()->SetIceProtocolType(proto);
+
+ // Channel should able to send ping requests and connections become writable
+ // in both directions.
+ EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+ ep2_ch1()->readable() && ep2_ch1()->writable(),
+ 1000);
+ EXPECT_TRUE(
+ ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+ LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
+ RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1]));
+
+ TestSendRecv(1);
+ DestroyChannels();
+ }
+
void OnChannelRequestSignaling(cricket::TransportChannelImpl* channel) {
channel->OnSignalingReady();
}
// We pass the candidates directly to the other side.
void OnCandidate(cricket::TransportChannelImpl* ch,
const cricket::Candidate& c) {
+ if (force_relay_ && c.type() != cricket::RELAY_PORT_TYPE)
+ return;
+
main_->PostDelayed(GetEndpoint(ch)->signaling_delay_, this, 0,
new CandidateData(ch, c));
}
@@ -627,7 +684,8 @@ class P2PTransportChannelTestBase : public testing::Test,
}
int SendData(cricket::TransportChannel* channel,
const char* data, size_t len) {
- return channel->SendPacket(data, len, talk_base::DSCP_NO_CHANGE, 0);
+ talk_base::PacketOptions options;
+ return channel->SendPacket(data, len, options, 0);
}
bool CheckDataOnChannel(cricket::TransportChannel* channel,
const char* data, int len) {
@@ -673,6 +731,10 @@ class P2PTransportChannelTestBase : public testing::Test,
clear_remote_candidates_ufrag_pwd_ = clear;
}
+ void set_force_relay(bool relay) {
+ force_relay_ = relay;
+ }
+
private:
talk_base::Thread* main_;
talk_base::scoped_ptr<talk_base::PhysicalSocketServer> pss_;
@@ -681,12 +743,14 @@ class P2PTransportChannelTestBase : public testing::Test,
talk_base::scoped_ptr<talk_base::FirewallSocketServer> ss_;
talk_base::SocketServerScope ss_scope_;
cricket::TestStunServer stun_server_;
+ cricket::TestTurnServer turn_server_;
cricket::TestRelayServer relay_server_;
talk_base::SocksProxyServer socks_server1_;
talk_base::SocksProxyServer socks_server2_;
Endpoint ep1_;
Endpoint ep2_;
bool clear_remote_candidates_ufrag_pwd_;
+ bool force_relay_;
};
// The tests have only a few outcomes, which we predefine.
@@ -739,6 +803,35 @@ class P2PTransportChannelTest : public P2PTransportChannelTestBase {
int allocator_flags1, int allocator_flags2,
int delay1, int delay2,
cricket::IceProtocolType type) {
+ // Ideally we want to use TURN server for both GICE and ICE, but in case
+ // of GICE, TURN server usage is not producing results reliabally.
+ // TODO(mallinath): Remove Relay and use TURN server for all tests.
+ GetEndpoint(0)->allocator_.reset(
+ new cricket::BasicPortAllocator(&(GetEndpoint(0)->network_manager_),
+ kStunAddr, talk_base::SocketAddress(), talk_base::SocketAddress(),
+ talk_base::SocketAddress()));
+ GetEndpoint(1)->allocator_.reset(
+ new cricket::BasicPortAllocator(&(GetEndpoint(1)->network_manager_),
+ kStunAddr, talk_base::SocketAddress(), talk_base::SocketAddress(),
+ talk_base::SocketAddress()));
+
+ cricket::RelayServerConfig relay_server(cricket::RELAY_GTURN);
+ if (type == cricket::ICEPROTO_RFC5245) {
+ relay_server.type = cricket::RELAY_TURN;
+ relay_server.credentials = kRelayCredentials;
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ kTurnUdpIntAddr, cricket::PROTO_UDP, false));
+ } else {
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ kRelayUdpIntAddr, cricket::PROTO_UDP, false));
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ kRelayTcpIntAddr, cricket::PROTO_TCP, false));
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ kRelaySslTcpIntAddr, cricket::PROTO_SSLTCP, false));
+ }
+ GetEndpoint(0)->allocator_->AddRelay(relay_server);
+ GetEndpoint(1)->allocator_->AddRelay(relay_server);
+
ConfigureEndpoint(0, config1);
SetIceProtocol(0, type);
SetAllocatorFlags(0, allocator_flags1);
@@ -1035,7 +1128,7 @@ const P2PTransportChannelTest::Result*
P2P_TEST(x, OPEN) \
FLAKY_P2P_TEST(x, NAT_FULL_CONE) \
FLAKY_P2P_TEST(x, NAT_ADDR_RESTRICTED) \
- P2P_TEST(x, NAT_PORT_RESTRICTED) \
+ FLAKY_P2P_TEST(x, NAT_PORT_RESTRICTED) \
P2P_TEST(x, NAT_SYMMETRIC) \
FLAKY_P2P_TEST(x, NAT_DOUBLE_CONE) \
P2P_TEST(x, NAT_SYMMETRIC_THEN_CONE) \
@@ -1082,6 +1175,7 @@ TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeAsIce) {
cricket::ICEPROTO_RFC5245);
CreateChannels(1);
TestHandleIceUfragPasswordChanged();
+ DestroyChannels();
}
// Test that we restart candidate allocation when local ufrag&pwd changed.
@@ -1097,6 +1191,7 @@ TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeBundleAsIce) {
CreateChannels(2);
TestHandleIceUfragPasswordChanged();
+ DestroyChannels();
}
// Test that we restart candidate allocation when local ufrag&pwd changed.
@@ -1109,6 +1204,7 @@ TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeAsGice) {
cricket::ICEPROTO_GOOGLE);
CreateChannels(1);
TestHandleIceUfragPasswordChanged();
+ DestroyChannels();
}
// Test that ICE restart works when bundle is enabled.
@@ -1124,6 +1220,7 @@ TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeBundleAsGice) {
CreateChannels(2);
TestHandleIceUfragPasswordChanged();
+ DestroyChannels();
}
// Test the operation of GetStats.
@@ -1389,6 +1486,19 @@ TEST_F(P2PTransportChannelTest, TestIceConfigWillPassDownToPort) {
ep2_ch1()->best_connection());
TestSendRecv(1);
+ DestroyChannels();
+}
+
+// This test verifies channel can handle ice messages when channel is in
+// hybrid mode.
+TEST_F(P2PTransportChannelTest, TestConnectivityBetweenHybridandIce) {
+ TestHybridConnectivity(cricket::ICEPROTO_RFC5245);
+}
+
+// This test verifies channel can handle Gice messages when channel is in
+// hybrid mode.
+TEST_F(P2PTransportChannelTest, TestConnectivityBetweenHybridandGice) {
+ TestHybridConnectivity(cricket::ICEPROTO_GOOGLE);
}
// Verify that we can set DSCP value and retrieve properly from P2PTC.
@@ -1420,7 +1530,8 @@ TEST_F(P2PTransportChannelTest, TestDefaultDscpValue) {
}
// Verify IPv6 connection is preferred over IPv4.
-TEST_F(P2PTransportChannelTest, TestIPv6Connections) {
+// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3317
+TEST_F(P2PTransportChannelTest, DISABLED_TestIPv6Connections) {
AddAddress(0, kIPv6PublicAddrs[0]);
AddAddress(0, kPublicAddrs[0]);
AddAddress(1, kIPv6PublicAddrs[1]);
@@ -1447,6 +1558,42 @@ TEST_F(P2PTransportChannelTest, TestIPv6Connections) {
DestroyChannels();
}
+// Testing forceful TURN connections.
+TEST_F(P2PTransportChannelTest, TestForceTurn) {
+ ConfigureEndpoints(NAT_PORT_RESTRICTED, NAT_SYMMETRIC,
+ kDefaultPortAllocatorFlags |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+ kDefaultPortAllocatorFlags |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG,
+ kDefaultStepDelay, kDefaultStepDelay,
+ cricket::ICEPROTO_RFC5245);
+ set_force_relay(true);
+
+ SetAllocationStepDelay(0, kMinimumStepDelay);
+ SetAllocationStepDelay(1, kMinimumStepDelay);
+
+ CreateChannels(1);
+
+ EXPECT_TRUE_WAIT(ep1_ch1()->readable() &&
+ ep1_ch1()->writable() &&
+ ep2_ch1()->readable() &&
+ ep2_ch1()->writable(),
+ 1000);
+
+ EXPECT_TRUE(ep1_ch1()->best_connection() &&
+ ep2_ch1()->best_connection());
+
+ EXPECT_EQ("relay", RemoteCandidate(ep1_ch1())->type());
+ EXPECT_EQ("relay", LocalCandidate(ep1_ch1())->type());
+ EXPECT_EQ("relay", RemoteCandidate(ep2_ch1())->type());
+ EXPECT_EQ("relay", LocalCandidate(ep2_ch1())->type());
+
+ TestSendRecv(1);
+ DestroyChannels();
+}
+
// Test what happens when we have 2 users behind the same NAT. This can lead
// to interesting behavior because the STUN server will only give out the
// address of the outermost NAT.
@@ -1498,8 +1645,11 @@ TEST_F(P2PTransportChannelMultihomedTest, DISABLED_TestBasic) {
// Test that we can quickly switch links if an interface goes down.
TEST_F(P2PTransportChannelMultihomedTest, TestFailover) {
AddAddress(0, kPublicAddrs[0]);
- AddAddress(1, kPublicAddrs[1]);
+ // Adding alternate address will make sure |kPublicAddrs| has the higher
+ // priority than others. This is due to FakeNetwork::AddInterface method.
AddAddress(1, kAlternateAddrs[1]);
+ AddAddress(1, kPublicAddrs[1]);
+
// Use only local ports for simplicity.
SetAllocatorFlags(0, kOnlyLocalPorts);
SetAllocatorFlags(1, kOnlyLocalPorts);
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/port.cc b/chromium/third_party/libjingle/source/talk/p2p/base/port.cc
index 24ef4271fb6..ad692cec1be 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/port.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/port.cc
@@ -176,13 +176,12 @@ Port::Port(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
generation_(0),
ice_username_fragment_(username_fragment),
password_(password),
- lifetime_(LT_PRESTART),
+ timeout_delay_(kPortTimeoutDelay),
enable_port_packets_(false),
- ice_protocol_(ICEPROTO_GOOGLE),
+ ice_protocol_(ICEPROTO_HYBRID),
ice_role_(ICEROLE_UNKNOWN),
tiebreaker_(0),
- shared_socket_(true),
- default_dscp_(talk_base::DSCP_NO_CHANGE) {
+ shared_socket_(true) {
Construct();
}
@@ -203,13 +202,12 @@ Port::Port(talk_base::Thread* thread, const std::string& type,
generation_(0),
ice_username_fragment_(username_fragment),
password_(password),
- lifetime_(LT_PRESTART),
+ timeout_delay_(kPortTimeoutDelay),
enable_port_packets_(false),
- ice_protocol_(ICEPROTO_GOOGLE),
+ ice_protocol_(ICEPROTO_HYBRID),
ice_role_(ICEROLE_UNKNOWN),
tiebreaker_(0),
- shared_socket_(false),
- default_dscp_(talk_base::DSCP_NO_CHANGE) {
+ shared_socket_(false) {
ASSERT(factory_ != NULL);
Construct();
}
@@ -250,6 +248,7 @@ Connection* Port::GetConnection(const talk_base::SocketAddress& remote_addr) {
void Port::AddAddress(const talk_base::SocketAddress& address,
const talk_base::SocketAddress& base_address,
+ const talk_base::SocketAddress& related_address,
const std::string& protocol,
const std::string& type,
uint32 type_preference,
@@ -260,12 +259,12 @@ void Port::AddAddress(const talk_base::SocketAddress& address,
c.set_type(type);
c.set_protocol(protocol);
c.set_address(address);
- c.set_priority(c.GetPriority(type_preference));
+ c.set_priority(c.GetPriority(type_preference, network_->preference()));
c.set_username(username_fragment());
c.set_password(password_);
c.set_network_name(network_->name());
c.set_generation(generation_);
- c.set_related_address(related_address_);
+ c.set_related_address(related_address);
c.set_foundation(ComputeFoundation(type, protocol, base_address));
candidates_.push_back(c);
SignalCandidateReady(this, c);
@@ -341,6 +340,10 @@ bool Port::IsGoogleIce() const {
return (ice_protocol_ == ICEPROTO_GOOGLE);
}
+bool Port::IsHybridIce() const {
+ return (ice_protocol_ == ICEPROTO_HYBRID);
+}
+
bool Port::GetStunMessage(const char* data, size_t size,
const talk_base::SocketAddress& addr,
IceMessage** out_msg, std::string* out_username) {
@@ -382,7 +385,9 @@ bool Port::GetStunMessage(const char* data, size_t size,
// If the username is bad or unknown, fail with a 401 Unauthorized.
std::string local_ufrag;
std::string remote_ufrag;
- if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag) ||
+ IceProtocolType remote_protocol_type;
+ if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag,
+ &remote_protocol_type) ||
local_ufrag != username_fragment()) {
LOG_J(LS_ERROR, this) << "Received STUN request with bad local username "
<< local_ufrag << " from "
@@ -392,6 +397,15 @@ bool Port::GetStunMessage(const char* data, size_t size,
return true;
}
+ // Port is initialized to GOOGLE-ICE protocol type. If pings from remote
+ // are received before the signal message, protocol type may be different.
+ // Based on the STUN username, we can determine what's the remote protocol.
+ // This also enables us to send the response back using the same protocol
+ // as the request.
+ if (IsHybridIce()) {
+ SetIceProtocolType(remote_protocol_type);
+ }
+
// If ICE, and the MESSAGE-INTEGRITY is bad, fail with a 401 Unauthorized
if (IsStandardIce() &&
!stun_msg->ValidateMessageIntegrity(data, size, password_)) {
@@ -453,7 +467,8 @@ bool Port::IsCompatibleAddress(const talk_base::SocketAddress& addr) {
bool Port::ParseStunUsername(const StunMessage* stun_msg,
std::string* local_ufrag,
- std::string* remote_ufrag) const {
+ std::string* remote_ufrag,
+ IceProtocolType* remote_protocol_type) const {
// The packet must include a username that either begins or ends with our
// fragment. It should begin with our fragment if it is a request and it
// should end with our fragment if it is a response.
@@ -465,8 +480,16 @@ bool Port::ParseStunUsername(const StunMessage* stun_msg,
return false;
const std::string username_attr_str = username_attr->GetString();
- if (IsStandardIce()) {
- size_t colon_pos = username_attr_str.find(":");
+ size_t colon_pos = username_attr_str.find(":");
+ // If we are in hybrid mode set the appropriate ice protocol type based on
+ // the username argument style.
+ if (IsHybridIce()) {
+ *remote_protocol_type = (colon_pos != std::string::npos) ?
+ ICEPROTO_RFC5245 : ICEPROTO_GOOGLE;
+ } else {
+ *remote_protocol_type = ice_protocol_;
+ }
+ if (*remote_protocol_type == ICEPROTO_RFC5245) {
if (colon_pos != std::string::npos) { // RFRAG:LFRAG
*local_ufrag = username_attr_str.substr(0, colon_pos);
*remote_ufrag = username_attr_str.substr(
@@ -474,7 +497,7 @@ bool Port::ParseStunUsername(const StunMessage* stun_msg,
} else {
return false;
}
- } else if (IsGoogleIce()) {
+ } else if (*remote_protocol_type == ICEPROTO_GOOGLE) {
int remote_frag_len = static_cast<int>(username_attr_str.size());
remote_frag_len -= static_cast<int>(username_fragment().size());
if (remote_frag_len < 0)
@@ -608,7 +631,8 @@ void Port::SendBindingResponse(StunMessage* request,
// Send the response message.
talk_base::ByteBuffer buf;
response.Write(&buf);
- if (SendTo(buf.Data(), buf.Length(), addr, DefaultDscpValue(), false) < 0) {
+ talk_base::PacketOptions options(DefaultDscpValue());
+ if (SendTo(buf.Data(), buf.Length(), addr, options, false) < 0) {
LOG_J(LS_ERROR, this) << "Failed to send STUN ping response to "
<< addr.ToSensitiveString();
}
@@ -662,15 +686,14 @@ void Port::SendBindingErrorResponse(StunMessage* request,
// Send the response message.
talk_base::ByteBuffer buf;
response.Write(&buf);
- SendTo(buf.Data(), buf.Length(), addr, DefaultDscpValue(), false);
+ talk_base::PacketOptions options(DefaultDscpValue());
+ SendTo(buf.Data(), buf.Length(), addr, options, false);
LOG_J(LS_INFO, this) << "Sending STUN binding error: reason=" << reason
<< " to " << addr.ToSensitiveString();
}
void Port::OnMessage(talk_base::Message *pmsg) {
ASSERT(pmsg->message_id == MSG_CHECKTIMEOUT);
- ASSERT(lifetime_ == LT_PRETIMEOUT);
- lifetime_ = LT_POSTTIMEOUT;
CheckTimeout();
}
@@ -686,24 +709,18 @@ void Port::EnablePortPackets() {
enable_port_packets_ = true;
}
-void Port::Start() {
- // The port sticks around for a minimum lifetime, after which
- // we destroy it when it drops to zero connections.
- if (lifetime_ == LT_PRESTART) {
- lifetime_ = LT_PRETIMEOUT;
- thread_->PostDelayed(kPortTimeoutDelay, this, MSG_CHECKTIMEOUT);
- } else {
- LOG_J(LS_WARNING, this) << "Port restart attempted";
- }
-}
-
void Port::OnConnectionDestroyed(Connection* conn) {
AddressMap::iterator iter =
connections_.find(conn->remote_candidate().address());
ASSERT(iter != connections_.end());
connections_.erase(iter);
- CheckTimeout();
+ // On the controlled side, ports time out, but only after all connections
+ // fail. Note: If a new connection is added after this message is posted,
+ // but it fails and is removed before kPortTimeoutDelay, then this message
+ // will still cause the Port to be destroyed.
+ if (ice_role_ == ICEROLE_CONTROLLED)
+ thread_->PostDelayed(timeout_delay_, this, MSG_CHECKTIMEOUT);
}
void Port::Destroy() {
@@ -714,17 +731,17 @@ void Port::Destroy() {
}
void Port::CheckTimeout() {
+ ASSERT(ice_role_ == ICEROLE_CONTROLLED);
// If this port has no connections, then there's no reason to keep it around.
// When the connections time out (both read and write), they will delete
// themselves, so if we have any connections, they are either readable or
// writable (or still connecting).
- if ((lifetime_ == LT_POSTTIMEOUT) && connections_.empty()) {
+ if (connections_.empty())
Destroy();
- }
}
const std::string Port::username_fragment() const {
- if (IsGoogleIce() &&
+ if (!IsStandardIce() &&
component_ == ICE_CANDIDATE_COMPONENT_RTCP) {
// In GICE mode, we should adjust username fragment for rtcp component.
return GetRtcpUfragFromRtpUfrag(ice_username_fragment_);
@@ -918,8 +935,9 @@ void Connection::set_use_candidate_attr(bool enable) {
void Connection::OnSendStunPacket(const void* data, size_t size,
StunRequest* req) {
+ talk_base::PacketOptions options(port_->DefaultDscpValue());
if (port_->SendTo(data, size, remote_candidate_.address(),
- port_->DefaultDscpValue(), false) < 0) {
+ options, false) < 0) {
LOG_J(LS_WARNING, this) << "Failed to send STUN ping " << req->id();
}
}
@@ -1005,7 +1023,7 @@ void Connection::OnReadPacket(
// id's match.
case STUN_BINDING_RESPONSE:
case STUN_BINDING_ERROR_RESPONSE:
- if (port_->IceProtocol() == ICEPROTO_GOOGLE ||
+ if (port_->IsGoogleIce() ||
msg->ValidateMessageIntegrity(
data, size, remote_candidate().password())) {
requests_.CheckResponse(msg.get());
@@ -1180,15 +1198,14 @@ std::string Connection::ToString() const {
<< ":" << local.type() << ":" << local.protocol()
<< ":" << local.address().ToSensitiveString()
<< "->" << remote.id() << ":" << remote.component()
- << ":" << remote.generation()
+ << ":" << remote.preference()
<< ":" << remote.type() << ":"
- << remote.protocol() << ":" << remote.address().ToSensitiveString()
- << "|"
+ << remote.protocol() << ":" << remote.address().ToSensitiveString() << "|"
<< CONNECT_STATE_ABBREV[connected()]
<< READ_STATE_ABBREV[read_state()]
<< WRITE_STATE_ABBREV[write_state()]
- << ICESTATE[state()]
- << "|";
+ << ICESTATE[state()] << "|"
+ << priority() << "|";
if (rtt_ < DEFAULT_RTT) {
ss << rtt_ << "]";
} else {
@@ -1394,12 +1411,13 @@ ProxyConnection::ProxyConnection(Port* port, size_t index,
}
int ProxyConnection::Send(const void* data, size_t size,
- talk_base::DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
if (write_state_ == STATE_WRITE_INIT || write_state_ == STATE_WRITE_TIMEOUT) {
error_ = EWOULDBLOCK;
return SOCKET_ERROR;
}
- int sent = port_->SendTo(data, size, remote_candidate_.address(), dscp, true);
+ int sent = port_->SendTo(data, size, remote_candidate_.address(),
+ options, true);
if (sent <= 0) {
ASSERT(sent < 0);
error_ = port_->GetError();
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/port.h b/chromium/third_party/libjingle/source/talk/p2p/base/port.h
index 9ea3f0c37aa..6e5c383b79a 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/port.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/port.h
@@ -172,13 +172,6 @@ class Port : public PortInterface, public talk_base::MessageHandler,
send_retransmit_count_attribute_ = enable;
}
- const talk_base::SocketAddress& related_address() const {
- return related_address_;
- }
- void set_related_address(const talk_base::SocketAddress& address) {
- related_address_ = address;
- }
-
// Identifies the generation that this port was created in.
uint32 generation() { return generation_; }
void set_generation(uint32 generation) { generation_ = generation; }
@@ -262,10 +255,6 @@ class Port : public PortInterface, public talk_base::MessageHandler,
virtual void EnablePortPackets();
- // Indicates to the port that its official use has now begun. This will
- // start the timer that checks to see if the port is being used.
- void Start();
-
// Called if the port has no connections and is no longer useful.
void Destroy();
@@ -277,11 +266,15 @@ class Port : public PortInterface, public talk_base::MessageHandler,
int min_port() { return min_port_; }
int max_port() { return max_port_; }
+ // Timeout shortening function to speed up unit tests.
+ void set_timeout_delay(int delay) { timeout_delay_ = delay; }
+
// This method will return local and remote username fragements from the
// stun username attribute if present.
bool ParseStunUsername(const StunMessage* stun_msg,
std::string* local_username,
- std::string* remote_username) const;
+ std::string* remote_username,
+ IceProtocolType* remote_protocol_type) const;
void CreateStunUsername(const std::string& remote_username,
std::string* stun_username_attr_str) const;
@@ -302,10 +295,8 @@ class Port : public PortInterface, public talk_base::MessageHandler,
// Returns if Google ICE protocol is used.
bool IsGoogleIce() const;
- // Returns default DSCP value.
- talk_base::DiffServCodePoint DefaultDscpValue() const {
- return default_dscp_;
- }
+ // Returns if Hybrid ICE protocol is used.
+ bool IsHybridIce() const;
protected:
enum {
@@ -317,6 +308,7 @@ class Port : public PortInterface, public talk_base::MessageHandler,
// Fills in the local address of the port.
void AddAddress(const talk_base::SocketAddress& address,
const talk_base::SocketAddress& base_address,
+ const talk_base::SocketAddress& related_address,
const std::string& protocol, const std::string& type,
uint32 type_preference, bool final);
@@ -342,9 +334,10 @@ class Port : public PortInterface, public talk_base::MessageHandler,
// Checks if the address in addr is compatible with the port's ip.
bool IsCompatibleAddress(const talk_base::SocketAddress& addr);
- // Default DSCP value for this port. Set by TransportChannel.
- void SetDefaultDscpValue(talk_base::DiffServCodePoint dscp) {
- default_dscp_ = dscp;
+ // Returns default DSCP value.
+ talk_base::DiffServCodePoint DefaultDscpValue() const {
+ // No change from what MediaChannel set.
+ return talk_base::DSCP_NO_CHANGE;
}
private:
@@ -366,7 +359,6 @@ class Port : public PortInterface, public talk_base::MessageHandler,
std::string content_name_;
int component_;
uint32 generation_;
- talk_base::SocketAddress related_address_;
// In order to establish a connection to this Port (so that real data can be
// sent through), the other side must send us a STUN binding request that is
// authenticated with this username_fragment and password.
@@ -379,15 +371,12 @@ class Port : public PortInterface, public talk_base::MessageHandler,
std::string password_;
std::vector<Candidate> candidates_;
AddressMap connections_;
- enum Lifetime { LT_PRESTART, LT_PRETIMEOUT, LT_POSTTIMEOUT } lifetime_;
+ int timeout_delay_;
bool enable_port_packets_;
IceProtocolType ice_protocol_;
IceRole ice_role_;
uint64 tiebreaker_;
bool shared_socket_;
- // DSCP value for ICE/STUN messages. Set by the P2PTransportChannel after
- // port becomes ready.
- talk_base::DiffServCodePoint default_dscp_;
// Information to use when going through a proxy.
std::string user_agent_;
talk_base::ProxyInfo proxy_;
@@ -463,7 +452,7 @@ class Connection : public talk_base::MessageHandler,
// the interface of AsyncPacketSocket, which may use UDP or TCP under the
// covers.
virtual int Send(const void* data, size_t size,
- talk_base::DiffServCodePoint dscp) = 0;
+ const talk_base::PacketOptions& options) = 0;
// Error if Send() returns < 0
virtual int GetError() = 0;
@@ -595,7 +584,7 @@ class ProxyConnection : public Connection {
ProxyConnection(Port* port, size_t index, const Candidate& candidate);
virtual int Send(const void* data, size_t size,
- talk_base::DiffServCodePoint dscp);
+ const talk_base::PacketOptions& options);
virtual int GetError() { return error_; }
private:
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/port_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/port_unittest.cc
index 1122d8aea01..fc6d48c9a5d 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/port_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/port_unittest.cc
@@ -34,6 +34,7 @@
#include "talk/base/physicalsocketserver.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/socketaddress.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/stringutils.h"
#include "talk/base/thread.h"
#include "talk/base/virtualsocketserver.h"
@@ -145,19 +146,21 @@ class TestPort : public Port {
virtual void PrepareAddress() {
talk_base::SocketAddress addr(ip(), min_port());
- AddAddress(addr, addr, "udp", Type(), ICE_TYPE_PREFERENCE_HOST, true);
+ AddAddress(addr, addr, talk_base::SocketAddress(), "udp", Type(),
+ ICE_TYPE_PREFERENCE_HOST, true);
}
// Exposed for testing candidate building.
void AddCandidateAddress(const talk_base::SocketAddress& addr) {
- AddAddress(addr, addr, "udp", Type(), type_preference_, false);
+ AddAddress(addr, addr, talk_base::SocketAddress(), "udp", Type(),
+ type_preference_, false);
}
void AddCandidateAddress(const talk_base::SocketAddress& addr,
const talk_base::SocketAddress& base_address,
const std::string& type,
int type_preference,
bool final) {
- AddAddress(addr, base_address, "udp", type,
+ AddAddress(addr, base_address, talk_base::SocketAddress(), "udp", type,
type_preference, final);
}
@@ -172,7 +175,7 @@ class TestPort : public Port {
}
virtual int SendTo(
const void* data, size_t size, const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp, bool payload) {
+ const talk_base::PacketOptions& options, bool payload) {
if (!payload) {
IceMessage* msg = new IceMessage;
ByteBuffer* buf = new ByteBuffer(static_cast<const char*>(data), size);
@@ -213,12 +216,14 @@ class TestPort : public Port {
class TestChannel : public sigslot::has_slots<> {
public:
+ // Takes ownership of |p1| (but not |p2|).
TestChannel(Port* p1, Port* p2)
: ice_mode_(ICEMODE_FULL), src_(p1), dst_(p2), complete_count_(0),
conn_(NULL), remote_request_(), nominated_(false) {
src_->SignalPortComplete.connect(
this, &TestChannel::OnPortComplete);
src_->SignalUnknownAddress.connect(this, &TestChannel::OnUnknownAddress);
+ src_->SignalDestroyed.connect(this, &TestChannel::OnSrcPortDestroyed);
}
int complete_count() { return complete_count_; }
@@ -305,6 +310,11 @@ class TestChannel : public sigslot::has_slots<> {
conn_ = NULL;
}
+ void OnSrcPortDestroyed(PortInterface* port) {
+ Port* destroyed_src = src_.release();
+ ASSERT_EQ(destroyed_src, port);
+ }
+
bool nominated() const { return nominated_; }
private:
@@ -341,16 +351,21 @@ class PortTest : public testing::Test, public sigslot::has_slots<> {
username_(talk_base::CreateRandomString(ICE_UFRAG_LENGTH)),
password_(talk_base::CreateRandomString(ICE_PWD_LENGTH)),
ice_protocol_(cricket::ICEPROTO_GOOGLE),
- role_conflict_(false) {
+ role_conflict_(false),
+ destroyed_(false) {
network_.AddIP(talk_base::IPAddress(INADDR_ANY));
}
protected:
static void SetUpTestCase() {
- // Ensure the RNG is inited.
- talk_base::InitRandom(NULL, 0);
+ talk_base::InitializeSSL();
+ }
+
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
}
+
void TestLocalToLocal() {
Port* port1 = CreateUdpPort(kLocalAddr1);
Port* port2 = CreateUdpPort(kLocalAddr2);
@@ -455,10 +470,17 @@ class PortTest : public testing::Test, public sigslot::has_slots<> {
TurnPort* CreateTurnPort(const SocketAddress& addr,
PacketSocketFactory* socket_factory,
ProtocolType int_proto, ProtocolType ext_proto) {
+ return CreateTurnPort(addr, socket_factory,
+ int_proto, ext_proto, kTurnUdpIntAddr);
+ }
+ TurnPort* CreateTurnPort(const SocketAddress& addr,
+ PacketSocketFactory* socket_factory,
+ ProtocolType int_proto, ProtocolType ext_proto,
+ const talk_base::SocketAddress& server_addr) {
TurnPort* port = TurnPort::Create(main_, socket_factory, &network_,
addr.ipaddr(), 0, 0,
username_, password_, ProtocolAddress(
- kTurnUdpIntAddr, PROTO_UDP),
+ server_addr, PROTO_UDP),
kRelayCredentials);
port->SetIceProtocolType(ice_protocol_);
return port;
@@ -513,12 +535,17 @@ class PortTest : public testing::Test, public sigslot::has_slots<> {
void TestCrossFamilyPorts(int type);
- // this does all the work
+ // This does all the work and then deletes |port1| and |port2|.
void TestConnectivity(const char* name1, Port* port1,
const char* name2, Port* port2,
bool accept, bool same_addr1,
bool same_addr2, bool possible);
+ // This connects and disconnects the provided channels in the same sequence as
+ // TestConnectivity with all options set to |true|. It does not delete either
+ // channel.
+ void ConnectAndDisconnectChannels(TestChannel* ch1, TestChannel* ch2);
+
void SetIceProtocolType(cricket::IceProtocolType protocol) {
ice_protocol_ = protocol;
}
@@ -562,6 +589,15 @@ class PortTest : public testing::Test, public sigslot::has_slots<> {
}
bool role_conflict() const { return role_conflict_; }
+ void ConnectToSignalDestroyed(PortInterface* port) {
+ port->SignalDestroyed.connect(this, &PortTest::OnDestroyed);
+ }
+
+ void OnDestroyed(PortInterface* port) {
+ destroyed_ = true;
+ }
+ bool destroyed() const { return destroyed_; }
+
talk_base::BasicPacketSocketFactory* nat_socket_factory1() {
return &nat_socket_factory1_;
}
@@ -586,6 +622,7 @@ class PortTest : public testing::Test, public sigslot::has_slots<> {
std::string password_;
cricket::IceProtocolType ice_protocol_;
bool role_conflict_;
+ bool destroyed_;
};
void PortTest::TestConnectivity(const char* name1, Port* port1,
@@ -596,7 +633,7 @@ void PortTest::TestConnectivity(const char* name1, Port* port1,
port1->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
port2->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
- // Set up channels.
+ // Set up channels and ensure both ports will be deleted.
TestChannel ch1(port1, port2);
TestChannel ch2(port2, port1);
EXPECT_EQ(0, ch1.complete_count());
@@ -719,6 +756,29 @@ void PortTest::TestConnectivity(const char* name1, Port* port1,
EXPECT_TRUE_WAIT(ch2.conn() == NULL, kTimeout);
}
+void PortTest::ConnectAndDisconnectChannels(TestChannel* ch1,
+ TestChannel* ch2) {
+ // Acquire addresses.
+ ch1->Start();
+ ch2->Start();
+
+ // Send a ping from src to dst.
+ ch1->CreateConnection();
+ EXPECT_TRUE_WAIT(ch1->conn()->connected(), kTimeout); // for TCP connect
+ ch1->Ping();
+ WAIT(!ch2->remote_address().IsNil(), kTimeout);
+
+ // Send a ping from dst to src.
+ ch2->AcceptConnection();
+ ch2->Ping();
+ EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch2->conn()->write_state(),
+ kTimeout);
+
+ // Destroy the connections.
+ ch1->Stop();
+ ch2->Stop();
+}
+
class FakePacketSocketFactory : public talk_base::PacketSocketFactory {
public:
FakePacketSocketFactory()
@@ -791,11 +851,11 @@ class FakeAsyncPacketSocket : public AsyncPacketSocket {
// Send a packet.
virtual int Send(const void *pv, size_t cb,
- talk_base::DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
return static_cast<int>(cb);
}
virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
- talk_base::DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
return static_cast<int>(cb);
}
virtual int Close() {
@@ -835,7 +895,8 @@ TEST_F(PortTest, TestLocalToSymNat) {
TestLocalToStun(NAT_SYMMETRIC);
}
-TEST_F(PortTest, TestLocalToTurn) {
+// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3316.
+TEST_F(PortTest, DISABLED_TestLocalToTurn) {
TestLocalToRelay(RELAY_TURN, PROTO_UDP);
}
@@ -1234,21 +1295,37 @@ TEST_F(PortTest, TestSkipCrossFamilyUdp) {
// This test verifies DSCP value set through SetOption interface can be
// get through DefaultDscpValue.
TEST_F(PortTest, TestDefaultDscpValue) {
+ int dscp;
talk_base::scoped_ptr<UDPPort> udpport(CreateUdpPort(kLocalAddr1));
- udpport->SetOption(talk_base::Socket::OPT_DSCP, talk_base::DSCP_CS6);
- EXPECT_EQ(talk_base::DSCP_CS6, udpport->DefaultDscpValue());
+ EXPECT_EQ(0, udpport->SetOption(talk_base::Socket::OPT_DSCP,
+ talk_base::DSCP_CS6));
+ EXPECT_EQ(0, udpport->GetOption(talk_base::Socket::OPT_DSCP, &dscp));
talk_base::scoped_ptr<TCPPort> tcpport(CreateTcpPort(kLocalAddr1));
- tcpport->SetOption(talk_base::Socket::OPT_DSCP, talk_base::DSCP_AF31);
- EXPECT_EQ(talk_base::DSCP_AF31, tcpport->DefaultDscpValue());
+ EXPECT_EQ(0, tcpport->SetOption(talk_base::Socket::OPT_DSCP,
+ talk_base::DSCP_AF31));
+ EXPECT_EQ(0, tcpport->GetOption(talk_base::Socket::OPT_DSCP, &dscp));
+ EXPECT_EQ(talk_base::DSCP_AF31, dscp);
talk_base::scoped_ptr<StunPort> stunport(
CreateStunPort(kLocalAddr1, nat_socket_factory1()));
- stunport->SetOption(talk_base::Socket::OPT_DSCP, talk_base::DSCP_AF41);
- EXPECT_EQ(talk_base::DSCP_AF41, stunport->DefaultDscpValue());
- talk_base::scoped_ptr<TurnPort> turnport(CreateTurnPort(
+ EXPECT_EQ(0, stunport->SetOption(talk_base::Socket::OPT_DSCP,
+ talk_base::DSCP_AF41));
+ EXPECT_EQ(0, stunport->GetOption(talk_base::Socket::OPT_DSCP, &dscp));
+ EXPECT_EQ(talk_base::DSCP_AF41, dscp);
+ talk_base::scoped_ptr<TurnPort> turnport1(CreateTurnPort(
kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
- turnport->SetOption(talk_base::Socket::OPT_DSCP, talk_base::DSCP_CS7);
- EXPECT_EQ(talk_base::DSCP_CS7, turnport->DefaultDscpValue());
- // TODO(mallinath) - Test DSCP through GetOption.
+ // Socket is created in PrepareAddress.
+ turnport1->PrepareAddress();
+ EXPECT_EQ(0, turnport1->SetOption(talk_base::Socket::OPT_DSCP,
+ talk_base::DSCP_CS7));
+ EXPECT_EQ(0, turnport1->GetOption(talk_base::Socket::OPT_DSCP, &dscp));
+ EXPECT_EQ(talk_base::DSCP_CS7, dscp);
+ // This will verify correct value returned without the socket.
+ talk_base::scoped_ptr<TurnPort> turnport2(CreateTurnPort(
+ kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
+ EXPECT_EQ(0, turnport2->SetOption(talk_base::Socket::OPT_DSCP,
+ talk_base::DSCP_CS6));
+ EXPECT_EQ(0, turnport2->GetOption(talk_base::Socket::OPT_DSCP, &dscp));
+ EXPECT_EQ(talk_base::DSCP_CS6, dscp);
}
// Test sending STUN messages in GICE format.
@@ -1619,6 +1696,81 @@ TEST_F(PortTest, TestHandleStunMessageAsIce) {
out_msg->GetErrorCode()->reason());
}
+// This test verifies port can handle ICE messages in Hybrid mode and switches
+// ICEPROTO_RFC5245 mode after successfully handling the message.
+TEST_F(PortTest, TestHandleStunMessageAsIceInHybridMode) {
+ // Our port will act as the "remote" port.
+ talk_base::scoped_ptr<TestPort> port(
+ CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+ port->SetIceProtocolType(ICEPROTO_HYBRID);
+
+ talk_base::scoped_ptr<IceMessage> in_msg, out_msg;
+ talk_base::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+ talk_base::SocketAddress addr(kLocalAddr1);
+ std::string username;
+
+ // BINDING-REQUEST from local to remote with valid ICE username,
+ // MESSAGE-INTEGRITY, and FINGERPRINT.
+ in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+ "rfrag:lfrag"));
+ in_msg->AddMessageIntegrity("rpass");
+ in_msg->AddFingerprint();
+ WriteStunMessage(in_msg.get(), buf.get());
+ EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+ out_msg.accept(), &username));
+ EXPECT_TRUE(out_msg.get() != NULL);
+ EXPECT_EQ("lfrag", username);
+ EXPECT_EQ(ICEPROTO_RFC5245, port->IceProtocol());
+}
+
+// This test verifies port can handle GICE messages in Hybrid mode and switches
+// ICEPROTO_GOOGLE mode after successfully handling the message.
+TEST_F(PortTest, TestHandleStunMessageAsGiceInHybridMode) {
+ // Our port will act as the "remote" port.
+ talk_base::scoped_ptr<TestPort> port(
+ CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+ port->SetIceProtocolType(ICEPROTO_HYBRID);
+
+ talk_base::scoped_ptr<IceMessage> in_msg, out_msg;
+ talk_base::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+ talk_base::SocketAddress addr(kLocalAddr1);
+ std::string username;
+
+ // BINDING-REQUEST from local to remote with valid GICE username and no M-I.
+ in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+ "rfraglfrag"));
+ WriteStunMessage(in_msg.get(), buf.get());
+ EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+ out_msg.accept(), &username));
+ EXPECT_TRUE(out_msg.get() != NULL); // Succeeds, since this is GICE.
+ EXPECT_EQ("lfrag", username);
+ EXPECT_EQ(ICEPROTO_GOOGLE, port->IceProtocol());
+}
+
+// Verify port is not switched out of RFC5245 mode if GICE message is received
+// in that mode.
+TEST_F(PortTest, TestHandleStunMessageAsGiceInIceMode) {
+ // Our port will act as the "remote" port.
+ talk_base::scoped_ptr<TestPort> port(
+ CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+ port->SetIceProtocolType(ICEPROTO_RFC5245);
+
+ talk_base::scoped_ptr<IceMessage> in_msg, out_msg;
+ talk_base::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+ talk_base::SocketAddress addr(kLocalAddr1);
+ std::string username;
+
+ // BINDING-REQUEST from local to remote with valid GICE username and no M-I.
+ in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+ "rfraglfrag"));
+ WriteStunMessage(in_msg.get(), buf.get());
+ // Should fail as there is no MI and fingerprint.
+ EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+ out_msg.accept(), &username));
+ EXPECT_EQ(ICEPROTO_RFC5245, port->IceProtocol());
+}
+
+
// Tests handling of GICE binding requests with missing or incorrect usernames.
TEST_F(PortTest, TestHandleStunMessageAsGiceBadUsername) {
talk_base::scoped_ptr<TestPort> port(
@@ -2024,16 +2176,35 @@ TEST_F(PortTest, TestCandidateFoundation) {
EXPECT_NE(udpport2->Candidates()[0].foundation(),
relayport->Candidates()[0].foundation());
// Verifying TURN candidate foundation.
- talk_base::scoped_ptr<Port> turnport(CreateTurnPort(
+ talk_base::scoped_ptr<Port> turnport1(CreateTurnPort(
kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
- turnport->PrepareAddress();
- ASSERT_EQ_WAIT(1U, turnport->Candidates().size(), kTimeout);
+ turnport1->PrepareAddress();
+ ASSERT_EQ_WAIT(1U, turnport1->Candidates().size(), kTimeout);
EXPECT_NE(udpport1->Candidates()[0].foundation(),
- turnport->Candidates()[0].foundation());
+ turnport1->Candidates()[0].foundation());
EXPECT_NE(udpport2->Candidates()[0].foundation(),
- turnport->Candidates()[0].foundation());
+ turnport1->Candidates()[0].foundation());
EXPECT_NE(stunport->Candidates()[0].foundation(),
- turnport->Candidates()[0].foundation());
+ turnport1->Candidates()[0].foundation());
+ talk_base::scoped_ptr<Port> turnport2(CreateTurnPort(
+ kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
+ turnport2->PrepareAddress();
+ ASSERT_EQ_WAIT(1U, turnport2->Candidates().size(), kTimeout);
+ EXPECT_EQ(turnport1->Candidates()[0].foundation(),
+ turnport2->Candidates()[0].foundation());
+
+ // Running a second turn server, to get different base IP address.
+ SocketAddress kTurnUdpIntAddr2("99.99.98.4", STUN_SERVER_PORT);
+ SocketAddress kTurnUdpExtAddr2("99.99.98.5", 0);
+ TestTurnServer turn_server2(
+ talk_base::Thread::Current(), kTurnUdpIntAddr2, kTurnUdpExtAddr2);
+ talk_base::scoped_ptr<Port> turnport3(CreateTurnPort(
+ kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP,
+ kTurnUdpIntAddr2));
+ turnport3->PrepareAddress();
+ ASSERT_EQ_WAIT(1U, turnport3->Candidates().size(), kTimeout);
+ EXPECT_NE(turnport3->Candidates()[0].foundation(),
+ turnport2->Candidates()[0].foundation());
}
// This test verifies the related addresses of different types of
@@ -2155,16 +2326,15 @@ TEST_F(PortTest, TestWritableState) {
// Data should be unsendable until the connection is accepted.
char data[] = "abcd";
int data_size = ARRAY_SIZE(data);
- EXPECT_EQ(SOCKET_ERROR,
- ch1.conn()->Send(data, data_size, talk_base::DSCP_NO_CHANGE));
+ talk_base::PacketOptions options;
+ EXPECT_EQ(SOCKET_ERROR, ch1.conn()->Send(data, data_size, options));
// Accept the connection to return the binding response, transition to
// writable, and allow data to be sent.
ch2.AcceptConnection();
EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(),
kTimeout);
- EXPECT_EQ(data_size,
- ch1.conn()->Send(data, data_size, talk_base::DSCP_NO_CHANGE));
+ EXPECT_EQ(data_size, ch1.conn()->Send(data, data_size, options));
// Ask the connection to update state as if enough time has passed to lose
// full writability and 5 pings went unresponded to. We'll accomplish the
@@ -2177,8 +2347,7 @@ TEST_F(PortTest, TestWritableState) {
EXPECT_EQ(Connection::STATE_WRITE_UNRELIABLE, ch1.conn()->write_state());
// Data should be able to be sent in this state.
- EXPECT_EQ(data_size,
- ch1.conn()->Send(data, data_size, talk_base::DSCP_NO_CHANGE));
+ EXPECT_EQ(data_size, ch1.conn()->Send(data, data_size, options));
// And now allow the other side to process the pings and send binding
// responses.
@@ -2195,8 +2364,7 @@ TEST_F(PortTest, TestWritableState) {
EXPECT_EQ(Connection::STATE_WRITE_TIMEOUT, ch1.conn()->write_state());
// Now that the connection has completely timed out, data send should fail.
- EXPECT_EQ(SOCKET_ERROR,
- ch1.conn()->Send(data, data_size, talk_base::DSCP_NO_CHANGE));
+ EXPECT_EQ(SOCKET_ERROR, ch1.conn()->Send(data, data_size, options));
ch1.Stop();
ch2.Stop();
@@ -2292,3 +2460,59 @@ TEST_F(PortTest, TestIceLiteConnectivity) {
EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) != NULL);
ch1.Stop();
}
+
+// This test case verifies that the CONTROLLING port does not time out.
+TEST_F(PortTest, TestControllingNoTimeout) {
+ SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+ UDPPort* port1 = CreateUdpPort(kLocalAddr1);
+ ConnectToSignalDestroyed(port1);
+ port1->set_timeout_delay(10); // milliseconds
+ port1->SetIceRole(cricket::ICEROLE_CONTROLLING);
+ port1->SetIceTiebreaker(kTiebreaker1);
+
+ UDPPort* port2 = CreateUdpPort(kLocalAddr2);
+ port2->SetIceRole(cricket::ICEROLE_CONTROLLED);
+ port2->SetIceTiebreaker(kTiebreaker2);
+
+ // Set up channels and ensure both ports will be deleted.
+ TestChannel ch1(port1, port2);
+ TestChannel ch2(port2, port1);
+
+ // Simulate a connection that succeeds, and then is destroyed.
+ ConnectAndDisconnectChannels(&ch1, &ch2);
+
+ // After the connection is destroyed, the port should not be destroyed.
+ talk_base::Thread::Current()->ProcessMessages(kTimeout);
+ EXPECT_FALSE(destroyed());
+}
+
+// This test case verifies that the CONTROLLED port does time out, but only
+// after connectivity is lost.
+TEST_F(PortTest, TestControlledTimeout) {
+ SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+ UDPPort* port1 = CreateUdpPort(kLocalAddr1);
+ port1->SetIceRole(cricket::ICEROLE_CONTROLLING);
+ port1->SetIceTiebreaker(kTiebreaker1);
+
+ UDPPort* port2 = CreateUdpPort(kLocalAddr2);
+ ConnectToSignalDestroyed(port2);
+ port2->set_timeout_delay(10); // milliseconds
+ port2->SetIceRole(cricket::ICEROLE_CONTROLLED);
+ port2->SetIceTiebreaker(kTiebreaker2);
+
+ // The connection must not be destroyed before a connection is attempted.
+ EXPECT_FALSE(destroyed());
+
+ port1->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
+ port2->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
+
+ // Set up channels and ensure both ports will be deleted.
+ TestChannel ch1(port1, port2);
+ TestChannel ch2(port2, port1);
+
+ // Simulate a connection that succeeds, and then is destroyed.
+ ConnectAndDisconnectChannels(&ch1, &ch2);
+
+ // The controlled port should be destroyed after 10 milliseconds.
+ EXPECT_TRUE_WAIT(destroyed(), kTimeout);
+}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/portallocator.h b/chromium/third_party/libjingle/source/talk/p2p/base/portallocator.h
index 348102165f7..e2cb3fd2087 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/portallocator.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/portallocator.h
@@ -54,7 +54,6 @@ const uint32 PORTALLOCATOR_ENABLE_IPV6 = 0x40;
const uint32 PORTALLOCATOR_ENABLE_SHARED_UFRAG = 0x80;
const uint32 PORTALLOCATOR_ENABLE_SHARED_SOCKET = 0x100;
const uint32 PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE = 0x200;
-const uint32 PORTALLOCATOR_USE_LARGE_SOCKET_SEND_BUFFERS = 0x400;
const uint32 kDefaultPortAllocatorFlags = 0;
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/portinterface.h b/chromium/third_party/libjingle/source/talk/p2p/base/portinterface.h
index 6ea63466c9d..5ebf6539873 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/portinterface.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/portinterface.h
@@ -30,13 +30,12 @@
#include <string>
-#include "talk/base/dscp.h"
#include "talk/base/socketaddress.h"
#include "talk/p2p/base/transport.h"
namespace talk_base {
class Network;
-class PacketSocketFactory;
+struct PacketOptions;
}
namespace cricket {
@@ -100,7 +99,7 @@ class PortInterface {
// that of a connection or an address that has sent to us already.
virtual int SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp, bool payload) = 0;
+ const talk_base::PacketOptions& options, bool payload) = 0;
// Indicates that we received a successful STUN binding request from an
// address that doesn't correspond to any current connection. To turn this
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/portproxy.cc b/chromium/third_party/libjingle/source/talk/p2p/base/portproxy.cc
index eae39f1612d..43bb747c964 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/portproxy.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/portproxy.cc
@@ -97,10 +97,10 @@ Connection* PortProxy::CreateConnection(const Candidate& remote_candidate,
int PortProxy::SendTo(const void* data,
size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
bool payload) {
ASSERT(impl_ != NULL);
- return impl_->SendTo(data, size, addr, dscp, payload);
+ return impl_->SendTo(data, size, addr, options, payload);
}
int PortProxy::SetOption(talk_base::Socket::Option opt,
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/portproxy.h b/chromium/third_party/libjingle/source/talk/p2p/base/portproxy.h
index da326646dcc..d138dc3614a 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/portproxy.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/portproxy.h
@@ -69,7 +69,7 @@ class PortProxy : public PortInterface, public sigslot::has_slots<> {
virtual int SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
bool payload);
virtual int SetOption(talk_base::Socket::Option opt, int value);
virtual int GetOption(talk_base::Socket::Option opt, int* value);
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc b/chromium/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc
index 56aa5b019a0..3925637a305 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc
@@ -27,8 +27,9 @@
#include "talk/p2p/base/pseudotcp.h"
-#include <cstdio>
-#include <cstdlib>
+#include <stdio.h>
+#include <stdlib.h>
+
#include <set>
#include "talk/base/basictypes.h"
@@ -81,7 +82,6 @@ const uint32 MAX_PACKET = 65535;
const uint32 MIN_PACKET = 296;
const uint32 IP_HEADER_SIZE = 20; // (+ up to 40 bytes of options?)
-const uint32 ICMP_HEADER_SIZE = 8;
const uint32 UDP_HEADER_SIZE = 8;
// TODO: Make JINGLE_HEADER_SIZE transparent to this code?
const uint32 JINGLE_HEADER_SIZE = 64; // when relay framing is in use
@@ -118,7 +118,6 @@ const uint32 DEFAULT_SND_BUF_SIZE = 90 * 1024;
#define PSEUDO_KEEPALIVE 0
-const uint32 MAX_SEQ = 0xFFFFFFFF;
const uint32 HEADER_SIZE = 24;
const uint32 PACKET_OVERHEAD = HEADER_SIZE + UDP_HEADER_SIZE + IP_HEADER_SIZE + JINGLE_HEADER_SIZE;
@@ -131,8 +130,6 @@ const uint8 FLAG_CTL = 0x02;
const uint8 FLAG_RST = 0x04;
const uint8 CTL_CONNECT = 0;
-//const uint8 CTL_REDIRECT = 1;
-const uint8 CTL_EXTRA = 255;
// TCP options.
const uint8 TCP_OPT_EOL = 0; // End of list.
@@ -140,14 +137,6 @@ const uint8 TCP_OPT_NOOP = 1; // No-op.
const uint8 TCP_OPT_MSS = 2; // Maximum segment size.
const uint8 TCP_OPT_WND_SCALE = 3; // Window scale factor.
-/*
-const uint8 FLAG_FIN = 0x01;
-const uint8 FLAG_SYN = 0x02;
-const uint8 FLAG_ACK = 0x10;
-*/
-
-const uint32 CTRL_BOUND = 0x80000000;
-
const long DEFAULT_TIMEOUT = 4000; // If there are no pending clocks, wake up every 4 seconds
const long CLOSED_TIMEOUT = 60 * 1000; // If the connection is closed, once per minute
@@ -728,13 +717,16 @@ bool PseudoTcp::process(Segment& seg) {
if ((seg.ack > m_snd_una) && (seg.ack <= m_snd_nxt)) {
// Calculate round-trip time
if (seg.tsecr) {
- long rtt = talk_base::TimeDiff(now, seg.tsecr);
+ int32 rtt = talk_base::TimeDiff(now, seg.tsecr);
if (rtt >= 0) {
if (m_rx_srtt == 0) {
m_rx_srtt = rtt;
m_rx_rttvar = rtt / 2;
} else {
- m_rx_rttvar = (3 * m_rx_rttvar + abs(long(rtt - m_rx_srtt))) / 4;
+ uint32 unsigned_rtt = static_cast<uint32>(rtt);
+ uint32 abs_err = unsigned_rtt > m_rx_srtt ? unsigned_rtt - m_rx_srtt
+ : m_rx_srtt - unsigned_rtt;
+ m_rx_rttvar = (3 * m_rx_rttvar + abs_err) / 4;
m_rx_srtt = (7 * m_rx_srtt + rtt) / 8;
}
m_rx_rto = bound(MIN_RTO, m_rx_srtt +
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.cc b/chromium/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.cc
index 2baef4245ab..37478ca4b50 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.cc
@@ -75,7 +75,7 @@ RawTransportChannel::~RawTransportChannel() {
}
int RawTransportChannel::SendPacket(const char *data, size_t size,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
int flags) {
if (port_ == NULL)
return -1;
@@ -83,7 +83,7 @@ int RawTransportChannel::SendPacket(const char *data, size_t size,
return -1;
if (flags != 0)
return -1;
- return port_->SendTo(data, size, remote_address_, dscp, true);
+ return port_->SendTo(data, size, remote_address_, options, true);
}
int RawTransportChannel::SetOption(talk_base::Socket::Option opt, int value) {
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.h b/chromium/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.h
index ed38952d561..52085c04fa3 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.h
@@ -65,7 +65,7 @@ class RawTransportChannel : public TransportChannelImpl,
// Implementation of normal channel packet sending.
virtual int SendPacket(const char *data, size_t len,
- talk_base::DiffServCodePoint dscp, int flags);
+ const talk_base::PacketOptions& options, int flags);
virtual int SetOption(talk_base::Socket::Option opt, int value);
virtual int GetError();
@@ -97,10 +97,14 @@ class RawTransportChannel : public TransportChannelImpl,
virtual IceRole GetIceRole() const { return ICEROLE_UNKNOWN; }
virtual void SetIceRole(IceRole role) {}
virtual void SetIceTiebreaker(uint64 tiebreaker) {}
+
+ virtual bool GetIceProtocolType(IceProtocolType* type) const { return false; }
virtual void SetIceProtocolType(IceProtocolType type) {}
+
virtual void SetIceUfrag(const std::string& ice_ufrag) {}
virtual void SetIcePwd(const std::string& ice_pwd) {}
virtual void SetRemoteIceMode(IceMode mode) {}
+ virtual size_t GetConnectionCount() const { return 1; }
virtual bool GetStats(ConnectionInfos* infos) {
return false;
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/relayport.cc b/chromium/third_party/libjingle/source/talk/p2p/base/relayport.cc
index ddfca7114ca..23571ea5fa7 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/relayport.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/relayport.cc
@@ -67,7 +67,7 @@ class RelayConnection : public sigslot::has_slots<> {
bool CheckResponse(StunMessage* msg);
// Sends data to the relay server.
- int Send(const void* pv, size_t cb, talk_base::DiffServCodePoint dscp);
+ int Send(const void* pv, size_t cb, const talk_base::PacketOptions& options);
// Sends a STUN allocate request message to the relay server.
void SendAllocateRequest(RelayEntry* entry, int delay);
@@ -124,7 +124,7 @@ class RelayEntry : public talk_base::MessageHandler,
// entry. This will wrap the packet in STUN if necessary.
int SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp);
+ const talk_base::PacketOptions& options);
// Schedules a keep-alive allocate request.
void ScheduleKeepAlive();
@@ -166,7 +166,7 @@ class RelayEntry : public talk_base::MessageHandler,
// Sends the given data on the socket to the server with no wrapping. This
// returns the number of bytes written or -1 if an error occurred.
int SendPacket(const void* data, size_t size,
- talk_base::DiffServCodePoint dscp);
+ const talk_base::PacketOptions& options);
};
// Handles an allocate request for a particular RelayEntry.
@@ -240,8 +240,11 @@ void RelayPort::SetReady() {
for (iter = external_addr_.begin();
iter != external_addr_.end(); ++iter) {
std::string proto_name = ProtoToString(iter->proto);
- AddAddress(iter->address, iter->address, proto_name,
- RELAY_PORT_TYPE, ICE_TYPE_PREFERENCE_RELAY, false);
+ // In case of Gturn, related address is set to null socket address.
+ // This is due to as mapped address stun attribute is used for allocated
+ // address.
+ AddAddress(iter->address, iter->address, talk_base::SocketAddress(),
+ proto_name, RELAY_PORT_TYPE, ICE_TYPE_PREFERENCE_RELAY, false);
}
ready_ = true;
SignalPortComplete(this);
@@ -258,8 +261,9 @@ bool RelayPort::HasMagicCookie(const char* data, size_t size) {
if (size < 24 + sizeof(TURN_MAGIC_COOKIE_VALUE)) {
return false;
} else {
- return 0 == std::memcmp(data + 24, TURN_MAGIC_COOKIE_VALUE,
- sizeof(TURN_MAGIC_COOKIE_VALUE));
+ return memcmp(data + 24,
+ TURN_MAGIC_COOKIE_VALUE,
+ sizeof(TURN_MAGIC_COOKIE_VALUE)) == 0;
}
}
@@ -304,7 +308,7 @@ Connection* RelayPort::CreateConnection(const Candidate& address,
int RelayPort::SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
bool payload) {
// Try to find an entry for this specific address. Note that the first entry
// created was not given an address initially, so it can be set to the first
@@ -346,7 +350,7 @@ int RelayPort::SendTo(const void* data, size_t size,
}
// Send the actual contents to the server using the usual mechanism.
- int sent = entry->SendTo(data, size, addr, dscp);
+ int sent = entry->SendTo(data, size, addr, options);
if (sent <= 0) {
ASSERT(sent < 0);
error_ = entry->GetError();
@@ -359,14 +363,6 @@ int RelayPort::SendTo(const void* data, size_t size,
int RelayPort::SetOption(talk_base::Socket::Option opt, int value) {
int result = 0;
- // DSCP option is not passed to the socket.
- // TODO(mallinath) - After we have the support on socket,
- // remove this specialization.
- if (opt == talk_base::Socket::OPT_DSCP) {
- SetDefaultDscpValue(static_cast<talk_base::DiffServCodePoint>(value));
- return result;
- }
-
for (size_t i = 0; i < entries_.size(); ++i) {
if (entries_[i]->SetSocketOption(opt, value) < 0) {
result = -1;
@@ -434,18 +430,18 @@ bool RelayConnection::CheckResponse(StunMessage* msg) {
void RelayConnection::OnSendPacket(const void* data, size_t size,
StunRequest* req) {
// TODO(mallinath) Find a way to get DSCP value from Port.
- int sent = socket_->SendTo(
- data, size, GetAddress(), talk_base::DSCP_NO_CHANGE);
+ talk_base::PacketOptions options; // Default dscp set to NO_CHANGE.
+ int sent = socket_->SendTo(data, size, GetAddress(), options);
if (sent <= 0) {
LOG(LS_VERBOSE) << "OnSendPacket: failed sending to " << GetAddress() <<
- std::strerror(socket_->GetError());
+ strerror(socket_->GetError());
ASSERT(sent < 0);
}
}
int RelayConnection::Send(const void* pv, size_t cb,
- talk_base::DiffServCodePoint dscp) {
- return socket_->SendTo(pv, cb, GetAddress(), dscp);
+ const talk_base::PacketOptions& options) {
+ return socket_->SendTo(pv, cb, GetAddress(), options);
}
void RelayConnection::SendAllocateRequest(RelayEntry* entry, int delay) {
@@ -555,21 +551,17 @@ void RelayEntry::OnConnect(const talk_base::SocketAddress& mapped_addr,
<< " @ " << mapped_addr.ToSensitiveString();
connected_ = true;
- // In case of Gturn related address is set to null socket address.
- // This is due to mapped address stun attribute is used for allocated
- // address.
- port_->set_related_address(talk_base::SocketAddress());
port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto));
port_->SetReady();
}
int RelayEntry::SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
// If this connection is locked to the address given, then we can send the
// packet with no wrapper.
if (locked_ && (ext_addr_ == addr))
- return SendPacket(data, size, dscp);
+ return SendPacket(data, size, options);
// Otherwise, we must wrap the given data in a STUN SEND request so that we
// can communicate the destination address to the server.
@@ -617,7 +609,7 @@ int RelayEntry::SendTo(const void* data, size_t size,
talk_base::ByteBuffer buf;
request.Write(&buf);
- return SendPacket(buf.Data(), buf.Length(), dscp);
+ return SendPacket(buf.Data(), buf.Length(), options);
}
void RelayEntry::ScheduleKeepAlive() {
@@ -766,12 +758,12 @@ void RelayEntry::OnReadyToSend(talk_base::AsyncPacketSocket* socket) {
}
int RelayEntry::SendPacket(const void* data, size_t size,
- talk_base::DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
int sent = 0;
if (current_connection_) {
// We are connected, no need to send packets anywere else than to
// the current connection.
- sent = current_connection_->Send(data, size, dscp);
+ sent = current_connection_->Send(data, size, options);
}
return sent;
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/relayport.h b/chromium/third_party/libjingle/source/talk/p2p/base/relayport.h
index 08df12f9d28..140c80fe065 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/relayport.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/relayport.h
@@ -93,7 +93,7 @@ class RelayPort : public Port {
virtual int SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
bool payload);
// Dispatches the given packet to the port or connection as appropriate.
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/relayport_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/relayport_unittest.cc
index bd00af86de0..987fd1e3966 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/relayport_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/relayport_unittest.cc
@@ -32,6 +32,7 @@
#include "talk/base/scoped_ptr.h"
#include "talk/base/socketadapters.h"
#include "talk/base/socketaddress.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/thread.h"
#include "talk/base/virtualsocketserver.h"
#include "talk/p2p/base/basicpacketsocketfactory.h"
@@ -93,10 +94,14 @@ class RelayPortTest : public testing::Test,
protected:
static void SetUpTestCase() {
- // Ensure the RNG is inited.
- talk_base::InitRandom(NULL, 0);
+ talk_base::InitializeSSL();
}
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
+ }
+
+
virtual void SetUp() {
// The relay server needs an external socket to work properly.
talk_base::AsyncUDPSocket* ext_socket =
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/relayserver.cc b/chromium/third_party/libjingle/source/talk/p2p/base/relayserver.cc
index c2619c03feb..3dd85065714 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/relayserver.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/relayserver.cc
@@ -46,12 +46,11 @@ const int MAX_LIFETIME = 15 * 60 * 1000;
// The number of bytes in each of the usernames we use.
const uint32 USERNAME_LENGTH = 16;
-static const uint32 kMessageAcceptConnection = 1;
-
// Calls SendTo on the given socket and logs any bad results.
void Send(talk_base::AsyncPacketSocket* socket, const char* bytes, size_t size,
const talk_base::SocketAddress& addr) {
- int result = socket->SendTo(bytes, size, addr, talk_base::DSCP_NO_CHANGE);
+ talk_base::PacketOptions options;
+ int result = socket->SendTo(bytes, size, addr, options);
if (result < static_cast<int>(size)) {
LOG(LS_ERROR) << "SendTo wrote only " << result << " of " << size
<< " bytes";
@@ -547,7 +546,10 @@ void RelayServer::RemoveBinding(RelayServerBinding* binding) {
}
void RelayServer::OnMessage(talk_base::Message *pmsg) {
+#if ENABLE_DEBUG
+ static const uint32 kMessageAcceptConnection = 1;
ASSERT(pmsg->message_id == kMessageAcceptConnection);
+#endif
talk_base::MessageData* data = pmsg->pdata;
talk_base::AsyncSocket* socket =
static_cast <talk_base::TypedMessageData<talk_base::AsyncSocket*>*>
@@ -712,8 +714,7 @@ bool RelayServerBinding::HasMagicCookie(const char* bytes, size_t size) const {
if (size < 24 + magic_cookie_.size()) {
return false;
} else {
- return 0 == std::memcmp(
- bytes + 24, magic_cookie_.c_str(), magic_cookie_.size());
+ return memcmp(bytes + 24, magic_cookie_.c_str(), magic_cookie_.size()) == 0;
}
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/relayserver_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/relayserver_unittest.cc
index 86d2eef6926..239f644b475 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/relayserver_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/relayserver_unittest.cc
@@ -32,6 +32,7 @@
#include "talk/base/logging.h"
#include "talk/base/physicalsocketserver.h"
#include "talk/base/socketaddress.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/testclient.h"
#include "talk/base/thread.h"
#include "talk/p2p/base/relayserver.h"
@@ -53,8 +54,13 @@ static const char* msg2 = "Lobster Thermidor a Crevette with a mornay sauce...";
class RelayServerTest : public testing::Test {
public:
static void SetUpTestCase() {
- talk_base::InitRandom(NULL, 0);
+ talk_base::InitializeSSL();
}
+
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
+ }
+
RelayServerTest()
: main_(talk_base::Thread::Current()), ss_(main_->socketserver()),
username_(talk_base::CreateRandomString(12)),
@@ -191,7 +197,7 @@ class RelayServerTest : public testing::Test {
TEST_F(RelayServerTest, TestBadRequest) {
talk_base::scoped_ptr<StunMessage> res;
- SendRaw1(bad, static_cast<int>(std::strlen(bad)));
+ SendRaw1(bad, static_cast<int>(strlen(bad)));
res.reset(Receive1());
ASSERT_TRUE(!res);
@@ -334,7 +340,7 @@ TEST_F(RelayServerTest, TestRemoteBadRequest) {
Allocate();
Bind();
- SendRaw1(bad, static_cast<int>(std::strlen(bad)));
+ SendRaw1(bad, static_cast<int>(strlen(bad)));
EXPECT_TRUE(Receive1() == NULL);
EXPECT_TRUE(Receive2() == NULL);
}
@@ -480,7 +486,7 @@ TEST_F(RelayServerTest, TestSendRaw) {
Send1(req.get());
EXPECT_EQ(msg1, ReceiveRaw2());
- SendRaw2(msg2, static_cast<int>(std::strlen(msg2)));
+ SendRaw2(msg2, static_cast<int>(strlen(msg2)));
res.reset(Receive1());
ASSERT_TRUE(res);
@@ -533,6 +539,6 @@ TEST_F(RelayServerTest, TestExpiration) {
EXPECT_EQ("Operation Not Supported", err->reason());
// Also verify that traffic from the external client is ignored.
- SendRaw2(msg2, static_cast<int>(std::strlen(msg2)));
+ SendRaw2(msg2, static_cast<int>(strlen(msg2)));
EXPECT_TRUE(ReceiveRaw1().empty());
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/session.cc b/chromium/third_party/libjingle/source/talk/p2p/base/session.cc
index e0f8dd3f4f8..a48f3cb0f66 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/session.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/session.cc
@@ -277,21 +277,35 @@ void TransportProxy::SetIceRole(IceRole role) {
}
bool TransportProxy::SetLocalTransportDescription(
- const TransportDescription& description, ContentAction action) {
+ const TransportDescription& description,
+ ContentAction action,
+ std::string* error_desc) {
// If this is an answer, finalize the negotiation.
if (action == CA_ANSWER) {
CompleteNegotiation();
}
- return transport_->get()->SetLocalTransportDescription(description, action);
+ bool result = transport_->get()->SetLocalTransportDescription(description,
+ action,
+ error_desc);
+ if (result)
+ local_description_set_ = true;
+ return result;
}
bool TransportProxy::SetRemoteTransportDescription(
- const TransportDescription& description, ContentAction action) {
+ const TransportDescription& description,
+ ContentAction action,
+ std::string* error_desc) {
// If this is an answer, finalize the negotiation.
if (action == CA_ANSWER) {
CompleteNegotiation();
}
- return transport_->get()->SetRemoteTransportDescription(description, action);
+ bool result = transport_->get()->SetRemoteTransportDescription(description,
+ action,
+ error_desc);
+ if (result)
+ remote_description_set_ = true;
+ return result;
}
void TransportProxy::OnSignalingReady() {
@@ -418,16 +432,22 @@ bool BaseSession::SetIdentity(talk_base::SSLIdentity* identity) {
}
bool BaseSession::PushdownTransportDescription(ContentSource source,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
if (source == CS_LOCAL) {
- return PushdownLocalTransportDescription(local_description_, action);
+ return PushdownLocalTransportDescription(local_description_,
+ action,
+ error_desc);
}
- return PushdownRemoteTransportDescription(remote_description_, action);
+ return PushdownRemoteTransportDescription(remote_description_,
+ action,
+ error_desc);
}
bool BaseSession::PushdownLocalTransportDescription(
const SessionDescription* sdesc,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
// Update the Transports with the right information, and trigger them to
// start connecting.
for (TransportMap::iterator iter = transports_.begin();
@@ -438,7 +458,8 @@ bool BaseSession::PushdownLocalTransportDescription(
bool ret = GetTransportDescription(
sdesc, iter->second->content_name(), &tdesc);
if (ret) {
- if (!iter->second->SetLocalTransportDescription(tdesc, action)) {
+ if (!iter->second->SetLocalTransportDescription(tdesc, action,
+ error_desc)) {
return false;
}
@@ -451,7 +472,8 @@ bool BaseSession::PushdownLocalTransportDescription(
bool BaseSession::PushdownRemoteTransportDescription(
const SessionDescription* sdesc,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
// Update the Transports with the right information.
for (TransportMap::iterator iter = transports_.begin();
iter != transports_.end(); ++iter) {
@@ -462,7 +484,8 @@ bool BaseSession::PushdownRemoteTransportDescription(
bool ret = GetTransportDescription(
sdesc, iter->second->content_name(), &tdesc);
if (ret) {
- if (!iter->second->SetRemoteTransportDescription(tdesc, action)) {
+ if (!iter->second->SetRemoteTransportDescription(tdesc, action,
+ error_desc)) {
return false;
}
}
@@ -522,11 +545,17 @@ TransportProxy* BaseSession::GetOrCreateTransportProxy(
this, &BaseSession::OnTransportCandidatesAllocationDone);
transport->SignalRoleConflict.connect(
this, &BaseSession::OnRoleConflict);
+ transport->SignalCompleted.connect(
+ this, &BaseSession::OnTransportCompleted);
+ transport->SignalFailed.connect(
+ this, &BaseSession::OnTransportFailed);
transproxy = new TransportProxy(worker_thread_, sid_, content_name,
new TransportWrapper(transport));
transproxy->SignalCandidatesReady.connect(
this, &BaseSession::OnTransportProxyCandidatesReady);
+ if (identity_)
+ transproxy->SetIdentity(identity_);
transports_[content_name] = transproxy;
return transproxy;
@@ -611,10 +640,11 @@ void BaseSession::SetState(State state) {
SignalNewDescription();
}
-void BaseSession::SetError(Error error) {
+void BaseSession::SetError(Error error, const std::string& error_desc) {
ASSERT(signaling_thread_->IsCurrent());
if (error != error_) {
error_ = error;
+ error_desc_ = error_desc;
SignalError(this, error);
}
}
@@ -738,9 +768,9 @@ void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
// Transport, since this removes the need to manually iterate over all
// the transports, as is needed to make sure signals are handled properly
// when BUNDLEing.
-#if 0
- ASSERT(!IsCandidateAllocationDone());
-#endif
+ // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
+ // that make it prohibitively difficult to run dbg builds. Disabled for now.
+ //ASSERT(!IsCandidateAllocationDone());
for (TransportMap::iterator iter = transports_.begin();
iter != transports_.end(); ++iter) {
if (iter->second->impl() == transport) {
@@ -856,7 +886,7 @@ void BaseSession::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
case MSG_TIMEOUT:
// Session timeout has occured.
- SetError(ERROR_TIME);
+ SetError(ERROR_TIME, "Session timeout has occured.");
break;
case MSG_STATE:
@@ -925,7 +955,7 @@ bool Session::Initiate(const std::string &to,
// the TransportDescriptions.
SpeculativelyConnectAllTransportChannels();
- PushdownTransportDescription(CS_LOCAL, CA_OFFER);
+ PushdownTransportDescription(CS_LOCAL, CA_OFFER, NULL);
SetState(Session::STATE_SENTINITIATE);
return true;
}
@@ -946,7 +976,7 @@ bool Session::Accept(const SessionDescription* sdesc) {
return false;
}
// TODO(juberti): Add BUNDLE support to transport-info messages.
- PushdownTransportDescription(CS_LOCAL, CA_ANSWER);
+ PushdownTransportDescription(CS_LOCAL, CA_ANSWER, NULL);
MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
SetState(Session::STATE_SENTACCEPT);
return true;
@@ -1261,8 +1291,10 @@ void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
if (!OnRedirectError(redirect, &error)) {
// TODO: Should we send a message back? The standard
// says nothing about it.
- LOG(LS_ERROR) << "Failed to redirect: " << error.text;
- SetError(ERROR_RESPONSE);
+ std::ostringstream desc;
+ desc << "Failed to redirect: " << error.text;
+ LOG(LS_ERROR) << desc.str();
+ SetError(ERROR_RESPONSE, desc.str());
}
return;
}
@@ -1290,7 +1322,7 @@ void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
} else if ((error_type != "continue") && (error_type != "wait")) {
// We do not set an error if the other side said it is okay to continue
// (possibly after waiting). These errors can be ignored.
- SetError(ERROR_RESPONSE);
+ SetError(ERROR_RESPONSE, "");
}
}
@@ -1318,7 +1350,7 @@ bool Session::OnInitiateMessage(const SessionMessage& msg,
init.transports,
init.groups));
// Updating transport with TransportDescription.
- PushdownTransportDescription(CS_REMOTE, CA_OFFER);
+ PushdownTransportDescription(CS_REMOTE, CA_OFFER, NULL);
SetState(STATE_RECEIVEDINITIATE);
// Users of Session may listen to state change and call Reject().
@@ -1352,7 +1384,7 @@ bool Session::OnAcceptMessage(const SessionMessage& msg, MessageError* error) {
accept.transports,
accept.groups));
// Updating transport with TransportDescription.
- PushdownTransportDescription(CS_REMOTE, CA_ANSWER);
+ PushdownTransportDescription(CS_REMOTE, CA_ANSWER, NULL);
MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
SetState(STATE_RECEIVEDACCEPT);
@@ -1496,8 +1528,8 @@ bool Session::CheckState(State expected, MessageError* error) {
return true;
}
-void Session::SetError(Error error) {
- BaseSession::SetError(error);
+void Session::SetError(Error error, const std::string& error_desc) {
+ BaseSession::SetError(error, error_desc);
if (error != ERROR_NONE)
signaling_thread()->Post(this, MSG_ERROR);
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/session.h b/chromium/third_party/libjingle/source/talk/p2p/base/session.h
index 637c9424b7b..504187f6213 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/session.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/session.h
@@ -102,7 +102,9 @@ class TransportProxy : public sigslot::has_slots<>,
connecting_(false),
negotiated_(false),
sent_candidates_(false),
- candidates_allocated_(false) {
+ candidates_allocated_(false),
+ local_description_set_(false),
+ remote_description_set_(false) {
transport_->get()->SignalCandidatesReady.connect(
this, &TransportProxy::OnTransportCandidatesReady);
}
@@ -145,9 +147,11 @@ class TransportProxy : public sigslot::has_slots<>,
void SetIceRole(IceRole role);
void SetIdentity(talk_base::SSLIdentity* identity);
bool SetLocalTransportDescription(const TransportDescription& description,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
bool SetRemoteTransportDescription(const TransportDescription& description,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
void OnSignalingReady();
bool OnRemoteCandidates(const Candidates& candidates, std::string* error);
@@ -163,6 +167,13 @@ class TransportProxy : public sigslot::has_slots<>,
SignalCandidatesReady(this, candidates);
}
+ bool local_description_set() const {
+ return local_description_set_;
+ }
+ bool remote_description_set() const {
+ return remote_description_set_;
+ }
+
// Handles sending of ready candidates and receiving of remote candidates.
sigslot::signal2<TransportProxy*,
const std::vector<Candidate>&> SignalCandidatesReady;
@@ -194,6 +205,8 @@ class TransportProxy : public sigslot::has_slots<>,
Candidates sent_candidates_;
Candidates unsent_candidates_;
bool candidates_allocated_;
+ bool local_description_set_;
+ bool remote_description_set_;
};
typedef std::map<std::string, TransportProxy*> TransportMap;
@@ -327,13 +340,15 @@ class BaseSession : public sigslot::has_slots<>,
// Returns the last error in the session. See the enum above for details.
// Each time the an error occurs, we will fire this signal.
Error error() const { return error_; }
+ const std::string& error_desc() const { return error_desc_; }
sigslot::signal2<BaseSession* , Error> SignalError;
// Updates the state, signaling if necessary.
virtual void SetState(State state);
// Updates the error state, signaling if necessary.
- virtual void SetError(Error error);
+ // TODO(ronghuawu): remove the SetError method that doesn't take |error_desc|.
+ virtual void SetError(Error error, const std::string& error_desc);
// Fired when the remote description is updated, with the updated
// contents.
@@ -384,7 +399,8 @@ class BaseSession : public sigslot::has_slots<>,
bool SetIdentity(talk_base::SSLIdentity* identity);
bool PushdownTransportDescription(ContentSource source,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
void set_initiator(bool initiator) { initiator_ = initiator; }
const TransportMap& transport_proxies() const { return transports_; }
@@ -427,6 +443,14 @@ class BaseSession : public sigslot::has_slots<>,
virtual void OnTransportReadable(Transport* transport) {
}
+ // Called when a transport has found its steady-state connections.
+ virtual void OnTransportCompleted(Transport* transport) {
+ }
+
+ // Called when a transport has failed permanently.
+ virtual void OnTransportFailed(Transport* transport) {
+ }
+
// Called when a transport signals that it has new candidates.
virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy,
const Candidates& candidates) {
@@ -466,13 +490,16 @@ class BaseSession : public sigslot::has_slots<>,
protected:
State state_;
Error error_;
+ std::string error_desc_;
private:
// Helper methods to push local and remote transport descriptions.
bool PushdownLocalTransportDescription(
- const SessionDescription* sdesc, ContentAction action);
+ const SessionDescription* sdesc, ContentAction action,
+ std::string* error_desc);
bool PushdownRemoteTransportDescription(
- const SessionDescription* sdesc, ContentAction action);
+ const SessionDescription* sdesc, ContentAction action,
+ std::string* error_desc);
bool IsCandidateAllocationDone() const;
void MaybeCandidateAllocationDone();
@@ -553,7 +580,7 @@ class Session : public BaseSession {
}
// Updates the error state, signaling if necessary.
- virtual void SetError(Error error);
+ virtual void SetError(Error error, const std::string& error_desc);
// When the session needs to send signaling messages, it beings by requesting
// signaling. The client should handle this by calling OnSignalingReady once
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/session_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/session_unittest.cc
index ab4620f879e..1c08bf18dd0 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/session_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/session_unittest.cc
@@ -25,14 +25,14 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <cstring>
+#include <string.h>
+
#include <sstream>
#include <deque>
#include <map>
#include "talk/base/base64.h"
#include "talk/base/common.h"
-#include "talk/base/dscp.h"
#include "talk/base/gunit.h"
#include "talk/base/helpers.h"
#include "talk/base/logging.h"
@@ -77,19 +77,6 @@ static const int kNumPorts = 2;
static const int kPort0 = 28653;
static const int kPortStep = 5;
-static const std::string kNotifyNick1 = "derekcheng_google.com^59422C27";
-static const std::string kNotifyNick2 = "someoneelses_google.com^7abd6a7a20";
-static const uint32 kNotifyAudioSsrc1 = 2625839801U;
-static const uint32 kNotifyAudioSsrc2 = 2529430427U;
-static const uint32 kNotifyVideoSsrc1 = 3;
-static const uint32 kNotifyVideoSsrc2 = 2;
-
-static const std::string kViewRequestNick = "param_google.com^16A3CDBE";
-static const uint32 kViewRequestSsrc = 4;
-static const int kViewRequestWidth = 320;
-static const int kViewRequestHeight = 200;
-static const int kViewRequestFrameRate = 15;
-
int GetPort(int port_index) {
return kPort0 + (port_index * kPortStep);
}
@@ -824,14 +811,15 @@ struct ChannelHandler : sigslot::has_slots<> {
EXPECT_LE(size, sizeof(last_data));
data_count += 1;
last_size = size;
- std::memcpy(last_data, buf, size);
+ memcpy(last_data, buf, size);
}
void Send(const char* data, size_t size) {
+ talk_base::PacketOptions options;
std::string data_with_id(name);
data_with_id += data;
int result = channel->SendPacket(data_with_id.c_str(), data_with_id.size(),
- talk_base::DSCP_NO_CHANGE, 0);
+ options, 0);
EXPECT_EQ(static_cast<int>(data_with_id.size()), result);
}
@@ -1170,14 +1158,10 @@ class SessionTest : public testing::Test {
EXPECT_EQ(strlen(dat1a), chan2a->last_size);
EXPECT_EQ(strlen(dat1b), chan2b->last_size);
- EXPECT_EQ(0, std::memcmp(chan1a->last_data, dat2a,
- strlen(dat2a)));
- EXPECT_EQ(0, std::memcmp(chan1b->last_data, dat2b,
- strlen(dat2b)));
- EXPECT_EQ(0, std::memcmp(chan2a->last_data, dat1a,
- strlen(dat1a)));
- EXPECT_EQ(0, std::memcmp(chan2b->last_data, dat1b,
- strlen(dat1b)));
+ EXPECT_EQ(0, memcmp(chan1a->last_data, dat2a, strlen(dat2a)));
+ EXPECT_EQ(0, memcmp(chan1b->last_data, dat2b, strlen(dat2b)));
+ EXPECT_EQ(0, memcmp(chan2a->last_data, dat1a, strlen(dat1a)));
+ EXPECT_EQ(0, memcmp(chan2b->last_data, dat1b, strlen(dat1b)));
}
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/stun.cc b/chromium/third_party/libjingle/source/talk/p2p/base/stun.cc
index 38fc96ee1a4..6331ba9ebd2 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/stun.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/stun.cc
@@ -27,7 +27,7 @@
#include "talk/p2p/base/stun.h"
-#include <cstring>
+#include <string.h>
#include "talk/base/byteorder.h"
#include "talk/base/common.h"
@@ -217,8 +217,9 @@ bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
return false;
// Comparing the calculated HMAC with the one present in the message.
- return (std::memcmp(data + current_pos + kStunAttributeHeaderSize,
- hmac, sizeof(hmac)) == 0);
+ return memcmp(data + current_pos + kStunAttributeHeaderSize,
+ hmac,
+ sizeof(hmac)) == 0;
}
bool StunMessage::AddMessageIntegrity(const std::string& password) {
@@ -734,7 +735,7 @@ void StunByteStringAttribute::CopyBytes(const char* bytes) {
void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) {
char* new_bytes = new char[length];
- std::memcpy(new_bytes, bytes, length);
+ memcpy(new_bytes, bytes, length);
SetBytes(new_bytes, length);
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/stun_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/stun_unittest.cc
index 6a5bcd9bbb9..71d87500e99 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/stun_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/stun_unittest.cc
@@ -50,8 +50,7 @@ class StunTest : public ::testing::Test {
ASSERT_EQ(length, msg.transaction_id().size());
ASSERT_EQ(length == kStunTransactionIdLength + 4, msg.IsLegacy());
ASSERT_EQ(length == kStunTransactionIdLength, !msg.IsLegacy());
- ASSERT_EQ(0, std::memcmp(msg.transaction_id().c_str(),
- expectedID, length));
+ ASSERT_EQ(0, memcmp(msg.transaction_id().c_str(), expectedID, length));
}
void CheckStunAddressAttribute(const StunAddressAttribute* addr,
@@ -64,13 +63,11 @@ class StunTest : public ::testing::Test {
if (addr->family() == STUN_ADDRESS_IPV4) {
in_addr v4_address = expected_address.ipv4_address();
in_addr stun_address = addr->ipaddr().ipv4_address();
- ASSERT_EQ(0, std::memcmp(&v4_address, &stun_address,
- sizeof(stun_address)));
+ ASSERT_EQ(0, memcmp(&v4_address, &stun_address, sizeof(stun_address)));
} else if (addr->family() == STUN_ADDRESS_IPV6) {
in6_addr v6_address = expected_address.ipv6_address();
in6_addr stun_address = addr->ipaddr().ipv6_address();
- ASSERT_EQ(0, std::memcmp(&v6_address, &stun_address,
- sizeof(stun_address)));
+ ASSERT_EQ(0, memcmp(&v6_address, &stun_address, sizeof(stun_address)));
} else {
ASSERT_TRUE(addr->family() == STUN_ADDRESS_IPV6 ||
addr->family() == STUN_ADDRESS_IPV4);
@@ -211,37 +208,6 @@ static const unsigned char kStunMessageWithErrorAttribute[] = {
0x69, 0x7a, 0x65, 0x64
};
-// Message with an address attribute with an unknown address family,
-// and a byte string attribute. Check that we quit reading after the
-// bogus address family and don't read the username attribute.
-static const unsigned char kStunMessageWithInvalidAddressFamily[] = {
- 0x01, 0x01, 0x00, 0x18, // binding response, length 24
- 0x21, 0x12, 0xa4, 0x42, // magic cookie
- 0x29, 0x1f, 0xcd, 0x7c, // transaction ID
- 0xba, 0x58, 0xab, 0xd7,
- 0xf2, 0x41, 0x01, 0x00,
- 0x00, 0x01, 0x00, 0x08, // Mapped address, 4 byte length
- 0x00, 0x09, 0xfe, 0xed, // Bogus address family (port unimportant).
- 0xac, 0x17, 0x44, 0xe6, // Should be skipped.
- 0x00, 0x06, 0x00, 0x08, // Username attribute (length 8)
- 0x61, 0x62, 0x63, 0x64, // abcdefgh
- 0x65, 0x66, 0x67, 0x68
-};
-
-// Message with an address attribute with an invalid address length.
-// Should fail to be read.
-static const unsigned char kStunMessageWithInvalidAddressLength[] = {
- 0x01, 0x01, 0x00, 0x18, // binding response, length 24
- 0x21, 0x12, 0xa4, 0x42, // magic cookie
- 0x29, 0x1f, 0xcd, 0x7c, // transaction ID
- 0xba, 0x58, 0xab, 0xd7,
- 0xf2, 0x41, 0x01, 0x00,
- 0x00, 0x01, 0x00, 0x0c, // Mapped address, 12 byte length
- 0x00, 0x01, 0xfe, 0xed, // Claims to be AF_INET.
- 0xac, 0x17, 0x44, 0xe6,
- 0x00, 0x06, 0x00, 0x08
-};
-
// Sample messages with an invalid length Field
// The actual length in bytes of the invalid messages (including STUN header)
@@ -514,19 +480,10 @@ const in6_addr kIPv6TestAddress2 = { { { 0x24, 0x01, 0xfa, 0x00,
0x06, 0x0c, 0xce, 0xff,
0xfe, 0x1f, 0x61, 0xa4 } } };
-// This is kIPv6TestAddress1 xor-ed with kTestTransactionID2.
-const in6_addr kIPv6XoredTestAddress = { { { 0x05, 0x13, 0x5e, 0x42,
- 0xe3, 0xad, 0x56, 0xe1,
- 0xc2, 0x30, 0x99, 0x9d,
- 0xaa, 0xed, 0x01, 0xc3 } } };
-
#ifdef POSIX
const in_addr kIPv4TestAddress1 = { 0xe64417ac };
-// This is kIPv4TestAddress xored with the STUN magic cookie.
-const in_addr kIPv4XoredTestAddress = { 0x8d05e0a4 };
#elif defined WIN32
// Windows in_addr has a union with a uchar[] array first.
-const in_addr kIPv4XoredTestAddress = { { 0x8d, 0x05, 0xe0, 0xa4 } };
const in_addr kIPv4TestAddress1 = { { 0x0ac, 0x017, 0x044, 0x0e6 } };
#endif
const char kTestUserName1[] = "abcdefgh";
@@ -788,9 +745,8 @@ TEST_F(StunTest, SetIPv6XorAddressAttributeOwner) {
EXPECT_TRUE(addr->Write(&correct_buf));
EXPECT_TRUE(addr2.Write(&wrong_buf));
// But when written out, the buffers should look different.
- ASSERT_NE(0, std::memcmp(correct_buf.Data(),
- wrong_buf.Data(),
- wrong_buf.Length()));
+ ASSERT_NE(0,
+ memcmp(correct_buf.Data(), wrong_buf.Data(), wrong_buf.Length()));
// And when reading a known good value, the address should be wrong.
addr2.Read(&correct_buf);
ASSERT_NE(addr->ipaddr(), addr2.ipaddr());
@@ -836,9 +792,8 @@ TEST_F(StunTest, SetIPv4XorAddressAttributeOwner) {
EXPECT_TRUE(addr->Write(&correct_buf));
EXPECT_TRUE(addr2.Write(&wrong_buf));
// The same address data should be written.
- ASSERT_EQ(0, std::memcmp(correct_buf.Data(),
- wrong_buf.Data(),
- wrong_buf.Length()));
+ ASSERT_EQ(0,
+ memcmp(correct_buf.Data(), wrong_buf.Data(), wrong_buf.Length()));
// And an attribute should be able to un-XOR an address belonging to a message
// with a different transaction ID.
EXPECT_TRUE(addr2.Read(&correct_buf));
@@ -927,9 +882,7 @@ TEST_F(StunTest, WriteMessageWithIPv6AddressAttribute) {
int len1 = static_cast<int>(out.Length());
std::string bytes;
out.ReadString(&bytes, len1);
- ASSERT_EQ(0, std::memcmp(bytes.c_str(),
- kStunMessageWithIPv6MappedAddress,
- len1));
+ ASSERT_EQ(0, memcmp(bytes.c_str(), kStunMessageWithIPv6MappedAddress, len1));
}
TEST_F(StunTest, WriteMessageWithIPv4AddressAttribute) {
@@ -958,9 +911,7 @@ TEST_F(StunTest, WriteMessageWithIPv4AddressAttribute) {
int len1 = static_cast<int>(out.Length());
std::string bytes;
out.ReadString(&bytes, len1);
- ASSERT_EQ(0, std::memcmp(bytes.c_str(),
- kStunMessageWithIPv4MappedAddress,
- len1));
+ ASSERT_EQ(0, memcmp(bytes.c_str(), kStunMessageWithIPv4MappedAddress, len1));
}
TEST_F(StunTest, WriteMessageWithIPv6XorAddressAttribute) {
@@ -989,9 +940,8 @@ TEST_F(StunTest, WriteMessageWithIPv6XorAddressAttribute) {
int len1 = static_cast<int>(out.Length());
std::string bytes;
out.ReadString(&bytes, len1);
- ASSERT_EQ(0, std::memcmp(bytes.c_str(),
- kStunMessageWithIPv6XorMappedAddress,
- len1));
+ ASSERT_EQ(0,
+ memcmp(bytes.c_str(), kStunMessageWithIPv6XorMappedAddress, len1));
}
TEST_F(StunTest, WriteMessageWithIPv4XoreAddressAttribute) {
@@ -1020,9 +970,8 @@ TEST_F(StunTest, WriteMessageWithIPv4XoreAddressAttribute) {
int len1 = static_cast<int>(out.Length());
std::string bytes;
out.ReadString(&bytes, len1);
- ASSERT_EQ(0, std::memcmp(bytes.c_str(),
- kStunMessageWithIPv4XorMappedAddress,
- len1));
+ ASSERT_EQ(0,
+ memcmp(bytes.c_str(), kStunMessageWithIPv4XorMappedAddress, len1));
}
TEST_F(StunTest, ReadByteStringAttribute) {
@@ -1107,7 +1056,7 @@ TEST_F(StunTest, WriteMessageWithAnErrorCodeAttribute) {
EXPECT_TRUE(msg.Write(&out));
ASSERT_EQ(size, out.Length());
// No padding.
- ASSERT_EQ(0, std::memcmp(out.Data(), kStunMessageWithErrorAttribute, size));
+ ASSERT_EQ(0, memcmp(out.Data(), kStunMessageWithErrorAttribute, size));
}
TEST_F(StunTest, WriteMessageWithAUInt16ListAttribute) {
@@ -1130,8 +1079,8 @@ TEST_F(StunTest, WriteMessageWithAUInt16ListAttribute) {
EXPECT_TRUE(msg.Write(&out));
ASSERT_EQ(size, out.Length());
// Check everything up to the padding.
- ASSERT_EQ(0, std::memcmp(out.Data(), kStunMessageWithUInt16ListAttribute,
- size - 2));
+ ASSERT_EQ(0,
+ memcmp(out.Data(), kStunMessageWithUInt16ListAttribute, size - 2));
}
// Test that we fail to read messages with invalid lengths.
@@ -1238,7 +1187,7 @@ TEST_F(StunTest, AddMessageIntegrity) {
const StunByteStringAttribute* mi_attr =
msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
EXPECT_EQ(20U, mi_attr->length());
- EXPECT_EQ(0, std::memcmp(
+ EXPECT_EQ(0, memcmp(
mi_attr->bytes(), kCalculatedHmac1, sizeof(kCalculatedHmac1)));
talk_base::ByteBuffer buf1;
@@ -1256,8 +1205,8 @@ TEST_F(StunTest, AddMessageIntegrity) {
const StunByteStringAttribute* mi_attr2 =
msg2.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
EXPECT_EQ(20U, mi_attr2->length());
- EXPECT_EQ(0, std::memcmp(
- mi_attr2->bytes(), kCalculatedHmac2, sizeof(kCalculatedHmac2)));
+ EXPECT_EQ(
+ 0, memcmp(mi_attr2->bytes(), kCalculatedHmac2, sizeof(kCalculatedHmac2)));
talk_base::ByteBuffer buf3;
EXPECT_TRUE(msg2.Write(&buf3));
@@ -1401,8 +1350,10 @@ TEST_F(StunTest, ReadRelayMessage) {
bytes = msg.GetByteString(STUN_ATTR_MAGIC_COOKIE);
ASSERT_TRUE(bytes != NULL);
EXPECT_EQ(4U, bytes->length());
- EXPECT_EQ(0, std::memcmp(bytes->bytes(), TURN_MAGIC_COOKIE_VALUE,
- sizeof(TURN_MAGIC_COOKIE_VALUE)));
+ EXPECT_EQ(0,
+ memcmp(bytes->bytes(),
+ TURN_MAGIC_COOKIE_VALUE,
+ sizeof(TURN_MAGIC_COOKIE_VALUE)));
bytes2 = StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
bytes2->CopyBytes(reinterpret_cast<const char*>(TURN_MAGIC_COOKIE_VALUE),
@@ -1454,7 +1405,7 @@ TEST_F(StunTest, ReadRelayMessage) {
size_t len1 = out.Length();
std::string outstring;
out.ReadString(&outstring, len1);
- EXPECT_EQ(0, std::memcmp(outstring.c_str(), input, len1));
+ EXPECT_EQ(0, memcmp(outstring.c_str(), input, len1));
talk_base::ByteBuffer out2;
EXPECT_TRUE(msg2.Write(&out2));
@@ -1462,7 +1413,7 @@ TEST_F(StunTest, ReadRelayMessage) {
size_t len2 = out2.Length();
std::string outstring2;
out2.ReadString(&outstring2, len2);
- EXPECT_EQ(0, std::memcmp(outstring2.c_str(), input, len2));
+ EXPECT_EQ(0, memcmp(outstring2.c_str(), input, len2));
}
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/stunport.cc b/chromium/third_party/libjingle/source/talk/p2p/base/stunport.cc
index 913f9af5f5b..6e18fc50569 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/stunport.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/stunport.cc
@@ -173,7 +173,7 @@ bool UDPPort::Init() {
UDPPort::~UDPPort() {
if (resolver_) {
- resolver_->Destroy(false);
+ resolver_->Destroy(true);
}
if (!SharedSocket())
delete socket_;
@@ -192,7 +192,7 @@ void UDPPort::MaybePrepareStunCandidate() {
if (!server_addr_.IsNil()) {
SendStunBindingRequest();
} else {
- // Processing host candidate address.
+ // Port is done allocating candidates.
SetResult(true);
}
}
@@ -218,9 +218,9 @@ Connection* UDPPort::CreateConnection(const Candidate& address,
int UDPPort::SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
bool payload) {
- int sent = socket_->SendTo(data, size, addr, dscp);
+ int sent = socket_->SendTo(data, size, addr, options);
if (sent < 0) {
error_ = socket_->GetError();
LOG_J(LS_ERROR, this) << "UDP send of " << size
@@ -230,12 +230,6 @@ int UDPPort::SendTo(const void* data, size_t size,
}
int UDPPort::SetOption(talk_base::Socket::Option opt, int value) {
- // TODO(mallinath) - After we have the support on socket,
- // remove this specialization.
- if (opt == talk_base::Socket::OPT_DSCP) {
- SetDefaultDscpValue(static_cast<talk_base::DiffServCodePoint>(value));
- return 0;
- }
return socket_->SetOption(opt, value);
}
@@ -249,7 +243,8 @@ int UDPPort::GetError() {
void UDPPort::OnLocalAddressReady(talk_base::AsyncPacketSocket* socket,
const talk_base::SocketAddress& address) {
- AddAddress(address, address, UDP_PROTOCOL_NAME, LOCAL_PORT_TYPE,
+ AddAddress(address, address, talk_base::SocketAddress(),
+ UDP_PROTOCOL_NAME, LOCAL_PORT_TYPE,
ICE_TYPE_PREFERENCE_HOST, false);
MaybePrepareStunCandidate();
}
@@ -330,11 +325,10 @@ void UDPPort::OnStunBindingRequestSucceeded(
if (!SharedSocket() || stun_addr != socket_->GetLocalAddress()) {
// If socket is shared and |stun_addr| is equal to local socket
// address then discarding the stun address.
- // Setting related address before STUN candidate is added. For STUN
- // related address is local socket address.
- set_related_address(socket_->GetLocalAddress());
- AddAddress(stun_addr, socket_->GetLocalAddress(), UDP_PROTOCOL_NAME,
- STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_PRFLX, false);
+ // For STUN related address is local socket address.
+ AddAddress(stun_addr, socket_->GetLocalAddress(),
+ socket_->GetLocalAddress(), UDP_PROTOCOL_NAME,
+ STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, false);
}
SetResult(true);
}
@@ -360,7 +354,8 @@ void UDPPort::SetResult(bool success) {
// TODO: merge this with SendTo above.
void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) {
StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req);
- if (socket_->SendTo(data, size, sreq->server_addr(), DefaultDscpValue()) < 0)
+ talk_base::PacketOptions options(DefaultDscpValue());
+ if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0)
PLOG(LERROR, socket_->GetError()) << "sendto";
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/stunport.h b/chromium/third_party/libjingle/source/talk/p2p/base/stunport.h
index a8b89c3be5d..c45d6af334c 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/stunport.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/stunport.h
@@ -125,7 +125,7 @@ class UDPPort : public Port {
virtual int SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
bool payload);
void OnLocalAddressReady(talk_base::AsyncPacketSocket* socket,
@@ -142,7 +142,6 @@ class UDPPort : public Port {
void SendStunBindingRequest();
-
private:
// DNS resolution of the STUN server.
void ResolveStunAddress();
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/stunport_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/stunport_unittest.cc
index 2a98a9fdb8b..5850027ec8d 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/stunport_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/stunport_unittest.cc
@@ -43,6 +43,8 @@ static const SocketAddress kBadAddr("0.0.0.1", 5000);
static const SocketAddress kStunHostnameAddr("localhost", 5000);
static const SocketAddress kBadHostnameAddr("not-a-real-hostname", 5000);
static const int kTimeoutMs = 10000;
+// stun prio = 100 << 24 | 30 (IPV4) << 8 | 256 - 0
+static const uint32 kStunCandidatePriority = 1677729535;
// Tests connecting a StunPort to a fake STUN server (cricket::StunServer)
// TODO: Use a VirtualSocketServer here. We have to use a
@@ -178,6 +180,7 @@ TEST_F(StunPortTest, TestPrepareAddressHostname) {
EXPECT_TRUE_WAIT(done(), kTimeoutMs);
ASSERT_EQ(1U, port()->Candidates().size());
EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
+ EXPECT_EQ(kStunCandidatePriority, port()->Candidates()[0].priority());
}
// Test that we handle hostname lookup failures properly.
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/stunrequest_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/stunrequest_unittest.cc
index b641585a70b..508660c8499 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/stunrequest_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/stunrequest_unittest.cc
@@ -28,6 +28,7 @@
#include "talk/base/gunit.h"
#include "talk/base/helpers.h"
#include "talk/base/logging.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/timeutils.h"
#include "talk/p2p/base/stunrequest.h"
@@ -37,8 +38,13 @@ class StunRequestTest : public testing::Test,
public sigslot::has_slots<> {
public:
static void SetUpTestCase() {
- talk_base::InitRandom(NULL, 0);
+ talk_base::InitializeSSL();
}
+
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
+ }
+
StunRequestTest()
: manager_(talk_base::Thread::Current()),
request_count_(0), response_(NULL),
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/stunserver.cc b/chromium/third_party/libjingle/source/talk/p2p/base/stunserver.cc
index 062be206876..ee6c64376bc 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/stunserver.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/stunserver.cc
@@ -103,8 +103,8 @@ void StunServer::SendResponse(
const StunMessage& msg, const talk_base::SocketAddress& addr) {
talk_base::ByteBuffer buf;
msg.Write(&buf);
- if (socket_->SendTo(
- buf.Data(), buf.Length(), addr, talk_base::DSCP_NO_CHANGE) < 0)
+ talk_base::PacketOptions options;
+ if (socket_->SendTo(buf.Data(), buf.Length(), addr, options) < 0)
LOG_ERR(LS_ERROR) << "sendto";
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/stunserver_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/stunserver_unittest.cc
index abb19578696..a6f56a5176e 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/stunserver_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/stunserver_unittest.cc
@@ -119,7 +119,7 @@ TEST_F(StunServerTest, TestBad) {
const char* bad = "this is a completely nonsensical message whose only "
"purpose is to make the parser go 'ack'. it doesn't "
"look anything like a normal stun message";
- Send(bad, static_cast<int>(std::strlen(bad)));
+ Send(bad, static_cast<int>(strlen(bad)));
StunMessage* msg = Receive();
ASSERT_TRUE(msg == NULL);
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/tcpport.cc b/chromium/third_party/libjingle/source/talk/p2p/base/tcpport.cc
index 2cca82f1946..069323a3cd3 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/tcpport.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/tcpport.cc
@@ -121,6 +121,7 @@ void TCPPort::PrepareAddress() {
if (socket_->GetState() == talk_base::AsyncPacketSocket::STATE_BOUND ||
socket_->GetState() == talk_base::AsyncPacketSocket::STATE_CLOSED)
AddAddress(socket_->GetLocalAddress(), socket_->GetLocalAddress(),
+ talk_base::SocketAddress(),
TCP_PROTOCOL_NAME, LOCAL_PORT_TYPE,
ICE_TYPE_PREFERENCE_HOST_TCP, true);
} else {
@@ -128,14 +129,15 @@ void TCPPort::PrepareAddress() {
// Note: We still add the address, since otherwise the remote side won't
// recognize our incoming TCP connections.
AddAddress(talk_base::SocketAddress(ip(), 0),
- talk_base::SocketAddress(ip(), 0), TCP_PROTOCOL_NAME,
- LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST_TCP, true);
+ talk_base::SocketAddress(ip(), 0), talk_base::SocketAddress(),
+ TCP_PROTOCOL_NAME, LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST_TCP,
+ true);
}
}
int TCPPort::SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
bool payload) {
talk_base::AsyncPacketSocket * socket = NULL;
if (TCPConnection * conn = static_cast<TCPConnection*>(GetConnection(addr))) {
@@ -149,7 +151,7 @@ int TCPPort::SendTo(const void* data, size_t size,
return -1; // TODO: Set error_
}
- int sent = socket->Send(data, size, dscp);
+ int sent = socket->Send(data, size, options);
if (sent < 0) {
error_ = socket->GetError();
LOG_J(LS_ERROR, this) << "TCP send of " << size
@@ -167,14 +169,6 @@ int TCPPort::GetOption(talk_base::Socket::Option opt, int* value) {
}
int TCPPort::SetOption(talk_base::Socket::Option opt, int value) {
- // If we are setting DSCP value, pass value to base Port and return.
- // TODO(mallinath) - After we have the support on socket,
- // remove this specialization.
- if (opt == talk_base::Socket::OPT_DSCP) {
- SetDefaultDscpValue(static_cast<talk_base::DiffServCodePoint>(value));
- return 0;
- }
-
if (socket_) {
return socket_->SetOption(opt, value);
} else {
@@ -229,7 +223,7 @@ void TCPPort::OnReadyToSend(talk_base::AsyncPacketSocket* socket) {
void TCPPort::OnAddressReady(talk_base::AsyncPacketSocket* socket,
const talk_base::SocketAddress& address) {
- AddAddress(address, address, "tcp",
+ AddAddress(address, address, talk_base::SocketAddress(), "tcp",
LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST_TCP,
true);
}
@@ -243,7 +237,7 @@ TCPConnection::TCPConnection(TCPPort* port, const Candidate& candidate,
int opts = (candidate.protocol() == SSLTCP_PROTOCOL_NAME) ?
talk_base::PacketSocketFactory::OPT_SSLTCP : 0;
socket_ = port->socket_factory()->CreateClientTcpSocket(
- talk_base::SocketAddress(port_->Network()->ip(), 0),
+ talk_base::SocketAddress(port->ip(), 0),
candidate.address(), port->proxy(), port->user_agent(), opts);
if (socket_) {
LOG_J(LS_VERBOSE, this) << "Connecting from "
@@ -273,7 +267,7 @@ TCPConnection::~TCPConnection() {
}
int TCPConnection::Send(const void* data, size_t size,
- talk_base::DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
if (!socket_) {
error_ = ENOTCONN;
return SOCKET_ERROR;
@@ -284,7 +278,7 @@ int TCPConnection::Send(const void* data, size_t size,
error_ = EWOULDBLOCK;
return SOCKET_ERROR;
}
- int sent = socket_->Send(data, size, dscp);
+ int sent = socket_->Send(data, size, options);
if (sent < 0) {
error_ = socket_->GetError();
} else {
@@ -299,9 +293,19 @@ int TCPConnection::GetError() {
void TCPConnection::OnConnect(talk_base::AsyncPacketSocket* socket) {
ASSERT(socket == socket_);
- LOG_J(LS_VERBOSE, this) << "Connection established to "
- << socket->GetRemoteAddress().ToSensitiveString();
- set_connected(true);
+ // Do not use this connection if the socket bound to a different address than
+ // the one we asked for. This is seen in Chrome, where TCP sockets cannot be
+ // given a binding address, and the platform is expected to pick the
+ // correct local address.
+ if (socket->GetLocalAddress().ipaddr() == port()->ip()) {
+ LOG_J(LS_VERBOSE, this) << "Connection established to "
+ << socket->GetRemoteAddress().ToSensitiveString();
+ set_connected(true);
+ } else {
+ LOG_J(LS_WARNING, this) << "Dropping connection as TCP socket bound to a "
+ << "different address from the local candidate.";
+ socket_->Close();
+ }
}
void TCPConnection::OnClose(talk_base::AsyncPacketSocket* socket, int error) {
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/tcpport.h b/chromium/third_party/libjingle/source/talk/p2p/base/tcpport.h
index 77b177a2d51..c152ec0d386 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/tcpport.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/tcpport.h
@@ -83,7 +83,7 @@ class TCPPort : public Port {
// Handles sending using the local TCP socket.
virtual int SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
bool payload);
// Accepts incoming TCP connection.
@@ -128,7 +128,7 @@ class TCPConnection : public Connection {
virtual ~TCPConnection();
virtual int Send(const void* data, size_t size,
- talk_base::DiffServCodePoint dscp);
+ const talk_base::PacketOptions& options);
virtual int GetError();
talk_base::AsyncPacketSocket* socket() { return socket_; }
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/transport.cc b/chromium/third_party/libjingle/source/talk/p2p/base/transport.cc
index 4404c081a83..16087e3f069 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/transport.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/transport.cc
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2005, Google Inc.
+ * Copyright 2004, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -53,6 +53,8 @@ enum {
MSG_CONNECTING,
MSG_CANDIDATEALLOCATIONCOMPLETE,
MSG_ROLECONFLICT,
+ MSG_COMPLETED,
+ MSG_FAILED,
};
struct ChannelParams : public talk_base::MessageData {
@@ -73,6 +75,49 @@ struct ChannelParams : public talk_base::MessageData {
Candidate* candidate;
};
+static std::string IceProtoToString(TransportProtocol proto) {
+ std::string proto_str;
+ switch (proto) {
+ case ICEPROTO_GOOGLE:
+ proto_str = "gice";
+ break;
+ case ICEPROTO_HYBRID:
+ proto_str = "hybrid";
+ break;
+ case ICEPROTO_RFC5245:
+ proto_str = "ice";
+ break;
+ default:
+ ASSERT(false);
+ break;
+ }
+ return proto_str;
+}
+
+static bool VerifyIceParams(const TransportDescription& desc) {
+ // For legacy protocols.
+ if (desc.ice_ufrag.empty() && desc.ice_pwd.empty())
+ return true;
+
+ if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH ||
+ desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) {
+ return false;
+ }
+ if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
+ desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
+ return false;
+ }
+ return true;
+}
+
+bool BadTransportDescription(const std::string& desc, std::string* err_desc) {
+ if (err_desc) {
+ *err_desc = desc;
+ }
+ LOG(LS_ERROR) << desc;
+ return false;
+}
+
Transport::Transport(talk_base::Thread* signaling_thread,
talk_base::Thread* worker_thread,
const std::string& content_name,
@@ -131,15 +176,21 @@ bool Transport::GetRemoteCertificate_w(talk_base::SSLCertificate** cert) {
}
bool Transport::SetLocalTransportDescription(
- const TransportDescription& description, ContentAction action) {
+ const TransportDescription& description,
+ ContentAction action,
+ std::string* error_desc) {
return worker_thread_->Invoke<bool>(Bind(
- &Transport::SetLocalTransportDescription_w, this, description, action));
+ &Transport::SetLocalTransportDescription_w, this,
+ description, action, error_desc));
}
bool Transport::SetRemoteTransportDescription(
- const TransportDescription& description, ContentAction action) {
+ const TransportDescription& description,
+ ContentAction action,
+ std::string* error_desc) {
return worker_thread_->Invoke<bool>(Bind(
- &Transport::SetRemoteTransportDescription_w, this, description, action));
+ &Transport::SetRemoteTransportDescription_w, this,
+ description, action, error_desc));
}
TransportChannelImpl* Transport::CreateChannel(int component) {
@@ -175,13 +226,14 @@ TransportChannelImpl* Transport::CreateChannel_w(int component) {
// Push down our transport state to the new channel.
impl->SetIceRole(ice_role_);
impl->SetIceTiebreaker(tiebreaker_);
- if (local_description_) {
- ApplyLocalTransportDescription_w(impl);
- if (remote_description_) {
- ApplyRemoteTransportDescription_w(impl);
- ApplyNegotiatedTransportDescription_w(impl);
- }
- }
+ // TODO(ronghuawu): Change CreateChannel_w to be able to return error since
+ // below Apply**Description_w calls can fail.
+ if (local_description_)
+ ApplyLocalTransportDescription_w(impl, NULL);
+ if (remote_description_)
+ ApplyRemoteTransportDescription_w(impl, NULL);
+ if (local_description_ && remote_description_)
+ ApplyNegotiatedTransportDescription_w(impl, NULL);
impl->SignalReadableState.connect(this, &Transport::OnChannelReadableState);
impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState);
@@ -192,6 +244,8 @@ TransportChannelImpl* Transport::CreateChannel_w(int component) {
impl->SignalCandidatesAllocationDone.connect(
this, &Transport::OnChannelCandidatesAllocationDone);
impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict);
+ impl->SignalConnectionRemoved.connect(
+ this, &Transport::OnChannelConnectionRemoved);
if (connect_requested_) {
impl->Connect();
@@ -276,7 +330,7 @@ void Transport::ConnectChannels_w() {
talk_base::CreateRandomString(ICE_PWD_LENGTH),
ICEMODE_FULL, CONNECTIONROLE_NONE, NULL,
Candidates());
- SetLocalTransportDescription_w(desc, CA_OFFER);
+ SetLocalTransportDescription_w(desc, CA_OFFER, NULL);
}
CallChannels_w(&TransportChannelImpl::Connect);
@@ -367,6 +421,12 @@ bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) {
// Disallow all ports below 1024, except for 80 and 443 on public addresses.
int port = cand.address().port();
+ if (port == 0) {
+ // Expected for active-only candidates per
+ // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
+ *error = "";
+ return false;
+ }
if (port < 1024) {
if ((port != 80) && (port != 443)) {
*error = "candidate has port below 1024, but not 80 or 443";
@@ -459,6 +519,8 @@ void Transport::OnChannelReadableState_s() {
void Transport::OnChannelWritableState(TransportChannel* channel) {
ASSERT(worker_thread()->IsCurrent());
signaling_thread()->Post(this, MSG_WRITESTATE, NULL);
+
+ MaybeCompleted_w();
}
void Transport::OnChannelWritableState_s() {
@@ -574,6 +636,8 @@ void Transport::OnChannelCandidatesAllocationDone(
return;
}
signaling_thread_->Post(this, MSG_CANDIDATEALLOCATIONCOMPLETE);
+
+ MaybeCompleted_w();
}
void Transport::OnChannelCandidatesAllocationDone_s() {
@@ -586,6 +650,51 @@ void Transport::OnRoleConflict(TransportChannelImpl* channel) {
signaling_thread_->Post(this, MSG_ROLECONFLICT);
}
+void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) {
+ ASSERT(worker_thread()->IsCurrent());
+ MaybeCompleted_w();
+
+ // Check if the state is now Failed.
+ // Failed is only available in the Controlling ICE role.
+ if (channel->GetIceRole() != ICEROLE_CONTROLLING) {
+ return;
+ }
+
+ ChannelMap::iterator iter = channels_.find(channel->component());
+ ASSERT(iter != channels_.end());
+ // Failed can only occur after candidate allocation has stopped.
+ if (!iter->second.candidates_allocated()) {
+ return;
+ }
+
+ size_t connections = channel->GetConnectionCount();
+ if (connections == 0) {
+ // A Transport has failed if any of its channels have no remaining
+ // connections.
+ signaling_thread_->Post(this, MSG_FAILED);
+ }
+}
+
+void Transport::MaybeCompleted_w() {
+ ASSERT(worker_thread()->IsCurrent());
+
+ // A Transport's ICE process is completed if all of its channels are writable,
+ // have finished allocating candidates, and have pruned all but one of their
+ // connections.
+ ChannelMap::const_iterator iter;
+ for (iter = channels_.begin(); iter != channels_.end(); ++iter) {
+ const TransportChannelImpl* channel = iter->second.get();
+ if (!(channel->writable() &&
+ channel->GetConnectionCount() == 1 &&
+ channel->GetIceRole() == ICEROLE_CONTROLLING &&
+ iter->second.candidates_allocated())) {
+ return;
+ }
+ }
+
+ signaling_thread_->Post(this, MSG_COMPLETED);
+}
+
void Transport::SetIceRole_w(IceRole role) {
talk_base::CritScope cs(&crit_);
ice_role_ = role;
@@ -606,63 +715,95 @@ void Transport::SetRemoteIceMode_w(IceMode mode) {
}
bool Transport::SetLocalTransportDescription_w(
- const TransportDescription& desc, ContentAction action) {
+ const TransportDescription& desc,
+ ContentAction action,
+ std::string* error_desc) {
bool ret = true;
talk_base::CritScope cs(&crit_);
- local_description_.reset(new TransportDescription(desc));
+ if (!VerifyIceParams(desc)) {
+ return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
+ error_desc);
+ }
+
+ local_description_.reset(new TransportDescription(desc));
for (ChannelMap::iterator iter = channels_.begin();
iter != channels_.end(); ++iter) {
- ret &= ApplyLocalTransportDescription_w(iter->second.get());
+ ret &= ApplyLocalTransportDescription_w(iter->second.get(), error_desc);
}
if (!ret)
return false;
// If PRANSWER/ANSWER is set, we should decide transport protocol type.
if (action == CA_PRANSWER || action == CA_ANSWER) {
- ret &= NegotiateTransportDescription_w(action);
+ ret &= NegotiateTransportDescription_w(action, error_desc);
}
return ret;
}
bool Transport::SetRemoteTransportDescription_w(
- const TransportDescription& desc, ContentAction action) {
+ const TransportDescription& desc,
+ ContentAction action,
+ std::string* error_desc) {
bool ret = true;
talk_base::CritScope cs(&crit_);
- remote_description_.reset(new TransportDescription(desc));
+ if (!VerifyIceParams(desc)) {
+ return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
+ error_desc);
+ }
+
+ remote_description_.reset(new TransportDescription(desc));
for (ChannelMap::iterator iter = channels_.begin();
iter != channels_.end(); ++iter) {
- ret &= ApplyRemoteTransportDescription_w(iter->second.get());
+ ret &= ApplyRemoteTransportDescription_w(iter->second.get(), error_desc);
}
// If PRANSWER/ANSWER is set, we should decide transport protocol type.
if (action == CA_PRANSWER || action == CA_ANSWER) {
- ret = NegotiateTransportDescription_w(CA_OFFER);
+ ret = NegotiateTransportDescription_w(CA_OFFER, error_desc);
}
return ret;
}
-bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch) {
+bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch,
+ std::string* error_desc) {
+ // If existing protocol_type is HYBRID, we may have not chosen the final
+ // protocol type, so update the channel protocol type from the
+ // local description. Otherwise, skip updating the protocol type.
+ // We check for HYBRID to avoid accidental changes; in the case of a
+ // session renegotiation, the new offer will have the google-ice ICE option,
+ // so we need to make sure we don't switch back from ICE mode to HYBRID
+ // when this happens.
+ // There are some other ways we could have solved this, but this is the
+ // simplest. The ultimate solution will be to get rid of GICE altogether.
+ IceProtocolType protocol_type;
+ if (ch->GetIceProtocolType(&protocol_type) &&
+ protocol_type == ICEPROTO_HYBRID) {
+ ch->SetIceProtocolType(
+ TransportProtocolFromDescription(local_description()));
+ }
ch->SetIceCredentials(local_description_->ice_ufrag,
local_description_->ice_pwd);
return true;
}
-bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch) {
+bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
+ std::string* error_desc) {
ch->SetRemoteIceCredentials(remote_description_->ice_ufrag,
remote_description_->ice_pwd);
return true;
}
bool Transport::ApplyNegotiatedTransportDescription_w(
- TransportChannelImpl* channel) {
+ TransportChannelImpl* channel, std::string* error_desc) {
channel->SetIceProtocolType(protocol_);
channel->SetRemoteIceMode(remote_ice_mode_);
return true;
}
-bool Transport::NegotiateTransportDescription_w(ContentAction local_role) {
+bool Transport::NegotiateTransportDescription_w(ContentAction local_role,
+ std::string* error_desc) {
// TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into
// P2PTransport.
const TransportDescription* offer;
@@ -690,7 +831,12 @@ bool Transport::NegotiateTransportDescription_w(ContentAction local_role) {
// answer must be treated as error.
if ((offer_proto == ICEPROTO_GOOGLE || offer_proto == ICEPROTO_RFC5245) &&
(offer_proto != answer_proto)) {
- return false;
+ std::ostringstream desc;
+ desc << "Offer and answer protocol mismatch: "
+ << IceProtoToString(offer_proto)
+ << " vs "
+ << IceProtoToString(answer_proto);
+ return BadTransportDescription(desc.str(), error_desc);
}
protocol_ = answer_proto == ICEPROTO_HYBRID ? ICEPROTO_GOOGLE : answer_proto;
@@ -712,7 +858,7 @@ bool Transport::NegotiateTransportDescription_w(ContentAction local_role) {
for (ChannelMap::iterator iter = channels_.begin();
iter != channels_.end();
++iter) {
- if (!ApplyNegotiatedTransportDescription_w(iter->second.get()))
+ if (!ApplyNegotiatedTransportDescription_w(iter->second.get(), error_desc))
return false;
}
return true;
@@ -759,6 +905,12 @@ void Transport::OnMessage(talk_base::Message* msg) {
case MSG_ROLECONFLICT:
SignalRoleConflict();
break;
+ case MSG_COMPLETED:
+ SignalCompleted(this);
+ break;
+ case MSG_FAILED:
+ SignalFailed(this);
+ break;
}
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/transport.h b/chromium/third_party/libjingle/source/talk/p2p/base/transport.h
index f9e9d887457..7f460d1127b 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/transport.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/transport.h
@@ -187,6 +187,8 @@ struct TransportStats {
TransportChannelStatsList channel_stats;
};
+bool BadTransportDescription(const std::string& desc, std::string* err_desc);
+
class Transport : public talk_base::MessageHandler,
public sigslot::has_slots<> {
public:
@@ -234,6 +236,8 @@ class Transport : public talk_base::MessageHandler,
}
sigslot::signal1<Transport*> SignalReadableState;
sigslot::signal1<Transport*> SignalWritableState;
+ sigslot::signal1<Transport*> SignalCompleted;
+ sigslot::signal1<Transport*> SignalFailed;
// Returns whether the client has requested the channels to connect.
bool connect_requested() const { return connect_requested_; }
@@ -270,11 +274,13 @@ class Transport : public talk_base::MessageHandler,
// Set the local TransportDescription to be used by TransportChannels.
// This should be called before ConnectChannels().
bool SetLocalTransportDescription(const TransportDescription& description,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
// Set the remote TransportDescription to be used by TransportChannels.
bool SetRemoteTransportDescription(const TransportDescription& description,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
// Tells all current and future channels to start connecting. When the first
// channel begins connecting, the following signal is raised.
@@ -362,25 +368,27 @@ class Transport : public talk_base::MessageHandler,
// Pushes down the transport parameters from the local description, such
// as the ICE ufrag and pwd.
// Derived classes can override, but must call the base as well.
- virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl*
- channel);
+ virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel,
+ std::string* error_desc);
// Pushes down remote ice credentials from the remote description to the
// transport channel.
- virtual bool ApplyRemoteTransportDescription_w(TransportChannelImpl* ch);
+ virtual bool ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
+ std::string* error_desc);
// Negotiates the transport parameters based on the current local and remote
// transport description, such at the version of ICE to use, and whether DTLS
// should be activated.
// Derived classes can negotiate their specific parameters here, but must call
// the base as well.
- virtual bool NegotiateTransportDescription_w(ContentAction local_role);
+ virtual bool NegotiateTransportDescription_w(ContentAction local_role,
+ std::string* error_desc);
// Pushes down the transport parameters obtained via negotiation.
// Derived classes can set their specific parameters here, but must call the
// base as well.
virtual bool ApplyNegotiatedTransportDescription_w(
- TransportChannelImpl* channel);
+ TransportChannelImpl* channel, std::string* error_desc);
virtual bool GetSslRole_w(talk_base::SSLRole* ssl_role) const {
return false;
@@ -435,6 +443,8 @@ class Transport : public talk_base::MessageHandler,
void OnChannelCandidatesAllocationDone(TransportChannelImpl* channel);
// Called when there is ICE role change.
void OnRoleConflict(TransportChannelImpl* channel);
+ // Called when the channel removes a connection.
+ void OnChannelConnectionRemoved(TransportChannelImpl* channel);
// Dispatches messages to the appropriate handler (below).
void OnMessage(talk_base::Message* msg);
@@ -468,12 +478,16 @@ class Transport : public talk_base::MessageHandler,
void SetIceRole_w(IceRole role);
void SetRemoteIceMode_w(IceMode mode);
bool SetLocalTransportDescription_w(const TransportDescription& desc,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
bool SetRemoteTransportDescription_w(const TransportDescription& desc,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
bool GetStats_w(TransportStats* infos);
bool GetRemoteCertificate_w(talk_base::SSLCertificate** cert);
+ // Sends SignalCompleted if we are now in that state.
+ void MaybeCompleted_w();
talk_base::Thread* signaling_thread_;
talk_base::Thread* worker_thread_;
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/transport_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/transport_unittest.cc
index e3b7badfff7..b91b1a0d0aa 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/transport_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/transport_unittest.cc
@@ -60,8 +60,12 @@ class TransportTest : public testing::Test,
transport_(new FakeTransport(
thread_, thread_, "test content name", NULL)),
channel_(NULL),
- connecting_signalled_(false) {
+ connecting_signalled_(false),
+ completed_(false),
+ failed_(false) {
transport_->SignalConnecting.connect(this, &TransportTest::OnConnecting);
+ transport_->SignalCompleted.connect(this, &TransportTest::OnCompleted);
+ transport_->SignalFailed.connect(this, &TransportTest::OnFailed);
}
~TransportTest() {
transport_->DestroyAllChannels();
@@ -83,11 +87,19 @@ class TransportTest : public testing::Test,
void OnConnecting(Transport* transport) {
connecting_signalled_ = true;
}
+ void OnCompleted(Transport* transport) {
+ completed_ = true;
+ }
+ void OnFailed(Transport* transport) {
+ failed_ = true;
+ }
talk_base::Thread* thread_;
talk_base::scoped_ptr<FakeTransport> transport_;
FakeTransportChannel* channel_;
bool connecting_signalled_;
+ bool completed_;
+ bool failed_;
};
class FakeCandidateTranslator : public cricket::CandidateTranslator {
@@ -147,7 +159,8 @@ TEST_F(TransportTest, TestChannelIceParameters) {
cricket::TransportDescription local_desc(
cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc,
- cricket::CA_OFFER));
+ cricket::CA_OFFER,
+ NULL));
EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role());
EXPECT_TRUE(SetupChannel());
EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
@@ -158,7 +171,8 @@ TEST_F(TransportTest, TestChannelIceParameters) {
cricket::TransportDescription remote_desc(
cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc,
- cricket::CA_ANSWER));
+ cricket::CA_ANSWER,
+ NULL));
EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
EXPECT_EQ(99U, channel_->IceTiebreaker());
EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode());
@@ -170,6 +184,43 @@ TEST_F(TransportTest, TestChannelIceParameters) {
EXPECT_EQ(kIcePwd1, channel_->remote_ice_pwd());
}
+// This test verifies that the Completed and Failed states can be reached.
+TEST_F(TransportTest, TestChannelCompletedAndFailed) {
+ transport_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+ cricket::TransportDescription local_desc(
+ cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+ ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc,
+ cricket::CA_OFFER,
+ NULL));
+ EXPECT_TRUE(SetupChannel());
+
+ cricket::TransportDescription remote_desc(
+ cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
+ ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc,
+ cricket::CA_ANSWER,
+ NULL));
+
+ channel_->SetConnectionCount(2);
+ channel_->SignalCandidatesAllocationDone(channel_);
+ channel_->SetWritable(true);
+ EXPECT_TRUE_WAIT(transport_->all_channels_writable(), 100);
+ // ICE is not yet completed because there is still more than one connection.
+ EXPECT_FALSE(completed_);
+ EXPECT_FALSE(failed_);
+
+ // When the connection count drops to 1, SignalCompleted should be emitted,
+ // and completed() should be true.
+ channel_->SetConnectionCount(1);
+ EXPECT_TRUE_WAIT(completed_, 100);
+ completed_ = false;
+
+ // When the connection count drops to 0, SignalFailed should be emitted, and
+ // completed() should be false.
+ channel_->SetConnectionCount(0);
+ EXPECT_TRUE_WAIT(failed_, 100);
+ EXPECT_FALSE(completed_);
+}
+
// Tests channel role is reversed after receiving ice-lite from remote.
TEST_F(TransportTest, TestSetRemoteIceLiteInOffer) {
transport_->SetIceRole(cricket::ICEROLE_CONTROLLED);
@@ -178,11 +229,13 @@ TEST_F(TransportTest, TestSetRemoteIceLiteInOffer) {
kIceUfrag1, kIcePwd1, cricket::ICEMODE_LITE,
cricket::CONNECTIONROLE_ACTPASS, NULL, cricket::Candidates());
ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc,
- cricket::CA_OFFER));
+ cricket::CA_OFFER,
+ NULL));
cricket::TransportDescription local_desc(
cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc,
- cricket::CA_ANSWER));
+ cricket::CA_ANSWER,
+ NULL));
EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role());
EXPECT_TRUE(SetupChannel());
EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
@@ -195,7 +248,8 @@ TEST_F(TransportTest, TestSetRemoteIceLiteInAnswer) {
cricket::TransportDescription local_desc(
cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1);
ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc,
- cricket::CA_OFFER));
+ cricket::CA_OFFER,
+ NULL));
EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role());
EXPECT_TRUE(SetupChannel());
EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
@@ -206,7 +260,8 @@ TEST_F(TransportTest, TestSetRemoteIceLiteInAnswer) {
kIceUfrag1, kIcePwd1, cricket::ICEMODE_LITE,
cricket::CONNECTIONROLE_NONE, NULL, cricket::Candidates());
ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc,
- cricket::CA_ANSWER));
+ cricket::CA_ANSWER,
+ NULL));
EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole());
// After receiving remote description with ICEMODE_LITE, channel should
// have mode set to ICEMODE_LITE.
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/transportchannel.h b/chromium/third_party/libjingle/source/talk/p2p/base/transportchannel.h
index 47ba990f35f..c548c1c8c1e 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/transportchannel.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/transportchannel.h
@@ -83,7 +83,7 @@ class TransportChannel : public sigslot::has_slots<> {
// Attempts to send the given packet. The return value is < 0 on failure.
// TODO: Remove the default argument once channel code is updated.
virtual int SendPacket(const char* data, size_t len,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
int flags = 0) = 0;
// Sets a socket option on this channel. Note that not all options are
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelimpl.h b/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelimpl.h
index d8432b73233..25c3121886f 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelimpl.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelimpl.h
@@ -53,7 +53,9 @@ class TransportChannelImpl : public TransportChannel {
virtual IceRole GetIceRole() const = 0;
virtual void SetIceRole(IceRole role) = 0;
virtual void SetIceTiebreaker(uint64 tiebreaker) = 0;
+ virtual size_t GetConnectionCount() const = 0;
// To toggle G-ICE/ICE.
+ virtual bool GetIceProtocolType(IceProtocolType* type) const = 0;
virtual void SetIceProtocolType(IceProtocolType type) = 0;
// SetIceCredentials only need to be implemented by the ICE
// transport channels. Non-ICE transport channels can just ignore.
@@ -113,6 +115,10 @@ class TransportChannelImpl : public TransportChannel {
// agents.
sigslot::signal1<TransportChannelImpl*> SignalRoleConflict;
+ // Emitted whenever the number of connections available to the transport
+ // channel decreases.
+ sigslot::signal1<TransportChannelImpl*> SignalConnectionRemoved;
+
private:
DISALLOW_EVIL_CONSTRUCTORS(TransportChannelImpl);
};
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc b/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc
index 0d8cace2a86..fdcc509d34c 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc
@@ -58,7 +58,6 @@ void TransportChannelProxy::SetImplementation(TransportChannelImpl* impl) {
ASSERT(talk_base::Thread::Current() == worker_thread_);
if (impl == impl_) {
- ASSERT(false);
// Ignore if the |impl| has already been set.
LOG(LS_WARNING) << "Ignored TransportChannelProxy::SetImplementation call "
<< "with a same impl as the existing one.";
@@ -102,14 +101,14 @@ void TransportChannelProxy::SetImplementation(TransportChannelImpl* impl) {
}
int TransportChannelProxy::SendPacket(const char* data, size_t len,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
int flags) {
ASSERT(talk_base::Thread::Current() == worker_thread_);
// Fail if we don't have an impl yet.
if (!impl_) {
return -1;
}
- return impl_->SendPacket(data, len, dscp, flags);
+ return impl_->SendPacket(data, len, options, flags);
}
int TransportChannelProxy::SetOption(talk_base::Socket::Option opt, int value) {
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h b/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h
index 196d0f6cfab..cb38c7bc495 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h
@@ -64,7 +64,7 @@ class TransportChannelProxy : public TransportChannel,
// Implementation of the TransportChannel interface. These simply forward to
// the implementation.
virtual int SendPacket(const char* data, size_t len,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
int flags);
virtual int SetOption(talk_base::Socket::Option opt, int value);
virtual int GetError();
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/turnport.cc b/chromium/third_party/libjingle/source/talk/p2p/base/turnport.cc
index 01d7f9c8998..195e9707bd6 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/turnport.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/turnport.cc
@@ -43,7 +43,6 @@ namespace cricket {
// TODO(juberti): Move to stun.h when relay messages have been renamed.
static const int TURN_ALLOCATE_REQUEST = STUN_ALLOCATE_REQUEST;
-static const int TURN_ALLOCATE_ERROR_RESPONSE = STUN_ALLOCATE_ERROR_RESPONSE;
// TODO(juberti): Extract to turnmessage.h
static const int TURN_DEFAULT_PORT = 3478;
@@ -153,7 +152,7 @@ class TurnEntry : public sigslot::has_slots<> {
// Sends a packet to the given destination address.
// This will wrap the packet in STUN if necessary.
int Send(const void* data, size_t size, bool payload,
- talk_base::DiffServCodePoint dscp);
+ const talk_base::PacketOptions& options);
void OnCreatePermissionSuccess();
void OnCreatePermissionError(StunMessage* response, int code);
@@ -172,6 +171,27 @@ class TurnEntry : public sigslot::has_slots<> {
TurnPort::TurnPort(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
talk_base::Network* network,
+ talk_base::AsyncPacketSocket* socket,
+ const std::string& username,
+ const std::string& password,
+ const ProtocolAddress& server_address,
+ const RelayCredentials& credentials)
+ : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(),
+ username, password),
+ server_address_(server_address),
+ credentials_(credentials),
+ socket_(socket),
+ resolver_(NULL),
+ error_(0),
+ request_manager_(thread),
+ next_channel_number_(TURN_CHANNEL_NUMBER_START),
+ connected_(false) {
+ request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
+}
+
+TurnPort::TurnPort(talk_base::Thread* thread,
+ talk_base::PacketSocketFactory* factory,
+ talk_base::Network* network,
const talk_base::IPAddress& ip,
int min_port, int max_port,
const std::string& username,
@@ -182,6 +202,7 @@ TurnPort::TurnPort(talk_base::Thread* thread,
username, password),
server_address_(server_address),
credentials_(credentials),
+ socket_(NULL),
resolver_(NULL),
error_(0),
request_manager_(thread),
@@ -195,6 +216,12 @@ TurnPort::~TurnPort() {
while (!entries_.empty()) {
DestroyEntry(entries_.front()->address());
}
+ if (resolver_) {
+ resolver_->Destroy(false);
+ }
+ if (!SharedSocket()) {
+ delete socket_;
+ }
}
void TurnPort::PrepareAddress() {
@@ -225,19 +252,19 @@ void TurnPort::PrepareAddress() {
LOG_J(LS_INFO, this) << "Trying to connect to TURN server via "
<< ProtoToString(server_address_.proto) << " @ "
<< server_address_.address.ToSensitiveString();
- if (server_address_.proto == PROTO_UDP) {
- socket_.reset(socket_factory()->CreateUdpSocket(
- talk_base::SocketAddress(ip(), 0), min_port(), max_port()));
+ if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
+ socket_ = socket_factory()->CreateUdpSocket(
+ talk_base::SocketAddress(ip(), 0), min_port(), max_port());
} else if (server_address_.proto == PROTO_TCP) {
+ ASSERT(!SharedSocket());
int opts = talk_base::PacketSocketFactory::OPT_STUN;
// If secure bit is enabled in server address, use TLS over TCP.
if (server_address_.secure) {
opts |= talk_base::PacketSocketFactory::OPT_TLS;
}
-
- socket_.reset(socket_factory()->CreateClientTcpSocket(
+ socket_ = socket_factory()->CreateClientTcpSocket(
talk_base::SocketAddress(ip(), 0), server_address_.address,
- proxy(), user_agent(), opts));
+ proxy(), user_agent(), opts);
}
if (!socket_) {
@@ -251,7 +278,11 @@ void TurnPort::PrepareAddress() {
socket_->SetOption(iter->first, iter->second);
}
- socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
+ if (!SharedSocket()) {
+ // If socket is shared, AllocationSequence will receive the packet.
+ socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
+ }
+
socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
if (server_address_.proto == PROTO_TCP) {
@@ -266,6 +297,18 @@ void TurnPort::PrepareAddress() {
}
void TurnPort::OnSocketConnect(talk_base::AsyncPacketSocket* socket) {
+ ASSERT(server_address_.proto == PROTO_TCP);
+ // Do not use this port if the socket bound to a different address than
+ // the one we asked for. This is seen in Chrome, where TCP sockets cannot be
+ // given a binding address, and the platform is expected to pick the
+ // correct local address.
+ if (socket->GetLocalAddress().ipaddr() != ip()) {
+ LOG(LS_WARNING) << "Socket is bound to a different address then the "
+ << "local port. Discarding TURN port.";
+ OnAllocateError();
+ return;
+ }
+
LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress()
<< " using tcp.";
SendRequest(new TurnAllocateRequest(this), 0);
@@ -292,23 +335,21 @@ Connection* TurnPort::CreateConnection(const Candidate& address,
// Create an entry, if needed, so we can get our permissions set up correctly.
CreateEntry(address.address());
- // TODO(juberti): The '0' index will need to change if we start gathering STUN
- // candidates on this port.
- ProxyConnection* conn = new ProxyConnection(this, 0, address);
- conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
- AddConnection(conn);
- return conn;
+ // A TURN port will have two candiates, STUN and TURN. STUN may not
+ // present in all cases. If present stun candidate will be added first
+ // and TURN candidate later.
+ for (size_t index = 0; index < Candidates().size(); ++index) {
+ if (Candidates()[index].type() == RELAY_PORT_TYPE) {
+ ProxyConnection* conn = new ProxyConnection(this, index, address);
+ conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
+ AddConnection(conn);
+ return conn;
+ }
+ }
+ return NULL;
}
int TurnPort::SetOption(talk_base::Socket::Option opt, int value) {
- // DSCP option is not passed to the socket.
- // TODO(mallinath) - After we have the support on socket,
- // remove this specialization.
- if (opt == talk_base::Socket::OPT_DSCP) {
- SetDefaultDscpValue(static_cast<talk_base::DiffServCodePoint>(value));
- return 0;
- }
-
if (!socket_) {
// If socket is not created yet, these options will be applied during socket
// creation.
@@ -319,8 +360,14 @@ int TurnPort::SetOption(talk_base::Socket::Option opt, int value) {
}
int TurnPort::GetOption(talk_base::Socket::Option opt, int* value) {
- if (!socket_)
- return -1;
+ if (!socket_) {
+ SocketOptionsMap::const_iterator it = socket_options_.find(opt);
+ if (it == socket_options_.end()) {
+ return -1;
+ }
+ *value = it->second;
+ return 0;
+ }
return socket_->GetOption(opt, value);
}
@@ -331,7 +378,7 @@ int TurnPort::GetError() {
int TurnPort::SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
bool payload) {
// Try to find an entry for this specific address; we should have one.
TurnEntry* entry = FindEntry(addr);
@@ -346,7 +393,7 @@ int TurnPort::SendTo(const void* data, size_t size,
}
// Send the actual contents to the server using the usual mechanism.
- int sent = entry->Send(data, size, payload, dscp);
+ int sent = entry->Send(data, size, payload, options);
if (sent <= 0) {
return SOCKET_ERROR;
}
@@ -360,7 +407,7 @@ void TurnPort::OnReadPacket(
talk_base::AsyncPacketSocket* socket, const char* data, size_t size,
const talk_base::SocketAddress& remote_addr,
const talk_base::PacketTime& packet_time) {
- ASSERT(socket == socket_.get());
+ ASSERT(socket == socket_);
ASSERT(remote_addr == server_address_.address);
// The message must be at least the size of a channel header.
@@ -407,35 +454,51 @@ void TurnPort::ResolveTurnAddress(const talk_base::SocketAddress& address) {
void TurnPort::OnResolveResult(talk_base::AsyncResolverInterface* resolver) {
ASSERT(resolver == resolver_);
+ // Copy the original server address in |resolved_address|. For TLS based
+ // sockets we need hostname along with resolved address.
+ talk_base::SocketAddress resolved_address = server_address_.address;
if (resolver_->GetError() != 0 ||
- !resolver_->GetResolvedAddress(ip().family(), &server_address_.address)) {
+ !resolver_->GetResolvedAddress(ip().family(), &resolved_address)) {
LOG_J(LS_WARNING, this) << "TURN host lookup received error "
<< resolver_->GetError();
OnAllocateError();
return;
}
-
+ // Signal needs both resolved and unresolved address. After signal is sent
+ // we can copy resolved address back into |server_address_|.
+ SignalResolvedServerAddress(this, server_address_.address,
+ resolved_address);
+ server_address_.address = resolved_address;
PrepareAddress();
}
void TurnPort::OnSendStunPacket(const void* data, size_t size,
StunRequest* request) {
- if (Send(data, size, DefaultDscpValue()) < 0) {
+ talk_base::PacketOptions options(DefaultDscpValue());
+ if (Send(data, size, options) < 0) {
LOG_J(LS_ERROR, this) << "Failed to send TURN message, err="
<< socket_->GetError();
}
}
void TurnPort::OnStunAddress(const talk_base::SocketAddress& address) {
- // For relay, mapped address is rel-addr.
- set_related_address(address);
+ // STUN Port will discover STUN candidate, as it's supplied with first TURN
+ // server address.
+ // Why not using this address? - P2PTransportChannel will start creating
+ // connections after first candidate, which means it could start creating the
+ // connections before TURN candidate added. For that to handle, we need to
+ // supply STUN candidate from this port to UDPPort, and TurnPort should have
+ // handle to UDPPort to pass back the address.
}
-void TurnPort::OnAllocateSuccess(const talk_base::SocketAddress& address) {
+void TurnPort::OnAllocateSuccess(const talk_base::SocketAddress& address,
+ const talk_base::SocketAddress& stun_address) {
connected_ = true;
- AddAddress(address,
- socket_->GetLocalAddress(),
- "udp",
+ // For relayed candidate, Base is the candidate itself.
+ AddAddress(address, // Candidate address.
+ address, // Base address.
+ stun_address, // Related address.
+ UDP_PROTOCOL_NAME,
RELAY_PORT_TYPE,
GetRelayPreference(server_address_.proto, server_address_.secure),
true);
@@ -577,8 +640,8 @@ void TurnPort::AddRequestAuthInfo(StunMessage* msg) {
}
int TurnPort::Send(const void* data, size_t len,
- talk_base::DiffServCodePoint dscp) {
- return socket_->SendTo(data, len, server_address_.address, dscp);
+ const talk_base::PacketOptions& options) {
+ return socket_->SendTo(data, len, server_address_.address, options);
}
void TurnPort::UpdateHash() {
@@ -682,8 +745,7 @@ void TurnAllocateRequest::OnResponse(StunMessage* response) {
<< "attribute in allocate success response";
return;
}
-
- // TODO(mallinath) - Use mapped address for STUN candidate.
+ // Using XOR-Mapped-Address for stun.
port_->OnStunAddress(mapped_attr->GetAddress());
const StunAddressAttribute* relayed_attr =
@@ -702,7 +764,8 @@ void TurnAllocateRequest::OnResponse(StunMessage* response) {
return;
}
// Notify the port the allocate succeeded, and schedule a refresh request.
- port_->OnAllocateSuccess(relayed_attr->GetAddress());
+ port_->OnAllocateSuccess(relayed_attr->GetAddress(),
+ mapped_attr->GetAddress());
port_->ScheduleRefresh(lifetime_attr->value());
}
@@ -911,7 +974,7 @@ void TurnEntry::SendChannelBindRequest(int delay) {
}
int TurnEntry::Send(const void* data, size_t size, bool payload,
- talk_base::DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
talk_base::ByteBuffer buf;
if (state_ != STATE_BOUND) {
// If we haven't bound the channel yet, we have to use a Send Indication.
@@ -936,7 +999,7 @@ int TurnEntry::Send(const void* data, size_t size, bool payload,
buf.WriteUInt16(static_cast<uint16>(size));
buf.WriteBytes(reinterpret_cast<const char*>(data), size);
}
- return port_->Send(buf.Data(), buf.Length(), dscp);
+ return port_->Send(buf.Data(), buf.Length(), options);
}
void TurnEntry::OnCreatePermissionSuccess() {
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/turnport.h b/chromium/third_party/libjingle/source/talk/p2p/base/turnport.h
index e380a8912f7..2f5e8c4ab1b 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/turnport.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/turnport.h
@@ -52,6 +52,18 @@ class TurnPort : public Port {
static TurnPort* Create(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
talk_base::Network* network,
+ talk_base::AsyncPacketSocket* socket,
+ const std::string& username, // ice username.
+ const std::string& password, // ice password.
+ const ProtocolAddress& server_address,
+ const RelayCredentials& credentials) {
+ return new TurnPort(thread, factory, network, socket,
+ username, password, server_address, credentials);
+ }
+
+ static TurnPort* Create(talk_base::Thread* thread,
+ talk_base::PacketSocketFactory* factory,
+ talk_base::Network* network,
const talk_base::IPAddress& ip,
int min_port, int max_port,
const std::string& username, // ice username.
@@ -74,15 +86,24 @@ class TurnPort : public Port {
const Candidate& c, PortInterface::CandidateOrigin origin);
virtual int SendTo(const void* data, size_t size,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp,
+ const talk_base::PacketOptions& options,
bool payload);
virtual int SetOption(talk_base::Socket::Option opt, int value);
virtual int GetOption(talk_base::Socket::Option opt, int* value);
virtual int GetError();
- virtual void OnReadPacket(
+
+ virtual bool HandleIncomingPacket(
talk_base::AsyncPacketSocket* socket, const char* data, size_t size,
const talk_base::SocketAddress& remote_addr,
- const talk_base::PacketTime& packet_time);
+ const talk_base::PacketTime& packet_time) {
+ OnReadPacket(socket, data, size, remote_addr, packet_time);
+ return true;
+ }
+ virtual void OnReadPacket(talk_base::AsyncPacketSocket* socket,
+ const char* data, size_t size,
+ const talk_base::SocketAddress& remote_addr,
+ const talk_base::PacketTime& packet_time);
+
virtual void OnReadyToSend(talk_base::AsyncPacketSocket* socket);
void OnSocketConnect(talk_base::AsyncPacketSocket* socket);
@@ -92,6 +113,13 @@ class TurnPort : public Port {
const std::string& hash() const { return hash_; }
const std::string& nonce() const { return nonce_; }
+ // Signal with resolved server address.
+ // Parameters are port, server address and resolved server address.
+ // This signal will be sent only if server address is resolved successfully.
+ sigslot::signal3<TurnPort*,
+ const talk_base::SocketAddress&,
+ const talk_base::SocketAddress&> SignalResolvedServerAddress;
+
// This signal is only for testing purpose.
sigslot::signal3<TurnPort*, const talk_base::SocketAddress&, int>
SignalCreatePermissionResult;
@@ -100,6 +128,15 @@ class TurnPort : public Port {
TurnPort(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
talk_base::Network* network,
+ talk_base::AsyncPacketSocket* socket,
+ const std::string& username,
+ const std::string& password,
+ const ProtocolAddress& server_address,
+ const RelayCredentials& credentials);
+
+ TurnPort(talk_base::Thread* thread,
+ talk_base::PacketSocketFactory* factory,
+ talk_base::Network* network,
const talk_base::IPAddress& ip,
int min_port, int max_port,
const std::string& username,
@@ -131,7 +168,8 @@ class TurnPort : public Port {
// Stun address from allocate success response.
// Currently used only for testing.
void OnStunAddress(const talk_base::SocketAddress& address);
- void OnAllocateSuccess(const talk_base::SocketAddress& address);
+ void OnAllocateSuccess(const talk_base::SocketAddress& address,
+ const talk_base::SocketAddress& stun_address);
void OnAllocateError();
void OnAllocateRequestTimeout();
@@ -145,7 +183,8 @@ class TurnPort : public Port {
bool ScheduleRefresh(int lifetime);
void SendRequest(StunRequest* request, int delay);
- int Send(const void* data, size_t size, talk_base::DiffServCodePoint dscp);
+ int Send(const void* data, size_t size,
+ const talk_base::PacketOptions& options);
void UpdateHash();
bool UpdateNonce(StunMessage* response);
@@ -159,7 +198,7 @@ class TurnPort : public Port {
ProtocolAddress server_address_;
RelayCredentials credentials_;
- talk_base::scoped_ptr<talk_base::AsyncPacketSocket> socket_;
+ talk_base::AsyncPacketSocket* socket_;
SocketOptionsMap socket_options_;
talk_base::AsyncResolverInterface* resolver_;
int error_;
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/turnport_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/base/turnport_unittest.cc
index d559894ac56..12a19aa4dba 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/turnport_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/turnport_unittest.cc
@@ -24,6 +24,9 @@
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#if defined(POSIX)
+#include <dirent.h>
+#endif
#include "talk/base/asynctcpsocket.h"
#include "talk/base/buffer.h"
@@ -71,7 +74,7 @@ static const char kIcePwd1[] = "TESTICEPWD00000000000001";
static const char kIcePwd2[] = "TESTICEPWD00000000000002";
static const char kTurnUsername[] = "test";
static const char kTurnPassword[] = "test";
-static const int kTimeout = 1000;
+static const unsigned int kTimeout = 1000;
static const cricket::ProtocolAddress kTurnUdpProtoAddr(
kTurnUdpIntAddr, cricket::PROTO_UDP);
@@ -80,8 +83,26 @@ static const cricket::ProtocolAddress kTurnTcpProtoAddr(
static const cricket::ProtocolAddress kTurnUdpIPv6ProtoAddr(
kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
+static const unsigned int MSG_TESTFINISH = 0;
+
+#if defined(LINUX)
+static int GetFDCount() {
+ struct dirent *dp;
+ int fd_count = 0;
+ DIR *dir = opendir("/proc/self/fd/");
+ while ((dp = readdir(dir)) != NULL) {
+ if (dp->d_name[0] == '.')
+ continue;
+ ++fd_count;
+ }
+ closedir(dir);
+ return fd_count;
+}
+#endif
+
class TurnPortTest : public testing::Test,
- public sigslot::has_slots<> {
+ public sigslot::has_slots<>,
+ public talk_base::MessageHandler {
public:
TurnPortTest()
: main_(talk_base::Thread::Current()),
@@ -95,10 +116,17 @@ class TurnPortTest : public testing::Test,
turn_error_(false),
turn_unknown_address_(false),
turn_create_permission_success_(false),
- udp_ready_(false) {
+ udp_ready_(false),
+ test_finish_(false) {
network_.AddIP(talk_base::IPAddress(INADDR_ANY));
}
+ virtual void OnMessage(talk_base::Message* msg) {
+ ASSERT(msg->message_id == MSG_TESTFINISH);
+ if (msg->message_id == MSG_TESTFINISH)
+ test_finish_ = true;
+ }
+
void OnTurnPortComplete(Port* port) {
turn_ready_ = true;
}
@@ -129,7 +157,13 @@ class TurnPortTest : public testing::Test,
const talk_base::PacketTime& packet_time) {
udp_packets_.push_back(talk_base::Buffer(data, size));
}
-
+ void OnSocketReadPacket(talk_base::AsyncPacketSocket* socket,
+ const char* data, size_t size,
+ const talk_base::SocketAddress& remote_addr,
+ const talk_base::PacketTime& packet_time) {
+ turn_port_->HandleIncomingPacket(socket, data, size, remote_addr,
+ packet_time);
+ }
talk_base::AsyncSocket* CreateServerSocket(const SocketAddress addr) {
talk_base::AsyncSocket* socket = ss_->CreateAsyncSocket(SOCK_STREAM);
EXPECT_GE(socket->Bind(addr), 0);
@@ -151,6 +185,39 @@ class TurnPortTest : public testing::Test,
local_address.ipaddr(), 0, 0,
kIceUfrag1, kIcePwd1,
server_address, credentials));
+ // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be
+ // in Hybrid mode. Protocol type is necessary to send correct type STUN ping
+ // messages.
+ // This TURN port will be the controlling.
+ turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+ turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+ ConnectSignals();
+ }
+
+ void CreateSharedTurnPort(const std::string& username,
+ const std::string& password,
+ const cricket::ProtocolAddress& server_address) {
+ ASSERT(server_address.proto == cricket::PROTO_UDP);
+
+ socket_.reset(socket_factory_.CreateUdpSocket(
+ talk_base::SocketAddress(kLocalAddr1.ipaddr(), 0), 0, 0));
+ ASSERT_TRUE(socket_ != NULL);
+ socket_->SignalReadPacket.connect(this, &TurnPortTest::OnSocketReadPacket);
+
+ cricket::RelayCredentials credentials(username, password);
+ turn_port_.reset(cricket::TurnPort::Create(
+ main_, &socket_factory_, &network_, socket_.get(),
+ kIceUfrag1, kIcePwd1, server_address, credentials));
+ // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be
+ // in Hybrid mode. Protocol type is necessary to send correct type STUN ping
+ // messages.
+ // This TURN port will be the controlling.
+ turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+ turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+ ConnectSignals();
+ }
+
+ void ConnectSignals() {
turn_port_->SignalPortComplete.connect(this,
&TurnPortTest::OnTurnPortComplete);
turn_port_->SignalPortError.connect(this,
@@ -164,6 +231,10 @@ class TurnPortTest : public testing::Test,
udp_port_.reset(UDPPort::Create(main_, &socket_factory_, &network_,
kLocalAddr2.ipaddr(), 0, 0,
kIceUfrag2, kIcePwd2));
+ // Set protocol type to RFC5245, as turn port is also in same mode.
+ // UDP port will be controlled.
+ udp_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+ udp_port_->SetIceRole(cricket::ICEROLE_CONTROLLED);
udp_port_->SignalPortComplete.connect(
this, &TurnPortTest::OnUdpPortComplete);
}
@@ -234,8 +305,8 @@ class TurnPortTest : public testing::Test,
for (size_t j = 0; j < i + 1; ++j) {
buf[j] = 0xFF - j;
}
- conn1->Send(buf, i + 1, talk_base::DSCP_NO_CHANGE);
- conn2->Send(buf, i + 1, talk_base::DSCP_NO_CHANGE);
+ conn1->Send(buf, i + 1, options);
+ conn2->Send(buf, i + 1, options);
main_->ProcessMessages(0);
}
@@ -256,6 +327,7 @@ class TurnPortTest : public testing::Test,
talk_base::SocketServerScope ss_scope_;
talk_base::Network network_;
talk_base::BasicPacketSocketFactory socket_factory_;
+ talk_base::scoped_ptr<talk_base::AsyncPacketSocket> socket_;
cricket::TestTurnServer turn_server_;
talk_base::scoped_ptr<TurnPort> turn_port_;
talk_base::scoped_ptr<UDPPort> udp_port_;
@@ -264,8 +336,10 @@ class TurnPortTest : public testing::Test,
bool turn_unknown_address_;
bool turn_create_permission_success_;
bool udp_ready_;
+ bool test_finish_;
std::vector<talk_base::Buffer> turn_packets_;
std::vector<talk_base::Buffer> udp_packets_;
+ talk_base::PacketOptions options;
};
// Do a normal TURN allocation.
@@ -309,6 +383,12 @@ TEST_F(TurnPortTest, TestTurnConnection) {
TestTurnConnection();
}
+// Similar to above, except that this test will use the shared socket.
+TEST_F(TurnPortTest, TestTurnConnectionUsingSharedSocket) {
+ CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+ TestTurnConnection();
+}
+
// Test that we can establish a TCP connection with TURN server.
TEST_F(TurnPortTest, TestTurnTcpConnection) {
turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
@@ -378,3 +458,24 @@ TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv6ExtenalIPv4) {
EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
}
+// This test verifies any FD's are not leaked after TurnPort is destroyed.
+// https://code.google.com/p/webrtc/issues/detail?id=2651
+#if defined(LINUX)
+TEST_F(TurnPortTest, TestResolverShutdown) {
+ turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
+ int last_fd_count = GetFDCount();
+ // Need to supply unresolved address to kick off resolver.
+ CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword,
+ cricket::ProtocolAddress(talk_base::SocketAddress(
+ "stun.l.google.com", 3478), cricket::PROTO_UDP));
+ turn_port_->PrepareAddress();
+ ASSERT_TRUE_WAIT(turn_error_, kTimeout);
+ EXPECT_TRUE(turn_port_->Candidates().empty());
+ turn_port_.reset();
+ talk_base::Thread::Current()->Post(this, MSG_TESTFINISH);
+ // Waiting for above message to be processed.
+ ASSERT_TRUE_WAIT(test_finish_, kTimeout);
+ EXPECT_EQ(last_fd_count, GetFDCount());
+}
+#endif
+
diff --git a/chromium/third_party/libjingle/source/talk/p2p/base/turnserver.cc b/chromium/third_party/libjingle/source/talk/p2p/base/turnserver.cc
index 0bd903abe22..4d7f39e8f1c 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/base/turnserver.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/base/turnserver.cc
@@ -57,8 +57,6 @@ static const size_t kNonceSize = 40;
static const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
// TODO(mallinath) - Move these to a common place.
-static const size_t kMaxPacketSize = 64 * 1024;
-
inline bool IsTurnChannelData(uint16 msg_type) {
// The first two bits of a channel data message are 0b01.
return ((msg_type & 0xC000) == 0x4000);
@@ -566,8 +564,8 @@ void TurnServer::SendStun(Connection* conn, StunMessage* msg) {
void TurnServer::Send(Connection* conn,
const talk_base::ByteBuffer& buf) {
- conn->socket()->SendTo(buf.Data(), buf.Length(), conn->src(),
- talk_base::DSCP_NO_CHANGE);
+ talk_base::PacketOptions options;
+ conn->socket()->SendTo(buf.Data(), buf.Length(), conn->src(), options);
}
void TurnServer::OnAllocationDestroyed(Allocation* allocation) {
@@ -940,7 +938,8 @@ void TurnServer::Allocation::SendErrorResponse(const TurnMessage* req, int code,
void TurnServer::Allocation::SendExternal(const void* data, size_t size,
const talk_base::SocketAddress& peer) {
- external_socket_->SendTo(data, size, peer, talk_base::DSCP_NO_CHANGE);
+ talk_base::PacketOptions options;
+ external_socket_->SendTo(data, size, peer, options);
}
void TurnServer::Allocation::OnMessage(talk_base::Message* msg) {
diff --git a/chromium/third_party/libjingle/source/talk/p2p/client/basicportallocator.cc b/chromium/third_party/libjingle/source/talk/p2p/client/basicportallocator.cc
index dbc2e3342ee..762726fbb24 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/client/basicportallocator.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/client/basicportallocator.cc
@@ -56,7 +56,6 @@ const uint32 MSG_SEQUENCEOBJECTS_CREATED = 6;
const uint32 MSG_CONFIG_STOP = 7;
const uint32 ALLOCATE_DELAY = 250;
-const uint32 ALLOCATION_STEP_DELAY = 1 * 1000;
const int PHASE_UDP = 0;
const int PHASE_RELAY = 1;
@@ -65,10 +64,6 @@ const int PHASE_SSLTCP = 3;
const int kNumPhases = 4;
-// Both these values are in bytes.
-const int kLargeSocketSendBufferSize = 128 * 1024;
-const int kNormalSocketSendBufferSize = 64 * 1024;
-
const int SHAKE_MIN_DELAY = 45 * 1000; // 45 seconds
const int SHAKE_MAX_DELAY = 90 * 1000; // 90 seconds
@@ -107,6 +102,7 @@ class AllocationSequence : public talk_base::MessageHandler,
uint32 flags);
~AllocationSequence();
bool Init();
+ void Clear();
State state() const { return state_; }
@@ -153,6 +149,9 @@ class AllocationSequence : public talk_base::MessageHandler,
const talk_base::PacketTime& packet_time);
void OnPortDestroyed(PortInterface* port);
+ void OnResolvedTurnServerAddress(
+ TurnPort* port, const talk_base::SocketAddress& server_address,
+ const talk_base::SocketAddress& resolved_server_address);
BasicPortAllocatorSession* session_;
talk_base::Network* network_;
@@ -162,8 +161,10 @@ class AllocationSequence : public talk_base::MessageHandler,
uint32 flags_;
ProtocolList protocols_;
talk_base::scoped_ptr<talk_base::AsyncPacketSocket> udp_socket_;
- // Keeping a list of all UDP based ports.
- std::deque<Port*> ports;
+ // There will be only one udp port per AllocationSequence.
+ UDPPort* udp_port_;
+ // Keeping a map for turn ports keyed with server addresses.
+ std::map<talk_base::SocketAddress, Port*> turn_ports_;
int phase_;
};
@@ -206,13 +207,15 @@ BasicPortAllocator::BasicPortAllocator(
stun_address_(stun_address) {
RelayServerConfig config(RELAY_GTURN);
- if (!relay_address_udp.IsAny())
+ if (!relay_address_udp.IsNil())
config.ports.push_back(ProtocolAddress(relay_address_udp, PROTO_UDP));
- if (!relay_address_tcp.IsAny())
+ if (!relay_address_tcp.IsNil())
config.ports.push_back(ProtocolAddress(relay_address_tcp, PROTO_TCP));
- if (!relay_address_ssl.IsAny())
+ if (!relay_address_ssl.IsNil())
config.ports.push_back(ProtocolAddress(relay_address_ssl, PROTO_SSLTCP));
- AddRelay(config);
+
+ if (!config.ports.empty())
+ AddRelay(config);
Construct();
}
@@ -242,7 +245,6 @@ BasicPortAllocatorSession::BasicPortAllocatorSession(
ice_ufrag, ice_pwd, allocator->flags()),
allocator_(allocator), network_thread_(NULL),
socket_factory_(allocator->socket_factory()),
- configuration_done_(false),
allocation_started_(false),
network_manager_started_(false),
running_(false),
@@ -257,6 +259,12 @@ BasicPortAllocatorSession::~BasicPortAllocatorSession() {
if (network_thread_ != NULL)
network_thread_->Clear(this);
+ for (uint32 i = 0; i < sequences_.size(); ++i) {
+ // AllocationSequence should clear it's map entry for turn ports before
+ // ports are destroyed.
+ sequences_[i]->Clear();
+ }
+
std::vector<PortData>::iterator it;
for (it = ports_.begin(); it != ports_.end(); it++)
delete it->port();
@@ -490,16 +498,6 @@ void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
port->set_send_retransmit_count_attribute((allocator_->flags() &
PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE) != 0);
- if (content_name().compare(CN_VIDEO) == 0 &&
- component_ == cricket::ICE_CANDIDATE_COMPONENT_RTP) {
- // For video RTP alone, we set send-buffer sizes. This used to be set in the
- // engines/channels.
- int sendBufSize = (flags() & PORTALLOCATOR_USE_LARGE_SOCKET_SEND_BUFFERS)
- ? kLargeSocketSendBufferSize
- : kNormalSocketSendBufferSize;
- port->SetOption(talk_base::Socket::OPT_SNDBUF, sendBufSize);
- }
-
PortData data(port, seq);
ports_.push_back(data);
@@ -515,8 +513,6 @@ void BasicPortAllocatorSession::AddAllocatedPort(Port* port,
if (prepare_address)
port->PrepareAddress();
- if (running_)
- port->Start();
}
void BasicPortAllocatorSession::OnAllocationSequenceObjectsCreated() {
@@ -711,6 +707,7 @@ AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
state_(kInit),
flags_(flags),
udp_socket_(),
+ udp_port_(NULL),
phase_(0) {
}
@@ -737,6 +734,11 @@ bool AllocationSequence::Init() {
return true;
}
+void AllocationSequence::Clear() {
+ udp_port_ = NULL;
+ turn_ports_.clear();
+}
+
AllocationSequence::~AllocationSequence() {
session_->network_thread()->Clear(this);
}
@@ -873,18 +875,27 @@ void AllocationSequence::CreateUDPPorts() {
}
if (port) {
- ports.push_back(port);
// If shared socket is enabled, STUN candidate will be allocated by the
// UDPPort.
- if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
- !IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
- ASSERT(config_ && !config_->stun_address.IsNil());
- if (!(config_ && !config_->stun_address.IsNil())) {
- LOG(LS_WARNING)
- << "AllocationSequence: No STUN server configured, skipping.";
- return;
+ if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
+ udp_port_ = port;
+
+ // If STUN is not disabled, setting stun server address to port.
+ if (!IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
+ // If config has stun_address, use it to get server reflexive candidate
+ // otherwise use first TURN server which supports UDP.
+ if (config_ && !config_->stun_address.IsNil()) {
+ LOG(LS_INFO) << "AllocationSequence: UDPPort will be handling the "
+ << "STUN candidate generation.";
+ port->set_server_addr(config_->stun_address);
+ } else if (config_ &&
+ config_->SupportsProtocol(RELAY_TURN, PROTO_UDP)) {
+ port->set_server_addr(config_->GetFirstRelayServerAddress(
+ RELAY_TURN, PROTO_UDP));
+ LOG(LS_INFO) << "AllocationSequence: TURN Server address will be "
+ << " used for generating STUN candidate.";
+ }
}
- port->set_server_addr(config_->stun_address);
}
session_->AddAllocatedPort(port, this, true);
@@ -919,8 +930,6 @@ void AllocationSequence::CreateStunPorts() {
}
if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
- LOG(LS_INFO) << "AllocationSequence: "
- << "UDPPort will be handling the STUN candidate generation.";
return;
}
@@ -1010,17 +1019,44 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
PortList::const_iterator relay_port;
for (relay_port = config.ports.begin();
relay_port != config.ports.end(); ++relay_port) {
- TurnPort* port = TurnPort::Create(session_->network_thread(),
- session_->socket_factory(),
- network_, ip_,
- session_->allocator()->min_port(),
- session_->allocator()->max_port(),
- session_->username(),
- session_->password(),
- *relay_port, config.credentials);
- if (port) {
- session_->AddAllocatedPort(port, this, true);
+ TurnPort* port = NULL;
+ // Shared socket mode must be enabled only for UDP based ports. Hence
+ // don't pass shared socket for ports which will create TCP sockets.
+ if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
+ relay_port->proto == PROTO_UDP) {
+ port = TurnPort::Create(session_->network_thread(),
+ session_->socket_factory(),
+ network_, udp_socket_.get(),
+ session_->username(), session_->password(),
+ *relay_port, config.credentials);
+ // If we are using shared socket for TURN and udp ports, we need to
+ // find a way to demux the packets to the correct port when received.
+ // Mapping against server_address is one way of doing this. When packet
+ // is received the remote_address will be checked against the map.
+ // If server address is not resolved, a signal will be sent from the port
+ // after the address is resolved. The map entry will updated with the
+ // resolved address when the signal is received from the port.
+ if ((*relay_port).address.IsUnresolved()) {
+ // If server address is not resolved then listen for signal from port.
+ port->SignalResolvedServerAddress.connect(
+ this, &AllocationSequence::OnResolvedTurnServerAddress);
+ }
+ turn_ports_[(*relay_port).address] = port;
+ // Listen to the port destroyed signal, to allow AllocationSequence to
+ // remove entrt from it's map.
+ port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed);
+ } else {
+ port = TurnPort::Create(session_->network_thread(),
+ session_->socket_factory(),
+ network_, ip_,
+ session_->allocator()->min_port(),
+ session_->allocator()->max_port(),
+ session_->username(),
+ session_->password(),
+ *relay_port, config.credentials);
}
+ ASSERT(port != NULL);
+ session_->AddAllocatedPort(port, this, true);
}
}
@@ -1029,22 +1065,51 @@ void AllocationSequence::OnReadPacket(
const talk_base::SocketAddress& remote_addr,
const talk_base::PacketTime& packet_time) {
ASSERT(socket == udp_socket_.get());
- for (std::deque<Port*>::iterator iter = ports.begin();
- iter != ports.end(); ++iter) {
- // We have only one port in the queue.
- // TODO(mallinath) - Add shared socket support to Relay and Turn ports.
- if ((*iter)->HandleIncomingPacket(
- socket, data, size, remote_addr, packet_time)) {
- break;
- }
+ // If the packet is received from one of the TURN server in the config, then
+ // pass down the packet to that port, otherwise it will be handed down to
+ // the local udp port.
+ Port* port = NULL;
+ std::map<talk_base::SocketAddress, Port*>::iterator iter =
+ turn_ports_.find(remote_addr);
+ if (iter != turn_ports_.end()) {
+ port = iter->second;
+ } else if (udp_port_) {
+ port = udp_port_;
+ }
+ ASSERT(port != NULL);
+ if (port) {
+ port->HandleIncomingPacket(socket, data, size, remote_addr, packet_time);
}
}
void AllocationSequence::OnPortDestroyed(PortInterface* port) {
- std::deque<Port*>::iterator iter =
- std::find(ports.begin(), ports.end(), port);
- ASSERT(iter != ports.end());
- ports.erase(iter);
+ if (udp_port_ == port) {
+ udp_port_ = NULL;
+ } else {
+ std::map<talk_base::SocketAddress, Port*>::iterator iter;
+ for (iter = turn_ports_.begin(); iter != turn_ports_.end(); ++iter) {
+ if (iter->second == port) {
+ turn_ports_.erase(iter);
+ break;
+ }
+ }
+ }
+}
+
+void AllocationSequence::OnResolvedTurnServerAddress(
+ TurnPort* port, const talk_base::SocketAddress& server_address,
+ const talk_base::SocketAddress& resolved_server_address) {
+ std::map<talk_base::SocketAddress, Port*>::iterator iter;
+ iter = turn_ports_.find(server_address);
+ if (iter == turn_ports_.end()) {
+ LOG(LS_INFO) << "TurnPort entry is not found in the map.";
+ return;
+ }
+
+ ASSERT(iter->second == port);
+ // Remove old entry and then insert using the resolved address as key.
+ turn_ports_.erase(iter);
+ turn_ports_[resolved_server_address] = port;
}
// PortConfiguration
@@ -1062,7 +1127,7 @@ void PortConfiguration::AddRelay(const RelayServerConfig& config) {
}
bool PortConfiguration::SupportsProtocol(
- const RelayServerConfig& relay, ProtocolType type) {
+ const RelayServerConfig& relay, ProtocolType type) const {
PortList::const_iterator relay_port;
for (relay_port = relay.ports.begin();
relay_port != relay.ports.end();
@@ -1073,4 +1138,24 @@ bool PortConfiguration::SupportsProtocol(
return false;
}
+bool PortConfiguration::SupportsProtocol(RelayType turn_type,
+ ProtocolType type) const {
+ for (size_t i = 0; i < relays.size(); ++i) {
+ if (relays[i].type == turn_type &&
+ SupportsProtocol(relays[i], type))
+ return true;
+ }
+ return false;
+}
+
+talk_base::SocketAddress PortConfiguration::GetFirstRelayServerAddress(
+ RelayType turn_type, ProtocolType type) const {
+ for (size_t i = 0; i < relays.size(); ++i) {
+ if (relays[i].type == turn_type && SupportsProtocol(relays[i], type)) {
+ return relays[i].ports.front().address;
+ }
+ }
+ return talk_base::SocketAddress();
+}
+
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/p2p/client/basicportallocator.h b/chromium/third_party/libjingle/source/talk/p2p/client/basicportallocator.h
index 1fc6ebe10fb..8a60c425ca6 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/client/basicportallocator.h
+++ b/chromium/third_party/libjingle/source/talk/p2p/client/basicportallocator.h
@@ -204,7 +204,6 @@ class BasicPortAllocatorSession : public PortAllocatorSession,
talk_base::Thread* network_thread_;
talk_base::scoped_ptr<talk_base::PacketSocketFactory> owned_socket_factory_;
talk_base::PacketSocketFactory* socket_factory_;
- bool configuration_done_;
bool allocation_started_;
bool network_manager_started_;
bool running_; // set when StartGetAllPorts is called
@@ -233,8 +232,13 @@ struct PortConfiguration : public talk_base::MessageData {
void AddRelay(const RelayServerConfig& config);
// Determines whether the given relay server supports the given protocol.
- static bool SupportsProtocol(const RelayServerConfig& relay,
- ProtocolType type);
+ bool SupportsProtocol(const RelayServerConfig& relay,
+ ProtocolType type) const;
+ bool SupportsProtocol(RelayType turn_type, ProtocolType type) const;
+ // Helper method returns the first server address for the matching
+ // RelayType and Protocol type.
+ talk_base::SocketAddress GetFirstRelayServerAddress(
+ RelayType turn_type, ProtocolType type) const;
};
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/p2p/client/connectivitychecker.cc b/chromium/third_party/libjingle/source/talk/p2p/client/connectivitychecker.cc
index 1075bd6947b..1b599430ed1 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/client/connectivitychecker.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/client/connectivitychecker.cc
@@ -22,10 +22,6 @@
namespace cricket {
-static const char kSessionTypeVideo[] =
- "http://www.google.com/session/video";
-static const char kSessionNameRtp[] = "rtp";
-
static const char kDefaultStunHostname[] = "stun.l.google.com";
static const int kDefaultStunPort = 19302;
diff --git a/chromium/third_party/libjingle/source/talk/p2p/client/connectivitychecker_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/client/connectivitychecker_unittest.cc
index fe1cb9b5391..c62120beeb7 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/client/connectivitychecker_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/client/connectivitychecker_unittest.cc
@@ -23,8 +23,6 @@ static const talk_base::SocketAddress kStunAddr("44.44.44.44", 4444);
static const talk_base::SocketAddress kRelayAddr("55.55.55.55", 5555);
static const talk_base::SocketAddress kProxyAddr("66.66.66.66", 6666);
static const talk_base::ProxyType kProxyType = talk_base::PROXY_HTTPS;
-static const char kChannelName[] = "rtp_test";
-static const int kComponent = 1;
static const char kRelayHost[] = "relay.google.com";
static const char kRelayToken[] =
"CAESFwoOb2phQGdvb2dsZS5jb20Q043h47MmGhBTB1rbfIXkhuarDCZe+xF6";
@@ -75,7 +73,7 @@ class FakeStunPort : public StunPort {
// Just set external address and signal that we are done.
virtual void PrepareAddress() {
- AddAddress(kExternalAddr, kExternalAddr, "udp",
+ AddAddress(kExternalAddr, kExternalAddr, talk_base::SocketAddress(), "udp",
STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, true);
SignalPortComplete(this);
}
diff --git a/chromium/third_party/libjingle/source/talk/p2p/client/httpportallocator.cc b/chromium/third_party/libjingle/source/talk/p2p/client/httpportallocator.cc
index e54acba5c4d..b881d439f18 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/client/httpportallocator.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/client/httpportallocator.cc
@@ -41,9 +41,6 @@
namespace {
-const uint32 MSG_TIMEOUT = 100; // must not conflict
- // with BasicPortAllocator.cpp
-
// Helper routine to remove whitespace from the ends of a string.
void Trim(std::string& str) {
size_t first = str.find_first_not_of(" \t\r\n");
diff --git a/chromium/third_party/libjingle/source/talk/p2p/client/portallocator_unittest.cc b/chromium/third_party/libjingle/source/talk/p2p/client/portallocator_unittest.cc
index 6966e44d04e..44a8f2725d8 100644
--- a/chromium/third_party/libjingle/source/talk/p2p/client/portallocator_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/p2p/client/portallocator_unittest.cc
@@ -35,6 +35,7 @@
#include "talk/base/network.h"
#include "talk/base/physicalsocketserver.h"
#include "talk/base/socketaddress.h"
+#include "talk/base/ssladapter.h"
#include "talk/base/thread.h"
#include "talk/base/virtualsocketserver.h"
#include "talk/p2p/base/basicpacketsocketfactory.h"
@@ -43,6 +44,7 @@
#include "talk/p2p/base/portallocatorsessionproxy.h"
#include "talk/p2p/base/testrelayserver.h"
#include "talk/p2p/base/teststunserver.h"
+#include "talk/p2p/base/testturnserver.h"
#include "talk/p2p/client/basicportallocator.h"
#include "talk/p2p/client/httpportallocator.h"
@@ -52,6 +54,7 @@ using talk_base::Thread;
static const SocketAddress kClientAddr("11.11.11.11", 0);
static const SocketAddress kClientIPv6Addr(
"2401:fa00:4:1000:be30:5bff:fee5:c3", 0);
+static const SocketAddress kClientAddr2("22.22.22.22", 0);
static const SocketAddress kNatAddr("77.77.77.77", talk_base::NAT_SERVER_PORT);
static const SocketAddress kRemoteClientAddr("22.22.22.22", 0);
static const SocketAddress kStunAddr("99.99.99.1", cricket::STUN_SERVER_PORT);
@@ -61,6 +64,9 @@ static const SocketAddress kRelayTcpIntAddr("99.99.99.2", 5002);
static const SocketAddress kRelayTcpExtAddr("99.99.99.3", 5003);
static const SocketAddress kRelaySslTcpIntAddr("99.99.99.2", 5004);
static const SocketAddress kRelaySslTcpExtAddr("99.99.99.3", 5005);
+static const SocketAddress kTurnUdpIntAddr("99.99.99.4", 3478);
+static const SocketAddress kTurnTcpIntAddr("99.99.99.5", 3478);
+static const SocketAddress kTurnUdpExtAddr("99.99.99.6", 0);
// Minimum and maximum port for port range tests.
static const int kMinPort = 10000;
@@ -74,6 +80,8 @@ static const char kIcePwd0[] = "TESTICEPWD00000000000000";
static const char kContentName[] = "test content";
static const int kDefaultAllocationTimeout = 1000;
+static const char kTurnUsername[] = "test";
+static const char kTurnPassword[] = "test";
namespace cricket {
@@ -88,9 +96,13 @@ std::ostream& operator<<(std::ostream& os, const cricket::Candidate& c) {
class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> {
public:
static void SetUpTestCase() {
- // Ensure the RNG is inited.
- talk_base::InitRandom(NULL, 0);
+ talk_base::InitializeSSL();
}
+
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
+ }
+
PortAllocatorTest()
: pss_(new talk_base::PhysicalSocketServer),
vss_(new talk_base::VirtualSocketServer(pss_.get())),
@@ -102,6 +114,7 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> {
relay_server_(Thread::Current(), kRelayUdpIntAddr, kRelayUdpExtAddr,
kRelayTcpIntAddr, kRelayTcpExtAddr,
kRelaySslTcpIntAddr, kRelaySslTcpExtAddr),
+ turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr),
allocator_(new cricket::BasicPortAllocator(
&network_manager_, kStunAddr,
kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr)),
@@ -240,6 +253,7 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> {
talk_base::BasicPacketSocketFactory nat_socket_factory_;
cricket::TestStunServer stun_server_;
cricket::TestRelayServer relay_server_;
+ cricket::TestTurnServer turn_server_;
talk_base::FakeNetworkManager network_manager_;
talk_base::scoped_ptr<cricket::BasicPortAllocator> allocator_;
talk_base::scoped_ptr<cricket::PortAllocatorSession> session_;
@@ -331,56 +345,7 @@ TEST_F(PortAllocatorTest, TestSetupVideoRtpPortsWithNormalSendBuffers) {
// If we Stop gathering now, we shouldn't get a second "done" callback.
session_->StopGettingPorts();
- // All ports should have normal send-buffer sizes (64KB).
- CheckSendBufferSizesOfAllPorts(64 * 1024);
-}
-
-TEST_F(PortAllocatorTest, TestSetupVideoRtpPortsWithLargeSendBuffers) {
- AddInterface(kClientAddr);
- allocator_->set_flags(allocator_->flags() |
- cricket::PORTALLOCATOR_USE_LARGE_SOCKET_SEND_BUFFERS);
- EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP,
- cricket::CN_VIDEO));
- session_->StartGettingPorts();
- ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
- EXPECT_TRUE(candidate_allocation_done_);
- // If we Stop gathering now, we shouldn't get a second "done" callback.
- session_->StopGettingPorts();
-
- // All ports should have large send-buffer sizes (128KB).
- CheckSendBufferSizesOfAllPorts(128 * 1024);
-}
-
-TEST_F(PortAllocatorTest, TestSetupVideoRtcpPortsAndCheckSendBuffers) {
- AddInterface(kClientAddr);
- allocator_->set_flags(allocator_->flags() |
- cricket::PORTALLOCATOR_USE_LARGE_SOCKET_SEND_BUFFERS);
- EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTCP,
- cricket::CN_DATA));
- session_->StartGettingPorts();
- ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
- EXPECT_TRUE(candidate_allocation_done_);
- // If we Stop gathering now, we shouldn't get a second "done" callback.
- session_->StopGettingPorts();
-
- // No ports should have send-buffer size set.
- CheckSendBufferSizesOfAllPorts(-1);
-}
-
-
-TEST_F(PortAllocatorTest, TestSetupNonVideoPortsAndCheckSendBuffers) {
- AddInterface(kClientAddr);
- allocator_->set_flags(allocator_->flags() |
- cricket::PORTALLOCATOR_USE_LARGE_SOCKET_SEND_BUFFERS);
- EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP,
- cricket::CN_DATA));
- session_->StartGettingPorts();
- ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout);
- EXPECT_TRUE(candidate_allocation_done_);
- // If we Stop gathering now, we shouldn't get a second "done" callback.
- session_->StopGettingPorts();
-
- // No ports should have send-buffer size set.
+ // All ports should have unset send-buffer sizes.
CheckSendBufferSizesOfAllPorts(-1);
}
@@ -536,6 +501,23 @@ TEST_F(PortAllocatorTest, TestGetAllPortsNoUdpAllowed) {
EXPECT_TRUE_WAIT(candidate_allocation_done_, 9000);
}
+TEST_F(PortAllocatorTest, TestCandidatePriorityOfMultipleInterfaces) {
+ AddInterface(kClientAddr);
+ AddInterface(kClientAddr2);
+ // Allocating only host UDP ports. This is done purely for testing
+ // convenience.
+ allocator().set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
+ cricket::PORTALLOCATOR_DISABLE_STUN |
+ cricket::PORTALLOCATOR_DISABLE_RELAY);
+ EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+ session_->StartGettingPorts();
+ EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+ ASSERT_EQ(2U, candidates_.size());
+ EXPECT_EQ(2U, ports_.size());
+ // Candidates priorities should be different.
+ EXPECT_NE(candidates_[0].priority(), candidates_[1].priority());
+}
+
// Test to verify ICE restart process.
TEST_F(PortAllocatorTest, TestGetAllPortsRestarts) {
AddInterface(kClientAddr);
@@ -680,7 +662,7 @@ TEST_F(PortAllocatorTest, TestDisableSharedUfrag) {
// is allocated for udp and stun. Also verify there is only one candidate
// (local) if stun candidate is same as local candidate, which will be the case
// in a public network like the below test.
-TEST_F(PortAllocatorTest, TestEnableSharedSocketWithoutNat) {
+TEST_F(PortAllocatorTest, TestSharedSocketWithoutNat) {
AddInterface(kClientAddr);
allocator_->set_flags(allocator().flags() |
cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
@@ -697,7 +679,7 @@ TEST_F(PortAllocatorTest, TestEnableSharedSocketWithoutNat) {
// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled only one port
// is allocated for udp and stun. In this test we should expect both stun and
// local candidates as client behind a nat.
-TEST_F(PortAllocatorTest, TestEnableSharedSocketWithNat) {
+TEST_F(PortAllocatorTest, TestSharedSocketWithNat) {
AddInterface(kClientAddr);
talk_base::scoped_ptr<talk_base::NATServer> nat_server(
CreateNatServer(kNatAddr, talk_base::NAT_OPEN_CONE));
@@ -720,10 +702,116 @@ TEST_F(PortAllocatorTest, TestEnableSharedSocketWithNat) {
EXPECT_EQ(3U, candidates_.size());
}
+// Test TURN port in shared socket mode with UDP and TCP TURN server adderesses.
+TEST_F(PortAllocatorTest, TestSharedSocketWithoutNatUsingTurn) {
+ turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
+ AddInterface(kClientAddr);
+ allocator_.reset(new cricket::BasicPortAllocator(&network_manager_));
+ cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
+ cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword);
+ relay_server.credentials = credentials;
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ kTurnUdpIntAddr, cricket::PROTO_UDP, false));
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ kTurnTcpIntAddr, cricket::PROTO_TCP, false));
+ allocator_->AddRelay(relay_server);
+
+ allocator_->set_step_delay(cricket::kMinimumStepDelay);
+ allocator_->set_flags(allocator().flags() |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+ cricket::PORTALLOCATOR_DISABLE_TCP);
+
+ EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+ session_->StartGettingPorts();
+
+ ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout);
+ ASSERT_EQ(3U, ports_.size());
+ EXPECT_PRED5(CheckCandidate, candidates_[0],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+ EXPECT_PRED5(CheckCandidate, candidates_[1],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+ talk_base::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+ EXPECT_PRED5(CheckCandidate, candidates_[2],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+ talk_base::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+ EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+ EXPECT_EQ(3U, candidates_.size());
+}
+
+// Testing DNS resolve for the TURN server, this will test AllocationSequence
+// handling the unresolved address signal from TurnPort.
+TEST_F(PortAllocatorTest, TestSharedSocketWithServerAddressResolve) {
+ turn_server_.AddInternalSocket(talk_base::SocketAddress("127.0.0.1", 3478),
+ cricket::PROTO_UDP);
+ AddInterface(kClientAddr);
+ allocator_.reset(new cricket::BasicPortAllocator(&network_manager_));
+ cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
+ cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword);
+ relay_server.credentials = credentials;
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ talk_base::SocketAddress("localhost", 3478),
+ cricket::PROTO_UDP, false));
+ allocator_->AddRelay(relay_server);
+
+ allocator_->set_step_delay(cricket::kMinimumStepDelay);
+ allocator_->set_flags(allocator().flags() |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+ cricket::PORTALLOCATOR_DISABLE_TCP);
+
+ EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+ session_->StartGettingPorts();
+
+ EXPECT_EQ_WAIT(2U, ports_.size(), kDefaultAllocationTimeout);
+}
+
+// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled only one port
+// is allocated for udp/stun/turn. In this test we should expect all local,
+// stun and turn candidates.
+TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurn) {
+ AddInterface(kClientAddr);
+ talk_base::scoped_ptr<talk_base::NATServer> nat_server(
+ CreateNatServer(kNatAddr, talk_base::NAT_OPEN_CONE));
+ allocator_.reset(new cricket::BasicPortAllocator(
+ &network_manager_, &nat_socket_factory_, kStunAddr));
+ cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
+ cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword);
+ relay_server.credentials = credentials;
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ kTurnUdpIntAddr, cricket::PROTO_UDP, false));
+ allocator_->AddRelay(relay_server);
+
+ allocator_->set_step_delay(cricket::kMinimumStepDelay);
+ allocator_->set_flags(allocator().flags() |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+ cricket::PORTALLOCATOR_DISABLE_TCP);
+
+ EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+ session_->StartGettingPorts();
+
+ ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout);
+ ASSERT_EQ(2U, ports_.size());
+ EXPECT_PRED5(CheckCandidate, candidates_[0],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
+ EXPECT_PRED5(CheckCandidate, candidates_[1],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
+ talk_base::SocketAddress(kNatAddr.ipaddr(), 0));
+ EXPECT_PRED5(CheckCandidate, candidates_[2],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+ talk_base::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+ EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+ EXPECT_EQ(3U, candidates_.size());
+ // Local port will be created first and then TURN port.
+ EXPECT_EQ(2U, ports_[0]->Candidates().size());
+ EXPECT_EQ(1U, ports_[1]->Candidates().size());
+}
+
// This test verifies when PORTALLOCATOR_ENABLE_SHARED_SOCKET flag is enabled
// and fail to generate STUN candidate, local UDP candidate is generated
// properly.
-TEST_F(PortAllocatorTest, TestEnableSharedSocketNoUdpAllowed) {
+TEST_F(PortAllocatorTest, TestSharedSocketNoUdpAllowed) {
allocator().set_flags(allocator().flags() |
cricket::PORTALLOCATOR_DISABLE_RELAY |
cricket::PORTALLOCATOR_DISABLE_TCP |
diff --git a/chromium/third_party/libjingle/source/talk/session/media/audiomonitor.cc b/chromium/third_party/libjingle/source/talk/session/media/audiomonitor.cc
index 385702f75f7..c3a2eb0cb44 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/audiomonitor.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/audiomonitor.cc
@@ -27,7 +27,7 @@
#include "talk/session/media/audiomonitor.h"
#include "talk/session/media/voicechannel.h"
-#include <cassert>
+#include <assert.h>
namespace cricket {
diff --git a/chromium/third_party/libjingle/source/talk/session/media/ssrcmuxfilter.cc b/chromium/third_party/libjingle/source/talk/session/media/bundlefilter.cc
index 638167d18e7..0d7927c2e95 100644..100755
--- a/chromium/third_party/libjingle/source/talk/session/media/ssrcmuxfilter.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/bundlefilter.cc
@@ -25,9 +25,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "talk/session/media/ssrcmuxfilter.h"
-
-#include <algorithm>
+#include "talk/session/media/bundlefilter.h"
#include "talk/base/logging.h"
#include "talk/media/base/rtputils.h"
@@ -36,41 +34,52 @@ namespace cricket {
static const uint32 kSsrc01 = 0x01;
-SsrcMuxFilter::SsrcMuxFilter() {
+BundleFilter::BundleFilter() {
}
-SsrcMuxFilter::~SsrcMuxFilter() {
+BundleFilter::~BundleFilter() {
}
-bool SsrcMuxFilter::IsActive() const {
- return !streams_.empty();
-}
+bool BundleFilter::DemuxPacket(const char* data, size_t len, bool rtcp) {
+ // For rtp packets, we check whether the payload type can be found.
+ // For rtcp packets, we check whether the ssrc can be found or is the special
+ // value 1 except for SDES packets which always pass through. Plus, if
+ // |streams_| is empty, we will allow all rtcp packets pass through provided
+ // that they are valid rtcp packets in case that they are for early media.
+ if (!rtcp) {
+ int payload_type = 0;
+ if (!GetRtpPayloadType(data, len, &payload_type)) {
+ return false;
+ }
+ return FindPayloadType(payload_type);
+ }
-bool SsrcMuxFilter::DemuxPacket(const char* data, size_t len, bool rtcp) {
+ // Rtcp packets using ssrc filter.
+ int pl_type = 0;
uint32 ssrc = 0;
- if (!rtcp) {
- GetRtpSsrc(data, len, &ssrc);
+ if (!GetRtcpType(data, len, &pl_type)) return false;
+ if (pl_type == kRtcpTypeSDES) {
+ // SDES packet parsing not supported.
+ LOG(LS_INFO) << "SDES packet received for demux.";
+ return true;
} else {
- int pl_type = 0;
- if (!GetRtcpType(data, len, &pl_type)) return false;
- if (pl_type == kRtcpTypeSDES) {
- // SDES packet parsing not supported.
- LOG(LS_INFO) << "SDES packet received for demux.";
+ if (!GetRtcpSsrc(data, len, &ssrc)) return false;
+ if (ssrc == kSsrc01) {
+ // SSRC 1 has a special meaning and indicates generic feedback on
+ // some systems and should never be dropped. If it is forwarded
+ // incorrectly it will be ignored by lower layers anyway.
return true;
- } else {
- if (!GetRtcpSsrc(data, len, &ssrc)) return false;
- if (ssrc == kSsrc01) {
- // SSRC 1 has a special meaning and indicates generic feedback on
- // some systems and should never be dropped. If it is forwarded
- // incorrectly it will be ignored by lower layers anyway.
- return true;
- }
}
}
- return FindStream(ssrc);
+ // Pass through if |streams_| is empty to allow early rtcp packets in.
+ return !HasStreams() || FindStream(ssrc);
}
-bool SsrcMuxFilter::AddStream(const StreamParams& stream) {
+void BundleFilter::AddPayloadType(int payload_type) {
+ payload_types_.insert(payload_type);
+}
+
+bool BundleFilter::AddStream(const StreamParams& stream) {
if (GetStreamBySsrc(streams_, stream.first_ssrc(), NULL)) {
LOG(LS_WARNING) << "Stream already added to filter";
return false;
@@ -79,15 +88,27 @@ bool SsrcMuxFilter::AddStream(const StreamParams& stream) {
return true;
}
-bool SsrcMuxFilter::RemoveStream(uint32 ssrc) {
+bool BundleFilter::RemoveStream(uint32 ssrc) {
return RemoveStreamBySsrc(&streams_, ssrc);
}
-bool SsrcMuxFilter::FindStream(uint32 ssrc) const {
+bool BundleFilter::HasStreams() const {
+ return !streams_.empty();
+}
+
+bool BundleFilter::FindStream(uint32 ssrc) const {
if (ssrc == 0) {
return false;
}
return (GetStreamBySsrc(streams_, ssrc, NULL));
}
+bool BundleFilter::FindPayloadType(int pl_type) const {
+ return payload_types_.find(pl_type) != payload_types_.end();
+}
+
+void BundleFilter::ClearAllPayloadTypes() {
+ payload_types_.clear();
+}
+
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/session/media/ssrcmuxfilter.h b/chromium/third_party/libjingle/source/talk/session/media/bundlefilter.h
index 9420f54cceb..34bc3307345 100644..100755
--- a/chromium/third_party/libjingle/source/talk/session/media/ssrcmuxfilter.h
+++ b/chromium/third_party/libjingle/source/talk/session/media/bundlefilter.h
@@ -25,9 +25,10 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TALK_SESSION_MEDIA_SSRCMUXFILTER_H_
-#define TALK_SESSION_MEDIA_SSRCMUXFILTER_H_
+#ifndef TALK_SESSION_MEDIA_BUNDLEFILTER_H_
+#define TALK_SESSION_MEDIA_BUNDLEFILTER_H_
+#include <set>
#include <vector>
#include "talk/base/basictypes.h"
@@ -35,33 +36,45 @@
namespace cricket {
-// This class maintains list of recv SSRC's destined for cricket::BaseChannel.
// In case of single RTP session and single transport channel, all session
// ( or media) channels share a common transport channel. Hence they all get
// SignalReadPacket when packet received on transport channel. This requires
// cricket::BaseChannel to know all the valid sources, else media channel
// will decode invalid packets.
-class SsrcMuxFilter {
+//
+// This class determines whether a packet is destined for cricket::BaseChannel.
+// For rtp packets, this is decided based on the payload type. For rtcp packets,
+// this is decided based on the sender ssrc values.
+class BundleFilter {
public:
- SsrcMuxFilter();
- ~SsrcMuxFilter();
+ BundleFilter();
+ ~BundleFilter();
- // Whether the rtp mux is active for a sdp session.
- // Returns true if the filter contains a stream.
- bool IsActive() const;
// Determines packet belongs to valid cricket::BaseChannel.
bool DemuxPacket(const char* data, size_t len, bool rtcp);
+
+ // Adds the supported payload type.
+ void AddPayloadType(int payload_type);
+
// Adding a valid source to the filter.
bool AddStream(const StreamParams& stream);
+
// Removes source from the filter.
bool RemoveStream(uint32 ssrc);
- // Utility method added for unitest.
+
+ // Utility methods added for unitest.
+ // True if |streams_| is not empty.
+ bool HasStreams() const;
bool FindStream(uint32 ssrc) const;
+ bool FindPayloadType(int pl_type) const;
+ void ClearAllPayloadTypes();
+
private:
+ std::set<int> payload_types_;
std::vector<StreamParams> streams_;
};
} // namespace cricket
-#endif // TALK_SESSION_MEDIA_SSRCMUXFILTER_H_
+#endif // TALK_SESSION_MEDIA_BUNDLEFILTER_H_
diff --git a/chromium/third_party/libjingle/source/talk/session/media/ssrcmuxfilter_unittest.cc b/chromium/third_party/libjingle/source/talk/session/media/bundlefilter_unittest.cc
index 85a4dbe50da..0386666c099 100644..100755
--- a/chromium/third_party/libjingle/source/talk/session/media/ssrcmuxfilter_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/bundlefilter_unittest.cc
@@ -25,34 +25,34 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
#include "talk/base/gunit.h"
-#include "talk/session/media/ssrcmuxfilter.h"
+#include "talk/session/media/bundlefilter.h"
+
+using cricket::StreamParams;
static const int kSsrc1 = 0x1111;
static const int kSsrc2 = 0x2222;
static const int kSsrc3 = 0x3333;
-
-using cricket::StreamParams;
-
-// SSRC = 0x1111
-static const unsigned char kRtpPacketSsrc1[] = {
- 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11,
-};
-
-// SSRC = 0x2222
-static const unsigned char kRtpPacketSsrc2[] = {
- 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22,
+static const int kPayloadType1 = 0x11;
+static const int kPayloadType2 = 0x22;
+static const int kPayloadType3 = 0x33;
+
+// SSRC = 0x1111, Payload type = 0x11
+static const unsigned char kRtpPacketPt1Ssrc1[] = {
+ 0x80, kPayloadType1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x11,
};
-// SSRC = 0
-static const unsigned char kRtpPacketInvalidSsrc[] = {
- 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+// SSRC = 0x2222, Payload type = 0x22
+static const unsigned char kRtpPacketPt2Ssrc2[] = {
+ 0x80, 0x80 + kPayloadType2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x22,
};
-// invalid size
-static const unsigned char kRtpPacketTooSmall[] = {
- 0x80, 0x80, 0x00, 0x00,
+// SSRC = 0x2222, Payload type = 0x33
+static const unsigned char kRtpPacketPt3Ssrc2[] = {
+ 0x80, kPayloadType3, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22,
+ 0x22,
};
// PT = 200 = SR, len = 28, SSRC of sender = 0x0001
@@ -105,80 +105,92 @@ static const unsigned char kRtcpPacketNonCompoundRtcpPliFeedback[] = {
0x81, 0xCE, 0x00, 0x0C, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11,
};
-TEST(SsrcMuxFilterTest, AddRemoveStreamTest) {
- cricket::SsrcMuxFilter ssrc_filter;
- EXPECT_FALSE(ssrc_filter.IsActive());
- EXPECT_TRUE(ssrc_filter.AddStream(StreamParams::CreateLegacy(kSsrc1)));
+TEST(BundleFilterTest, AddRemoveStreamTest) {
+ cricket::BundleFilter bundle_filter;
+ EXPECT_FALSE(bundle_filter.HasStreams());
+ EXPECT_TRUE(bundle_filter.AddStream(StreamParams::CreateLegacy(kSsrc1)));
StreamParams stream2;
stream2.ssrcs.push_back(kSsrc2);
stream2.ssrcs.push_back(kSsrc3);
- EXPECT_TRUE(ssrc_filter.AddStream(stream2));
-
- EXPECT_TRUE(ssrc_filter.IsActive());
- EXPECT_TRUE(ssrc_filter.FindStream(kSsrc1));
- EXPECT_TRUE(ssrc_filter.FindStream(kSsrc2));
- EXPECT_TRUE(ssrc_filter.FindStream(kSsrc3));
- EXPECT_TRUE(ssrc_filter.RemoveStream(kSsrc1));
- EXPECT_FALSE(ssrc_filter.FindStream(kSsrc1));
- EXPECT_TRUE(ssrc_filter.RemoveStream(kSsrc3));
- EXPECT_FALSE(ssrc_filter.RemoveStream(kSsrc2)); // Already removed.
- EXPECT_FALSE(ssrc_filter.IsActive());
+ EXPECT_TRUE(bundle_filter.AddStream(stream2));
+
+ EXPECT_TRUE(bundle_filter.HasStreams());
+ EXPECT_TRUE(bundle_filter.FindStream(kSsrc1));
+ EXPECT_TRUE(bundle_filter.FindStream(kSsrc2));
+ EXPECT_TRUE(bundle_filter.FindStream(kSsrc3));
+ EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc1));
+ EXPECT_FALSE(bundle_filter.FindStream(kSsrc1));
+ EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc3));
+ EXPECT_FALSE(bundle_filter.RemoveStream(kSsrc2)); // Already removed.
+ EXPECT_FALSE(bundle_filter.HasStreams());
}
-TEST(SsrcMuxFilterTest, RtpPacketTest) {
- cricket::SsrcMuxFilter ssrc_filter;
- EXPECT_TRUE(ssrc_filter.AddStream(StreamParams::CreateLegacy(kSsrc1)));
- EXPECT_TRUE(ssrc_filter.DemuxPacket(
- reinterpret_cast<const char*>(kRtpPacketSsrc1),
- sizeof(kRtpPacketSsrc1), false));
- EXPECT_TRUE(ssrc_filter.AddStream(StreamParams::CreateLegacy(kSsrc2)));
- EXPECT_TRUE(ssrc_filter.DemuxPacket(
- reinterpret_cast<const char*>(kRtpPacketSsrc2),
- sizeof(kRtpPacketSsrc2), false));
- EXPECT_TRUE(ssrc_filter.RemoveStream(kSsrc2));
- EXPECT_FALSE(ssrc_filter.DemuxPacket(
- reinterpret_cast<const char*>(kRtpPacketSsrc2),
- sizeof(kRtpPacketSsrc2), false));
- EXPECT_FALSE(ssrc_filter.DemuxPacket(
- reinterpret_cast<const char*>(kRtpPacketInvalidSsrc),
- sizeof(kRtpPacketInvalidSsrc), false));
- EXPECT_FALSE(ssrc_filter.DemuxPacket(
- reinterpret_cast<const char*>(kRtpPacketTooSmall),
- sizeof(kRtpPacketTooSmall), false));
+TEST(BundleFilterTest, RtpPacketTest) {
+ cricket::BundleFilter bundle_filter;
+ bundle_filter.AddPayloadType(kPayloadType1);
+ EXPECT_TRUE(bundle_filter.DemuxPacket(
+ reinterpret_cast<const char*>(kRtpPacketPt1Ssrc1),
+ sizeof(kRtpPacketPt1Ssrc1), false));
+ bundle_filter.AddPayloadType(kPayloadType2);
+ EXPECT_TRUE(bundle_filter.DemuxPacket(
+ reinterpret_cast<const char*>(kRtpPacketPt2Ssrc2),
+ sizeof(kRtpPacketPt2Ssrc2), false));
+
+ // Payload type 0x33 is not added.
+ EXPECT_FALSE(bundle_filter.DemuxPacket(
+ reinterpret_cast<const char*>(kRtpPacketPt3Ssrc2),
+ sizeof(kRtpPacketPt3Ssrc2), false));
+ // Size is too small.
+ EXPECT_FALSE(bundle_filter.DemuxPacket(
+ reinterpret_cast<const char*>(kRtpPacketPt1Ssrc1), 11, false));
+
+ bundle_filter.ClearAllPayloadTypes();
+ EXPECT_FALSE(bundle_filter.DemuxPacket(
+ reinterpret_cast<const char*>(kRtpPacketPt1Ssrc1),
+ sizeof(kRtpPacketPt1Ssrc1), false));
+ EXPECT_FALSE(bundle_filter.DemuxPacket(
+ reinterpret_cast<const char*>(kRtpPacketPt2Ssrc2),
+ sizeof(kRtpPacketPt2Ssrc2), false));
}
-TEST(SsrcMuxFilterTest, RtcpPacketTest) {
- cricket::SsrcMuxFilter ssrc_filter;
- EXPECT_TRUE(ssrc_filter.AddStream(StreamParams::CreateLegacy(kSsrc1)));
- EXPECT_TRUE(ssrc_filter.DemuxPacket(
+TEST(BundleFilterTest, RtcpPacketTest) {
+ cricket::BundleFilter bundle_filter;
+ EXPECT_TRUE(bundle_filter.AddStream(StreamParams::CreateLegacy(kSsrc1)));
+ EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketCompoundSrSdesSsrc1),
sizeof(kRtcpPacketCompoundSrSdesSsrc1), true));
- EXPECT_TRUE(ssrc_filter.AddStream(StreamParams::CreateLegacy(kSsrc2)));
- EXPECT_TRUE(ssrc_filter.DemuxPacket(
+ EXPECT_TRUE(bundle_filter.AddStream(StreamParams::CreateLegacy(kSsrc2)));
+ EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSrSsrc2),
sizeof(kRtcpPacketSrSsrc2), true));
- EXPECT_TRUE(ssrc_filter.DemuxPacket(
+ EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSdesSsrc2),
sizeof(kRtcpPacketSdesSsrc2), true));
- EXPECT_TRUE(ssrc_filter.RemoveStream(kSsrc2));
+ EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc2));
// RTCP Packets other than SR and RR are demuxed regardless of SSRC.
- EXPECT_TRUE(ssrc_filter.DemuxPacket(
+ EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSdesSsrc2),
sizeof(kRtcpPacketSdesSsrc2), true));
// RTCP Packets with 'special' SSRC 0x01 are demuxed also
- EXPECT_TRUE(ssrc_filter.DemuxPacket(
+ EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSrSsrc01),
sizeof(kRtcpPacketSrSsrc01), true));
- EXPECT_FALSE(ssrc_filter.DemuxPacket(
+ EXPECT_FALSE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSrSsrc2),
sizeof(kRtcpPacketSrSsrc2), true));
- EXPECT_FALSE(ssrc_filter.DemuxPacket(
+ EXPECT_FALSE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketFixedHeaderOnly),
sizeof(kRtcpPacketFixedHeaderOnly), true));
- EXPECT_FALSE(ssrc_filter.DemuxPacket(
+ EXPECT_FALSE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketTooSmall),
sizeof(kRtcpPacketTooSmall), true));
- EXPECT_TRUE(ssrc_filter.DemuxPacket(
+ EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketNonCompoundRtcpPliFeedback),
sizeof(kRtcpPacketNonCompoundRtcpPliFeedback), true));
+ // If the streams_ is empty, rtcp packet passes through
+ EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc1));
+ EXPECT_FALSE(bundle_filter.HasStreams());
+ EXPECT_TRUE(bundle_filter.DemuxPacket(
+ reinterpret_cast<const char*>(kRtcpPacketSrSsrc2),
+ sizeof(kRtcpPacketSrSsrc2), true));
}
diff --git a/chromium/third_party/libjingle/source/talk/session/media/call.cc b/chromium/third_party/libjingle/source/talk/session/media/call.cc
index 967846bd214..91fe146e95a 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/call.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/call.cc
@@ -34,6 +34,7 @@
#include "talk/media/base/screencastid.h"
#include "talk/p2p/base/parsing.h"
#include "talk/session/media/call.h"
+#include "talk/session/media/currentspeakermonitor.h"
#include "talk/session/media/mediasessionclient.h"
namespace cricket {
@@ -74,6 +75,22 @@ bool ContentContainsCrypto(const cricket::ContentInfo* content) {
}
+AudioSourceProxy::AudioSourceProxy(Call* call)
+ : call_(call) {
+ call_->SignalAudioMonitor.connect(this, &AudioSourceProxy::OnAudioMonitor);
+ call_->SignalMediaStreamsUpdate.connect(
+ this, &AudioSourceProxy::OnMediaStreamsUpdate);
+}
+
+void AudioSourceProxy::OnAudioMonitor(Call* call, const AudioInfo& info) {
+ SignalAudioMonitor(this, info);
+}
+
+void AudioSourceProxy::OnMediaStreamsUpdate(Call* call, Session* session,
+ const MediaStreams& added, const MediaStreams& removed) {
+ SignalMediaStreamsUpdate(this, session, added, removed);
+}
+
Call::Call(MediaSessionClient* session_client)
: id_(talk_base::CreateRandomId()),
session_client_(session_client),
@@ -84,6 +101,7 @@ Call::Call(MediaSessionClient* session_client)
video_muted_(false),
send_to_voicemail_(true),
playing_dtmf_(false) {
+ audio_source_proxy_.reset(new AudioSourceProxy(this));
}
Call::~Call() {
@@ -523,7 +541,7 @@ bool Call::StartScreencast(Session* session,
VideoContentDescription* video = CreateVideoStreamUpdate(stream);
// TODO(pthatcher): Wait until view request before sending video.
- video_channel->SetLocalContent(video, CA_UPDATE);
+ video_channel->SetLocalContent(video, CA_UPDATE, NULL);
SendVideoStreamUpdate(session, video);
return true;
}
@@ -546,7 +564,7 @@ bool Call::StopScreencast(Session* session,
// No ssrcs
VideoContentDescription* video = CreateVideoStreamUpdate(stream);
- video_channel->SetLocalContent(video, CA_UPDATE);
+ video_channel->SetLocalContent(video, CA_UPDATE, NULL);
SendVideoStreamUpdate(session, video);
return true;
}
@@ -718,7 +736,8 @@ void Call::StartSpeakerMonitor(Session* session) {
StartAudioMonitor(session, kAudioMonitorPollPeriodMillis);
}
CurrentSpeakerMonitor* speaker_monitor =
- new cricket::CurrentSpeakerMonitor(this, session);
+ new cricket::CurrentSpeakerMonitor(
+ audio_source_proxy_.get(), session);
speaker_monitor->SignalUpdate.connect(this, &Call::OnSpeakerMonitor);
speaker_monitor->Start();
speaker_monitor_map_[session->id()] = speaker_monitor;
@@ -870,9 +889,11 @@ void Call::OnRemoteDescriptionUpdate(BaseSession* base_session,
bool Call::UpdateVoiceChannelRemoteContent(
Session* session, const AudioContentDescription* audio) {
VoiceChannel* voice_channel = GetVoiceChannel(session);
- if (!voice_channel->SetRemoteContent(audio, CA_UPDATE)) {
- LOG(LS_ERROR) << "Failure in audio SetRemoteContent with CA_UPDATE";
- session->SetError(BaseSession::ERROR_CONTENT);
+ if (!voice_channel->SetRemoteContent(audio, CA_UPDATE, NULL)) {
+ const std::string error_desc =
+ "Failure in audio SetRemoteContent with CA_UPDATE";
+ LOG(LS_ERROR) << error_desc;
+ session->SetError(BaseSession::ERROR_CONTENT, error_desc);
return false;
}
return true;
@@ -881,9 +902,11 @@ bool Call::UpdateVoiceChannelRemoteContent(
bool Call::UpdateVideoChannelRemoteContent(
Session* session, const VideoContentDescription* video) {
VideoChannel* video_channel = GetVideoChannel(session);
- if (!video_channel->SetRemoteContent(video, CA_UPDATE)) {
- LOG(LS_ERROR) << "Failure in video SetRemoteContent with CA_UPDATE";
- session->SetError(BaseSession::ERROR_CONTENT);
+ if (!video_channel->SetRemoteContent(video, CA_UPDATE, NULL)) {
+ const std::string error_desc =
+ "Failure in video SetRemoteContent with CA_UPDATE";
+ LOG(LS_ERROR) << error_desc;
+ session->SetError(BaseSession::ERROR_CONTENT, error_desc);
return false;
}
return true;
@@ -892,9 +915,11 @@ bool Call::UpdateVideoChannelRemoteContent(
bool Call::UpdateDataChannelRemoteContent(
Session* session, const DataContentDescription* data) {
DataChannel* data_channel = GetDataChannel(session);
- if (!data_channel->SetRemoteContent(data, CA_UPDATE)) {
- LOG(LS_ERROR) << "Failure in data SetRemoteContent with CA_UPDATE";
- session->SetError(BaseSession::ERROR_CONTENT);
+ if (!data_channel->SetRemoteContent(data, CA_UPDATE, NULL)) {
+ const std::string error_desc =
+ "Failure in data SetRemoteContent with CA_UPDATE";
+ LOG(LS_ERROR) << error_desc;
+ session->SetError(BaseSession::ERROR_CONTENT, error_desc);
return false;
}
return true;
@@ -1098,4 +1123,8 @@ Session* Call::InternalInitiateSession(const std::string& id,
return session;
}
+AudioSourceProxy* Call::GetAudioSourceProxy() {
+ return audio_source_proxy_.get();
+}
+
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/session/media/call.h b/chromium/third_party/libjingle/source/talk/session/media/call.h
index efb4ea396f4..063447a7f73 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/call.h
+++ b/chromium/third_party/libjingle/source/talk/session/media/call.h
@@ -48,6 +48,8 @@
namespace cricket {
+struct AudioInfo;
+class Call;
class MediaSessionClient;
class BaseChannel;
class VoiceChannel;
@@ -58,6 +60,26 @@ class DataChannel;
struct CallOptions : public MediaSessionOptions {
};
+// CurrentSpeakerMonitor used to have a dependency on Call. To remove this
+// dependency, we create AudioSourceContext. CurrentSpeakerMonitor depends on
+// AudioSourceContext.
+// AudioSourceProxy acts as a proxy so that when SignalAudioMonitor
+// in Call is triggered, SignalAudioMonitor in AudioSourceContext is triggered.
+// Likewise, when OnMediaStreamsUpdate in Call is triggered,
+// OnMediaStreamsUpdate in AudioSourceContext is triggered.
+class AudioSourceProxy: public AudioSourceContext, public sigslot::has_slots<> {
+ public:
+ explicit AudioSourceProxy(Call* call);
+
+ private:
+ void OnAudioMonitor(Call* call, const AudioInfo& info);
+ void OnMediaStreamsUpdate(Call* call, cricket::Session*,
+ const cricket::MediaStreams&, const cricket::MediaStreams&);
+
+ AudioSourceContext* audio_source_context_;
+ Call* call_;
+};
+
class Call : public talk_base::MessageHandler, public sigslot::has_slots<> {
public:
explicit Call(MediaSessionClient* session_client);
@@ -167,6 +189,8 @@ class Call : public talk_base::MessageHandler, public sigslot::has_slots<> {
const ReceiveDataParams&,
const talk_base::Buffer&> SignalDataReceived;
+ AudioSourceProxy* GetAudioSourceProxy();
+
private:
void OnMessage(talk_base::Message* message);
void OnSessionState(BaseSession* base_session, BaseSession::State state);
@@ -276,6 +300,8 @@ class Call : public talk_base::MessageHandler, public sigslot::has_slots<> {
VoiceMediaInfo last_voice_media_info_;
+ talk_base::scoped_ptr<AudioSourceProxy> audio_source_proxy_;
+
friend class MediaSessionClient;
};
diff --git a/chromium/third_party/libjingle/source/talk/session/media/channel.cc b/chromium/third_party/libjingle/source/talk/session/media/channel.cc
index 9a8559a5b05..575c7595339 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/channel.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/channel.cc
@@ -27,61 +27,34 @@
#include "talk/session/media/channel.h"
+#include "talk/base/bind.h"
#include "talk/base/buffer.h"
#include "talk/base/byteorder.h"
#include "talk/base/common.h"
#include "talk/base/dscp.h"
#include "talk/base/logging.h"
+#include "talk/media/base/constants.h"
#include "talk/media/base/rtputils.h"
#include "talk/p2p/base/transportchannel.h"
#include "talk/session/media/channelmanager.h"
#include "talk/session/media/mediamessages.h"
-#include "talk/session/media/rtcpmuxfilter.h"
#include "talk/session/media/typingmonitor.h"
namespace cricket {
+using talk_base::Bind;
+
enum {
- MSG_ENABLE = 1,
- MSG_DISABLE,
- MSG_MUTESTREAM,
- MSG_ISSTREAMMUTED,
- MSG_SETREMOTECONTENT,
- MSG_SETLOCALCONTENT,
- MSG_EARLYMEDIATIMEOUT,
- MSG_CANINSERTDTMF,
- MSG_INSERTDTMF,
- MSG_GETSTATS,
- MSG_SETRENDERER,
- MSG_ADDRECVSTREAM,
- MSG_REMOVERECVSTREAM,
- MSG_ADDSENDSTREAM,
- MSG_REMOVESENDSTREAM,
- MSG_SETRINGBACKTONE,
- MSG_PLAYRINGBACKTONE,
- MSG_SETMAXSENDBANDWIDTH,
- MSG_ADDSCREENCAST,
- MSG_REMOVESCREENCAST,
- MSG_SENDINTRAFRAME,
- MSG_REQUESTINTRAFRAME,
+ MSG_EARLYMEDIATIMEOUT = 1,
MSG_SCREENCASTWINDOWEVENT,
MSG_RTPPACKET,
MSG_RTCPPACKET,
MSG_CHANNEL_ERROR,
- MSG_SETCHANNELOPTIONS,
- MSG_SCALEVOLUME,
- MSG_HANDLEVIEWREQUEST,
MSG_READYTOSENDDATA,
- MSG_SENDDATA,
MSG_DATARECEIVED,
- MSG_SETCAPTURER,
- MSG_ISSCREENCASTING,
- MSG_GETSCREENCASTDETAILS,
- MSG_SETSCREENCASTFACTORY,
MSG_FIRSTPACKETRECEIVED,
- MSG_SESSION_ERROR,
- MSG_NEWSTREAMRECEIVED,
+ MSG_STREAMCLOSEDREMOTELY,
};
// Value specified in RFC 5764.
@@ -89,6 +62,17 @@ static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp";
static const int kAgcMinus10db = -10;
+static void SetSessionError(BaseSession* session, BaseSession::Error error,
+ const std::string& error_desc) {
+ session->SetError(error, error_desc);
+}
+
+static void SafeSetError(const std::string& message, std::string* error_desc) {
+ if (error_desc) {
+ *error_desc = message;
+ }
+}
+
// TODO(hellner): use the device manager for creation of screen capturers when
// the cl enabling it has landed.
class NullScreenCapturerFactory : public VideoChannel::ScreenCapturerFactory {
@@ -103,129 +87,11 @@ VideoChannel::ScreenCapturerFactory* CreateScreenCapturerFactory() {
return new NullScreenCapturerFactory();
}
-struct SetContentData : public talk_base::MessageData {
- SetContentData(const MediaContentDescription* content, ContentAction action)
- : content(content),
- action(action),
- result(false) {
- }
- const MediaContentDescription* content;
- ContentAction action;
- bool result;
-};
-
-struct SetBandwidthData : public talk_base::MessageData {
- explicit SetBandwidthData(int value) : value(value), result(false) {}
- int value;
- bool result;
-};
-
-struct SetRingbackToneMessageData : public talk_base::MessageData {
- SetRingbackToneMessageData(const void* b, int l)
- : buf(b),
- len(l),
- result(false) {
- }
- const void* buf;
- int len;
- bool result;
-};
-
-struct PlayRingbackToneMessageData : public talk_base::MessageData {
- PlayRingbackToneMessageData(uint32 s, bool p, bool l)
- : ssrc(s),
- play(p),
- loop(l),
- result(false) {
- }
- uint32 ssrc;
- bool play;
- bool loop;
- bool result;
-};
-typedef talk_base::TypedMessageData<bool> BoolMessageData;
-struct DtmfMessageData : public talk_base::MessageData {
- DtmfMessageData(uint32 ssrc, int event, int duration, int flags)
- : ssrc(ssrc),
- event(event),
- duration(duration),
- flags(flags),
- result(false) {
- }
- uint32 ssrc;
- int event;
- int duration;
- int flags;
- bool result;
-};
-struct ScaleVolumeMessageData : public talk_base::MessageData {
- ScaleVolumeMessageData(uint32 s, double l, double r)
- : ssrc(s),
- left(l),
- right(r),
- result(false) {
- }
- uint32 ssrc;
- double left;
- double right;
- bool result;
-};
-
-struct VoiceStatsMessageData : public talk_base::MessageData {
- explicit VoiceStatsMessageData(VoiceMediaInfo* stats)
- : result(false),
- stats(stats) {
- }
- bool result;
- VoiceMediaInfo* stats;
-};
-
-struct VideoStatsMessageData : public talk_base::MessageData {
- explicit VideoStatsMessageData(VideoMediaInfo* stats)
- : result(false),
- stats(stats) {
- }
- bool result;
- VideoMediaInfo* stats;
-};
-
struct PacketMessageData : public talk_base::MessageData {
talk_base::Buffer packet;
talk_base::DiffServCodePoint dscp;
};
-struct AudioRenderMessageData: public talk_base::MessageData {
- AudioRenderMessageData(uint32 s, AudioRenderer* r, bool l)
- : ssrc(s), renderer(r), is_local(l), result(false) {}
- uint32 ssrc;
- AudioRenderer* renderer;
- bool is_local;
- bool result;
-};
-
-struct VideoRenderMessageData : public talk_base::MessageData {
- VideoRenderMessageData(uint32 s, VideoRenderer* r) : ssrc(s), renderer(r) {}
- uint32 ssrc;
- VideoRenderer* renderer;
-};
-
-struct AddScreencastMessageData : public talk_base::MessageData {
- AddScreencastMessageData(uint32 s, const ScreencastId& id)
- : ssrc(s),
- window_id(id),
- result(NULL) {
- }
- uint32 ssrc;
- ScreencastId window_id;
- VideoCapturer* result;
-};
-
-struct RemoveScreencastMessageData : public talk_base::MessageData {
- explicit RemoveScreencastMessageData(uint32 s) : ssrc(s), result(false) {}
- uint32 ssrc;
- bool result;
-};
-
struct ScreencastEventMessageData : public talk_base::MessageData {
ScreencastEventMessageData(uint32 s, talk_base::WindowEvent we)
: ssrc(s),
@@ -235,15 +101,6 @@ struct ScreencastEventMessageData : public talk_base::MessageData {
talk_base::WindowEvent event;
};
-struct ViewRequestMessageData : public talk_base::MessageData {
- explicit ViewRequestMessageData(const ViewRequest& r)
- : request(r),
- result(false) {
- }
- ViewRequest request;
- bool result;
-};
-
struct VoiceChannelErrorMessageData : public talk_base::MessageData {
VoiceChannelErrorMessageData(uint32 in_ssrc,
VoiceMediaChannel::Error in_error)
@@ -273,75 +130,9 @@ struct DataChannelErrorMessageData : public talk_base::MessageData {
DataMediaChannel::Error error;
};
-struct SessionErrorMessageData : public talk_base::MessageData {
- explicit SessionErrorMessageData(cricket::BaseSession::Error error)
- : error_(error) {}
-
- BaseSession::Error error_;
-};
-
-struct SsrcMessageData : public talk_base::MessageData {
- explicit SsrcMessageData(uint32 ssrc) : ssrc(ssrc), result(false) {}
- uint32 ssrc;
- bool result;
-};
-
-struct StreamMessageData : public talk_base::MessageData {
- explicit StreamMessageData(const StreamParams& in_sp)
- : sp(in_sp),
- result(false) {
- }
- StreamParams sp;
- bool result;
-};
-
-struct MuteStreamData : public talk_base::MessageData {
- MuteStreamData(uint32 ssrc, bool mute)
- : ssrc(ssrc), mute(mute), result(false) {}
- uint32 ssrc;
- bool mute;
- bool result;
-};
-
-struct AudioOptionsMessageData : public talk_base::MessageData {
- explicit AudioOptionsMessageData(const AudioOptions& options)
- : options(options),
- result(false) {
- }
- AudioOptions options;
- bool result;
-};
-struct VideoOptionsMessageData : public talk_base::MessageData {
- explicit VideoOptionsMessageData(const VideoOptions& options)
- : options(options),
- result(false) {
- }
- VideoOptions options;
- bool result;
-};
-
-struct SetCapturerMessageData : public talk_base::MessageData {
- SetCapturerMessageData(uint32 s, VideoCapturer* c)
- : ssrc(s),
- capturer(c),
- result(false) {
- }
- uint32 ssrc;
- VideoCapturer* capturer;
- bool result;
-};
-
-struct IsScreencastingMessageData : public talk_base::MessageData {
- IsScreencastingMessageData()
- : result(false) {
- }
- bool result;
-};
-
-struct VideoChannel::ScreencastDetailsMessageData :
- public talk_base::MessageData {
- explicit ScreencastDetailsMessageData(uint32 s)
+struct VideoChannel::ScreencastDetailsData {
+ explicit ScreencastDetailsData(uint32 s)
: ssrc(s), fps(0), screencast_max_pixels(0) {
}
uint32 ssrc;
@@ -349,14 +140,6 @@ struct VideoChannel::ScreencastDetailsMessageData :
int screencast_max_pixels;
};
-struct SetScreenCaptureFactoryMessageData : public talk_base::MessageData {
- explicit SetScreenCaptureFactoryMessageData(
- VideoChannel::ScreenCapturerFactory* f)
- : screencapture_factory(f) {
- }
- VideoChannel::ScreenCapturerFactory* screencapture_factory;
-};
-
static const char* PacketType(bool rtcp) {
return (!rtcp) ? "RTP" : "RTCP";
}
@@ -404,7 +187,8 @@ BaseChannel::BaseChannel(talk_base::Thread* thread,
remote_content_direction_(MD_INACTIVE),
has_received_packet_(false),
dtls_keyed_(false),
- secure_required_(false) {
+ secure_required_(false),
+ rtp_abs_sendtime_extn_id_(-1) {
ASSERT(worker_thread_ == talk_base::Thread::Current());
LOG(LS_INFO) << "Created channel for " << content_name;
}
@@ -414,7 +198,7 @@ BaseChannel::~BaseChannel() {
Deinit();
StopConnectionMonitor();
FlushRtcpMessages(); // Send any outstanding RTCP packets.
- Clear(); // eats any outstanding messages or packets
+ worker_thread_->Clear(this); // eats any outstanding messages or packets
// We must destroy the media channel before the transport channel, otherwise
// the media channel may try to send on the dead transport channel. NULLing
// is not an effective strategy since the sends will come on another thread.
@@ -462,67 +246,51 @@ void BaseChannel::Deinit() {
media_channel_->SetInterface(NULL);
}
-// Can be called from thread other than worker thread
bool BaseChannel::Enable(bool enable) {
- Send(enable ? MSG_ENABLE : MSG_DISABLE);
+ worker_thread_->Invoke<void>(Bind(
+ enable ? &BaseChannel::EnableMedia_w : &BaseChannel::DisableMedia_w,
+ this));
return true;
}
-// Can be called from thread other than worker thread
bool BaseChannel::MuteStream(uint32 ssrc, bool mute) {
- MuteStreamData data(ssrc, mute);
- Send(MSG_MUTESTREAM, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&BaseChannel::MuteStream_w, this, ssrc, mute));
}
bool BaseChannel::IsStreamMuted(uint32 ssrc) {
- SsrcMessageData data(ssrc);
- Send(MSG_ISSTREAMMUTED, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&BaseChannel::IsStreamMuted_w, this, ssrc));
}
bool BaseChannel::AddRecvStream(const StreamParams& sp) {
- StreamMessageData data(sp);
- Send(MSG_ADDRECVSTREAM, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&BaseChannel::AddRecvStream_w, this, sp));
}
bool BaseChannel::RemoveRecvStream(uint32 ssrc) {
- SsrcMessageData data(ssrc);
- Send(MSG_REMOVERECVSTREAM, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&BaseChannel::RemoveRecvStream_w, this, ssrc));
}
bool BaseChannel::AddSendStream(const StreamParams& sp) {
- StreamMessageData data(sp);
- Send(MSG_ADDSENDSTREAM, &data);
- return data.result;
+ return InvokeOnWorker(
+ Bind(&MediaChannel::AddSendStream, media_channel(), sp));
}
bool BaseChannel::RemoveSendStream(uint32 ssrc) {
- SsrcMessageData data(ssrc);
- Send(MSG_REMOVESENDSTREAM, &data);
- return data.result;
+ return InvokeOnWorker(
+ Bind(&MediaChannel::RemoveSendStream, media_channel(), ssrc));
}
bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
- ContentAction action) {
- SetContentData data(content, action);
- Send(MSG_SETLOCALCONTENT, &data);
- return data.result;
+ ContentAction action,
+ std::string* error_desc) {
+ return InvokeOnWorker(Bind(&BaseChannel::SetLocalContent_w,
+ this, content, action, error_desc));
}
bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
- ContentAction action) {
- SetContentData data(content, action);
- Send(MSG_SETREMOTECONTENT, &data);
- return data.result;
-}
-
-bool BaseChannel::SetMaxSendBandwidth(int max_bandwidth) {
- SetBandwidthData data(max_bandwidth);
- Send(MSG_SETMAXSENDBANDWIDTH, &data);
- return data.result;
+ ContentAction action,
+ std::string* error_desc) {
+ return InvokeOnWorker(Bind(&BaseChannel::SetRemoteContent_w,
+ this, content, action, error_desc));
}
void BaseChannel::StartConnectionMonitor(int cms) {
@@ -696,14 +464,40 @@ bool BaseChannel::SendPacket(bool rtcp, talk_base::Buffer* packet,
SignalSendPacketPreCrypto(packet->data(), packet->length(), rtcp);
}
+ talk_base::PacketOptions options(dscp);
// Protect if needed.
if (srtp_filter_.IsActive()) {
bool res;
char* data = packet->data();
int len = static_cast<int>(packet->length());
if (!rtcp) {
- res = srtp_filter_.ProtectRtp(data, len,
- static_cast<int>(packet->capacity()), &len);
+ // If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done
+ // inside libsrtp for a RTP packet. A external HMAC module will be writing
+ // a fake HMAC value. This is ONLY done for a RTP packet.
+ // Socket layer will update rtp sendtime extension header if present in
+ // packet with current time before updating the HMAC.
+#if !defined(ENABLE_EXTERNAL_AUTH)
+ res = srtp_filter_.ProtectRtp(
+ data, len, static_cast<int>(packet->capacity()), &len);
+#else
+ options.packet_time_params.rtp_sendtime_extension_id =
+ rtp_abs_sendtime_extn_id_;
+ res = srtp_filter_.ProtectRtp(
+ data, len, static_cast<int>(packet->capacity()), &len,
+ &options.packet_time_params.srtp_packet_index);
+ // If protection succeeds, let's get auth params from srtp.
+ if (res) {
+ uint8* auth_key = NULL;
+ int key_len;
+ res = srtp_filter_.GetRtpAuthParams(
+ &auth_key, &key_len, &options.packet_time_params.srtp_auth_tag_len);
+ if (res) {
+ options.packet_time_params.srtp_auth_key.resize(key_len);
+ options.packet_time_params.srtp_auth_key.assign(auth_key,
+ auth_key + key_len);
+ }
+ }
+#endif
if (!res) {
int seq_num = -1;
uint32 ssrc = 0;
@@ -745,7 +539,7 @@ bool BaseChannel::SendPacket(bool rtcp, talk_base::Buffer* packet,
}
// Bon voyage.
- int ret = channel->SendPacket(packet->data(), packet->length(), dscp,
+ int ret = channel->SendPacket(packet->data(), packet->length(), options,
(secure() && secure_dtls()) ? PF_SRTP_BYPASS : 0);
if (ret != static_cast<int>(packet->length())) {
if (channel->GetError() == EWOULDBLOCK) {
@@ -765,15 +559,9 @@ bool BaseChannel::WantsPacket(bool rtcp, talk_base::Buffer* packet) {
<< packet->length();
return false;
}
- // If this channel is suppose to handle RTP data, that is determined by
- // checking against ssrc filter. This is necessary to do it here to avoid
- // double decryption.
- if (ssrc_filter_.IsActive() &&
- !ssrc_filter_.DemuxPacket(packet->data(), packet->length(), rtcp)) {
- return false;
- }
- return true;
+ // Bundle filter handles both rtp and rtcp packets.
+ return bundle_filter_.DemuxPacket(packet->data(), packet->length(), rtcp);
}
void BaseChannel::HandlePacket(bool rtcp, talk_base::Buffer* packet,
@@ -858,10 +646,11 @@ void BaseChannel::OnNewLocalDescription(
GetFirstContent(session->local_description());
const MediaContentDescription* content_desc =
GetContentDescription(content_info);
+ std::string error_desc;
if (content_desc && content_info && !content_info->rejected &&
- !SetLocalContent(content_desc, action)) {
+ !SetLocalContent(content_desc, action, &error_desc)) {
+ SetSessionError(session_, BaseSession::ERROR_CONTENT, error_desc);
LOG(LS_ERROR) << "Failure in SetLocalContent with action " << action;
- session->SetError(BaseSession::ERROR_CONTENT);
}
}
@@ -871,10 +660,11 @@ void BaseChannel::OnNewRemoteDescription(
GetFirstContent(session->remote_description());
const MediaContentDescription* content_desc =
GetContentDescription(content_info);
+ std::string error_desc;
if (content_desc && content_info && !content_info->rejected &&
- !SetRemoteContent(content_desc, action)) {
- LOG(LS_ERROR) << "Failure in SetRemoteContent with action " << action;
- session->SetError(BaseSession::ERROR_CONTENT);
+ !SetRemoteContent(content_desc, action, &error_desc)) {
+ SetSessionError(session_, BaseSession::ERROR_CONTENT, error_desc);
+ LOG(LS_ERROR) << "Failure in SetRemoteContent with action " << action;
}
}
@@ -939,19 +729,27 @@ void BaseChannel::ChannelWritable_w() {
// If we're doing DTLS-SRTP, now is the time.
if (!was_ever_writable_ && ShouldSetupDtlsSrtp()) {
if (!SetupDtlsSrtp(false)) {
- LOG(LS_ERROR) << "Couldn't finish DTLS-SRTP on RTP channel";
- SessionErrorMessageData data(BaseSession::ERROR_TRANSPORT);
+ const std::string error_desc =
+ "Couldn't set up DTLS-SRTP on RTP channel.";
// Sent synchronously.
- signaling_thread()->Send(this, MSG_SESSION_ERROR, &data);
+ signaling_thread()->Invoke<void>(Bind(
+ &SetSessionError,
+ session_,
+ BaseSession::ERROR_TRANSPORT,
+ error_desc));
return;
}
if (rtcp_transport_channel_) {
if (!SetupDtlsSrtp(true)) {
- LOG(LS_ERROR) << "Couldn't finish DTLS-SRTP on RTCP channel";
- SessionErrorMessageData data(BaseSession::ERROR_TRANSPORT);
+ const std::string error_desc =
+ "Couldn't set up DTLS-SRTP on RTCP channel";
// Sent synchronously.
- signaling_thread()->Send(this, MSG_SESSION_ERROR, &data);
+ signaling_thread()->Invoke<void>(Bind(
+ &SetSessionError,
+ session_,
+ BaseSession::ERROR_TRANSPORT,
+ error_desc));
return;
}
}
@@ -1086,62 +884,69 @@ void BaseChannel::ChannelNotWritable_w() {
ChangeState();
}
-// Sets the maximum video bandwidth for automatic bandwidth adjustment.
-bool BaseChannel::SetMaxSendBandwidth_w(int max_bandwidth) {
- return media_channel()->SetSendBandwidth(true, max_bandwidth);
-}
-
// |dtls| will be set to true if DTLS is active for transport channel and
// crypto is empty.
bool BaseChannel::CheckSrtpConfig(const std::vector<CryptoParams>& cryptos,
- bool* dtls) {
+ bool* dtls,
+ std::string* error_desc) {
*dtls = transport_channel_->IsDtlsActive();
if (*dtls && !cryptos.empty()) {
- LOG(LS_WARNING) << "Cryptos must be empty when DTLS is active.";
+ SafeSetError("Cryptos must be empty when DTLS is active.",
+ error_desc);
return false;
}
return true;
}
bool BaseChannel::SetSrtp_w(const std::vector<CryptoParams>& cryptos,
- ContentAction action, ContentSource src) {
+ ContentAction action,
+ ContentSource src,
+ std::string* error_desc) {
+ if (action == CA_UPDATE) {
+ // no crypto params.
+ return true;
+ }
bool ret = false;
bool dtls = false;
- ret = CheckSrtpConfig(cryptos, &dtls);
+ ret = CheckSrtpConfig(cryptos, &dtls, error_desc);
+ if (!ret) {
+ return false;
+ }
switch (action) {
case CA_OFFER:
// If DTLS is already active on the channel, we could be renegotiating
// here. We don't update the srtp filter.
- if (ret && !dtls) {
+ if (!dtls) {
ret = srtp_filter_.SetOffer(cryptos, src);
}
break;
case CA_PRANSWER:
// If we're doing DTLS-SRTP, we don't want to update the filter
// with an answer, because we already have SRTP parameters.
- if (ret && !dtls) {
+ if (!dtls) {
ret = srtp_filter_.SetProvisionalAnswer(cryptos, src);
}
break;
case CA_ANSWER:
// If we're doing DTLS-SRTP, we don't want to update the filter
// with an answer, because we already have SRTP parameters.
- if (ret && !dtls) {
+ if (!dtls) {
ret = srtp_filter_.SetAnswer(cryptos, src);
}
break;
- case CA_UPDATE:
- // no crypto params.
- ret = true;
- break;
default:
break;
}
- return ret;
+ if (!ret) {
+ SafeSetError("Failed to setup SRTP filter.", error_desc);
+ return false;
+ }
+ return true;
}
bool BaseChannel::SetRtcpMux_w(bool enable, ContentAction action,
- ContentSource src) {
+ ContentSource src,
+ std::string* error_desc) {
bool ret = false;
switch (action) {
case CA_OFFER:
@@ -1163,17 +968,21 @@ bool BaseChannel::SetRtcpMux_w(bool enable, ContentAction action,
default:
break;
}
+ if (!ret) {
+ SafeSetError("Failed to setup RTCP mux filter.", error_desc);
+ return false;
+ }
// |rtcp_mux_filter_| can be active if |action| is CA_PRANSWER or
// CA_ANSWER, but we only want to tear down the RTCP transport channel if we
// received a final answer.
- if (ret && rtcp_mux_filter_.IsActive()) {
+ if (rtcp_mux_filter_.IsActive()) {
// If the RTP transport is already writable, then so are we.
if (transport_channel_->writable()) {
ChannelWritable_w();
}
}
- return ret;
+ return true;
}
bool BaseChannel::AddRecvStream_w(const StreamParams& sp) {
@@ -1181,27 +990,18 @@ bool BaseChannel::AddRecvStream_w(const StreamParams& sp) {
if (!media_channel()->AddRecvStream(sp))
return false;
- return ssrc_filter_.AddStream(sp);
+ return bundle_filter_.AddStream(sp);
}
bool BaseChannel::RemoveRecvStream_w(uint32 ssrc) {
ASSERT(worker_thread() == talk_base::Thread::Current());
- ssrc_filter_.RemoveStream(ssrc);
+ bundle_filter_.RemoveStream(ssrc);
return media_channel()->RemoveRecvStream(ssrc);
}
-bool BaseChannel::AddSendStream_w(const StreamParams& sp) {
- ASSERT(worker_thread() == talk_base::Thread::Current());
- return media_channel()->AddSendStream(sp);
-}
-
-bool BaseChannel::RemoveSendStream_w(uint32 ssrc) {
- ASSERT(worker_thread() == talk_base::Thread::Current());
- return media_channel()->RemoveSendStream(ssrc);
-}
-
bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
if (!VERIFY(action == CA_OFFER || action == CA_ANSWER ||
action == CA_PRANSWER || action == CA_UPDATE))
return false;
@@ -1218,15 +1018,18 @@ bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
local_streams_.push_back(*it);
LOG(LS_INFO) << "Add send stream ssrc: " << it->first_ssrc();
} else {
- LOG(LS_INFO) << "Failed to add send stream ssrc: "
- << it->first_ssrc();
+ std::ostringstream desc;
+ desc << "Failed to add send stream ssrc: " << it->first_ssrc();
+ SafeSetError(desc.str(), error_desc);
return false;
}
} else if (stream_exist && !it->has_ssrcs()) {
if (!media_channel()->RemoveSendStream(existing_stream.first_ssrc())) {
- LOG(LS_ERROR) << "Failed to remove send stream with ssrc "
- << it->first_ssrc() << ".";
- return false;
+ std::ostringstream desc;
+ desc << "Failed to remove send stream with ssrc "
+ << it->first_ssrc() << ".";
+ SafeSetError(desc.str(), error_desc);
+ return false;
}
RemoveStreamBySsrc(&local_streams_, existing_stream.first_ssrc());
} else {
@@ -1243,8 +1046,10 @@ bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
it != local_streams_.end(); ++it) {
if (!GetStreamBySsrc(streams, it->first_ssrc(), NULL)) {
if (!media_channel()->RemoveSendStream(it->first_ssrc())) {
- LOG(LS_ERROR) << "Failed to remove send stream with ssrc "
- << it->first_ssrc() << ".";
+ std::ostringstream desc;
+ desc << "Failed to remove send stream with ssrc "
+ << it->first_ssrc() << ".";
+ SafeSetError(desc.str(), error_desc);
ret = false;
}
}
@@ -1256,7 +1061,9 @@ bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
if (media_channel()->AddSendStream(*it)) {
LOG(LS_INFO) << "Add send ssrc: " << it->ssrcs[0];
} else {
- LOG(LS_INFO) << "Failed to add send stream ssrc: " << it->first_ssrc();
+ std::ostringstream desc;
+ desc << "Failed to add send stream ssrc: " << it->first_ssrc();
+ SafeSetError(desc.str(), error_desc);
ret = false;
}
}
@@ -1267,7 +1074,8 @@ bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
bool BaseChannel::UpdateRemoteStreams_w(
const std::vector<StreamParams>& streams,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
if (!VERIFY(action == CA_OFFER || action == CA_ANSWER ||
action == CA_PRANSWER || action == CA_UPDATE))
return false;
@@ -1284,15 +1092,18 @@ bool BaseChannel::UpdateRemoteStreams_w(
remote_streams_.push_back(*it);
LOG(LS_INFO) << "Add remote stream ssrc: " << it->first_ssrc();
} else {
- LOG(LS_INFO) << "Failed to add remote stream ssrc: "
- << it->first_ssrc();
+ std::ostringstream desc;
+ desc << "Failed to add remote stream ssrc: " << it->first_ssrc();
+ SafeSetError(desc.str(), error_desc);
return false;
}
} else if (stream_exists && !it->has_ssrcs()) {
if (!RemoveRecvStream_w(existing_stream.first_ssrc())) {
- LOG(LS_ERROR) << "Failed to remove remote stream with ssrc "
- << it->first_ssrc() << ".";
- return false;
+ std::ostringstream desc;
+ desc << "Failed to remove remote stream with ssrc "
+ << it->first_ssrc() << ".";
+ SafeSetError(desc.str(), error_desc);
+ return false;
}
RemoveStreamBySsrc(&remote_streams_, existing_stream.first_ssrc());
} else {
@@ -1312,8 +1123,10 @@ bool BaseChannel::UpdateRemoteStreams_w(
it != remote_streams_.end(); ++it) {
if (!GetStreamBySsrc(streams, it->first_ssrc(), NULL)) {
if (!RemoveRecvStream_w(it->first_ssrc())) {
- LOG(LS_ERROR) << "Failed to remove remote stream with ssrc "
- << it->first_ssrc() << ".";
+ std::ostringstream desc;
+ desc << "Failed to remove remote stream with ssrc "
+ << it->first_ssrc() << ".";
+ SafeSetError(desc.str(), error_desc);
ret = false;
}
}
@@ -1325,8 +1138,9 @@ bool BaseChannel::UpdateRemoteStreams_w(
if (AddRecvStream_w(*it)) {
LOG(LS_INFO) << "Add remote ssrc: " << it->ssrcs[0];
} else {
- LOG(LS_INFO) << "Failed to add remote stream ssrc: "
- << it->first_ssrc();
+ std::ostringstream desc;
+ desc << "Failed to add remote stream ssrc: " << it->first_ssrc();
+ SafeSetError(desc.str(), error_desc);
ret = false;
}
}
@@ -1336,96 +1150,73 @@ bool BaseChannel::UpdateRemoteStreams_w(
}
bool BaseChannel::SetBaseLocalContent_w(const MediaContentDescription* content,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
// Cache secure_required_ for belt and suspenders check on SendPacket
- secure_required_ = content->crypto_required();
- bool ret = UpdateLocalStreams_w(content->streams(), action);
+ secure_required_ = content->crypto_required() != CT_NONE;
+ bool ret = UpdateLocalStreams_w(content->streams(), action, error_desc);
// Set local SRTP parameters (what we will encrypt with).
- ret &= SetSrtp_w(content->cryptos(), action, CS_LOCAL);
+ ret &= SetSrtp_w(content->cryptos(), action, CS_LOCAL, error_desc);
// Set local RTCP mux parameters.
- ret &= SetRtcpMux_w(content->rtcp_mux(), action, CS_LOCAL);
+ ret &= SetRtcpMux_w(content->rtcp_mux(), action, CS_LOCAL, error_desc);
// Set local RTP header extensions.
if (content->rtp_header_extensions_set()) {
- ret &= media_channel()->SetRecvRtpHeaderExtensions(
- content->rtp_header_extensions());
+ if (!media_channel()->SetRecvRtpHeaderExtensions(
+ content->rtp_header_extensions())) {
+ std::ostringstream desc;
+ desc << "Failed to set receive rtp header extensions for "
+ << MediaTypeToString(content->type()) << " content.";
+ SafeSetError(desc.str(), error_desc);
+ ret = false;
+ }
}
set_local_content_direction(content->direction());
return ret;
}
bool BaseChannel::SetBaseRemoteContent_w(const MediaContentDescription* content,
- ContentAction action) {
- bool ret = UpdateRemoteStreams_w(content->streams(), action);
+ ContentAction action,
+ std::string* error_desc) {
+ bool ret = UpdateRemoteStreams_w(content->streams(), action, error_desc);
// Set remote SRTP parameters (what the other side will encrypt with).
- ret &= SetSrtp_w(content->cryptos(), action, CS_REMOTE);
+ ret &= SetSrtp_w(content->cryptos(), action, CS_REMOTE, error_desc);
// Set remote RTCP mux parameters.
- ret &= SetRtcpMux_w(content->rtcp_mux(), action, CS_REMOTE);
+ ret &= SetRtcpMux_w(content->rtcp_mux(), action, CS_REMOTE, error_desc);
// Set remote RTP header extensions.
if (content->rtp_header_extensions_set()) {
- ret &= media_channel()->SetSendRtpHeaderExtensions(
- content->rtp_header_extensions());
+ if (!media_channel()->SetSendRtpHeaderExtensions(
+ content->rtp_header_extensions())) {
+ std::ostringstream desc;
+ desc << "Failed to set send rtp header extensions for "
+ << MediaTypeToString(content->type()) << " content.";
+ SafeSetError(desc.str(), error_desc);
+ ret = false;
+ } else {
+ MaybeCacheRtpAbsSendTimeHeaderExtension(content->rtp_header_extensions());
+ }
}
- if (content->bandwidth() != kAutoBandwidth) {
- ret &= media_channel()->SetSendBandwidth(false, content->bandwidth());
+
+ if (!media_channel()->SetMaxSendBandwidth(content->bandwidth())) {
+ std::ostringstream desc;
+ desc << "Failed to set max send bandwidth for "
+ << MediaTypeToString(content->type()) << " content.";
+ SafeSetError(desc.str(), error_desc);
+ ret = false;
}
set_remote_content_direction(content->direction());
return ret;
}
+void BaseChannel::MaybeCacheRtpAbsSendTimeHeaderExtension(
+ const std::vector<RtpHeaderExtension>& extensions) {
+ const RtpHeaderExtension* send_time_extension =
+ FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
+ rtp_abs_sendtime_extn_id_ =
+ send_time_extension ? send_time_extension->id : -1;
+}
+
void BaseChannel::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
- case MSG_ENABLE:
- EnableMedia_w();
- break;
- case MSG_DISABLE:
- DisableMedia_w();
- break;
- case MSG_MUTESTREAM: {
- MuteStreamData* data = static_cast<MuteStreamData*>(pmsg->pdata);
- data->result = MuteStream_w(data->ssrc, data->mute);
- break;
- }
- case MSG_ISSTREAMMUTED: {
- SsrcMessageData* data = static_cast<SsrcMessageData*>(pmsg->pdata);
- data->result = IsStreamMuted_w(data->ssrc);
- break;
- }
- case MSG_SETLOCALCONTENT: {
- SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
- data->result = SetLocalContent_w(data->content, data->action);
- break;
- }
- case MSG_SETREMOTECONTENT: {
- SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
- data->result = SetRemoteContent_w(data->content, data->action);
- break;
- }
- case MSG_ADDRECVSTREAM: {
- StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
- data->result = AddRecvStream_w(data->sp);
- break;
- }
- case MSG_REMOVERECVSTREAM: {
- SsrcMessageData* data = static_cast<SsrcMessageData*>(pmsg->pdata);
- data->result = RemoveRecvStream_w(data->ssrc);
- break;
- }
- case MSG_ADDSENDSTREAM: {
- StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
- data->result = AddSendStream_w(data->sp);
- break;
- }
- case MSG_REMOVESENDSTREAM: {
- SsrcMessageData* data = static_cast<SsrcMessageData*>(pmsg->pdata);
- data->result = RemoveSendStream_w(data->ssrc);
- break;
- }
- case MSG_SETMAXSENDBANDWIDTH: {
- SetBandwidthData* data = static_cast<SetBandwidthData*>(pmsg->pdata);
- data->result = SetMaxSendBandwidth_w(data->value);
- break;
- }
-
case MSG_RTPPACKET:
case MSG_RTCPPACKET: {
PacketMessageData* data = static_cast<PacketMessageData*>(pmsg->pdata);
@@ -1437,41 +1228,18 @@ void BaseChannel::OnMessage(talk_base::Message *pmsg) {
SignalFirstPacketReceived(this);
break;
}
- case MSG_SESSION_ERROR: {
- SessionErrorMessageData* data = static_cast<SessionErrorMessageData*>
- (pmsg->pdata);
- session_->SetError(data->error_);
- break;
- }
}
}
-void BaseChannel::Send(uint32 id, talk_base::MessageData *pdata) {
- worker_thread_->Send(this, id, pdata);
-}
-
-void BaseChannel::Post(uint32 id, talk_base::MessageData *pdata) {
- worker_thread_->Post(this, id, pdata);
-}
-
-void BaseChannel::PostDelayed(int cmsDelay, uint32 id,
- talk_base::MessageData *pdata) {
- worker_thread_->PostDelayed(cmsDelay, this, id, pdata);
-}
-
-void BaseChannel::Clear(uint32 id, talk_base::MessageList* removed) {
- worker_thread_->Clear(this, id, removed);
-}
-
void BaseChannel::FlushRtcpMessages() {
// Flush all remaining RTCP messages. This should only be called in
// destructor.
ASSERT(talk_base::Thread::Current() == worker_thread_);
talk_base::MessageList rtcp_messages;
- Clear(MSG_RTCPPACKET, &rtcp_messages);
+ worker_thread_->Clear(this, MSG_RTCPPACKET, &rtcp_messages);
for (talk_base::MessageList::iterator it = rtcp_messages.begin();
it != rtcp_messages.end(); ++it) {
- Send(MSG_RTCPPACKET, it->pdata);
+ worker_thread_->Send(this, MSG_RTCPPACKET, it->pdata);
}
}
@@ -1510,21 +1278,17 @@ bool VoiceChannel::Init() {
}
bool VoiceChannel::SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer) {
- AudioRenderMessageData data(ssrc, renderer, false);
- Send(MSG_SETRENDERER, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::SetRemoteRenderer,
+ media_channel(), ssrc, renderer));
}
bool VoiceChannel::SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer) {
- AudioRenderMessageData data(ssrc, renderer, true);
- Send(MSG_SETRENDERER, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::SetLocalRenderer,
+ media_channel(), ssrc, renderer));
}
bool VoiceChannel::SetRingbackTone(const void* buf, int len) {
- SetRingbackToneMessageData data(buf, len);
- Send(MSG_SETRINGBACKTONE, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceChannel::SetRingbackTone_w, this, buf, len));
}
// TODO(juberti): Handle early media the right way. We should get an explicit
@@ -1535,17 +1299,17 @@ bool VoiceChannel::SetRingbackTone(const void* buf, int len) {
void VoiceChannel::SetEarlyMedia(bool enable) {
if (enable) {
// Start the early media timeout
- PostDelayed(kEarlyMediaTimeout, MSG_EARLYMEDIATIMEOUT);
+ worker_thread()->PostDelayed(kEarlyMediaTimeout, this,
+ MSG_EARLYMEDIATIMEOUT);
} else {
// Stop the timeout if currently going.
- Clear(MSG_EARLYMEDIATIMEOUT);
+ worker_thread()->Clear(this, MSG_EARLYMEDIATIMEOUT);
}
}
bool VoiceChannel::PlayRingbackTone(uint32 ssrc, bool play, bool loop) {
- PlayRingbackToneMessageData data(ssrc, play, loop);
- Send(MSG_PLAYRINGBACKTONE, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceChannel::PlayRingbackTone_w,
+ this, ssrc, play, loop));
}
bool VoiceChannel::PressDTMF(int digit, bool playout) {
@@ -1558,27 +1322,24 @@ bool VoiceChannel::PressDTMF(int digit, bool playout) {
}
bool VoiceChannel::CanInsertDtmf() {
- BoolMessageData data(false);
- Send(MSG_CANINSERTDTMF, &data);
- return data.data();
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::CanInsertDtmf,
+ media_channel()));
}
bool VoiceChannel::InsertDtmf(uint32 ssrc, int event_code, int duration,
int flags) {
- DtmfMessageData data(ssrc, event_code, duration, flags);
- Send(MSG_INSERTDTMF, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceChannel::InsertDtmf_w, this,
+ ssrc, event_code, duration, flags));
}
bool VoiceChannel::SetOutputScaling(uint32 ssrc, double left, double right) {
- ScaleVolumeMessageData data(ssrc, left, right);
- Send(MSG_SCALEVOLUME, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::SetOutputScaling,
+ media_channel(), ssrc, left, right));
}
+
bool VoiceChannel::GetStats(VoiceMediaInfo* stats) {
- VoiceStatsMessageData data(stats);
- Send(MSG_GETSTATS, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::GetStats,
+ media_channel(), stats));
}
void VoiceChannel::StartMediaMonitor(int cms) {
@@ -1686,25 +1447,36 @@ const ContentInfo* VoiceChannel::GetFirstContent(
}
bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
ASSERT(worker_thread() == talk_base::Thread::Current());
LOG(LS_INFO) << "Setting local voice description";
const AudioContentDescription* audio =
static_cast<const AudioContentDescription*>(content);
ASSERT(audio != NULL);
- if (!audio) return false;
+ if (!audio) {
+ SafeSetError("Can't find audio content in local description.", error_desc);
+ return false;
+ }
- bool ret = SetBaseLocalContent_w(content, action);
+ bool ret = SetBaseLocalContent_w(content, action, error_desc);
// Set local audio codecs (what we want to receive).
// TODO(whyuan): Change action != CA_UPDATE to !audio->partial() when partial
// is set properly.
if (action != CA_UPDATE || audio->has_codecs()) {
- ret &= media_channel()->SetRecvCodecs(audio->codecs());
+ if (!media_channel()->SetRecvCodecs(audio->codecs())) {
+ SafeSetError("Failed to set audio receive codecs.", error_desc);
+ ret = false;
+ }
}
// If everything worked, see if we can start receiving.
if (ret) {
+ std::vector<AudioCodec>::const_iterator it = audio->codecs().begin();
+ for (; it != audio->codecs().end(); ++it) {
+ bundle_filter()->AddPayloadType(it->id);
+ }
ChangeState();
} else {
LOG(LS_WARNING) << "Failed to set local voice description";
@@ -1713,22 +1485,29 @@ bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
}
bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
ASSERT(worker_thread() == talk_base::Thread::Current());
LOG(LS_INFO) << "Setting remote voice description";
const AudioContentDescription* audio =
static_cast<const AudioContentDescription*>(content);
ASSERT(audio != NULL);
- if (!audio) return false;
+ if (!audio) {
+ SafeSetError("Can't find audio content in remote description.", error_desc);
+ return false;
+ }
bool ret = true;
// Set remote video codecs (what the other side wants to receive).
if (action != CA_UPDATE || audio->has_codecs()) {
- ret &= media_channel()->SetSendCodecs(audio->codecs());
+ if (!media_channel()->SetSendCodecs(audio->codecs())) {
+ SafeSetError("Failed to set audio send codecs.", error_desc);
+ ret = false;
+ }
}
- ret &= SetBaseRemoteContent_w(content, action);
+ ret &= SetBaseRemoteContent_w(content, action, error_desc);
if (action != CA_UPDATE) {
// Tweak our audio processing settings, if needed.
@@ -1781,10 +1560,6 @@ void VoiceChannel::HandleEarlyMediaTimeout() {
}
}
-bool VoiceChannel::CanInsertDtmf_w() {
- return media_channel()->CanInsertDtmf();
-}
-
bool VoiceChannel::InsertDtmf_w(uint32 ssrc, int event, int duration,
int flags) {
if (!enabled()) {
@@ -1794,74 +1569,16 @@ bool VoiceChannel::InsertDtmf_w(uint32 ssrc, int event, int duration,
return media_channel()->InsertDtmf(ssrc, event, duration, flags);
}
-bool VoiceChannel::SetOutputScaling_w(uint32 ssrc, double left, double right) {
- return media_channel()->SetOutputScaling(ssrc, left, right);
-}
-
-bool VoiceChannel::GetStats_w(VoiceMediaInfo* stats) {
- return media_channel()->GetStats(stats);
-}
-
bool VoiceChannel::SetChannelOptions(const AudioOptions& options) {
- AudioOptionsMessageData data(options);
- Send(MSG_SETCHANNELOPTIONS, &data);
- return data.result;
-}
-
-bool VoiceChannel::SetChannelOptions_w(const AudioOptions& options) {
- return media_channel()->SetOptions(options);
-}
-
-bool VoiceChannel::SetRenderer_w(uint32 ssrc, AudioRenderer* renderer,
- bool is_local) {
- if (is_local)
- return media_channel()->SetLocalRenderer(ssrc, renderer);
-
- return media_channel()->SetRemoteRenderer(ssrc, renderer);
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::SetOptions,
+ media_channel(), options));
}
void VoiceChannel::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
- case MSG_SETRINGBACKTONE: {
- SetRingbackToneMessageData* data =
- static_cast<SetRingbackToneMessageData*>(pmsg->pdata);
- data->result = SetRingbackTone_w(data->buf, data->len);
- break;
- }
- case MSG_PLAYRINGBACKTONE: {
- PlayRingbackToneMessageData* data =
- static_cast<PlayRingbackToneMessageData*>(pmsg->pdata);
- data->result = PlayRingbackTone_w(data->ssrc, data->play, data->loop);
- break;
- }
case MSG_EARLYMEDIATIMEOUT:
HandleEarlyMediaTimeout();
break;
- case MSG_CANINSERTDTMF: {
- BoolMessageData* data =
- static_cast<BoolMessageData*>(pmsg->pdata);
- data->data() = CanInsertDtmf_w();
- break;
- }
- case MSG_INSERTDTMF: {
- DtmfMessageData* data =
- static_cast<DtmfMessageData*>(pmsg->pdata);
- data->result = InsertDtmf_w(data->ssrc, data->event, data->duration,
- data->flags);
- break;
- }
- case MSG_SCALEVOLUME: {
- ScaleVolumeMessageData* data =
- static_cast<ScaleVolumeMessageData*>(pmsg->pdata);
- data->result = SetOutputScaling_w(data->ssrc, data->left, data->right);
- break;
- }
- case MSG_GETSTATS: {
- VoiceStatsMessageData* data =
- static_cast<VoiceStatsMessageData*>(pmsg->pdata);
- data->result = GetStats_w(data->stats);
- break;
- }
case MSG_CHANNEL_ERROR: {
VoiceChannelErrorMessageData* data =
static_cast<VoiceChannelErrorMessageData*>(pmsg->pdata);
@@ -1869,18 +1586,6 @@ void VoiceChannel::OnMessage(talk_base::Message *pmsg) {
delete data;
break;
}
- case MSG_SETCHANNELOPTIONS: {
- AudioOptionsMessageData* data =
- static_cast<AudioOptionsMessageData*>(pmsg->pdata);
- data->result = SetChannelOptions_w(data->options);
- break;
- }
- case MSG_SETRENDERER: {
- AudioRenderMessageData* data =
- static_cast<AudioRenderMessageData*>(pmsg->pdata);
- data->result = SetRenderer_w(data->ssrc, data->renderer, data->is_local);
- break;
- }
default:
BaseChannel::OnMessage(pmsg);
break;
@@ -1994,68 +1699,65 @@ VideoChannel::~VideoChannel() {
}
bool VideoChannel::SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
- VideoRenderMessageData data(ssrc, renderer);
- Send(MSG_SETRENDERER, &data);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoMediaChannel::SetRenderer, media_channel(), ssrc, renderer));
return true;
}
bool VideoChannel::ApplyViewRequest(const ViewRequest& request) {
- ViewRequestMessageData data(request);
- Send(MSG_HANDLEVIEWREQUEST, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VideoChannel::ApplyViewRequest_w, this, request));
}
VideoCapturer* VideoChannel::AddScreencast(
uint32 ssrc, const ScreencastId& id) {
- AddScreencastMessageData data(ssrc, id);
- Send(MSG_ADDSCREENCAST, &data);
- return data.result;
+ return worker_thread()->Invoke<VideoCapturer*>(Bind(
+ &VideoChannel::AddScreencast_w, this, ssrc, id));
}
bool VideoChannel::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
- SetCapturerMessageData data(ssrc, capturer);
- Send(MSG_SETCAPTURER, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VideoMediaChannel::SetCapturer,
+ media_channel(), ssrc, capturer));
}
bool VideoChannel::RemoveScreencast(uint32 ssrc) {
- RemoveScreencastMessageData data(ssrc);
- Send(MSG_REMOVESCREENCAST, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VideoChannel::RemoveScreencast_w, this, ssrc));
}
bool VideoChannel::IsScreencasting() {
- IsScreencastingMessageData data;
- Send(MSG_ISSCREENCASTING, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VideoChannel::IsScreencasting_w, this));
}
int VideoChannel::GetScreencastFps(uint32 ssrc) {
- ScreencastDetailsMessageData data(ssrc);
- Send(MSG_GETSCREENCASTDETAILS, &data);
+ ScreencastDetailsData data(ssrc);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoChannel::GetScreencastDetails_w, this, &data));
return data.fps;
}
int VideoChannel::GetScreencastMaxPixels(uint32 ssrc) {
- ScreencastDetailsMessageData data(ssrc);
- Send(MSG_GETSCREENCASTDETAILS, &data);
+ ScreencastDetailsData data(ssrc);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoChannel::GetScreencastDetails_w, this, &data));
return data.screencast_max_pixels;
}
bool VideoChannel::SendIntraFrame() {
- Send(MSG_SENDINTRAFRAME);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoMediaChannel::SendIntraFrame, media_channel()));
return true;
}
bool VideoChannel::RequestIntraFrame() {
- Send(MSG_REQUESTINTRAFRAME);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoMediaChannel::RequestIntraFrame, media_channel()));
return true;
}
void VideoChannel::SetScreenCaptureFactory(
ScreenCapturerFactory* screencapture_factory) {
- SetScreenCaptureFactoryMessageData data(screencapture_factory);
- Send(MSG_SETSCREENCASTFACTORY, &data);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoChannel::SetScreenCaptureFactory_w,
+ this, screencapture_factory));
}
void VideoChannel::ChangeState() {
@@ -2078,10 +1780,10 @@ void VideoChannel::ChangeState() {
LOG(LS_INFO) << "Changing video state, recv=" << recv << " send=" << send;
}
-bool VideoChannel::GetStats(VideoMediaInfo* stats) {
- VideoStatsMessageData data(stats);
- Send(MSG_GETSTATS, &data);
- return data.result;
+bool VideoChannel::GetStats(
+ const StatsOptions& options, VideoMediaInfo* stats) {
+ return InvokeOnWorker(Bind(&VideoMediaChannel::GetStats,
+ media_channel(), options, stats));
}
void VideoChannel::StartMediaMonitor(int cms) {
@@ -2105,19 +1807,26 @@ const ContentInfo* VideoChannel::GetFirstContent(
}
bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
ASSERT(worker_thread() == talk_base::Thread::Current());
LOG(LS_INFO) << "Setting local video description";
const VideoContentDescription* video =
static_cast<const VideoContentDescription*>(content);
ASSERT(video != NULL);
- if (!video) return false;
+ if (!video) {
+ SafeSetError("Can't find video content in local description.", error_desc);
+ return false;
+ }
- bool ret = SetBaseLocalContent_w(content, action);
+ bool ret = SetBaseLocalContent_w(content, action, error_desc);
// Set local video codecs (what we want to receive).
if (action != CA_UPDATE || video->has_codecs()) {
- ret &= media_channel()->SetRecvCodecs(video->codecs());
+ if (!media_channel()->SetRecvCodecs(video->codecs())) {
+ SafeSetError("Failed to set video receive codecs.", error_desc);
+ ret = false;
+ }
}
if (action != CA_UPDATE) {
@@ -2133,6 +1842,10 @@ bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
// If everything worked, see if we can start receiving.
if (ret) {
+ std::vector<VideoCodec>::const_iterator it = video->codecs().begin();
+ for (; it != video->codecs().end(); ++it) {
+ bundle_filter()->AddPayloadType(it->id);
+ }
ChangeState();
} else {
LOG(LS_WARNING) << "Failed to set local video description";
@@ -2141,22 +1854,29 @@ bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
}
bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
ASSERT(worker_thread() == talk_base::Thread::Current());
LOG(LS_INFO) << "Setting remote video description";
const VideoContentDescription* video =
static_cast<const VideoContentDescription*>(content);
ASSERT(video != NULL);
- if (!video) return false;
+ if (!video) {
+ SafeSetError("Can't find video content in remote description.", error_desc);
+ return false;
+ }
bool ret = true;
// Set remote video codecs (what the other side wants to receive).
if (action != CA_UPDATE || video->has_codecs()) {
- ret &= media_channel()->SetSendCodecs(video->codecs());
+ if (!media_channel()->SetSendCodecs(video->codecs())) {
+ SafeSetError("Failed to set video send codecs.", error_desc);
+ ret = false;
+ }
}
- ret &= SetBaseRemoteContent_w(content, action);
+ ret &= SetBaseRemoteContent_w(content, action, error_desc);
if (action != CA_UPDATE) {
// Tweak our video processing settings, if needed.
@@ -2219,10 +1939,6 @@ bool VideoChannel::ApplyViewRequest_w(const ViewRequest& request) {
return ret;
}
-void VideoChannel::SetRenderer_w(uint32 ssrc, VideoRenderer* renderer) {
- media_channel()->SetRenderer(ssrc, renderer);
-}
-
VideoCapturer* VideoChannel::AddScreencast_w(
uint32 ssrc, const ScreencastId& id) {
if (screencast_capturers_.find(ssrc) != screencast_capturers_.end()) {
@@ -2239,10 +1955,6 @@ VideoCapturer* VideoChannel::AddScreencast_w(
return screen_capturer;
}
-bool VideoChannel::SetCapturer_w(uint32 ssrc, VideoCapturer* capturer) {
- return media_channel()->SetCapturer(ssrc, capturer);
-}
-
bool VideoChannel::RemoveScreencast_w(uint32 ssrc) {
ScreencastMap::iterator iter = screencast_capturers_.find(ssrc);
if (iter == screencast_capturers_.end()) {
@@ -2258,8 +1970,8 @@ bool VideoChannel::IsScreencasting_w() const {
return !screencast_capturers_.empty();
}
-void VideoChannel::ScreencastDetails_w(
- ScreencastDetailsMessageData* data) const {
+void VideoChannel::GetScreencastDetails_w(
+ ScreencastDetailsData* data) const {
ScreencastMap::const_iterator iter = screencast_capturers_.find(data->ssrc);
if (iter == screencast_capturers_.end()) {
return;
@@ -2279,10 +1991,6 @@ void VideoChannel::SetScreenCaptureFactory_w(
}
}
-bool VideoChannel::GetStats_w(VideoMediaInfo* stats) {
- return media_channel()->GetStats(stats);
-}
-
void VideoChannel::OnScreencastWindowEvent_s(uint32 ssrc,
talk_base::WindowEvent we) {
ASSERT(signaling_thread() == talk_base::Thread::Current());
@@ -2290,41 +1998,12 @@ void VideoChannel::OnScreencastWindowEvent_s(uint32 ssrc,
}
bool VideoChannel::SetChannelOptions(const VideoOptions &options) {
- VideoOptionsMessageData data(options);
- Send(MSG_SETCHANNELOPTIONS, &data);
- return data.result;
-}
-
-bool VideoChannel::SetChannelOptions_w(const VideoOptions &options) {
- return media_channel()->SetOptions(options);
+ return InvokeOnWorker(Bind(&VideoMediaChannel::SetOptions,
+ media_channel(), options));
}
void VideoChannel::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
- case MSG_SETRENDERER: {
- const VideoRenderMessageData* data =
- static_cast<VideoRenderMessageData*>(pmsg->pdata);
- SetRenderer_w(data->ssrc, data->renderer);
- break;
- }
- case MSG_ADDSCREENCAST: {
- AddScreencastMessageData* data =
- static_cast<AddScreencastMessageData*>(pmsg->pdata);
- data->result = AddScreencast_w(data->ssrc, data->window_id);
- break;
- }
- case MSG_SETCAPTURER: {
- SetCapturerMessageData* data =
- static_cast<SetCapturerMessageData*>(pmsg->pdata);
- data->result = SetCapturer_w(data->ssrc, data->capturer);
- break;
- }
- case MSG_REMOVESCREENCAST: {
- RemoveScreencastMessageData* data =
- static_cast<RemoveScreencastMessageData*>(pmsg->pdata);
- data->result = RemoveScreencast_w(data->ssrc);
- break;
- }
case MSG_SCREENCASTWINDOWEVENT: {
const ScreencastEventMessageData* data =
static_cast<ScreencastEventMessageData*>(pmsg->pdata);
@@ -2332,32 +2011,6 @@ void VideoChannel::OnMessage(talk_base::Message *pmsg) {
delete data;
break;
}
- case MSG_ISSCREENCASTING: {
- IsScreencastingMessageData* data =
- static_cast<IsScreencastingMessageData*>(pmsg->pdata);
- data->result = IsScreencasting_w();
- break;
- }
- case MSG_GETSCREENCASTDETAILS: {
- ScreencastDetailsMessageData* data =
- static_cast<ScreencastDetailsMessageData*>(pmsg->pdata);
- ScreencastDetails_w(data);
- break;
- }
- case MSG_SENDINTRAFRAME: {
- SendIntraFrame_w();
- break;
- }
- case MSG_REQUESTINTRAFRAME: {
- RequestIntraFrame_w();
- break;
- }
- case MSG_SETCHANNELOPTIONS: {
- VideoOptionsMessageData* data =
- static_cast<VideoOptionsMessageData*>(pmsg->pdata);
- data->result = SetChannelOptions_w(data->options);
- break;
- }
case MSG_CHANNEL_ERROR: {
const VideoChannelErrorMessageData* data =
static_cast<VideoChannelErrorMessageData*>(pmsg->pdata);
@@ -2365,24 +2018,6 @@ void VideoChannel::OnMessage(talk_base::Message *pmsg) {
delete data;
break;
}
- case MSG_HANDLEVIEWREQUEST: {
- ViewRequestMessageData* data =
- static_cast<ViewRequestMessageData*>(pmsg->pdata);
- data->result = ApplyViewRequest_w(data->request);
- break;
- }
- case MSG_SETSCREENCASTFACTORY: {
- SetScreenCaptureFactoryMessageData* data =
- static_cast<SetScreenCaptureFactoryMessageData*>(pmsg->pdata);
- SetScreenCaptureFactory_w(data->screencapture_factory);
- break;
- }
- case MSG_GETSTATS: {
- VideoStatsMessageData* data =
- static_cast<VideoStatsMessageData*>(pmsg->pdata);
- data->result = GetStats_w(data->stats);
- break;
- }
default:
BaseChannel::OnMessage(pmsg);
break;
@@ -2428,9 +2063,8 @@ void VideoChannel::OnStateChange(VideoCapturer* capturer, CaptureState ev) {
if (!GetLocalSsrc(capturer, &ssrc)) {
return;
}
- ScreencastEventMessageData* pdata =
- new ScreencastEventMessageData(ssrc, we);
- signaling_thread()->Post(this, MSG_SCREENCASTWINDOWEVENT, pdata);
+
+ OnScreencastWindowEvent(ssrc, we);
}
bool VideoChannel::GetLocalSsrc(const VideoCapturer* capturer, uint32* ssrc) {
@@ -2515,8 +2149,8 @@ bool DataChannel::Init() {
this, &DataChannel::OnDataChannelError);
media_channel()->SignalReadyToSend.connect(
this, &DataChannel::OnDataChannelReadyToSend);
- media_channel()->SignalNewStreamReceived.connect(
- this, &DataChannel::OnDataChannelNewStreamReceived);
+ media_channel()->SignalStreamClosedRemotely.connect(
+ this, &DataChannel::OnStreamClosedRemotely);
srtp_filter()->SignalSrtpError.connect(
this, &DataChannel::OnSrtpError);
return true;
@@ -2525,9 +2159,8 @@ bool DataChannel::Init() {
bool DataChannel::SendData(const SendDataParams& params,
const talk_base::Buffer& payload,
SendDataResult* result) {
- SendDataMessageData message_data(params, &payload, result);
- Send(MSG_SENDDATA, &message_data);
- return message_data.succeeded;
+ return InvokeOnWorker(Bind(&DataMediaChannel::SendData,
+ media_channel(), params, payload, result));
}
const ContentInfo* DataChannel::GetFirstContent(
@@ -2556,13 +2189,8 @@ bool DataChannel::WantsPacket(bool rtcp, talk_base::Buffer* packet) {
return false;
}
-// Sets the maximum bandwidth. Anything over this will be dropped.
-bool DataChannel::SetMaxSendBandwidth_w(int max_bps) {
- LOG(LS_INFO) << "DataChannel: Setting max bandwidth to " << max_bps;
- return media_channel()->SetSendBandwidth(false, max_bps);
-}
-
-bool DataChannel::SetDataChannelType(DataChannelType new_data_channel_type) {
+bool DataChannel::SetDataChannelType(DataChannelType new_data_channel_type,
+ std::string* error_desc) {
// It hasn't been set before, so set it now.
if (data_channel_type_ == DCT_NONE) {
data_channel_type_ = new_data_channel_type;
@@ -2571,9 +2199,11 @@ bool DataChannel::SetDataChannelType(DataChannelType new_data_channel_type) {
// It's been set before, but doesn't match. That's bad.
if (data_channel_type_ != new_data_channel_type) {
- LOG(LS_WARNING) << "Data channel type mismatch."
- << " Expected " << data_channel_type_
- << " Got " << new_data_channel_type;
+ std::ostringstream desc;
+ desc << "Data channel type mismatch."
+ << " Expected " << data_channel_type_
+ << " Got " << new_data_channel_type;
+ SafeSetError(desc.str(), error_desc);
return false;
}
@@ -2582,47 +2212,61 @@ bool DataChannel::SetDataChannelType(DataChannelType new_data_channel_type) {
}
bool DataChannel::SetDataChannelTypeFromContent(
- const DataContentDescription* content) {
+ const DataContentDescription* content,
+ std::string* error_desc) {
bool is_sctp = ((content->protocol() == kMediaProtocolSctp) ||
(content->protocol() == kMediaProtocolDtlsSctp));
DataChannelType data_channel_type = is_sctp ? DCT_SCTP : DCT_RTP;
- return SetDataChannelType(data_channel_type);
+ return SetDataChannelType(data_channel_type, error_desc);
}
bool DataChannel::SetLocalContent_w(const MediaContentDescription* content,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
ASSERT(worker_thread() == talk_base::Thread::Current());
LOG(LS_INFO) << "Setting local data description";
const DataContentDescription* data =
static_cast<const DataContentDescription*>(content);
ASSERT(data != NULL);
- if (!data) return false;
+ if (!data) {
+ SafeSetError("Can't find data content in local description.", error_desc);
+ return false;
+ }
bool ret = false;
- if (!SetDataChannelTypeFromContent(data)) {
+ if (!SetDataChannelTypeFromContent(data, error_desc)) {
return false;
}
if (data_channel_type_ == DCT_SCTP) {
// SCTP data channels don't need the rest of the stuff.
- ret = UpdateLocalStreams_w(data->streams(), action);
+ ret = UpdateLocalStreams_w(data->streams(), action, error_desc);
if (ret) {
set_local_content_direction(content->direction());
// As in SetRemoteContent_w, make sure we set the local SCTP port
// number as specified in our DataContentDescription.
- ret = media_channel()->SetRecvCodecs(data->codecs());
+ if (!media_channel()->SetRecvCodecs(data->codecs())) {
+ SafeSetError("Failed to set data receive codecs.", error_desc);
+ ret = false;
+ }
}
} else {
- ret = SetBaseLocalContent_w(content, action);
-
+ ret = SetBaseLocalContent_w(content, action, error_desc);
if (action != CA_UPDATE || data->has_codecs()) {
- ret &= media_channel()->SetRecvCodecs(data->codecs());
+ if (!media_channel()->SetRecvCodecs(data->codecs())) {
+ SafeSetError("Failed to set data receive codecs.", error_desc);
+ ret = false;
+ }
}
}
// If everything worked, see if we can start receiving.
if (ret) {
+ std::vector<DataCodec>::const_iterator it = data->codecs().begin();
+ for (; it != data->codecs().end(); ++it) {
+ bundle_filter()->AddPayloadType(it->id);
+ }
ChangeState();
} else {
LOG(LS_WARNING) << "Failed to set local data description";
@@ -2631,28 +2275,35 @@ bool DataChannel::SetLocalContent_w(const MediaContentDescription* content,
}
bool DataChannel::SetRemoteContent_w(const MediaContentDescription* content,
- ContentAction action) {
+ ContentAction action,
+ std::string* error_desc) {
ASSERT(worker_thread() == talk_base::Thread::Current());
const DataContentDescription* data =
static_cast<const DataContentDescription*>(content);
ASSERT(data != NULL);
- if (!data) return false;
+ if (!data) {
+ SafeSetError("Can't find data content in remote description.", error_desc);
+ return false;
+ }
bool ret = true;
- if (!SetDataChannelTypeFromContent(data)) {
+ if (!SetDataChannelTypeFromContent(data, error_desc)) {
return false;
}
if (data_channel_type_ == DCT_SCTP) {
LOG(LS_INFO) << "Setting SCTP remote data description";
// SCTP data channels don't need the rest of the stuff.
- ret = UpdateRemoteStreams_w(content->streams(), action);
+ ret = UpdateRemoteStreams_w(content->streams(), action, error_desc);
if (ret) {
set_remote_content_direction(content->direction());
// We send the SCTP port number (not to be confused with the underlying
// UDP port number) as a codec parameter. Make sure it gets there.
- ret = media_channel()->SetSendCodecs(data->codecs());
+ if (!media_channel()->SetSendCodecs(data->codecs())) {
+ SafeSetError("Failed to set data send codecs.", error_desc);
+ ret = false;
+ }
}
} else {
// If the remote data doesn't have codecs and isn't an update, it
@@ -2664,17 +2315,24 @@ bool DataChannel::SetRemoteContent_w(const MediaContentDescription* content,
// Set remote video codecs (what the other side wants to receive).
if (action != CA_UPDATE || data->has_codecs()) {
- ret &= media_channel()->SetSendCodecs(data->codecs());
+ if (!media_channel()->SetSendCodecs(data->codecs())) {
+ SafeSetError("Failed to set data send codecs.", error_desc);
+ ret = false;
+ }
}
if (ret) {
- ret &= SetBaseRemoteContent_w(content, action);
+ ret &= SetBaseRemoteContent_w(content, action, error_desc);
}
if (action != CA_UPDATE) {
int bandwidth_bps = data->bandwidth();
- bool auto_bandwidth = (bandwidth_bps == kAutoBandwidth);
- ret &= media_channel()->SetSendBandwidth(auto_bandwidth, bandwidth_bps);
+ if (!media_channel()->SetMaxSendBandwidth(bandwidth_bps)) {
+ std::ostringstream desc;
+ desc << "Failed to set max send bandwidth for data content.";
+ SafeSetError(desc.str(), error_desc);
+ ret = false;
+ }
}
}
@@ -2702,9 +2360,8 @@ void DataChannel::ChangeState() {
LOG(LS_ERROR) << "Failed to SetSend on data channel";
}
- // Post to trigger SignalReadyToSendData.
- signaling_thread()->Post(this, MSG_READYTOSENDDATA,
- new DataChannelReadyToSendMessageData(send));
+ // Trigger SignalReadyToSendData asynchronously.
+ OnDataChannelReadyToSend(send);
LOG(LS_INFO) << "Changing data state, recv=" << recv << " send=" << send;
}
@@ -2719,13 +2376,6 @@ void DataChannel::OnMessage(talk_base::Message *pmsg) {
delete data;
break;
}
- case MSG_SENDDATA: {
- SendDataMessageData* msg =
- static_cast<SendDataMessageData*>(pmsg->pdata);
- msg->succeeded = media_channel()->SendData(
- msg->params, *(msg->payload), msg->result);
- break;
- }
case MSG_DATARECEIVED: {
DataReceivedMessageData* data =
static_cast<DataReceivedMessageData*>(pmsg->pdata);
@@ -2740,10 +2390,10 @@ void DataChannel::OnMessage(talk_base::Message *pmsg) {
delete data;
break;
}
- case MSG_NEWSTREAMRECEIVED: {
- DataChannelNewStreamReceivedMessageData* data =
- static_cast<DataChannelNewStreamReceivedMessageData*>(pmsg->pdata);
- SignalNewStreamReceived(data->label, data->init);
+ case MSG_STREAMCLOSEDREMOTELY: {
+ talk_base::TypedMessageData<uint32>* data =
+ static_cast<talk_base::TypedMessageData<uint32>*>(pmsg->pdata);
+ SignalStreamClosedRemotely(data->data());
delete data;
break;
}
@@ -2802,14 +2452,6 @@ void DataChannel::OnDataChannelReadyToSend(bool writable) {
new DataChannelReadyToSendMessageData(writable));
}
-void DataChannel::OnDataChannelNewStreamReceived(
- const std::string& label, const webrtc::DataChannelInit& init) {
- signaling_thread()->Post(
- this,
- MSG_NEWSTREAMRECEIVED,
- new DataChannelNewStreamReceivedMessageData(label, init));
-}
-
void DataChannel::OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode,
SrtpFilter::Error error) {
switch (error) {
@@ -2841,4 +2483,10 @@ bool DataChannel::ShouldSetupDtlsSrtp() const {
return (data_channel_type_ == DCT_RTP);
}
+void DataChannel::OnStreamClosedRemotely(uint32 sid) {
+ talk_base::TypedMessageData<uint32>* message =
+ new talk_base::TypedMessageData<uint32>(sid);
+ signaling_thread()->Post(this, MSG_STREAMCLOSEDREMOTELY, message);
+}
+
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/session/media/channel.h b/chromium/third_party/libjingle/source/talk/session/media/channel.h
index d297ee4b8fd..d48a64e10db 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/channel.h
+++ b/chromium/third_party/libjingle/source/talk/session/media/channel.h
@@ -31,7 +31,6 @@
#include <string>
#include <vector>
-#include "talk/app/webrtc/datachannelinterface.h"
#include "talk/base/asyncudpsocket.h"
#include "talk/base/criticalsection.h"
#include "talk/base/network.h"
@@ -45,11 +44,11 @@
#include "talk/p2p/base/session.h"
#include "talk/p2p/client/socketmonitor.h"
#include "talk/session/media/audiomonitor.h"
+#include "talk/session/media/bundlefilter.h"
#include "talk/session/media/mediamonitor.h"
#include "talk/session/media/mediasession.h"
#include "talk/session/media/rtcpmuxfilter.h"
#include "talk/session/media/srtpfilter.h"
-#include "talk/session/media/ssrcmuxfilter.h"
namespace cricket {
@@ -112,10 +111,11 @@ class BaseChannel
// Channel control
bool SetLocalContent(const MediaContentDescription* content,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
bool SetRemoteContent(const MediaContentDescription* content,
- ContentAction action);
- bool SetMaxSendBandwidth(int max_bandwidth);
+ ContentAction action,
+ std::string* error_desc);
bool Enable(bool enable);
// Mute sending media on the stream with SSRC |ssrc|
@@ -213,7 +213,7 @@ class BaseChannel
}
}
- SsrcMuxFilter* ssrc_filter() { return &ssrc_filter_; }
+ BundleFilter* bundle_filter() { return &bundle_filter_; }
const std::vector<StreamParams>& local_streams() const {
return local_streams_;
@@ -248,12 +248,6 @@ class BaseChannel
SrtpFilter* srtp_filter() { return &srtp_filter_; }
bool rtcp() const { return rtcp_; }
- void Send(uint32 id, talk_base::MessageData* pdata = NULL);
- void Post(uint32 id, talk_base::MessageData* pdata = NULL);
- void PostDelayed(int cmsDelay, uint32 id = 0,
- talk_base::MessageData* pdata = NULL);
- void Clear(uint32 id = talk_base::MQID_ANY,
- talk_base::MessageList* removed = NULL);
void FlushRtcpMessages();
// NetworkInterface implementation, called by MediaEngine
@@ -307,24 +301,40 @@ class BaseChannel
virtual const ContentInfo* GetFirstContent(
const SessionDescription* sdesc) = 0;
bool UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
bool UpdateRemoteStreams_w(const std::vector<StreamParams>& streams,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
bool SetBaseLocalContent_w(const MediaContentDescription* content,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
virtual bool SetLocalContent_w(const MediaContentDescription* content,
- ContentAction action) = 0;
+ ContentAction action,
+ std::string* error_desc) = 0;
bool SetBaseRemoteContent_w(const MediaContentDescription* content,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
virtual bool SetRemoteContent_w(const MediaContentDescription* content,
- ContentAction action) = 0;
-
- bool CheckSrtpConfig(const std::vector<CryptoParams>& cryptos, bool* dtls);
- bool SetSrtp_w(const std::vector<CryptoParams>& params, ContentAction action,
- ContentSource src);
- bool SetRtcpMux_w(bool enable, ContentAction action, ContentSource src);
-
- virtual bool SetMaxSendBandwidth_w(int max_bandwidth);
+ ContentAction action,
+ std::string* error_desc) = 0;
+
+ // Helper method to get RTP Absoulute SendTime extension header id if
+ // present in remote supported extensions list.
+ void MaybeCacheRtpAbsSendTimeHeaderExtension(
+ const std::vector<RtpHeaderExtension>& extensions);
+
+ bool CheckSrtpConfig(const std::vector<CryptoParams>& cryptos,
+ bool* dtls,
+ std::string* error_desc);
+ bool SetSrtp_w(const std::vector<CryptoParams>& params,
+ ContentAction action,
+ ContentSource src,
+ std::string* error_desc);
+ bool SetRtcpMux_w(bool enable,
+ ContentAction action,
+ ContentSource src,
+ std::string* error_desc);
// From MessageHandler
virtual void OnMessage(talk_base::Message* pmsg);
@@ -335,6 +345,12 @@ class BaseChannel
virtual void OnConnectionMonitorUpdate(SocketMonitor* monitor,
const std::vector<ConnectionInfo>& infos) = 0;
+ // Helper function for invoking bool-returning methods on the worker thread.
+ template <class FunctorT>
+ bool InvokeOnWorker(const FunctorT& functor) {
+ return worker_thread_->Invoke<bool>(functor);
+ }
+
private:
sigslot::signal3<const void*, size_t, bool> SignalSendPacketPreCrypto;
sigslot::signal3<const void*, size_t, bool> SignalSendPacketPostCrypto;
@@ -356,7 +372,7 @@ class BaseChannel
TransportChannel* rtcp_transport_channel_;
SrtpFilter srtp_filter_;
RtcpMuxFilter rtcp_mux_filter_;
- SsrcMuxFilter ssrc_filter_;
+ BundleFilter bundle_filter_;
talk_base::scoped_ptr<SocketMonitor> socket_monitor_;
bool enabled_;
bool writable_;
@@ -369,6 +385,7 @@ class BaseChannel
bool has_received_packet_;
bool dtls_keyed_;
bool secure_required_;
+ int rtp_abs_sendtime_extn_id_;
};
// VoiceChannel is a specialization that adds support for early media, DTMF,
@@ -451,13 +468,14 @@ class VoiceChannel : public BaseChannel {
virtual void ChangeState();
virtual const ContentInfo* GetFirstContent(const SessionDescription* sdesc);
virtual bool SetLocalContent_w(const MediaContentDescription* content,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
virtual bool SetRemoteContent_w(const MediaContentDescription* content,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
bool SetRingbackTone_w(const void* buf, int len);
bool PlayRingbackTone_w(uint32 ssrc, bool play, bool loop);
void HandleEarlyMediaTimeout();
- bool CanInsertDtmf_w();
bool InsertDtmf_w(uint32 ssrc, int event, int duration, int flags);
bool SetOutputScaling_w(uint32 ssrc, double left, double right);
bool GetStats_w(VoiceMediaInfo* stats);
@@ -472,9 +490,6 @@ class VoiceChannel : public BaseChannel {
void OnVoiceChannelError(uint32 ssrc, VoiceMediaChannel::Error error);
void SendLastMediaError();
void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error);
- // Configuration and setting.
- bool SetChannelOptions_w(const AudioOptions& options);
- bool SetRenderer_w(uint32 ssrc, AudioRenderer* renderer, bool is_local);
static const int kEarlyMediaTimeout = 1000;
bool received_media_;
@@ -515,7 +530,7 @@ class VideoChannel : public BaseChannel {
int GetScreencastFps(uint32 ssrc);
int GetScreencastMaxPixels(uint32 ssrc);
// Get statistics about the current media session.
- bool GetStats(VideoMediaInfo* stats);
+ bool GetStats(const StatsOptions& options, VideoMediaInfo* stats);
sigslot::signal2<VideoChannel*, const std::vector<ConnectionInfo>&>
SignalConnectionMonitor;
@@ -544,31 +559,24 @@ class VideoChannel : public BaseChannel {
private:
typedef std::map<uint32, VideoCapturer*> ScreencastMap;
- struct ScreencastDetailsMessageData;
+ struct ScreencastDetailsData;
// overrides from BaseChannel
virtual void ChangeState();
virtual const ContentInfo* GetFirstContent(const SessionDescription* sdesc);
virtual bool SetLocalContent_w(const MediaContentDescription* content,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
virtual bool SetRemoteContent_w(const MediaContentDescription* content,
- ContentAction action);
- void SendIntraFrame_w() {
- media_channel()->SendIntraFrame();
- }
- void RequestIntraFrame_w() {
- media_channel()->RequestIntraFrame();
- }
-
+ ContentAction action,
+ std::string* error_desc);
bool ApplyViewRequest_w(const ViewRequest& request);
- void SetRenderer_w(uint32 ssrc, VideoRenderer* renderer);
VideoCapturer* AddScreencast_w(uint32 ssrc, const ScreencastId& id);
- bool SetCapturer_w(uint32 ssrc, VideoCapturer* capturer);
bool RemoveScreencast_w(uint32 ssrc);
void OnScreencastWindowEvent_s(uint32 ssrc, talk_base::WindowEvent we);
bool IsScreencasting_w() const;
- void ScreencastDetails_w(ScreencastDetailsMessageData* d) const;
+ void GetScreencastDetails_w(ScreencastDetailsData* d) const;
void SetScreenCaptureFactory_w(
ScreenCapturerFactory* screencapture_factory);
bool GetStats_w(VideoMediaInfo* stats);
@@ -586,8 +594,6 @@ class VideoChannel : public BaseChannel {
void OnVideoChannelError(uint32 ssrc, VideoMediaChannel::Error error);
void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error);
- // Configuration and setting.
- bool SetChannelOptions_w(const VideoOptions& options);
VoiceChannel* voice_channel_;
VideoRenderer* renderer_;
@@ -634,11 +640,8 @@ class DataChannel : public BaseChannel {
// That occurs when the channel is enabled, the transport is writable,
// both local and remote descriptions are set, and the channel is unblocked.
sigslot::signal1<bool> SignalReadyToSendData;
- // Signal for notifying when a new stream is added from the remote side. Used
- // for the in-band negotioation through the OPEN message for SCTP data
- // channel.
- sigslot::signal2<const std::string&, const webrtc::DataChannelInit&>
- SignalNewStreamReceived;
+ // Signal for notifying that the remote side has closed the DataChannel.
+ sigslot::signal1<uint32> SignalStreamClosedRemotely;
protected:
// downcasts a MediaChannel.
@@ -678,31 +681,23 @@ class DataChannel : public BaseChannel {
typedef talk_base::TypedMessageData<bool> DataChannelReadyToSendMessageData;
- struct DataChannelNewStreamReceivedMessageData
- : public talk_base::MessageData {
- DataChannelNewStreamReceivedMessageData(
- const std::string& label, const webrtc::DataChannelInit& init)
- : label(label),
- init(init) {
- }
- const std::string label;
- const webrtc::DataChannelInit init;
- };
-
// overrides from BaseChannel
virtual const ContentInfo* GetFirstContent(const SessionDescription* sdesc);
// If data_channel_type_ is DCT_NONE, set it. Otherwise, check that
// it's the same as what was set previously. Returns false if it's
// set to one type one type and changed to another type later.
- bool SetDataChannelType(DataChannelType new_data_channel_type);
+ bool SetDataChannelType(DataChannelType new_data_channel_type,
+ std::string* error_desc);
// Same as SetDataChannelType, but extracts the type from the
// DataContentDescription.
- bool SetDataChannelTypeFromContent(const DataContentDescription* content);
- virtual bool SetMaxSendBandwidth_w(int max_bandwidth);
+ bool SetDataChannelTypeFromContent(const DataContentDescription* content,
+ std::string* error_desc);
virtual bool SetLocalContent_w(const MediaContentDescription* content,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
virtual bool SetRemoteContent_w(const MediaContentDescription* content,
- ContentAction action);
+ ContentAction action,
+ std::string* error_desc);
virtual void ChangeState();
virtual bool WantsPacket(bool rtcp, talk_base::Buffer* packet);
@@ -717,9 +712,8 @@ class DataChannel : public BaseChannel {
const ReceiveDataParams& params, const char* data, size_t len);
void OnDataChannelError(uint32 ssrc, DataMediaChannel::Error error);
void OnDataChannelReadyToSend(bool writable);
- void OnDataChannelNewStreamReceived(const std::string& label,
- const webrtc::DataChannelInit& init);
void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error);
+ void OnStreamClosedRemotely(uint32 sid);
talk_base::scoped_ptr<DataMediaMonitor> media_monitor_;
// TODO(pthatcher): Make a separate SctpDataChannel and
diff --git a/chromium/third_party/libjingle/source/talk/session/media/channel_unittest.cc b/chromium/third_party/libjingle/source/talk/session/media/channel_unittest.cc
index 48a9bdef563..c22361d6570 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/channel_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/channel_unittest.cc
@@ -71,7 +71,8 @@ static const cricket::DataCodec kGoogleDataCodec(101, "google-data", 0);
static const uint32 kSsrc1 = 0x1111;
static const uint32 kSsrc2 = 0x2222;
static const uint32 kSsrc3 = 0x3333;
-static const char kCName[] = "a@b.com";
+static const int kAudioPts[] = {0, 8};
+static const int kVideoPts[] = {97, 99};
template<class ChannelT,
class MediaChannelT,
@@ -318,14 +319,17 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
}
bool SendInitiate() {
- bool result = channel1_->SetLocalContent(&local_media_content1_, CA_OFFER);
+ bool result = channel1_->SetLocalContent(&local_media_content1_,
+ CA_OFFER, NULL);
if (result) {
channel1_->Enable(true);
- result = channel2_->SetRemoteContent(&remote_media_content1_, CA_OFFER);
+ result = channel2_->SetRemoteContent(&remote_media_content1_,
+ CA_OFFER, NULL);
if (result) {
session1_.Connect(&session2_);
- result = channel2_->SetLocalContent(&local_media_content2_, CA_ANSWER);
+ result = channel2_->SetLocalContent(&local_media_content2_,
+ CA_ANSWER, NULL);
}
}
return result;
@@ -333,34 +337,39 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
bool SendAccept() {
channel2_->Enable(true);
- return channel1_->SetRemoteContent(&remote_media_content2_, CA_ANSWER);
+ return channel1_->SetRemoteContent(&remote_media_content2_,
+ CA_ANSWER, NULL);
}
bool SendOffer() {
- bool result = channel1_->SetLocalContent(&local_media_content1_, CA_OFFER);
+ bool result = channel1_->SetLocalContent(&local_media_content1_,
+ CA_OFFER, NULL);
if (result) {
channel1_->Enable(true);
- result = channel2_->SetRemoteContent(&remote_media_content1_, CA_OFFER);
+ result = channel2_->SetRemoteContent(&remote_media_content1_,
+ CA_OFFER, NULL);
}
return result;
}
bool SendProvisionalAnswer() {
bool result = channel2_->SetLocalContent(&local_media_content2_,
- CA_PRANSWER);
+ CA_PRANSWER, NULL);
if (result) {
channel2_->Enable(true);
result = channel1_->SetRemoteContent(&remote_media_content2_,
- CA_PRANSWER);
+ CA_PRANSWER, NULL);
session1_.Connect(&session2_);
}
return result;
}
bool SendFinalAnswer() {
- bool result = channel2_->SetLocalContent(&local_media_content2_, CA_ANSWER);
+ bool result = channel2_->SetLocalContent(&local_media_content2_,
+ CA_ANSWER, NULL);
if (result)
- result = channel1_->SetRemoteContent(&remote_media_content2_, CA_ANSWER);
+ result = channel1_->SetRemoteContent(&remote_media_content2_,
+ CA_ANSWER, NULL);
return result;
}
@@ -401,13 +410,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
static_cast<int>(rtcp_packet_.size()));
}
// Methods to send custom data.
- bool SendCustomRtp1(uint32 ssrc, int sequence_number) {
- std::string data(CreateRtpData(ssrc, sequence_number));
+ bool SendCustomRtp1(uint32 ssrc, int sequence_number, int pl_type = -1) {
+ std::string data(CreateRtpData(ssrc, sequence_number, pl_type));
return media_channel1_->SendRtp(data.c_str(),
static_cast<int>(data.size()));
}
- bool SendCustomRtp2(uint32 ssrc, int sequence_number) {
- std::string data(CreateRtpData(ssrc, sequence_number));
+ bool SendCustomRtp2(uint32 ssrc, int sequence_number, int pl_type = -1) {
+ std::string data(CreateRtpData(ssrc, sequence_number, pl_type));
return media_channel2_->SendRtp(data.c_str(),
static_cast<int>(data.size()));
}
@@ -438,13 +447,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
static_cast<int>(rtcp_packet_.size()));
}
// Methods to check custom data.
- bool CheckCustomRtp1(uint32 ssrc, int sequence_number) {
- std::string data(CreateRtpData(ssrc, sequence_number));
+ bool CheckCustomRtp1(uint32 ssrc, int sequence_number, int pl_type = -1 ) {
+ std::string data(CreateRtpData(ssrc, sequence_number, pl_type));
return media_channel1_->CheckRtp(data.c_str(),
static_cast<int>(data.size()));
}
- bool CheckCustomRtp2(uint32 ssrc, int sequence_number) {
- std::string data(CreateRtpData(ssrc, sequence_number));
+ bool CheckCustomRtp2(uint32 ssrc, int sequence_number, int pl_type = -1) {
+ std::string data(CreateRtpData(ssrc, sequence_number, pl_type));
return media_channel2_->CheckRtp(data.c_str(),
static_cast<int>(data.size()));
}
@@ -458,11 +467,14 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
return media_channel2_->CheckRtcp(data.c_str(),
static_cast<int>(data.size()));
}
- std::string CreateRtpData(uint32 ssrc, int sequence_number) {
+ std::string CreateRtpData(uint32 ssrc, int sequence_number, int pl_type) {
std::string data(rtp_packet_);
// Set SSRC in the rtp packet copy.
talk_base::SetBE32(const_cast<char*>(data.c_str()) + 8, ssrc);
talk_base::SetBE16(const_cast<char*>(data.c_str()) + 2, sequence_number);
+ if (pl_type >= 0) {
+ talk_base::Set8(const_cast<char*>(data.c_str()), 1, pl_type);
+ }
return data;
}
std::string CreateRtcpData(uint32 ssrc) {
@@ -591,9 +603,9 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
CreateChannels(0, 0);
typename T::Content content;
CreateContent(0, kPcmuCodec, kH264Codec, &content);
- EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER, NULL));
EXPECT_EQ(0U, media_channel1_->codecs().size());
- EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER, NULL));
ASSERT_EQ(1U, media_channel1_->codecs().size());
EXPECT_TRUE(CodecMatches(content.codecs()[0],
media_channel1_->codecs()[0]));
@@ -604,10 +616,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
void TestSetContentsNullOffer() {
CreateChannels(0, 0);
typename T::Content content;
- EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER, NULL));
CreateContent(0, kPcmuCodec, kH264Codec, &content);
EXPECT_EQ(0U, media_channel1_->codecs().size());
- EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER, NULL));
ASSERT_EQ(1U, media_channel1_->codecs().size());
EXPECT_TRUE(CodecMatches(content.codecs()[0],
media_channel1_->codecs()[0]));
@@ -623,13 +635,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
CreateContent(0, kPcmuCodec, kH264Codec, &content);
// Both sides agree on mux. Should no longer be a separate RTCP channel.
content.set_rtcp_mux(true);
- EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER));
- EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER, NULL));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER, NULL));
EXPECT_TRUE(channel1_->rtcp_transport_channel() == NULL);
// Only initiator supports mux. Should still have a separate RTCP channel.
- EXPECT_TRUE(channel2_->SetLocalContent(&content, CA_OFFER));
+ EXPECT_TRUE(channel2_->SetLocalContent(&content, CA_OFFER, NULL));
content.set_rtcp_mux(false);
- EXPECT_TRUE(channel2_->SetRemoteContent(&content, CA_ANSWER));
+ EXPECT_TRUE(channel2_->SetRemoteContent(&content, CA_ANSWER, NULL));
EXPECT_TRUE(channel2_->rtcp_transport_channel() != NULL);
}
@@ -642,17 +654,17 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
typename T::Content content;
CreateContent(0, kPcmuCodec, kH264Codec, &content);
content.set_rtcp_mux(true);
- EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER));
- EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_PRANSWER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER, NULL));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_PRANSWER, NULL));
EXPECT_TRUE(channel1_->rtcp_transport_channel() != NULL);
- EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER, NULL));
// Both sides agree on mux. Should no longer be a separate RTCP channel.
EXPECT_TRUE(channel1_->rtcp_transport_channel() == NULL);
// Only initiator supports mux. Should still have a separate RTCP channel.
- EXPECT_TRUE(channel2_->SetLocalContent(&content, CA_OFFER));
+ EXPECT_TRUE(channel2_->SetLocalContent(&content, CA_OFFER, NULL));
content.set_rtcp_mux(false);
- EXPECT_TRUE(channel2_->SetRemoteContent(&content, CA_PRANSWER));
- EXPECT_TRUE(channel2_->SetRemoteContent(&content, CA_ANSWER));
+ EXPECT_TRUE(channel2_->SetRemoteContent(&content, CA_PRANSWER, NULL));
+ EXPECT_TRUE(channel2_->SetRemoteContent(&content, CA_ANSWER, NULL));
EXPECT_TRUE(channel2_->rtcp_transport_channel() != NULL);
}
@@ -663,7 +675,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
typename T::Content content;
CreateContent(0, kPcmuCodec, kH264Codec, &content);
content.set_buffered_mode_latency(101);
- EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER, NULL));
EXPECT_EQ(0U, media_channel1_->codecs().size());
cricket::VideoOptions options;
ASSERT_TRUE(media_channel1_->GetOptions(&options));
@@ -671,7 +683,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
EXPECT_TRUE(options.buffered_mode_latency.Get(&latency));
EXPECT_EQ(101, latency);
content.set_buffered_mode_latency(102);
- EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER, NULL));
ASSERT_EQ(1U, media_channel1_->codecs().size());
EXPECT_TRUE(CodecMatches(content.codecs()[0],
media_channel1_->codecs()[0]));
@@ -688,8 +700,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
kPcmuCodec, kH264Codec,
&content);
EXPECT_EQ(0U, media_channel1_->codecs().size());
- EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER));
- EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER, NULL));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER, NULL));
ASSERT_EQ(1U, media_channel1_->codecs().size());
EXPECT_TRUE(CodecMatches(content.codecs()[0],
media_channel1_->codecs()[0]));
@@ -698,14 +710,14 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
update_content.set_partial(true);
CreateContent(0, kIsacCodec, kH264SvcCodec,
&update_content);
- EXPECT_TRUE(channel1_->SetRemoteContent(&update_content, CA_UPDATE));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&update_content, CA_UPDATE, NULL));
ASSERT_EQ(1U, media_channel1_->codecs().size());
EXPECT_TRUE(CodecMatches(update_content.codecs()[0],
media_channel1_->codecs()[0]));
// Now update without any codecs. This is ignored.
typename T::Content empty_content;
empty_content.set_partial(true);
- EXPECT_TRUE(channel1_->SetRemoteContent(&empty_content, CA_UPDATE));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&empty_content, CA_UPDATE, NULL));
ASSERT_EQ(1U, media_channel1_->codecs().size());
EXPECT_TRUE(CodecMatches(update_content.codecs()[0],
media_channel1_->codecs()[0]));
@@ -751,7 +763,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
CreateContent(0, kPcmuCodec, kH264Codec, &content1);
content1.AddStream(stream1);
EXPECT_EQ(0u, media_channel1_->send_streams().size());
- EXPECT_TRUE(channel1_->SetLocalContent(&content1, CA_OFFER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content1, CA_OFFER, NULL));
ASSERT_EQ(1u, media_channel1_->send_streams().size());
EXPECT_EQ(stream1, media_channel1_->send_streams()[0]);
@@ -762,7 +774,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
content2.AddStream(stream2);
content2.AddStream(stream3);
content2.set_partial(true);
- EXPECT_TRUE(channel1_->SetLocalContent(&content2, CA_UPDATE));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content2, CA_UPDATE, NULL));
ASSERT_EQ(3u, media_channel1_->send_streams().size());
EXPECT_EQ(stream1, media_channel1_->send_streams()[0]);
EXPECT_EQ(stream2, media_channel1_->send_streams()[1]);
@@ -774,7 +786,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
stream1.ssrcs.clear();
content3.AddStream(stream1);
content3.set_partial(true);
- EXPECT_TRUE(channel1_->SetLocalContent(&content3, CA_UPDATE));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content3, CA_UPDATE, NULL));
ASSERT_EQ(2u, media_channel1_->send_streams().size());
EXPECT_EQ(stream2, media_channel1_->send_streams()[0]);
EXPECT_EQ(stream3, media_channel1_->send_streams()[1]);
@@ -784,7 +796,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
typename T::Content content4;
content4.AddStream(stream2);
content4.set_partial(true);
- EXPECT_TRUE(channel1_->SetLocalContent(&content4, CA_UPDATE));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content4, CA_UPDATE, NULL));
ASSERT_EQ(2u, media_channel1_->send_streams().size());
EXPECT_EQ(stream2, media_channel1_->send_streams()[0]);
EXPECT_EQ(stream3, media_channel1_->send_streams()[1]);
@@ -818,7 +830,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
CreateContent(0, kPcmuCodec, kH264Codec, &content1);
content1.AddStream(stream1);
EXPECT_EQ(0u, media_channel1_->recv_streams().size());
- EXPECT_TRUE(channel1_->SetRemoteContent(&content1, CA_OFFER));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content1, CA_OFFER, NULL));
ASSERT_EQ(1u, media_channel1_->codecs().size());
ASSERT_EQ(1u, media_channel1_->recv_streams().size());
@@ -830,7 +842,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
content2.AddStream(stream2);
content2.AddStream(stream3);
content2.set_partial(true);
- EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_UPDATE));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_UPDATE, NULL));
ASSERT_EQ(3u, media_channel1_->recv_streams().size());
EXPECT_EQ(stream1, media_channel1_->recv_streams()[0]);
EXPECT_EQ(stream2, media_channel1_->recv_streams()[1]);
@@ -842,7 +854,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
stream1.ssrcs.clear();
content3.AddStream(stream1);
content3.set_partial(true);
- EXPECT_TRUE(channel1_->SetRemoteContent(&content3, CA_UPDATE));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content3, CA_UPDATE, NULL));
ASSERT_EQ(2u, media_channel1_->recv_streams().size());
EXPECT_EQ(stream2, media_channel1_->recv_streams()[0]);
EXPECT_EQ(stream3, media_channel1_->recv_streams()[1]);
@@ -852,7 +864,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
typename T::Content content4;
content4.AddStream(stream2);
content4.set_partial(true);
- EXPECT_TRUE(channel1_->SetRemoteContent(&content4, CA_UPDATE));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content4, CA_UPDATE, NULL));
ASSERT_EQ(2u, media_channel1_->recv_streams().size());
EXPECT_EQ(stream2, media_channel1_->recv_streams()[0]);
EXPECT_EQ(stream3, media_channel1_->recv_streams()[1]);
@@ -879,20 +891,20 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
typename T::Content content1;
CreateContent(0, kPcmuCodec, kH264Codec, &content1);
content1.AddStream(stream1);
- EXPECT_TRUE(channel1_->SetLocalContent(&content1, CA_OFFER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content1, CA_OFFER, NULL));
EXPECT_TRUE(channel1_->Enable(true));
EXPECT_EQ(1u, media_channel1_->send_streams().size());
- EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER));
+ EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER, NULL));
EXPECT_EQ(1u, media_channel2_->recv_streams().size());
session1_.Connect(&session2_);
// Channel 2 do not send anything.
typename T::Content content2;
CreateContent(0, kPcmuCodec, kH264Codec, &content2);
- EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_ANSWER, NULL));
EXPECT_EQ(0u, media_channel1_->recv_streams().size());
- EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_ANSWER));
+ EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_ANSWER, NULL));
EXPECT_TRUE(channel2_->Enable(true));
EXPECT_EQ(0u, media_channel2_->send_streams().size());
@@ -903,21 +915,21 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
typename T::Content content3;
CreateContent(SECURE, kPcmuCodec, kH264Codec, &content3);
content3.AddStream(stream2);
- EXPECT_TRUE(channel2_->SetLocalContent(&content3, CA_OFFER));
+ EXPECT_TRUE(channel2_->SetLocalContent(&content3, CA_OFFER, NULL));
ASSERT_EQ(1u, media_channel2_->send_streams().size());
EXPECT_EQ(stream2, media_channel2_->send_streams()[0]);
- EXPECT_TRUE(channel1_->SetRemoteContent(&content3, CA_OFFER));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content3, CA_OFFER, NULL));
ASSERT_EQ(1u, media_channel1_->recv_streams().size());
EXPECT_EQ(stream2, media_channel1_->recv_streams()[0]);
// Channel 1 replies but stop sending stream1.
typename T::Content content4;
CreateContent(SECURE, kPcmuCodec, kH264Codec, &content4);
- EXPECT_TRUE(channel1_->SetLocalContent(&content4, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content4, CA_ANSWER, NULL));
EXPECT_EQ(0u, media_channel1_->send_streams().size());
- EXPECT_TRUE(channel2_->SetRemoteContent(&content4, CA_ANSWER));
+ EXPECT_TRUE(channel2_->SetRemoteContent(&content4, CA_ANSWER, NULL));
EXPECT_EQ(0u, media_channel2_->recv_streams().size());
EXPECT_TRUE(channel1_->secure());
@@ -936,13 +948,16 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
EXPECT_TRUE(channel1_->Enable(true));
EXPECT_FALSE(media_channel1_->playout());
EXPECT_FALSE(media_channel1_->sending());
- EXPECT_TRUE(channel1_->SetLocalContent(&local_media_content1_, CA_OFFER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&local_media_content1_,
+ CA_OFFER, NULL));
EXPECT_TRUE(media_channel1_->playout());
EXPECT_FALSE(media_channel1_->sending());
- EXPECT_TRUE(channel2_->SetRemoteContent(&local_media_content1_, CA_OFFER));
+ EXPECT_TRUE(channel2_->SetRemoteContent(&local_media_content1_,
+ CA_OFFER, NULL));
EXPECT_FALSE(media_channel2_->playout());
EXPECT_FALSE(media_channel2_->sending());
- EXPECT_TRUE(channel2_->SetLocalContent(&local_media_content2_, CA_ANSWER));
+ EXPECT_TRUE(channel2_->SetLocalContent(&local_media_content2_,
+ CA_ANSWER, NULL));
EXPECT_FALSE(media_channel2_->playout());
EXPECT_FALSE(media_channel2_->sending());
session1_.Connect(&session2_);
@@ -953,7 +968,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
EXPECT_TRUE(channel2_->Enable(true));
EXPECT_TRUE(media_channel2_->playout());
EXPECT_TRUE(media_channel2_->sending());
- EXPECT_TRUE(channel1_->SetRemoteContent(&local_media_content2_, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&local_media_content2_,
+ CA_ANSWER, NULL));
EXPECT_TRUE(media_channel1_->playout());
EXPECT_TRUE(media_channel1_->sending());
}
@@ -998,10 +1014,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
EXPECT_FALSE(media_channel2_->playout());
EXPECT_FALSE(media_channel2_->sending());
- EXPECT_TRUE(channel1_->SetLocalContent(&content1, CA_OFFER));
- EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER));
- EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_PRANSWER));
- EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_PRANSWER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content1, CA_OFFER, NULL));
+ EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER, NULL));
+ EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_PRANSWER, NULL));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_PRANSWER, NULL));
session1_.Connect(&session2_);
EXPECT_TRUE(media_channel1_->playout());
@@ -1011,8 +1027,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
// Update |content2| to be RecvOnly.
content2.set_direction(cricket::MD_RECVONLY);
- EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_PRANSWER));
- EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_PRANSWER));
+ EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_PRANSWER, NULL));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_PRANSWER, NULL));
EXPECT_TRUE(media_channel1_->playout());
EXPECT_TRUE(media_channel1_->sending());
@@ -1021,8 +1037,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
// Update |content2| to be SendRecv.
content2.set_direction(cricket::MD_SENDRECV);
- EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_ANSWER));
- EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_ANSWER));
+ EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_ANSWER, NULL));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_ANSWER, NULL));
EXPECT_TRUE(media_channel1_->playout());
EXPECT_TRUE(media_channel1_->sending());
@@ -1427,60 +1443,63 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
EXPECT_TRUE(CheckNoRtp2());
}
- void SendSsrcMuxToSsrcMuxWithRtcpMux() {
+ void SendBundleToBundle(
+ const int* pl_types, int len, bool rtcp_mux, bool secure) {
+ ASSERT_EQ(2, len);
int sequence_number1_1 = 0, sequence_number2_2 = 0;
- CreateChannels(SSRC_MUX | RTCP | RTCP_MUX, SSRC_MUX | RTCP | RTCP_MUX);
+ // Only pl_type1 was added to the bundle filter for both |channel1_|
+ // and |channel2_|.
+ int pl_type1 = pl_types[0];
+ int pl_type2 = pl_types[1];
+ int flags = SSRC_MUX | RTCP;
+ if (secure) flags |= SECURE;
+ uint32 expected_channels = 2U;
+ if (rtcp_mux) {
+ flags |= RTCP_MUX;
+ expected_channels = 1U;
+ }
+ CreateChannels(flags, flags);
EXPECT_TRUE(SendInitiate());
EXPECT_EQ(2U, GetTransport1()->channels().size());
- EXPECT_EQ(1U, GetTransport2()->channels().size());
+ EXPECT_EQ(expected_channels, GetTransport2()->channels().size());
EXPECT_TRUE(SendAccept());
- EXPECT_EQ(1U, GetTransport1()->channels().size());
- EXPECT_EQ(1U, GetTransport2()->channels().size());
- EXPECT_TRUE(channel1_->ssrc_filter()->IsActive());
- // channel1 - should have media_content2 as remote. i.e. kSsrc2
- EXPECT_TRUE(channel1_->ssrc_filter()->FindStream(kSsrc2));
- EXPECT_TRUE(channel2_->ssrc_filter()->IsActive());
- // channel2 - should have media_content1 as remote. i.e. kSsrc1
- EXPECT_TRUE(channel2_->ssrc_filter()->FindStream(kSsrc1));
- EXPECT_TRUE(SendCustomRtp1(kSsrc1, ++sequence_number1_1));
- EXPECT_TRUE(SendCustomRtp2(kSsrc2, ++sequence_number2_2));
- EXPECT_TRUE(SendCustomRtcp1(kSsrc1));
- EXPECT_TRUE(SendCustomRtcp2(kSsrc2));
- EXPECT_TRUE(CheckCustomRtp1(kSsrc2, sequence_number2_2));
+ EXPECT_EQ(expected_channels, GetTransport1()->channels().size());
+ EXPECT_EQ(expected_channels, GetTransport2()->channels().size());
+ EXPECT_TRUE(channel1_->bundle_filter()->FindPayloadType(pl_type1));
+ EXPECT_TRUE(channel2_->bundle_filter()->FindPayloadType(pl_type1));
+ EXPECT_FALSE(channel1_->bundle_filter()->FindPayloadType(pl_type2));
+ EXPECT_FALSE(channel2_->bundle_filter()->FindPayloadType(pl_type2));
+ // channel1 - should only have media_content2 as remote. i.e. kSsrc2
+ EXPECT_TRUE(channel1_->bundle_filter()->FindStream(kSsrc2));
+ EXPECT_FALSE(channel1_->bundle_filter()->FindStream(kSsrc1));
+ // channel2 - should only have media_content1 as remote. i.e. kSsrc1
+ EXPECT_TRUE(channel2_->bundle_filter()->FindStream(kSsrc1));
+ EXPECT_FALSE(channel2_->bundle_filter()->FindStream(kSsrc2));
+
+ // Both channels can receive pl_type1 only.
+ EXPECT_TRUE(SendCustomRtp1(kSsrc1, ++sequence_number1_1, pl_type1));
+ EXPECT_TRUE(CheckCustomRtp2(kSsrc1, sequence_number1_1, pl_type1));
+ EXPECT_TRUE(SendCustomRtp2(kSsrc2, ++sequence_number2_2, pl_type1));
+ EXPECT_TRUE(CheckCustomRtp1(kSsrc2, sequence_number2_2, pl_type1));
EXPECT_TRUE(CheckNoRtp1());
- EXPECT_TRUE(CheckCustomRtp2(kSsrc1, sequence_number1_1));
EXPECT_TRUE(CheckNoRtp2());
+
+ // RTCP test
+ EXPECT_TRUE(SendCustomRtp1(kSsrc1, ++sequence_number1_1, pl_type2));
+ EXPECT_FALSE(CheckCustomRtp2(kSsrc1, sequence_number1_1, pl_type2));
+ EXPECT_TRUE(SendCustomRtp2(kSsrc2, ++sequence_number2_2, pl_type2));
+ EXPECT_FALSE(CheckCustomRtp1(kSsrc2, sequence_number2_2, pl_type2));
+
+ EXPECT_TRUE(SendCustomRtcp1(kSsrc1));
+ EXPECT_TRUE(SendCustomRtcp2(kSsrc2));
EXPECT_TRUE(CheckCustomRtcp1(kSsrc2));
EXPECT_TRUE(CheckNoRtcp1());
EXPECT_TRUE(CheckCustomRtcp2(kSsrc1));
EXPECT_TRUE(CheckNoRtcp2());
- }
- void SendSsrcMuxToSsrcMux() {
- int sequence_number1_1 = 0, sequence_number2_2 = 0;
- CreateChannels(SSRC_MUX | RTCP, SSRC_MUX | RTCP);
- EXPECT_TRUE(SendInitiate());
- EXPECT_EQ(2U, GetTransport1()->channels().size());
- EXPECT_EQ(2U, GetTransport2()->channels().size());
- EXPECT_TRUE(SendAccept());
- EXPECT_EQ(2U, GetTransport1()->channels().size());
- EXPECT_EQ(2U, GetTransport2()->channels().size());
- EXPECT_TRUE(channel1_->ssrc_filter()->IsActive());
- // channel1 - should have media_content2 as remote. i.e. kSsrc2
- EXPECT_TRUE(channel1_->ssrc_filter()->FindStream(kSsrc2));
- EXPECT_TRUE(channel2_->ssrc_filter()->IsActive());
- // channel2 - should have media_content1 as remote. i.e. kSsrc1
- EXPECT_TRUE(SendCustomRtp1(kSsrc1, ++sequence_number1_1));
- EXPECT_TRUE(SendCustomRtp2(kSsrc2, ++sequence_number2_2));
- EXPECT_TRUE(SendCustomRtcp1(kSsrc1));
- EXPECT_TRUE(SendCustomRtcp2(kSsrc2));
- EXPECT_TRUE(CheckCustomRtp1(kSsrc2, sequence_number2_2));
- EXPECT_FALSE(CheckCustomRtp1(kSsrc1, sequence_number2_2));
- EXPECT_TRUE(CheckCustomRtp2(kSsrc1, sequence_number1_1));
- EXPECT_FALSE(CheckCustomRtp2(kSsrc2, sequence_number1_1));
- EXPECT_TRUE(CheckCustomRtcp1(kSsrc2));
+ EXPECT_TRUE(SendCustomRtcp1(kSsrc2));
+ EXPECT_TRUE(SendCustomRtcp2(kSsrc1));
EXPECT_FALSE(CheckCustomRtcp1(kSsrc1));
- EXPECT_TRUE(CheckCustomRtcp2(kSsrc1));
EXPECT_FALSE(CheckCustomRtcp2(kSsrc2));
}
@@ -1587,21 +1606,21 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
// Test failures in SetLocalContent.
media_channel1_->set_fail_set_recv_codecs(true);
- session1_.SetError(cricket::BaseSession::ERROR_NONE);
+ session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
session1_.SetState(cricket::Session::STATE_SENTINITIATE);
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
media_channel1_->set_fail_set_recv_codecs(true);
- session1_.SetError(cricket::BaseSession::ERROR_NONE);
+ session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
session1_.SetState(cricket::Session::STATE_SENTACCEPT);
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
// Test failures in SetRemoteContent.
media_channel1_->set_fail_set_send_codecs(true);
- session1_.SetError(cricket::BaseSession::ERROR_NONE);
+ session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
session1_.SetState(cricket::Session::STATE_RECEIVEDINITIATE);
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
media_channel1_->set_fail_set_send_codecs(true);
- session1_.SetError(cricket::BaseSession::ERROR_NONE);
+ session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
session1_.SetState(cricket::Session::STATE_RECEIVEDACCEPT);
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
}
@@ -1613,7 +1632,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
cricket::SessionDescription* sdesc = CreateSessionDescriptionWithStream(1);
EXPECT_TRUE(session1_.set_local_description(sdesc));
- session1_.SetError(cricket::BaseSession::ERROR_NONE);
+ session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
session1_.SetState(cricket::Session::STATE_SENTINITIATE);
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
EXPECT_TRUE(media_channel1_->HasSendStream(1));
@@ -1635,7 +1654,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
cricket::SessionDescription* sdesc = CreateSessionDescriptionWithStream(1);
EXPECT_TRUE(session1_.set_remote_description(sdesc));
- session1_.SetError(cricket::BaseSession::ERROR_NONE);
+ session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
session1_.SetState(cricket::Session::STATE_RECEIVEDINITIATE);
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
EXPECT_TRUE(media_channel1_->HasRecvStream(1));
@@ -1655,7 +1674,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
cricket::SessionDescription* sdesc = CreateSessionDescriptionWithStream(1);
EXPECT_TRUE(session1_.set_remote_description(sdesc));
- session1_.SetError(cricket::BaseSession::ERROR_NONE);
+ session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
session1_.SetState(cricket::Session::STATE_RECEIVEDINITIATE);
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
EXPECT_TRUE(media_channel1_->HasRecvStream(1));
@@ -1687,7 +1706,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
cricket::SessionDescription* sdesc = CreateSessionDescriptionWithStream(1);
EXPECT_TRUE(session1_.set_local_description(sdesc));
- session1_.SetError(cricket::BaseSession::ERROR_NONE);
+ session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
session1_.SetState(cricket::Session::STATE_SENTINITIATE);
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
EXPECT_TRUE(media_channel1_->HasSendStream(1));
@@ -1742,10 +1761,24 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
error_);
}
- void TestSrtpError() {
- static const unsigned char kBadPacket[] = {
- 0x84, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
- };
+ void TestSrtpError(int pl_type) {
+ // For Audio, only pl_type 0 is added to the bundle filter.
+ // For Video, only pl_type 97 is added to the bundle filter.
+ // So we need to pass in pl_type so that the packet can pass through
+ // the bundle filter before it can be processed by the srtp filter.
+ // The packet is not a valid srtp packet because it is too short.
+ unsigned const char kBadPacket[] = {0x84,
+ static_cast<unsigned char>(pl_type),
+ 0x00,
+ 0x01,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x01};
CreateChannels(RTCP | SECURE, RTCP | SECURE);
EXPECT_FALSE(channel1_->secure());
EXPECT_FALSE(channel2_->secure());
@@ -1810,8 +1843,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
CreateContent(0, kPcmuCodec, kH264Codec, &content);
// Both sides agree on mux. Should no longer be a separate RTCP channel.
content.set_rtcp_mux(true);
- EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER));
- EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER, NULL));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER, NULL));
EXPECT_TRUE(channel1_->rtcp_transport_channel() == NULL);
TransportChannel* rtp = channel1_->transport_channel();
EXPECT_FALSE(media_channel1_->ready_to_send());
@@ -2266,7 +2299,7 @@ TEST_F(VoiceChannelTest, TestChangeStateError) {
}
TEST_F(VoiceChannelTest, TestSrtpError) {
- Base::TestSrtpError();
+ Base::TestSrtpError(kAudioPts[0]);
}
TEST_F(VoiceChannelTest, TestOnReadyToSend) {
@@ -2378,12 +2411,22 @@ TEST_F(VoiceChannelTest, TestScaleVolumeMultiwayCall) {
EXPECT_DOUBLE_EQ(0.0, right);
}
-TEST_F(VoiceChannelTest, SendSsrcMuxToSsrcMux) {
- Base::SendSsrcMuxToSsrcMux();
+TEST_F(VoiceChannelTest, SendBundleToBundle) {
+ Base::SendBundleToBundle(kAudioPts, ARRAY_SIZE(kAudioPts), false, false);
}
-TEST_F(VoiceChannelTest, SendSsrcMuxToSsrcMuxWithRtcpMux) {
- Base::SendSsrcMuxToSsrcMuxWithRtcpMux();
+TEST_F(VoiceChannelTest, SendBundleToBundleSecure) {
+ Base::SendBundleToBundle(kAudioPts, ARRAY_SIZE(kAudioPts), false, true);
+}
+
+TEST_F(VoiceChannelTest, SendBundleToBundleWithRtcpMux) {
+ Base::SendBundleToBundle(
+ kAudioPts, ARRAY_SIZE(kAudioPts), true, false);
+}
+
+TEST_F(VoiceChannelTest, SendBundleToBundleWithRtcpMuxSecure) {
+ Base::SendBundleToBundle(
+ kAudioPts, ARRAY_SIZE(kAudioPts), true, true);
}
TEST_F(VoiceChannelTest, TestSetChannelOptions) {
@@ -2593,18 +2636,28 @@ TEST_F(VideoChannelTest, TestFlushRtcp) {
Base::TestFlushRtcp();
}
-TEST_F(VideoChannelTest, SendSsrcMuxToSsrcMux) {
- Base::SendSsrcMuxToSsrcMux();
+TEST_F(VideoChannelTest, SendBundleToBundle) {
+ Base::SendBundleToBundle(kVideoPts, ARRAY_SIZE(kVideoPts), false, false);
+}
+
+TEST_F(VideoChannelTest, SendBundleToBundleSecure) {
+ Base::SendBundleToBundle(kVideoPts, ARRAY_SIZE(kVideoPts), false, true);
+}
+
+TEST_F(VideoChannelTest, SendBundleToBundleWithRtcpMux) {
+ Base::SendBundleToBundle(
+ kVideoPts, ARRAY_SIZE(kVideoPts), true, false);
}
-TEST_F(VideoChannelTest, SendSsrcMuxToSsrcMuxWithRtcpMux) {
- Base::SendSsrcMuxToSsrcMuxWithRtcpMux();
+TEST_F(VideoChannelTest, SendBundleToBundleWithRtcpMuxSecure) {
+ Base::SendBundleToBundle(
+ kVideoPts, ARRAY_SIZE(kVideoPts), true, true);
}
// TODO(gangji): Add VideoChannelTest.TestChangeStateError.
TEST_F(VideoChannelTest, TestSrtpError) {
- Base::TestSrtpError();
+ Base::TestSrtpError(kVideoPts[0]);
}
TEST_F(VideoChannelTest, TestOnReadyToSend) {
diff --git a/chromium/third_party/libjingle/source/talk/session/media/channelmanager.cc b/chromium/third_party/libjingle/source/talk/session/media/channelmanager.cc
index d4fcc79dfa7..88316b56321 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/channelmanager.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/channelmanager.cc
@@ -217,7 +217,11 @@ bool ChannelManager::Init() {
}
ASSERT(worker_thread_ != NULL);
- if (worker_thread_ && worker_thread_->started()) {
+ ASSERT(worker_thread_->RunningForChannelManager());
+ // TODO(fischman): remove the if below (and
+ // Thread::RunningForChannelManager()) once the ASSERT above has stuck for a
+ // month (2014/06/22).
+ if (worker_thread_ && worker_thread_->RunningForChannelManager()) {
if (media_engine_->Init(worker_thread_)) {
initialized_ = true;
@@ -574,6 +578,29 @@ bool ChannelManager::SetAudioOptions_w(
return ret;
}
+// Sets Engine-specific audio options according to enabled experiments.
+bool ChannelManager::SetEngineAudioOptions(const AudioOptions& options) {
+ // If we're initialized, pass the settings to the media engine.
+ bool ret = false;
+ if (initialized_) {
+ ret = worker_thread_->Invoke<bool>(
+ Bind(&ChannelManager::SetEngineAudioOptions_w, this, options));
+ }
+
+ // If all worked well, save the audio options.
+ if (ret) {
+ audio_options_ = options;
+ }
+ return ret;
+}
+
+bool ChannelManager::SetEngineAudioOptions_w(const AudioOptions& options) {
+ ASSERT(worker_thread_ == talk_base::Thread::Current());
+ ASSERT(initialized_);
+
+ return media_engine_->SetAudioOptions(options);
+}
+
bool ChannelManager::GetOutputVolume(int* level) {
if (!initialized_) {
return false;
@@ -939,12 +966,9 @@ VideoFormat ChannelManager::GetStartCaptureFormat() {
Bind(&MediaEngineInterface::GetStartCaptureFormat, media_engine_.get()));
}
-bool ChannelManager::SetAudioOptions(const AudioOptions& options) {
- if (!media_engine_->SetAudioOptions(options)) {
- return false;
- }
- audio_options_ = options;
- return true;
+bool ChannelManager::StartAecDump(talk_base::PlatformFile file) {
+ return worker_thread_->Invoke<bool>(
+ Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file));
}
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/session/media/channelmanager.h b/chromium/third_party/libjingle/source/talk/session/media/channelmanager.h
index fdb8f733624..e8d6c0e5e4f 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/channelmanager.h
+++ b/chromium/third_party/libjingle/source/talk/session/media/channelmanager.h
@@ -32,6 +32,7 @@
#include <vector>
#include "talk/base/criticalsection.h"
+#include "talk/base/fileutils.h"
#include "talk/base/sigslotrepeater.h"
#include "talk/base/thread.h"
#include "talk/media/base/capturemanager.h"
@@ -142,6 +143,8 @@ class ChannelManager : public talk_base::MessageHandler,
bool SetAudioOptions(const std::string& wave_in_device,
const std::string& wave_out_device,
const AudioOptions& options);
+ // Sets Engine-specific audio options according to enabled experiments.
+ bool SetEngineAudioOptions(const AudioOptions& options);
bool GetOutputVolume(int* level);
bool SetOutputVolume(int level);
bool IsSameCapturer(const std::string& capturer_name,
@@ -214,6 +217,9 @@ class ChannelManager : public talk_base::MessageHandler,
void SetVideoCaptureDeviceMaxFormat(const std::string& usb_id,
const VideoFormat& max_format);
+ // Starts AEC dump using existing file.
+ bool StartAecDump(talk_base::PlatformFile file);
+
sigslot::repeater0<> SignalDevicesChange;
sigslot::signal2<VideoCapturer*, CaptureState> SignalVideoCaptureStateChange;
@@ -226,10 +232,6 @@ class ChannelManager : public talk_base::MessageHandler,
// removed.
VideoFormat GetStartCaptureFormat();
- // TODO(turajs): Remove this function when ACM2 is in use. Used mainly to
- // choose between ACM1 and ACM2.
- bool SetAudioOptions(const AudioOptions& options);
-
protected:
// Adds non-transient parameters which can only be changed through the
// options store.
@@ -266,6 +268,7 @@ class ChannelManager : public talk_base::MessageHandler,
void DestroySoundclip_w(Soundclip* soundclip);
bool SetAudioOptions_w(const AudioOptions& options, int delay_offset,
const Device* in_dev, const Device* out_dev);
+ bool SetEngineAudioOptions_w(const AudioOptions& options);
bool SetCaptureDevice_w(const Device* cam_device);
void OnVideoCaptureStateChange(VideoCapturer* capturer,
CaptureState result);
diff --git a/chromium/third_party/libjingle/source/talk/session/media/channelmanager_unittest.cc b/chromium/third_party/libjingle/source/talk/session/media/channelmanager_unittest.cc
index d0d380d3eb8..cbf19f88858 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/channelmanager_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/channelmanager_unittest.cc
@@ -122,7 +122,9 @@ TEST_F(ChannelManagerTest, StartupShutdownOnThread) {
}
// Test that we fail to startup if we're given an unstarted thread.
-TEST_F(ChannelManagerTest, StartupShutdownOnUnstartedThread) {
+// TODO(fischman): delete once Thread::RunningForChannelManager() is gone
+// (webrtc:3388).
+TEST_F(ChannelManagerTest, DISABLED_StartupShutdownOnUnstartedThread) {
EXPECT_TRUE(cm_->set_worker_thread(&worker_));
EXPECT_FALSE(cm_->Init());
EXPECT_FALSE(cm_->initialized());
@@ -319,6 +321,25 @@ TEST_F(ChannelManagerTest, SetAudioOptions) {
EXPECT_FALSE(cm_->SetAudioOptions("audio-in9", "audio-out2", options));
}
+TEST_F(ChannelManagerTest, SetEngineAudioOptions) {
+ EXPECT_TRUE(cm_->Init());
+ // Test setting specific values.
+ AudioOptions options;
+ options.experimental_ns.Set(true);
+ EXPECT_TRUE(cm_->SetEngineAudioOptions(options));
+ bool experimental_ns = false;
+ EXPECT_TRUE(fme_->audio_options().experimental_ns.Get(&experimental_ns));
+ EXPECT_TRUE(experimental_ns);
+}
+
+TEST_F(ChannelManagerTest, SetEngineAudioOptionsBeforeInitFails) {
+ // Test that values that we set before Init are not applied.
+ AudioOptions options;
+ options.experimental_ns.Set(true);
+ EXPECT_FALSE(cm_->SetEngineAudioOptions(options));
+ EXPECT_FALSE(fme_->audio_options().experimental_ns.IsSet());
+}
+
TEST_F(ChannelManagerTest, SetCaptureDeviceBeforeInit) {
// Test that values that we set before Init are applied.
EXPECT_TRUE(cm_->SetCaptureDevice("video-in2"));
diff --git a/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor.cc b/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor.cc
index 1f3e0938fb9..8965cde9582 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor.cc
@@ -28,7 +28,9 @@
#include "talk/session/media/currentspeakermonitor.h"
#include "talk/base/logging.h"
-#include "talk/session/media/call.h"
+#include "talk/media/base/streamparams.h"
+#include "talk/session/media/audiomonitor.h"
+#include "talk/session/media/mediamessages.h"
namespace cricket {
@@ -39,9 +41,10 @@ const int kMaxAudioLevel = 9;
const int kDefaultMinTimeBetweenSwitches = 1000;
}
-CurrentSpeakerMonitor::CurrentSpeakerMonitor(Call* call, BaseSession* session)
+CurrentSpeakerMonitor::CurrentSpeakerMonitor(
+ AudioSourceContext* audio_source_context, BaseSession* session)
: started_(false),
- call_(call),
+ audio_source_context_(audio_source_context),
session_(session),
current_speaker_ssrc_(0),
earliest_permitted_switch_time_(0),
@@ -54,10 +57,12 @@ CurrentSpeakerMonitor::~CurrentSpeakerMonitor() {
void CurrentSpeakerMonitor::Start() {
if (!started_) {
- call_->SignalAudioMonitor.connect(
+ audio_source_context_->SignalAudioMonitor.connect(
this, &CurrentSpeakerMonitor::OnAudioMonitor);
- call_->SignalMediaStreamsUpdate.connect(
+ audio_source_context_->SignalMediaStreamsUpdate.connect(
this, &CurrentSpeakerMonitor::OnMediaStreamsUpdate);
+ audio_source_context_->SignalMediaStreamsReset.connect(
+ this, &CurrentSpeakerMonitor::OnMediaStreamsReset);
started_ = true;
}
@@ -65,8 +70,8 @@ void CurrentSpeakerMonitor::Start() {
void CurrentSpeakerMonitor::Stop() {
if (started_) {
- call_->SignalAudioMonitor.disconnect(this);
- call_->SignalMediaStreamsUpdate.disconnect(this);
+ audio_source_context_->SignalAudioMonitor.disconnect(this);
+ audio_source_context_->SignalMediaStreamsUpdate.disconnect(this);
started_ = false;
ssrc_to_speaking_state_map_.clear();
@@ -80,7 +85,8 @@ void CurrentSpeakerMonitor::set_min_time_between_switches(
min_time_between_switches_ = min_time_between_switches;
}
-void CurrentSpeakerMonitor::OnAudioMonitor(Call* call, const AudioInfo& info) {
+void CurrentSpeakerMonitor::OnAudioMonitor(
+ AudioSourceContext* audio_source_context, const AudioInfo& info) {
std::map<uint32, int> active_ssrc_to_level_map;
cricket::AudioInfo::StreamList::const_iterator stream_list_it;
for (stream_list_it = info.active_streams.begin();
@@ -187,22 +193,29 @@ void CurrentSpeakerMonitor::OnAudioMonitor(Call* call, const AudioInfo& info) {
}
}
-void CurrentSpeakerMonitor::OnMediaStreamsUpdate(Call* call,
- Session* session,
- const MediaStreams& added,
- const MediaStreams& removed) {
- if (call == call_ && session == session_) {
+void CurrentSpeakerMonitor::OnMediaStreamsUpdate(
+ AudioSourceContext* audio_source_context, BaseSession* session,
+ const MediaStreams& added, const MediaStreams& removed) {
+
+ if (audio_source_context == audio_source_context_ && session == session_) {
// Update the speaking state map based on added and removed streams.
for (std::vector<cricket::StreamParams>::const_iterator
- it = removed.video().begin(); it != removed.video().end(); ++it) {
+ it = removed.audio().begin(); it != removed.audio().end(); ++it) {
ssrc_to_speaking_state_map_.erase(it->first_ssrc());
}
for (std::vector<cricket::StreamParams>::const_iterator
- it = added.video().begin(); it != added.video().end(); ++it) {
+ it = added.audio().begin(); it != added.audio().end(); ++it) {
ssrc_to_speaking_state_map_[it->first_ssrc()] = SS_NOT_SPEAKING;
}
}
}
+void CurrentSpeakerMonitor::OnMediaStreamsReset(
+ AudioSourceContext* audio_source_context, BaseSession* session) {
+ if (audio_source_context == audio_source_context_ && session == session_) {
+ ssrc_to_speaking_state_map_.clear();
+ }
+}
+
} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor.h b/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor.h
index 1781db58c49..8e05c8e6772 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor.h
+++ b/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor.h
@@ -39,16 +39,34 @@
namespace cricket {
class BaseSession;
-class Call;
class Session;
struct AudioInfo;
struct MediaStreams;
-// Note that the call's audio monitor must be started before this is started.
+class AudioSourceContext {
+ public:
+ sigslot::signal2<AudioSourceContext*, const cricket::AudioInfo&>
+ SignalAudioMonitor;
+ sigslot::signal2<AudioSourceContext*, cricket::BaseSession*>
+ SignalMediaStreamsReset;
+ sigslot::signal4<AudioSourceContext*, cricket::BaseSession*,
+ const cricket::MediaStreams&, const cricket::MediaStreams&>
+ SignalMediaStreamsUpdate;
+};
+
+// CurrentSpeakerMonitor can be used to monitor the audio-levels from
+// many audio-sources and report on changes in the loudest audio-source.
+// Its a generic type and relies on an AudioSourceContext which is aware of
+// the audio-sources. AudioSourceContext needs to provide two signals namely
+// SignalAudioInfoMonitor - provides audio info of the all current speakers.
+// SignalMediaSourcesUpdated - provides updates when a speaker leaves or joins.
+// Note that the AudioSourceContext's audio monitor must be started
+// before this is started.
// It's recommended that the audio monitor be started with a 100 ms period.
class CurrentSpeakerMonitor : public sigslot::has_slots<> {
public:
- CurrentSpeakerMonitor(Call* call, BaseSession* session);
+ CurrentSpeakerMonitor(AudioSourceContext* audio_source_context,
+ BaseSession* session);
~CurrentSpeakerMonitor();
BaseSession* session() const { return session_; }
@@ -62,16 +80,19 @@ class CurrentSpeakerMonitor : public sigslot::has_slots<> {
void set_min_time_between_switches(uint32 min_time_between_switches);
// This is fired when the current speaker changes, and provides his audio
- // SSRC. This only fires after the audio monitor on the underlying Call has
- // been started.
+ // SSRC. This only fires after the audio monitor on the underlying
+ // AudioSourceContext has been started.
sigslot::signal2<CurrentSpeakerMonitor*, uint32> SignalUpdate;
private:
- void OnAudioMonitor(Call* call, const AudioInfo& info);
- void OnMediaStreamsUpdate(Call* call,
- Session* session,
+ void OnAudioMonitor(AudioSourceContext* audio_source_context,
+ const AudioInfo& info);
+ void OnMediaStreamsUpdate(AudioSourceContext* audio_source_context,
+ BaseSession* session,
const MediaStreams& added,
const MediaStreams& removed);
+ void OnMediaStreamsReset(AudioSourceContext* audio_source_context,
+ BaseSession* session);
// These are states that a participant will pass through so that we gradually
// recognize that they have started and stopped speaking. This avoids
@@ -85,7 +106,7 @@ class CurrentSpeakerMonitor : public sigslot::has_slots<> {
};
bool started_;
- Call* call_;
+ AudioSourceContext* audio_source_context_;
BaseSession* session_;
std::map<uint32, SpeakingState> ssrc_to_speaking_state_map_;
uint32 current_speaker_ssrc_;
diff --git a/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor_unittest.cc b/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor_unittest.cc
index 84c76185545..b65611f6d01 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/currentspeakermonitor_unittest.cc
@@ -47,7 +47,7 @@ class MockCall : public Call {
MockCall() : Call(NULL) {}
void EmitAudioMonitor(const AudioInfo& info) {
- SignalAudioMonitor(this, info);
+ GetAudioSourceProxy()->SignalAudioMonitor(GetAudioSourceProxy(), info);
}
};
@@ -56,7 +56,7 @@ class CurrentSpeakerMonitorTest : public testing::Test,
public:
CurrentSpeakerMonitorTest() {
call_ = new MockCall();
- monitor_ = new CurrentSpeakerMonitor(call_, NULL);
+ monitor_ = new CurrentSpeakerMonitor(call_->GetAudioSourceProxy(), NULL);
// Shrink the minimum time betweeen switches to 10 ms so we don't have to
// slow down our tests.
monitor_->set_min_time_between_switches(kMinTimeBetweenSwitches);
diff --git a/chromium/third_party/libjingle/source/talk/session/media/externalhmac.cc b/chromium/third_party/libjingle/source/talk/session/media/externalhmac.cc
new file mode 100644
index 00000000000..470668d7656
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/session/media/externalhmac.cc
@@ -0,0 +1,173 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(HAVE_SRTP) && defined(ENABLE_EXTERNAL_AUTH)
+
+#include "talk/session/media/externalhmac.h"
+
+#include <stdlib.h> // For malloc/free.
+
+#ifdef SRTP_RELATIVE_PATH
+#include "srtp.h" // NOLINT
+#else
+#include "third_party/libsrtp/include/srtp.h"
+#endif // SRTP_RELATIVE_PATH
+
+#include "talk/base/logging.h"
+
+// Begin test case 0 */
+static const uint8_t kExternalHmacTestCase0Key[20] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+};
+
+static const uint8_t kExternalHmacTestCase0Data[8] = {
+ 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 // "Hi There"
+};
+
+static const uint8_t kExternalHmacFakeTag[10] = {
+ 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd
+};
+
+static const auth_test_case_t kExternalHmacTestCase0 = {
+ 20, // Octets in key
+ const_cast<uint8_t*>(kExternalHmacTestCase0Key), // Key
+ 8, // Octets in data
+ const_cast<uint8_t*>(kExternalHmacTestCase0Data), // Data
+ 10, // Octets in tag
+ const_cast<uint8_t*>(kExternalHmacFakeTag), // Tag
+ NULL // Pointer to next
+ // testcase
+};
+
+static const char kExternalHmacDescription[] =
+ "external hmac sha-1 authentication";
+
+// auth_type_t external_hmac is the hmac metaobject
+
+static const auth_type_t external_hmac = {
+ external_hmac_alloc,
+ external_hmac_dealloc,
+ (auth_init_func) external_hmac_init,
+ (auth_compute_func) external_hmac_compute,
+ (auth_update_func) external_hmac_update,
+ (auth_start_func) external_hmac_start,
+ const_cast<char*>(kExternalHmacDescription),
+ 0, // Instance count.
+ const_cast<auth_test_case_t*>(&kExternalHmacTestCase0),
+ NULL, // No debugging module.
+ EXTERNAL_HMAC_SHA1
+};
+
+
+err_status_t external_hmac_alloc(auth_t** a, int key_len, int out_len) {
+ uint8_t* pointer;
+
+ // Check key length - note that we don't support keys larger
+ // than 20 bytes yet
+ if (key_len > 20)
+ return err_status_bad_param;
+
+ // Check output length - should be less than 20 bytes/
+ if (out_len > 20)
+ return err_status_bad_param;
+
+ // Allocate memory for auth and hmac_ctx_t structures.
+ pointer = new uint8_t[(sizeof(external_hmac_ctx_t) + sizeof(auth_t))];
+ if (pointer == NULL)
+ return err_status_alloc_fail;
+
+ // Set pointers
+ *a = (auth_t *)pointer;
+ // |external_hmac| is const and libsrtp expects |type| to be non-const.
+ // const conversion is required. |external_hmac| is constant because we don't
+ // want to increase global count in Chrome.
+ (*a)->type = const_cast<auth_type_t*>(&external_hmac);
+ (*a)->state = pointer + sizeof(auth_t);
+ (*a)->out_len = out_len;
+ (*a)->key_len = key_len;
+ (*a)->prefix_len = 0;
+
+ return err_status_ok;
+}
+
+err_status_t external_hmac_dealloc(auth_t* a) {
+ // Zeroize entire state
+ memset((uint8_t *)a, 0, sizeof(external_hmac_ctx_t) + sizeof(auth_t));
+
+ // Free memory
+ delete[] a;
+
+ return err_status_ok;
+}
+
+err_status_t external_hmac_init(external_hmac_ctx_t* state,
+ const uint8_t* key,
+ int key_len) {
+ if (key_len > HMAC_KEY_LENGTH)
+ return err_status_bad_param;
+
+ memset(state->key, 0, key_len);
+ memcpy(state->key, key, key_len);
+ state->key_length = key_len;
+ return err_status_ok;
+}
+
+err_status_t external_hmac_start(external_hmac_ctx_t* state) {
+ return err_status_ok;
+}
+
+err_status_t external_hmac_update(external_hmac_ctx_t* state,
+ const uint8_t* message,
+ int msg_octets) {
+ return err_status_ok;
+}
+
+err_status_t external_hmac_compute(external_hmac_ctx_t* state,
+ const void* message,
+ int msg_octets,
+ int tag_len,
+ uint8_t* result) {
+ memcpy(result, kExternalHmacFakeTag, tag_len);
+ return err_status_ok;
+}
+
+err_status_t external_crypto_init() {
+ // |external_hmac| is const. const_cast is required as libsrtp expects
+ // non-const.
+ err_status_t status = crypto_kernel_replace_auth_type(
+ const_cast<auth_type_t*>(&external_hmac), EXTERNAL_HMAC_SHA1);
+ if (status) {
+ LOG(LS_ERROR) << "Error in replacing default auth module, error: "
+ << status;
+ return err_status_fail;
+ }
+ return err_status_ok;
+}
+
+#endif // defined(HAVE_SRTP) && defined(ENABLE_EXTERNAL_AUTH)
diff --git a/chromium/third_party/libjingle/source/talk/session/media/externalhmac.h b/chromium/third_party/libjingle/source/talk/session/media/externalhmac.h
new file mode 100644
index 00000000000..287d9680a7a
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/session/media/externalhmac.h
@@ -0,0 +1,90 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_SESSION_MEDIA_EXTERNAL_HMAC_H_
+#define TALK_SESSION_MEDIA_EXTERNAL_HMAC_H_
+
+// External libsrtp HMAC auth module which implements methods defined in
+// auth_type_t.
+// The default auth module will be replaced only when the ENABLE_EXTERNAL_AUTH
+// flag is enabled. This allows us to access to authentication keys,
+// as the default auth implementation doesn't provide access and avoids
+// hashing each packet twice.
+
+// How will libsrtp select this module?
+// Libsrtp defines authentication function types identified by an unsigned
+// integer, e.g. HMAC_SHA1 is 3. Using authentication ids, the application
+// can plug any desired authentication modules into libsrtp.
+// libsrtp also provides a mechanism to select different auth functions for
+// individual streams. This can be done by setting the right value in
+// the auth_type of srtp_policy_t. The application must first register auth
+// functions and the corresponding authentication id using
+// crypto_kernel_replace_auth_type function.
+#if defined(HAVE_SRTP) && defined(ENABLE_EXTERNAL_AUTH)
+
+#include "talk/base/basictypes.h"
+#ifdef SRTP_RELATIVE_PATH
+#include "auth.h" // NOLINT
+#else
+#include "third_party/libsrtp/crypto/include/auth.h"
+#endif // SRTP_RELATIVE_PATH
+
+#define EXTERNAL_HMAC_SHA1 HMAC_SHA1 + 1
+#define HMAC_KEY_LENGTH 20
+
+// The HMAC context structure used to store authentication keys.
+// The pointer to the key will be allocated in the external_hmac_init function.
+// This pointer is owned by srtp_t in a template context.
+typedef struct {
+ uint8 key[HMAC_KEY_LENGTH];
+ int key_length;
+} external_hmac_ctx_t;
+
+err_status_t external_hmac_alloc(auth_t** a, int key_len, int out_len);
+
+err_status_t external_hmac_dealloc(auth_t* a);
+
+err_status_t external_hmac_init(external_hmac_ctx_t* state,
+ const uint8_t* key,
+ int key_len);
+
+err_status_t external_hmac_start(external_hmac_ctx_t* state);
+
+err_status_t external_hmac_update(external_hmac_ctx_t* state,
+ const uint8_t* message,
+ int msg_octets);
+
+err_status_t external_hmac_compute(external_hmac_ctx_t* state,
+ const void* message,
+ int msg_octets,
+ int tag_len,
+ uint8_t* result);
+
+err_status_t external_crypto_init();
+
+#endif // defined(HAVE_SRTP) && defined(ENABLE_EXTERNAL_AUTH)
+#endif // TALK_SESSION_MEDIA_EXTERNAL_HMAC_H_
diff --git a/chromium/third_party/libjingle/source/talk/session/media/mediamessages.cc b/chromium/third_party/libjingle/source/talk/session/media/mediamessages.cc
index 6b5d03cf95d..45c6c7965f1 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/mediamessages.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/mediamessages.cc
@@ -52,13 +52,6 @@ bool ParseSsrc(const std::string& string, uint32* ssrc) {
return talk_base::FromString(string, ssrc);
}
-bool ParseSsrc(const buzz::XmlElement* element, uint32* ssrc) {
- if (element == NULL) {
- return false;
- }
- return ParseSsrc(element->BodyText(), ssrc);
-}
-
// Builds a <view> element according to the following spec:
// goto/jinglemuc
buzz::XmlElement* CreateViewElem(const std::string& name,
diff --git a/chromium/third_party/libjingle/source/talk/session/media/mediasession.cc b/chromium/third_party/libjingle/source/talk/session/media/mediasession.cc
index ba510b94150..006975f9319 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/mediasession.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/mediasession.cc
@@ -62,6 +62,10 @@ using talk_base::scoped_ptr;
// RFC4585
const char kMediaProtocolAvpf[] = "RTP/AVPF";
// RFC5124
+const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
+
+// This should be replaced by "UDP/TLS/RTP/SAVPF", but we need to support it for
+// now to be compatible with previous Chrome versions.
const char kMediaProtocolSavpf[] = "RTP/SAVPF";
const char kMediaProtocolRtpPrefix[] = "RTP/";
@@ -308,6 +312,20 @@ static void GetCurrentStreamParams(const SessionDescription* sdesc,
}
}
+// Filters the data codecs for the data channel type.
+void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
+ // Filter RTP codec for SCTP and vice versa.
+ int codec_id = sctp ? kGoogleRtpDataCodecId : kGoogleSctpDataCodecId;
+ for (std::vector<DataCodec>::iterator iter = codecs->begin();
+ iter != codecs->end();) {
+ if (iter->id == codec_id) {
+ iter = codecs->erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+}
+
template <typename IdStruct>
class UsedIds {
public:
@@ -398,9 +416,9 @@ class UsedRtpHeaderExtensionIds : public UsedIds<RtpHeaderExtension> {
}
private:
- // Min and Max local identifier as specified by RFC5285.
+ // Min and Max local identifier for one-byte header extensions, per RFC5285.
static const int kLocalIdMin = 1;
- static const int kLocalIdMax = 255;
+ static const int kLocalIdMax = 14;
};
static bool IsSctp(const MediaContentDescription* desc) {
@@ -691,7 +709,7 @@ template <class C>
static bool CreateMediaContentOffer(
const MediaSessionOptions& options,
const std::vector<C>& codecs,
- const SecureMediaPolicy& secure_policy,
+ const SecurePolicy& secure_policy,
const CryptoParamsVec* current_cryptos,
const std::vector<std::string>& crypto_suites,
const RtpHeaderExtensions& rtp_extensions,
@@ -701,7 +719,9 @@ static bool CreateMediaContentOffer(
offer->AddCodecs(codecs);
offer->SortCodecs();
- offer->set_crypto_required(secure_policy == SEC_REQUIRED);
+ if (secure_policy == SEC_REQUIRED) {
+ offer->set_crypto_required(CT_SDES);
+ }
offer->set_rtcp_mux(options.rtcp_mux_enabled);
offer->set_multistream(options.is_muc);
offer->set_rtp_header_extensions(rtp_extensions);
@@ -725,7 +745,7 @@ static bool CreateMediaContentOffer(
}
#endif
- if (offer->crypto_required() && offer->cryptos().empty()) {
+ if (offer->crypto_required() == CT_SDES && offer->cryptos().empty()) {
return false;
}
return true;
@@ -841,7 +861,7 @@ static bool FindByUri(const RtpHeaderExtensions& extensions,
// We assume that all URIs are given in a canonical format.
if (it->uri == ext_to_match.uri) {
if (found_extension != NULL) {
- *found_extension= *it;
+ *found_extension = *it;
}
return true;
}
@@ -852,12 +872,16 @@ static bool FindByUri(const RtpHeaderExtensions& extensions,
static void FindAndSetRtpHdrExtUsed(
const RtpHeaderExtensions& reference_extensions,
RtpHeaderExtensions* offered_extensions,
+ const RtpHeaderExtensions& other_extensions,
UsedRtpHeaderExtensionIds* used_extensions) {
for (RtpHeaderExtensions::const_iterator it = reference_extensions.begin();
it != reference_extensions.end(); ++it) {
if (!FindByUri(*offered_extensions, *it, NULL)) {
- RtpHeaderExtension ext = *it;
- used_extensions->FindAndSetIdUsed(&ext);
+ RtpHeaderExtension ext;
+ if (!FindByUri(other_extensions, *it, &ext)) {
+ ext = *it;
+ used_extensions->FindAndSetIdUsed(&ext);
+ }
offered_extensions->push_back(ext);
}
}
@@ -903,7 +927,7 @@ static bool CreateMediaContentAnswer(
const MediaContentDescriptionImpl<C>* offer,
const MediaSessionOptions& options,
const std::vector<C>& local_codecs,
- const SecureMediaPolicy& sdes_policy,
+ const SecurePolicy& sdes_policy,
const CryptoParamsVec* current_cryptos,
const RtpHeaderExtensions& local_rtp_extenstions,
StreamParamsVec* current_streams,
@@ -934,7 +958,7 @@ static bool CreateMediaContentAnswer(
}
if (answer->cryptos().empty() &&
- (offer->crypto_required() || sdes_policy == SEC_REQUIRED)) {
+ (offer->crypto_required() == CT_SDES || sdes_policy == SEC_REQUIRED)) {
return false;
}
@@ -967,17 +991,20 @@ static bool CreateMediaContentAnswer(
}
static bool IsMediaProtocolSupported(MediaType type,
- const std::string& protocol) {
+ const std::string& protocol,
+ bool secure_transport) {
// Data channels can have a protocol of SCTP or SCTP/DTLS.
if (type == MEDIA_TYPE_DATA &&
- (protocol == kMediaProtocolSctp ||
- protocol == kMediaProtocolDtlsSctp)) {
+ ((protocol == kMediaProtocolSctp && !secure_transport)||
+ (protocol == kMediaProtocolDtlsSctp && secure_transport))) {
return true;
}
+
// Since not all applications serialize and deserialize the media protocol,
// we will have to accept |protocol| to be empty.
- return protocol == kMediaProtocolAvpf || protocol == kMediaProtocolSavpf ||
- protocol.empty();
+ return protocol == kMediaProtocolAvpf || protocol.empty() ||
+ protocol == kMediaProtocolSavpf ||
+ (protocol == kMediaProtocolDtlsSavpf && secure_transport);
}
static void SetMediaProtocol(bool secure_transport,
@@ -1024,6 +1051,25 @@ static bool IsDtlsActive(
return current_tdesc->secure();
}
+std::string MediaTypeToString(MediaType type) {
+ std::string type_str;
+ switch (type) {
+ case MEDIA_TYPE_AUDIO:
+ type_str = "audio";
+ break;
+ case MEDIA_TYPE_VIDEO:
+ type_str = "video";
+ break;
+ case MEDIA_TYPE_DATA:
+ type_str = "data";
+ break;
+ default:
+ ASSERT(false);
+ break;
+ }
+ return type_str;
+}
+
void MediaSessionOptions::AddStream(MediaType type,
const std::string& id,
const std::string& sync_label) {
@@ -1179,6 +1225,8 @@ SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
scoped_ptr<DataContentDescription> data(new DataContentDescription());
bool is_sctp = (options.data_channel_type == DCT_SCTP);
+ FilterDataCodecs(&data_codecs, is_sctp);
+
cricket::SecurePolicy sdes_policy =
IsDtlsActive(CN_DATA, current_description) ?
cricket::SEC_DISABLED : secure();
@@ -1296,8 +1344,9 @@ SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
}
bool rejected = !options.has_audio || audio_content->rejected ||
- !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
- audio_answer->protocol());
+ !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
+ audio_answer->protocol(),
+ audio_transport->secure());
if (!rejected) {
AddTransportAnswer(audio_content->name, *(audio_transport.get()),
answer.get());
@@ -1344,7 +1393,9 @@ SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
return NULL;
}
bool rejected = !options.has_video || video_content->rejected ||
- !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO, video_answer->protocol());
+ !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
+ video_answer->protocol(),
+ video_transport->secure());
if (!rejected) {
if (!AddTransportAnswer(video_content->name, *(video_transport.get()),
answer.get())) {
@@ -1372,6 +1423,10 @@ SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
if (!data_transport) {
return NULL;
}
+ bool is_sctp = (options.data_channel_type == DCT_SCTP);
+ std::vector<DataCodec> data_codecs(data_codecs_);
+ FilterDataCodecs(&data_codecs, is_sctp);
+
scoped_ptr<DataContentDescription> data_answer(
new DataContentDescription());
// Do not require or create SDES cryptos if DTLS is used.
@@ -1393,7 +1448,9 @@ SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
}
bool rejected = !options.has_data() || data_content->rejected ||
- !IsMediaProtocolSupported(MEDIA_TYPE_DATA, data_answer->protocol());
+ !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
+ data_answer->protocol(),
+ data_transport->secure());
if (!rejected) {
data_answer->set_bandwidth(options.data_bandwidth);
if (!AddTransportAnswer(data_content->name, *(data_transport.get()),
@@ -1488,6 +1545,8 @@ void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
const SessionDescription* current_description,
RtpHeaderExtensions* audio_extensions,
RtpHeaderExtensions* video_extensions) const {
+ // All header extensions allocated from the same range to avoid potential
+ // issues when using BUNDLE.
UsedRtpHeaderExtensionIds used_ids;
audio_extensions->clear();
video_extensions->clear();
@@ -1514,9 +1573,9 @@ void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
// Add our default RTP header extensions that are not in
// |current_description|.
FindAndSetRtpHdrExtUsed(audio_rtp_header_extensions(), audio_extensions,
- &used_ids);
+ *video_extensions, &used_ids);
FindAndSetRtpHdrExtUsed(video_rtp_header_extensions(), video_extensions,
- &used_ids);
+ *audio_extensions, &used_ids);
}
bool MediaSessionDescriptionFactory::AddTransportOffer(
diff --git a/chromium/third_party/libjingle/source/talk/session/media/mediasession.h b/chromium/third_party/libjingle/source/talk/session/media/mediasession.h
index ff25f5a040e..5041de0a970 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/mediasession.h
+++ b/chromium/third_party/libjingle/source/talk/session/media/mediasession.h
@@ -54,15 +54,14 @@ typedef std::vector<DataCodec> DataCodecs;
typedef std::vector<CryptoParams> CryptoParamsVec;
typedef std::vector<RtpHeaderExtension> RtpHeaderExtensions;
-// TODO(juberti): Replace SecureMediaPolicy with SecurePolicy everywhere.
-typedef SecurePolicy SecureMediaPolicy;
-
enum MediaType {
MEDIA_TYPE_AUDIO,
MEDIA_TYPE_VIDEO,
MEDIA_TYPE_DATA
};
+std::string MediaTypeToString(MediaType type);
+
enum MediaContentDirection {
MD_INACTIVE,
MD_SENDONLY,
@@ -70,11 +69,19 @@ enum MediaContentDirection {
MD_SENDRECV
};
+enum CryptoType {
+ CT_NONE,
+ CT_SDES,
+ CT_DTLS
+};
+
// RTC4585 RTP/AVPF
extern const char kMediaProtocolAvpf[];
// RFC5124 RTP/SAVPF
extern const char kMediaProtocolSavpf[];
+extern const char kMediaProtocolDtlsSavpf[];
+
extern const char kMediaProtocolRtpPrefix[];
extern const char kMediaProtocolSctp[];
@@ -153,7 +160,7 @@ class MediaContentDescription : public ContentDescription {
MediaContentDescription()
: rtcp_mux_(false),
bandwidth_(kAutoBandwidth),
- crypto_required_(false),
+ crypto_required_(CT_NONE),
rtp_header_extensions_set_(false),
multistream_(false),
conference_mode_(false),
@@ -188,9 +195,10 @@ class MediaContentDescription : public ContentDescription {
void set_cryptos(const std::vector<CryptoParams>& cryptos) {
cryptos_ = cryptos;
}
- bool crypto_required() const { return crypto_required_; }
- void set_crypto_required(bool crypto) {
- crypto_required_ = crypto;
+
+ CryptoType crypto_required() const { return crypto_required_; }
+ void set_crypto_required(CryptoType type) {
+ crypto_required_ = type;
}
const RtpHeaderExtensions& rtp_header_extensions() const {
@@ -277,7 +285,7 @@ class MediaContentDescription : public ContentDescription {
int bandwidth_;
std::string protocol_;
std::vector<CryptoParams> cryptos_;
- bool crypto_required_;
+ CryptoType crypto_required_;
std::vector<RtpHeaderExtension> rtp_header_extensions_;
bool rtp_header_extensions_set_;
bool multistream_;
@@ -312,6 +320,16 @@ class MediaContentDescriptionImpl : public MediaContentDescription {
void AddCodec(const C& codec) {
codecs_.push_back(codec);
}
+ void AddOrReplaceCodec(const C& codec) {
+ for (typename std::vector<C>::iterator iter = codecs_.begin();
+ iter != codecs_.end(); ++iter) {
+ if (iter->id == codec.id) {
+ *iter = codec;
+ return;
+ }
+ }
+ AddCodec(codec);
+ }
void AddCodecs(const std::vector<C>& codecs) {
typename std::vector<C>::const_iterator codec;
for (codec = codecs.begin(); codec != codecs.end(); ++codec) {
diff --git a/chromium/third_party/libjingle/source/talk/session/media/mediasession_unittest.cc b/chromium/third_party/libjingle/source/talk/session/media/mediasession_unittest.cc
index 0e645667162..cf492a65ee1 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/mediasession_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/mediasession_unittest.cc
@@ -41,12 +41,12 @@
#ifdef HAVE_SRTP
#define ASSERT_CRYPTO(cd, s, cs) \
- ASSERT_FALSE(cd->crypto_required()); \
+ ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
ASSERT_EQ(s, cd->cryptos().size()); \
ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
#else
#define ASSERT_CRYPTO(cd, s, cs) \
- ASSERT_FALSE(cd->crypto_required()); \
+ ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
ASSERT_EQ(0U, cd->cryptos().size());
#endif
@@ -143,6 +143,7 @@ static const RtpHeaderExtension kAudioRtpExtension1[] = {
static const RtpHeaderExtension kAudioRtpExtension2[] = {
RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
RtpHeaderExtension("http://google.com/testing/audio_something_else", 8),
+ RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
};
static const RtpHeaderExtension kAudioRtpExtensionAnswer[] = {
@@ -151,18 +152,21 @@ static const RtpHeaderExtension kAudioRtpExtensionAnswer[] = {
static const RtpHeaderExtension kVideoRtpExtension1[] = {
RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
- RtpHeaderExtension("http://google.com/testing/video_something", 15),
+ RtpHeaderExtension("http://google.com/testing/video_something", 13),
};
static const RtpHeaderExtension kVideoRtpExtension2[] = {
RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
RtpHeaderExtension("http://google.com/testing/video_something_else", 14),
+ RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
};
static const RtpHeaderExtension kVideoRtpExtensionAnswer[] = {
RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
};
+static const uint32 kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
+static const uint32 kSimSsrc[] = {10, 20, 30};
static const uint32 kFec1Ssrc[] = {10, 11};
static const uint32 kFec2Ssrc[] = {20, 21};
static const uint32 kFec3Ssrc[] = {30, 31};
@@ -192,6 +196,32 @@ class MediaSessionDescriptionFactoryTest : public testing::Test {
tdf2_.set_identity(&id2_);
}
+ // Create a video StreamParamsVec object with:
+ // - one video stream with 3 simulcast streams and FEC,
+ StreamParamsVec CreateComplexVideoStreamParamsVec() {
+ SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
+ SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
+ SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
+ SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
+
+ std::vector<SsrcGroup> ssrc_groups;
+ ssrc_groups.push_back(sim_group);
+ ssrc_groups.push_back(fec_group1);
+ ssrc_groups.push_back(fec_group2);
+ ssrc_groups.push_back(fec_group3);
+
+ StreamParams simulcast_params;
+ simulcast_params.id = kVideoTrack1;
+ simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
+ simulcast_params.ssrc_groups = ssrc_groups;
+ simulcast_params.cname = "Video_SIM_FEC";
+ simulcast_params.sync_label = kMediaStream1;
+
+ StreamParamsVec video_streams;
+ video_streams.push_back(simulcast_params);
+
+ return video_streams;
+ }
bool CompareCryptoParams(const CryptoParamsVec& c1,
const CryptoParamsVec& c2) {
@@ -1588,17 +1618,19 @@ TEST_F(MediaSessionDescriptionFactoryTest,
// extensions from the first offer/answer exchange plus the extensions only
// |f2_| offer.
// Since the default local extension id |f2_| uses has already been used by
- // |f1_| for another extensions, it is changed to 255.
+ // |f1_| for another extensions, it is changed to 13.
const RtpHeaderExtension kUpdatedAudioRtpExtensions[] = {
kAudioRtpExtensionAnswer[0],
- RtpHeaderExtension(kAudioRtpExtension2[1].uri, 255),
+ RtpHeaderExtension(kAudioRtpExtension2[1].uri, 13),
+ kAudioRtpExtension2[2],
};
// Since the default local extension id |f2_| uses has already been used by
- // |f1_| for another extensions, is is changed to 254.
+ // |f1_| for another extensions, is is changed to 12.
const RtpHeaderExtension kUpdatedVideoRtpExtensions[] = {
kVideoRtpExtensionAnswer[0],
- RtpHeaderExtension(kVideoRtpExtension2[1].uri, 254),
+ RtpHeaderExtension(kVideoRtpExtension2[1].uri, 12),
+ kVideoRtpExtension2[2],
};
const AudioContentDescription* updated_acd =
@@ -1756,6 +1788,64 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
TestCryptoWithBundle(false);
}
+// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
+// DTLS is not enabled locally.
+TEST_F(MediaSessionDescriptionFactoryTest,
+ TestOfferDtlsSavpfWithoutDtlsFailed) {
+ f1_.set_secure(SEC_ENABLED);
+ f2_.set_secure(SEC_ENABLED);
+ tdf1_.set_secure(SEC_DISABLED);
+ tdf2_.set_secure(SEC_DISABLED);
+
+ talk_base::scoped_ptr<SessionDescription> offer(
+ f1_.CreateOffer(MediaSessionOptions(), NULL));
+ ASSERT_TRUE(offer.get() != NULL);
+ ContentInfo* offer_content = offer->GetContentByName("audio");
+ ASSERT_TRUE(offer_content != NULL);
+ AudioContentDescription* offer_audio_desc =
+ static_cast<AudioContentDescription*>(offer_content->description);
+ offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
+
+ talk_base::scoped_ptr<SessionDescription> answer(
+ f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
+ ASSERT_TRUE(answer != NULL);
+ ContentInfo* answer_content = answer->GetContentByName("audio");
+ ASSERT_TRUE(answer_content != NULL);
+
+ ASSERT_TRUE(answer_content->rejected);
+}
+
+// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
+// UDP/TLS/RTP/SAVPF.
+TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
+ f1_.set_secure(SEC_ENABLED);
+ f2_.set_secure(SEC_ENABLED);
+ tdf1_.set_secure(SEC_ENABLED);
+ tdf2_.set_secure(SEC_ENABLED);
+
+ talk_base::scoped_ptr<SessionDescription> offer(
+ f1_.CreateOffer(MediaSessionOptions(), NULL));
+ ASSERT_TRUE(offer.get() != NULL);
+ ContentInfo* offer_content = offer->GetContentByName("audio");
+ ASSERT_TRUE(offer_content != NULL);
+ AudioContentDescription* offer_audio_desc =
+ static_cast<AudioContentDescription*>(offer_content->description);
+ offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
+
+ talk_base::scoped_ptr<SessionDescription> answer(
+ f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
+ ASSERT_TRUE(answer != NULL);
+
+ const ContentInfo* answer_content = answer->GetContentByName("audio");
+ ASSERT_TRUE(answer_content != NULL);
+ ASSERT_FALSE(answer_content->rejected);
+
+ const AudioContentDescription* answer_audio_desc =
+ static_cast<const AudioContentDescription*>(answer_content->description);
+ EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
+ answer_audio_desc->protocol());
+}
+
// Test that we include both SDES and DTLS in the offer, but only include SDES
// in the answer if DTLS isn't negotiated.
TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
diff --git a/chromium/third_party/libjingle/source/talk/session/media/mediasessionclient.cc b/chromium/third_party/libjingle/source/talk/session/media/mediasessionclient.cc
index 246592c617f..a5a652cc78d 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/mediasessionclient.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/mediasessionclient.cc
@@ -339,8 +339,9 @@ bool ParseGingleEncryption(const buzz::XmlElement* desc,
encryption != NULL;
encryption = encryption->NextNamed(QN_ENCRYPTION)) {
if (encryption->FirstNamed(usage) != NULL) {
- media->set_crypto_required(
- GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false));
+ if (GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false)) {
+ media->set_crypto_required(CT_SDES);
+ }
for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO);
crypto != NULL;
crypto = crypto->NextNamed(QN_CRYPTO)) {
@@ -479,8 +480,9 @@ bool ParseJingleEncryption(const buzz::XmlElement* content_elem,
return true;
}
- media->set_crypto_required(
- GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false));
+ if (GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false)) {
+ media->set_crypto_required(CT_SDES);
+ }
for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO);
crypto != NULL;
diff --git a/chromium/third_party/libjingle/source/talk/session/media/mediasessionclient_unittest.cc b/chromium/third_party/libjingle/source/talk/session/media/mediasessionclient_unittest.cc
index 1ad93722bda..7cb1ec97e39 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/mediasessionclient_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/mediasessionclient_unittest.cc
@@ -891,7 +891,6 @@ const std::string kJingleInitiateDynamicWithoutNames(
const uint32 kAudioSsrc = 4294967295U;
const uint32 kVideoSsrc = 87654321;
const uint32 kDataSsrc = 1010101;
-const uint32 kDataSid = 0;
// Note that this message does not specify a session ID. It must be populated
// before use.
const std::string kGingleAcceptWithSsrcs(
@@ -2514,6 +2513,7 @@ class MediaSessionClientTest : public sigslot::has_slots<> {
CheckDataSsrcForIncomingAccept(call_->sessions()[0]);
}
// TODO(pthatcher): Check kDataSid if DCT_SCTP.
+ // const uint32 kDataSid = 0;
}
size_t ClearStanzas() {
@@ -2751,11 +2751,11 @@ class MediaSessionClientTest : public sigslot::has_slots<> {
ClearStanzas();
}
- void MakeSignalingSecure(cricket::SecureMediaPolicy secure) {
+ void MakeSignalingSecure(cricket::SecurePolicy secure) {
client_->set_secure(secure);
}
- void ExpectCrypto(cricket::SecureMediaPolicy secure) {
+ void ExpectCrypto(cricket::SecurePolicy secure) {
MakeSignalingSecure(secure);
expect_incoming_crypto_ = true;
#ifdef HAVE_SRTP
diff --git a/chromium/third_party/libjingle/source/talk/session/media/planarfunctions_unittest.cc b/chromium/third_party/libjingle/source/talk/session/media/planarfunctions_unittest.cc
new file mode 100644
index 00000000000..32cacf99575
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/session/media/planarfunctions_unittest.cc
@@ -0,0 +1,1010 @@
+// libjingle
+// Copyright 2014 Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// 3. The name of the author may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string>
+
+#include "libyuv/convert.h"
+#include "libyuv/convert_from.h"
+#include "libyuv/convert_from_argb.h"
+#include "libyuv/format_conversion.h"
+#include "libyuv/mjpeg_decoder.h"
+#include "libyuv/planar_functions.h"
+#include "talk/base/flags.h"
+#include "talk/base/gunit.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/media/base/testutils.h"
+#include "talk/media/base/videocommon.h"
+
+// Undefine macros for the windows build.
+#undef max
+#undef min
+
+using cricket::DumpPlanarYuvTestImage;
+
+DEFINE_bool(planarfunctions_dump, false,
+ "whether to write out scaled images for inspection");
+DEFINE_int(planarfunctions_repeat, 1,
+ "how many times to perform each scaling operation (for perf testing)");
+
+namespace cricket {
+
+// Number of testing colors in each color channel.
+static const int kTestingColorChannelResolution = 6;
+
+// The total number of testing colors
+// kTestingColorNum = kTestingColorChannelResolution^3;
+static const int kTestingColorNum = kTestingColorChannelResolution *
+ kTestingColorChannelResolution * kTestingColorChannelResolution;
+
+static const int kWidth = 1280;
+static const int kHeight = 720;
+static const int kAlignment = 16;
+
+class PlanarFunctionsTest : public testing::TestWithParam<int> {
+ protected:
+ PlanarFunctionsTest() : dump_(false), repeat_(1) {
+ InitializeColorBand();
+ }
+
+ virtual void SetUp() {
+ dump_ = FLAG_planarfunctions_dump;
+ repeat_ = FLAG_planarfunctions_repeat;
+ }
+
+ // Initialize the color band for testing.
+ void InitializeColorBand() {
+ testing_color_y_.reset(new uint8[kTestingColorNum]);
+ testing_color_u_.reset(new uint8[kTestingColorNum]);
+ testing_color_v_.reset(new uint8[kTestingColorNum]);
+ testing_color_r_.reset(new uint8[kTestingColorNum]);
+ testing_color_g_.reset(new uint8[kTestingColorNum]);
+ testing_color_b_.reset(new uint8[kTestingColorNum]);
+ int color_counter = 0;
+ for (int i = 0; i < kTestingColorChannelResolution; ++i) {
+ uint8 color_r = static_cast<uint8>(
+ i * 255 / (kTestingColorChannelResolution - 1));
+ for (int j = 0; j < kTestingColorChannelResolution; ++j) {
+ uint8 color_g = static_cast<uint8>(
+ j * 255 / (kTestingColorChannelResolution - 1));
+ for (int k = 0; k < kTestingColorChannelResolution; ++k) {
+ uint8 color_b = static_cast<uint8>(
+ k * 255 / (kTestingColorChannelResolution - 1));
+ testing_color_r_[color_counter] = color_r;
+ testing_color_g_[color_counter] = color_g;
+ testing_color_b_[color_counter] = color_b;
+ // Converting the testing RGB colors to YUV colors.
+ ConvertRgbPixel(color_r, color_g, color_b,
+ &(testing_color_y_[color_counter]),
+ &(testing_color_u_[color_counter]),
+ &(testing_color_v_[color_counter]));
+ ++color_counter;
+ }
+ }
+ }
+ }
+ // Simple and slow RGB->YUV conversion. From NTSC standard, c/o Wikipedia.
+ // (from lmivideoframe_unittest.cc)
+ void ConvertRgbPixel(uint8 r, uint8 g, uint8 b,
+ uint8* y, uint8* u, uint8* v) {
+ *y = ClampUint8(.257 * r + .504 * g + .098 * b + 16);
+ *u = ClampUint8(-.148 * r - .291 * g + .439 * b + 128);
+ *v = ClampUint8(.439 * r - .368 * g - .071 * b + 128);
+ }
+
+ uint8 ClampUint8(double value) {
+ value = std::max(0., std::min(255., value));
+ uint8 uint8_value = static_cast<uint8>(value);
+ return uint8_value;
+ }
+
+ // Generate a Red-Green-Blue inter-weaving chessboard-like
+ // YUV testing image (I420/I422/I444).
+ // The pattern looks like c0 c1 c2 c3 ...
+ // c1 c2 c3 c4 ...
+ // c2 c3 c4 c5 ...
+ // ...............
+ // The size of each chrome block is (block_size) x (block_size).
+ uint8* CreateFakeYuvTestingImage(int height, int width, int block_size,
+ libyuv::JpegSubsamplingType subsample_type,
+ uint8* &y_pointer,
+ uint8* &u_pointer,
+ uint8* &v_pointer) {
+ if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
+ int y_size = height * width;
+ int u_size, v_size;
+ int vertical_sample_ratio = 1, horizontal_sample_ratio = 1;
+ switch (subsample_type) {
+ case libyuv::kJpegYuv420:
+ u_size = ((height + 1) >> 1) * ((width + 1) >> 1);
+ v_size = u_size;
+ vertical_sample_ratio = 2, horizontal_sample_ratio = 2;
+ break;
+ case libyuv::kJpegYuv422:
+ u_size = height * ((width + 1) >> 1);
+ v_size = u_size;
+ vertical_sample_ratio = 1, horizontal_sample_ratio = 2;
+ break;
+ case libyuv::kJpegYuv444:
+ v_size = u_size = y_size;
+ vertical_sample_ratio = 1, horizontal_sample_ratio = 1;
+ break;
+ case libyuv::kJpegUnknown:
+ default:
+ return NULL;
+ break;
+ }
+ uint8* image_pointer = new uint8[y_size + u_size + v_size + kAlignment];
+ y_pointer = ALIGNP(image_pointer, kAlignment);
+ u_pointer = ALIGNP(&image_pointer[y_size], kAlignment);
+ v_pointer = ALIGNP(&image_pointer[y_size + u_size], kAlignment);
+ uint8* current_y_pointer = y_pointer;
+ uint8* current_u_pointer = u_pointer;
+ uint8* current_v_pointer = v_pointer;
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ int color = ((i / block_size) + (j / block_size)) % kTestingColorNum;
+ *(current_y_pointer++) = testing_color_y_[color];
+ if (i % horizontal_sample_ratio == 0 &&
+ j % vertical_sample_ratio == 0) {
+ *(current_u_pointer++) = testing_color_u_[color];
+ *(current_v_pointer++) = testing_color_v_[color];
+ }
+ }
+ }
+ return image_pointer;
+ }
+
+ // Generate a Red-Green-Blue inter-weaving chessboard-like
+ // YUY2/UYVY testing image.
+ // The pattern looks like c0 c1 c2 c3 ...
+ // c1 c2 c3 c4 ...
+ // c2 c3 c4 c5 ...
+ // ...............
+ // The size of each chrome block is (block_size) x (block_size).
+ uint8* CreateFakeInterleaveYuvTestingImage(
+ int height, int width, int block_size,
+ uint8* &yuv_pointer, FourCC fourcc_type) {
+ if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
+ if (fourcc_type != FOURCC_YUY2 && fourcc_type != FOURCC_UYVY) {
+ LOG(LS_ERROR) << "Format " << static_cast<int>(fourcc_type)
+ << " is not supported.";
+ return NULL;
+ }
+ // Regularize the width of the output to be even.
+ int awidth = (width + 1) & ~1;
+
+ uint8* image_pointer = new uint8[2 * height * awidth + kAlignment];
+ yuv_pointer = ALIGNP(image_pointer, kAlignment);
+ uint8* current_yuv_pointer = yuv_pointer;
+ switch (fourcc_type) {
+ case FOURCC_YUY2: {
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < awidth; i += 2, current_yuv_pointer += 4) {
+ int color1 = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ int color2 = (((i + 1) / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ current_yuv_pointer[0] = testing_color_y_[color1];
+ if (i < width) {
+ current_yuv_pointer[1] = static_cast<uint8>(
+ (static_cast<uint32>(testing_color_u_[color1]) +
+ static_cast<uint32>(testing_color_u_[color2])) / 2);
+ current_yuv_pointer[2] = testing_color_y_[color2];
+ current_yuv_pointer[3] = static_cast<uint8>(
+ (static_cast<uint32>(testing_color_v_[color1]) +
+ static_cast<uint32>(testing_color_v_[color2])) / 2);
+ } else {
+ current_yuv_pointer[1] = testing_color_u_[color1];
+ current_yuv_pointer[2] = 0;
+ current_yuv_pointer[3] = testing_color_v_[color1];
+ }
+ }
+ }
+ break;
+ }
+ case FOURCC_UYVY: {
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < awidth; i += 2, current_yuv_pointer += 4) {
+ int color1 = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ int color2 = (((i + 1) / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ if (i < width) {
+ current_yuv_pointer[0] = static_cast<uint8>(
+ (static_cast<uint32>(testing_color_u_[color1]) +
+ static_cast<uint32>(testing_color_u_[color2])) / 2);
+ current_yuv_pointer[1] = testing_color_y_[color1];
+ current_yuv_pointer[2] = static_cast<uint8>(
+ (static_cast<uint32>(testing_color_v_[color1]) +
+ static_cast<uint32>(testing_color_v_[color2])) / 2);
+ current_yuv_pointer[3] = testing_color_y_[color2];
+ } else {
+ current_yuv_pointer[0] = testing_color_u_[color1];
+ current_yuv_pointer[1] = testing_color_y_[color1];
+ current_yuv_pointer[2] = testing_color_v_[color1];
+ current_yuv_pointer[3] = 0;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return image_pointer;
+ }
+ // Generate a Red-Green-Blue inter-weaving chessboard-like
+ // Q420 testing image.
+ // The pattern looks like c0 c1 c2 c3 ...
+ // c1 c2 c3 c4 ...
+ // c2 c3 c4 c5 ...
+ // ...............
+ // The size of each chrome block is (block_size) x (block_size).
+ uint8* CreateFakeQ420TestingImage(int height, int width, int block_size,
+ uint8* &y_pointer, uint8* &yuy2_pointer) {
+ if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
+ // Regularize the width of the output to be even.
+ int awidth = (width + 1) & ~1;
+
+ uint8* image_pointer = new uint8[(height / 2) * awidth * 2 +
+ ((height + 1) / 2) * width + kAlignment];
+ y_pointer = ALIGNP(image_pointer, kAlignment);
+ yuy2_pointer = y_pointer + ((height + 1) / 2) * width;
+ uint8* current_yuy2_pointer = yuy2_pointer;
+ uint8* current_y_pointer = y_pointer;
+ for (int j = 0; j < height; ++j) {
+ if (j % 2 == 0) {
+ for (int i = 0; i < width; ++i) {
+ int color = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ *(current_y_pointer++) = testing_color_y_[color];
+ }
+ } else {
+ for (int i = 0; i < awidth; i += 2, current_yuy2_pointer += 4) {
+ int color1 = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ int color2 = (((i + 1) / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ current_yuy2_pointer[0] = testing_color_y_[color1];
+ if (i < width) {
+ current_yuy2_pointer[1] = static_cast<uint8>(
+ (static_cast<uint32>(testing_color_u_[color1]) +
+ static_cast<uint32>(testing_color_u_[color2])) / 2);
+ current_yuy2_pointer[2] = testing_color_y_[color2];
+ current_yuy2_pointer[3] = static_cast<uint8>(
+ (static_cast<uint32>(testing_color_v_[color1]) +
+ static_cast<uint32>(testing_color_v_[color2])) / 2);
+ } else {
+ current_yuy2_pointer[1] = testing_color_u_[color1];
+ current_yuy2_pointer[2] = 0;
+ current_yuy2_pointer[3] = testing_color_v_[color1];
+ }
+ }
+ }
+ }
+ return image_pointer;
+ }
+
+ // Generate a Red-Green-Blue inter-weaving chessboard-like
+ // NV12 testing image.
+ // (Note: No interpolation is used.)
+ // The pattern looks like c0 c1 c2 c3 ...
+ // c1 c2 c3 c4 ...
+ // c2 c3 c4 c5 ...
+ // ...............
+ // The size of each chrome block is (block_size) x (block_size).
+ uint8* CreateFakeNV12TestingImage(int height, int width, int block_size,
+ uint8* &y_pointer, uint8* &uv_pointer) {
+ if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
+
+ uint8* image_pointer = new uint8[height * width +
+ ((height + 1) / 2) * ((width + 1) / 2) * 2 + kAlignment];
+ y_pointer = ALIGNP(image_pointer, kAlignment);
+ uv_pointer = y_pointer + height * width;
+ uint8* current_uv_pointer = uv_pointer;
+ uint8* current_y_pointer = y_pointer;
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ int color = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ *(current_y_pointer++) = testing_color_y_[color];
+ }
+ if (j % 2 == 0) {
+ for (int i = 0; i < width; i += 2, current_uv_pointer += 2) {
+ int color = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ current_uv_pointer[0] = testing_color_u_[color];
+ current_uv_pointer[1] = testing_color_v_[color];
+ }
+ }
+ }
+ return image_pointer;
+ }
+
+ // Generate a Red-Green-Blue inter-weaving chessboard-like
+ // M420 testing image.
+ // (Note: No interpolation is used.)
+ // The pattern looks like c0 c1 c2 c3 ...
+ // c1 c2 c3 c4 ...
+ // c2 c3 c4 c5 ...
+ // ...............
+ // The size of each chrome block is (block_size) x (block_size).
+ uint8* CreateFakeM420TestingImage(
+ int height, int width, int block_size, uint8* &m420_pointer) {
+ if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
+
+ uint8* image_pointer = new uint8[height * width +
+ ((height + 1) / 2) * ((width + 1) / 2) * 2 + kAlignment];
+ m420_pointer = ALIGNP(image_pointer, kAlignment);
+ uint8* current_m420_pointer = m420_pointer;
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ int color = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ *(current_m420_pointer++) = testing_color_y_[color];
+ }
+ if (j % 2 == 1) {
+ for (int i = 0; i < width; i += 2, current_m420_pointer += 2) {
+ int color = ((i / block_size) + ((j - 1) / block_size)) %
+ kTestingColorNum;
+ current_m420_pointer[0] = testing_color_u_[color];
+ current_m420_pointer[1] = testing_color_v_[color];
+ }
+ }
+ }
+ return image_pointer;
+ }
+
+ // Generate a Red-Green-Blue inter-weaving chessboard-like
+ // ARGB/ABGR/RAW/BG24 testing image.
+ // The pattern looks like c0 c1 c2 c3 ...
+ // c1 c2 c3 c4 ...
+ // c2 c3 c4 c5 ...
+ // ...............
+ // The size of each chrome block is (block_size) x (block_size).
+ uint8* CreateFakeArgbTestingImage(int height, int width, int block_size,
+ uint8* &argb_pointer, FourCC fourcc_type) {
+ if (height <= 0 || width <= 0 || block_size <= 0) { return NULL; }
+ uint8* image_pointer = NULL;
+ if (fourcc_type == FOURCC_ABGR || fourcc_type == FOURCC_BGRA ||
+ fourcc_type == FOURCC_ARGB) {
+ image_pointer = new uint8[height * width * 4 + kAlignment];
+ } else if (fourcc_type == FOURCC_RAW || fourcc_type == FOURCC_24BG) {
+ image_pointer = new uint8[height * width * 3 + kAlignment];
+ } else {
+ LOG(LS_ERROR) << "Format " << static_cast<int>(fourcc_type)
+ << " is not supported.";
+ return NULL;
+ }
+ argb_pointer = ALIGNP(image_pointer, kAlignment);
+ uint8* current_pointer = argb_pointer;
+ switch (fourcc_type) {
+ case FOURCC_ARGB: {
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ int color = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ *(current_pointer++) = testing_color_b_[color];
+ *(current_pointer++) = testing_color_g_[color];
+ *(current_pointer++) = testing_color_r_[color];
+ *(current_pointer++) = 255;
+ }
+ }
+ break;
+ }
+ case FOURCC_ABGR: {
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ int color = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ *(current_pointer++) = testing_color_r_[color];
+ *(current_pointer++) = testing_color_g_[color];
+ *(current_pointer++) = testing_color_b_[color];
+ *(current_pointer++) = 255;
+ }
+ }
+ break;
+ }
+ case FOURCC_BGRA: {
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ int color = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ *(current_pointer++) = 255;
+ *(current_pointer++) = testing_color_r_[color];
+ *(current_pointer++) = testing_color_g_[color];
+ *(current_pointer++) = testing_color_b_[color];
+ }
+ }
+ break;
+ }
+ case FOURCC_24BG: {
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ int color = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ *(current_pointer++) = testing_color_b_[color];
+ *(current_pointer++) = testing_color_g_[color];
+ *(current_pointer++) = testing_color_r_[color];
+ }
+ }
+ break;
+ }
+ case FOURCC_RAW: {
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ int color = ((i / block_size) + (j / block_size)) %
+ kTestingColorNum;
+ *(current_pointer++) = testing_color_r_[color];
+ *(current_pointer++) = testing_color_g_[color];
+ *(current_pointer++) = testing_color_b_[color];
+ }
+ }
+ break;
+ }
+ default: {
+ LOG(LS_ERROR) << "Format " << static_cast<int>(fourcc_type)
+ << " is not supported.";
+ }
+ }
+ return image_pointer;
+ }
+
+ // Check if two memory chunks are equal.
+ // (tolerate MSE errors within a threshold).
+ static bool IsMemoryEqual(const uint8* ibuf, const uint8* obuf,
+ int osize, double average_error) {
+ double sse = cricket::ComputeSumSquareError(ibuf, obuf, osize);
+ double error = sse / osize; // Mean Squared Error.
+ double PSNR = cricket::ComputePSNR(sse, osize);
+ LOG(LS_INFO) << "Image MSE: " << error << " Image PSNR: " << PSNR
+ << " First Diff Byte: " << FindDiff(ibuf, obuf, osize);
+ return (error < average_error);
+ }
+
+ // Returns the index of the first differing byte. Easier to debug than memcmp.
+ static int FindDiff(const uint8* buf1, const uint8* buf2, int len) {
+ int i = 0;
+ while (i < len && buf1[i] == buf2[i]) {
+ i++;
+ }
+ return (i < len) ? i : -1;
+ }
+
+ // Dump the result image (ARGB format).
+ void DumpArgbImage(const uint8* obuf, int width, int height) {
+ DumpPlanarArgbTestImage(GetTestName(), obuf, width, height);
+ }
+
+ // Dump the result image (YUV420 format).
+ void DumpYuvImage(const uint8* obuf, int width, int height) {
+ DumpPlanarYuvTestImage(GetTestName(), obuf, width, height);
+ }
+
+ std::string GetTestName() {
+ const testing::TestInfo* const test_info =
+ testing::UnitTest::GetInstance()->current_test_info();
+ std::string test_name(test_info->name());
+ return test_name;
+ }
+
+ bool dump_;
+ int repeat_;
+
+ // Y, U, V and R, G, B channels of testing colors.
+ talk_base::scoped_ptr<uint8[]> testing_color_y_;
+ talk_base::scoped_ptr<uint8[]> testing_color_u_;
+ talk_base::scoped_ptr<uint8[]> testing_color_v_;
+ talk_base::scoped_ptr<uint8[]> testing_color_r_;
+ talk_base::scoped_ptr<uint8[]> testing_color_g_;
+ talk_base::scoped_ptr<uint8[]> testing_color_b_;
+};
+
+TEST_F(PlanarFunctionsTest, I420Copy) {
+ uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL;
+ int y_pitch = kWidth;
+ int u_pitch = (kWidth + 1) >> 1;
+ int v_pitch = (kWidth + 1) >> 1;
+ int y_size = kHeight * kWidth;
+ int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
+ int block_size = 3;
+ // Generate a fake input image.
+ talk_base::scoped_ptr<uint8[]> yuv_input(
+ CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
+ libyuv::kJpegYuv420,
+ y_pointer, u_pointer, v_pointer));
+ // Allocate space for the output image.
+ talk_base::scoped_ptr<uint8[]> yuv_output(
+ new uint8[I420_SIZE(kHeight, kWidth) + kAlignment]);
+ uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment);
+ uint8 *u_output_pointer = y_output_pointer + y_size;
+ uint8 *v_output_pointer = u_output_pointer + uv_size;
+
+ for (int i = 0; i < repeat_; ++i) {
+ libyuv::I420Copy(y_pointer, y_pitch,
+ u_pointer, u_pitch,
+ v_pointer, v_pitch,
+ y_output_pointer, y_pitch,
+ u_output_pointer, u_pitch,
+ v_output_pointer, v_pitch,
+ kWidth, kHeight);
+ }
+
+ // Expect the copied frame to be exactly the same.
+ EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_pointer,
+ I420_SIZE(kHeight, kWidth), 1.e-6));
+
+ if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); }
+}
+
+TEST_F(PlanarFunctionsTest, I422ToI420) {
+ uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL;
+ int y_pitch = kWidth;
+ int u_pitch = (kWidth + 1) >> 1;
+ int v_pitch = (kWidth + 1) >> 1;
+ int y_size = kHeight * kWidth;
+ int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
+ int block_size = 2;
+ // Generate a fake input image.
+ talk_base::scoped_ptr<uint8[]> yuv_input(
+ CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
+ libyuv::kJpegYuv422,
+ y_pointer, u_pointer, v_pointer));
+ // Allocate space for the output image.
+ talk_base::scoped_ptr<uint8[]> yuv_output(
+ new uint8[I420_SIZE(kHeight, kWidth) + kAlignment]);
+ uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment);
+ uint8 *u_output_pointer = y_output_pointer + y_size;
+ uint8 *v_output_pointer = u_output_pointer + uv_size;
+ // Generate the expected output.
+ uint8 *y_expected_pointer = NULL, *u_expected_pointer = NULL,
+ *v_expected_pointer = NULL;
+ talk_base::scoped_ptr<uint8[]> yuv_output_expected(
+ CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
+ libyuv::kJpegYuv420,
+ y_expected_pointer, u_expected_pointer, v_expected_pointer));
+
+ for (int i = 0; i < repeat_; ++i) {
+ libyuv::I422ToI420(y_pointer, y_pitch,
+ u_pointer, u_pitch,
+ v_pointer, v_pitch,
+ y_output_pointer, y_pitch,
+ u_output_pointer, u_pitch,
+ v_output_pointer, v_pitch,
+ kWidth, kHeight);
+ }
+
+ // Compare the output frame with what is expected; expect exactly the same.
+ // Note: MSE should be set to a larger threshold if an odd block width
+ // is used, since the conversion will be lossy.
+ EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_expected_pointer,
+ I420_SIZE(kHeight, kWidth), 1.e-6));
+
+ if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); }
+}
+
+TEST_P(PlanarFunctionsTest, Q420ToI420) {
+ // Get the unalignment offset
+ int unalignment = GetParam();
+ uint8 *y_pointer = NULL, *yuy2_pointer = NULL;
+ int y_pitch = kWidth;
+ int yuy2_pitch = 2 * ((kWidth + 1) & ~1);
+ int u_pitch = (kWidth + 1) >> 1;
+ int v_pitch = (kWidth + 1) >> 1;
+ int y_size = kHeight * kWidth;
+ int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
+ int block_size = 2;
+ // Generate a fake input image.
+ talk_base::scoped_ptr<uint8[]> yuv_input(
+ CreateFakeQ420TestingImage(kHeight, kWidth, block_size,
+ y_pointer, yuy2_pointer));
+ // Allocate space for the output image.
+ talk_base::scoped_ptr<uint8[]> yuv_output(
+ new uint8[I420_SIZE(kHeight, kWidth) + kAlignment + unalignment]);
+ uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment) +
+ unalignment;
+ uint8 *u_output_pointer = y_output_pointer + y_size;
+ uint8 *v_output_pointer = u_output_pointer + uv_size;
+ // Generate the expected output.
+ uint8 *y_expected_pointer = NULL, *u_expected_pointer = NULL,
+ *v_expected_pointer = NULL;
+ talk_base::scoped_ptr<uint8[]> yuv_output_expected(
+ CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
+ libyuv::kJpegYuv420,
+ y_expected_pointer, u_expected_pointer, v_expected_pointer));
+
+ for (int i = 0; i < repeat_; ++i) {
+ libyuv::Q420ToI420(y_pointer, y_pitch,
+ yuy2_pointer, yuy2_pitch,
+ y_output_pointer, y_pitch,
+ u_output_pointer, u_pitch,
+ v_output_pointer, v_pitch,
+ kWidth, kHeight);
+ }
+ // Compare the output frame with what is expected; expect exactly the same.
+ // Note: MSE should be set to a larger threshold if an odd block width
+ // is used, since the conversion will be lossy.
+ EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_expected_pointer,
+ I420_SIZE(kHeight, kWidth), 1.e-6));
+
+ if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); }
+}
+
+TEST_P(PlanarFunctionsTest, M420ToI420) {
+ // Get the unalignment offset
+ int unalignment = GetParam();
+ uint8 *m420_pointer = NULL;
+ int y_pitch = kWidth;
+ int m420_pitch = kWidth;
+ int u_pitch = (kWidth + 1) >> 1;
+ int v_pitch = (kWidth + 1) >> 1;
+ int y_size = kHeight * kWidth;
+ int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
+ int block_size = 2;
+ // Generate a fake input image.
+ talk_base::scoped_ptr<uint8[]> yuv_input(
+ CreateFakeM420TestingImage(kHeight, kWidth, block_size, m420_pointer));
+ // Allocate space for the output image.
+ talk_base::scoped_ptr<uint8[]> yuv_output(
+ new uint8[I420_SIZE(kHeight, kWidth) + kAlignment + unalignment]);
+ uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment) + unalignment;
+ uint8 *u_output_pointer = y_output_pointer + y_size;
+ uint8 *v_output_pointer = u_output_pointer + uv_size;
+ // Generate the expected output.
+ uint8 *y_expected_pointer = NULL, *u_expected_pointer = NULL,
+ *v_expected_pointer = NULL;
+ talk_base::scoped_ptr<uint8[]> yuv_output_expected(
+ CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
+ libyuv::kJpegYuv420,
+ y_expected_pointer, u_expected_pointer, v_expected_pointer));
+
+ for (int i = 0; i < repeat_; ++i) {
+ libyuv::M420ToI420(m420_pointer, m420_pitch,
+ y_output_pointer, y_pitch,
+ u_output_pointer, u_pitch,
+ v_output_pointer, v_pitch,
+ kWidth, kHeight);
+ }
+ // Compare the output frame with what is expected; expect exactly the same.
+ // Note: MSE should be set to a larger threshold if an odd block width
+ // is used, since the conversion will be lossy.
+ EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_expected_pointer,
+ I420_SIZE(kHeight, kWidth), 1.e-6));
+
+ if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); }
+}
+
+TEST_P(PlanarFunctionsTest, NV12ToI420) {
+ // Get the unalignment offset
+ int unalignment = GetParam();
+ uint8 *y_pointer = NULL, *uv_pointer = NULL;
+ int y_pitch = kWidth;
+ int uv_pitch = 2 * ((kWidth + 1) >> 1);
+ int u_pitch = (kWidth + 1) >> 1;
+ int v_pitch = (kWidth + 1) >> 1;
+ int y_size = kHeight * kWidth;
+ int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
+ int block_size = 2;
+ // Generate a fake input image.
+ talk_base::scoped_ptr<uint8[]> yuv_input(
+ CreateFakeNV12TestingImage(kHeight, kWidth, block_size,
+ y_pointer, uv_pointer));
+ // Allocate space for the output image.
+ talk_base::scoped_ptr<uint8[]> yuv_output(
+ new uint8[I420_SIZE(kHeight, kWidth) + kAlignment + unalignment]);
+ uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment) + unalignment;
+ uint8 *u_output_pointer = y_output_pointer + y_size;
+ uint8 *v_output_pointer = u_output_pointer + uv_size;
+ // Generate the expected output.
+ uint8 *y_expected_pointer = NULL, *u_expected_pointer = NULL,
+ *v_expected_pointer = NULL;
+ talk_base::scoped_ptr<uint8[]> yuv_output_expected(
+ CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
+ libyuv::kJpegYuv420,
+ y_expected_pointer, u_expected_pointer, v_expected_pointer));
+
+ for (int i = 0; i < repeat_; ++i) {
+ libyuv::NV12ToI420(y_pointer, y_pitch,
+ uv_pointer, uv_pitch,
+ y_output_pointer, y_pitch,
+ u_output_pointer, u_pitch,
+ v_output_pointer, v_pitch,
+ kWidth, kHeight);
+ }
+ // Compare the output frame with what is expected; expect exactly the same.
+ // Note: MSE should be set to a larger threshold if an odd block width
+ // is used, since the conversion will be lossy.
+ EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_expected_pointer,
+ I420_SIZE(kHeight, kWidth), 1.e-6));
+
+ if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); }
+}
+
+// A common macro for testing converting YUY2/UYVY to I420.
+#define TEST_YUVTOI420(SRC_NAME, MSE, BLOCK_SIZE) \
+TEST_P(PlanarFunctionsTest, SRC_NAME##ToI420) { \
+ /* Get the unalignment offset.*/ \
+ int unalignment = GetParam(); \
+ uint8 *yuv_pointer = NULL; \
+ int yuv_pitch = 2 * ((kWidth + 1) & ~1); \
+ int y_pitch = kWidth; \
+ int u_pitch = (kWidth + 1) >> 1; \
+ int v_pitch = (kWidth + 1) >> 1; \
+ int y_size = kHeight * kWidth; \
+ int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1); \
+ int block_size = 2; \
+ /* Generate a fake input image.*/ \
+ talk_base::scoped_ptr<uint8[]> yuv_input( \
+ CreateFakeInterleaveYuvTestingImage(kHeight, kWidth, BLOCK_SIZE, \
+ yuv_pointer, FOURCC_##SRC_NAME)); \
+ /* Allocate space for the output image.*/ \
+ talk_base::scoped_ptr<uint8[]> yuv_output( \
+ new uint8[I420_SIZE(kHeight, kWidth) + kAlignment + unalignment]); \
+ uint8 *y_output_pointer = ALIGNP(yuv_output.get(), kAlignment) + \
+ unalignment; \
+ uint8 *u_output_pointer = y_output_pointer + y_size; \
+ uint8 *v_output_pointer = u_output_pointer + uv_size; \
+ /* Generate the expected output.*/ \
+ uint8 *y_expected_pointer = NULL, *u_expected_pointer = NULL, \
+ *v_expected_pointer = NULL; \
+ talk_base::scoped_ptr<uint8[]> yuv_output_expected( \
+ CreateFakeYuvTestingImage(kHeight, kWidth, block_size, \
+ libyuv::kJpegYuv420, \
+ y_expected_pointer, u_expected_pointer, v_expected_pointer)); \
+ for (int i = 0; i < repeat_; ++i) { \
+ libyuv::SRC_NAME##ToI420(yuv_pointer, yuv_pitch, \
+ y_output_pointer, y_pitch, \
+ u_output_pointer, u_pitch, \
+ v_output_pointer, v_pitch, \
+ kWidth, kHeight); \
+ } \
+ /* Compare the output frame with what is expected.*/ \
+ /* Note: MSE should be set to a larger threshold if an odd block width*/ \
+ /* is used, since the conversion will be lossy.*/ \
+ EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_expected_pointer, \
+ I420_SIZE(kHeight, kWidth), MSE)); \
+ if (dump_) { DumpYuvImage(y_output_pointer, kWidth, kHeight); } \
+} \
+
+// TEST_P(PlanarFunctionsTest, YUV2ToI420)
+TEST_YUVTOI420(YUY2, 1.e-6, 2);
+// TEST_P(PlanarFunctionsTest, UYVYToI420)
+TEST_YUVTOI420(UYVY, 1.e-6, 2);
+
+// A common macro for testing converting I420 to ARGB, BGRA and ABGR.
+#define TEST_YUVTORGB(SRC_NAME, DST_NAME, JPG_TYPE, MSE, BLOCK_SIZE) \
+TEST_F(PlanarFunctionsTest, SRC_NAME##To##DST_NAME) { \
+ uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL; \
+ uint8 *argb_expected_pointer = NULL; \
+ int y_pitch = kWidth; \
+ int u_pitch = (kWidth + 1) >> 1; \
+ int v_pitch = (kWidth + 1) >> 1; \
+ /* Generate a fake input image.*/ \
+ talk_base::scoped_ptr<uint8[]> yuv_input( \
+ CreateFakeYuvTestingImage(kHeight, kWidth, BLOCK_SIZE, JPG_TYPE, \
+ y_pointer, u_pointer, v_pointer)); \
+ /* Generate the expected output.*/ \
+ talk_base::scoped_ptr<uint8[]> argb_expected( \
+ CreateFakeArgbTestingImage(kHeight, kWidth, BLOCK_SIZE, \
+ argb_expected_pointer, FOURCC_##DST_NAME)); \
+ /* Allocate space for the output.*/ \
+ talk_base::scoped_ptr<uint8[]> argb_output( \
+ new uint8[kHeight * kWidth * 4 + kAlignment]); \
+ uint8 *argb_pointer = ALIGNP(argb_expected.get(), kAlignment); \
+ for (int i = 0; i < repeat_; ++i) { \
+ libyuv::SRC_NAME##To##DST_NAME(y_pointer, y_pitch, \
+ u_pointer, u_pitch, \
+ v_pointer, v_pitch, \
+ argb_pointer, \
+ kWidth * 4, \
+ kWidth, kHeight); \
+ } \
+ EXPECT_TRUE(IsMemoryEqual(argb_expected_pointer, argb_pointer, \
+ kHeight * kWidth * 4, MSE)); \
+ if (dump_) { DumpArgbImage(argb_pointer, kWidth, kHeight); } \
+}
+
+// TEST_F(PlanarFunctionsTest, I420ToARGB)
+TEST_YUVTORGB(I420, ARGB, libyuv::kJpegYuv420, 3., 2);
+// TEST_F(PlanarFunctionsTest, I420ToABGR)
+TEST_YUVTORGB(I420, ABGR, libyuv::kJpegYuv420, 3., 2);
+// TEST_F(PlanarFunctionsTest, I420ToBGRA)
+TEST_YUVTORGB(I420, BGRA, libyuv::kJpegYuv420, 3., 2);
+// TEST_F(PlanarFunctionsTest, I422ToARGB)
+TEST_YUVTORGB(I422, ARGB, libyuv::kJpegYuv422, 3., 2);
+// TEST_F(PlanarFunctionsTest, I444ToARGB)
+TEST_YUVTORGB(I444, ARGB, libyuv::kJpegYuv444, 3., 3);
+// Note: an empirical MSE tolerance 3.0 is used here for the probable
+// error from float-to-uint8 type conversion.
+
+TEST_F(PlanarFunctionsTest, I400ToARGB_Reference) {
+ uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL;
+ int y_pitch = kWidth;
+ int u_pitch = (kWidth + 1) >> 1;
+ int v_pitch = (kWidth + 1) >> 1;
+ int block_size = 3;
+ // Generate a fake input image.
+ talk_base::scoped_ptr<uint8[]> yuv_input(
+ CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
+ libyuv::kJpegYuv420,
+ y_pointer, u_pointer, v_pointer));
+ // As the comparison standard, we convert a grayscale image (by setting both
+ // U and V channels to be 128) using an I420 converter.
+ int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
+
+ talk_base::scoped_ptr<uint8[]> uv(new uint8[uv_size + kAlignment]);
+ u_pointer = v_pointer = ALIGNP(uv.get(), kAlignment);
+ memset(u_pointer, 128, uv_size);
+
+ // Allocate space for the output image and generate the expected output.
+ talk_base::scoped_ptr<uint8[]> argb_expected(
+ new uint8[kHeight * kWidth * 4 + kAlignment]);
+ talk_base::scoped_ptr<uint8[]> argb_output(
+ new uint8[kHeight * kWidth * 4 + kAlignment]);
+ uint8 *argb_expected_pointer = ALIGNP(argb_expected.get(), kAlignment);
+ uint8 *argb_pointer = ALIGNP(argb_output.get(), kAlignment);
+
+ libyuv::I420ToARGB(y_pointer, y_pitch,
+ u_pointer, u_pitch,
+ v_pointer, v_pitch,
+ argb_expected_pointer, kWidth * 4,
+ kWidth, kHeight);
+ for (int i = 0; i < repeat_; ++i) {
+ libyuv::I400ToARGB_Reference(y_pointer, y_pitch,
+ argb_pointer, kWidth * 4,
+ kWidth, kHeight);
+ }
+
+ // Note: I420ToARGB and I400ToARGB_Reference should produce identical results.
+ EXPECT_TRUE(IsMemoryEqual(argb_expected_pointer, argb_pointer,
+ kHeight * kWidth * 4, 2.));
+ if (dump_) { DumpArgbImage(argb_pointer, kWidth, kHeight); }
+}
+
+TEST_P(PlanarFunctionsTest, I400ToARGB) {
+ // Get the unalignment offset
+ int unalignment = GetParam();
+ uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL;
+ int y_pitch = kWidth;
+ int u_pitch = (kWidth + 1) >> 1;
+ int v_pitch = (kWidth + 1) >> 1;
+ int block_size = 3;
+ // Generate a fake input image.
+ talk_base::scoped_ptr<uint8[]> yuv_input(
+ CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
+ libyuv::kJpegYuv420,
+ y_pointer, u_pointer, v_pointer));
+ // As the comparison standard, we convert a grayscale image (by setting both
+ // U and V channels to be 128) using an I420 converter.
+ int uv_size = ((kHeight + 1) >> 1) * ((kWidth + 1) >> 1);
+
+ // 1 byte extra if in the unaligned mode.
+ talk_base::scoped_ptr<uint8[]> uv(new uint8[uv_size * 2 + kAlignment]);
+ u_pointer = ALIGNP(uv.get(), kAlignment);
+ v_pointer = u_pointer + uv_size;
+ memset(u_pointer, 128, uv_size);
+ memset(v_pointer, 128, uv_size);
+
+ // Allocate space for the output image and generate the expected output.
+ talk_base::scoped_ptr<uint8[]> argb_expected(
+ new uint8[kHeight * kWidth * 4 + kAlignment]);
+ // 1 byte extra if in the misalinged mode.
+ talk_base::scoped_ptr<uint8[]> argb_output(
+ new uint8[kHeight * kWidth * 4 + kAlignment + unalignment]);
+ uint8 *argb_expected_pointer = ALIGNP(argb_expected.get(), kAlignment);
+ uint8 *argb_pointer = ALIGNP(argb_output.get(), kAlignment) + unalignment;
+
+ libyuv::I420ToARGB(y_pointer, y_pitch,
+ u_pointer, u_pitch,
+ v_pointer, v_pitch,
+ argb_expected_pointer, kWidth * 4,
+ kWidth, kHeight);
+ for (int i = 0; i < repeat_; ++i) {
+ libyuv::I400ToARGB(y_pointer, y_pitch,
+ argb_pointer, kWidth * 4,
+ kWidth, kHeight);
+ }
+
+ // Note: current I400ToARGB uses an approximate method,
+ // so the error tolerance is larger here.
+ EXPECT_TRUE(IsMemoryEqual(argb_expected_pointer, argb_pointer,
+ kHeight * kWidth * 4, 64.0));
+ if (dump_) { DumpArgbImage(argb_pointer, kWidth, kHeight); }
+}
+
+TEST_P(PlanarFunctionsTest, ARGBToI400) {
+ // Get the unalignment offset
+ int unalignment = GetParam();
+ // Create a fake ARGB input image.
+ uint8 *y_pointer = NULL, *u_pointer = NULL, *v_pointer = NULL;
+ uint8 *argb_pointer = NULL;
+ int block_size = 3;
+ // Generate a fake input image.
+ talk_base::scoped_ptr<uint8[]> argb_input(
+ CreateFakeArgbTestingImage(kHeight, kWidth, block_size,
+ argb_pointer, FOURCC_ARGB));
+ // Generate the expected output. Only Y channel is used
+ talk_base::scoped_ptr<uint8[]> yuv_expected(
+ CreateFakeYuvTestingImage(kHeight, kWidth, block_size,
+ libyuv::kJpegYuv420,
+ y_pointer, u_pointer, v_pointer));
+ // Allocate space for the Y output.
+ talk_base::scoped_ptr<uint8[]> y_output(
+ new uint8[kHeight * kWidth + kAlignment + unalignment]);
+ uint8 *y_output_pointer = ALIGNP(y_output.get(), kAlignment) + unalignment;
+
+ for (int i = 0; i < repeat_; ++i) {
+ libyuv::ARGBToI400(argb_pointer, kWidth * 4, y_output_pointer, kWidth,
+ kWidth, kHeight);
+ }
+ // Check if the output matches the input Y channel.
+ // Note: an empirical MSE tolerance 2.0 is used here for the probable
+ // error from float-to-uint8 type conversion.
+ EXPECT_TRUE(IsMemoryEqual(y_output_pointer, y_pointer,
+ kHeight * kWidth, 2.));
+ if (dump_) { DumpArgbImage(argb_pointer, kWidth, kHeight); }
+}
+
+// A common macro for testing converting RAW, BG24, BGRA, and ABGR
+// to ARGB.
+#define TEST_ARGB(SRC_NAME, FC_ID, BPP, BLOCK_SIZE) \
+TEST_P(PlanarFunctionsTest, SRC_NAME##ToARGB) { \
+ int unalignment = GetParam(); /* Get the unalignment offset.*/ \
+ uint8 *argb_expected_pointer = NULL, *src_pointer = NULL; \
+ /* Generate a fake input image.*/ \
+ talk_base::scoped_ptr<uint8[]> src_input( \
+ CreateFakeArgbTestingImage(kHeight, kWidth, BLOCK_SIZE, \
+ src_pointer, FOURCC_##FC_ID)); \
+ /* Generate the expected output.*/ \
+ talk_base::scoped_ptr<uint8[]> argb_expected( \
+ CreateFakeArgbTestingImage(kHeight, kWidth, BLOCK_SIZE, \
+ argb_expected_pointer, FOURCC_ARGB)); \
+ /* Allocate space for the output; 1 byte extra if in the unaligned mode.*/ \
+ talk_base::scoped_ptr<uint8[]> argb_output( \
+ new uint8[kHeight * kWidth * 4 + kAlignment + unalignment]); \
+ uint8 *argb_pointer = ALIGNP(argb_output.get(), kAlignment) + unalignment; \
+ for (int i = 0; i < repeat_; ++i) { \
+ libyuv:: SRC_NAME##ToARGB(src_pointer, kWidth * (BPP), argb_pointer, \
+ kWidth * 4, kWidth, kHeight); \
+ } \
+ /* Compare the result; expect identical.*/ \
+ EXPECT_TRUE(IsMemoryEqual(argb_expected_pointer, argb_pointer, \
+ kHeight * kWidth * 4, 1.e-6)); \
+ if (dump_) { DumpArgbImage(argb_pointer, kWidth, kHeight); } \
+}
+
+TEST_ARGB(RAW, RAW, 3, 3); // TEST_P(PlanarFunctionsTest, RAWToARGB)
+TEST_ARGB(BG24, 24BG, 3, 3); // TEST_P(PlanarFunctionsTest, BG24ToARGB)
+TEST_ARGB(ABGR, ABGR, 4, 3); // TEST_P(PlanarFunctionsTest, ABGRToARGB)
+TEST_ARGB(BGRA, BGRA, 4, 3); // TEST_P(PlanarFunctionsTest, BGRAToARGB)
+
+// Parameter Test: The parameter is the unalignment offset.
+// Aligned data for testing assembly versions.
+INSTANTIATE_TEST_CASE_P(PlanarFunctionsAligned, PlanarFunctionsTest,
+ ::testing::Values(0));
+
+// Purposely unalign the output argb pointer to test slow path (C version).
+INSTANTIATE_TEST_CASE_P(PlanarFunctionsMisaligned, PlanarFunctionsTest,
+ ::testing::Values(1));
+
+} // namespace cricket
diff --git a/chromium/third_party/libjingle/source/talk/session/media/srtpfilter.cc b/chromium/third_party/libjingle/source/talk/session/media/srtpfilter.cc
index 8e1c2c1c4fd..10e9514e1cb 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/srtpfilter.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/srtpfilter.cc
@@ -29,8 +29,9 @@
#include "talk/session/media/srtpfilter.h"
+#include <string.h>
+
#include <algorithm>
-#include <cstring>
#include "talk/base/base64.h"
#include "talk/base/logging.h"
@@ -44,9 +45,16 @@
#ifdef HAVE_SRTP
#ifdef SRTP_RELATIVE_PATH
#include "srtp.h" // NOLINT
+extern "C" srtp_stream_t srtp_get_stream(srtp_t srtp, uint32_t ssrc);
+#include "srtp_priv.h" // NOLINT
#else
#include "third_party/libsrtp/include/srtp.h"
+extern "C" srtp_stream_t srtp_get_stream(srtp_t srtp, uint32_t ssrc);
+#include "third_party/libsrtp/include/srtp_priv.h"
#endif // SRTP_RELATIVE_PATH
+#ifdef ENABLE_EXTERNAL_AUTH
+#include "talk/session/media/externalhmac.h"
+#endif // ENABLE_EXTERNAL_AUTH
#ifdef _DEBUG
extern "C" debug_module_t mod_srtp;
extern "C" debug_module_t mod_auth;
@@ -158,7 +166,6 @@ bool SrtpFilter::SetRtpParams(const std::string& send_cs,
LOG(LS_INFO) << "SRTP activated with negotiated parameters:"
<< " send cipher_suite " << send_cs
<< " recv cipher_suite " << recv_cs;
-
return true;
}
@@ -208,6 +215,16 @@ bool SrtpFilter::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
return send_session_->ProtectRtp(p, in_len, max_len, out_len);
}
+bool SrtpFilter::ProtectRtp(void* p, int in_len, int max_len, int* out_len,
+ int64* index) {
+ if (!IsActive()) {
+ LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
+ return false;
+ }
+
+ return send_session_->ProtectRtp(p, in_len, max_len, out_len, index);
+}
+
bool SrtpFilter::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
if (!IsActive()) {
LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
@@ -240,6 +257,15 @@ bool SrtpFilter::UnprotectRtcp(void* p, int in_len, int* out_len) {
}
}
+bool SrtpFilter::GetRtpAuthParams(uint8** key, int* key_len, int* tag_len) {
+ if (!IsActive()) {
+ LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active";
+ return false;
+ }
+
+ return send_session_->GetRtpAuthParams(key, key_len, tag_len);
+}
+
void SrtpFilter::set_signal_silent_time(uint32 signal_silent_time_in_ms) {
signal_silent_time_in_ms_ = signal_silent_time_in_ms;
if (state_ == ST_ACTIVE) {
@@ -496,6 +522,14 @@ bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
return true;
}
+bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len,
+ int64* index) {
+ if (!ProtectRtp(p, in_len, max_len, out_len)) {
+ return false;
+ }
+ return (index) ? GetSendStreamPacketIndex(p, in_len, index) : true;
+}
+
bool SrtpSession::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
if (!session_) {
LOG(LS_WARNING) << "Failed to protect SRTCP packet: no SRTP Session";
@@ -554,6 +588,43 @@ bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) {
return true;
}
+bool SrtpSession::GetRtpAuthParams(uint8** key, int* key_len,
+ int* tag_len) {
+#if defined(ENABLE_EXTERNAL_AUTH)
+ external_hmac_ctx_t* external_hmac = NULL;
+ // stream_template will be the reference context for other streams.
+ // Let's use it for getting the keys.
+ srtp_stream_ctx_t* srtp_context = session_->stream_template;
+ if (srtp_context && srtp_context->rtp_auth) {
+ external_hmac = reinterpret_cast<external_hmac_ctx_t*>(
+ srtp_context->rtp_auth->state);
+ }
+
+ if (!external_hmac) {
+ LOG(LS_ERROR) << "Failed to get auth keys from libsrtp!.";
+ return false;
+ }
+
+ *key = external_hmac->key;
+ *key_len = external_hmac->key_length;
+ *tag_len = rtp_auth_tag_len_;
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SrtpSession::GetSendStreamPacketIndex(void* p, int in_len, int64* index) {
+ srtp_hdr_t* hdr = reinterpret_cast<srtp_hdr_t*>(p);
+ srtp_stream_ctx_t* stream = srtp_get_stream(session_, hdr->ssrc);
+ if (stream == NULL)
+ return false;
+
+ // Shift packet index, put into network byte order
+ *index = be64_to_cpu(rdbx_get_packet_index(&stream->rtp_rdbx) << 16);
+ return true;
+}
+
void SrtpSession::set_signal_silent_time(uint32 signal_silent_time_in_ms) {
srtp_stat_->set_signal_silent_time(signal_silent_time_in_ms);
}
@@ -596,6 +667,16 @@ bool SrtpSession::SetKey(int type, const std::string& cs,
// TODO(astor) parse window size from WSH session-param
policy.window_size = 1024;
policy.allow_repeat_tx = 1;
+ // If external authentication option is enabled, supply custom auth module
+ // id EXTERNAL_HMAC_SHA1 in the policy structure.
+ // We want to set this option only for rtp packets.
+ // By default policy structure is initialized to HMAC_SHA1.
+#if defined(ENABLE_EXTERNAL_AUTH)
+ // Enable external HMAC authentication only for outgoing streams.
+ if (type == ssrc_any_outbound) {
+ policy.rtp.auth_type = EXTERNAL_HMAC_SHA1;
+ }
+#endif
policy.next = NULL;
int err = srtp_create(&session_, &policy);
@@ -604,6 +685,7 @@ bool SrtpSession::SetKey(int type, const std::string& cs,
return false;
}
+
rtp_auth_tag_len_ = policy.rtp.auth_tag_len;
rtcp_auth_tag_len_ = policy.rtcp.auth_tag_len;
return true;
@@ -623,7 +705,13 @@ bool SrtpSession::Init() {
LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err;
return false;
}
-
+#if defined(ENABLE_EXTERNAL_AUTH)
+ err = external_crypto_init();
+ if (err != err_status_ok) {
+ LOG(LS_ERROR) << "Failed to initialize fake auth, err=" << err;
+ return false;
+ }
+#endif
inited_ = true;
}
diff --git a/chromium/third_party/libjingle/source/talk/session/media/srtpfilter.h b/chromium/third_party/libjingle/source/talk/session/media/srtpfilter.h
index b6a269952a4..bc1735a40a4 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/srtpfilter.h
+++ b/chromium/third_party/libjingle/source/talk/session/media/srtpfilter.h
@@ -122,12 +122,18 @@ class SrtpFilter {
// Encrypts/signs an individual RTP/RTCP packet, in-place.
// If an HMAC is used, this will increase the packet size.
bool ProtectRtp(void* data, int in_len, int max_len, int* out_len);
+ // Overloaded version, outputs packet index.
+ bool ProtectRtp(void* data, int in_len, int max_len, int* out_len,
+ int64* index);
bool ProtectRtcp(void* data, int in_len, int max_len, int* out_len);
// Decrypts/verifies an invidiual RTP/RTCP packet.
// If an HMAC is used, this will decrease the packet size.
bool UnprotectRtp(void* data, int in_len, int* out_len);
bool UnprotectRtcp(void* data, int in_len, int* out_len);
+ // Returns rtp auth params from srtp context.
+ bool GetRtpAuthParams(uint8** key, int* key_len, int* tag_len);
+
// Update the silent threshold (in ms) for signaling errors.
void set_signal_silent_time(uint32 signal_silent_time_in_ms);
@@ -200,12 +206,18 @@ class SrtpSession {
// Encrypts/signs an individual RTP/RTCP packet, in-place.
// If an HMAC is used, this will increase the packet size.
bool ProtectRtp(void* data, int in_len, int max_len, int* out_len);
+ // Overloaded version, outputs packet index.
+ bool ProtectRtp(void* data, int in_len, int max_len, int* out_len,
+ int64* index);
bool ProtectRtcp(void* data, int in_len, int max_len, int* out_len);
// Decrypts/verifies an invidiual RTP/RTCP packet.
// If an HMAC is used, this will decrease the packet size.
bool UnprotectRtp(void* data, int in_len, int* out_len);
bool UnprotectRtcp(void* data, int in_len, int* out_len);
+ // Helper method to get authentication params.
+ bool GetRtpAuthParams(uint8** key, int* key_len, int* tag_len);
+
// Update the silent threshold (in ms) for signaling errors.
void set_signal_silent_time(uint32 signal_silent_time_in_ms);
@@ -217,9 +229,13 @@ class SrtpSession {
private:
bool SetKey(int type, const std::string& cs, const uint8* key, int len);
+ // Returns send stream current packet index from srtp db.
+ bool GetSendStreamPacketIndex(void* data, int in_len, int64* index);
+
static bool Init();
void HandleEvent(const srtp_event_data_t* ev);
static void HandleEventThunk(srtp_event_data_t* ev);
+
static std::list<SrtpSession*>* sessions();
srtp_t session_;
diff --git a/chromium/third_party/libjingle/source/talk/session/media/srtpfilter_unittest.cc b/chromium/third_party/libjingle/source/talk/session/media/srtpfilter_unittest.cc
index 1b4aef2796e..4f0ebd49649 100644
--- a/chromium/third_party/libjingle/source/talk/session/media/srtpfilter_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/session/media/srtpfilter_unittest.cc
@@ -522,6 +522,25 @@ TEST_F(SrtpFilterTest, TestSetParamsKeyTooShort) {
kTestKey1, kTestKeyLen - 1));
}
+#if defined(ENABLE_EXTERNAL_AUTH)
+TEST_F(SrtpFilterTest, TestGetSendAuthParams) {
+ EXPECT_TRUE(f1_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey1, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey2, kTestKeyLen));
+ EXPECT_TRUE(f1_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey1, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey2, kTestKeyLen));
+ uint8* auth_key = NULL;
+ int auth_key_len = 0, auth_tag_len = 0;
+ EXPECT_TRUE(f1_.GetRtpAuthParams(&auth_key, &auth_key_len, &auth_tag_len));
+ EXPECT_TRUE(auth_key != NULL);
+ EXPECT_EQ(20, auth_key_len);
+ EXPECT_EQ(4, auth_tag_len);
+}
+#endif
+
class SrtpSessionTest : public testing::Test {
protected:
virtual void SetUp() {
@@ -606,6 +625,17 @@ TEST_F(SrtpSessionTest, TestProtect_AES_CM_128_HMAC_SHA1_32) {
TestUnprotectRtcp(CS_AES_CM_128_HMAC_SHA1_32);
}
+TEST_F(SrtpSessionTest, TestGetSendStreamPacketIndex) {
+ EXPECT_TRUE(s1_.SetSend(CS_AES_CM_128_HMAC_SHA1_32, kTestKey1, kTestKeyLen));
+ int64 index;
+ int out_len = 0;
+ EXPECT_TRUE(s1_.ProtectRtp(rtp_packet_, rtp_len_,
+ sizeof(rtp_packet_), &out_len, &index));
+ // |index| will be shifted by 16.
+ int64 be64_index = be64_to_cpu(1 << 16);
+ EXPECT_EQ(be64_index, index);
+}
+
// Test that we fail to unprotect if someone tampers with the RTP/RTCP paylaods.
TEST_F(SrtpSessionTest, TestTamperReject) {
int out_len;
diff --git a/chromium/third_party/libjingle/source/talk/session/media/yuvscaler_unittest.cc b/chromium/third_party/libjingle/source/talk/session/media/yuvscaler_unittest.cc
new file mode 100644
index 00000000000..93ac5343aa7
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/session/media/yuvscaler_unittest.cc
@@ -0,0 +1,615 @@
+/*
+ * libjingle
+ * Copyright 2010 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sstream>
+
+#include "libyuv/cpu_id.h"
+#include "libyuv/scale.h"
+#include "talk/base/basictypes.h"
+#include "talk/base/flags.h"
+#include "talk/base/gunit.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/media/base/testutils.h"
+
+#if defined(_MSC_VER)
+#define ALIGN16(var) __declspec(align(16)) var
+#else
+#define ALIGN16(var) var __attribute__((aligned(16)))
+#endif
+
+using cricket::LoadPlanarYuvTestImage;
+using cricket::DumpPlanarYuvTestImage;
+using talk_base::scoped_ptr;
+
+DEFINE_bool(yuvscaler_dump, false,
+ "whether to write out scaled images for inspection");
+DEFINE_int(yuvscaler_repeat, 1,
+ "how many times to perform each scaling operation (for perf testing)");
+
+static const int kAlignment = 16;
+
+// TEST_UNCACHED flushes cache to test real memory performance.
+// TEST_RSTSC uses cpu cycles for more accurate benchmark of the scale function.
+#ifndef __arm__
+// #define TEST_UNCACHED 1
+// #define TEST_RSTSC 1
+#endif
+
+#if defined(TEST_UNCACHED) || defined(TEST_RSTSC)
+#ifdef _MSC_VER
+#include <emmintrin.h> // NOLINT
+#endif
+
+#if defined(__GNUC__) && defined(__i386__)
+static inline uint64 __rdtsc(void) {
+ uint32_t a, d;
+ __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));
+ return (reinterpret_cast<uint64>(d) << 32) + a;
+}
+
+static inline void _mm_clflush(volatile void *__p) {
+ asm volatile("clflush %0" : "+m" (*(volatile char *)__p));
+}
+#endif
+
+static void FlushCache(uint8* dst, int count) {
+ while (count >= 32) {
+ _mm_clflush(dst);
+ dst += 32;
+ count -= 32;
+ }
+}
+#endif
+
+class YuvScalerTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ dump_ = *FlagList::Lookup("yuvscaler_dump")->bool_variable();
+ repeat_ = *FlagList::Lookup("yuvscaler_repeat")->int_variable();
+ }
+
+ // Scale an image and compare against a Lanczos-filtered test image.
+ // Lanczos is considered to be the "ideal" image resampling method, so we try
+ // to get as close to that as possible, while being as fast as possible.
+ bool TestScale(int iw, int ih, int ow, int oh, int offset, bool usefile,
+ bool optimize, int cpuflags, bool interpolate,
+ int memoffset, double* error) {
+ *error = 0.;
+ size_t isize = I420_SIZE(iw, ih);
+ size_t osize = I420_SIZE(ow, oh);
+ scoped_ptr<uint8[]> ibuffer(new uint8[isize + kAlignment + memoffset]());
+ scoped_ptr<uint8[]> obuffer(new uint8[osize + kAlignment + memoffset]());
+ scoped_ptr<uint8[]> xbuffer(new uint8[osize + kAlignment + memoffset]());
+
+ uint8 *ibuf = ALIGNP(ibuffer.get(), kAlignment) + memoffset;
+ uint8 *obuf = ALIGNP(obuffer.get(), kAlignment) + memoffset;
+ uint8 *xbuf = ALIGNP(xbuffer.get(), kAlignment) + memoffset;
+
+ if (usefile) {
+ if (!LoadPlanarYuvTestImage("faces", iw, ih, ibuf) ||
+ !LoadPlanarYuvTestImage("faces", ow, oh, xbuf)) {
+ LOG(LS_ERROR) << "Failed to load image";
+ return false;
+ }
+ } else {
+ // These are used to test huge images.
+ memset(ibuf, 213, isize); // Input is constant color.
+ memset(obuf, 100, osize); // Output set to something wrong for now.
+ memset(xbuf, 213, osize); // Expected result.
+ }
+
+#ifdef TEST_UNCACHED
+ FlushCache(ibuf, isize);
+ FlushCache(obuf, osize);
+ FlushCache(xbuf, osize);
+#endif
+
+ // Scale down.
+ // If cpu true, disable cpu optimizations. Else allow auto detect
+ // TODO(fbarchard): set flags for libyuv
+ libyuv::MaskCpuFlags(cpuflags);
+#ifdef TEST_RSTSC
+ uint64 t = 0;
+#endif
+ for (int i = 0; i < repeat_; ++i) {
+#ifdef TEST_UNCACHED
+ FlushCache(ibuf, isize);
+ FlushCache(obuf, osize);
+#endif
+#ifdef TEST_RSTSC
+ uint64 t1 = __rdtsc();
+#endif
+ EXPECT_EQ(0, libyuv::ScaleOffset(ibuf, iw, ih, obuf, ow, oh,
+ offset, interpolate));
+#ifdef TEST_RSTSC
+ uint64 t2 = __rdtsc();
+ t += t2 - t1;
+#endif
+ }
+
+#ifdef TEST_RSTSC
+ LOG(LS_INFO) << "Time: " << std::setw(9) << t;
+#endif
+
+ if (dump_) {
+ const testing::TestInfo* const test_info =
+ testing::UnitTest::GetInstance()->current_test_info();
+ std::string test_name(test_info->name());
+ DumpPlanarYuvTestImage(test_name, obuf, ow, oh);
+ }
+
+ double sse = cricket::ComputeSumSquareError(obuf, xbuf, osize);
+ *error = sse / osize; // Mean Squared Error.
+ double PSNR = cricket::ComputePSNR(sse, osize);
+ LOG(LS_INFO) << "Image MSE: " <<
+ std::setw(6) << std::setprecision(4) << *error <<
+ " Image PSNR: " << PSNR;
+ return true;
+ }
+
+ // Returns the index of the first differing byte. Easier to debug than memcmp.
+ static int FindDiff(const uint8* buf1, const uint8* buf2, int len) {
+ int i = 0;
+ while (i < len && buf1[i] == buf2[i]) {
+ i++;
+ }
+ return (i < len) ? i : -1;
+ }
+
+ protected:
+ bool dump_;
+ int repeat_;
+};
+
+// Tests straight copy of data.
+TEST_F(YuvScalerTest, TestCopy) {
+ const int iw = 640, ih = 360;
+ const int ow = 640, oh = 360;
+ ALIGN16(uint8 ibuf[I420_SIZE(iw, ih)]);
+ ALIGN16(uint8 obuf[I420_SIZE(ow, oh)]);
+
+ // Load the frame, scale it, check it.
+ ASSERT_TRUE(LoadPlanarYuvTestImage("faces", iw, ih, ibuf));
+ for (int i = 0; i < repeat_; ++i) {
+ libyuv::ScaleOffset(ibuf, iw, ih, obuf, ow, oh, 0, false);
+ }
+ if (dump_) DumpPlanarYuvTestImage("TestCopy", obuf, ow, oh);
+ EXPECT_EQ(-1, FindDiff(obuf, ibuf, sizeof(ibuf)));
+}
+
+// Tests copy from 4:3 to 16:9.
+TEST_F(YuvScalerTest, TestOffset16_10Copy) {
+ const int iw = 640, ih = 360;
+ const int ow = 640, oh = 480;
+ const int offset = (480 - 360) / 2;
+ scoped_ptr<uint8[]> ibuffer(new uint8[I420_SIZE(iw, ih) + kAlignment]);
+ scoped_ptr<uint8[]> obuffer(new uint8[I420_SIZE(ow, oh) + kAlignment]);
+
+ uint8 *ibuf = ALIGNP(ibuffer.get(), kAlignment);
+ uint8 *obuf = ALIGNP(obuffer.get(), kAlignment);
+
+ // Load the frame, scale it, check it.
+ ASSERT_TRUE(LoadPlanarYuvTestImage("faces", iw, ih, ibuf));
+
+ // Clear to black, which is Y = 0 and U and V = 128
+ memset(obuf, 0, ow * oh);
+ memset(obuf + ow * oh, 128, ow * oh / 2);
+ for (int i = 0; i < repeat_; ++i) {
+ libyuv::ScaleOffset(ibuf, iw, ih, obuf, ow, oh, offset, false);
+ }
+ if (dump_) DumpPlanarYuvTestImage("TestOffsetCopy16_9", obuf, ow, oh);
+ EXPECT_EQ(-1, FindDiff(obuf + ow * offset,
+ ibuf,
+ iw * ih));
+ EXPECT_EQ(-1, FindDiff(obuf + ow * oh + ow * offset / 4,
+ ibuf + iw * ih,
+ iw * ih / 4));
+ EXPECT_EQ(-1, FindDiff(obuf + ow * oh * 5 / 4 + ow * offset / 4,
+ ibuf + iw * ih * 5 / 4,
+ iw * ih / 4));
+}
+
+// The following are 'cpu' flag values:
+// Allow all SIMD optimizations
+#define ALLFLAGS -1
+// Disable SSSE3 but allow other forms of SIMD (SSE2)
+#define NOSSSE3 ~libyuv::kCpuHasSSSE3
+// Disable SSE2 and SSSE3
+#define NOSSE ~libyuv::kCpuHasSSE2 & ~libyuv::kCpuHasSSSE3
+
+// TEST_M scale factor with variations of opt, align, int
+#define TEST_M(name, iwidth, iheight, owidth, oheight, mse) \
+TEST_F(YuvScalerTest, name##Ref) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, true, false, ALLFLAGS, false, 0, &error)); \
+ EXPECT_LE(error, mse); \
+} \
+TEST_F(YuvScalerTest, name##OptAligned) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, true, true, ALLFLAGS, false, 0, &error)); \
+ EXPECT_LE(error, mse); \
+} \
+TEST_F(YuvScalerTest, name##OptUnaligned) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, true, true, ALLFLAGS, false, 1, &error)); \
+ EXPECT_LE(error, mse); \
+} \
+TEST_F(YuvScalerTest, name##OptSSE2) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, true, true, NOSSSE3, false, 0, &error)); \
+ EXPECT_LE(error, mse); \
+} \
+TEST_F(YuvScalerTest, name##OptC) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, true, true, NOSSE, false, 0, &error)); \
+ EXPECT_LE(error, mse); \
+} \
+TEST_F(YuvScalerTest, name##IntRef) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, true, false, ALLFLAGS, true, 0, &error)); \
+ EXPECT_LE(error, mse); \
+} \
+TEST_F(YuvScalerTest, name##IntOptAligned) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, true, true, ALLFLAGS, true, 0, &error)); \
+ EXPECT_LE(error, mse); \
+} \
+TEST_F(YuvScalerTest, name##IntOptUnaligned) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, true, true, ALLFLAGS, true, 1, &error)); \
+ EXPECT_LE(error, mse); \
+} \
+TEST_F(YuvScalerTest, name##IntOptSSE2) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, true, true, NOSSSE3, true, 0, &error)); \
+ EXPECT_LE(error, mse); \
+} \
+TEST_F(YuvScalerTest, name##IntOptC) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, true, true, NOSSE, true, 0, &error)); \
+ EXPECT_LE(error, mse); \
+}
+
+#define TEST_H(name, iwidth, iheight, owidth, oheight, opt, cpu, intr, mse) \
+TEST_F(YuvScalerTest, name) { \
+ double error; \
+ EXPECT_TRUE(TestScale(iwidth, iheight, owidth, oheight, \
+ 0, false, opt, cpu, intr, 0, &error)); \
+ EXPECT_LE(error, mse); \
+}
+
+// Test 4x3 aspect ratio scaling
+
+// Tests 1/1x scale down.
+TEST_M(TestScale4by3Down11, 640, 480, 640, 480, 0)
+
+// Tests 3/4x scale down.
+TEST_M(TestScale4by3Down34, 640, 480, 480, 360, 60)
+
+// Tests 1/2x scale down.
+TEST_M(TestScale4by3Down12, 640, 480, 320, 240, 60)
+
+// Tests 3/8x scale down.
+TEST_M(TestScale4by3Down38, 640, 480, 240, 180, 60)
+
+// Tests 1/4x scale down..
+TEST_M(TestScale4by3Down14, 640, 480, 160, 120, 60)
+
+// Tests 3/16x scale down.
+TEST_M(TestScale4by3Down316, 640, 480, 120, 90, 120)
+
+// Tests 1/8x scale down.
+TEST_M(TestScale4by3Down18, 640, 480, 80, 60, 150)
+
+// Tests 2/3x scale down.
+TEST_M(TestScale4by3Down23, 480, 360, 320, 240, 60)
+
+// Tests 4/3x scale up.
+TEST_M(TestScale4by3Up43, 480, 360, 640, 480, 60)
+
+// Tests 2/1x scale up.
+TEST_M(TestScale4by3Up21, 320, 240, 640, 480, 60)
+
+// Tests 4/1x scale up.
+TEST_M(TestScale4by3Up41, 160, 120, 640, 480, 80)
+
+// Test 16x10 aspect ratio scaling
+
+// Tests 1/1x scale down.
+TEST_M(TestScale16by10Down11, 640, 400, 640, 400, 0)
+
+// Tests 3/4x scale down.
+TEST_M(TestScale16by10Down34, 640, 400, 480, 300, 60)
+
+// Tests 1/2x scale down.
+TEST_M(TestScale16by10Down12, 640, 400, 320, 200, 60)
+
+// Tests 3/8x scale down.
+TEST_M(TestScale16by10Down38, 640, 400, 240, 150, 60)
+
+// Tests 1/4x scale down..
+TEST_M(TestScale16by10Down14, 640, 400, 160, 100, 60)
+
+// Tests 3/16x scale down.
+TEST_M(TestScale16by10Down316, 640, 400, 120, 75, 120)
+
+// Tests 1/8x scale down.
+TEST_M(TestScale16by10Down18, 640, 400, 80, 50, 150)
+
+// Tests 2/3x scale down.
+TEST_M(TestScale16by10Down23, 480, 300, 320, 200, 60)
+
+// Tests 4/3x scale up.
+TEST_M(TestScale16by10Up43, 480, 300, 640, 400, 60)
+
+// Tests 2/1x scale up.
+TEST_M(TestScale16by10Up21, 320, 200, 640, 400, 60)
+
+// Tests 4/1x scale up.
+TEST_M(TestScale16by10Up41, 160, 100, 640, 400, 80)
+
+// Test 16x9 aspect ratio scaling
+
+// Tests 1/1x scale down.
+TEST_M(TestScaleDown11, 640, 360, 640, 360, 0)
+
+// Tests 3/4x scale down.
+TEST_M(TestScaleDown34, 640, 360, 480, 270, 60)
+
+// Tests 1/2x scale down.
+TEST_M(TestScaleDown12, 640, 360, 320, 180, 60)
+
+// Tests 3/8x scale down.
+TEST_M(TestScaleDown38, 640, 360, 240, 135, 60)
+
+// Tests 1/4x scale down..
+TEST_M(TestScaleDown14, 640, 360, 160, 90, 60)
+
+// Tests 3/16x scale down.
+TEST_M(TestScaleDown316, 640, 360, 120, 68, 120)
+
+// Tests 1/8x scale down.
+TEST_M(TestScaleDown18, 640, 360, 80, 45, 150)
+
+// Tests 2/3x scale down.
+TEST_M(TestScaleDown23, 480, 270, 320, 180, 60)
+
+// Tests 4/3x scale up.
+TEST_M(TestScaleUp43, 480, 270, 640, 360, 60)
+
+// Tests 2/1x scale up.
+TEST_M(TestScaleUp21, 320, 180, 640, 360, 60)
+
+// Tests 4/1x scale up.
+TEST_M(TestScaleUp41, 160, 90, 640, 360, 80)
+
+// Test HD 4x3 aspect ratio scaling
+
+// Tests 1/1x scale down.
+TEST_M(TestScaleHD4x3Down11, 1280, 960, 1280, 960, 0)
+
+// Tests 3/4x scale down.
+TEST_M(TestScaleHD4x3Down34, 1280, 960, 960, 720, 60)
+
+// Tests 1/2x scale down.
+TEST_M(TestScaleHD4x3Down12, 1280, 960, 640, 480, 60)
+
+// Tests 3/8x scale down.
+TEST_M(TestScaleHD4x3Down38, 1280, 960, 480, 360, 60)
+
+// Tests 1/4x scale down..
+TEST_M(TestScaleHD4x3Down14, 1280, 960, 320, 240, 60)
+
+// Tests 3/16x scale down.
+TEST_M(TestScaleHD4x3Down316, 1280, 960, 240, 180, 120)
+
+// Tests 1/8x scale down.
+TEST_M(TestScaleHD4x3Down18, 1280, 960, 160, 120, 150)
+
+// Tests 2/3x scale down.
+TEST_M(TestScaleHD4x3Down23, 960, 720, 640, 480, 60)
+
+// Tests 4/3x scale up.
+TEST_M(TestScaleHD4x3Up43, 960, 720, 1280, 960, 60)
+
+// Tests 2/1x scale up.
+TEST_M(TestScaleHD4x3Up21, 640, 480, 1280, 960, 60)
+
+// Tests 4/1x scale up.
+TEST_M(TestScaleHD4x3Up41, 320, 240, 1280, 960, 80)
+
+// Test HD 16x10 aspect ratio scaling
+
+// Tests 1/1x scale down.
+TEST_M(TestScaleHD16x10Down11, 1280, 800, 1280, 800, 0)
+
+// Tests 3/4x scale down.
+TEST_M(TestScaleHD16x10Down34, 1280, 800, 960, 600, 60)
+
+// Tests 1/2x scale down.
+TEST_M(TestScaleHD16x10Down12, 1280, 800, 640, 400, 60)
+
+// Tests 3/8x scale down.
+TEST_M(TestScaleHD16x10Down38, 1280, 800, 480, 300, 60)
+
+// Tests 1/4x scale down..
+TEST_M(TestScaleHD16x10Down14, 1280, 800, 320, 200, 60)
+
+// Tests 3/16x scale down.
+TEST_M(TestScaleHD16x10Down316, 1280, 800, 240, 150, 120)
+
+// Tests 1/8x scale down.
+TEST_M(TestScaleHD16x10Down18, 1280, 800, 160, 100, 150)
+
+// Tests 2/3x scale down.
+TEST_M(TestScaleHD16x10Down23, 960, 600, 640, 400, 60)
+
+// Tests 4/3x scale up.
+TEST_M(TestScaleHD16x10Up43, 960, 600, 1280, 800, 60)
+
+// Tests 2/1x scale up.
+TEST_M(TestScaleHD16x10Up21, 640, 400, 1280, 800, 60)
+
+// Tests 4/1x scale up.
+TEST_M(TestScaleHD16x10Up41, 320, 200, 1280, 800, 80)
+
+// Test HD 16x9 aspect ratio scaling
+
+// Tests 1/1x scale down.
+TEST_M(TestScaleHDDown11, 1280, 720, 1280, 720, 0)
+
+// Tests 3/4x scale down.
+TEST_M(TestScaleHDDown34, 1280, 720, 960, 540, 60)
+
+// Tests 1/2x scale down.
+TEST_M(TestScaleHDDown12, 1280, 720, 640, 360, 60)
+
+// Tests 3/8x scale down.
+TEST_M(TestScaleHDDown38, 1280, 720, 480, 270, 60)
+
+// Tests 1/4x scale down..
+TEST_M(TestScaleHDDown14, 1280, 720, 320, 180, 60)
+
+// Tests 3/16x scale down.
+TEST_M(TestScaleHDDown316, 1280, 720, 240, 135, 120)
+
+// Tests 1/8x scale down.
+TEST_M(TestScaleHDDown18, 1280, 720, 160, 90, 150)
+
+// Tests 2/3x scale down.
+TEST_M(TestScaleHDDown23, 960, 540, 640, 360, 60)
+
+// Tests 4/3x scale up.
+TEST_M(TestScaleHDUp43, 960, 540, 1280, 720, 60)
+
+// Tests 2/1x scale up.
+TEST_M(TestScaleHDUp21, 640, 360, 1280, 720, 60)
+
+// Tests 4/1x scale up.
+TEST_M(TestScaleHDUp41, 320, 180, 1280, 720, 80)
+
+// Tests 1366x768 resolution for comparison to chromium scaler_bench
+TEST_M(TestScaleHDUp1366, 1280, 720, 1366, 768, 10)
+
+// Tests odd source/dest sizes. 3 less to make chroma odd as well.
+TEST_M(TestScaleHDUp1363, 1277, 717, 1363, 765, 10)
+
+// Tests 1/2x scale down, using optimized algorithm.
+TEST_M(TestScaleOddDown12, 180, 100, 90, 50, 50)
+
+// Tests bilinear scale down
+TEST_M(TestScaleOddDownBilin, 160, 100, 90, 50, 120)
+
+// Test huge buffer scales that are expected to use a different code path
+// that avoids stack overflow but still work using point sampling.
+// Max output size is 640 wide.
+
+// Tests interpolated 1/8x scale down, using optimized algorithm.
+TEST_H(TestScaleDown18HDOptInt, 6144, 48, 768, 6, true, ALLFLAGS, true, 1)
+
+// Tests interpolated 1/8x scale down, using c_only optimized algorithm.
+TEST_H(TestScaleDown18HDCOnlyOptInt, 6144, 48, 768, 6, true, NOSSE, true, 1)
+
+// Tests interpolated 3/8x scale down, using optimized algorithm.
+TEST_H(TestScaleDown38HDOptInt, 2048, 16, 768, 6, true, ALLFLAGS, true, 1)
+
+// Tests interpolated 3/8x scale down, using no SSSE3 optimized algorithm.
+TEST_H(TestScaleDown38HDNoSSSE3OptInt, 2048, 16, 768, 6, true, NOSSSE3, true, 1)
+
+// Tests interpolated 3/8x scale down, using c_only optimized algorithm.
+TEST_H(TestScaleDown38HDCOnlyOptInt, 2048, 16, 768, 6, true, NOSSE, true, 1)
+
+// Tests interpolated 3/16x scale down, using optimized algorithm.
+TEST_H(TestScaleDown316HDOptInt, 4096, 32, 768, 6, true, ALLFLAGS, true, 1)
+
+// Tests interpolated 3/16x scale down, using no SSSE3 optimized algorithm.
+TEST_H(TestScaleDown316HDNoSSSE3OptInt, 4096, 32, 768, 6, true, NOSSSE3, true,
+ 1)
+
+// Tests interpolated 3/16x scale down, using c_only optimized algorithm.
+TEST_H(TestScaleDown316HDCOnlyOptInt, 4096, 32, 768, 6, true, NOSSE, true, 1)
+
+// Test special sizes dont crash
+// Tests scaling down to 1 pixel width
+TEST_H(TestScaleDown1x6OptInt, 3, 24, 1, 6, true, ALLFLAGS, true, 4)
+
+// Tests scaling down to 1 pixel height
+TEST_H(TestScaleDown6x1OptInt, 24, 3, 6, 1, true, ALLFLAGS, true, 4)
+
+// Tests scaling up from 1 pixel width
+TEST_H(TestScaleUp1x6OptInt, 1, 6, 3, 24, true, ALLFLAGS, true, 4)
+
+// Tests scaling up from 1 pixel height
+TEST_H(TestScaleUp6x1OptInt, 6, 1, 24, 3, true, ALLFLAGS, true, 4)
+
+// Test performance of a range of box filter scale sizes
+
+// Tests interpolated 1/2x scale down, using optimized algorithm.
+TEST_H(TestScaleDown2xHDOptInt, 1280, 720, 1280 / 2, 720 / 2, true, ALLFLAGS,
+ true, 1)
+
+// Tests interpolated 1/3x scale down, using optimized algorithm.
+TEST_H(TestScaleDown3xHDOptInt, 1280, 720, 1280 / 3, 720 / 3, true, ALLFLAGS,
+ true, 1)
+
+// Tests interpolated 1/4x scale down, using optimized algorithm.
+TEST_H(TestScaleDown4xHDOptInt, 1280, 720, 1280 / 4, 720 / 4, true, ALLFLAGS,
+ true, 1)
+
+// Tests interpolated 1/5x scale down, using optimized algorithm.
+TEST_H(TestScaleDown5xHDOptInt, 1280, 720, 1280 / 5, 720 / 5, true, ALLFLAGS,
+ true, 1)
+
+// Tests interpolated 1/6x scale down, using optimized algorithm.
+TEST_H(TestScaleDown6xHDOptInt, 1280, 720, 1280 / 6, 720 / 6, true, ALLFLAGS,
+ true, 1)
+
+// Tests interpolated 1/7x scale down, using optimized algorithm.
+TEST_H(TestScaleDown7xHDOptInt, 1280, 720, 1280 / 7, 720 / 7, true, ALLFLAGS,
+ true, 1)
+
+// Tests interpolated 1/8x scale down, using optimized algorithm.
+TEST_H(TestScaleDown8xHDOptInt, 1280, 720, 1280 / 8, 720 / 8, true, ALLFLAGS,
+ true, 1)
+
+// Tests interpolated 1/8x scale down, using optimized algorithm.
+TEST_H(TestScaleDown9xHDOptInt, 1280, 720, 1280 / 9, 720 / 9, true, ALLFLAGS,
+ true, 1)
+
+// Tests interpolated 1/8x scale down, using optimized algorithm.
+TEST_H(TestScaleDown10xHDOptInt, 1280, 720, 1280 / 10, 720 / 10, true, ALLFLAGS,
+ true, 1)
diff --git a/chromium/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.cc b/chromium/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.cc
index ee88797c1a1..d95dc857d56 100644
--- a/chromium/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.cc
+++ b/chromium/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.cc
@@ -504,7 +504,8 @@ IPseudoTcpNotify::WriteResult PseudoTcpChannel::TcpWritePacket(
ASSERT(cs_.CurrentThreadIsOwner());
ASSERT(tcp == tcp_);
ASSERT(NULL != channel_);
- int sent = channel_->SendPacket(buffer, len, talk_base::DSCP_NO_CHANGE);
+ talk_base::PacketOptions packet_options;
+ int sent = channel_->SendPacket(buffer, len, packet_options);
if (sent > 0) {
//LOG_F(LS_VERBOSE) << "(" << sent << ") Sent";
return IPseudoTcpNotify::WR_SUCCESS;
diff --git a/chromium/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.cc b/chromium/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.cc
index 9287d22ab5c..55f408387ba 100644
--- a/chromium/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.cc
+++ b/chromium/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.cc
@@ -360,8 +360,8 @@ void SecureTunnelSession::OnAccept() {
const std::string& cert_pem =
role_ == INITIATOR ? remote_tunnel->server_pem_certificate :
remote_tunnel->client_pem_certificate;
- talk_base::SSLCertificate* peer_cert =
- ParseCertificate(cert_pem);
+ talk_base::scoped_ptr<talk_base::SSLCertificate> peer_cert(
+ ParseCertificate(cert_pem));
if (peer_cert == NULL) {
ASSERT(role_ == INITIATOR); // when RESPONDER we validated it earlier
LOG(LS_ERROR)
@@ -373,7 +373,17 @@ void SecureTunnelSession::OnAccept() {
talk_base::SSLStreamAdapter* ssl_stream =
static_cast<talk_base::SSLStreamAdapter*>(
ssl_stream_reference_->GetStream());
- ssl_stream->SetPeerCertificate(peer_cert); // pass ownership of certificate.
+
+ std::string algorithm;
+ if (!peer_cert->GetSignatureDigestAlgorithm(&algorithm)) {
+ LOG(LS_ERROR) << "Failed to get the algorithm for the peer cert signature";
+ return;
+ }
+ unsigned char digest[talk_base::MessageDigest::kMaxSize];
+ size_t digest_len;
+ peer_cert->ComputeDigest(algorithm, digest, ARRAY_SIZE(digest), &digest_len);
+ ssl_stream->SetPeerCertificateDigest(algorithm, digest, digest_len);
+
// We no longer need our handle to the ssl stream.
ssl_stream_reference_.reset();
LOG(LS_INFO) << "Connecting tunnel";
diff --git a/chromium/third_party/libjingle/source/talk/site_scons/site_tools/talk_linux.py b/chromium/third_party/libjingle/source/talk/site_scons/site_tools/talk_linux.py
deleted file mode 100644
index acba92120f0..00000000000
--- a/chromium/third_party/libjingle/source/talk/site_scons/site_tools/talk_linux.py
+++ /dev/null
@@ -1,313 +0,0 @@
-# Copyright 2010 Google Inc.
-# All Rights Reserved.
-# Author: tschmelcher@google.com (Tristan Schmelcher)
-
-"""Tool for helpers used in linux building process."""
-
-import os
-import SCons.Defaults
-import subprocess
-
-
-def _OutputFromShellCommand(command):
- process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
- return process.communicate()[0].strip()
-
-
-# This is a pure SCons helper function.
-def _InternalBuildDebianPackage(env, debian_files, package_files,
- output_dir=None, force_version=None):
- """Creates build rules to build a Debian package from the specified sources.
-
- Args:
- env: SCons Environment.
- debian_files: Array of the Debian control file sources that should be
- copied into the package source tree, e.g., changelog, control, rules,
- etc.
- package_files: An array of 2-tuples listing the files that should be
- copied into the package source tree.
- The first element is the path where the file should be placed for the
- .install control file to find it, relative to the generated debian
- package source directory.
- The second element is the file source.
- output_dir: An optional directory to place the files in. If omitted, the
- current output directory is used.
- force_version: Optional. Forces the version of the package to start with
- this version string if specified. If the last entry in the changelog
- is not for a version that starts with this then a dummy entry is
- generated with this version and a ~prerelease suffix (so that the
- final version will compare as greater).
-
- Return:
- A list of the targets (if any).
- """
- if 0 != subprocess.call(['which', 'dpkg-buildpackage']):
- print ('dpkg-buildpackage not installed on this system; '
- 'skipping DEB build stage')
- return []
- # Read the control file and changelog file to determine the package name,
- # version, and arch that the Debian build tools will use to name the
- # generated files.
- control_file = None
- changelog_file = None
- for file_name in debian_files:
- if os.path.basename(file_name) == 'control':
- control_file = env.File(file_name).srcnode().abspath
- elif os.path.basename(file_name) == 'changelog':
- changelog_file = env.File(file_name).srcnode().abspath
- if not control_file:
- raise Exception('Need to have a control file')
- if not changelog_file:
- raise Exception('Need to have a changelog file')
- source = _OutputFromShellCommand(
- "awk '/^Source:/ { print $2; }' " + control_file)
- packages = _OutputFromShellCommand(
- "awk '/^Package:/ { print $2; }' " + control_file).split('\n')
- version = _OutputFromShellCommand(
- "sed -nr '1 { s/.*\\((.*)\\).*/\\1/; p }' " + changelog_file)
- arch = _OutputFromShellCommand('dpkg --print-architecture')
- add_dummy_changelog_entry = False
- if force_version and not version.startswith(force_version):
- print ('Warning: no entry in ' + changelog_file + ' for version ' +
- force_version + ' (last is ' + version +'). A dummy entry will be ' +
- 'generated. Remember to add the real changelog entry before ' +
- 'releasing.')
- version = force_version + '~prerelease'
- add_dummy_changelog_entry = True
- source_dir_name = source + '_' + version + '_' + arch
- target_file_names = [ source_dir_name + '.changes' ]
- for package in packages:
- package_file_name = package + '_' + version + '_' + arch + '.deb'
- target_file_names.append(package_file_name)
- # The targets
- if output_dir:
- targets = [os.path.join(output_dir, s) for s in target_file_names]
- else:
- targets = target_file_names
- # Path to where we will construct the debian build tree.
- deb_build_tree = os.path.join(source_dir_name, 'deb_build_tree')
- # First copy the files.
- for file_name in package_files:
- env.Command(os.path.join(deb_build_tree, file_name[0]), file_name[1],
- SCons.Defaults.Copy('$TARGET', '$SOURCE'))
- env.Depends(targets, os.path.join(deb_build_tree, file_name[0]))
- # Now copy the Debian metadata sources. We have to do this all at once so
- # that we can remove the target directory before copying, because there
- # can't be any other stale files there or else dpkg-buildpackage may use
- # them and give incorrect build output.
- copied_debian_files_paths = []
- for file_name in debian_files:
- copied_debian_files_paths.append(os.path.join(deb_build_tree, 'debian',
- os.path.basename(file_name)))
- copy_commands = [
- """dir=$$(dirname $TARGET) && \
- rm -Rf $$dir && \
- mkdir -p $$dir && \
- cp $SOURCES $$dir && \
- chmod -R u+w $$dir"""
- ]
- if add_dummy_changelog_entry:
- copy_commands += [
- """debchange -c $$(dirname $TARGET)/changelog --newversion %s \
- --distribution UNRELEASED \
- 'Developer preview build. (This entry was auto-generated.)'""" %
- version
- ]
- env.Command(copied_debian_files_paths, debian_files, copy_commands)
- env.Depends(targets, copied_debian_files_paths)
- # Must explicitly specify -a because otherwise cross-builds won't work.
- # Must explicitly specify -D because -a disables it.
- # Must explicitly specify fakeroot because old dpkg tools don't assume that.
- env.Command(targets, None,
- """dir=%(dir)s && \
- cd $$dir && \
- dpkg-buildpackage -b -uc -a%(arch)s -D -rfakeroot && \
- cd $$OLDPWD && \
- for file in %(targets)s; do \
- mv $$dir/../$$file $$(dirname $TARGET) || exit 1; \
- done""" %
- {'dir':env.Dir(deb_build_tree).path,
- 'arch':arch,
- 'targets':' '.join(target_file_names)})
- return targets
-
-
-def BuildDebianPackage(env, debian_files, package_files, force_version=None):
- """Creates build rules to build a Debian package from the specified sources.
-
- This is a Hammer-ified version of _InternalBuildDebianPackage that knows to
- put the packages in the Hammer staging dir.
-
- Args:
- env: SCons Environment.
- debian_files: Array of the Debian control file sources that should be
- copied into the package source tree, e.g., changelog, control, rules,
- etc.
- package_files: An array of 2-tuples listing the files that should be
- copied into the package source tree.
- The first element is the path where the file should be placed for the
- .install control file to find it, relative to the generated debian
- package source directory.
- The second element is the file source.
- force_version: Optional. Forces the version of the package to start with
- this version string if specified. If the last entry in the changelog
- is not for a version that starts with this then a dummy entry is
- generated with this version and a ~prerelease suffix (so that the
- final version will compare as greater).
-
- Return:
- A list of the targets (if any).
- """
- if not env.Bit('host_linux'):
- return []
- return _InternalBuildDebianPackage(env, debian_files, package_files,
- output_dir='$STAGING_DIR', force_version=force_version)
-
-
-def _GetPkgConfigCommand():
- """Return the pkg-config command line to use.
-
- Returns:
- A string specifying the pkg-config command line to use.
- """
- return os.environ.get('PKG_CONFIG') or 'pkg-config'
-
-
-def _EscapePosixShellArgument(arg):
- """Escapes a shell command line argument so that it is interpreted literally.
-
- Args:
- arg: The shell argument to escape.
-
- Returns:
- The escaped string.
- """
- return "'%s'" % arg.replace("'", "'\\''")
-
-
-def _HavePackage(package):
- """Whether the given pkg-config package name is present on the build system.
-
- Args:
- package: The name of the package.
-
- Returns:
- True if the package is present, else False
- """
- return subprocess.call('%s --exists %s' % (
- _GetPkgConfigCommand(),
- _EscapePosixShellArgument(package)), shell=True) == 0
-
-
-def _GetPackageFlags(flag_type, packages):
- """Get the flags needed to compile/link against the given package(s).
-
- Returns the flags that are needed to compile/link against the given pkg-config
- package(s).
-
- Args:
- flag_type: The option to pkg-config specifying the type of flags to get.
- packages: The list of package names as strings.
-
- Returns:
- The flags of the requested type.
-
- Raises:
- subprocess.CalledProcessError: The pkg-config command failed.
- """
- pkg_config = _GetPkgConfigCommand()
- command = ' '.join([pkg_config] +
- [_EscapePosixShellArgument(arg) for arg in
- [flag_type] + packages])
- process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
- output = process.communicate()[0]
- if process.returncode != 0:
- raise subprocess.CalledProcessError(process.returncode, pkg_config)
- return output.strip().split(' ')
-
-
-def GetPackageParams(env, packages):
- """Get the params needed to compile/link against the given package(s).
-
- Returns the params that are needed to compile/link against the given
- pkg-config package(s).
-
- Args:
- env: The current SCons environment.
- packages: The name of the package, or a list of names.
-
- Returns:
- A dictionary containing the params.
-
- Raises:
- Exception: One or more of the packages is not installed.
- """
- if not env.Bit('host_linux'):
- return {}
- if not SCons.Util.is_List(packages):
- packages = [packages]
- for package in packages:
- if not _HavePackage(package):
- raise Exception(('Required package \"%s\" was not found. Please install '
- 'the package that provides the \"%s.pc\" file.') %
- (package, package))
- package_ccflags = _GetPackageFlags('--cflags', packages)
- package_libs = _GetPackageFlags('--libs', packages)
- # Split package_libs into libs, libdirs, and misc. linker flags. (In a perfect
- # world we could just leave libdirs in link_flags, but some linkers are
- # somehow confused by the different argument order.)
- libs = [flag[2:] for flag in package_libs if flag[0:2] == '-l']
- libdirs = [flag[2:] for flag in package_libs if flag[0:2] == '-L']
- link_flags = [flag for flag in package_libs if flag[0:2] not in ['-l', '-L']]
- return {
- 'ccflags': package_ccflags,
- 'libs': libs,
- 'libdirs': libdirs,
- 'link_flags': link_flags,
- 'dependent_target_settings' : {
- 'libs': libs[:],
- 'libdirs': libdirs[:],
- 'link_flags': link_flags[:],
- },
- }
-
-
-def EnableFeatureWherePackagePresent(env, bit, cpp_flag, package):
- """Enable a feature if a required pkg-config package is present.
-
- Args:
- env: The current SCons environment.
- bit: The name of the Bit to enable when the package is present.
- cpp_flag: The CPP flag to enable when the package is present.
- package: The name of the package.
- """
- if not env.Bit('host_linux'):
- return
- if _HavePackage(package):
- env.SetBits(bit)
- env.Append(CPPDEFINES=[cpp_flag])
- else:
- print ('Warning: Package \"%s\" not found. Feature \"%s\" will not be '
- 'built. To build with this feature, install the package that '
- 'provides the \"%s.pc\" file.') % (package, bit, package)
-
-def GetGccVersion(env):
- if env.Bit('cross_compile'):
- gcc_command = env['CXX']
- else:
- gcc_command = 'gcc'
- version_string = _OutputFromShellCommand(
- '%s --version | head -n 1 |'
- r'sed "s/.*\([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/g"' % gcc_command)
- return tuple([int(x or '0') for x in version_string.split('.')])
-
-def generate(env):
- if env.Bit('linux'):
- env.AddMethod(EnableFeatureWherePackagePresent)
- env.AddMethod(GetPackageParams)
- env.AddMethod(BuildDebianPackage)
- env.AddMethod(GetGccVersion)
-
-
-def exists(env):
- return 1 # Required by scons
diff --git a/chromium/third_party/libjingle/source/talk/site_scons/site_tools/talk_noops.py b/chromium/third_party/libjingle/source/talk/site_scons/site_tools/talk_noops.py
deleted file mode 100644
index b184ddc542d..00000000000
--- a/chromium/third_party/libjingle/source/talk/site_scons/site_tools/talk_noops.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2010 Google Inc.
-# All Rights Reserved.
-# Author: thaloun@google.com (Tim Haloun)
-
-"""Noop tool that defines builder functions for non-default platforms to
- avoid errors when scanning sconsscripts."""
-
-import SCons.Builder
-
-
-def generate(env):
- """SCons method."""
- if not env.Bit('windows'):
- builder = SCons.Builder.Builder(
- action=''
- )
- env.Append(BUILDERS={'RES': builder, 'Grit': builder})
-
-def exists(dummy):
- return 1
diff --git a/chromium/third_party/libjingle/source/talk/site_scons/talk.py b/chromium/third_party/libjingle/source/talk/site_scons/talk.py
deleted file mode 100644
index 745f1d813f8..00000000000
--- a/chromium/third_party/libjingle/source/talk/site_scons/talk.py
+++ /dev/null
@@ -1,635 +0,0 @@
-# Copyright 2010 Google Inc.
-# All Rights Reserved.
-#
-# Author: Tim Haloun (thaloun@google.com)
-# Daniel Petersson (dape@google.com)
-#
-import os
-import SCons.Util
-
-class LibraryInfo:
- """Records information on the libraries defined in a build configuration.
-
- Attributes:
- lib_targets: Dictionary of library target params for lookups in
- ExtendComponent().
- prebuilt_libraries: Set of all prebuilt static libraries.
- system_libraries: Set of libraries not found in the above (used to detect
- out-of-order build rules).
- """
-
- # Dictionary of LibraryInfo objects keyed by BUILD_TYPE value.
- __library_info = {}
-
- @staticmethod
- def get(env):
- """Gets the LibraryInfo object for the current build type.
-
- Args:
- env: The environment object.
-
- Returns:
- The LibraryInfo object.
- """
- return LibraryInfo.__library_info.setdefault(env['BUILD_TYPE'],
- LibraryInfo())
-
- def __init__(self):
- self.lib_targets = {}
- self.prebuilt_libraries = set()
- self.system_libraries = set()
-
-
-def _GetLibParams(env, lib):
- """Gets the params for the given library if it is a library target.
-
- Returns the params that were specified when the given lib target name was
- created, or None if no such lib target has been defined. In the None case, it
- additionally records the negative result so as to detect out-of-order
- dependencies for future targets.
-
- Args:
- env: The environment object.
- lib: The library's name as a string.
-
- Returns:
- Its dictionary of params, or None.
- """
- info = LibraryInfo.get(env)
- if lib in info.lib_targets:
- return info.lib_targets[lib]
- else:
- if lib not in info.prebuilt_libraries and lib not in info.system_libraries:
- info.system_libraries.add(lib)
- return None
-
-
-def _RecordLibParams(env, lib, params):
- """Record the params used for a library target.
-
- Record the params used for a library target while checking for several error
- conditions.
-
- Args:
- env: The environment object.
- lib: The library target's name as a string.
- params: Its dictionary of params.
-
- Raises:
- Exception: The lib target has already been recorded, or the lib was
- previously declared to be prebuilt, or the lib target is being defined
- after a reverse library dependency.
- """
- info = LibraryInfo.get(env)
- if lib in info.lib_targets:
- raise Exception('Multiple definitions of ' + lib)
- if lib in info.prebuilt_libraries:
- raise Exception(lib + ' already declared as a prebuilt library')
- if lib in info.system_libraries:
- raise Exception(lib + ' cannot be defined after its reverse library '
- 'dependencies')
- info.lib_targets[lib] = params
-
-
-def _IsPrebuiltLibrary(env, lib):
- """Checks whether or not the given library is a prebuilt static library.
-
- Returns whether or not the given library name has been declared to be a
- prebuilt static library. In the False case, it additionally records the
- negative result so as to detect out-of-order dependencies for future targets.
-
- Args:
- env: The environment object.
- lib: The library's name as a string.
-
- Returns:
- True or False
- """
- info = LibraryInfo.get(env)
- if lib in info.prebuilt_libraries:
- return True
- else:
- if lib not in info.lib_targets and lib not in info.system_libraries:
- info.system_libraries.add(lib)
- return False
-
-
-def _RecordPrebuiltLibrary(env, lib):
- """Record that a library is a prebuilt static library.
-
- Record that the given library name refers to a prebuilt static library while
- checking for several error conditions.
-
- Args:
- env: The environment object.
- lib: The library's name as a string.
-
- Raises:
- Exception: The lib has already been recorded to be prebuilt, or the lib was
- previously declared as a target, or the lib is being declared as
- prebuilt after a reverse library dependency.
- """
- info = LibraryInfo.get(env)
- if lib in info.prebuilt_libraries:
- raise Exception('Multiple prebuilt declarations of ' + lib)
- if lib in info.lib_targets:
- raise Exception(lib + ' already defined as a target')
- if lib in info.system_libraries:
- raise Exception(lib + ' cannot be declared as prebuilt after its reverse '
- 'library dependencies')
- info.prebuilt_libraries.add(lib)
-
-
-def _GenericLibrary(env, static, **kwargs):
- """Extends ComponentLibrary to support multiplatform builds
- of dynamic or static libraries.
-
- Args:
- env: The environment object.
- kwargs: The keyword arguments.
-
- Returns:
- See swtoolkit ComponentLibrary
- """
- params = CombineDicts(kwargs, {'COMPONENT_STATIC': static})
- return ExtendComponent(env, 'ComponentLibrary', **params)
-
-
-def DeclarePrebuiltLibraries(env, libraries):
- """Informs the build engine about external static libraries.
-
- Informs the build engine that the given external library name(s) are prebuilt
- static libraries, as opposed to shared libraries.
-
- Args:
- env: The environment object.
- libraries: The library or libraries that are being declared as prebuilt
- static libraries.
- """
- if not SCons.Util.is_List(libraries):
- libraries = [libraries]
- for library in libraries:
- _RecordPrebuiltLibrary(env, library)
-
-
-def Library(env, **kwargs):
- """Extends ComponentLibrary to support multiplatform builds of static
- libraries.
-
- Args:
- env: The current environment.
- kwargs: The keyword arguments.
-
- Returns:
- See swtoolkit ComponentLibrary
- """
- return _GenericLibrary(env, True, **kwargs)
-
-
-def DynamicLibrary(env, **kwargs):
- """Extends ComponentLibrary to support multiplatform builds
- of dynmic libraries.
-
- Args:
- env: The environment object.
- kwargs: The keyword arguments.
-
- Returns:
- See swtoolkit ComponentLibrary
- """
- return _GenericLibrary(env, False, **kwargs)
-
-
-def Object(env, **kwargs):
- return ExtendComponent(env, 'ComponentObject', **kwargs)
-
-
-def Unittest(env, **kwargs):
- """Extends ComponentTestProgram to support unittest built
- for multiple platforms.
-
- Args:
- env: The current environment.
- kwargs: The keyword arguments.
-
- Returns:
- See swtoolkit ComponentProgram.
- """
- kwargs['name'] = kwargs['name'] + '_unittest'
-
- common_test_params = {
- 'posix_cppdefines': ['GUNIT_NO_GOOGLE3', 'GTEST_HAS_RTTI=0'],
- 'libs': ['unittest_main', 'gunit']
- }
- if 'explicit_libs' not in kwargs:
- common_test_params['win_libs'] = [
- 'advapi32',
- 'crypt32',
- 'iphlpapi',
- 'secur32',
- 'shell32',
- 'shlwapi',
- 'user32',
- 'wininet',
- 'ws2_32'
- ]
- common_test_params['lin_libs'] = [
- 'crypto',
- 'pthread',
- 'ssl',
- ]
-
- params = CombineDicts(kwargs, common_test_params)
- return ExtendComponent(env, 'ComponentTestProgram', **params)
-
-
-def App(env, **kwargs):
- """Extends ComponentProgram to support executables with platform specific
- options.
-
- Args:
- env: The current environment.
- kwargs: The keyword arguments.
-
- Returns:
- See swtoolkit ComponentProgram.
- """
- if 'explicit_libs' not in kwargs:
- common_app_params = {
- 'win_libs': [
- 'advapi32',
- 'crypt32',
- 'iphlpapi',
- 'secur32',
- 'shell32',
- 'shlwapi',
- 'user32',
- 'wininet',
- 'ws2_32'
- ]}
- params = CombineDicts(kwargs, common_app_params)
- else:
- params = kwargs
- return ExtendComponent(env, 'ComponentProgram', **params)
-
-def WiX(env, **kwargs):
- """ Extends the WiX builder
- Args:
- env: The current environment.
- kwargs: The keyword arguments.
-
- Returns:
- The node produced by the environment's wix builder
- """
- return ExtendComponent(env, 'WiX', **kwargs)
-
-def Repository(env, at, path):
- """Maps a directory external to $MAIN_DIR to the given path so that sources
- compiled from it end up in the correct place under $OBJ_DIR. NOT required
- when only referring to header files.
-
- Args:
- env: The current environment object.
- at: The 'mount point' within the current directory.
- path: Path to the actual directory.
- """
- env.Dir(at).addRepository(env.Dir(path))
-
-
-def Components(*paths):
- """Completes the directory paths with the correct file
- names such that the directory/directory.scons name
- convention can be used.
-
- Args:
- paths: The paths to complete. If it refers to an existing
- file then it is ignored.
-
- Returns:
- The completed lif scons files that are needed to build talk.
- """
- files = []
- for path in paths:
- if os.path.isfile(path):
- files.append(path)
- else:
- files.append(ExpandSconsPath(path))
- return files
-
-
-def ExpandSconsPath(path):
- """Expands a directory path into the path to the
- scons file that our build uses.
- Ex: magiflute/plugin/common => magicflute/plugin/common/common.scons
-
- Args:
- path: The directory path to expand.
-
- Returns:
- The expanded path.
- """
- return '%s/%s.scons' % (path, os.path.basename(path))
-
-
-def ReadVersion(filename):
- """Executes the supplied file and pulls out a version definition from it. """
- defs = {}
- execfile(str(filename), defs)
- if 'version' not in defs:
- return '0.0.0.0'
- version = defs['version']
- parts = version.split(',')
- build = os.environ.get('GOOGLE_VERSION_BUILDNUMBER')
- if build:
- parts[-1] = str(build)
- return '.'.join(parts)
-
-
-#-------------------------------------------------------------------------------
-# Helper methods for translating talk.Foo() declarations in to manipulations of
-# environmuent construction variables, including parameter parsing and merging,
-#
-def PopEntry(dictionary, key):
- """Get the value from a dictionary by key. If the key
- isn't in the dictionary then None is returned. If it is in
- the dictionary the value is fetched and then is it removed
- from the dictionary.
-
- Args:
- dictionary: The dictionary.
- key: The key to get the value for.
- Returns:
- The value or None if the key is missing.
- """
- value = None
- if key in dictionary:
- value = dictionary[key]
- dictionary.pop(key)
- return value
-
-
-def MergeAndFilterByPlatform(env, params):
- """Take a dictionary of arguments to lists of values, and, depending on
- which platform we are targetting, merge the lists of associated keys.
- Merge by combining value lists like so:
- {win_foo = [a,b], lin_foo = [c,d], foo = [e], mac_bar = [f], bar = [g] }
- becomes {foo = [a,b,e], bar = [g]} on windows, and
- {foo = [e], bar = [f,g]} on mac
-
- Args:
- env: The hammer environment which knows which platforms are active
- params: The keyword argument dictionary.
- Returns:
- A new dictionary with the filtered and combined entries of params
- """
- platforms = {
- 'linux': 'lin_',
- 'mac': 'mac_',
- 'posix': 'posix_',
- 'windows': 'win_',
- }
- active_prefixes = [
- platforms[x] for x in iter(platforms) if env.Bit(x)
- ]
- inactive_prefixes = [
- platforms[x] for x in iter(platforms) if not env.Bit(x)
- ]
-
- merged = {}
- for arg, values in params.iteritems():
- inactive_platform = False
-
- key = arg
-
- for prefix in active_prefixes:
- if arg.startswith(prefix):
- key = arg[len(prefix):]
-
- for prefix in inactive_prefixes:
- if arg.startswith(prefix):
- inactive_platform = True
-
- if inactive_platform:
- continue
-
- AddToDict(merged, key, values)
-
- return merged
-
-
-def MergeSettingsFromLibraryDependencies(env, params):
- if 'libs' in params:
- for lib in params['libs']:
- libparams = _GetLibParams(env, lib)
- if libparams:
- if 'dependent_target_settings' in libparams:
- params = CombineDicts(
- params,
- MergeAndFilterByPlatform(
- env,
- libparams['dependent_target_settings']))
- return params
-
-
-def ExtendComponent(env, component, **kwargs):
- """A wrapper around a scons builder function that preprocesses and post-
- processes its inputs and outputs. For example, it merges and filters
- certain keyword arguments before appending them to the environments
- construction variables. It can build signed targets and 64bit copies
- of targets as well.
-
- Args:
- env: The hammer environment with which to build the target
- component: The environment's builder function, e.g. ComponentProgram
- kwargs: keyword arguments that are either merged, translated, and passed on
- to the call to component, or which control execution.
- TODO(): Document the fields, such as cppdefines->CPPDEFINES,
- prepend_includedirs, include_talk_media_libs, etc.
- Returns:
- The output node returned by the call to component, or a subsequent signed
- dependant node.
- """
- env = env.Clone()
-
- # prune parameters intended for other platforms, then merge
- params = MergeAndFilterByPlatform(env, kwargs)
-
- # get the 'target' field
- name = PopEntry(params, 'name')
-
- # get the 'packages' field and process it if present (only used for Linux).
- packages = PopEntry(params, 'packages')
- if packages and len(packages):
- params = CombineDicts(params, env.GetPackageParams(packages))
-
- # save pristine params of lib targets for future reference
- if 'ComponentLibrary' == component:
- _RecordLibParams(env, name, dict(params))
-
- # add any dependent target settings from library dependencies
- params = MergeSettingsFromLibraryDependencies(env, params)
-
- # if this is a signed binary we need to make an unsigned version first
- signed = env.Bit('windows') and PopEntry(params, 'signed')
- if signed:
- name = 'unsigned_' + name
-
- # potentially exit now
- srcs = PopEntry(params, 'srcs')
- if not srcs or not hasattr(env, component):
- return None
-
- # apply any explicit dependencies
- dependencies = PopEntry(params, 'depends')
- if dependencies is not None:
- env.Depends(name, dependencies)
-
- # put the contents of params into the environment
- # some entries are renamed then appended, others renamed then prepended
- appends = {
- 'cppdefines' : 'CPPDEFINES',
- 'libdirs' : 'LIBPATH',
- 'link_flags' : 'LINKFLAGS',
- 'libs' : 'LIBS',
- 'FRAMEWORKS' : 'FRAMEWORKS',
- }
- prepends = {}
- if env.Bit('windows'):
- # MSVC compile flags have precedence at the beginning ...
- prepends['ccflags'] = 'CCFLAGS'
- else:
- # ... while GCC compile flags have precedence at the end
- appends['ccflags'] = 'CCFLAGS'
- if PopEntry(params, 'prepend_includedirs'):
- prepends['includedirs'] = 'CPPPATH'
- else:
- appends['includedirs'] = 'CPPPATH'
-
- for field, var in appends.items():
- values = PopEntry(params, field)
- if values is not None:
- env.Append(**{var : values})
- for field, var in prepends.items():
- values = PopEntry(params, field)
- if values is not None:
- env.Prepend(**{var : values})
-
- # any other parameters are replaced without renaming
- for field, value in params.items():
- env.Replace(**{field : value})
-
- if env.Bit('linux') and 'LIBS' in env:
- libs = env['LIBS']
- # When using --as-needed + --start/end-group, shared libraries need to come
- # after --end-group on the command-line because the pruning decision only
- # considers the preceding modules and --start/end-group may cause the
- # effective position of early static libraries on the command-line to be
- # deferred to the point of --end-group. To effect this, we move shared libs
- # into _LIBFLAGS, which has the --end-group as its first entry. SCons does
- # not track dependencies on system shared libraries anyway so we lose
- # nothing by removing them from LIBS.
- static_libs = [lib for lib in libs if
- _GetLibParams(env, lib) or _IsPrebuiltLibrary(env, lib)]
- shared_libs = ['-l' + lib for lib in libs if not
- (_GetLibParams(env, lib) or _IsPrebuiltLibrary(env, lib))]
- env.Replace(LIBS=static_libs)
- env.Append(_LIBFLAGS=shared_libs)
-
- # invoke the builder function
- builder = getattr(env, component)
-
- node = builder(name, srcs)
-
- if env.Bit('mac') and 'ComponentProgram' == component:
- # Build .dSYM debug packages. This is useful even for non-stripped
- # binaries, as the dsym utility will fetch symbols from all
- # statically-linked libraries (the linker doesn't include them in to the
- # final binary).
- build_dsym = env.Command(
- env.Dir('$STAGING_DIR/%s.dSYM' % node[0]),
- node,
- 'mkdir -p `dirname $TARGET` && dsymutil -o $TARGET $SOURCE')
- env.Alias('all_dsym', env.Alias('%s.dSYM' % node[0], build_dsym))
-
- if signed:
- # Get the name of the built binary, then get the name of the final signed
- # version from it. We need the output path since we don't know the file
- # extension beforehand.
- target = node[0].path.split('_', 1)[1]
- # postsignprefix: If defined, postsignprefix is a string that should be
- # prepended to the target executable. This is to provide a work around
- # for EXEs and DLLs with the same name, which thus have PDBs with the
- # same name. Setting postsignprefix allows the EXE and its PDB
- # to be renamed and copied in a previous step; then the desired
- # name of the EXE (but not PDB) is reconstructed after signing.
- postsignprefix = PopEntry(params, 'postsignprefix')
- if postsignprefix is not None:
- target = postsignprefix + target
- signed_node = env.SignedBinary(
- source = node,
- target = '$STAGING_DIR/' + target,
- )
- env.Alias('signed_binaries', signed_node)
- return signed_node
-
- return node
-
-
-def AddToDict(dictionary, key, values, append=True):
- """Merge the given key value(s) pair into a dictionary. If it contains an
- entry with that key already, then combine by appending or prepending the
- values as directed. Otherwise, assign a new keyvalue pair.
- """
- if values is None:
- return
-
- if key not in dictionary:
- dictionary[key] = values
- return
-
- cur = dictionary[key]
- # TODO(dape): Make sure that there are no duplicates
- # in the list. I can't use python set for this since
- # the nodes that are returned by the SCONS builders
- # are not hashable.
- # dictionary[key] = list(set(cur).union(set(values)))
- if append:
- dictionary[key] = cur + values
- else:
- dictionary[key] = values + cur
-
-
-def CombineDicts(a, b):
- """Unions two dictionaries of arrays/dictionaries.
-
- Unions two dictionaries of arrays/dictionaries by combining the values of keys
- shared between them. The original dictionaries should not be used again after
- this call.
-
- Args:
- a: First dict.
- b: Second dict.
-
- Returns:
- The union of a and b.
- """
- c = {}
- for key in a:
- if key in b:
- aval = a[key]
- bval = b.pop(key)
- if isinstance(aval, dict) and isinstance(bval, dict):
- c[key] = CombineDicts(aval, bval)
- else:
- c[key] = aval + bval
- else:
- c[key] = a[key]
-
- for key in b:
- c[key] = b[key]
-
- return c
-
-
-def RenameKey(d, old, new, append=True):
- AddToDict(d, new, PopEntry(d, old), append)
diff --git a/chromium/third_party/libjingle/source/talk/xmllite/xmlparser.cc b/chromium/third_party/libjingle/source/talk/xmllite/xmlparser.cc
index 3e4d73348ee..8802231872e 100644
--- a/chromium/third_party/libjingle/source/talk/xmllite/xmlparser.cc
+++ b/chromium/third_party/libjingle/source/talk/xmllite/xmlparser.cc
@@ -60,7 +60,7 @@ XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) {
}
XmlParser::XmlParser(XmlParseHandler *pxph) :
- context_(this), pxph_(pxph), sentError_(false) {
+ pxph_(pxph), sentError_(false) {
expat_ = XML_ParserCreate(NULL);
XML_SetUserData(expat_, this);
XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
@@ -196,8 +196,7 @@ XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) {
parser.Parse(text.c_str(), text.length(), true);
}
-XmlParser::ParseContext::ParseContext(XmlParser *parser) :
- parser_(parser),
+XmlParser::ParseContext::ParseContext() :
xmlnsstack_(),
raised_(XML_ERROR_NONE),
line_number_(0),
diff --git a/chromium/third_party/libjingle/source/talk/xmllite/xmlparser.h b/chromium/third_party/libjingle/source/talk/xmllite/xmlparser.h
index 69cde75f770..4a79858e42f 100644
--- a/chromium/third_party/libjingle/source/talk/xmllite/xmlparser.h
+++ b/chromium/third_party/libjingle/source/talk/xmllite/xmlparser.h
@@ -87,7 +87,7 @@ private:
class ParseContext : public XmlParseContext {
public:
- ParseContext(XmlParser * parser);
+ ParseContext();
virtual ~ParseContext();
virtual QName ResolveQName(const char * qname, bool isAttr);
virtual void RaiseError(XML_Error err) { if (!raised_) raised_ = err; }
@@ -102,7 +102,6 @@ private:
void SetPosition(int line, int column, long byte_index);
private:
- const XmlParser * parser_;
XmlnsStack xmlnsstack_;
XML_Error raised_;
XML_Size line_number_;
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/chatroommoduleimpl.cc b/chromium/third_party/libjingle/source/talk/xmpp/chatroommoduleimpl.cc
index eb046d72112..a12ff5e029d 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/chatroommoduleimpl.cc
+++ b/chromium/third_party/libjingle/source/talk/xmpp/chatroommoduleimpl.cc
@@ -320,17 +320,13 @@ XmppChatroomModuleImpl::RequestExitChatroom() {
if (!engine())
return XMPP_RETURN_BADSTATE;
- // currently, can't leave a room unless you've entered
- // no way to cancel a pending enter call - is that bad?
- if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM)
- return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code?
-
// exiting a chatroom is a presence request to the server
XmlElement element(QN_PRESENCE);
element.AddAttr(QN_TO, member_jid().Str());
element.AddAttr(QN_TYPE, "unavailable");
XmppReturnStatus status = engine()->SendStanza(&element);
- if (status == XMPP_RETURN_OK) {
+ if (status == XMPP_RETURN_OK &&
+ chatroom_state_ == XMPP_CHATROOM_STATE_IN_ROOM) {
return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_EXIT);
}
return status;
@@ -513,6 +509,7 @@ XmppChatroomModuleImpl::ServerChangedOtherPresence(const XmlElement&
FireMemberChanged(member);
}
else if (presence->available() == XMPP_PRESENCE_UNAVAILABLE) {
+ member->SetPresence(presence.get());
chatroom_jid_members_.erase(pos);
chatroom_jid_members_version_++;
FireMemberExited(member);
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/constants.cc b/chromium/third_party/libjingle/source/talk/xmpp/constants.cc
index c56796bc9e7..f69f84e469c 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/constants.cc
+++ b/chromium/third_party/libjingle/source/talk/xmpp/constants.cc
@@ -118,6 +118,10 @@ const char STR_MUC_ROOM_FEATURE_HANGOUT[] = "muc_es";
const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[] = "muc_lite";
const char STR_MUC_ROOM_FEATURE_BROADCAST[] = "broadcast";
const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[] = "muc_muvc";
+const char STR_MUC_ROOM_FEATURE_RECORDABLE[] = "recordable";
+const char STR_MUC_ROOM_FEATURE_CUSTOM_RECORDING[] = "custom_recording";
+const char STR_MUC_ROOM_OWNER_PROFILE_ID[] = "muc#roominfo_owner_profile_id";
+const char STR_MUC_ROOM_FEATURE_ABUSE_RECORDABLE[] = "abuse_recordable";
const char STR_ID_TYPE_CONVERSATION[] = "conversation";
const char NS_GOOGLE_MUC_HANGOUT[] = "google:muc#hangout";
@@ -213,7 +217,6 @@ const char NS_GOOGLE_AUTH_PROTOCOL[] =
"http://www.google.com/talk/protocol/auth";
const StaticQName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT =
{ NS_GOOGLE_AUTH_PROTOCOL, "client-uses-full-bind-result" };
-const char NS_GOOGLE_AUTH_OLD[] = "google:auth";
const StaticQName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN =
{ NS_GOOGLE_AUTH_PROTOCOL, "allow-non-google-login" };
const StaticQName QN_GOOGLE_AUTH_SERVICE =
@@ -342,8 +345,6 @@ const StaticQName QN_NICK = { STR_EMPTY, "nick" };
const StaticQName QN_SUBSCRIPTION = { STR_EMPTY, "subscription" };
const StaticQName QN_TITLE1 = { STR_EMPTY, "title1" };
const StaticQName QN_TITLE2 = { STR_EMPTY, "title2" };
-const StaticQName QN_SOURCE = { STR_EMPTY, "source" };
-const StaticQName QN_TIME = { STR_EMPTY, "time" };
const StaticQName QN_XMLNS_CLIENT = { NS_XMLNS, STR_CLIENT };
const StaticQName QN_XMLNS_SERVER = { NS_XMLNS, STR_SERVER };
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/constants.h b/chromium/third_party/libjingle/source/talk/xmpp/constants.h
index c53abb5b86f..6d940957da6 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/constants.h
+++ b/chromium/third_party/libjingle/source/talk/xmpp/constants.h
@@ -111,6 +111,10 @@ extern const char STR_MUC_ROOM_FEATURE_HANGOUT[];
extern const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[];
extern const char STR_MUC_ROOM_FEATURE_BROADCAST[];
extern const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[];
+extern const char STR_MUC_ROOM_FEATURE_RECORDABLE[];
+extern const char STR_MUC_ROOM_FEATURE_CUSTOM_RECORDING[];
+extern const char STR_MUC_ROOM_OWNER_PROFILE_ID[];
+extern const char STR_MUC_ROOM_FEATURE_ABUSE_RECORDABLE[];
extern const char STR_ID_TYPE_CONVERSATION[];
extern const char NS_GOOGLE_MUC_HANGOUT[];
@@ -119,6 +123,7 @@ extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE;
extern const StaticQName QN_ATTR_CREATE_ACTIVITY;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE;
+extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_STATUS;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT;
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID;
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient.cc b/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient.cc
index b6669a10865..aede56318cc 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient.cc
+++ b/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient.cc
@@ -42,56 +42,9 @@ namespace buzz {
namespace {
const char kPresenting[] = "s";
const char kNotPresenting[] = "o";
-const char kEmpty[] = "";
-
-const std::string GetPublisherNickFromPubSubItem(const XmlElement* item_elem) {
- if (item_elem == NULL) {
- return "";
- }
-
- return Jid(item_elem->Attr(QN_ATTR_PUBLISHER)).resource();
-}
} // namespace
-
-// Knows how to handle specific states and XML.
-template <typename C>
-class PubSubStateSerializer {
- public:
- virtual ~PubSubStateSerializer() {}
- virtual XmlElement* Write(const QName& state_name, const C& state) = 0;
- virtual C Parse(const XmlElement* state_elem) = 0;
-};
-
-// Knows how to create "keys" for states, which determines their
-// uniqueness. Most states are per-nick, but block is
-// per-blocker-and-blockee. This is independent of itemid, especially
-// in the case of presenter state.
-class PubSubStateKeySerializer {
- public:
- virtual ~PubSubStateKeySerializer() {}
- virtual std::string GetKey(const std::string& publisher_nick,
- const std::string& published_nick) = 0;
-};
-
-class PublishedNickKeySerializer : public PubSubStateKeySerializer {
- public:
- virtual std::string GetKey(const std::string& publisher_nick,
- const std::string& published_nick) {
- return published_nick;
- }
-};
-
-class PublisherAndPublishedNicksKeySerializer
- : public PubSubStateKeySerializer {
- public:
- virtual std::string GetKey(const std::string& publisher_nick,
- const std::string& published_nick) {
- return publisher_nick + ":" + published_nick;
- }
-};
-
// A simple serialiazer where presence of item => true, lack of item
// => false.
class BoolStateSerializer : public PubSubStateSerializer<bool> {
@@ -103,195 +56,11 @@ class BoolStateSerializer : public PubSubStateSerializer<bool> {
return new XmlElement(state_name, true);
}
- virtual bool Parse(const XmlElement* state_elem) {
- return state_elem != NULL;
+ virtual void Parse(const XmlElement* state_elem, bool *state_out) {
+ *state_out = state_elem != NULL;
}
};
-// Adapts PubSubClient to be specifically suited for pub sub call
-// states. Signals state changes and keeps track of keys, which are
-// normally nicks.
-// TODO: Expose this as a generally useful class, not just
-// private to hangouts.
-template <typename C>
-class PubSubStateClient : public sigslot::has_slots<> {
- public:
- // Gets ownership of the serializers, but not the client.
- PubSubStateClient(const std::string& publisher_nick,
- PubSubClient* client,
- const QName& state_name,
- C default_state,
- PubSubStateKeySerializer* key_serializer,
- PubSubStateSerializer<C>* state_serializer)
- : publisher_nick_(publisher_nick),
- client_(client),
- state_name_(state_name),
- default_state_(default_state) {
- key_serializer_.reset(key_serializer);
- state_serializer_.reset(state_serializer);
- client_->SignalItems.connect(
- this, &PubSubStateClient<C>::OnItems);
- client_->SignalPublishResult.connect(
- this, &PubSubStateClient<C>::OnPublishResult);
- client_->SignalPublishError.connect(
- this, &PubSubStateClient<C>::OnPublishError);
- client_->SignalRetractResult.connect(
- this, &PubSubStateClient<C>::OnRetractResult);
- client_->SignalRetractError.connect(
- this, &PubSubStateClient<C>::OnRetractError);
- }
-
- virtual ~PubSubStateClient() {}
-
- virtual void Publish(const std::string& published_nick,
- const C& state,
- std::string* task_id_out) {
- std::string key = key_serializer_->GetKey(publisher_nick_, published_nick);
- std::string itemid = state_name_.LocalPart() + ":" + key;
- if (StatesEqual(state, default_state_)) {
- client_->RetractItem(itemid, task_id_out);
- } else {
- XmlElement* state_elem = state_serializer_->Write(state_name_, state);
- state_elem->AddAttr(QN_NICK, published_nick);
- client_->PublishItem(itemid, state_elem, task_id_out);
- }
- };
-
- sigslot::signal1<const PubSubStateChange<C>&> SignalStateChange;
- // Signal (task_id, item). item is NULL for retract.
- sigslot::signal2<const std::string&,
- const XmlElement*> SignalPublishResult;
- // Signal (task_id, item, error stanza). item is NULL for retract.
- sigslot::signal3<const std::string&,
- const XmlElement*,
- const XmlElement*> SignalPublishError;
-
- protected:
- // return false if retracted item (no info or state given)
- virtual bool ParseStateItem(const PubSubItem& item,
- StateItemInfo* info_out,
- bool* state_out) {
- const XmlElement* state_elem = item.elem->FirstNamed(state_name_);
- if (state_elem == NULL) {
- return false;
- }
-
- info_out->publisher_nick = GetPublisherNickFromPubSubItem(item.elem);
- info_out->published_nick = state_elem->Attr(QN_NICK);
- *state_out = state_serializer_->Parse(state_elem);
- return true;
- };
-
- virtual bool StatesEqual(C state1, C state2) {
- return state1 == state2;
- }
-
- PubSubClient* client() { return client_; }
-
- private:
- void OnItems(PubSubClient* pub_sub_client,
- const std::vector<PubSubItem>& items) {
- for (std::vector<PubSubItem>::const_iterator item = items.begin();
- item != items.end(); ++item) {
- OnItem(*item);
- }
- }
-
- void OnItem(const PubSubItem& item) {
- const std::string& itemid = item.itemid;
- StateItemInfo info;
- C new_state;
-
- bool retracted = !ParseStateItem(item, &info, &new_state);
- if (retracted) {
- bool known_itemid =
- (info_by_itemid_.find(itemid) != info_by_itemid_.end());
- if (!known_itemid) {
- // Nothing to retract, and nothing to publish.
- // Probably a different state type.
- return;
- } else {
- info = info_by_itemid_[itemid];
- info_by_itemid_.erase(itemid);
- new_state = default_state_;
- }
- } else {
- // TODO: Assert new key matches the known key. It
- // shouldn't change!
- info_by_itemid_[itemid] = info;
- }
-
- std::string key = key_serializer_->GetKey(
- info.publisher_nick, info.published_nick);
- bool has_old_state = (state_by_key_.find(key) != state_by_key_.end());
- C old_state = has_old_state ? state_by_key_[key] : default_state_;
- if ((retracted && !has_old_state) || StatesEqual(new_state, old_state)) {
- // Nothing change, so don't bother signalling.
- return;
- }
-
- if (retracted || StatesEqual(new_state, default_state_)) {
- // We treat a default state similar to a retract.
- state_by_key_.erase(key);
- } else {
- state_by_key_[key] = new_state;
- }
-
- PubSubStateChange<C> change;
- if (!retracted) {
- // Retracts do not have publisher information.
- change.publisher_nick = info.publisher_nick;
- }
- change.published_nick = info.published_nick;
- change.old_state = old_state;
- change.new_state = new_state;
- SignalStateChange(change);
- }
-
- void OnPublishResult(PubSubClient* pub_sub_client,
- const std::string& task_id,
- const XmlElement* item) {
- SignalPublishResult(task_id, item);
- }
-
- void OnPublishError(PubSubClient* pub_sub_client,
- const std::string& task_id,
- const buzz::XmlElement* item,
- const buzz::XmlElement* stanza) {
- SignalPublishError(task_id, item, stanza);
- }
-
- void OnRetractResult(PubSubClient* pub_sub_client,
- const std::string& task_id) {
- // There's no point in differentiating between publish and retract
- // errors, so we simplify by making them both signal a publish
- // result.
- const XmlElement* item = NULL;
- SignalPublishResult(task_id, item);
- }
-
- void OnRetractError(PubSubClient* pub_sub_client,
- const std::string& task_id,
- const buzz::XmlElement* stanza) {
- // There's no point in differentiating between publish and retract
- // errors, so we simplify by making them both signal a publish
- // error.
- const XmlElement* item = NULL;
- SignalPublishError(task_id, item, stanza);
- }
-
- std::string publisher_nick_;
- PubSubClient* client_;
- const QName state_name_;
- C default_state_;
- talk_base::scoped_ptr<PubSubStateKeySerializer> key_serializer_;
- talk_base::scoped_ptr<PubSubStateSerializer<C> > state_serializer_;
- // key => state
- std::map<std::string, C> state_by_key_;
- // itemid => StateItemInfo
- std::map<std::string, StateItemInfo> info_by_itemid_;
-};
-
class PresenterStateClient : public PubSubStateClient<bool> {
public:
PresenterStateClient(const std::string& publisher_nick,
@@ -336,15 +105,17 @@ class PresenterStateClient : public PubSubStateClient<bool> {
return false;
}
- info_out->publisher_nick = GetPublisherNickFromPubSubItem(item.elem);
+ info_out->publisher_nick =
+ client()->GetPublisherNickFromPubSubItem(item.elem);
info_out->published_nick = presenter_elem->Attr(QN_NICK);
*state_out = (presentation_item_elem->Attr(
QN_PRESENTER_PRESENTATION_TYPE) != kNotPresenting);
return true;
}
- virtual bool StatesEqual(bool state1, bool state2) {
- return false; // Make every item trigger an event, even if state doesn't change.
+ virtual bool StatesEqual(const bool& state1, const bool& state2) {
+ // Make every item trigger an event, even if state doesn't change.
+ return false;
}
};
@@ -506,6 +277,7 @@ void HangoutPubSubClient::OnAudioMuteStateChange(
bool is_muted = change.new_state;
bool remote_action = (!change.publisher_nick.empty() &&
(change.publisher_nick != change.published_nick));
+
if (remote_action) {
const std::string& mutee_nick = change.published_nick;
const std::string& muter_nick = change.publisher_nick;
@@ -516,9 +288,8 @@ void HangoutPubSubClient::OnAudioMuteStateChange(
}
bool should_mute_locally = (mutee_nick == nick_);
SignalRemoteMute(mutee_nick, muter_nick, should_mute_locally);
- } else {
- SignalAudioMuteStateChange(change.published_nick, was_muted, is_muted);
}
+ SignalAudioMuteStateChange(change.published_nick, was_muted, is_muted);
}
const std::string GetAudioMuteNickFromItem(const XmlElement* item) {
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient.h b/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient.h
index a9986db1598..2fcd6913290 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient.h
+++ b/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient.h
@@ -37,6 +37,7 @@
#include "talk/base/sigslotrepeater.h"
#include "talk/xmpp/jid.h"
#include "talk/xmpp/pubsubclient.h"
+#include "talk/xmpp/pubsubstateclient.h"
// Gives a high-level API for MUC call PubSub needs such as
// presenter state, recording state, mute state, and remote mute.
@@ -47,30 +48,6 @@ class Jid;
class XmlElement;
class XmppTaskParentInterface;
-// To handle retracts correctly, we need to remember certain details
-// about an item. We could just cache the entire XML element, but
-// that would take more memory and require re-parsing.
-struct StateItemInfo {
- std::string published_nick;
- std::string publisher_nick;
-};
-
-// Represents a PubSub state change. Usually, the key is the nick,
-// but not always. It's a per-state-type thing. Currently documented
-// at https://docs.google.com/a/google.com/document/d/
-// 1QyHu_ufyVdf0VICdfc_DtJbrOdrdIUm4eM73RZqnivI/edit?hl=en_US
-template <typename C>
-struct PubSubStateChange {
- // The nick of the user changing the state.
- std::string publisher_nick;
- // The nick of the user whose state is changing.
- std::string published_nick;
- C old_state;
- C new_state;
-};
-
-template <typename C> class PubSubStateClient;
-
// A client tied to a specific MUC jid and local nick. Provides ways
// to get updates and publish state and events. Must call
// RequestAll() to start getting updates.
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient_unittest.cc b/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient_unittest.cc
index 0ffb248f3c3..1d1c14b13ee 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient_unittest.cc
+++ b/chromium/third_party/libjingle/source/talk/xmpp/hangoutpubsubclient_unittest.cc
@@ -449,11 +449,14 @@ TEST_F(HangoutPubSubClientTest, TestRequest) {
" </event>"
"</message>";
+ listener->last_is_audio_muted = false;
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_remote_mute_message));
EXPECT_EQ("mutee", listener->last_mutee_nick);
EXPECT_EQ("muter", listener->last_muter_nick);
EXPECT_FALSE(listener->last_should_mute);
+ EXPECT_EQ("mutee", listener->last_audio_muted_nick);
+ EXPECT_TRUE(listener->last_is_audio_muted);
std::string incoming_remote_mute_me_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
@@ -466,11 +469,14 @@ TEST_F(HangoutPubSubClientTest, TestRequest) {
" </event>"
"</message>";
+ listener->last_is_audio_muted = false;
xmpp_client->HandleStanza(
buzz::XmlElement::ForStr(incoming_remote_mute_me_message));
EXPECT_EQ("me", listener->last_mutee_nick);
EXPECT_EQ("muter", listener->last_muter_nick);
EXPECT_TRUE(listener->last_should_mute);
+ EXPECT_EQ("me", listener->last_audio_muted_nick);
+ EXPECT_TRUE(listener->last_is_audio_muted);
std::string incoming_media_block_message =
"<message xmlns='jabber:client' from='room@domain.com'>"
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/pubsubclient.cc b/chromium/third_party/libjingle/source/talk/xmpp/pubsubclient.cc
index 8d6d4c414a2..b62758710c7 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/pubsubclient.cc
+++ b/chromium/third_party/libjingle/source/talk/xmpp/pubsubclient.cc
@@ -134,4 +134,13 @@ void PubSubClient::OnRetractError(IqTask* task,
SignalRetractError(this, retract_task->task_id(), stanza);
}
+
+const std::string PubSubClient::GetPublisherNickFromPubSubItem(
+ const XmlElement* item_elem) {
+ if (item_elem == NULL) {
+ return "";
+ }
+
+ return Jid(item_elem->Attr(QN_ATTR_PUBLISHER)).resource();
+}
} // namespace buzz
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/pubsubclient.h b/chromium/third_party/libjingle/source/talk/xmpp/pubsubclient.h
index 099765a2d35..f0cd7a98f4a 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/pubsubclient.h
+++ b/chromium/third_party/libjingle/source/talk/xmpp/pubsubclient.h
@@ -101,6 +101,9 @@ class PubSubClient : public sigslot::has_slots<> {
void RetractItem(const std::string& itemid,
std::string* task_id_out);
+ // Get the publisher nick if it exists from the pubsub item.
+ const std::string GetPublisherNickFromPubSubItem(const XmlElement* item_elem);
+
private:
void OnRequestError(IqTask* task,
const XmlElement* stanza);
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/pubsubstateclient.cc b/chromium/third_party/libjingle/source/talk/xmpp/pubsubstateclient.cc
new file mode 100644
index 00000000000..5cd7b1a703b
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/xmpp/pubsubstateclient.cc
@@ -0,0 +1,42 @@
+/*
+ * libjingle
+ * Copyright 2011, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/xmpp/pubsubstateclient.h"
+
+namespace buzz {
+
+std::string PublishedNickKeySerializer::GetKey(
+ const std::string& publisher_nick, const std::string& published_nick) {
+ return published_nick;
+}
+
+std::string PublisherAndPublishedNicksKeySerializer::GetKey(
+ const std::string& publisher_nick, const std::string& published_nick) {
+ return publisher_nick + ":" + published_nick;
+}
+
+} // namespace buzz
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/pubsubstateclient.h b/chromium/third_party/libjingle/source/talk/xmpp/pubsubstateclient.h
new file mode 100644
index 00000000000..f38658defd7
--- /dev/null
+++ b/chromium/third_party/libjingle/source/talk/xmpp/pubsubstateclient.h
@@ -0,0 +1,287 @@
+/*
+ * libjingle
+ * Copyright 2011, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_XMPP_PUBSUBSTATECLIENT_H_
+#define TALK_XMPP_PUBSUBSTATECLIENT_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/sigslotrepeater.h"
+#include "talk/xmpp/constants.h"
+#include "talk/xmpp/jid.h"
+#include "talk/xmpp/pubsubclient.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmllite/xmlelement.h"
+
+namespace buzz {
+
+// To handle retracts correctly, we need to remember certain details
+// about an item. We could just cache the entire XML element, but
+// that would take more memory and require re-parsing.
+struct StateItemInfo {
+ std::string published_nick;
+ std::string publisher_nick;
+};
+
+// Represents a PubSub state change. Usually, the key is the nick,
+// but not always. It's a per-state-type thing. Look below on how keys are
+// computed.
+template <typename C>
+struct PubSubStateChange {
+ // The nick of the user changing the state.
+ std::string publisher_nick;
+ // The nick of the user whose state is changing.
+ std::string published_nick;
+ C old_state;
+ C new_state;
+};
+
+// Knows how to handle specific states and XML.
+template <typename C>
+class PubSubStateSerializer {
+ public:
+ virtual ~PubSubStateSerializer() {}
+ virtual XmlElement* Write(const QName& state_name, const C& state) = 0;
+ virtual void Parse(const XmlElement* state_elem, C* state_out) = 0;
+};
+
+// Knows how to create "keys" for states, which determines their
+// uniqueness. Most states are per-nick, but block is
+// per-blocker-and-blockee. This is independent of itemid, especially
+// in the case of presenter state.
+class PubSubStateKeySerializer {
+ public:
+ virtual ~PubSubStateKeySerializer() {}
+ virtual std::string GetKey(const std::string& publisher_nick,
+ const std::string& published_nick) = 0;
+};
+
+class PublishedNickKeySerializer : public PubSubStateKeySerializer {
+ public:
+ virtual std::string GetKey(const std::string& publisher_nick,
+ const std::string& published_nick);
+};
+
+class PublisherAndPublishedNicksKeySerializer
+ : public PubSubStateKeySerializer {
+ public:
+ virtual std::string GetKey(const std::string& publisher_nick,
+ const std::string& published_nick);
+};
+
+// Adapts PubSubClient to be specifically suited for pub sub call
+// states. Signals state changes and keeps track of keys, which are
+// normally nicks.
+template <typename C>
+class PubSubStateClient : public sigslot::has_slots<> {
+ public:
+ // Gets ownership of the serializers, but not the client.
+ PubSubStateClient(const std::string& publisher_nick,
+ PubSubClient* client,
+ const QName& state_name,
+ C default_state,
+ PubSubStateKeySerializer* key_serializer,
+ PubSubStateSerializer<C>* state_serializer)
+ : publisher_nick_(publisher_nick),
+ client_(client),
+ state_name_(state_name),
+ default_state_(default_state) {
+ key_serializer_.reset(key_serializer);
+ state_serializer_.reset(state_serializer);
+ client_->SignalItems.connect(
+ this, &PubSubStateClient<C>::OnItems);
+ client_->SignalPublishResult.connect(
+ this, &PubSubStateClient<C>::OnPublishResult);
+ client_->SignalPublishError.connect(
+ this, &PubSubStateClient<C>::OnPublishError);
+ client_->SignalRetractResult.connect(
+ this, &PubSubStateClient<C>::OnRetractResult);
+ client_->SignalRetractError.connect(
+ this, &PubSubStateClient<C>::OnRetractError);
+ }
+
+ virtual ~PubSubStateClient() {}
+
+ virtual void Publish(const std::string& published_nick,
+ const C& state,
+ std::string* task_id_out) {
+ std::string key = key_serializer_->GetKey(publisher_nick_, published_nick);
+ std::string itemid = state_name_.LocalPart() + ":" + key;
+ if (StatesEqual(state, default_state_)) {
+ client_->RetractItem(itemid, task_id_out);
+ } else {
+ XmlElement* state_elem = state_serializer_->Write(state_name_, state);
+ state_elem->AddAttr(QN_NICK, published_nick);
+ client_->PublishItem(itemid, state_elem, task_id_out);
+ }
+ }
+
+ sigslot::signal1<const PubSubStateChange<C>&> SignalStateChange;
+ // Signal (task_id, item). item is NULL for retract.
+ sigslot::signal2<const std::string&,
+ const XmlElement*> SignalPublishResult;
+ // Signal (task_id, item, error stanza). item is NULL for retract.
+ sigslot::signal3<const std::string&,
+ const XmlElement*,
+ const XmlElement*> SignalPublishError;
+
+ protected:
+ // return false if retracted item (no info or state given)
+ virtual bool ParseStateItem(const PubSubItem& item,
+ StateItemInfo* info_out,
+ C* state_out) {
+ const XmlElement* state_elem = item.elem->FirstNamed(state_name_);
+ if (state_elem == NULL) {
+ return false;
+ }
+
+ info_out->publisher_nick =
+ client_->GetPublisherNickFromPubSubItem(item.elem);
+ info_out->published_nick = state_elem->Attr(QN_NICK);
+ state_serializer_->Parse(state_elem, state_out);
+ return true;
+ }
+
+ virtual bool StatesEqual(const C& state1, const C& state2) {
+ return state1 == state2;
+ }
+
+ PubSubClient* client() { return client_; }
+ const QName& state_name() { return state_name_; }
+
+ private:
+ void OnItems(PubSubClient* pub_sub_client,
+ const std::vector<PubSubItem>& items) {
+ for (std::vector<PubSubItem>::const_iterator item = items.begin();
+ item != items.end(); ++item) {
+ OnItem(*item);
+ }
+ }
+
+ void OnItem(const PubSubItem& item) {
+ const std::string& itemid = item.itemid;
+ StateItemInfo info;
+ C new_state;
+
+ bool retracted = !ParseStateItem(item, &info, &new_state);
+ if (retracted) {
+ bool known_itemid =
+ (info_by_itemid_.find(itemid) != info_by_itemid_.end());
+ if (!known_itemid) {
+ // Nothing to retract, and nothing to publish.
+ // Probably a different state type.
+ return;
+ } else {
+ info = info_by_itemid_[itemid];
+ info_by_itemid_.erase(itemid);
+ new_state = default_state_;
+ }
+ } else {
+ // TODO: Assert new key matches the known key. It
+ // shouldn't change!
+ info_by_itemid_[itemid] = info;
+ }
+
+ std::string key = key_serializer_->GetKey(
+ info.publisher_nick, info.published_nick);
+ bool has_old_state = (state_by_key_.find(key) != state_by_key_.end());
+ C old_state = has_old_state ? state_by_key_[key] : default_state_;
+ if ((retracted && !has_old_state) || StatesEqual(new_state, old_state)) {
+ // Nothing change, so don't bother signalling.
+ return;
+ }
+
+ if (retracted || StatesEqual(new_state, default_state_)) {
+ // We treat a default state similar to a retract.
+ state_by_key_.erase(key);
+ } else {
+ state_by_key_[key] = new_state;
+ }
+
+ PubSubStateChange<C> change;
+ if (!retracted) {
+ // Retracts do not have publisher information.
+ change.publisher_nick = info.publisher_nick;
+ }
+ change.published_nick = info.published_nick;
+ change.old_state = old_state;
+ change.new_state = new_state;
+ SignalStateChange(change);
+ }
+
+ void OnPublishResult(PubSubClient* pub_sub_client,
+ const std::string& task_id,
+ const XmlElement* item) {
+ SignalPublishResult(task_id, item);
+ }
+
+ void OnPublishError(PubSubClient* pub_sub_client,
+ const std::string& task_id,
+ const buzz::XmlElement* item,
+ const buzz::XmlElement* stanza) {
+ SignalPublishError(task_id, item, stanza);
+ }
+
+ void OnRetractResult(PubSubClient* pub_sub_client,
+ const std::string& task_id) {
+ // There's no point in differentiating between publish and retract
+ // errors, so we simplify by making them both signal a publish
+ // result.
+ const XmlElement* item = NULL;
+ SignalPublishResult(task_id, item);
+ }
+
+ void OnRetractError(PubSubClient* pub_sub_client,
+ const std::string& task_id,
+ const buzz::XmlElement* stanza) {
+ // There's no point in differentiating between publish and retract
+ // errors, so we simplify by making them both signal a publish
+ // error.
+ const XmlElement* item = NULL;
+ SignalPublishError(task_id, item, stanza);
+ }
+
+ std::string publisher_nick_;
+ PubSubClient* client_;
+ const QName state_name_;
+ C default_state_;
+ talk_base::scoped_ptr<PubSubStateKeySerializer> key_serializer_;
+ talk_base::scoped_ptr<PubSubStateSerializer<C> > state_serializer_;
+ // key => state
+ std::map<std::string, C> state_by_key_;
+ // itemid => StateItemInfo
+ std::map<std::string, StateItemInfo> info_by_itemid_;
+
+ DISALLOW_COPY_AND_ASSIGN(PubSubStateClient);
+};
+} // namespace buzz
+
+#endif // TALK_XMPP_PUBSUBSTATECLIENT_H_
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/pubsubtasks.cc b/chromium/third_party/libjingle/source/talk/xmpp/pubsubtasks.cc
index bbefbe55cf6..015708eb5e9 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/pubsubtasks.cc
+++ b/chromium/third_party/libjingle/source/talk/xmpp/pubsubtasks.cc
@@ -173,9 +173,16 @@ void PubSubRequestTask::HandleResult(const XmlElement* stanza) {
SignalResult(this, items);
}
+int PubSubReceiveTask::ProcessStart() {
+ if (SignalUpdate.is_empty()) {
+ return STATE_DONE;
+ }
+ return ReceiveTask::ProcessStart();
+}
+
bool PubSubReceiveTask::WantsStanza(const XmlElement* stanza) {
return MatchStanzaFrom(stanza, pubsubjid_) &&
- IsPubSubEventItemsElem(stanza, node_);
+ IsPubSubEventItemsElem(stanza, node_) && !SignalUpdate.is_empty();
}
void PubSubReceiveTask::ReceiveStanza(const XmlElement* stanza) {
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/pubsubtasks.h b/chromium/third_party/libjingle/source/talk/xmpp/pubsubtasks.h
index f0a1581783c..2ba618b341c 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/pubsubtasks.h
+++ b/chromium/third_party/libjingle/source/talk/xmpp/pubsubtasks.h
@@ -71,6 +71,7 @@ class PubSubReceiveTask : public ReceiveTask {
node_(node) {
}
+ virtual int ProcessStart();
sigslot::signal2<PubSubReceiveTask*,
const std::vector<PubSubItem>&> SignalUpdate;
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/rostermoduleimpl.cc b/chromium/third_party/libjingle/source/talk/xmpp/rostermoduleimpl.cc
index 31b3abdf0fb..993cfa905f8 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/rostermoduleimpl.cc
+++ b/chromium/third_party/libjingle/source/talk/xmpp/rostermoduleimpl.cc
@@ -351,10 +351,6 @@ XmppPresenceImpl::set_raw_xml(const XmlElement * xml) {
xml->Name() != QN_PRESENCE)
return XMPP_RETURN_BADARGUMENT;
- const std::string& type = xml->Attr(QN_TYPE);
- if (type != STR_EMPTY && type != "unavailable")
- return XMPP_RETURN_BADARGUMENT;
-
raw_xml_.reset(new XmlElement(*xml));
return XMPP_RETURN_OK;
}
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/xmppengineimpl.cc b/chromium/third_party/libjingle/source/talk/xmpp/xmppengineimpl.cc
index d4c9c7d5f67..cf07ab70ab5 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/xmppengineimpl.cc
+++ b/chromium/third_party/libjingle/source/talk/xmpp/xmppengineimpl.cc
@@ -418,8 +418,7 @@ void XmppEngineImpl::StartTls(const std::string& domain) {
XmppEngineImpl::EnterExit::EnterExit(XmppEngineImpl* engine)
: engine_(engine),
- state_(engine->state_),
- error_(engine->error_code_) {
+ state_(engine->state_) {
engine->engine_entered_ += 1;
}
diff --git a/chromium/third_party/libjingle/source/talk/xmpp/xmppengineimpl.h b/chromium/third_party/libjingle/source/talk/xmpp/xmppengineimpl.h
index e292e75d1ce..82786813651 100644
--- a/chromium/third_party/libjingle/source/talk/xmpp/xmppengineimpl.h
+++ b/chromium/third_party/libjingle/source/talk/xmpp/xmppengineimpl.h
@@ -234,8 +234,6 @@ class XmppEngineImpl : public XmppEngine {
private:
XmppEngineImpl* engine_;
State state_;
- Error error_;
-
};
friend class StanzaParseHandler;