From 5e53579eba120b41b4a96cdf1c9c1500ac56aae8 Mon Sep 17 00:00:00 2001 From: "sarandogou0@gmail.com" Date: Wed, 23 Jul 2014 10:55:17 +0200 Subject: [PATCH] First commit --- AStyle.sh | 1 + LICENSE-BSD | 27 + LICENSE-GPL3 | 674 +++ README.md | 55 + WebRTC.htm | 315 + common/_AsyncEvent.cc | 198 + common/_AsyncEvent.h | 111 + common/_Buffer.cc | 39 + common/_Buffer.h | 26 + common/_Common.cc | 106 + common/_Common.h | 457 ++ common/_Config.h | 141 + common/_Debug.h | 45 + common/_Main.cc | 182 + common/_MediaStream.cc | 234 + common/_MediaStream.h | 72 + common/_MediaStreamConstraints.cc | 18 + common/_MediaStreamConstraints.h | 35 + common/_MediaStreamTrack.cc | 384 ++ common/_MediaStreamTrack.h | 166 + common/_MediaTrackConstraints.cc | 22 + common/_MediaTrackConstraints.h | 47 + common/_NavigatorUserMedia.cc | 55 + common/_NavigatorUserMedia.h | 19 + common/_PeerConnection.cc | 810 +++ common/_PeerConnection.h | 148 + common/_RTCDisplay.cc | 420 ++ common/_RTCDisplay.h | 104 + common/_RTCIceCandidate.cc | 17 + common/_RTCIceCandidate.h | 32 + common/_RTCMediaConstraints.cc | 38 + common/_RTCMediaConstraints.h | 31 + common/_SessionDescription.cc | 102 + common/_SessionDescription.h | 30 + common/_Utils.cc | 294 + common/_Utils.h | 47 + common/jsoncpp/json/json-forwards.h | 251 + common/jsoncpp/json/json.h | 1830 ++++++ common/jsoncpp/jsoncpp.cc | 4231 ++++++++++++++ common/mac/.DS_Store | Bin 0 -> 6148 bytes common/mac/_WebRtcVideoCapturer.cc | 0 common/mac/_WebRtcVideoCapturer.h | 0 common/mac/_messagehandler.cc | 37 + common/mac/_videocapturer.cc | 742 +++ common/resource.h | 14 + common/webrtc-everywhere-common.aps | Bin 0 -> 2624 bytes common/webrtc-everywhere-common.rc | Bin 0 -> 4588 bytes common/webrtc-everywhere-common.vcproj | 238 + common/webrtc-everywhere-common.vcxproj | 147 + .../webrtc-everywhere-common.vcxproj.filters | 119 + common/webrtc-everywhere-console.vcxproj | 94 + .../webrtc-everywhere-console.vcxproj.filters | 22 + git.exe.stackdump | 28 + ie/BrowserCallback.cc | 56 + ie/BrowserCallback.h | 33 + ie/Debug/webrtc-everywhere.res | Bin 0 -> 25628 bytes ie/DictOptions.cc | 8 + ie/DictOptions.h | 49 + ie/DictOptions.rgs | 26 + ie/MediaSourceStates.cc | 140 + ie/MediaSourceStates.h | 67 + ie/MediaSourceStates.rgs | 16 + ie/MediaStream.cc | 320 + ie/MediaStream.h | 85 + ie/MediaStream.rgs | 16 + ie/MediaStreamEvent.cc | 55 + ie/MediaStreamEvent.h | 58 + ie/MediaStreamEvent.rgs | 16 + ie/MediaStreamTrack.cc | 379 ++ ie/MediaStreamTrack.h | 104 + ie/MediaStreamTrack.rgs | 16 + ie/PeerConnection.cc | 860 +++ ie/PeerConnection.h | 112 + ie/PeerConnection.rgs | 26 + ie/RTCIceCandidate.cc | 90 + ie/RTCIceCandidate.h | 62 + ie/RTCIceCandidate.rgs | 16 + ie/RTCIceCandidate1.rgs | 16 + ie/RTCIceCandidate2.rgs | 16 + ie/RTCIceCandidate3.rgs | 16 + ie/RTCIceCandidate4.rgs | 16 + ie/RTCPeerConnectionIceEvent.cc | 53 + ie/RTCPeerConnectionIceEvent.h | 58 + ie/RTCPeerConnectionIceEvent.rgs | 16 + ie/RTCStats.cc | 98 + ie/RTCStats.h | 64 + ie/RTCStats.rgs | 16 + ie/RTCStatsReport.cc | 61 + ie/RTCStatsReport.h | 58 + ie/RTCStatsReport.rgs | 16 + ie/SessionDescription.cc | 124 + ie/SessionDescription.h | 60 + ie/SessionDescription.rgs | 26 + ie/SourceInfo.cc | 71 + ie/SourceInfo.h | 62 + ie/SourceInfo.rgs | 16 + ie/Utils.cc | 439 ++ ie/Utils.h | 51 + ie/WebRTC.bmp | Bin 0 -> 246 bytes ie/WebRTC.cc | 388 ++ ie/WebRTC.h | 221 + ie/WebRTC.rgs | 34 + ie/_IWebRTCEvents_CP.h | 8 + ie/dlldata.c | 40 + ie/dllmain.cc | 37 + ie/dllmain.h | 10 + ie/resource.h | 32 + ie/stdafx.cc | 7 + ie/stdafx.h | 24 + ie/targetver.h | 26 + ie/webrtc-everywhere-ie.vcproj | 403 ++ ie/webrtc-everywhere-ie.vcxproj | 235 + ie/webrtc-everywhere-ie.vcxproj.filters | 207 + ie/webrtc-everywhere.aps | Bin 0 -> 13468 bytes ie/webrtc-everywhere.cc | 65 + ie/webrtc-everywhere.def | 10 + ie/webrtc-everywhere.rc | 160 + ie/webrtc-everywhere.rgs | 11 + ie/webrtc-everywherePS.vcproj | 186 + ie/webrtc-everywherePS.vcxproj | 104 + ie/webrtc-everywherePS.vcxproj.filters | 26 + ie/webrtc-everywhereps.def | 8 + ie/webrtceverywhere.idl | 365 ++ ie/webrtceverywhere_i.c | 160 + ie/webrtceverywhere_i.h | 3305 +++++++++++ ie/webrtceverywhere_p.c | 5162 +++++++++++++++++ npapi/BrowserCallback.cc | 104 + npapi/BrowserCallback.h | 49 + npapi/MediaSourceStates.cc | 245 + npapi/MediaSourceStates.h | 49 + npapi/MediaStream.cc | 393 ++ npapi/MediaStream.h | 65 + npapi/MediaStreamEvent.cc | 165 + npapi/MediaStreamEvent.h | 51 + npapi/MediaStreamTrack.cc | 484 ++ npapi/MediaStreamTrack.h | 68 + npapi/NPCommon.h | 44 + npapi/PeerConnection.cc | 817 +++ npapi/PeerConnection.h | 70 + npapi/Plugin.cc | 306 + npapi/Plugin.h | 57 + npapi/RTCIceCandidate.cc | 194 + npapi/RTCIceCandidate.h | 52 + npapi/RTCPeerConnectionIceEvent.cc | 162 + npapi/RTCPeerConnectionIceEvent.h | 49 + npapi/RTCStats.cc | 213 + npapi/RTCStats.h | 51 + npapi/RTCStatsReport.cc | 171 + npapi/RTCStatsReport.h | 51 + npapi/Release/webrtc-everywhere-npapi.res | Bin 0 -> 1052 bytes npapi/SessionDescription.cc | 206 + npapi/SessionDescription.h | 56 + npapi/SourceInfo.cc | 192 + npapi/SourceInfo.h | 49 + npapi/Utils.cc | 480 ++ npapi/Utils.h | 44 + npapi/WebRTC.cc | 462 ++ npapi/WebRTC.h | 74 + npapi/dllmain.cc | 39 + npapi/npapi-includes.h | 15 + npapi/resource.h | 14 + npapi/webrtc-everywhere-npapi.aps | Bin 0 -> 20296 bytes npapi/webrtc-everywhere-npapi.def | 6 + npapi/webrtc-everywhere-npapi.rc | 103 + npapi/webrtc-everywhere-npapi.vcproj | 236 + npapi/webrtc-everywhere-npapi.vcxproj | 154 + npapi/webrtc-everywhere-npapi.vcxproj.filters | 130 + .../common/include/npapi-sdk/headers/npapi.h | 925 +++ .../include/npapi-sdk/headers/npfunctions.h | 329 ++ .../include/npapi-sdk/headers/npruntime.h | 392 ++ .../include/npapi-sdk/headers/nptypes.h | 121 + .../webrtc-sdk/talk/app/webrtc/audiotrack.h | 70 + .../talk/app/webrtc/audiotrackrenderer.h | 59 + .../webrtc-sdk/talk/app/webrtc/datachannel.h | 246 + .../talk/app/webrtc/datachannelinterface.h | 141 + .../webrtc-sdk/talk/app/webrtc/dtmfsender.h | 138 + .../talk/app/webrtc/dtmfsenderinterface.h | 105 + .../app/webrtc/fakeportallocatorfactory.h | 74 + .../include/webrtc-sdk/talk/app/webrtc/jsep.h | 164 + .../talk/app/webrtc/jsepicecandidate.h | 92 + .../talk/app/webrtc/jsepsessiondescription.h | 106 + .../talk/app/webrtc/localaudiosource.h | 72 + .../app/webrtc/mediaconstraintsinterface.h | 145 + .../webrtc-sdk/talk/app/webrtc/mediastream.h | 75 + .../talk/app/webrtc/mediastreamhandler.h | 295 + .../talk/app/webrtc/mediastreaminterface.h | 264 + .../talk/app/webrtc/mediastreamprovider.h | 84 + .../talk/app/webrtc/mediastreamproxy.h | 54 + .../talk/app/webrtc/mediastreamsignaling.h | 397 ++ .../talk/app/webrtc/mediastreamtrack.h | 81 + .../talk/app/webrtc/mediastreamtrackproxy.h | 77 + .../webrtc-sdk/talk/app/webrtc/notifier.h | 77 + .../talk/app/webrtc/peerconnection.h | 204 + .../talk/app/webrtc/peerconnectionfactory.h | 133 + .../talk/app/webrtc/peerconnectioninterface.h | 528 ++ .../talk/app/webrtc/peerconnectionproxy.h | 75 + .../talk/app/webrtc/portallocatorfactory.h | 70 + .../webrtc-sdk/talk/app/webrtc/proxy.h | 287 + .../talk/app/webrtc/remoteaudiosource.h | 66 + .../talk/app/webrtc/remotevideocapturer.h | 65 + .../webrtc-sdk/talk/app/webrtc/sctputils.h | 55 + .../talk/app/webrtc/statscollector.h | 129 + .../webrtc-sdk/talk/app/webrtc/statstypes.h | 215 + .../talk/app/webrtc/streamcollection.h | 125 + .../webrtc-sdk/talk/app/webrtc/umametrics.h | 59 + .../webrtc-sdk/talk/app/webrtc/videosource.h | 103 + .../talk/app/webrtc/videosourceinterface.h | 58 + .../talk/app/webrtc/videosourceproxy.h | 52 + .../webrtc-sdk/talk/app/webrtc/videotrack.h | 64 + .../talk/app/webrtc/videotrackrenderers.h | 77 + .../webrtc-sdk/talk/app/webrtc/webrtcsdp.h | 81 + .../talk/app/webrtc/webrtcsession.h | 354 ++ .../webrtc/webrtcsessiondescriptionfactory.h | 169 + .../include/webrtc-sdk/talk/base/asyncfile.h | 57 + .../webrtc-sdk/talk/base/asynchttprequest.h | 121 + .../webrtc-sdk/talk/base/asyncinvoker-inl.h | 146 + .../webrtc-sdk/talk/base/asyncinvoker.h | 151 + .../webrtc-sdk/talk/base/asyncpacketsocket.h | 157 + .../talk/base/asyncresolverinterface.h | 64 + .../webrtc-sdk/talk/base/asyncsocket.h | 141 + .../webrtc-sdk/talk/base/asynctcpsocket.h | 117 + .../webrtc-sdk/talk/base/asyncudpsocket.h | 80 + .../include/webrtc-sdk/talk/base/atomicops.h | 166 + .../webrtc-sdk/talk/base/autodetectproxy.h | 107 + .../webrtc-sdk/talk/base/bandwidthsmoother.h | 76 + .../include/webrtc-sdk/talk/base/base64.h | 104 + .../include/webrtc-sdk/talk/base/basicdefs.h | 37 + .../include/webrtc-sdk/talk/base/basictypes.h | 171 + .../include/webrtc-sdk/talk/base/bind.h | 604 ++ .../include/webrtc-sdk/talk/base/buffer.h | 119 + .../include/webrtc-sdk/talk/base/bytebuffer.h | 136 + .../include/webrtc-sdk/talk/base/byteorder.h | 185 + .../include/webrtc-sdk/talk/base/callback.h | 278 + .../include/webrtc-sdk/talk/base/checks.h | 44 + .../include/webrtc-sdk/talk/base/common.h | 218 + .../webrtc-sdk/talk/base/compile_assert.h | 99 + .../webrtc-sdk/talk/base/constructormagic.h | 58 + .../include/webrtc-sdk/talk/base/cpumonitor.h | 140 + .../include/webrtc-sdk/talk/base/crc32.h | 51 + .../webrtc-sdk/talk/base/criticalsection.h | 196 + .../webrtc-sdk/talk/base/cryptstring.h | 200 + .../include/webrtc-sdk/talk/base/dbus.h | 185 + .../include/webrtc-sdk/talk/base/diskcache.h | 142 + .../webrtc-sdk/talk/base/diskcache_win32.h | 46 + .../include/webrtc-sdk/talk/base/dscp.h | 62 + .../include/webrtc-sdk/talk/base/event.h | 68 + .../webrtc-sdk/talk/base/fakecpumonitor.h | 49 + .../webrtc-sdk/talk/base/fakenetwork.h | 136 + .../webrtc-sdk/talk/base/fakesslidentity.h | 111 + .../webrtc-sdk/talk/base/faketaskrunner.h | 55 + .../include/webrtc-sdk/talk/base/filelock.h | 70 + .../include/webrtc-sdk/talk/base/fileutils.h | 476 ++ .../webrtc-sdk/talk/base/fileutils_mock.h | 270 + .../talk/base/firewallsocketserver.h | 137 + .../include/webrtc-sdk/talk/base/flags.h | 284 + .../webrtc-sdk/talk/base/genericslot.h | 258 + .../include/webrtc-sdk/talk/base/gunit.h | 105 + .../include/webrtc-sdk/talk/base/gunit_prod.h | 41 + .../include/webrtc-sdk/talk/base/helpers.h | 73 + .../include/webrtc-sdk/talk/base/httpbase.h | 201 + .../include/webrtc-sdk/talk/base/httpclient.h | 219 + .../webrtc-sdk/talk/base/httpcommon-inl.h | 148 + .../include/webrtc-sdk/talk/base/httpcommon.h | 463 ++ .../webrtc-sdk/talk/base/httprequest.h | 132 + .../include/webrtc-sdk/talk/base/httpserver.h | 154 + .../webrtc-sdk/talk/base/ifaddrs-android.h | 50 + .../include/webrtc-sdk/talk/base/ipaddress.h | 158 + .../include/webrtc-sdk/talk/base/json.h | 106 + .../talk/base/latebindingsymboltable.h | 86 + .../talk/base/libdbusglibsymboltable.h | 73 + .../include/webrtc-sdk/talk/base/linked_ptr.h | 142 + .../include/webrtc-sdk/talk/base/linux.h | 140 + .../webrtc-sdk/talk/base/linuxfdwalk.h | 51 + .../webrtc-sdk/talk/base/linuxwindowpicker.h | 68 + .../include/webrtc-sdk/talk/base/logging.h | 404 ++ .../webrtc-sdk/talk/base/macasyncsocket.h | 91 + .../talk/base/maccocoasocketserver.h | 65 + .../talk/base/maccocoathreadhelper.h | 44 + .../webrtc-sdk/talk/base/macconversion.h | 56 + .../webrtc-sdk/talk/base/macsocketserver.h | 130 + .../include/webrtc-sdk/talk/base/macutils.h | 76 + .../webrtc-sdk/talk/base/macwindowpicker.h | 31 + .../include/webrtc-sdk/talk/base/mathutils.h | 37 + .../common/include/webrtc-sdk/talk/base/md5.h | 40 + .../include/webrtc-sdk/talk/base/md5digest.h | 63 + .../webrtc-sdk/talk/base/messagedigest.h | 126 + .../webrtc-sdk/talk/base/messagehandler.h | 85 + .../webrtc-sdk/talk/base/messagequeue.h | 271 + .../include/webrtc-sdk/talk/base/move.h | 207 + .../include/webrtc-sdk/talk/base/multipart.h | 94 + .../include/webrtc-sdk/talk/base/natserver.h | 127 + .../webrtc-sdk/talk/base/natsocketfactory.h | 183 + .../include/webrtc-sdk/talk/base/nattypes.h | 64 + .../include/webrtc-sdk/talk/base/nethelpers.h | 82 + .../include/webrtc-sdk/talk/base/network.h | 262 + .../webrtc-sdk/talk/base/nssidentity.h | 147 + .../webrtc-sdk/talk/base/nssstreamadapter.h | 129 + .../webrtc-sdk/talk/base/nullsocketserver.h | 78 + .../include/webrtc-sdk/talk/base/openssl.h | 37 + .../webrtc-sdk/talk/base/openssladapter.h | 105 + .../webrtc-sdk/talk/base/openssldigest.h | 67 + .../webrtc-sdk/talk/base/opensslidentity.h | 167 + .../talk/base/opensslstreamadapter.h | 215 + .../webrtc-sdk/talk/base/optionsfile.h | 66 + .../include/webrtc-sdk/talk/base/pathutils.h | 180 + .../talk/base/physicalsocketserver.h | 137 + .../include/webrtc-sdk/talk/base/posix.h | 42 + .../include/webrtc-sdk/talk/base/profiler.h | 178 + .../webrtc-sdk/talk/base/proxydetect.h | 48 + .../include/webrtc-sdk/talk/base/proxyinfo.h | 59 + .../webrtc-sdk/talk/base/proxyserver.h | 113 + .../webrtc-sdk/talk/base/ratelimiter.h | 80 + .../webrtc-sdk/talk/base/ratetracker.h | 59 + .../include/webrtc-sdk/talk/base/refcount.h | 95 + .../base/referencecountedsingletonfactory.h | 174 + .../webrtc-sdk/talk/base/rollingaccumulator.h | 189 + .../webrtc-sdk/talk/base/safe_conversions.h | 96 + .../talk/base/safe_conversions_impl.h | 205 + .../webrtc-sdk/talk/base/schanneladapter.h | 94 + .../talk/base/scoped_autorelease_pool.h | 76 + .../include/webrtc-sdk/talk/base/scoped_ptr.h | 590 ++ .../webrtc-sdk/talk/base/scoped_ref_ptr.h | 164 + .../talk/base/scopedptrcollection.h | 77 + .../include/webrtc-sdk/talk/base/sec_buffer.h | 173 + .../include/webrtc-sdk/talk/base/sha1.h | 28 + .../include/webrtc-sdk/talk/base/sha1digest.h | 64 + .../talk/base/sharedexclusivelock.h | 93 + .../webrtc-sdk/talk/base/signalthread.h | 173 + .../include/webrtc-sdk/talk/base/sigslot.h | 2850 +++++++++ .../webrtc-sdk/talk/base/sigslotrepeater.h | 111 + .../include/webrtc-sdk/talk/base/socket.h | 205 + .../webrtc-sdk/talk/base/socket_unittest.h | 105 + .../webrtc-sdk/talk/base/socketadapters.h | 261 + .../webrtc-sdk/talk/base/socketaddress.h | 231 + .../webrtc-sdk/talk/base/socketaddresspair.h | 58 + .../webrtc-sdk/talk/base/socketfactory.h | 55 + .../include/webrtc-sdk/talk/base/socketpool.h | 160 + .../webrtc-sdk/talk/base/socketserver.h | 61 + .../webrtc-sdk/talk/base/socketstream.h | 74 + .../include/webrtc-sdk/talk/base/ssladapter.h | 78 + .../include/webrtc-sdk/talk/base/sslconfig.h | 50 + .../webrtc-sdk/talk/base/sslfingerprint.h | 68 + .../webrtc-sdk/talk/base/sslidentity.h | 189 + .../include/webrtc-sdk/talk/base/sslroots.h | 4930 ++++++++++++++++ .../webrtc-sdk/talk/base/sslsocketfactory.h | 98 + .../webrtc-sdk/talk/base/sslstreamadapter.h | 179 + .../talk/base/sslstreamadapterhelper.h | 135 + .../include/webrtc-sdk/talk/base/stream.h | 837 +++ .../webrtc-sdk/talk/base/stringdigest.h | 34 + .../webrtc-sdk/talk/base/stringencode.h | 227 + .../webrtc-sdk/talk/base/stringutils.h | 335 ++ .../include/webrtc-sdk/talk/base/systeminfo.h | 98 + .../include/webrtc-sdk/talk/base/task.h | 194 + .../include/webrtc-sdk/talk/base/taskparent.h | 79 + .../include/webrtc-sdk/talk/base/taskrunner.h | 117 + .../webrtc-sdk/talk/base/template_util.h | 106 + .../include/webrtc-sdk/talk/base/testbase64.h | 5 + .../include/webrtc-sdk/talk/base/testclient.h | 110 + .../webrtc-sdk/talk/base/testechoserver.h | 90 + .../include/webrtc-sdk/talk/base/testutils.h | 646 +++ .../include/webrtc-sdk/talk/base/thread.h | 311 + .../include/webrtc-sdk/talk/base/timeutils.h | 113 + .../include/webrtc-sdk/talk/base/timing.h | 76 + .../webrtc-sdk/talk/base/transformadapter.h | 97 + .../webrtc-sdk/talk/base/unixfilesystem.h | 143 + .../include/webrtc-sdk/talk/base/urlencode.h | 60 + .../webrtc-sdk/talk/base/versionparsing.h | 52 + .../talk/base/virtualsocketserver.h | 251 + .../include/webrtc-sdk/talk/base/win32.h | 146 + .../webrtc-sdk/talk/base/win32filesystem.h | 118 + .../webrtc-sdk/talk/base/win32regkey.h | 354 ++ .../webrtc-sdk/talk/base/win32socketinit.h | 37 + .../webrtc-sdk/talk/base/win32socketserver.h | 181 + .../webrtc-sdk/talk/base/win32toolhelp.h | 166 + .../webrtc-sdk/talk/base/win32window.h | 77 + .../webrtc-sdk/talk/base/win32windowpicker.h | 33 + .../include/webrtc-sdk/talk/base/window.h | 141 + .../webrtc-sdk/talk/base/windowpicker.h | 78 + .../talk/base/windowpickerfactory.h | 76 + .../webrtc-sdk/talk/base/winfirewall.h | 73 + .../include/webrtc-sdk/talk/base/winping.h | 120 + .../include/webrtc-sdk/talk/base/worker.h | 89 + .../webrtc-sdk/talk/media/base/audioframe.h | 63 + .../talk/media/base/audiorenderer.h | 76 + .../talk/media/base/capturemanager.h | 114 + .../talk/media/base/capturerenderadapter.h | 91 + .../webrtc-sdk/talk/media/base/codec.h | 325 ++ .../webrtc-sdk/talk/media/base/constants.h | 142 + .../webrtc-sdk/talk/media/base/cpuid.h | 76 + .../webrtc-sdk/talk/media/base/cryptoparams.h | 54 + .../talk/media/base/fakecapturemanager.h | 52 + .../talk/media/base/fakemediaengine.h | 1086 ++++ .../talk/media/base/fakemediaprocessor.h | 79 + .../talk/media/base/fakenetworkinterface.h | 259 + .../webrtc-sdk/talk/media/base/fakertp.h | 104 + .../talk/media/base/fakevideocapturer.h | 154 + .../talk/media/base/fakevideorenderer.h | 168 + .../talk/media/base/filemediaengine.h | 339 ++ .../talk/media/base/hybriddataengine.h | 76 + .../talk/media/base/hybridvideoengine.h | 286 + .../webrtc-sdk/talk/media/base/mediachannel.h | 1284 ++++ .../webrtc-sdk/talk/media/base/mediacommon.h | 44 + .../webrtc-sdk/talk/media/base/mediaengine.h | 395 ++ .../talk/media/base/mutedvideocapturer.h | 60 + .../talk/media/base/nullvideoframe.h | 94 + .../talk/media/base/nullvideorenderer.h | 48 + .../talk/media/base/rtpdataengine.h | 145 + .../webrtc-sdk/talk/media/base/rtpdump.h | 233 + .../webrtc-sdk/talk/media/base/rtputils.h | 79 + .../webrtc-sdk/talk/media/base/screencastid.h | 88 + .../webrtc-sdk/talk/media/base/streamparams.h | 228 + .../webrtc-sdk/talk/media/base/testutils.h | 252 + .../webrtc-sdk/talk/media/base/videoadapter.h | 214 + .../talk/media/base/videocapturer.h | 402 ++ .../webrtc-sdk/talk/media/base/videocommon.h | 265 + .../talk/media/base/videoengine_unittest.h | 1834 ++++++ .../webrtc-sdk/talk/media/base/videoframe.h | 195 + .../talk/media/base/videoframe_unittest.h | 2107 +++++++ .../talk/media/base/videoprocessor.h | 50 + .../talk/media/base/videorenderer.h | 58 + .../talk/media/base/voiceprocessor.h | 56 + .../talk/media/base/yuvframegenerator.h | 78 + .../talk/media/devices/carbonvideorenderer.h | 72 + .../talk/media/devices/deviceinfo.h | 42 + .../talk/media/devices/devicemanager.h | 216 + .../talk/media/devices/dummydevicemanager.h | 51 + .../talk/media/devices/fakedevicemanager.h | 222 + .../talk/media/devices/filevideocapturer.h | 156 + .../talk/media/devices/gdivideorenderer.h | 60 + .../talk/media/devices/gtkvideorenderer.h | 69 + .../talk/media/devices/libudevsymboltable.h | 79 + .../talk/media/devices/linuxdevicemanager.h | 55 + .../talk/media/devices/macdevicemanager.h | 56 + .../webrtc-sdk/talk/media/devices/v4llookup.h | 44 + .../talk/media/devices/videorendererfactory.h | 66 + .../talk/media/devices/win32devicemanager.h | 60 + .../talk/media/devices/yuvframescapturer.h | 71 + .../talk/media/other/linphonemediaengine.h | 174 + .../talk/media/sctp/sctpdataengine.h | 262 + .../talk/media/webrtc/fakewebrtccommon.h | 66 + .../talk/media/webrtc/fakewebrtcdeviceinfo.h | 123 + .../talk/media/webrtc/fakewebrtcvcmfactory.h | 63 + .../webrtc/fakewebrtcvideocapturemodule.h | 150 + .../talk/media/webrtc/fakewebrtcvideoengine.h | 1283 ++++ .../talk/media/webrtc/fakewebrtcvoiceengine.h | 1152 ++++ .../talk/media/webrtc/webrtccommon.h | 76 + .../talk/media/webrtc/webrtcexport.h | 79 + .../talk/media/webrtc/webrtcmediaengine.h | 203 + .../media/webrtc/webrtcpassthroughrender.h | 211 + .../media/webrtc/webrtctexturevideoframe.h | 113 + .../talk/media/webrtc/webrtcvideocapturer.h | 107 + .../media/webrtc/webrtcvideochannelfactory.h | 44 + .../media/webrtc/webrtcvideodecoderfactory.h | 53 + .../media/webrtc/webrtcvideoencoderfactory.h | 89 + .../talk/media/webrtc/webrtcvideoengine.h | 468 ++ .../talk/media/webrtc/webrtcvideoengine2.h | 332 ++ .../talk/media/webrtc/webrtcvideoframe.h | 134 + .../webrtc-sdk/talk/media/webrtc/webrtcvie.h | 151 + .../webrtc-sdk/talk/media/webrtc/webrtcvoe.h | 179 + .../talk/media/webrtc/webrtcvoiceengine.h | 464 ++ .../talk/p2p/base/asyncstuntcpsocket.h | 67 + .../talk/p2p/base/basicpacketsocketfactory.h | 68 + .../webrtc-sdk/talk/p2p/base/candidate.h | 222 + .../include/webrtc-sdk/talk/p2p/base/common.h | 37 + .../webrtc-sdk/talk/p2p/base/constants.h | 276 + .../webrtc-sdk/talk/p2p/base/dtlstransport.h | 256 + .../talk/p2p/base/dtlstransportchannel.h | 264 + .../webrtc-sdk/talk/p2p/base/fakesession.h | 509 ++ .../webrtc-sdk/talk/p2p/base/p2ptransport.h | 103 + .../talk/p2p/base/p2ptransportchannel.h | 259 + .../talk/p2p/base/packetsocketfactory.h | 69 + .../webrtc-sdk/talk/p2p/base/parsing.h | 157 + .../include/webrtc-sdk/talk/p2p/base/port.h | 596 ++ .../webrtc-sdk/talk/p2p/base/portallocator.h | 190 + .../talk/p2p/base/portallocatorsessionproxy.h | 123 + .../webrtc-sdk/talk/p2p/base/portinterface.h | 143 + .../webrtc-sdk/talk/p2p/base/portproxy.h | 104 + .../webrtc-sdk/talk/p2p/base/pseudotcp.h | 258 + .../webrtc-sdk/talk/p2p/base/rawtransport.h | 81 + .../talk/p2p/base/rawtransportchannel.h | 206 + .../webrtc-sdk/talk/p2p/base/relayport.h | 118 + .../webrtc-sdk/talk/p2p/base/relayserver.h | 252 + .../webrtc-sdk/talk/p2p/base/session.h | 768 +++ .../webrtc-sdk/talk/p2p/base/sessionclient.h | 95 + .../talk/p2p/base/sessiondescription.h | 202 + .../webrtc-sdk/talk/p2p/base/sessionid.h | 37 + .../webrtc-sdk/talk/p2p/base/sessionmanager.h | 211 + .../talk/p2p/base/sessionmessages.h | 243 + .../include/webrtc-sdk/talk/p2p/base/stun.h | 648 +++ .../webrtc-sdk/talk/p2p/base/stunport.h | 214 + .../webrtc-sdk/talk/p2p/base/stunrequest.h | 133 + .../webrtc-sdk/talk/p2p/base/stunserver.h | 78 + .../webrtc-sdk/talk/p2p/base/tcpport.h | 153 + .../talk/p2p/base/testrelayserver.h | 118 + .../webrtc-sdk/talk/p2p/base/teststunserver.h | 55 + .../webrtc-sdk/talk/p2p/base/testturnserver.h | 94 + .../webrtc-sdk/talk/p2p/base/transport.h | 525 ++ .../talk/p2p/base/transportchannel.h | 160 + .../talk/p2p/base/transportchannelimpl.h | 128 + .../talk/p2p/base/transportchannelproxy.h | 112 + .../talk/p2p/base/transportdescription.h | 186 + .../p2p/base/transportdescriptionfactory.h | 83 + .../webrtc-sdk/talk/p2p/base/transportinfo.h | 60 + .../webrtc-sdk/talk/p2p/base/turnport.h | 225 + .../webrtc-sdk/talk/p2p/base/turnserver.h | 187 + .../webrtc-sdk/talk/p2p/base/udpport.h | 34 + .../talk/p2p/client/autoportallocator.h | 69 + .../talk/p2p/client/basicportallocator.h | 246 + .../talk/p2p/client/connectivitychecker.h | 274 + .../talk/p2p/client/fakeportallocator.h | 107 + .../talk/p2p/client/httpportallocator.h | 190 + .../talk/p2p/client/sessionmanagertask.h | 93 + .../talk/p2p/client/sessionsendtask.h | 145 + .../talk/p2p/client/socketmonitor.h | 71 + .../talk/session/media/audiomonitor.h | 75 + .../talk/session/media/bundlefilter.h | 80 + .../webrtc-sdk/talk/session/media/call.h | 309 + .../webrtc-sdk/talk/session/media/channel.h | 724 +++ .../talk/session/media/channelmanager.h | 316 + .../session/media/currentspeakermonitor.h | 120 + .../talk/session/media/externalhmac.h | 90 + .../talk/session/media/mediamessages.h | 169 + .../talk/session/media/mediamonitor.h | 98 + .../talk/session/media/mediarecorder.h | 119 + .../talk/session/media/mediasession.h | 522 ++ .../talk/session/media/mediasessionclient.h | 175 + .../webrtc-sdk/talk/session/media/mediasink.h | 48 + .../talk/session/media/rtcpmuxfilter.h | 86 + .../webrtc-sdk/talk/session/media/soundclip.h | 70 + .../talk/session/media/srtpfilter.h | 327 ++ .../talk/session/media/typingmonitor.h | 84 + .../talk/session/media/voicechannel.h | 33 + .../talk/session/tunnel/pseudotcpchannel.h | 140 + .../tunnel/securetunnelsessionclient.h | 165 + .../talk/session/tunnel/tunnelsessionclient.h | 182 + .../webrtc-sdk/talk/sound/alsasoundsystem.h | 120 + .../webrtc-sdk/talk/sound/alsasymboltable.h | 66 + .../sound/automaticallychosensoundsystem.h | 105 + .../webrtc-sdk/talk/sound/linuxsoundsystem.h | 58 + .../webrtc-sdk/talk/sound/nullsoundsystem.h | 70 + .../talk/sound/nullsoundsystemfactory.h | 50 + .../talk/sound/platformsoundsystem.h | 40 + .../talk/sound/platformsoundsystemfactory.h | 52 + .../talk/sound/pulseaudiosoundsystem.h | 194 + .../talk/sound/pulseaudiosymboltable.h | 104 + .../talk/sound/sounddevicelocator.h | 71 + .../talk/sound/soundinputstreaminterface.h | 85 + .../talk/sound/soundoutputstreaminterface.h | 89 + .../talk/sound/soundsystemfactory.h | 44 + .../talk/sound/soundsysteminterface.h | 129 + .../webrtc-sdk/talk/sound/soundsystemproxy.h | 64 + .../include/webrtc-sdk/talk/xmllite/qname.h | 100 + .../webrtc-sdk/talk/xmllite/xmlbuilder.h | 78 + .../webrtc-sdk/talk/xmllite/xmlconstants.h | 47 + .../webrtc-sdk/talk/xmllite/xmlelement.h | 251 + .../webrtc-sdk/talk/xmllite/xmlnsstack.h | 62 + .../webrtc-sdk/talk/xmllite/xmlparser.h | 120 + .../webrtc-sdk/talk/xmllite/xmlprinter.h | 49 + .../third_party/jsoncpp/assertions.h | 31 + .../webrtc-sdk/third_party/jsoncpp/autolink.h | 24 + .../webrtc-sdk/third_party/jsoncpp/config.h | 98 + .../webrtc-sdk/third_party/jsoncpp/features.h | 49 + .../webrtc-sdk/third_party/jsoncpp/forwards.h | 44 + .../webrtc-sdk/third_party/jsoncpp/json.h | 15 + .../webrtc-sdk/third_party/jsoncpp/reader.h | 213 + .../webrtc-sdk/third_party/jsoncpp/value.h | 1109 ++++ .../webrtc-sdk/third_party/jsoncpp/writer.h | 184 + .../third_party/libyuv/include/libyuv.h | 33 + .../libyuv/include/libyuv/basic_types.h | 118 + .../libyuv/include/libyuv/compare.h | 73 + .../libyuv/include/libyuv/convert.h | 254 + .../libyuv/include/libyuv/convert_argb.h | 225 + .../libyuv/include/libyuv/convert_from.h | 173 + .../libyuv/include/libyuv/convert_from_argb.h | 168 + .../libyuv/include/libyuv/cpu_id.h | 81 + .../libyuv/include/libyuv/format_conversion.h | 168 + .../libyuv/include/libyuv/mjpeg_decoder.h | 201 + .../libyuv/include/libyuv/planar_functions.h | 434 ++ .../libyuv/include/libyuv/rotate.h | 117 + .../libyuv/include/libyuv/rotate_argb.h | 33 + .../third_party/libyuv/include/libyuv/row.h | 1694 ++++++ .../third_party/libyuv/include/libyuv/scale.h | 85 + .../libyuv/include/libyuv/scale_argb.h | 57 + .../libyuv/include/libyuv/scale_row.h | 301 + .../libyuv/include/libyuv/version.h | 16 + .../libyuv/include/libyuv/video_common.h | 182 + .../webrtc-sdk/webrtc/base/constructormagic.h | 41 + .../include/webrtc-sdk/webrtc/common_types.h | 788 +++ .../common_video/interface/i420_video_frame.h | 155 + .../common_video/interface/native_handle.h | 36 + .../interface/texture_video_frame.h | 72 + .../common_video/interface/video_image.h | 72 + .../common_video/libyuv/include/scaler.h | 69 + .../libyuv/include/webrtc_libyuv.h | 177 + .../webrtc-sdk/webrtc/common_video/plane.h | 75 + .../webrtc/modules/interface/module.h | 66 + .../modules/interface/module_common_types.h | 902 +++ .../video_capture/include/video_capture.h | 159 + .../include/video_capture_defines.h | 130 + .../include/video_capture_factory.h | 49 + .../interface/aligned_malloc.h | 59 + .../system_wrappers/interface/asm_defines.h | 59 + .../system_wrappers/interface/atomic32.h | 66 + .../webrtc/system_wrappers/interface/clock.h | 81 + .../interface/compile_assert.h | 90 + .../interface/compile_assert_c.h | 22 + .../interface/condition_variable_wrapper.h | 42 + .../interface/cpu_features_wrapper.h | 51 + .../system_wrappers/interface/cpu_info.h | 29 + .../interface/critical_section_wrapper.h | 54 + .../system_wrappers/interface/data_log.h | 119 + .../system_wrappers/interface/data_log_c.h | 85 + .../system_wrappers/interface/data_log_impl.h | 155 + .../system_wrappers/interface/event_tracer.h | 73 + .../system_wrappers/interface/event_wrapper.h | 60 + .../system_wrappers/interface/field_trial.h | 70 + .../system_wrappers/interface/file_wrapper.h | 87 + .../fix_interlocked_exchange_pointer_win.h | 39 + .../interface/logcat_trace_context.h | 35 + .../system_wrappers/interface/logging.h | 161 + .../system_wrappers/interface/ref_count.h | 82 + .../system_wrappers/interface/rtp_to_ntp.h | 50 + .../interface/rw_lock_wrapper.h | 68 + .../system_wrappers/interface/scoped_ptr.h | 566 ++ .../system_wrappers/interface/scoped_refptr.h | 144 + .../system_wrappers/interface/scoped_vector.h | 149 + .../webrtc/system_wrappers/interface/sleep.h | 24 + .../webrtc/system_wrappers/interface/sort.h | 65 + .../interface/static_instance.h | 153 + .../system_wrappers/interface/stl_util.h | 265 + .../interface/stringize_macros.h | 38 + .../system_wrappers/interface/template_util.h | 114 + .../interface/thread_annotations.h | 99 + .../interface/thread_wrapper.h | 92 + .../system_wrappers/interface/tick_util.h | 298 + .../interface/timestamp_extrapolator.h | 56 + .../webrtc/system_wrappers/interface/trace.h | 92 + .../system_wrappers/interface/trace_event.h | 912 +++ .../system_wrappers/interface/utf_util_win.h | 57 + .../source/condition_variable_event_win.h | 46 + .../source/condition_variable_native_win.h | 54 + .../source/condition_variable_posix.h | 42 + .../source/critical_section_posix.h | 36 + .../source/critical_section_win.h | 38 + .../source/data_log_c_helpers_unittest.h | 58 + .../system_wrappers/source/event_posix.h | 65 + .../webrtc/system_wrappers/source/event_win.h | 41 + .../webrtc/system_wrappers/source/file_impl.h | 70 + .../webrtc/system_wrappers/source/move.h | 226 + .../system_wrappers/source/rw_lock_generic.h | 46 + .../system_wrappers/source/rw_lock_posix.h | 41 + .../system_wrappers/source/rw_lock_win.h | 40 + .../source/set_thread_name_win.h | 108 + .../system_wrappers/source/thread_posix.h | 73 + .../system_wrappers/source/thread_win.h | 65 + .../system_wrappers/source/trace_impl.h | 130 + .../system_wrappers/source/trace_posix.h | 41 + .../webrtc/system_wrappers/source/trace_win.h | 37 + .../source/unittest_utilities.h | 82 + .../include/webrtc-sdk/webrtc/typedefs.h | 112 + thirdparties/win32/bin/AStyle.exe | Bin 0 -> 432128 bytes thirdparties/win32/include/inttypes.h | 305 + thirdparties/win32/include/stdint.h | 247 + webrtc-everywhere.sln | 76 + wininstall/innosetup.iss | 59 + wininstall/webrtc-everywhere-i386-10.4.dmg | Bin 0 -> 5815330 bytes .../project.pbxproj | 803 +++ .../contents.xcworkspacedata | 7 + .../xcshareddata/webrtc-everywhere.xccheckout | 41 + .../UserInterfaceState.xcuserstate | Bin 0 -> 61187 bytes .../WorkspaceSettings.xcsettings | 10 + .../xcschemes/webrtc-everywhere.xcscheme | 59 + .../xcschemes/xcschememanagement.plist | 27 + .../en.lproj/InfoPlist.strings | 2 + .../webrtc-everywhere-Info.plist | 40 + .../webrtc-everywhere-Prefix.pch | 7 + xcode/webrtc-everywhere/webrtc_everywhere.cp | 22 + xcode/webrtc-everywhere/webrtc_everywhere.h | 18 + .../webrtc-everywhere/webrtc_everywherePriv.h | 19 + .../webrtc_everywhereProj.xcconfig | 4 + .../webrtc_everywhereTarget.xcconfig | 9 + 681 files changed, 125528 insertions(+) create mode 100644 AStyle.sh create mode 100644 LICENSE-BSD create mode 100644 LICENSE-GPL3 create mode 100644 README.md create mode 100755 WebRTC.htm create mode 100755 common/_AsyncEvent.cc create mode 100755 common/_AsyncEvent.h create mode 100755 common/_Buffer.cc create mode 100755 common/_Buffer.h create mode 100755 common/_Common.cc create mode 100755 common/_Common.h create mode 100755 common/_Config.h create mode 100755 common/_Debug.h create mode 100755 common/_Main.cc create mode 100755 common/_MediaStream.cc create mode 100755 common/_MediaStream.h create mode 100755 common/_MediaStreamConstraints.cc create mode 100755 common/_MediaStreamConstraints.h create mode 100755 common/_MediaStreamTrack.cc create mode 100755 common/_MediaStreamTrack.h create mode 100755 common/_MediaTrackConstraints.cc create mode 100755 common/_MediaTrackConstraints.h create mode 100755 common/_NavigatorUserMedia.cc create mode 100755 common/_NavigatorUserMedia.h create mode 100755 common/_PeerConnection.cc create mode 100755 common/_PeerConnection.h create mode 100755 common/_RTCDisplay.cc create mode 100755 common/_RTCDisplay.h create mode 100755 common/_RTCIceCandidate.cc create mode 100755 common/_RTCIceCandidate.h create mode 100755 common/_RTCMediaConstraints.cc create mode 100755 common/_RTCMediaConstraints.h create mode 100755 common/_SessionDescription.cc create mode 100755 common/_SessionDescription.h create mode 100755 common/_Utils.cc create mode 100755 common/_Utils.h create mode 100644 common/jsoncpp/json/json-forwards.h create mode 100644 common/jsoncpp/json/json.h create mode 100644 common/jsoncpp/jsoncpp.cc create mode 100755 common/mac/.DS_Store create mode 100644 common/mac/_WebRtcVideoCapturer.cc create mode 100644 common/mac/_WebRtcVideoCapturer.h create mode 100755 common/mac/_messagehandler.cc create mode 100755 common/mac/_videocapturer.cc create mode 100755 common/resource.h create mode 100644 common/webrtc-everywhere-common.aps create mode 100644 common/webrtc-everywhere-common.rc create mode 100644 common/webrtc-everywhere-common.vcproj create mode 100644 common/webrtc-everywhere-common.vcxproj create mode 100644 common/webrtc-everywhere-common.vcxproj.filters create mode 100644 common/webrtc-everywhere-console.vcxproj create mode 100644 common/webrtc-everywhere-console.vcxproj.filters create mode 100644 git.exe.stackdump create mode 100644 ie/BrowserCallback.cc create mode 100644 ie/BrowserCallback.h create mode 100644 ie/Debug/webrtc-everywhere.res create mode 100644 ie/DictOptions.cc create mode 100644 ie/DictOptions.h create mode 100644 ie/DictOptions.rgs create mode 100644 ie/MediaSourceStates.cc create mode 100644 ie/MediaSourceStates.h create mode 100644 ie/MediaSourceStates.rgs create mode 100644 ie/MediaStream.cc create mode 100644 ie/MediaStream.h create mode 100644 ie/MediaStream.rgs create mode 100644 ie/MediaStreamEvent.cc create mode 100644 ie/MediaStreamEvent.h create mode 100644 ie/MediaStreamEvent.rgs create mode 100644 ie/MediaStreamTrack.cc create mode 100644 ie/MediaStreamTrack.h create mode 100644 ie/MediaStreamTrack.rgs create mode 100644 ie/PeerConnection.cc create mode 100644 ie/PeerConnection.h create mode 100644 ie/PeerConnection.rgs create mode 100644 ie/RTCIceCandidate.cc create mode 100644 ie/RTCIceCandidate.h create mode 100644 ie/RTCIceCandidate.rgs create mode 100644 ie/RTCIceCandidate1.rgs create mode 100644 ie/RTCIceCandidate2.rgs create mode 100644 ie/RTCIceCandidate3.rgs create mode 100644 ie/RTCIceCandidate4.rgs create mode 100644 ie/RTCPeerConnectionIceEvent.cc create mode 100644 ie/RTCPeerConnectionIceEvent.h create mode 100644 ie/RTCPeerConnectionIceEvent.rgs create mode 100644 ie/RTCStats.cc create mode 100644 ie/RTCStats.h create mode 100644 ie/RTCStats.rgs create mode 100644 ie/RTCStatsReport.cc create mode 100644 ie/RTCStatsReport.h create mode 100644 ie/RTCStatsReport.rgs create mode 100644 ie/SessionDescription.cc create mode 100644 ie/SessionDescription.h create mode 100644 ie/SessionDescription.rgs create mode 100644 ie/SourceInfo.cc create mode 100644 ie/SourceInfo.h create mode 100644 ie/SourceInfo.rgs create mode 100644 ie/Utils.cc create mode 100644 ie/Utils.h create mode 100644 ie/WebRTC.bmp create mode 100644 ie/WebRTC.cc create mode 100644 ie/WebRTC.h create mode 100644 ie/WebRTC.rgs create mode 100644 ie/_IWebRTCEvents_CP.h create mode 100644 ie/dlldata.c create mode 100644 ie/dllmain.cc create mode 100644 ie/dllmain.h create mode 100644 ie/resource.h create mode 100644 ie/stdafx.cc create mode 100644 ie/stdafx.h create mode 100644 ie/targetver.h create mode 100644 ie/webrtc-everywhere-ie.vcproj create mode 100644 ie/webrtc-everywhere-ie.vcxproj create mode 100644 ie/webrtc-everywhere-ie.vcxproj.filters create mode 100644 ie/webrtc-everywhere.aps create mode 100644 ie/webrtc-everywhere.cc create mode 100644 ie/webrtc-everywhere.def create mode 100644 ie/webrtc-everywhere.rc create mode 100644 ie/webrtc-everywhere.rgs create mode 100644 ie/webrtc-everywherePS.vcproj create mode 100644 ie/webrtc-everywherePS.vcxproj create mode 100644 ie/webrtc-everywherePS.vcxproj.filters create mode 100644 ie/webrtc-everywhereps.def create mode 100644 ie/webrtceverywhere.idl create mode 100644 ie/webrtceverywhere_i.c create mode 100644 ie/webrtceverywhere_i.h create mode 100644 ie/webrtceverywhere_p.c create mode 100755 npapi/BrowserCallback.cc create mode 100755 npapi/BrowserCallback.h create mode 100755 npapi/MediaSourceStates.cc create mode 100755 npapi/MediaSourceStates.h create mode 100755 npapi/MediaStream.cc create mode 100755 npapi/MediaStream.h create mode 100755 npapi/MediaStreamEvent.cc create mode 100755 npapi/MediaStreamEvent.h create mode 100755 npapi/MediaStreamTrack.cc create mode 100755 npapi/MediaStreamTrack.h create mode 100755 npapi/NPCommon.h create mode 100755 npapi/PeerConnection.cc create mode 100755 npapi/PeerConnection.h create mode 100755 npapi/Plugin.cc create mode 100755 npapi/Plugin.h create mode 100755 npapi/RTCIceCandidate.cc create mode 100755 npapi/RTCIceCandidate.h create mode 100755 npapi/RTCPeerConnectionIceEvent.cc create mode 100755 npapi/RTCPeerConnectionIceEvent.h create mode 100755 npapi/RTCStats.cc create mode 100755 npapi/RTCStats.h create mode 100755 npapi/RTCStatsReport.cc create mode 100755 npapi/RTCStatsReport.h create mode 100644 npapi/Release/webrtc-everywhere-npapi.res create mode 100755 npapi/SessionDescription.cc create mode 100755 npapi/SessionDescription.h create mode 100755 npapi/SourceInfo.cc create mode 100755 npapi/SourceInfo.h create mode 100755 npapi/Utils.cc create mode 100755 npapi/Utils.h create mode 100755 npapi/WebRTC.cc create mode 100755 npapi/WebRTC.h create mode 100755 npapi/dllmain.cc create mode 100755 npapi/npapi-includes.h create mode 100755 npapi/resource.h create mode 100755 npapi/webrtc-everywhere-npapi.aps create mode 100755 npapi/webrtc-everywhere-npapi.def create mode 100755 npapi/webrtc-everywhere-npapi.rc create mode 100755 npapi/webrtc-everywhere-npapi.vcproj create mode 100755 npapi/webrtc-everywhere-npapi.vcxproj create mode 100755 npapi/webrtc-everywhere-npapi.vcxproj.filters create mode 100644 thirdparties/common/include/npapi-sdk/headers/npapi.h create mode 100644 thirdparties/common/include/npapi-sdk/headers/npfunctions.h create mode 100644 thirdparties/common/include/npapi-sdk/headers/npruntime.h create mode 100644 thirdparties/common/include/npapi-sdk/headers/nptypes.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/audiotrack.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/audiotrackrenderer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/datachannel.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/datachannelinterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/dtmfsender.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/dtmfsenderinterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/fakeportallocatorfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsep.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsepicecandidate.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsepsessiondescription.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/localaudiosource.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediaconstraintsinterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastream.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamhandler.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreaminterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamprovider.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamproxy.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamsignaling.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamtrack.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamtrackproxy.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/notifier.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnection.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectionfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectioninterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectionproxy.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/portallocatorfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/proxy.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/remoteaudiosource.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/remotevideocapturer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/sctputils.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/statscollector.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/statstypes.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/streamcollection.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/umametrics.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosource.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosourceinterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosourceproxy.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videotrack.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videotrackrenderers.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsdp.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsession.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsessiondescriptionfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/asyncfile.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/asynchttprequest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/asyncinvoker-inl.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/asyncinvoker.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/asyncpacketsocket.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/asyncresolverinterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/asyncsocket.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/asynctcpsocket.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/asyncudpsocket.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/atomicops.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/autodetectproxy.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/bandwidthsmoother.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/base64.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/basicdefs.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/basictypes.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/bind.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/buffer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/bytebuffer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/byteorder.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/callback.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/checks.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/common.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/compile_assert.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/constructormagic.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/cpumonitor.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/crc32.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/criticalsection.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/cryptstring.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/dbus.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/diskcache.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/diskcache_win32.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/dscp.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/event.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/fakecpumonitor.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/fakenetwork.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/fakesslidentity.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/faketaskrunner.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/filelock.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/fileutils.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/fileutils_mock.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/firewallsocketserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/flags.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/genericslot.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/gunit.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/gunit_prod.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/helpers.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/httpbase.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/httpclient.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/httpcommon-inl.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/httpcommon.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/httprequest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/httpserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/ifaddrs-android.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/ipaddress.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/json.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/latebindingsymboltable.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/libdbusglibsymboltable.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/linked_ptr.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/linux.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/linuxfdwalk.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/linuxwindowpicker.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/logging.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/macasyncsocket.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/maccocoasocketserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/maccocoathreadhelper.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/macconversion.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/macsocketserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/macutils.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/macwindowpicker.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/mathutils.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/md5.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/md5digest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/messagedigest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/messagehandler.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/messagequeue.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/move.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/multipart.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/natserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/natsocketfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/nattypes.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/nethelpers.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/network.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/nssidentity.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/nssstreamadapter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/nullsocketserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/openssl.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/openssladapter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/openssldigest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/opensslidentity.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/opensslstreamadapter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/optionsfile.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/pathutils.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/physicalsocketserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/posix.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/profiler.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/proxydetect.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/proxyinfo.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/proxyserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/ratelimiter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/ratetracker.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/refcount.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/referencecountedsingletonfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/rollingaccumulator.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/safe_conversions.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/safe_conversions_impl.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/schanneladapter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/scoped_autorelease_pool.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/scoped_ptr.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/scoped_ref_ptr.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/scopedptrcollection.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sec_buffer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sha1.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sha1digest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sharedexclusivelock.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/signalthread.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sigslot.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sigslotrepeater.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/socket.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/socket_unittest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/socketadapters.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/socketaddress.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/socketaddresspair.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/socketfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/socketpool.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/socketserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/socketstream.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/ssladapter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sslconfig.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sslfingerprint.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sslidentity.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sslroots.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sslsocketfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sslstreamadapter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/sslstreamadapterhelper.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/stream.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/stringdigest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/stringencode.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/stringutils.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/systeminfo.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/task.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/taskparent.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/taskrunner.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/template_util.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/testbase64.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/testclient.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/testechoserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/testutils.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/thread.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/timeutils.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/timing.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/transformadapter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/unixfilesystem.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/urlencode.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/versionparsing.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/virtualsocketserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/win32.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/win32filesystem.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/win32regkey.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/win32socketinit.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/win32socketserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/win32toolhelp.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/win32window.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/win32windowpicker.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/window.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/windowpicker.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/windowpickerfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/winfirewall.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/winping.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/base/worker.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/audioframe.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/audiorenderer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/capturemanager.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/capturerenderadapter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/codec.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/constants.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/cpuid.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/cryptoparams.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/fakecapturemanager.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/fakemediaengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/fakemediaprocessor.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/fakenetworkinterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/fakertp.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/fakevideocapturer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/fakevideorenderer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/filemediaengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/hybriddataengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/hybridvideoengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/mediachannel.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/mediacommon.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/mediaengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/mutedvideocapturer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/nullvideoframe.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/nullvideorenderer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/rtpdataengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/rtpdump.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/rtputils.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/screencastid.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/streamparams.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/testutils.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/videoadapter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/videocapturer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/videocommon.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/videoengine_unittest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/videoframe.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/videoframe_unittest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/videoprocessor.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/videorenderer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/voiceprocessor.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/base/yuvframegenerator.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/carbonvideorenderer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/deviceinfo.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/devicemanager.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/dummydevicemanager.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/fakedevicemanager.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/filevideocapturer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/gdivideorenderer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/gtkvideorenderer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/libudevsymboltable.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/linuxdevicemanager.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/macdevicemanager.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/v4llookup.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/videorendererfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/win32devicemanager.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/devices/yuvframescapturer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/other/linphonemediaengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/sctp/sctpdataengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtccommon.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcdeviceinfo.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvcmfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvideocapturemodule.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvideoengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvoiceengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtccommon.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcexport.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcmediaengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcpassthroughrender.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtctexturevideoframe.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideocapturer.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideochannelfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideodecoderfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoencoderfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoengine2.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoframe.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvie.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvoe.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvoiceengine.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/asyncstuntcpsocket.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/basicpacketsocketfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/candidate.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/common.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/constants.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/dtlstransport.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/dtlstransportchannel.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/fakesession.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/p2ptransport.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/p2ptransportchannel.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/packetsocketfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/parsing.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/port.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/portallocator.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/portallocatorsessionproxy.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/portinterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/portproxy.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/pseudotcp.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/rawtransport.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/rawtransportchannel.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/relayport.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/relayserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/session.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionclient.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessiondescription.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionid.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionmanager.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionmessages.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/stun.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunport.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunrequest.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/tcpport.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/testrelayserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/teststunserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/testturnserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/transport.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannel.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannelimpl.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannelproxy.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportdescription.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportdescriptionfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportinfo.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/turnport.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/turnserver.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/base/udpport.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/client/autoportallocator.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/client/basicportallocator.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/client/connectivitychecker.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/client/fakeportallocator.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/client/httpportallocator.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/client/sessionmanagertask.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/client/sessionsendtask.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/p2p/client/socketmonitor.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/audiomonitor.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/bundlefilter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/call.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/channel.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/channelmanager.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/currentspeakermonitor.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/externalhmac.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/mediamessages.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/mediamonitor.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/mediarecorder.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/mediasession.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/mediasessionclient.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/mediasink.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/rtcpmuxfilter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/soundclip.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/srtpfilter.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/typingmonitor.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/media/voicechannel.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/tunnel/pseudotcpchannel.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/tunnel/securetunnelsessionclient.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/session/tunnel/tunnelsessionclient.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/alsasoundsystem.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/alsasymboltable.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/automaticallychosensoundsystem.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/linuxsoundsystem.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/nullsoundsystem.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/nullsoundsystemfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/platformsoundsystem.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/platformsoundsystemfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/pulseaudiosoundsystem.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/pulseaudiosymboltable.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/sounddevicelocator.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/soundinputstreaminterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/soundoutputstreaminterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/soundsystemfactory.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/soundsysteminterface.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/sound/soundsystemproxy.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/xmllite/qname.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlbuilder.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlconstants.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlelement.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlnsstack.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlparser.h create mode 100644 thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlprinter.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/assertions.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/autolink.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/config.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/features.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/forwards.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/json.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/reader.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/value.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/writer.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/basic_types.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/compare.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_argb.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_from.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_from_argb.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/cpu_id.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/format_conversion.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/mjpeg_decoder.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/planar_functions.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/rotate.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/rotate_argb.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/row.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale_argb.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale_row.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/version.h create mode 100644 thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/video_common.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/base/constructormagic.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/common_types.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/i420_video_frame.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/native_handle.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/texture_video_frame.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/video_image.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/common_video/libyuv/include/scaler.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/common_video/libyuv/include/webrtc_libyuv.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/common_video/plane.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/modules/interface/module.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/modules/interface/module_common_types.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture_defines.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture_factory.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/aligned_malloc.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/asm_defines.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/atomic32.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/clock.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/compile_assert.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/compile_assert_c.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/condition_variable_wrapper.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/cpu_features_wrapper.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/cpu_info.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/critical_section_wrapper.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log_c.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log_impl.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/event_tracer.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/event_wrapper.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/field_trial.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/file_wrapper.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/logcat_trace_context.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/logging.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/ref_count.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/rtp_to_ntp.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/rw_lock_wrapper.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_ptr.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_refptr.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_vector.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/sleep.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/sort.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/static_instance.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/stl_util.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/stringize_macros.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/template_util.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/thread_annotations.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/thread_wrapper.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/tick_util.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/timestamp_extrapolator.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/trace.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/trace_event.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/utf_util_win.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_event_win.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_native_win.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_posix.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/critical_section_posix.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/critical_section_win.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/data_log_c_helpers_unittest.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/event_posix.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/event_win.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/file_impl.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/move.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_generic.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_posix.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_win.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/set_thread_name_win.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/thread_posix.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/thread_win.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_impl.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_posix.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_win.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/unittest_utilities.h create mode 100644 thirdparties/common/include/webrtc-sdk/webrtc/typedefs.h create mode 100644 thirdparties/win32/bin/AStyle.exe create mode 100644 thirdparties/win32/include/inttypes.h create mode 100644 thirdparties/win32/include/stdint.h create mode 100644 webrtc-everywhere.sln create mode 100644 wininstall/innosetup.iss create mode 100644 wininstall/webrtc-everywhere-i386-10.4.dmg create mode 100755 xcode/webrtc-everywhere.xcodeproj/project.pbxproj create mode 100755 xcode/webrtc-everywhere.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100755 xcode/webrtc-everywhere.xcodeproj/project.xcworkspace/xcshareddata/webrtc-everywhere.xccheckout create mode 100755 xcode/webrtc-everywhere.xcodeproj/project.xcworkspace/xcuserdata/diopmamadou.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 xcode/webrtc-everywhere.xcodeproj/project.xcworkspace/xcuserdata/diopmamadou.xcuserdatad/WorkspaceSettings.xcsettings create mode 100755 xcode/webrtc-everywhere.xcodeproj/xcuserdata/diopmamadou.xcuserdatad/xcschemes/webrtc-everywhere.xcscheme create mode 100755 xcode/webrtc-everywhere.xcodeproj/xcuserdata/diopmamadou.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 xcode/webrtc-everywhere/en.lproj/InfoPlist.strings create mode 100755 xcode/webrtc-everywhere/webrtc-everywhere-Info.plist create mode 100755 xcode/webrtc-everywhere/webrtc-everywhere-Prefix.pch create mode 100755 xcode/webrtc-everywhere/webrtc_everywhere.cp create mode 100755 xcode/webrtc-everywhere/webrtc_everywhere.h create mode 100755 xcode/webrtc-everywhere/webrtc_everywherePriv.h create mode 100755 xcode/webrtc-everywhere/webrtc_everywhereProj.xcconfig create mode 100755 xcode/webrtc-everywhere/webrtc_everywhereTarget.xcconfig diff --git a/AStyle.sh b/AStyle.sh new file mode 100644 index 0000000..5cea901 --- /dev/null +++ b/AStyle.sh @@ -0,0 +1 @@ +thirdparties/win32/bin/AStyle.exe --style=k/r --lineend=linux --mode=c --add-brackets --break-closing-brackets --recursive "*.c" "*.cc" "*.h" \ No newline at end of file diff --git a/LICENSE-BSD b/LICENSE-BSD new file mode 100644 index 0000000..e19ac7d --- /dev/null +++ b/LICENSE-BSD @@ -0,0 +1,27 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of Google nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +HOLDER OR CONTRIBUTORS 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. diff --git a/LICENSE-GPL3 b/LICENSE-GPL3 new file mode 100644 index 0000000..3d90694 --- /dev/null +++ b/LICENSE-GPL3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d02db0b --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +**webrtc-everywhere** is an open source project (with **business-friendly** license) to add support for WebRTC features to Safari (Windows and MAC OSX) and Internet Explorer (Windows). + +# Downloads +Version **1.0.1**: + - MAC OSX + - Windows + +# Online samples +The following samples use our adapter.js and could be tested on Safari and Internet Explorer (off course they also work on Firefox and Chrome): + - getUserMedia() + - Choose camera resolution + - Choose camera and microphone + - Audio-only getUserMedia() output to local audio element + - Peer connection + - Audio-only peer connection + - Multiple peer connections + - Multiple relay + - Munge SDP + - Accept incoming peer connection + - Peer connection states + - Constraints and stats + - Display createOffer output + - ICE candidate gathering + +next #2 samples work but are toooo sloooow (to be fixed): + - getUserMedia() + Canvas + - getUserMedia() + Canvas + CSS filters + +# Using our plugin in your own project + - Download and install the plugin for MAC OSX or Windows + - Include adapter.js in your code. + - Change the code you're using to attach a stream to a <audio/> or <video /> HTML5 element:
+ from: + ``` + document.getElementById("eltId").src = mediaStream; + ``` +
to: + ``` + attachMediaStream(document.getElementById("eltId"), mediaStream); + ``` + +# Building source code +To build the source code you'll need Visual Studio 2013 (Windows) or Xcode (MAC OSX). +... to be continued + +# Release notes + - **1.0.1** + - Initial release **without** support for DataChannel + +# License + - Binaries and installers: All binaries and installers **from us** are released under **BSD** terms to allow using the project in your commercial products. + - The source code: **GPLv3** + + # Getting help + The best way to get help is via our dev-group. \ No newline at end of file diff --git a/WebRTC.htm b/WebRTC.htm new file mode 100755 index 0000000..e42a601 --- /dev/null +++ b/WebRTC.htm @@ -0,0 +1,315 @@ + + +ATL 8.0 test page for object WebRTC + + + + + + + + + + + +
+
+
+ + + + + + + + diff --git a/common/_AsyncEvent.cc b/common/_AsyncEvent.cc new file mode 100755 index 0000000..b4b9c60 --- /dev/null +++ b/common/_AsyncEvent.cc @@ -0,0 +1,198 @@ +/* Copyright(C) 2014 Sarandogou */ + +#include "_AsyncEvent.h" +#include "_Utils.h" +#include "_Debug.h" + +// +// _AsyncEventDispatcher +// + +_AsyncEventDispatcher::_AsyncEventDispatcher() + : m_Hwnd(NULL) +#if WE_UNDER_WINDOWS + , m_Proc(NULL) +#endif +{ + +} + +_AsyncEventDispatcher::~_AsyncEventDispatcher() +{ + SetWindow(NULL, false); +} + +bool _AsyncEventDispatcher::SetWindow(HWND hWnd, bool bSubClass /*= true*/) +{ +#if WE_UNDER_WINDOWS + if (m_Hwnd && m_Proc) { + SetWindowLongPtr(m_Hwnd, GWL_WNDPROC, (LONG)m_Proc); + // SetWindowLongPtr(m_Hwnd, DWLP_USER, (LONG)NULL); + m_Proc = NULL; + } + + if ((m_Hwnd = hWnd)) { + if (bSubClass) { + m_Proc = (WNDPROC)SetWindowLongPtr(m_Hwnd, GWL_WNDPROC, (LONG)_Utils::WndProc); + if (!m_Proc) { + WE_DEBUG_ERROR("SetWindowLongPtr() failed with errcode=%d", GetLastError()); + return false; + } + // SetWindowLongPtr(m_Hwnd, GWLP_USERDATA, reinterpret_cast(this)); + } + } +#endif + + return true; +} + +LONGLONG _AsyncEventDispatcher::GetWindowHandle() +{ + return reinterpret_cast(m_Hwnd); +} + +bool _AsyncEventDispatcher::RaiseCallback(_BrowserCallback* cb) +{ + return _Utils::RaiseCallback(GetWindowHandle(), cb); +} + +// +// _AsyncEventRaiser +// + +_AsyncEventRaiser::_AsyncEventRaiser() + : m_pDispatcher(NULL) +{ + +} + +_AsyncEventRaiser::~_AsyncEventRaiser() +{ + SetDispatcher(NULL); +} + +void _AsyncEventRaiser::SetDispatcher(_AsyncEventDispatcher* dispatcher) +{ + if (m_pDispatcher) { + m_pDispatcher->ReleaseObject(); + m_pDispatcher = NULL; + } + if (dispatcher) { + m_pDispatcher = dynamic_cast<_AsyncEventDispatcher*>(dispatcher->RetainObject()); + } +} + +bool _AsyncEventRaiser::RaiseCallback(_BrowserCallback* cb) +{ + assert(m_pDispatcher != NULL); + return m_pDispatcher->RaiseCallback(cb); +} + +#if 0 +// +// _AsyncEventToken +// +_AsyncEventToken::_AsyncEventToken() +{ + static long __id = 1; + + m_id = _Utils::ToString(we_atomic_inc(&__id)); +} + +_AsyncEventToken::~_AsyncEventToken() +{ + +} + +bool _AsyncEventToken::AddCallback(std::string id, _BrowserCallback** cb)const +{ + return _AsyncEventHolder::Add(this, "callback_getUserMediaSuccess", cb); +} + + + +// +// _AsyncEventHolder +// + +webrtc::CriticalSectionWrapper* _AsyncEventHolder::s_critsect = webrtc::CriticalSectionWrapper::CreateCriticalSection(); +std::map _AsyncEventHolder::s_callbacks; + +bool _AsyncEventHolder::Add(const _AsyncEventToken* token, std::string _id, _BrowserCallback** cb) +{ + std::string id = BuildUniqueId(token, _id); + s_critsect->Enter(); + std::map::iterator it = s_callbacks.find(id); + if (it != s_callbacks.end()) { + if (it->second) { + delete it->second; + } + s_callbacks.erase(it); + } + s_callbacks[id] = *cb; + *cb = NULL; + s_critsect->Leave(); + return true; +} + +_BrowserCallback* _AsyncEventHolder::Get(const _AsyncEventToken* token, std::string _id) +{ + std::string id = BuildUniqueId(token, _id); + _BrowserCallback* ret = NULL; + s_critsect->Enter(); + std::map::iterator it = s_callbacks.find(id); + if (it != s_callbacks.end()) { + ret = it->second; + } + s_critsect->Leave(); + return ret; +} + +_BrowserCallback* _AsyncEventHolder::Pop(const _AsyncEventToken* token, std::string _id) +{ + std::string id = BuildUniqueId(token, _id); + _BrowserCallback* ret = NULL; + s_critsect->Enter(); + std::map::iterator it = s_callbacks.find(id); + if (it != s_callbacks.end()) { + ret = it->second; + s_callbacks.erase(it); + } + s_critsect->Leave(); + return ret; +} + +bool _AsyncEventHolder::Remove(const _AsyncEventToken* token, std::string _id) +{ + std::string id = BuildUniqueId(token, _id); + s_critsect->Enter(); + std::map::iterator it = s_callbacks.find(id); + if (it != s_callbacks.end()) { + if (it->second) { + delete it->second; + } + s_callbacks.erase(it); + } + s_critsect->Leave(); + return true; +} + +bool _AsyncEventHolder::Clear() +{ + s_critsect->Enter(); + std::map::iterator it = s_callbacks.begin(); + for (; it != s_callbacks.end(); ++it) { + if (it->second) { + delete it->second; + } + } + s_callbacks.clear(); + s_critsect->Leave(); + return true; +} + +std::string _AsyncEventHolder::BuildUniqueId(const _AsyncEventToken* token, std::string id) +{ + return token->id() + std::string("_") + id; +} +#endif \ No newline at end of file diff --git a/common/_AsyncEvent.h b/common/_AsyncEvent.h new file mode 100755 index 0000000..9ab792e --- /dev/null +++ b/common/_AsyncEvent.h @@ -0,0 +1,111 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_COMMON_ASYNCEVENTDISPATCHER_H_ +#define _WEBRTC_EVERYWHERE_COMMON_ASYNCEVENTDISPATCHER_H_ + +#include "_Config.h" +#include "_Common.h" + +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" + +#include + +#if WE_UNDER_WINDOWS +# include +#endif + +#if !defined(WM_USER) +#define WM_USER 0x0400 +#endif +#define WM_SUCCESS (WM_USER + 101) +#define WM_ERROR (WM_SUCCESS + 1) +#define WM_GETUSERMEDIA_SUCESS (WM_ERROR + 1) +#define WM_GETUSERMEDIA_ERROR (WM_GETUSERMEDIA_SUCESS + 1) +#define WM_CREATEOFFER_SUCCESS (WM_GETUSERMEDIA_ERROR + 1) +#define WM_CREATEOFFER_ERROR (WM_CREATEOFFER_SUCCESS + 1) +#define WM_ONNEGOTIATIONNEEDED (WM_CREATEOFFER_ERROR + 1) +#define WM_ONICECANDIDATE (WM_ONNEGOTIATIONNEEDED + 1) +#define WM_ONSIGNALINGSTATECHANGE (WM_ONICECANDIDATE + 1) +#define WM_ONADDSTREAM (WM_ONSIGNALINGSTATECHANGE + 1) +#define WM_ONREMOVESTREAM (WM_ONADDSTREAM + 1) +#define WM_ONICECONNECTIONSTATECHANGE (WM_ONREMOVESTREAM + 1) + +class WEBRTC_EVERYWHERE_API _AsyncEventDispatcher : public _BrowserObject +{ +protected: + _AsyncEventDispatcher(); +public: + virtual ~_AsyncEventDispatcher(); + bool SetWindow(HWND hWnd, bool bSubClass = true); + LONGLONG GetWindowHandle(); + bool RaiseCallback(_BrowserCallback* cb); + +private: + HWND m_Hwnd; +#if WE_UNDER_WINDOWS + WNDPROC m_Proc; +#endif +}; + +class WEBRTC_EVERYWHERE_API _AsyncEventRaiser +{ +protected: + _AsyncEventRaiser(); +public: + virtual ~_AsyncEventRaiser(); + void SetDispatcher(_AsyncEventDispatcher* dispatcher); + bool RaiseCallback(_BrowserCallback* cb); + WE_INLINE const _AsyncEventDispatcher* GetDispatcher() { return m_pDispatcher; } + +private: + _AsyncEventDispatcher* m_pDispatcher; +}; + +#if 0 + +class WEBRTC_EVERYWHERE_API _AsyncEventToken +{ +protected: + _AsyncEventToken(); +public: + virtual ~_AsyncEventToken(); + bool AddCallback(std::string id, _BrowserCallback** cb)const; + WE_INLINE std::string id()const { return m_id; } + +private: +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + std::string m_id; +#if _MSC_VER +#pragma warning(pop) +#endif +}; + +class WEBRTC_EVERYWHERE_API _AsyncEventHolder +{ +public: + virtual ~_AsyncEventHolder() {} + static bool Add(const _AsyncEventToken* token, std::string id, _BrowserCallback** cb); + static _BrowserCallback* Get(const _AsyncEventToken* token, std::string id); + static _BrowserCallback* Pop(const _AsyncEventToken* token, std::string id); + static bool Remove(const _AsyncEventToken* token, std::string id); + static bool Clear(); + +private: + static std::string BuildUniqueId(const _AsyncEventToken* token, std::string id); + +private: +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + static std::map s_callbacks; + static webrtc::CriticalSectionWrapper *s_critsect; +#if _MSC_VER +#pragma warning(pop) +#endif +}; +#endif + +#endif /* _WEBRTC_EVERYWHERE_COMMON_ASYNCEVENTDISPATCHER_H_ */ diff --git a/common/_Buffer.cc b/common/_Buffer.cc new file mode 100755 index 0000000..7b1980b --- /dev/null +++ b/common/_Buffer.cc @@ -0,0 +1,39 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "_Buffer.h" +#include "_Debug.h" + +_Buffer::_Buffer() + : m_pPtr(NULL) + , m_nSize(0) +{ +} + +_Buffer::~_Buffer() +{ + SafeFree(&m_pPtr); +} + +WeError _Buffer::New(const void* ptr, size_t size, _Buffer** ppObj) +{ + if (!ppObj || !size) { + WE_DEBUG_ERROR("Invalid argument"); + return WeError_InvalidArgument; + } + (*ppObj) = new _Buffer(); + if (!(*ppObj)) { + WE_DEBUG_ERROR("Failed to create new buffer"); + return WeError_OutOfMemory; + } + (*ppObj)->m_pPtr = malloc(size + 1); + if (!(*ppObj)) { + WE_DEBUG_ERROR("Failed to allocate buffer with size=%lu", size); + SafeFree(ppObj); + return WeError_OutOfMemory; + } + ((char*)(*ppObj)->m_pPtr)[size] = '\0'; + if (ptr) { + memcpy((*ppObj)->m_pPtr, ptr, size); + } + (*ppObj)->m_nSize = size; + return WeError_Success; +} diff --git a/common/_Buffer.h b/common/_Buffer.h new file mode 100755 index 0000000..9dcd15d --- /dev/null +++ b/common/_Buffer.h @@ -0,0 +1,26 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_COMMON_BUFFER_H_ +#define _WEBRTC_EVERYWHERE_COMMON_BUFFER_H_ + +#include "_Config.h" + +class WEBRTC_EVERYWHERE_API _Buffer +{ +public: + virtual ~_Buffer(); + WE_INLINE const void* getPtr()const { + return m_pPtr; + } + WE_INLINE size_t getSize()const { + return m_nSize; + } + + static WeError New(const void* ptr, size_t size, _Buffer** ppObj); + +private: + _Buffer(); + void* m_pPtr; + size_t m_nSize; +}; + +#endif /* _WEBRTC_EVERYWHERE_COMMON_BUFFER_H_ */ diff --git a/common/_Common.cc b/common/_Common.cc new file mode 100755 index 0000000..61f7b2d --- /dev/null +++ b/common/_Common.cc @@ -0,0 +1,106 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "_Common.h" +#include "_Utils.h" +#include "_MediaStream.h" + +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" + +#if !defined(PEERCONN_MODE) +#define PEERCONN_MODE 1 +#endif + +#if PEERCONN_MODE == 1 +static talk_base::scoped_refptr _fake_peer_connection = NULL; // TODO: "getUserMedia" fails if no PeerconnectionFactory instance exists. Why? +static webrtc::CriticalSectionWrapper* _fake_peer_connection_cs = webrtc::CriticalSectionWrapper::CreateCriticalSection(); +#else +talk_base::scoped_refptr _fake_peer_connection(webrtc::CreatePeerConnectionFactory()); +#endif + +WEBRTC_EVERYWHERE_API talk_base::scoped_refptr GetPeerConnectionFactory() +{ +#if PEERCONN_MODE == 1 + _fake_peer_connection_cs->Enter(); + talk_base::scoped_refptr _peer = _fake_peer_connection; + _fake_peer_connection_cs->Leave(); + return _peer; +#else + return _fake_peer_connection; +#endif +} + +WEBRTC_EVERYWHERE_API void TakeFakePeerConnectionFactory() +{ +#if PEERCONN_MODE == 1 + _fake_peer_connection_cs->Enter(); + if (!_fake_peer_connection) { + _fake_peer_connection = webrtc::CreatePeerConnectionFactory(); + } + else { + _fake_peer_connection->AddRef(); + } + _fake_peer_connection_cs->Leave(); +#endif +} + +WEBRTC_EVERYWHERE_API void ReleaseFakePeerConnectionFactory() +{ +#if PEERCONN_MODE == 1 + _fake_peer_connection_cs->Enter(); + if (_fake_peer_connection) { + // hack because no function to retrieve the refCount value; + webrtc::PeerConnectionFactoryInterface* tmp = _fake_peer_connection.get(); + tmp->AddRef(); + if (tmp->Release() == 1) { + _fake_peer_connection = NULL; + } + else { + _fake_peer_connection->Release(); + } + } + _fake_peer_connection_cs->Leave(); +#endif +} + +talk_base::scoped_refptr<_RTCMediaConstraints> BuildConstraints(const _MediaConstraintsObj* _constraints /*= NULL*/) +{ + talk_base::scoped_refptr<_RTCMediaConstraints> contraints = new talk_base::RefCountedObject<_RTCMediaConstraints>(); + + _MediaConstraints::const_iterator it; + + if (_constraints) { + if (_constraints->optional) { + for (it = _constraints->optional->begin(); it != _constraints->optional->end(); ++it) { + contraints->AddOptional(it->first, it->second); + } + } + if (_constraints->mandatory) { + for (it = _constraints->mandatory->begin(); it != _constraints->mandatory->end(); ++it) { + contraints->AddMandatory(it->first, it->second); + } + } + } + + return contraints; +} + +webrtc::MediaStreamInterface* BuildMediaStream(const _MediaStream* stream) +{ + if (!stream) { + return NULL; + } + return dynamic_cast((webrtc::MediaStreamInterface*)stream->GetWrappedStream()); +} + +_UniqueObject::_UniqueObject() +: m_id(_Utils::UniqueId()) +{ + _Utils::UniqueObjAdd(this); +} + +_UniqueObject::~_UniqueObject() +{ + _Utils::UniqueObjRemove(this->UniqueId()); +} + + + diff --git a/common/_Common.h b/common/_Common.h new file mode 100755 index 0000000..b280de9 --- /dev/null +++ b/common/_Common.h @@ -0,0 +1,457 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_COMMON_COMMON_H_ +#define _WEBRTC_EVERYWHERE_COMMON_COMMON_H_ + +#include "_Config.h" +#include "_RTCMediaConstraints.h" + +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/app/webrtc/mediaconstraintsinterface.h" +#include "talk/app/webrtc/mediastreaminterface.h" + +#include +#include + +class _SessionDescription; +class _MediaStream; +class _RTCIceCandidate; + +typedef void* VideoTrackInterfacePtr; +typedef void* MediaStreamInterfacePtr; +typedef void* MediaStreamTrackInterfacePtr; +typedef void* VideoRendererPtr; + +static const char kAudioLabel[] = "audio_label"; +static const char kVideoLabel[] = "video_label"; +static const char kStreamLabel[] = "stream_label"; + +// http://www.w3.org/TR/webrtc/#idl-def-RTCSignalingState +static const char kSignalingStateStable[] = "stable"; +static const char kSignalingStateHaveLocalOffer[] = "have-local-offer"; +static const char kSignalingStateHaveRemoteOffer[] = "have-remote-offer"; +static const char kSignalingStateHaveLocalPrAnswer[] = "have-local-pranswer"; +static const char kSignalingStateHaveRemotePrAnswer[] = "have-remote-pranswer"; +static const char kSignalingStateClosed[] = "closed"; + +// http://www.w3.org/TR/webrtc/#idl-def-RTCIceGatheringState +static const char kIceGatheringStateNew[] = "new"; +static const char kIceGatheringStateGathering[] = "gathering"; +static const char kIceGatheringStateComplete[] = "complete"; + +// http://www.w3.org/TR/webrtc/#idl-def-RTCIceConnectionState +static const char kIceConnectionStateNew[] = "new"; +static const char kIceConnectionStatChecking[] = "checking"; +static const char kIceConnectionStatConnected[] = "connected"; +static const char kIceConnectionStatCompleted[] = "completed"; +static const char kIceConnectionStatFailed[] = "failed"; +static const char kIceConnectionStatDisconnected[] = "disconnected"; +static const char kIceConnectionStatClosed[] = "closed"; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-MediaStreamTrackState +static const char kMediaStreamTrackStateNew[] = "new"; +static const char kMediaStreamTrackStateLive[] = "live"; +static const char kMediaStreamTrackStateEnded[] = "ended"; +static const char kMediaStreamTrackStateFailed[] = "failed"; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-SourceTypeEnum +static const char kSourceTypeEnumNone[] = "none"; +static const char kSourceTypeEnumCamera[] = "camera"; +static const char kSourceTypeEnumMicrophone[] = "microphone"; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-VideoFacingModeEnum +static const char kVideoFacingModeEnumUser[] = "user"; +static const char kVideoFacingModeEnumEnvironment[] = "environment"; +static const char kVideoFacingModeEnumLeft[] = "left"; +static const char kVideoFacingModeEnumRight[] = "right"; + +// http://www.w3.org/TR/webrtc/#rtcstats-dictionary +static const char kRTCStatsTypeInboundRtp[] = "inbound-rtp"; +static const char kRTCStatsTypeOutboundRtp[] = "outbound-rtp"; + +#define kMaxParamArgs 10 + +typedef struct __BrowserObject { + virtual struct __BrowserObject* RetainObject() = 0; + virtual struct __BrowserObject* ReleaseObject() = 0; +} _BrowserObject; + +typedef struct __BrowserCallback : _BrowserObject { + unsigned msgid; + __BrowserCallback(unsigned _msgid) { + msgid = _msgid; + } + virtual unsigned GetMsgId() { return msgid; } + virtual bool Invoke() = 0; +} _BrowserCallback; + +typedef struct __RTCIceServer { + std::string uri; + std::string username; + std::string password; + __RTCIceServer(std::string _uri, std::string _username = std::string(""), std::string _password = std::string("")) { + uri = _uri, username = _username, password = _password; + } +} _RTCIceServer; + +typedef struct __RTCConfiguration { + std::vector<_RTCIceServer>iceServers; + __RTCConfiguration() { + } + ~__RTCConfiguration() { + iceServers.clear(); + } +} +_RTCConfiguration; + +// http://www.w3.org/TR/webrtc/#idl-def-RTCPeerConnectionIceEvent +typedef struct __RTCPeerConnectionIceEvent { + cpp11::shared_ptr<_RTCIceCandidate> candidate; + __RTCPeerConnectionIceEvent(cpp11::shared_ptr<_RTCIceCandidate> _candidate = nullPtr) { + candidate = _candidate; + } + ~__RTCPeerConnectionIceEvent() { + candidate = nullPtr; + } +} _RTCPeerConnectionIceEvent; + +// http://www.w3.org/TR/webrtc/#idl-def-MediaStreamEvent +typedef struct __MediaStreamEvent { + cpp11::shared_ptr<_MediaStream> stream; + __MediaStreamEvent(cpp11::shared_ptr<_MediaStream> _stream = nullPtr) { + stream = _stream; + } + ~__MediaStreamEvent() { + stream = nullPtr; + } +} +_MediaStreamEvent; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-NavigatorUserMediaError +typedef struct __NavigatorUserMediaError { + std::string constraintName; + __NavigatorUserMediaError(std::string _constraintName) { + constraintName = _constraintName; + } +} _NavigatorUserMediaError; + +// http://tools.ietf.org/html/draft-burnett-rtcweb-constraints-registry-05 +typedef std::pair< std::string, std::string> _MediaConstraint; +typedef std::map _MediaConstraints; +typedef struct __MediaConstraintsObj { + cpp11::shared_ptr<_MediaConstraints> optional; + cpp11::shared_ptr<_MediaConstraints> mandatory; + __MediaConstraintsObj(cpp11::shared_ptr<_MediaConstraints> _optional = nullPtr, cpp11::shared_ptr<_MediaConstraints> _mandatory = nullPtr) { + optional = _optional; + mandatory = _mandatory; + } +} +_MediaConstraintsObj; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-SourceInfo +typedef struct __SourceInfo { + std::string sourceId; + std::string kind; + std::string label; + std::string facing; // VideoFacingModeEnum + + __SourceInfo(std::string _sourceId = "", std::string _kind = "", std::string _label = "") { + sourceId = _sourceId; + kind = _kind; + label = _label; + } +} +_SourceInfo; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-MediaSourceStates +typedef struct __MediaSourceStates{ + std::string sourceType; // SourceTypeEnum sourceType; + std::string sourceId; + unsigned long width; + unsigned long height; + float frameRate; + float aspectRatio; + std::string facingMode; // VideoFacingModeEnum ? facingMode; + unsigned long volume; +} +_MediaSourceStates; + +// http://www.w3.org/TR/webrtc/#rtcstats-dictionary +typedef struct __RTCStats { + double timestamp; // DOMHiResTimeStamp timestamp; + std::string type; // RTCStatsType type; + std::string id; // DOMString id; + std::map names; + std::string stat(std::string name) { + std::map::iterator it = names.find(name); + if (it != names.end()) { + return (*it).second; + } + return std::string(""); + } +} +_RTCStats; + +// http://www.w3.org/TR/webrtc/#dictionary-rtcrtpstreamstats-members +typedef struct __RTCRTPStreamStats : _RTCStats{ + std::string ssrc; // DOMString ssrc; + std::string remoteId; // DOMString remoteId; +} +_RTCRTPStreamStats; + +// http://www.w3.org/TR/webrtc/#dictionary-rtcinboundrtpstreamstats-members +typedef struct __RTCInboundRTPStreamStats : _RTCStats{ + unsigned long bytesReceived; + unsigned long packetsReceived; +} +_RTCInboundRTPStreamStats; + +// http://www.w3.org/TR/webrtc/#dictionary-rtcoutboundrtpstreamstats-members +typedef struct __RTCOutboundRTPStreamStats : _RTCStats{ + unsigned long bytesSent; + unsigned long packetsSent; +} +_RTCOutboundRTPStreamStats; + +// http://www.w3.org/TR/webrtc/#rtcstatsreport-object +typedef struct __RTCStatsReport { + std::map > values; // getter RTCStats(DOMString id); +} +_RTCStatsReport; + + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-CapabilityRange +typedef struct __CapabilityRange { + enum RangeType { + String, + Integer + }; + // any max; + // any min; + bool supported; + RangeType type; + __CapabilityRange(RangeType _type, bool _supported) { + type = _type; + supported = _supported; + } +} +_CapabilityRange; +typedef struct __CapabilityRangeInteger : public _CapabilityRange { + long max; + long min; + __CapabilityRangeInteger(bool _supported, long _max, long _min) : _CapabilityRange(_CapabilityRange::Integer, _supported) { + max = _max, min = _min; + } +} +_CapabilityRangeInteger; +typedef struct __CapabilityRangeString : public _CapabilityRange { + std::string max; + std::string min; + __CapabilityRangeString(bool _supported, std::string _max, std::string _min) : _CapabilityRange(_CapabilityRange::String, _supported) { + max = _max, min = _min; + } +} +_CapabilityRangeString; + +template +struct _Sequence { + std::vector > values; + _Sequence() { + + } + void Clear() { + values.clear(); + } + void Add(cpp11::shared_ptr v) { + values.push_back(v); + } + ~_Sequence() { + Clear(); + } +}; + +typedef struct __AllCapabilities { + enum CapType { + Audio, + Video + }; + CapType type; + __AllCapabilities(CapType _type) { + type = _type; + } +} +_AllCapabilities; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-CapabilityList +typedef _Sequence _CapabilityList; // typedef sequence CapabilityList; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-AllVideoCapabilities +typedef struct __AllVideoCapabilities : public _AllCapabilities { + cpp11::shared_ptr<_CapabilityList> sourceType; // CapabilityList ? sourceType; + cpp11::shared_ptr<_CapabilityList> sourceId; // CapabilityList ? sourceId; + cpp11::shared_ptr<_CapabilityRange> width; // CapabilityRange ? width; + cpp11::shared_ptr<_CapabilityRange> height; // CapabilityRange ? height; + cpp11::shared_ptr<_CapabilityRange> frameRate; // CapabilityRange ? frameRate; + cpp11::shared_ptr<_CapabilityRange> aspectRatio; // CapabilityRange ? aspectRatio; + cpp11::shared_ptr<_CapabilityList> facingMode; // CapabilityList ? facingMode; + __AllVideoCapabilities() : _AllCapabilities(_AllCapabilities::Video){ + } +} +_AllVideoCapabilities; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-AllAudioCapabilities +typedef struct __AllAudioCapabilities : public _AllCapabilities { + cpp11::shared_ptr<_CapabilityRange> volume; // CapabilityRange ? volume; + __AllAudioCapabilities() : _AllCapabilities(_AllCapabilities::Audio){ + } +} +_AllAudioCapabilities; + +template +class WEBRTC_EVERYWHERE_API _AutoLock { +public: + explicit _AutoLock(T* obj) : obj_(obj) { obj_->Enter(); } + virtual ~_AutoLock() { obj_->Leave(); } +protected: + T* obj_; +}; + +class WEBRTC_EVERYWHERE_API _UniqueObject { +public: + virtual ~_UniqueObject(); + WE_INLINE long UniqueId()const { return m_id; } + operator long() const { + return m_id; + } +protected: + explicit _UniqueObject(); +private: + long m_id; +}; + + +typedef cpp11::function _VoidFunctionCallback; + +// http://www.w3.org/TR/webrtc/#idl-def-RTCSessionDescriptionCallback +typedef cpp11::function sdp)> _RTCSessionDescriptionCallback; + +// http://www.w3.org/TR/webrtc/#idl-def-RTCPeerConnectionErrorCallback +typedef cpp11::function error)> _RTCPeerConnectionErrorCallback; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-NavigatorUserMediaSuccessCallback +typedef cpp11::function stream)> _NavigatorUserMediaSuccessCallback; + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-NavigatorUserMediaErrorCallback +typedef cpp11::function e)> _NavigatorUserMediaErrorCallback; + +// http://www.w3.org/TR/webrtc/#event-negotiation +typedef cpp11::function _onnegotiationneededCallback; +// http://www.w3.org/TR/webrtc/#event-icecandidate +typedef cpp11::function e)> _onicecandidateCallback; +// http://www.w3.org/TR/webrtc/#event-signalingstatechange +typedef cpp11::function _onsignalingstatechangeCallback; +// http://www.w3.org/TR/webrtc/#event-mediastream-addstream +typedef cpp11::function stream)> _onaddstreamCallback; +// http://www.w3.org/TR/webrtc/#event-mediastream-removestream +typedef cpp11::function stream)> _onremovestreamCallback; +// http://www.w3.org/TR/webrtc/#event-iceconnectionstatechange +typedef cpp11::function _oniceconnectionstatechangeCallback; +// http://www.w3.org/TR/webrtc/#idl-def-RTCStatsCallback +typedef cpp11::function report)> _RTCStatsCallback; + +typedef _MediaStream*(*_MediaStreamAllocateFn)(); + + +#if defined(__GNUC__) || (HAVE___SYNC_FETCH_AND_ADD && HAVE___SYNC_FETCH_AND_SUB) +# define we_atomic_inc(_ptr_) __sync_fetch_and_add((_ptr_), 1) +# define we_atomic_dec(_ptr_) __sync_fetch_and_sub((_ptr_), 1) +#elif defined(_MSC_VER) +# define we_atomic_inc(_ptr_) InterlockedIncrement((_ptr_)) +# define we_atomic_dec(_ptr_) InterlockedDecrement((_ptr_)) +#else +# define we_atomic_inc(_ptr_) ++(*(_ptr_)) +# define we_atomic_dec(_ptr_) --(*(_ptr_)) +#endif + +#define SafeDelete(pptr) if(pptr && *pptr) delete *pptr, *pptr = NULL; + +#define BrowserObjectImpl_IUnknown() \ + virtual struct __BrowserObject* RetainObject() { \ + if (AddRef()) return dynamic_cast(this); \ + return NULL; \ + } \ + virtual struct __BrowserObject* ReleaseObject() { \ + if (Release()) return dynamic_cast(this); \ + return NULL; \ +} + +#define BrowserObjectImpl_NPObject() \ + virtual struct __BrowserObject* RetainObject(){ \ + extern NPNetscapeFuncs* BrowserFuncs; \ + if (BrowserFuncs->retainobject(this)) return this; \ + return NULL; \ + } \ + virtual struct __BrowserObject* ReleaseObject(){ \ + extern NPNetscapeFuncs* BrowserFuncs; \ + BrowserFuncs->releaseobject(this); \ + if (this->referenceCount == 0) return NULL; \ + return this; \ + } + +#define BrowserObjectImpl_Inline() \ + private: \ + volatile long m_nRefCount = 1; \ + public: \ + struct __BrowserObject* RetainObject() { \ + assert(m_nRefCount > 0); \ + we_atomic_inc(&m_nRefCount); return this; \ + } \ +struct __BrowserObject* ReleaseObject() { \ + assert(m_nRefCount > 0); \ + we_atomic_dec(&m_nRefCount); \ + if (m_nRefCount) return this; \ + delete this; return NULL; \ +} + +#define NPObjectImpl_CreateInstanceWithRef(classname) \ + static NPError CreateInstanceWithRef(NPP instance, classname** ppObj) { \ + extern NPClass classname##Class; \ + extern NPNetscapeFuncs* BrowserFuncs; \ + if (!ppObj) { \ + CHECK_NPERR_RETURN(NPERR_INVALID_PARAM); \ + } \ + NPObject* pObj; \ + if (!(pObj = BrowserFuncs->createobject(instance, &classname##Class))) { \ + CHECK_NPERR_RETURN(NPERR_OUT_OF_MEMORY_ERROR); \ + } \ + *ppObj = dynamic_cast((classname*)pObj); \ + return NPERR_NO_ERROR; \ + } + +#define NPObjectImpl_NPObjectRelease(classname) \ + static void ReleaseInstance(classname** ppObj) { \ + if (ppObj && *ppObj) { \ + extern NPNetscapeFuncs* BrowserFuncs; \ + NPObject *pObj = dynamic_cast(*ppObj); \ + SafeReleaseNPObject(&pObj); \ + *ppObj = NULL; \ + } \ + } +#define NPObjectImpl_IsInstanceOf(classname) \ + static bool IsInstanceOf(NPObject* pObj) { \ + extern NPClass classname##Class; \ + return (pObj && pObj->_class == &classname##Class); \ + } + +#undef CHECK_HR +// In CHECK_HR(x) When (x) is a function it will be executed twice when used in "WE_DEBUG_ERROR(x)" and "If(x)" +#define CHECK_HR_BAIL(x) { HRESULT __hr__ = (x); if (FAILED(__hr__)) { WE_DEBUG_ERROR("Operation Failed (%08x)", __hr__); goto bail; } } +#define CHECK_HR_RETURN(x) { HRESULT __hr__ = (x); if (FAILED(__hr__)) { WE_DEBUG_ERROR("Operation Failed (%08x)", __hr__); return __hr__; } } +#define CHECK_NPERR_RETURN(x) { NPError __err__ = (x); if (__err__ != NPERR_NO_ERROR) { WE_DEBUG_ERROR("Operation Failed (%08x)", __err__); return __err__; } } + +extern WEBRTC_EVERYWHERE_API talk_base::scoped_refptr GetPeerConnectionFactory(); +extern WEBRTC_EVERYWHERE_API void TakeFakePeerConnectionFactory(); +extern WEBRTC_EVERYWHERE_API void ReleaseFakePeerConnectionFactory(); +extern talk_base::scoped_refptr<_RTCMediaConstraints> BuildConstraints(const _MediaConstraintsObj* constraints = NULL); +extern webrtc::MediaStreamInterface* BuildMediaStream(const _MediaStream* stream); + +#endif /* _WEBRTC_EVERYWHERE_COMMON_COMMON_H_ */ diff --git a/common/_Config.h b/common/_Config.h new file mode 100755 index 0000000..7a2675e --- /dev/null +++ b/common/_Config.h @@ -0,0 +1,141 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_CONFIG_H_ +#define _WEBRTC_EVERYWHERE_CONFIG_H_ + +#define WE_CAT_(A, B) A ## B +#define WE_CAT(A, B) WE_CAT_(A, B) +#define WE_STRING_(A) #A +#define WE_STRING(A) WE_STRING_(A) + +#if !defined(kPluginMIMEType) +# define kPluginMIMEType "application/webrtc-everywhere" +#endif + +#if !defined(kPluginVersionMajor) +# define kPluginVersionMajor 1 +#endif +#if !defined(kPluginVersionMinor) +# define kPluginVersionMinor 0 +#endif +#if !defined(kPluginVersionMicro) +# define kPluginVersionMicro 1 +#endif +#if !defined(kPluginVersionString) +# define kPluginVersionString WE_STRING(WE_CAT(kPluginVersionMajor, .)) WE_STRING(WE_CAT(kPluginVersionMinor, .)) WE_STRING(kPluginVersionMicro) +#endif + +// Windows +#if defined(WIN32)|| defined(_WIN32) || defined(_WIN32_WCE) +# define WE_UNDER_WINDOWS 1 +#else +typedef int64_t LONGLONG; +typedef unsigned int UINT; +typedef long LRESULT; +typedef void* WPARAM; +typedef void* LPARAM; +typedef void* HWND; +#define CALLBACK +#endif + +// OS X or iOS +#if defined(__APPLE__) +# define WE_UNDER_APPLE 1 +#endif +#if TARGET_OS_MAC +# define WE_UNDER_MAC 1 +#endif +#if TARGET_OS_IPHONE +# define WE_UNDER_IPHONE 1 +#endif +#if TARGET_IPHONE_SIMULATOR +# define WE_UNDER_IPHONE_SIMULATOR 1 +#endif + + +#ifdef _MSC_VER +# define _CRT_SECURE_NO_WARNINGS +# define WE_INLINE _inline +# define we_stricmp _stricmp +# ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +# endif +#else +# define WE_INLINE inline +# define we_stricmp stricmp +#endif + +#if !defined(__GNUC__) && defined(WEBRTC_EVERYWHERE_EXPORTS) +# define WEBRTC_EVERYWHERE_API __declspec(dllexport) +# define WEBRTC_EVERYWHERE_GEXTERN extern __declspec(dllexport) +#elif !defined(__GNUC__) && !defined(WEBRTC_EVERYWHERE_IMPORTS_IGNORE) +# define WEBRTC_EVERYWHERE_API __declspec(dllimport) +# define WEBRTC_EVERYWHERE_GEXTERN __declspec(dllimport) +#else +# define WEBRTC_EVERYWHERE_API +# define WEBRTC_EVERYWHERE_GEXTERN extern +#endif + +typedef enum WeError { + WeError_Success = 0, + WeError_InvalidArgument, + WeError_InvalidJsonContent, + WeError_OutOfMemory, + WeError_System +} +WeError; + +// http://www.w3.org/TR/webrtc/#idl-def-RTCSdpType +#define kRTCSdpType_offer "offer" +#define kRTCSdpType_pranswer "pranswer" +#define kRTCSdpType_answer "answer" + +#define SafeRelease(ppObj) { if ((ppObj) && *(ppObj)) { (*(ppObj))->Release(); *(ppObj) = NULL; } } +#define SafeReleaseObject(ppObj) { if ((ppObj) && *(ppObj)) { (*(ppObj))->ReleaseObject(); *(ppObj) = NULL; } } +#define SafeFree(ppObj) { if ((ppObj) && *(ppObj)) { free(*(ppObj)); *(ppObj) = NULL; } } + +#define SafeReleaseNPObject(ppObj) \ + if ((ppObj) && *(ppObj)) { \ + if ((*(ppObj))->referenceCount > 0) BrowserFuncs->releaseobject(*(ppObj)); \ + *(ppObj) = NULL; \ + } + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// C++11 +#include +#include + +#if __clang__ +# include +# include + +namespace cpp11 = std::tr1; +class { +public: + template + operator cpp11::shared_ptr() { return cpp11::shared_ptr(); } +} nullPtr; +#elif _MSC_VER || __llvm__ || 1 +# include +namespace cpp11 = std; +# define nullPtr nullptr +#else +# error "Not implemented" +#endif + +#if 0 +#include +#include +#endif + +#endif /* _WEBRTC_EVERYWHERE_CONFIG_H_ */ + diff --git a/common/_Debug.h b/common/_Debug.h new file mode 100755 index 0000000..e19ef8c --- /dev/null +++ b/common/_Debug.h @@ -0,0 +1,45 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_DEBUG_H_ +#define _WEBRTC_EVERYWHERE_DEBUG_H_ + +#include "_Config.h" + +#if !defined(WE_DEBUG_LEVEL) +# define WE_DEBUG_LEVEL WE_DEBUG_LEVEL_ERROR +#endif + +#define WE_DEBUG_LEVEL_INFO 4 +#define WE_DEBUG_LEVEL_WARN 3 +#define WE_DEBUG_LEVEL_ERROR 2 +#define WE_DEBUG_LEVEL_FATAL 1 + +/* INFO */ +#if WE_DEBUG_LEVEL >= DEBUG_LEVEL_INFO +# define WE_DEBUG_INFO(FMT, ...) fprintf(stderr, "*INFO: " FMT "\n", ##__VA_ARGS__); +#else +# define WE_DEBUG_INFO(FMT, ...) +#endif + +/* WARN */ +#if WE_DEBUG_LEVEL >= DEBUG_LEVEL_WARN +# define WE_DEBUG_WARN(FMT, ...) fprintf(stderr, "**WARN: function: \"%s()\" \nfile: \"%s\" \nline: \"%u\" \nMSG: " FMT "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__); +#else +# define WE_DEBUG_WARN(FMT, ...) +#endif + +/* WARN */ +#if WE_DEBUG_LEVEL >= DEBUG_LEVEL_ERROR +# define WE_DEBUG_ERROR(FMT, ...) fprintf(stderr, "**ERROR: function: \"%s()\" \nfile: \"%s\" \nline: \"%u\" \nMSG: " FMT "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__); +#else +# define WE_DEBUG_ERROR(FMT, ...) +#endif + +/* FATAL */ +#if WE_DEBUG_LEVEL >= DEBUG_LEVEL_FATAL +# define WE_DEBUG_FATAL(FMT, ...) fprintf(stderr, "**FATAL: function: \"%s()\" \nfile: \"%s\" \nline: \"%u\" \nMSG: " FMT "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__); +#else +# define WE_DEBUG_FATAL(FMT, ...) +#endif + +#endif /* _WEBRTC_EVERYWHERE_DEBUG_H_ */ + diff --git a/common/_Main.cc b/common/_Main.cc new file mode 100755 index 0000000..0e1f627 --- /dev/null +++ b/common/_Main.cc @@ -0,0 +1,182 @@ +// http://www.w3.org/TR/mediacapture-streams/ +// http://www.w3.org/TR/webrtc/ + + + +#include +#include +#include +#include + +#include "_PeerConnection.h" +#include "_NavigatorUserMedia.h" +#include "_MediaStream.h" +#include "_MediaStreamTrack.h" +#include "_MediaTrackConstraints.h" +#include "_MediaStreamConstraints.h" +#include "_Utils.h" +#include "_Debug.h" + +#ifdef WIN32 +#include +#endif + +static std::shared_ptr<_MediaStream> mediaStream = nullptr; +static std::shared_ptr<_SessionDescription>sdpOffer = nullptr; +static std::shared_ptr<_PeerConnection>peerConnection = nullptr; + +// http://www.w3.org/TR/webrtc/#idl-def-RTCSessionDescriptionCallback +static void CreateOfferSuccessCb(std::shared_ptr<_SessionDescription> sdp) +{ + sdpOffer = sdp; +} + +// http://www.w3.org/TR/webrtc/#idl-def-RTCPeerConnectionErrorCallback +static void CreateOfferErrorCb(std::shared_ptr error) +{ + +} + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-NavigatorUserMediaSuccessCallback +static void NavigatorUserMediaSuccessCb(std::shared_ptr<_MediaStream> stream) +{ + mediaStream = stream; +} + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-NavigatorUserMediaErrorCallback +static void NavigatorUserMediaErrorCb(std::shared_ptr<_NavigatorUserMediaError>e) +{ + WE_DEBUG_ERROR("%s", e->constraintName.c_str()); +} + +// http://www.w3.org/TR/webrtc/#event-negotiation +static void onnegotiationneededCallback() +{ + +} +// http://www.w3.org/TR/webrtc/#event-icecandidate +static void onicecandidateCallback(std::shared_ptr<_RTCPeerConnectionIceEvent> e) +{ + if (e->candidate) { + peerConnection->AddIceCandidate(e->candidate.get()); + } +} +// http://www.w3.org/TR/webrtc/#event-signalingstatechange +static void onsignalingstatechangeCallback() +{ + if (peerConnection) { + WE_DEBUG_INFO("New signaling state: %s", peerConnection->SignalingState()); + } +} +// http://www.w3.org/TR/webrtc/#event-mediastream-addstream +static void onaddstreamCallback(std::shared_ptr<_MediaStreamEvent> stream) +{ + +} + +// http://www.w3.org/TR/webrtc/#event-mediastream-removestream +static void onremovestreamCallback(std::shared_ptr<_MediaStreamEvent> stream) +{ + +} +// http://www.w3.org/TR/webrtc/#event-iceconnectionstatechange +static void oniceconnectionstatechangeCallback() +{ + +} + +// http://www.w3.org/TR/webrtc/#idl-def-RTCStatsCallback +static void onRTCStatsCallback(std::shared_ptr<_RTCStatsReport> report) +{ + +} + +int _tmain(int argc, _TCHAR* argv[]) +{ + _Utils::Initialize(); + TakeFakePeerConnectionFactory(); + + peerConnection = std::make_shared<_PeerConnection>(); + static _RTCIceServer iceServers[] = { + { "stun:stun.l.google.com:19302" }, + { "turn:numb.viagenie.ca:3478", "user", "password" }, + }; + static size_t iceServersCount = sizeof(iceServers) / sizeof(iceServers[0]); + + std::shared_ptr<_Sequence<_MediaStream> > localStreams; + std::shared_ptr<_Sequence<_MediaStream> > remoteStreams; + + _RTCConfiguration peerConnectionConfiguration; + peerConnectionConfiguration.iceServers.push_back(_RTCIceServer(iceServers[0].uri, iceServers[0].username, iceServers[0].password)); + peerConnectionConfiguration.iceServers.push_back(_RTCIceServer(iceServers[1].uri, iceServers[1].username, iceServers[1].password)); + + std::shared_ptr<_MediaConstraints> optional = std::make_shared<_MediaConstraints>(); + std::shared_ptr<_MediaConstraints> mandatory = std::make_shared<_MediaConstraints>(); + _MediaConstraintsObj peerConnectionConstraints(optional, mandatory); + + std::shared_ptr<_MediaTrackConstraints> audio = std::make_shared<_MediaTrackConstraints>(true); + std::shared_ptr<_MediaTrackConstraints> video = std::make_shared<_MediaTrackConstraints>(true); + _MediaStreamConstraints mediaStreamConstraints(audio, video); + + _NavigatorUserMedia::getUserMedia(&mediaStreamConstraints, NavigatorUserMediaSuccessCb, NavigatorUserMediaErrorCb); + + if (!mediaStream) { + goto bail; + } + + peerConnection->SetCallback_onnegotiationneeded(onnegotiationneededCallback); + peerConnection->SetCallback_onicecandidate(onicecandidateCallback); + peerConnection->SetCallback_onsignalingstatechange(onsignalingstatechangeCallback); + peerConnection->SetCallback_onaddstream(onaddstreamCallback); + peerConnection->SetCallback_onremovestream(onremovestreamCallback); + peerConnection->SetCallback_oniceconnectionstatechange(oniceconnectionstatechangeCallback); + + mandatory->insert(std::pair("DtlsSrtpKeyAgreement", "true")); + if (!peerConnection->Init(&peerConnectionConfiguration, &peerConnectionConstraints)) { + goto bail; + } + + if (!peerConnection->AddStream(mediaStream.get())) { + goto bail; + } + + if (!peerConnection->CreateOffer(CreateOfferSuccessCb, CreateOfferErrorCb)) { + goto bail; + } + + // FIXME: AssertBreak() at the end because not all streams are destroyed + localStreams = peerConnection->GetLocalStreams(); + remoteStreams = peerConnection->GetRemoteStreams(); + + if (localStreams->values.size() > 0) { + std::shared_ptr<_MediaStream>localStream = localStreams->values[0]->clone(); + + std::shared_ptr<_Sequence<_MediaStreamTrack> > audioTracks = localStream->getAudioTracks(); + std::shared_ptr<_Sequence<_MediaStreamTrack> > videoTracks = localStream->getVideoTracks(); + + WE_DEBUG_INFO("audioTracks.size() = %ld", audioTracks->values.size()); + WE_DEBUG_INFO("videoTracks.size() = %ld", videoTracks->values.size()); + + for (size_t i = 0; i < audioTracks->values.size(); ++i) { + WE_DEBUG_INFO("AudioTrack: %s, %s, %s", audioTracks->values[i]->id(), audioTracks->values[i]->kind(), audioTracks->values[i]->label()); + } + for (size_t i = 0; i < videoTracks->values.size(); ++i) { + WE_DEBUG_INFO("VideoTrack: %s, %s, %s", videoTracks->values[i]->id(), videoTracks->values[i]->kind(), videoTracks->values[i]->label()); + } + } + + getchar(); + + localStreams = nullptr; + remoteStreams = nullptr; + peerConnection = nullptr; + mediaStream = nullptr; + _Utils::DeInitialize(); + ReleaseFakePeerConnectionFactory(); + + return 0; + +bail: + assert(0); + return -1; +} \ No newline at end of file diff --git a/common/_MediaStream.cc b/common/_MediaStream.cc new file mode 100755 index 0000000..0977b0a --- /dev/null +++ b/common/_MediaStream.cc @@ -0,0 +1,234 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#mediastream +#include "_MediaStream.h" +#include "_MediaStreamTrack.h" +#include "_Common.h" +#include "_Utils.h" +#include "_Debug.h" + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/logging.h" + +#if WE_UNDER_WINDOWS +# include +#endif + +#define RETURN_IF_NOT_VALID() if (!IsValid()) return; + +_MediaStreamAllocateFn _MediaStream::s_Allocator = _MediaStream::AllocateDefault; + +_MediaStream::_MediaStream(MediaStreamInterfacePtr _stream /*= NULL*/) +{ + m_stream = dynamic_cast((webrtc::MediaStreamInterface*)_stream); + if (!m_stream) { + talk_base::scoped_refptr peer_connection_factory = GetPeerConnectionFactory(); + if (peer_connection_factory) { + static long __id = 1; + std::string _id = _Utils::ToString(we_atomic_inc(&__id)); + m_stream = peer_connection_factory->CreateLocalMediaStream(_id); + } + } + if (!m_stream) { + WE_DEBUG_ERROR("Failed to create stream"); + } + else { + m_id = m_stream->label(); + } +} + +_MediaStream::~_MediaStream() +{ + m_stream = NULL; + WE_DEBUG_INFO("_MediaStream::~_MediaStream"); +} + +_MediaStream* _MediaStream::AllocateDefault() +{ + return new _MediaStream(); +} + +cpp11::shared_ptr<_Sequence<_MediaStreamTrack> > _MediaStream::getAudioTracks() +{ + cpp11::shared_ptr<_Sequence<_MediaStreamTrack> > seq(new _Sequence<_MediaStreamTrack>()); + + if (IsValid()) { + webrtc::AudioTrackVector tracks = m_stream->GetAudioTracks(); + for (size_t i = 0; i < tracks.size(); ++i){ + if (tracks[i]) { + seq->Add(cpp11::shared_ptr<_MediaStreamTrackAudio>(new _MediaStreamTrackAudio(tracks[i]))); + } + } + } + + return seq; +} + +cpp11::shared_ptr<_Sequence<_MediaStreamTrack> > _MediaStream::getVideoTracks() +{ + cpp11::shared_ptr<_Sequence<_MediaStreamTrack> > seq(new _Sequence<_MediaStreamTrack>()); + + if (IsValid()) { + webrtc::VideoTrackVector tracks = m_stream->GetVideoTracks(); + for (size_t i = 0; i < tracks.size(); ++i){ + if (tracks[i]) { + seq->Add(cpp11::shared_ptr<_MediaStreamTrackVideo>(new _MediaStreamTrackVideo(tracks[i]))); + } + } + } + + return seq; +} + +// void addTrack (MediaStreamTrack track); +// http://www.w3.org/TR/mediacapture-streams/#widl-MediaStream-addTrack-void-MediaStreamTrack-track +void _MediaStream::addTrack(_MediaStreamTrack* p_track) +{ + RETURN_IF_NOT_VALID(); + if (!p_track) { + WE_DEBUG_ERROR("Invalid parameter"); + return; + } + + _MediaStreamTrackBase *_pTrack = dynamic_cast<_MediaStreamTrackBase*>(p_track); + bool added = false; + if (_pTrack) { + switch (p_track->type()) + { + case _MediaStreamTrackTypeAudio: + { + added = m_stream->AddTrack(dynamic_cast<_MediaStreamTrackAudio*>(_pTrack)->track()); + break; + } + case _MediaStreamTrackTypeVideo: + { + added = m_stream->AddTrack(dynamic_cast<_MediaStreamTrackVideo*>(_pTrack)->track()); + break; + } + default: + WE_DEBUG_ERROR("%d not valid stream track type", p_track->type()); + break; + } + } + else { + WE_DEBUG_ERROR("Invalid stream track"); + } + + if (added && m_onaddtrack) { + m_onaddtrack(); + } +} + +// void removeTrack (MediaStreamTrack track); +// http://www.w3.org/TR/mediacapture-streams/#widl-MediaStream-removeTrack-void-MediaStreamTrack-track +void _MediaStream::removeTrack(_MediaStreamTrack* p_track) +{ + RETURN_IF_NOT_VALID(); + if (!p_track) { + WE_DEBUG_ERROR("Invalid parameter"); + return; + } + + _MediaStreamTrackBase *_pTrack = dynamic_cast<_MediaStreamTrackBase*>(p_track); + bool removed = false; + if (_pTrack) { + switch (p_track->type()) + { + case _MediaStreamTrackTypeAudio: + removed = m_stream->RemoveTrack(dynamic_cast<_MediaStreamTrackAudio*>(_pTrack)->track()); + break; + case _MediaStreamTrackTypeVideo: + removed = m_stream->RemoveTrack(dynamic_cast<_MediaStreamTrackVideo*>(_pTrack)->track()); + break; + default: + WE_DEBUG_ERROR("%d not valid stream track type", p_track->type()); + break; + } + } + else { + WE_DEBUG_ERROR("Invalid stream track"); + } + + if (removed && m_onremovetrack) { + m_onremovetrack(); + } +} + +cpp11::shared_ptr<_MediaStreamTrack> _MediaStream::getTrackById(const char* trackId) +{ + cpp11::shared_ptr<_MediaStreamTrack> track = nullPtr; + if (trackId && IsValid()) { + talk_base::scoped_refptr track_audio = m_stream->FindAudioTrack(std::string(trackId)); + if (track_audio.get()) { + track = cpp11::shared_ptr<_MediaStreamTrackAudio>(new _MediaStreamTrackAudio(track_audio)); + } + else { + talk_base::scoped_refptr track_video = m_stream->FindVideoTrack(std::string(trackId)); + if (track_video.get()) { + track = cpp11::shared_ptr<_MediaStreamTrackVideo>(new _MediaStreamTrackVideo(track_video)); + } + } + } + + return track; +} + +cpp11::shared_ptr<_MediaStream> _MediaStream::clone() +{ + // http://www.w3.org/TR/mediacapture-streams/#widl-MediaStream-clone-MediaStream + cpp11::shared_ptr<_MediaStream> _clone = nullPtr; + if (IsValid()) { + _clone = cpp11::shared_ptr<_MediaStream>(new _MediaStream()); + if (_clone && _clone->IsValid()) { + // audio + cpp11::shared_ptr<_Sequence<_MediaStreamTrack> > audioTracks = getAudioTracks(); + if (audioTracks) { + for (size_t i = 0; i < audioTracks->values.size(); ++i) { + if (audioTracks->values[i].get()) { + _clone->addTrack(audioTracks->values[i].get()); + } + } + } + // video + cpp11::shared_ptr<_Sequence<_MediaStreamTrack> > videoTracks = getVideoTracks(); + if (videoTracks) { + for (size_t i = 0; i < videoTracks->values.size(); ++i) { + if (videoTracks->values[i].get()) { + _clone->addTrack(videoTracks->values[i].get()); + } + } + } + } + } + return _clone; +} + +bool _MediaStream::ended() +{ + if (IsValid()) { + return m_stream == NULL; + } + return true; +} + +void _MediaStream::stop() +{ + cpp11::shared_ptr<_Sequence<_MediaStreamTrack> > _tracks[] = { getAudioTracks(), getVideoTracks() }; + for (size_t i = 0; i < sizeof(_tracks) / sizeof(_tracks[0]); ++i) { + if (_tracks[i]){ + for (size_t j = 0; j < _tracks[i]->values.size(); ++j) { + if (_tracks[i]->values[j]){ + removeTrack(_tracks[i]->values[j].get()); + } + } + } + } +} + +VideoTrackInterfacePtr _MediaStream::GetVideoTrack(int index /*= 0*/)const +{ + if (m_stream && index >= 0 && index < (int)m_stream->GetVideoTracks().size()) { + return m_stream->GetVideoTracks().at(index); + } + return NULL; +} \ No newline at end of file diff --git a/common/_MediaStream.h b/common/_MediaStream.h new file mode 100755 index 0000000..a1a7b2c --- /dev/null +++ b/common/_MediaStream.h @@ -0,0 +1,72 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#mediastream +#ifndef _WEBRTC_EVERYWHERE_COMMON_MEDIASTREAM_H_ +#define _WEBRTC_EVERYWHERE_COMMON_MEDIASTREAM_H_ + +#include "_Config.h" +#include "_Common.h" +#include "_MediaStreamTrack.h" + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/base/scoped_ptr.h" + +class _MediaStreamTrack; + +class WEBRTC_EVERYWHERE_API _MediaStream +{ +public: + _MediaStream(MediaStreamInterfacePtr stream = NULL); + virtual ~_MediaStream(); + +public: + // readonly attribute DOMString id; + const char* id() { return m_id.c_str(); } + // sequence getAudioTracks (); + cpp11::shared_ptr<_Sequence<_MediaStreamTrack> > getAudioTracks(); + // sequence getVideoTracks (); + cpp11::shared_ptr<_Sequence<_MediaStreamTrack> > getVideoTracks(); + // http://www.w3.org/TR/mediacapture-streams/#widl-MediaStream-addTrack-void-MediaStreamTrack-track + // void addTrack (MediaStreamTrack track); + void addTrack(_MediaStreamTrack* p_track); + // http://www.w3.org/TR/mediacapture-streams/#widl-MediaStream-removeTrack-void-MediaStreamTrack-track + // void removeTrack (MediaStreamTrack track); + void removeTrack(_MediaStreamTrack* p_track); + // MediaStreamTrack? getTrackById (DOMString trackId); + cpp11::shared_ptr<_MediaStreamTrack> getTrackById(const char* trackId); + // MediaStream clone (); + cpp11::shared_ptr<_MediaStream> clone(); + // readonly attribute boolean ended; + bool ended(); + // not part of the standard but implemented in Chrome + void stop(); + + void onendedSet(_VoidFunctionCallback onended) { m_onended = onended; } // attribute EventHandler onended; + void onaddtrackSet(_VoidFunctionCallback onaddtrack) { m_onaddtrack = onaddtrack; } // attribute EventHandler onaddtrack; + void onremovetrackSet(_VoidFunctionCallback onremovetrack) { m_onremovetrack = onremovetrack; } // attribute EventHandler onremovetrack; + + bool IsValid()const { return m_stream != NULL; } + MediaStreamInterfacePtr GetWrappedStream()const { return m_stream; } + VideoTrackInterfacePtr GetVideoTrack(int index = 0)const; + static void SetAllocator(_MediaStreamAllocateFn allocator) { s_Allocator = allocator; } + static _MediaStream* Allocate() { return s_Allocator ? s_Allocator() : NULL; } + +private: + static _MediaStream* AllocateDefault(); + +private: +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + std::string m_id; + talk_base::scoped_refptr m_stream; + static _MediaStreamAllocateFn s_Allocator; + _VoidFunctionCallback m_onended; + _VoidFunctionCallback m_onaddtrack; + _VoidFunctionCallback m_onremovetrack; +#if _MSC_VER +#pragma warning(pop) +#endif +}; + +#endif /* _WEBRTC_EVERYWHERE_COMMON_MEDIASTREAM_H_ */ diff --git a/common/_MediaStreamConstraints.cc b/common/_MediaStreamConstraints.cc new file mode 100755 index 0000000..c8ba4e6 --- /dev/null +++ b/common/_MediaStreamConstraints.cc @@ -0,0 +1,18 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#idl-def-MediaStreamConstraints +#include "_MediaStreamConstraints.h" +#include "_Debug.h" + +_MediaStreamConstraints::_MediaStreamConstraints(cpp11::shared_ptr<_MediaTrackConstraints> audio /*= nullPtr*/, cpp11::shared_ptr<_MediaTrackConstraints> video /*= nullPtr*/) + : m_audio(audio) + , m_video(video) +{ +} + +_MediaStreamConstraints::~_MediaStreamConstraints() +{ + m_audio = nullPtr; + m_video = nullPtr; + + WE_DEBUG_INFO("_MediaStreamConstraints::~_MediaStreamConstraints"); +} diff --git a/common/_MediaStreamConstraints.h b/common/_MediaStreamConstraints.h new file mode 100755 index 0000000..a2c83f7 --- /dev/null +++ b/common/_MediaStreamConstraints.h @@ -0,0 +1,35 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#idl-def-MediaStreamConstraints +#ifndef _WEBRTC_EVERYWHERE_COMMON_MEDIASTREAMCONSTRAINTS_H_ +#define _WEBRTC_EVERYWHERE_COMMON_MEDIASTREAMCONSTRAINTS_H_ + +#include "_Config.h" +#include "_Common.h" +#include "_MediaTrackConstraints.h" + +#include + +class _Buffer; + +class WEBRTC_EVERYWHERE_API _MediaStreamConstraints +{ +public: + _MediaStreamConstraints(cpp11::shared_ptr<_MediaTrackConstraints> audio = nullPtr, cpp11::shared_ptr<_MediaTrackConstraints> video = nullPtr); + virtual ~_MediaStreamConstraints(); + + WE_INLINE cpp11::shared_ptr<_MediaTrackConstraints> audio() const { return m_audio; } + WE_INLINE cpp11::shared_ptr<_MediaTrackConstraints> video() const { return m_video; } + +private: +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + cpp11::shared_ptr<_MediaTrackConstraints> m_audio; + cpp11::shared_ptr<_MediaTrackConstraints> m_video; +#if _MSC_VER +#pragma warning(pop) +#endif +}; + +#endif /* _WEBRTC_EVERYWHERE_COMMON_MEDIASTREAMCONSTRAINTS_H_ */ diff --git a/common/_MediaStreamTrack.cc b/common/_MediaStreamTrack.cc new file mode 100755 index 0000000..e4d0ceb --- /dev/null +++ b/common/_MediaStreamTrack.cc @@ -0,0 +1,384 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#mediastreamtrack +#include "_MediaStreamTrack.h" +#include "_Common.h" +#include "_Utils.h" +#include "_Debug.h" + +#include "talk/app/webrtc/videosourceinterface.h" +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/media/devices/devicemanager.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/logging.h" + +#if WE_UNDER_WINDOWS +# include +#endif + +// +// _MediaStreamTrack +// + +_MediaStreamTrack::_MediaStreamTrack(_MediaStreamTrackType eType, MediaStreamTrackInterfacePtr track /*= NULL*/, const _MediaTrackConstraints* constrains /*= NULL*/) + : m_eType(eType) + , m_bRemote(!!track) + , m_pConstraints(nullPtr) +{ + static long __label = 1; + + m_label = _Utils::ToString(we_atomic_inc(&__label)); +} + +_MediaStreamTrack::~_MediaStreamTrack() +{ + WE_DEBUG_INFO("_MediaStreamTrack::~_MediaStreamTrack"); +} + +cpp11::shared_ptr<_Sequence<_SourceInfo> > _MediaStreamTrack::getSourceInfos() +{ + cpp11::shared_ptr<_Sequence<_SourceInfo> > infos(new _Sequence<_SourceInfo>()); + cpp11::shared_ptr<_SourceInfo> info; + + talk_base::scoped_ptr dev_manager( + cricket::DeviceManagerFactory::Create()); + if (!dev_manager->Init()) { + LOG(LS_ERROR) << "Can't create device manager"; + return infos; + } + + // VideoCapture + std::vector devs; + std::string video("video"); + if (dev_manager->GetVideoCaptureDevices(&devs)) { + std::vector::iterator dev_it = devs.begin(); + for (; dev_it != devs.end(); ++dev_it) { + info = cpp11::shared_ptr<_SourceInfo>(new _SourceInfo(dev_it->id, video, dev_it->name)); + if (info.get()) { + infos->Add(info); + } + } + } + else { + LOG(LS_ERROR) << "Can't enumerate video devices"; + } +#if 0 + // AudioOut + if (dev_manager->GetAudioOutputDevices(&devs)) { + std::vector::iterator dev_it = devs.begin(); + std::string audio("audio"); + for (; dev_it != devs.end(); ++dev_it) { + info = cpp11::shared_ptr<_SourceInfo>(new _SourceInfo(dev_it->id, audio, dev_it->name)); + if (info.get()) { + infos->Add(info); + } + } + } + else { + LOG(LS_ERROR) << "Can't enumerate audioOut devices"; + } +#endif + + // AudioIn + if (dev_manager->GetAudioInputDevices(&devs)) { + std::vector::iterator dev_it = devs.begin(); + std::string audio("audio"); + for (; dev_it != devs.end(); ++dev_it) { + info = cpp11::shared_ptr<_SourceInfo>(new _SourceInfo(dev_it->id, audio, dev_it->name)); + if (info.get()) { + infos->Add(info); + } + } + } + else { + LOG(LS_ERROR) << "Can't enumerate audioIn devices"; + return infos; + } + + return infos; +} + + +// +// _MediaStreamTrackBase +// + +_MediaStreamTrackBase::_MediaStreamTrackBase(_MediaStreamTrackType eType, MediaStreamTrackInterfacePtr track /*= NULL*/, const _MediaTrackConstraints* constrains /*= NULL*/) + : _MediaStreamTrack(eType, track, constrains) +{ +} + +_MediaStreamTrackBase::~_MediaStreamTrackBase() +{ + +} + +void _MediaStreamTrackBase::InitLocalVarsToAvoidDanglingPointerIssue() +{ + if (_track()) { + m_id = _track()->id(); + m_kind = _track()->kind(); + } +} + +// "_MediaStreamTrack" interface implementation + +bool _MediaStreamTrackBase::enabledSet(bool enabled) +{ + if (_track()) { + return _track()->set_enabled(enabled); + } + return false; +} +bool _MediaStreamTrackBase::enabled() +{ + if (_track()) { + return _track()->enabled(); + } + return false; +} + +bool _MediaStreamTrackBase::readonly() +{ + if (_track()) { + return false; + } + return true; +} + +const char* _MediaStreamTrackBase::readyState() +{ + if (_track()) { + switch (_track()->state()) { + case webrtc::MediaStreamTrackInterface::kEnded: + return kMediaStreamTrackStateEnded; + case webrtc::MediaStreamTrackInterface::kFailed: + return kMediaStreamTrackStateFailed; + case webrtc::MediaStreamTrackInterface::kInitializing: + return kMediaStreamTrackStateNew; + case webrtc::MediaStreamTrackInterface::kLive: + return kMediaStreamTrackStateLive; + } + } + return kMediaStreamTrackStateFailed; +} + +cpp11::shared_ptr<_MediaSourceStates> _MediaStreamTrackBase::states() +{ + cpp11::shared_ptr<_MediaSourceStates> _states; + + // FIXME: not implemented yet + WE_DEBUG_ERROR("Not implemented yet"); + + return _states; +} + +cpp11::shared_ptr<_AllCapabilities> _MediaStreamTrackBase::capabilities() +{ + cpp11::shared_ptr<_AllCapabilities> _capabilities; + + // FIXME: not implemented yet + WE_DEBUG_ERROR("Not implemented yet"); + + return _capabilities; +} + +void _MediaStreamTrackBase::applyConstraints(const _MediaTrackConstraints* constrains) +{ + if (_track()) { + + } + + // http://www.w3.org/TR/mediacapture-streams/#widl-MediaStreamTrack-applyConstraints-void-MediaTrackConstraints-constraints + // FIXME: not implemented yet + WE_DEBUG_ERROR("Not implemented yet"); +} + +cpp11::shared_ptr<_MediaStreamTrack> _MediaStreamTrackBase::clone() +{ + // http://www.w3.org/TR/mediacapture-streams/#widl-MediaStreamTrack-clone-MediaStreamTrack + // FIXME: not implemented yet + WE_DEBUG_ERROR("Not implemented yet"); + + return nullPtr; +} + +void _MediaStreamTrackBase::stop() +{ + if (_track()) { + + } + + // http://www.w3.org/TR/mediacapture-streams/#widl-MediaStreamTrack-stop-void + // FIXME: not implemented yet + WE_DEBUG_ERROR("Not implemented yet"); +} + +// +// _MediaStreamTrackAudio +// + +_MediaStreamTrackAudio::_MediaStreamTrackAudio(talk_base::scoped_refptr track /*= NULL*/, const _MediaTrackConstraints* constrains /*= NULL*/) + : _MediaStreamTrackBase(_MediaStreamTrackTypeAudio, track, constrains) + , m_track(track) +{ + if (!m_track) { + talk_base::scoped_refptr peer_connection_factory = GetPeerConnectionFactory(); + if (peer_connection_factory) { + m_label += "_audio_track"; + __MediaConstraintsObj _constrainsObject(constrains ? constrains->optional() : nullPtr, constrains ? constrains->mandatory() : nullPtr); + m_track = peer_connection_factory->CreateAudioTrack(m_label, peer_connection_factory->CreateAudioSource(BuildConstraints(&_constrainsObject))); + } + } + InitLocalVarsToAvoidDanglingPointerIssue(); +} + +_MediaStreamTrackAudio::~_MediaStreamTrackAudio() +{ + m_track = NULL; + + WE_DEBUG_INFO("_MediaStreamTrackAudio::~_MediaStreamTrackAudio"); +} + +// "_MediaStreamTrack" interface implementation +bool _MediaStreamTrackAudio::muted() +{ + // TODO: no "muted()" function in "AudioTrackInterface" + if (m_track) { + return !enabled(); + } + return true; +} + +// +// _MediaStreamTrackVideo +// +static cricket::VideoCapturer* OpenVideoCaptureDevice(std::string id); + +_MediaStreamTrackVideo::_MediaStreamTrackVideo(talk_base::scoped_refptr track /*= NULL*/, const _MediaTrackConstraints* constrains /*= NULL*/) + : _MediaStreamTrackBase(_MediaStreamTrackTypeVideo, track, constrains) + , m_track(track) +{ + if (!m_track) { + talk_base::scoped_refptr peer_connection_factory = GetPeerConnectionFactory(); + if (peer_connection_factory) { + __MediaConstraintsObj _constrainsObject(constrains ? constrains->optional() : nullPtr, constrains ? constrains->mandatory() : nullPtr); + talk_base::scoped_refptr<_RTCMediaConstraints> _constrains = BuildConstraints(&_constrainsObject); + std::string sourceId; + if (_constrains) { + if (!_constrains->GetMandatory().FindFirst("sourceId", &sourceId)) { + _constrains->GetOptional().FindFirst("sourceId", &sourceId); + } + } + cricket::VideoCapturer* capturer = OpenVideoCaptureDevice(sourceId); + if (!capturer) { + WE_DEBUG_ERROR("Failed to open video capture device"); + return; + } + m_label += "_video_track"; + m_track = peer_connection_factory->CreateVideoTrack(m_label, peer_connection_factory->CreateVideoSource(capturer, _constrains)); + } + } + InitLocalVarsToAvoidDanglingPointerIssue(); +} + + +_MediaStreamTrackVideo:: ~_MediaStreamTrackVideo() +{ + m_track = NULL; + + WE_DEBUG_INFO("_MediaStreamTrackVideo::~_MediaStreamTrackVideo"); +} + +// ISSUE: https://groups.google.com/forum/#!topic/discuss-webrtc/RV6oKhY2qEM +#if WE_UNDER_APPLE +#include "mac/_webrtcvideocapturer.h" +#include "webrtc/modules/video_capture/include/video_capture_factory.h" +class _VideoCapturerFactory : public cricket::VideoCapturerFactory { +public: + _VideoCapturerFactory() {} + virtual ~_VideoCapturerFactory() {} + + cricket::VideoCapturer* Create(const cricket::Device& device) { + cricket::WebRtcVideoCapturer* return_value = new cricket::WebRtcVideoCapturer(); + if (!return_value->Init(device)) { + delete return_value; + return NULL; + } + return return_value; + } +}; +#endif /* WE_UNDER_APPLE */ + +static cricket::VideoCapturer* OpenVideoCaptureDevice(std::string id) { + talk_base::scoped_ptr dev_manager( + cricket::DeviceManagerFactory::Create()); + if (!dev_manager->Init()) { + LOG(LS_ERROR) << "Can't create device manager"; + return NULL; + } + + // ISSUE: https://groups.google.com/forum/#!topic/discuss-webrtc/RV6oKhY2qEM +#if WE_UNDER_APPLE + cricket::DeviceManager* device_manager = static_cast(dev_manager.get()); + device_manager->set_device_video_capturer_factory(new _VideoCapturerFactory()); +#endif /* WE_UNDER_APPLE */ + + std::vector devs; + if (!dev_manager->GetVideoCaptureDevices(&devs)) { + LOG(LS_ERROR) << "Can't enumerate video devices"; + return NULL; + } + std::vector::iterator dev_it; + cricket::VideoCapturer* capturer = NULL; + + if (!id.empty()) { + for (dev_it = devs.begin(); dev_it != devs.end(); ++dev_it) { + if ((*dev_it).id == id) { + capturer = dev_manager->CreateVideoCapturer(*dev_it); + if (capturer) { + return capturer; + } + } + } + } + +#if 0 + webrtc::VideoCaptureModule::DeviceInfo *info = webrtc::VideoCaptureFactory::CreateDeviceInfo(0); + if (info) { + // Find the desired camera, by name. + // In the future, comparing IDs will be more robust. + // TODO(juberti): Figure what's needed to allow this. + int num_cams = info->NumberOfDevices(); + char vcm_id[256] = ""; + bool found = false; + for (int index = 0; index < num_cams; ++index) { + char vcm_name[256]; + if (info->GetDeviceName(index, vcm_name, ARRAY_SIZE(vcm_name), + vcm_id, ARRAY_SIZE(vcm_id)) != -1) { + if ((*devs.begin()).name == reinterpret_cast(vcm_name)) { + found = true; + break; + } + } + } + if (found) { + //std::vector supported; + int32_t num_caps = info->NumberOfCapabilities(vcm_id); + for (int32_t i = 0; i < num_caps; ++i) { + webrtc::VideoCaptureCapability cap; + if (info->GetCapability(vcm_id, i, cap) != -1) { + printf(""); + } + } + } + } +#endif + + for (dev_it = devs.begin(); dev_it != devs.end(); ++dev_it) { + capturer = dev_manager->CreateVideoCapturer(*dev_it); + if (capturer != NULL) + break; + } + return capturer; +} diff --git a/common/_MediaStreamTrack.h b/common/_MediaStreamTrack.h new file mode 100755 index 0000000..be89393 --- /dev/null +++ b/common/_MediaStreamTrack.h @@ -0,0 +1,166 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#mediastreamtrack +#ifndef _WEBRTC_EVERYWHERE_COMMON_MEDIASTREAMTRACK_H_ +#define _WEBRTC_EVERYWHERE_COMMON_MEDIASTREAMTRACK_H_ + +#include "_Config.h" +#include "_MediaTrackConstraints.h" +#include "_Common.h" + +#include "talk/app/webrtc/mediastreaminterface.h" + +class _Buffer; +class _MediaTrackConstraints; + +typedef enum __MediaStreamTrackType +{ + _MediaStreamTrackTypeUnknown, + _MediaStreamTrackTypeAudio, + _MediaStreamTrackTypeVideo +} +_MediaStreamTrackType; + + +// +// _MediaStreamTrack +// +class WEBRTC_EVERYWHERE_API _MediaStreamTrack +{ +protected: + _MediaStreamTrack(_MediaStreamTrackType eType, MediaStreamTrackInterfacePtr track = NULL, const _MediaTrackConstraints* constrains = NULL); +public: + virtual ~_MediaStreamTrack(); + WE_INLINE _MediaStreamTrackType type() { return m_eType; } + WE_INLINE virtual bool IsValid() = 0; + + virtual const char* kind() { return m_kind.c_str(); }; // readonly attribute DOMString kind; + virtual const char* id() { return m_id.c_str(); }; // readonly attribute DOMString id; + virtual const char* label() { return m_label.c_str(); }; // readonly attribute DOMString id; + virtual bool enabledSet(bool enabled) = 0; // attribute boolean enabled; + virtual bool enabled() = 0; // attribute boolean enabled; + virtual bool muted() = 0; // readonly attribute boolean muted; + + void onmuteSet(_VoidFunctionCallback onmute) { m_onmute = onmute; }; // attribute EventHandler onmute; + void onunmuteSet(_VoidFunctionCallback onunmute) { m_onunmute = onunmute; }; // attribute EventHandler onunmute; + + virtual bool readonly() = 0; // readonly attribute boolean _readonly; + virtual bool remote() { return m_bRemote; } // readonly attribute boolean remote; + virtual const char* readyState() = 0; // readonly attribute MediaStreamTrackState readyState; + + void onstartedSet(_VoidFunctionCallback onstarted) { m_onstarted = onstarted; } // attribute EventHandler onstarted; + void onendedSet(_VoidFunctionCallback onended) { m_onended = onended; } // attribute EventHandler onended; + + static cpp11::shared_ptr<_Sequence<_SourceInfo> > getSourceInfos();// static sequence getSourceInfos (); + cpp11::shared_ptr<_MediaTrackConstraints> constraints() { return m_pConstraints; } // MediaTrackConstraints? constraints (); + + virtual cpp11::shared_ptr<_MediaSourceStates> states() = 0; // MediaSourceStates states (); + + virtual cpp11::shared_ptr<_AllCapabilities> capabilities() = 0; // (AllVideoCapabilities or AllAudioCapabilities) capabilities (); + virtual void applyConstraints(const _MediaTrackConstraints* constrains) = 0; // void applyConstraints(MediaTrackConstraints constraints); + + void onoverconstrainedSet(_VoidFunctionCallback onoverconstrained) { m_onoverconstrained = onoverconstrained; }; // attribute EventHandler onoverconstrained; + + virtual cpp11::shared_ptr<_MediaStreamTrack> clone() = 0; // MediaStreamTrack clone (); + virtual void stop() = 0; // void stop (); + + +protected: +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + _MediaStreamTrackType m_eType; + // loacl strings to avoid "dangling pointer" issue + std::string m_label; + std::string m_id; + std::string m_kind; + + bool m_bRemote; + cpp11::shared_ptr<_MediaTrackConstraints> m_pConstraints; + + _VoidFunctionCallback m_onmute; + _VoidFunctionCallback m_onunmute; + _VoidFunctionCallback m_onstarted; + _VoidFunctionCallback m_onended; + _VoidFunctionCallback m_onoverconstrained; +#if _MSC_VER +#pragma warning(pop) +#endif +}; + +// +// _MediaStreamTrackBase +// +class _MediaStreamTrackBase : public _MediaStreamTrack +{ +protected: + _MediaStreamTrackBase(_MediaStreamTrackType eType, MediaStreamTrackInterfacePtr track = NULL, const _MediaTrackConstraints* constrains = NULL); +public: + virtual ~_MediaStreamTrackBase(); + + // "_MediaStreamTrack" interface implementation + virtual bool enabledSet(bool enabled); + virtual bool enabled(); + virtual bool muted() { return false; } // override in "_MediaStreamTrackAudio" + virtual bool readonly(); + virtual const char* readyState(); + virtual cpp11::shared_ptr<_MediaSourceStates> states(); + virtual cpp11::shared_ptr<_AllCapabilities> capabilities(); + virtual void applyConstraints(const _MediaTrackConstraints* constrains); + virtual cpp11::shared_ptr<_MediaStreamTrack> clone(); + virtual void stop(); + +public: + virtual webrtc::MediaStreamTrackInterface* _track() = 0; + +protected: + void InitLocalVarsToAvoidDanglingPointerIssue(); + +protected: + +}; + +// +// _MediaStreamTrackAudio +// +class _MediaStreamTrackAudio + : public _MediaStreamTrackBase +{ +public: + _MediaStreamTrackAudio(talk_base::scoped_refptr track = NULL, const _MediaTrackConstraints* constrains = NULL); + virtual ~_MediaStreamTrackAudio(); + + WE_INLINE virtual bool IsValid() { return !!m_track; } + virtual talk_base::scoped_refptr track() { return m_track; }; + + // _MediaStreamTrackBase Interface + virtual webrtc::MediaStreamTrackInterface* _track() { return track(); } + + // "_MediaStreamTrack" interface implementation + virtual bool muted(); + +private: + talk_base::scoped_refptr m_track; +}; + +// +// _MediaStreamTrackVideo +// +class _MediaStreamTrackVideo + : public _MediaStreamTrackBase +{ +public: + _MediaStreamTrackVideo(talk_base::scoped_refptr track = NULL, const _MediaTrackConstraints* constrains = NULL); + virtual ~_MediaStreamTrackVideo(); + + WE_INLINE virtual bool IsValid() { return !!m_track; } + virtual talk_base::scoped_refptr track() { return m_track; }; + + // _MediaStreamTrackBase Interface + virtual webrtc::MediaStreamTrackInterface* _track() { return track(); } + +private: + talk_base::scoped_refptr m_track; +}; + +#endif /* _WEBRTC_EVERYWHERE_COMMON_MEDIASTREAMTRACK_H_ */ diff --git a/common/_MediaTrackConstraints.cc b/common/_MediaTrackConstraints.cc new file mode 100755 index 0000000..2b5bd0a --- /dev/null +++ b/common/_MediaTrackConstraints.cc @@ -0,0 +1,22 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "_MediaTrackConstraints.h" +#include "_Debug.h" + +_MediaTrackConstraints::_MediaTrackConstraints(bool bVal) +: m_bValue(bVal) +, m_eType(_MediaTrackConstraintsTypeBoolean) +{ +} + +_MediaTrackConstraints::_MediaTrackConstraints(cpp11::shared_ptr<_MediaConstraints> mandatory /*= nullPtr*/, cpp11::shared_ptr<_MediaConstraints> optional /*= nullPtr*/) + : m_mandatory(mandatory) + , m_optional(optional) + , m_eType(_MediaTrackConstraintsTypeComposite) +{ +} + +_MediaTrackConstraints::~_MediaTrackConstraints() +{ + WE_DEBUG_INFO("_MediaTrackConstraints::~_MediaTrackConstraints"); +} + diff --git a/common/_MediaTrackConstraints.h b/common/_MediaTrackConstraints.h new file mode 100755 index 0000000..d5a24aa --- /dev/null +++ b/common/_MediaTrackConstraints.h @@ -0,0 +1,47 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#idl-def-MediaStreamConstraints +#ifndef _WEBRTC_EVERYWHERE_COMMON_MEDIATRACKCONSTRAINT_H_ +#define _WEBRTC_EVERYWHERE_COMMON_MEDIATRACKCONSTRAINT_H_ + +#include "_Config.h" +#include "_Common.h" + +#include + +class _Buffer; + +typedef enum __MediaTrackConstraintsType +{ + _MediaTrackConstraintsTypeUnknown, + _MediaTrackConstraintsTypeBoolean, + _MediaTrackConstraintsTypeComposite +} _MediaTrackConstraintsType; + +class WEBRTC_EVERYWHERE_API _MediaTrackConstraints +{ +public: + _MediaTrackConstraints(bool bVal); + _MediaTrackConstraints(cpp11::shared_ptr<_MediaConstraints> mandatory = nullPtr, cpp11::shared_ptr<_MediaConstraints> optional = nullPtr); + virtual ~_MediaTrackConstraints(); + + WE_INLINE _MediaTrackConstraintsType type()const { return m_eType; } + WE_INLINE bool isBool()const { return type() == _MediaTrackConstraintsTypeBoolean; } + WE_INLINE bool boolVal()const { return m_bValue; } + WE_INLINE const cpp11::shared_ptr<_MediaConstraints> mandatory()const { return m_mandatory; } + WE_INLINE const cpp11::shared_ptr<_MediaConstraints> optional()const { return m_optional; } + +private: +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + _MediaTrackConstraintsType m_eType; + bool m_bValue; // only if type is _MediaTrackConstraintsTypeBoolean + cpp11::shared_ptr<_MediaConstraints> m_mandatory; // only if type is _MediaTrackConstraintsTypeComposite + cpp11::shared_ptr<_MediaConstraints> m_optional; // only if type is _MediaTrackConstraintsTypeComposite +#if _MSC_VER +#pragma warning(pop) +#endif +}; + +#endif /* _WEBRTC_EVERYWHERE_COMMON_MEDIATRACKCONSTRAINT_H_ */ diff --git a/common/_NavigatorUserMedia.cc b/common/_NavigatorUserMedia.cc new file mode 100755 index 0000000..499ebbd --- /dev/null +++ b/common/_NavigatorUserMedia.cc @@ -0,0 +1,55 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#navigatorusermedia +#include "_NavigatorUserMedia.h" +#include "_MediaStream.h" +#include "_MediaStreamTrack.h" +#include "_MediaTrackConstraints.h" +#include "_MediaStreamConstraints.h" +#include "_Utils.h" +#include "_Debug.h" + +#include "talk/app/webrtc/videosourceinterface.h" +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/media/devices/devicemanager.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/logging.h" + +// void getUserMedia (MediaStreamConstraints? constraints, NavigatorUserMediaSuccessCallback successCallback, NavigatorUserMediaErrorCallback errorCallback); +void _NavigatorUserMedia::getUserMedia(const _MediaStreamConstraints* constraints/*= NULL*/, _NavigatorUserMediaSuccessCallback successCallback/*= nullPtr*/, _NavigatorUserMediaErrorCallback errorCallback /*= nullPtr*/) +{ +#define RAISE_ERR(e) { \ + WE_DEBUG_ERROR(e); \ + if (errorCallback) { \ + cpp11::shared_ptr<_NavigatorUserMediaError> err(new _NavigatorUserMediaError(e)); \ + errorCallback(err); \ + } \ + } + + cpp11::shared_ptr<_MediaStream> stream(new _MediaStream()); + if (!stream) { + RAISE_ERR("Failed to create media stream"); + return; + } + + bool bHaveAudio = !constraints || !constraints->audio() || !constraints->audio()->isBool() || constraints->audio()->boolVal(); + bool bHaveVideo = !constraints || !constraints->video() || !constraints->video()->isBool() || constraints->video()->boolVal(); + + if (bHaveAudio) { + _MediaStreamTrackAudio audio(NULL, constraints ? constraints->audio().get() : NULL); + if (audio.IsValid()) { + stream->addTrack(&audio); + } + } + if (bHaveVideo) { + _MediaStreamTrackVideo video(NULL, constraints ? constraints->video().get() : NULL); + if (video.IsValid()) { + stream->addTrack(&video); + } + } + + if (successCallback) { + successCallback(stream); + } +} + diff --git a/common/_NavigatorUserMedia.h b/common/_NavigatorUserMedia.h new file mode 100755 index 0000000..c99cedd --- /dev/null +++ b/common/_NavigatorUserMedia.h @@ -0,0 +1,19 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#navigatorusermedia +#ifndef _WEBRTC_EVERYWHERE_COMMON_NAVIGATORUSERMEDIA_H_ +#define _WEBRTC_EVERYWHERE_COMMON_NAVIGATORUSERMEDIA_H_ + +#include "_Config.h" +#include "_Common.h" + +class _Buffer; +class _MediaStreamConstraints; + +class WEBRTC_EVERYWHERE_API _NavigatorUserMedia +{ +public: + // void getUserMedia (MediaStreamConstraints? constraints, NavigatorUserMediaSuccessCallback successCallback, NavigatorUserMediaErrorCallback errorCallback); + static void getUserMedia(const _MediaStreamConstraints* constraints = NULL, _NavigatorUserMediaSuccessCallback successCallback = nullPtr, _NavigatorUserMediaErrorCallback errorCallback = nullPtr); +}; + +#endif /* _WEBRTC_EVERYWHERE_COMMON_NAVIGATORUSERMEDIA_H_ */ diff --git a/common/_PeerConnection.cc b/common/_PeerConnection.cc new file mode 100755 index 0000000..1d777b0 --- /dev/null +++ b/common/_PeerConnection.cc @@ -0,0 +1,810 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "_PeerConnection.h" +#include "_Buffer.h" +#include "_SessionDescription.h" +#include "_MediaStream.h" +#include "_MediaStreamTrack.h" +#include "_MediaTrackConstraints.h" +#include "_MediaStreamConstraints.h" +#include "_RTCIceCandidate.h" +#include "_utils.h" +#include "_Common.h" +#include "_Debug.h" + +#include "talk/app/webrtc/mediaconstraintsinterface.h" +#include "talk/base/json.h" +#include "talk/base/logging.h" + +// http://www.w3.org/TR/webrtc/#interface-definition + +// +// DummySetSessionDescriptionObserver +// +class DummySetSessionDescriptionObserver + : public webrtc::SetSessionDescriptionObserver { +public: + static DummySetSessionDescriptionObserver* Create(_VoidFunctionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr) { + return + new talk_base::RefCountedObject(successCallback, failureCallback); + } + virtual void OnSuccess() { + LOG(INFO) << __FUNCTION__; + if (m_successCallback) { + m_successCallback(); + } + } + virtual void OnFailure(const std::string& error) { + LOG(INFO) << __FUNCTION__ << " " << error; + cpp11::shared_ptr err(new std::string(error)); + if (m_failureCallback) { + m_failureCallback(err); + } + } + +protected: + DummySetSessionDescriptionObserver(_VoidFunctionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr) : m_successCallback(successCallback), m_failureCallback(failureCallback){} + ~DummySetSessionDescriptionObserver() + { + WE_DEBUG_INFO("~DummySetSessionDescriptionObserver"); + } +private: + _VoidFunctionCallback m_successCallback; + _RTCPeerConnectionErrorCallback m_failureCallback; +}; + +// +// DummyCreateSessionDescriptionObserver +// +class DummyCreateSessionDescriptionObserver + : public webrtc::CreateSessionDescriptionObserver { +public: + static DummyCreateSessionDescriptionObserver* Create(const _RTCPeerConnection* pc, _RTCSessionDescriptionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr) { + return + new talk_base::RefCountedObject(pc, successCallback, failureCallback); + } + virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc) { + LOG(INFO) << __FUNCTION__; + if (m_pc) { +#if 0 + const_cast<_RTCPeerConnection*>(m_pc)->setLocalDescription(desc); +#endif + } + if (m_successCallback) { + std::string sdp; + desc->ToString(&sdp); + cpp11::shared_ptr<_SessionDescription>_sdp(new _SessionDescription((const void*)sdp.c_str(), sdp.length(), (const void*)desc->type().c_str(), desc->type().length())); + m_successCallback(_sdp); + } + } + virtual void OnFailure(const std::string& error) { + LOG(INFO) << __FUNCTION__ << " " << error; + cpp11::shared_ptr err(new std::string(error)); + if (m_failureCallback) { + m_failureCallback(err); + } + } + +protected: + DummyCreateSessionDescriptionObserver(const _RTCPeerConnection* pc, _RTCSessionDescriptionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr) + : m_pc(pc) + , m_successCallback(successCallback) + , m_failureCallback(failureCallback){} + virtual ~DummyCreateSessionDescriptionObserver() + { + WE_DEBUG_INFO("~DummyCreateSessionDescriptionObserver"); + } +private: + const _RTCPeerConnection* m_pc; + _RTCSessionDescriptionCallback m_successCallback; + _RTCPeerConnectionErrorCallback m_failureCallback; +}; + + +// +// DummyStatsObserver +// +class DummyStatsObserver + : public webrtc::StatsObserver { +public: + static DummyStatsObserver* Create(_RTCStatsCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr) { + return + new talk_base::RefCountedObject(successCallback, failureCallback); + } + virtual void OnComplete(const std::vector& reports) { + LOG(INFO) << __FUNCTION__; + if (m_successCallback) { + cpp11::shared_ptr<_RTCStatsReport> _report(new _RTCStatsReport()); + if (_report) { + for (size_t i = 0; i < reports.size(); ++i) { + cpp11::shared_ptr<_RTCStats> stats(new _RTCStats()); + if (stats) { + stats->id = std::string(reports[i].id); + stats->type = std::string(reports[i].type); + stats->timestamp = reports[i].timestamp; + for (size_t j = 0; j < reports[i].values.size(); ++j) { + stats->names.insert(std::pair(reports[i].values[j].name, reports[i].values[j].value)); + } + _report->values.insert(std::pair >(stats->id, stats)); + } + } + m_successCallback(_report); + } + } + } +protected: + DummyStatsObserver(_RTCStatsCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr) { + m_successCallback = successCallback; + m_failureCallback = failureCallback; + } + ~DummyStatsObserver() { + WE_DEBUG_INFO("~DummyStatsObserver"); + } +private: + _RTCStatsCallback m_successCallback; + _RTCPeerConnectionErrorCallback m_failureCallback; +}; + +// +// _RTCPeerConnection +// + +_RTCPeerConnection::_RTCPeerConnection(const _PeerConnection* pcBase, const webrtc::PeerConnectionInterface::RTCConfiguration& configuration, const webrtc::MediaConstraintsInterface* constraints /*= NULL*/) + : m_bValid(false) + , m_pcBase(pcBase) +{ + m_peer_connection_factory = GetPeerConnectionFactory(); + if (!m_peer_connection_factory.get()) { + WE_DEBUG_ERROR("Failed to create factory"); + return; + } + + m_peer_connection = m_peer_connection_factory->CreatePeerConnection(configuration, + constraints, + NULL, + NULL, + this); + if (!m_peer_connection.get()) { + WE_DEBUG_ERROR("Failed to create peer connection"); + return; + } + + m_bValid = true; +} + +bool _RTCPeerConnection::createOffer(_RTCSessionDescriptionCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/, const webrtc::MediaConstraintsInterface* constraints /*= NULL*/) +{ + if (IsValid()) { + m_peer_connection->CreateOffer(DummyCreateSessionDescriptionObserver::Create(this, successCallback, failureCallback), constraints); + return true; + } + return false; +} + +bool _RTCPeerConnection::createAnswer(_RTCSessionDescriptionCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/, const webrtc::MediaConstraintsInterface* constraints /*= NULL*/) +{ + if (IsValid()) { + m_peer_connection->CreateAnswer(DummyCreateSessionDescriptionObserver::Create(this, successCallback, failureCallback), constraints); + return true; + } + return false; +} + +bool _RTCPeerConnection::setLocalDescription(webrtc::SessionDescriptionInterface* description, _VoidFunctionCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/) +{ + if (IsValid()) { + m_peer_connection->SetLocalDescription(DummySetSessionDescriptionObserver::Create(successCallback, failureCallback), description); + return true; + } + return false; +} + +const webrtc::SessionDescriptionInterface* _RTCPeerConnection::localDescription() +{ + if (IsValid()) { + return m_peer_connection->local_description(); + } + return NULL; +} + +bool _RTCPeerConnection::setRemoteDescription(webrtc::SessionDescriptionInterface* description, _VoidFunctionCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/) +{ + if (IsValid()) { + m_peer_connection->SetRemoteDescription(DummySetSessionDescriptionObserver::Create(successCallback, failureCallback), description); + return true; + } + return false; +} + +const webrtc::SessionDescriptionInterface* _RTCPeerConnection::remoteDescription() +{ + if (IsValid()) { + return m_peer_connection->remote_description(); + } + return NULL; +} + +const char* _RTCPeerConnection::signalingState() +{ + if (IsValid()) { + switch (m_peer_connection->signaling_state()) { + case webrtc::PeerConnectionInterface::kStable : return kSignalingStateStable; + case webrtc::PeerConnectionInterface::kHaveLocalOffer:return kSignalingStateHaveLocalOffer; + case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer: return kSignalingStateHaveLocalPrAnswer; + case webrtc::PeerConnectionInterface::kHaveRemoteOffer: return kSignalingStateHaveRemoteOffer; + case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer: return kSignalingStateHaveRemotePrAnswer; + case webrtc::PeerConnectionInterface::kClosed: return kSignalingStateClosed; + } + } + return kSignalingStateClosed; +} + +bool _RTCPeerConnection::updateIce(const webrtc::PeerConnectionInterface::RTCConfiguration& configuration, const webrtc::MediaConstraintsInterface* constraints /*= NULL*/) +{ + if (IsValid()) { + return m_peer_connection->UpdateIce(configuration.servers, constraints); + } + return false; +} + +bool _RTCPeerConnection::addIceCandidate(const webrtc::IceCandidateInterface* candidate, _VoidFunctionCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/) +{ + if (IsValid()) { + bool ret = m_peer_connection->AddIceCandidate(candidate); + if (ret) { + if (successCallback) { + successCallback(); + } + } + else { + if (failureCallback) { + failureCallback(cpp11::shared_ptr(new std::string("Internal error"))); + } + } + return ret; + } + if (failureCallback) { + failureCallback(cpp11::shared_ptr(new std::string("Peer connection not initialized yet"))); + } + return false; +} + +const char* _RTCPeerConnection::iceGatheringState() +{ + if (IsValid()) { + switch (m_peer_connection->ice_gathering_state()) { + case webrtc::PeerConnectionInterface::kIceGatheringNew: return kIceGatheringStateNew; + case webrtc::PeerConnectionInterface::kIceGatheringGathering: return kIceGatheringStateGathering; + case webrtc::PeerConnectionInterface::kIceGatheringComplete:return kIceGatheringStateComplete; + } + } + return kIceGatheringStateNew; +} + +const char* _RTCPeerConnection::iceConnectionState() +{ + if (IsValid()) { + switch (m_peer_connection->ice_connection_state()) { + case webrtc::PeerConnectionInterface::kIceConnectionNew: return kIceConnectionStateNew; + case webrtc::PeerConnectionInterface::kIceConnectionChecking: return kIceConnectionStatChecking; + case webrtc::PeerConnectionInterface::kIceConnectionConnected: return kIceConnectionStatConnected; + case webrtc::PeerConnectionInterface::kIceConnectionCompleted: return kIceConnectionStatCompleted; + case webrtc::PeerConnectionInterface::kIceConnectionFailed: return kIceConnectionStatFailed; + case webrtc::PeerConnectionInterface::kIceConnectionDisconnected: return kIceConnectionStatDisconnected; + case webrtc::PeerConnectionInterface::kIceConnectionClosed: return kIceConnectionStatClosed; + } + } + return kIceConnectionStateNew; +} + +talk_base::scoped_refptr _RTCPeerConnection::getLocalStreams() +{ + if (IsValid()) { + return m_peer_connection->local_streams(); + } + return NULL; +} + +talk_base::scoped_refptr _RTCPeerConnection::getRemoteStreams() +{ + if (IsValid()) { + return m_peer_connection->remote_streams(); + } + return NULL; +} + +webrtc::MediaStreamInterface* _RTCPeerConnection::getStreamById(std::string streamId) +{ + if (IsValid()) { + webrtc::MediaStreamInterface* stream = NULL; + talk_base::scoped_refptr streams; + if ((streams = m_peer_connection->local_streams()) && (stream = streams->find(streamId))) { + return stream; + } + if ((streams = m_peer_connection->remote_streams()) && (stream = streams->find(streamId))) { + return stream; + } + } + return NULL; +} + +bool _RTCPeerConnection::addStream(webrtc::MediaStreamInterface* stream, const webrtc::MediaConstraintsInterface* constraints) +{ + if (IsValid()) { + return m_peer_connection->AddStream(stream, constraints); + } + return false; +} + +bool _RTCPeerConnection::removeStream(webrtc::MediaStreamInterface* stream) +{ + if (IsValid()) { + m_peer_connection->RemoveStream(stream); + return true; + } + return false; +} + +bool _RTCPeerConnection::close() +{ + if (IsValid()) { + m_peer_connection->Close(); + return true; + } + return false; +} + +bool _RTCPeerConnection::getStats(webrtc::MediaStreamTrackInterface* selector /*= NULL*/, _RTCStatsCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/) +{ + if (IsValid()) { + return m_peer_connection->GetStats(DummyStatsObserver::Create(successCallback, failureCallback), selector, webrtc::PeerConnectionInterface::kStatsOutputLevelStandard); + } + return false; +} + +_RTCPeerConnection::~_RTCPeerConnection() +{ + m_peer_connection = NULL; + m_peer_connection_factory = NULL; + + WE_DEBUG_INFO("_RTCPeerConnection::~_RTCPeerConnection"); +} + + +//--- PeerConnectionObserver implementation ---// +void _RTCPeerConnection::OnError() +{ + WE_DEBUG_INFO("_RTCPeerConnection::OnError"); +} + +void _RTCPeerConnection::OnStateChange(webrtc::PeerConnectionObserver::StateType state_changed) +{ + WE_DEBUG_INFO("_RTCPeerConnection::OnStateChange"); + if (m_pcBase) { + if (state_changed == kSignalingState && m_pcBase->onsignalingstatechange) { + m_pcBase->onsignalingstatechange(); + } + else if (state_changed == kIceState && m_pcBase->oniceconnectionstatechange) { + m_pcBase->oniceconnectionstatechange(); + } + } +} + +void _RTCPeerConnection::OnAddStream(webrtc::MediaStreamInterface* stream) +{ + WE_DEBUG_INFO("_PeerConnection::OnAddStream"); + if (m_pcBase && m_pcBase->onaddstream && stream) { + cpp11::shared_ptr<_MediaStreamEvent>_e (new _MediaStreamEvent(cpp11::shared_ptr<_MediaStream>(new _MediaStream(stream)))); + m_pcBase->onaddstream(_e); + } +} + +void _RTCPeerConnection::OnRemoveStream(webrtc::MediaStreamInterface* stream) +{ + WE_DEBUG_INFO("_RTCPeerConnection::OnRemoveStream"); + if (m_pcBase && m_pcBase->onremovestream && stream) { + cpp11::shared_ptr<_MediaStreamEvent>_e (new _MediaStreamEvent(cpp11::shared_ptr<_MediaStream>(new _MediaStream(stream)))); + m_pcBase->onremovestream(_e); + } +} + +void _RTCPeerConnection::OnRenegotiationNeeded() +{ + WE_DEBUG_INFO("_RTCPeerConnection::OnRenegotiationNeeded"); + if (m_pcBase && m_pcBase->onnegotiationneeded) { + m_pcBase->onnegotiationneeded(); + } +} + +void _RTCPeerConnection::OnIceChange() +{ + WE_DEBUG_INFO("_RTCPeerConnection::OnIceChange"); + if (m_pcBase && m_pcBase->oniceconnectionstatechange) { + m_pcBase->oniceconnectionstatechange(); + } +} + +void _RTCPeerConnection::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) +{ + WE_DEBUG_INFO("_RTCPeerConnection::OnIceCandidate"); + + if (m_pcBase && m_pcBase->onicecandidate) { + if (candidate) { + std::string _str; + candidate->ToString(&_str); + cpp11::shared_ptr<_RTCIceCandidate>_candidate(new _RTCIceCandidate(_str.c_str(), candidate->sdp_mid().c_str(), candidate->sdp_mline_index())); + cpp11::shared_ptr<_RTCPeerConnectionIceEvent>_e(new _RTCPeerConnectionIceEvent(_candidate)); + m_pcBase->onicecandidate(_e); + } + else { + cpp11::shared_ptr<_RTCPeerConnectionIceEvent>_e(nullPtr); + m_pcBase->onicecandidate(_e); + } + } +} + +void _RTCPeerConnection::OnIceComplete() +{ + WE_DEBUG_INFO("_RTCPeerConnection::OnIceComplete"); + OnIceCandidate(NULL); // null candidate used as a hack to signal end of ICe gathering +} + + +// +// _PeerConnection +// + +#define CHECK_INITIALIZED() \ + if (!IsInitialized()) { \ + WE_DEBUG_ERROR("Not initialized"); \ + return false; \ + } + +_PeerConnection::_PeerConnection() +: m_bInitialized(false) +, m_peer_connection(NULL) +, m_sdp_local(nullPtr) +, m_sdp_remote(nullPtr) +{ + _Utils::Initialize(); +} + +_PeerConnection::~_PeerConnection() +{ + DeInit(); + + m_sdp_local = nullPtr; + m_sdp_remote = nullPtr; + + WE_DEBUG_INFO("_PeerConnection::~_PeerConnection"); +} + +// http://www.w3.org/TR/webrtc/#widl-ctor-RTCPeerConnection--RTCConfiguration-configuration-MediaConstraints-constraints +bool _PeerConnection::Init(const _RTCConfiguration* configuration /*= NULL*/, const _MediaConstraintsObj* constraints /*= NULL*/) +{ + if (IsInitialized()) { + WE_DEBUG_INFO("Already initialized"); + return true; + } + + webrtc::PeerConnectionInterface::RTCConfiguration _configuration/*(webrtc::PeerConnectionInterface::IceTransportsType::kAll)*/; + webrtc::PeerConnectionInterface::IceServers servers; + if (configuration) { + for (size_t i = 0; i < configuration->iceServers.size(); ++i) { + webrtc::PeerConnectionInterface::IceServer server; + server.uri = configuration->iceServers[i].uri; + server.password = configuration->iceServers[i].password; + server.username = configuration->iceServers[i].username; + _configuration.servers.push_back(server); + } + } + + talk_base::scoped_refptr<_RTCMediaConstraints> _constraints = BuildConstraints(constraints); + + // DTLS is required, enable it unless the end-user decided to disable it + std::string value; + if (!_constraints->GetMandatory().FindFirst(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, &value)) { + _constraints->AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, webrtc::MediaConstraintsInterface::kValueTrue); + } + + m_peer_connection = new talk_base::RefCountedObject<_RTCPeerConnection>(this, _configuration, _constraints); + if (!m_peer_connection.get() || !m_peer_connection->IsValid()) { + WE_DEBUG_ERROR("Failed to create peer connection"); + return false; + } + + m_bInitialized = true; + return true; +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-createOffer-void-RTCSessionDescriptionCallback-successCallback-RTCPeerConnectionErrorCallback-failureCallback-MediaConstraints-constraints +// void createOffer (RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional MediaConstraints constraints); +bool _PeerConnection::CreateOffer(_RTCSessionDescriptionCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/, const _MediaConstraintsObj* constraints /*= NULL*/) +{ + CHECK_INITIALIZED(); + return m_peer_connection->createOffer(successCallback, failureCallback, BuildConstraints(constraints)); +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-createAnswer-void-RTCSessionDescriptionCallback-successCallback-RTCPeerConnectionErrorCallback-failureCallback-MediaConstraints-constraints +// void createAnswer (RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional MediaConstraints constraints) +bool _PeerConnection::CreateAnswer(_RTCSessionDescriptionCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/, const _MediaConstraintsObj* constraints /*= NULL*/) +{ + CHECK_INITIALIZED(); + m_sdp_local = nullPtr; + return m_peer_connection->createAnswer(successCallback, failureCallback, BuildConstraints(constraints)); +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-setLocalDescription-void-RTCSessionDescription-description-VoidFunction-successCallback-RTCPeerConnectionErrorCallback-failureCallback +// void setLocalDescription (RTCSessionDescription description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback); +bool _PeerConnection::SetLocalDescription(const _SessionDescription* description, _VoidFunctionCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/) +{ + CHECK_INITIALIZED(); + if (!description) { + WE_DEBUG_ERROR("Invalid argument"); + return false; + } + + std::string type((const char*)description->getType()->getPtr(), description->getType()->getSize()); + std::string sdp((const char*)description->getSdp()->getPtr(), description->getSdp()->getSize()); + webrtc::SdpParseError err; + webrtc::SessionDescriptionInterface* _description = webrtc::CreateSessionDescription(type, sdp, &err); + if (!_description) { + if (failureCallback) { + failureCallback(cpp11::shared_ptr(new std::string(err.description))); + WE_DEBUG_ERROR("CreateSessionDescription eror: %s", err.description.c_str()); + } + return false; + } + bool ret = m_peer_connection->setLocalDescription(_description, successCallback, failureCallback); + if (ret) { + m_sdp_local = nullPtr; + _description = NULL; // now is owned by the peerconnection + } + if (_description) delete _description; + return ret; +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-localDescription +// readonly attribute RTCSessionDescription? localDescription; +cpp11::shared_ptr<_SessionDescription> _PeerConnection::LocalDescription() +{ + if (!IsInitialized()) { + WE_DEBUG_ERROR("Not initialized"); + return nullPtr; + } + if (!m_sdp_local) { + const webrtc::SessionDescriptionInterface* localDescription = m_peer_connection->localDescription(); + if (localDescription){ + std::string sdp; + localDescription->ToString(&sdp); + m_sdp_local = cpp11::shared_ptr<_SessionDescription>(new _SessionDescription(sdp.c_str(), sdp.length(), localDescription->type().c_str(), localDescription->type().length())); + } + } + return m_sdp_local; +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-setRemoteDescription-void-RTCSessionDescription-description-VoidFunction-successCallback-RTCPeerConnectionErrorCallback-failureCallback +// void setRemoteDescription(RTCSessionDescription description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback); +bool _PeerConnection::SetRemoteDescription(const _SessionDescription* description, _VoidFunctionCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/) +{ + CHECK_INITIALIZED(); + if (!description) { + WE_DEBUG_ERROR("Invalid argument"); + return false; + } + + std::string type((const char*)description->getType()->getPtr(), description->getType()->getSize()); + std::string sdp((const char*)description->getSdp()->getPtr(), description->getSdp()->getSize()); + webrtc::SdpParseError err; + webrtc::SessionDescriptionInterface* _description = webrtc::CreateSessionDescription(type, sdp, &err); + if (!_description) { + if (failureCallback) { + failureCallback(cpp11::shared_ptr(new std::string(err.description))); + WE_DEBUG_ERROR("CreateSessionDescription eror: %s", err.description.c_str()); + } + return false; + } + bool ret = m_peer_connection->setRemoteDescription(_description, successCallback, failureCallback); + if (ret) { + m_sdp_remote = nullPtr; + _description = NULL; // now is owned by the peerconnection + } + if (_description) delete _description; + return ret; +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-remoteDescription +// readonly attribute RTCSessionDescription? remoteDescription; +cpp11::shared_ptr<_SessionDescription> _PeerConnection::RemoteDescription() +{ + if (!IsInitialized()) { + WE_DEBUG_ERROR("Not initialized"); + return nullPtr; + } + if (!m_sdp_remote) { + const webrtc::SessionDescriptionInterface* remoteDescription = m_peer_connection->remoteDescription(); + if (remoteDescription){ + std::string sdp; + remoteDescription->ToString(&sdp); + m_sdp_remote = cpp11::shared_ptr<_SessionDescription>(new _SessionDescription(sdp.c_str(), sdp.length(), remoteDescription->type().c_str(), remoteDescription->type().length())); + } + } + return m_sdp_remote; +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-signalingState +// readonly attribute RTCSignalingState signalingState; +const char* _PeerConnection::SignalingState() +{ + if (IsInitialized()) { + return m_peer_connection->signalingState(); + } + return kSignalingStateClosed; +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-updateIce-void-RTCConfiguration-configuration-MediaConstraints-constraints +// void updateIce (optional RTCConfiguration configuration, optional MediaConstraints constraints); +bool _PeerConnection::UpdateIce(const _RTCConfiguration* configuration /*= NULL*/, const _MediaConstraintsObj* constraints /*= NULL*/) +{ + CHECK_INITIALIZED(); + webrtc::PeerConnectionInterface::RTCConfiguration _configuration/*(webrtc::PeerConnectionInterface::IceTransportsType::kAll)*/; + webrtc::PeerConnectionInterface::IceServers servers; + if (configuration) { + for (size_t i = 0; i < configuration->iceServers.size(); ++i) { + webrtc::PeerConnectionInterface::IceServer server; + server.uri = configuration->iceServers[i].uri; + server.password = configuration->iceServers[i].password; + server.username = configuration->iceServers[i].username; + _configuration.servers.push_back(server); + } + } + + return m_peer_connection->updateIce(_configuration, BuildConstraints(constraints)); +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-addIceCandidate-void-RTCIceCandidate-candidate-VoidFunction-successCallback-RTCPeerConnectionErrorCallback-failureCallback +// void addIceCandidate (RTCIceCandidate candidate, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback); +bool _PeerConnection::AddIceCandidate(const _RTCIceCandidate* candidate, _VoidFunctionCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/) +{ + CHECK_INITIALIZED(); + if (!candidate) { + WE_DEBUG_ERROR("Invalid argument"); + return false; + } + + webrtc::SdpParseError error; + webrtc::IceCandidateInterface* _candidate = webrtc::CreateIceCandidate(candidate->sdpMid(), + candidate->sdpMLineIndex(), + candidate->candidate(), + &error); + if (!_candidate) { + if (failureCallback) { + failureCallback(cpp11::shared_ptr(new std::string(error.description))); + } + return false; + } + bool ret = m_peer_connection->addIceCandidate(_candidate, successCallback, failureCallback); + if (!ret) { + SafeDelete(&_candidate); + } + return ret; +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-iceGatheringState +// readonly attribute RTCIceGatheringState iceGatheringState; +const char* _PeerConnection::IceGatheringState() +{ + if (!IsInitialized()) { + return kIceGatheringStateNew; + } + return m_peer_connection->iceGatheringState(); +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-iceConnectionState +// readonly attribute RTCIceConnectionState iceConnectionState; +const char* _PeerConnection::IceConnectionState() +{ + if (!IsInitialized()) { + return kIceConnectionStateNew; + } + return m_peer_connection->iceConnectionState(); +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-getLocalStreams-sequence-MediaStream +// sequence getLocalStreams(); +cpp11::shared_ptr<_Sequence<_MediaStream> > _PeerConnection::GetLocalStreams() +{ + cpp11::shared_ptr<_Sequence<_MediaStream> > seq(new _Sequence<_MediaStream>()); + + if (IsInitialized()) { + talk_base::scoped_refptr _streams = m_peer_connection->getLocalStreams(); + if (_streams) { + for (size_t i = 0; i < _streams->count(); ++i){ + webrtc::MediaStreamInterface* _stream = _streams->at(i); + if (_stream) { + seq->Add(cpp11::shared_ptr<_MediaStream>(new _MediaStream(_stream))); + } + } + } + } + + return seq; +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-getRemoteStreams-sequence-MediaStream +// sequence getRemoteStreams(); +cpp11::shared_ptr<_Sequence<_MediaStream> > _PeerConnection::GetRemoteStreams() +{ + cpp11::shared_ptr<_Sequence<_MediaStream> > seq(new _Sequence<_MediaStream>()); + + if (IsInitialized()) { + talk_base::scoped_refptr _streams = m_peer_connection->getRemoteStreams(); + if (_streams) { + for (size_t i = 0; i < _streams->count(); ++i){ + webrtc::MediaStreamInterface* _stream = _streams->at(i); + if (_stream) { + seq->Add(cpp11::shared_ptr<_MediaStream>(new _MediaStream(_stream))); + } + } + } + } + + return seq; +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-getStreamById-MediaStream-DOMString-streamId +// MediaStream? getStreamById (DOMString streamId); +cpp11::shared_ptr<_MediaStream> _PeerConnection::GetStreamById(const char* streamId) +{ + if (IsInitialized() && streamId) { + webrtc::MediaStreamInterface* stream = m_peer_connection->getStreamById(std::string(streamId)); + if (stream) { + return cpp11::shared_ptr<_MediaStream>(new _MediaStream(stream)); + } + } + return nullPtr; +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-addStream-void-MediaStream-stream-MediaConstraints-constraints +// void addStream (MediaStream stream, optional MediaConstraints constraints); +bool _PeerConnection::AddStream(_MediaStream* stream, const _MediaConstraintsObj* constraints /*= NULL*/) +{ + CHECK_INITIALIZED(); + return m_peer_connection->addStream(BuildMediaStream(stream), BuildConstraints(constraints)); +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-removeStream-void-MediaStream-stream +// void removeStream (MediaStream stream); +bool _PeerConnection::RemoveStream(_MediaStream* stream) +{ + CHECK_INITIALIZED(); + if (!stream) { + WE_DEBUG_ERROR("Invalid argument"); + return false; + } + return m_peer_connection->removeStream(dynamic_cast((webrtc::MediaStreamInterface*)stream->GetWrappedStream())); +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-close-void +// void close (); +bool _PeerConnection::Close() +{ + CHECK_INITIALIZED(); + return m_peer_connection->close(); +} + +bool _PeerConnection::GetStats(_MediaStreamTrackBase* selector /*= NULL*/, _RTCStatsCallback successCallback /*= nullPtr*/, _RTCPeerConnectionErrorCallback failureCallback /*= nullPtr*/) +{ + CHECK_INITIALIZED(); + return m_peer_connection->getStats(selector ? selector->_track() : NULL, successCallback, failureCallback); +} + +// http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-getStats-void-MediaStreamTrack-selector-RTCStatsCallback-successCallback-RTCPeerConnectionErrorCallback-failureCallback +// void getStats (MediaStreamTrack? selector, RTCStatsCallback successCallback, RTCPeerConnectionErrorCallback failureCallback); + +bool _PeerConnection::DeInit() +{ + m_peer_connection = NULL; + + return true; +} + diff --git a/common/_PeerConnection.h b/common/_PeerConnection.h new file mode 100755 index 0000000..eaaa6fd --- /dev/null +++ b/common/_PeerConnection.h @@ -0,0 +1,148 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_COMMON_PEERCONNECTION_H_ +#define _WEBRTC_EVERYWHERE_COMMON_PEERCONNECTION_H_ + +#include "_Config.h" +#include "_Common.h" + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/base/scoped_ptr.h" + +class _Buffer; +class _MediaStream; +class _PeerConnection; +class _SessionDescription; +class _MediaStreamTrackBase; + +namespace webrtc { +class VideoCaptureModule; +} // namespace webrtc + +namespace cricket { +class VideoRenderer; +} // namespace cricket + +// +// _RTCPeerConnection +// +class _RTCPeerConnection + : public webrtc::PeerConnectionObserver + , public talk_base::RefCountInterface +{ +public: + _RTCPeerConnection(const _PeerConnection* pcBase, const webrtc::PeerConnectionInterface::RTCConfiguration& configuration, const webrtc::MediaConstraintsInterface* constraints = NULL); + bool IsValid() { return m_bValid; } + + bool createOffer(_RTCSessionDescriptionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr, const webrtc::MediaConstraintsInterface* constraints = NULL); + bool createAnswer(_RTCSessionDescriptionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr, const webrtc::MediaConstraintsInterface* constraints = NULL); + bool setLocalDescription(webrtc::SessionDescriptionInterface* description, _VoidFunctionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr); + const webrtc::SessionDescriptionInterface* localDescription(); + bool setRemoteDescription(webrtc::SessionDescriptionInterface* description, _VoidFunctionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr); + const webrtc::SessionDescriptionInterface* remoteDescription(); + const char* signalingState(); + bool updateIce(const webrtc::PeerConnectionInterface::RTCConfiguration& configuration, const webrtc::MediaConstraintsInterface* constraints = NULL); + bool addIceCandidate(const webrtc::IceCandidateInterface* candidate, _VoidFunctionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr); + const char* iceGatheringState(); + const char* iceConnectionState(); + talk_base::scoped_refptr getLocalStreams(); + talk_base::scoped_refptr getRemoteStreams(); + webrtc::MediaStreamInterface* getStreamById(std::string streamId); + bool addStream(webrtc::MediaStreamInterface* stream, const webrtc::MediaConstraintsInterface* constraints); + bool removeStream(webrtc::MediaStreamInterface* stream); + bool close(); + bool getStats(webrtc::MediaStreamTrackInterface* selector = NULL, _RTCStatsCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr); + +protected: + virtual ~_RTCPeerConnection(); + + // + // PeerConnectionObserver implementation. + // + virtual void OnError(); + virtual void OnStateChange(webrtc::PeerConnectionObserver::StateType state_changed); + virtual void OnAddStream(webrtc::MediaStreamInterface* stream); + virtual void OnRemoveStream(webrtc::MediaStreamInterface* stream); + virtual void OnRenegotiationNeeded(); + virtual void OnIceChange(); + virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate); + virtual void OnIceComplete(); + +private: + talk_base::scoped_refptr m_peer_connection; + talk_base::scoped_refptr m_peer_connection_factory; + const _PeerConnection* m_pcBase; + + bool m_bValid; +}; + +// +// _PeerConnection +// +class WEBRTC_EVERYWHERE_API _PeerConnection +{ + friend class _RTCPeerConnection; +public: + _PeerConnection(); + virtual ~_PeerConnection(); + + bool Init(const _RTCConfiguration* configuration = NULL, const _MediaConstraintsObj* constraints = NULL); + bool IsInitialized() { return m_bInitialized; } + + bool CreateOffer(_RTCSessionDescriptionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr, const _MediaConstraintsObj* constraints = NULL); + bool CreateAnswer(_RTCSessionDescriptionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr, const _MediaConstraintsObj* constraints = NULL); + bool SetLocalDescription(const _SessionDescription* description, _VoidFunctionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr); + cpp11::shared_ptr<_SessionDescription> LocalDescription(); + bool SetRemoteDescription(const _SessionDescription* description, _VoidFunctionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr); + cpp11::shared_ptr<_SessionDescription> RemoteDescription(); + const char* SignalingState(); + bool UpdateIce(const _RTCConfiguration* configuration = NULL, const _MediaConstraintsObj* constraints = NULL); + bool AddIceCandidate(const _RTCIceCandidate* candidate, _VoidFunctionCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr); + const char* IceGatheringState(); + const char* IceConnectionState(); + cpp11::shared_ptr<_Sequence<_MediaStream> > GetLocalStreams(); + cpp11::shared_ptr<_Sequence<_MediaStream> > GetRemoteStreams(); + cpp11::shared_ptr<_MediaStream> GetStreamById(const char* streamId); + bool AddStream(_MediaStream* stream, const _MediaConstraintsObj* constraints = NULL); + bool RemoveStream(_MediaStream* stream); + bool Close(); + bool GetStats(_MediaStreamTrackBase* selector = NULL, _RTCStatsCallback successCallback = nullPtr, _RTCPeerConnectionErrorCallback failureCallback = nullPtr); + + + // callbacks + WE_INLINE void SetCallback_onnegotiationneeded(_onnegotiationneededCallback _onnegotiationneeded) { onnegotiationneeded = _onnegotiationneeded; } + WE_INLINE void SetCallback_onicecandidate(_onicecandidateCallback _onicecandidate) { onicecandidate = _onicecandidate; } + WE_INLINE void SetCallback_onsignalingstatechange(_onsignalingstatechangeCallback _onsignalingstatechange) { onsignalingstatechange = _onsignalingstatechange; } + WE_INLINE void SetCallback_onaddstream(_onaddstreamCallback _onaddstream) { onaddstream = _onaddstream; } + WE_INLINE void SetCallback_onremovestream(_onremovestreamCallback _onremovestream) { onremovestream = _onremovestream; } + WE_INLINE void SetCallback_oniceconnectionstatechange(_oniceconnectionstatechangeCallback _oniceconnectionstatechange) { oniceconnectionstatechange = _oniceconnectionstatechange; } + +private: + bool DeInit(); + +private: +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + talk_base::scoped_refptr<_RTCPeerConnection> m_peer_connection; + cpp11::shared_ptr<_SessionDescription> m_sdp_local; + cpp11::shared_ptr<_SessionDescription> m_sdp_remote; + bool m_bInitialized; + + // callbacks + _onnegotiationneededCallback onnegotiationneeded; + _onicecandidateCallback onicecandidate; + _onsignalingstatechangeCallback onsignalingstatechange; + _onaddstreamCallback onaddstream; + _onremovestreamCallback onremovestream; + _oniceconnectionstatechangeCallback oniceconnectionstatechange; + +#if _MSC_VER +#pragma warning(pop) +#endif +}; + + + +#endif /* _WEBRTC_EVERYWHERE_COMMON_PEERCONNECTION_H_ */ diff --git a/common/_RTCDisplay.cc b/common/_RTCDisplay.cc new file mode 100755 index 0000000..9d67169 --- /dev/null +++ b/common/_RTCDisplay.cc @@ -0,0 +1,420 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "_RTCDisplay.h" +#include "_Debug.h" + +#include "talk/media/base/videocommon.h" +#include "talk/media/base/videoframe.h" + +#include + +#if WE_UNDER_WINDOWS +#include +#endif + + +// +// _VideoRenderer +// +_VideoRenderer::_VideoRenderer(int width, int height, cpp11::function fnOnStartVideoRenderer, webrtc::VideoTrackInterface* track_to_render) + : m_fnOnStartVideoRenderer(fnOnStartVideoRenderer) +#if WE_UNDER_WINDOWS + , m_Hwnd(NULL) +#elif WE_UNDER_APPLE + , m_layer(NULL) + , m_context(NULL) + , m_context_buff(NULL) + , m_context_buff_size(0) + , m_group(dispatch_group_create()) + +#endif + , m_cs(NULL) + , m_width(width) + , m_height(height) +{ + m_rendered_track = track_to_render; + m_cs = webrtc::CriticalSectionWrapper::CreateCriticalSection(); +#if WE_UNDER_WINDOWS + ZeroMemory(&m_bmi, sizeof(m_bmi)); + m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + m_bmi.bmiHeader.biPlanes = 1; + m_bmi.bmiHeader.biBitCount = 32; + m_bmi.bmiHeader.biCompression = BI_RGB; + m_bmi.bmiHeader.biWidth = width; + m_bmi.bmiHeader.biHeight = -height; + m_bmi.bmiHeader.biSizeImage = width * height * + (m_bmi.bmiHeader.biBitCount >> 3); +#elif WE_UNDER_APPLE +#endif + m_rendered_track->AddRenderer(this); +} + +_VideoRenderer::~_VideoRenderer() +{ + if (m_rendered_track) { + m_rendered_track->RemoveRenderer(this); + } +#if WE_UNDER_APPLE + // wait until async video rendering finish + dispatch_group_wait(m_group, DISPATCH_TIME_FOREVER); +#endif + + { + _AutoLock<_VideoRenderer> lock(this); + + m_rendered_track = NULL; + m_image.reset(); + +#if WE_UNDER_WINDOWS + +#elif WE_UNDER_APPLE + if (m_layer) { + m_layer.contents = NULL; + [m_layer release], m_layer = NULL; + } + if (m_context) { + CGContextRelease(m_context); + m_context = NULL; + } + if (m_context_buff) { + free(m_context_buff), m_context_buff = NULL; + } + m_context_buff_size = 0; + dispatch_release(m_group); +#endif + } // ~lock + + if (m_cs) { + delete m_cs; + } +} + +#if WE_UNDER_WINDOWS +void _VideoRenderer::SetHwnd(HWND hwnd) +{ + _AutoLock<_VideoRenderer> lock(this); + + m_Hwnd = hwnd; +} + +HWND _VideoRenderer::GetHwnd() +{ + _AutoLock<_VideoRenderer> lock(this); + + return m_Hwnd; +} +#elif WE_UNDER_APPLE +void _VideoRenderer::SetLayer(CALayer *layer) +{ + _AutoLock<_VideoRenderer> lock(this); + + if (m_layer) { + m_layer.contents = NULL; + [m_layer release], m_layer = NULL; + } + if (layer) { + m_layer = [layer retain]; + } +} + +CALayer *_VideoRenderer::GetLayer() +{ + _AutoLock<_VideoRenderer> lock(this); + + return m_layer; +} +#endif + +// On Windows, must be called inside OnPaint() +bool _VideoRenderer::PaintFrame() +{ + _AutoLock<_VideoRenderer> lock(this); + +#if WE_UNDER_WINDOWS + const uint8* image = m_image.get(); + if (m_Hwnd && image) { + PAINTSTRUCT ps; + HDC hdc; + if (!(hdc = ::BeginPaint(m_Hwnd, &ps))) { + return false; + } + + RECT rc; + if (!::GetClientRect(m_Hwnd, &rc)) { + ::EndPaint(m_Hwnd, &ps); + return false; + } + +#if 1 + int height = abs(m_bmi.bmiHeader.biHeight); + int width = m_bmi.bmiHeader.biWidth; + + HDC dc_mem = ::CreateCompatibleDC(ps.hdc); + ::SetStretchBltMode(dc_mem, HALFTONE); + + // Set the map mode so that the ratio will be maintained for us. + HDC all_dc[] = { ps.hdc, dc_mem }; + for (int i = 0; i < ARRAY_SIZE(all_dc); ++i) { + SetMapMode(all_dc[i], MM_ISOTROPIC); + SetWindowExtEx(all_dc[i], width, height, NULL); + SetViewportExtEx(all_dc[i], rc.right, rc.bottom, NULL); + } + + HBITMAP bmp_mem = ::CreateCompatibleBitmap(ps.hdc, rc.right, rc.bottom); + HGDIOBJ bmp_old = ::SelectObject(dc_mem, bmp_mem); + + POINT logical_area = { rc.right, rc.bottom }; + DPtoLP(ps.hdc, &logical_area, 1); + + HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0)); + RECT logical_rect = { 0, 0, logical_area.x, logical_area.y }; + ::FillRect(dc_mem, &logical_rect, brush); + ::DeleteObject(brush); + + int x = (logical_area.x / 2) - (width / 2); + int y = (logical_area.y / 2) - (height / 2); + + StretchDIBits(dc_mem, x, y, width, height, + 0, 0, width, height, image, &m_bmi, DIB_RGB_COLORS, SRCCOPY); + + BitBlt(ps.hdc, 0, 0, logical_area.x, logical_area.y, + dc_mem, 0, 0, SRCCOPY); + + // Cleanup. + ::SelectObject(dc_mem, bmp_old); + ::DeleteObject(bmp_mem); + ::DeleteDC(dc_mem); +#else + ::StretchDIBits(hdc, 0, 0, (rc.right - rc.left), (rc.bottom - rc.top), + 0, 0, m_bmi.bmiHeader.biWidth, abs(m_bmi.bmiHeader.biHeight), image, &m_bmi, DIB_RGB_COLORS, SRCCOPY); +#endif + + ::EndPaint(m_Hwnd, &ps); + + return true; + } +#else + +#endif + + return false; +} + +int _VideoRenderer::GetVideoWidth() +{ + _AutoLock<_VideoRenderer> lock(this); + + return m_width; +} + +int _VideoRenderer::GetVideoHeight() +{ + _AutoLock<_VideoRenderer> lock(this); + + return m_height; +} + + + +size_t _VideoRenderer::CopyFromFrame(void* bufferPtr, size_t bufferSize) +{ + if (bufferPtr && bufferSize) { + _AutoLock<_VideoRenderer> lock(this); + size_t sizeToCopy = std::min((int)bufferSize, (m_width * m_height * 4)); + const uint8* image = m_image.get(); + if (image) { + memcpy(bufferPtr, image, sizeToCopy); + return sizeToCopy; + } + } + return 0; +} + +// VideoRendererInterface implementation +void _VideoRenderer::SetSize(int width, int height) +{ + _AutoLock<_VideoRenderer> lock(this); + + m_width = width; + m_height = height; + +#if WE_UNDER_WINDOWS + m_bmi.bmiHeader.biWidth = width; + m_bmi.bmiHeader.biHeight = -height; + m_bmi.bmiHeader.biSizeImage = width * height * + (m_bmi.bmiHeader.biBitCount >> 3); + m_image.reset(new uint8[m_bmi.bmiHeader.biSizeImage]); +#elif WE_UNDER_APPLE + if (m_context) { + CGContextRelease(m_context); + m_context = NULL; + } + m_context_buff_size = (m_width * m_height) << 2; + m_context_buff = realloc(m_context_buff, m_context_buff_size); + if (!m_context_buff) { + WE_DEBUG_ERROR("failed to allocate buffer with size = %d", m_context_buff_size); + m_context_buff_size = 0; + return; + } + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + m_context = CGBitmapContextCreate(m_context_buff, m_width, m_height, 8, m_width * 4, colorSpace, + kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); + CGColorSpaceRelease(colorSpace); + if (!m_context) { + WE_DEBUG_ERROR("failed to create RGB32 context"); + return; // return and do not signal "video started" event + } + else { + m_image.reset(new uint8[m_context_buff_size]); + CGContextSetInterpolationQuality(m_context, kCGInterpolationMedium); + CGContextSetShouldAntialias(m_context, true); + } +#endif + + if (m_fnOnStartVideoRenderer) { + m_fnOnStartVideoRenderer(); + } +} + +// VideoRendererInterface implementation +void _VideoRenderer::RenderFrame(const cricket::VideoFrame* frame) +{ + if (!frame) { + return; + } + + _AutoLock<_VideoRenderer> lock(this); + + if (!m_image.get()) { + return; + } + +#if WE_UNDER_WINDOWS + frame->ConvertToRgbBuffer(cricket::FOURCC_ARGB, + m_image.get(), + m_bmi.bmiHeader.biSizeImage, + m_bmi.bmiHeader.biWidth * + m_bmi.bmiHeader.biBitCount / 8); + + if (m_Hwnd) { + InvalidateRect(m_Hwnd, NULL, FALSE); + } +#elif WE_UNDER_APPLE + if (m_context_buff && m_context && m_layer) { + frame->ConvertToRgbBuffer(cricket::FOURCC_ARGB, m_image.get(), m_context_buff_size, m_width * 4); + memcpy(m_context_buff, m_image.get(), m_context_buff_size); + + dispatch_group_enter(m_group); + dispatch_group_async(m_group, dispatch_get_main_queue(), ^{ + _AutoLock<_VideoRenderer> lock(this); + if (m_context_buff && m_context && m_layer) { + CGImageRef image = CGBitmapContextCreateImage(m_context); + m_layer.contentsGravity = kCAGravityResizeAspect; + m_layer.contents = (id)image; + CGImageRelease(image); + } + dispatch_group_leave(m_group); + }); + } + +#endif +} + + +// +// _RTCDisplay +// + +_RTCDisplay::_RTCDisplay() +{ + m_cs = webrtc::CriticalSectionWrapper::CreateCriticalSection(); +} + +_RTCDisplay::~_RTCDisplay() +{ + StopVideoRenderer(); + + if (m_cs) { + delete m_cs, m_cs = NULL; + } +} + +void _RTCDisplay::StartVideoRenderer(VideoTrackInterfacePtr video) +{ + _AutoLock<_RTCDisplay> lock(this); + if (!video) { + StopVideoRenderer(); + return; + } + + webrtc::VideoTrackInterface* _v = dynamic_cast((webrtc::VideoTrackInterface*)video); + if (_v) { + _VideoRenderer* _video = new _VideoRenderer(1, 1, cpp11::bind(&_RTCDisplay::OnStartVideoRenderer, this), _v); + if (_video) { +#if WE_UNDER_WINDOWS + _video->SetHwnd(Handle()); + SetWindowLongPtr(_video->GetHwnd(), GWLP_USERDATA, reinterpret_cast(this)); +#elif WE_UNDER_APPLE + _video->SetLayer(Layer()); +#endif + m_renderer.reset(_video); + } + } +} + +void _RTCDisplay::StopVideoRenderer() +{ + _AutoLock<_RTCDisplay> lock(this); + +#if WE_UNDER_WINDOWS + if (m_renderer) { + SetWindowLongPtr(m_renderer->GetHwnd(), GWLP_USERDATA, NULL); + } +#endif + + m_renderer.reset(); + OnStopVideoRenderer(); +} + + +// On Windows, must be called inside OnPaint() +bool _RTCDisplay::PaintFrame() +{ + _AutoLock<_RTCDisplay> lock(this); + + bool ret = false; + + if (m_renderer.get()) { + ret = m_renderer->PaintFrame(); + } + + return ret; +} + +int _RTCDisplay::GetVideoWidth() +{ + if (m_renderer.get()) { + return m_renderer->GetVideoWidth(); + } + return -1; +} + +int _RTCDisplay::GetVideoHeight() +{ + _AutoLock<_RTCDisplay> lock(this); + + if (m_renderer.get()) { + return m_renderer->GetVideoHeight(); + } + return -1; +} + +size_t _RTCDisplay::CopyFromFrame(void* bufferPtr, size_t bufferSize) +{ + _AutoLock<_RTCDisplay> lock(this); + + if (m_renderer.get()) { + return m_renderer->CopyFromFrame(bufferPtr, bufferSize); + } + return 0; +} \ No newline at end of file diff --git a/common/_RTCDisplay.h b/common/_RTCDisplay.h new file mode 100755 index 0000000..9130be7 --- /dev/null +++ b/common/_RTCDisplay.h @@ -0,0 +1,104 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_COMMON_RTCDISPLAY_H_ +#define _WEBRTC_EVERYWHERE_COMMON_RTCDISPLAY_H_ + +#include "_Config.h" +#include "_Common.h" + +#include "talk/media/base/videorenderer.h" +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" +#if WE_UNDER_APPLE +#import +#import +#import +#endif + +class _VideoRenderer : public webrtc::VideoRendererInterface +{ +public: + _VideoRenderer(int width, int height, cpp11::function fnOnStartVideoRenderer, webrtc::VideoTrackInterface* track_to_render); + virtual ~_VideoRenderer(); + + void Enter() { m_cs->Enter(); } + void Leave() { m_cs->Leave(); } + +#if WE_UNDER_WINDOWS + void SetHwnd(HWND hwnd); + HWND GetHwnd(); +#elif WE_UNDER_APPLE + void SetLayer(CALayer *layer); + CALayer *GetLayer(); +#endif + bool PaintFrame(); + int GetVideoWidth(); + int GetVideoHeight(); + size_t CopyFromFrame(void* bufferPtr, size_t bufferSize); + + // VideoRendererInterface implementation + virtual void SetSize(int width, int height); + virtual void RenderFrame(const cricket::VideoFrame* frame); + +private: + enum { + SET_SIZE, + RENDER_FRAME, + }; + +#if WE_UNDER_WINDOWS + HWND m_Hwnd; + BITMAPINFO m_bmi; +#elif WE_UNDER_APPLE + CALayer *m_layer; + CGContextRef m_context; + void* m_context_buff; + int m_context_buff_size; + dispatch_group_t m_group; +#endif + int m_width; + int m_height; + cpp11::function m_fnOnStartVideoRenderer; + webrtc::CriticalSectionWrapper *m_cs; + talk_base::scoped_ptr m_image; + talk_base::scoped_refptr m_rendered_track; +}; + +class WEBRTC_EVERYWHERE_API _RTCDisplay +{ +protected: + _RTCDisplay(); +public: + virtual ~_RTCDisplay(); + + void Enter() { m_cs->Enter(); } + void Leave() { m_cs->Leave(); } + + virtual void OnStartVideoRenderer() {}; + virtual void OnStopVideoRenderer() {}; + + void StartVideoRenderer(VideoTrackInterfacePtr video); + void StopVideoRenderer(); + bool PaintFrame(); + + int GetVideoWidth(); + int GetVideoHeight(); + size_t CopyFromFrame(void* bufferPtr, size_t bufferSize); + +#if WE_UNDER_WINDOWS + virtual HWND Handle() = 0; +#elif WE_UNDER_APPLE + virtual CALayer *Layer() = 0; +#endif + +private: +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + talk_base::scoped_ptr<_VideoRenderer> m_renderer; + webrtc::CriticalSectionWrapper *m_cs; +#if _MSC_VER +#pragma warning(pop) +#endif +}; + +#endif /* _WEBRTC_EVERYWHERE_COMMON_RTCDISPLAY_H_ */ \ No newline at end of file diff --git a/common/_RTCIceCandidate.cc b/common/_RTCIceCandidate.cc new file mode 100755 index 0000000..09e2ae1 --- /dev/null +++ b/common/_RTCIceCandidate.cc @@ -0,0 +1,17 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/webrtc/#idl-def-RTCIceCandidate +#include "_RTCIceCandidate.h" +#include "_Debug.h" + +_RTCIceCandidate::_RTCIceCandidate(const char* candidate /*= ""*/, const char* sdpMid /*= ""*/, unsigned short sdpMLineIndex /*= 0*/) + : m_candidate(candidate) + , m_sdpMid(sdpMid) + , m_sdpMLineIndex(sdpMLineIndex) +{ + +} + +_RTCIceCandidate::~_RTCIceCandidate() +{ + WE_DEBUG_INFO("_RTCIceCandidate::~_RTCIceCandidate"); +} diff --git a/common/_RTCIceCandidate.h b/common/_RTCIceCandidate.h new file mode 100755 index 0000000..4feb60a --- /dev/null +++ b/common/_RTCIceCandidate.h @@ -0,0 +1,32 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/webrtc/#idl-def-RTCIceCandidate +#ifndef _WEBRTC_EVERYWHERE_COMMON_RTCICECANDIDATE_H_ +#define _WEBRTC_EVERYWHERE_COMMON_RTCICECANDIDATE_H_ + +#include "_Config.h" + +class WEBRTC_EVERYWHERE_API _RTCIceCandidate +{ +public: + _RTCIceCandidate(const char* candidate = "", const char* sdpMid = "", unsigned short sdpMLineIndex = 0); + virtual ~_RTCIceCandidate(); + + // RTCIceCandidate + const char* candidate() const { return m_candidate.c_str(); } + const char* sdpMid() const { return m_sdpMid.c_str(); } + unsigned short sdpMLineIndex()const { return m_sdpMLineIndex; } + +private: +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + std::string m_candidate; + std::string m_sdpMid; + unsigned short m_sdpMLineIndex; +#if _MSC_VER +#pragma warning(pop) +#endif +}; + +#endif /* _WEBRTC_EVERYWHERE_COMMON_RTCICECANDIDATE_H_ */ diff --git a/common/_RTCMediaConstraints.cc b/common/_RTCMediaConstraints.cc new file mode 100755 index 0000000..37e420a --- /dev/null +++ b/common/_RTCMediaConstraints.cc @@ -0,0 +1,38 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "_RTCMediaConstraints.h" + +_RTCMediaConstraints::_RTCMediaConstraints() +{ + +} + +_RTCMediaConstraints::_RTCMediaConstraints(const Constraints& mandatory, const Constraints& optional) + : m_mandatory(mandatory) + , m_optional(optional) +{ + +} +_RTCMediaConstraints::~_RTCMediaConstraints() +{ + +} + +void _RTCMediaConstraints::AddOptional(const std::string& key, const std::string& value) +{ + m_optional.push_back(webrtc::MediaConstraintsInterface::Constraint(key, value)); +} + +bool _RTCMediaConstraints::AddMandatory(const std::string& key, const std::string& value, bool override_if_exists /*= true*/) { + for (webrtc::MediaConstraintsInterface::Constraints::iterator iter = m_mandatory.begin(); + iter != m_mandatory.end(); + ++iter) { + if (iter->key == key) { + if (override_if_exists) { + iter->value = value; + } + return override_if_exists; + } + } + m_mandatory.push_back(webrtc::MediaConstraintsInterface::Constraint(key, value)); + return true; +} diff --git a/common/_RTCMediaConstraints.h b/common/_RTCMediaConstraints.h new file mode 100755 index 0000000..437063c --- /dev/null +++ b/common/_RTCMediaConstraints.h @@ -0,0 +1,31 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_COMMON_RTCMEDIACONSTRAINTS_H_ +#define _WEBRTC_EVERYWHERE_COMMON_RTCMEDIACONSTRAINTS_H_ + +#include "_Config.h" + +#include "talk/app/webrtc/mediaconstraintsinterface.h" +#include "talk/base/refcount.h" + +class _RTCMediaConstraints + : public webrtc::MediaConstraintsInterface + , public talk_base::RefCountInterface +{ +public: + _RTCMediaConstraints(); + _RTCMediaConstraints(const Constraints& mandatory, const Constraints& optional); + virtual ~_RTCMediaConstraints(); + + // MediaConstraintsInterface + virtual const Constraints& GetMandatory() const { return m_mandatory; } + virtual const Constraints& GetOptional() const { return m_optional; }; + + void AddOptional(const std::string& key, const std::string& value); + bool AddMandatory(const std::string& key, const std::string& value, bool override_if_exists = true); + +private: + Constraints m_mandatory; + Constraints m_optional; +}; + +#endif /* _WEBRTC_EVERYWHERE_COMMON_RTCMEDIACONSTRAINTS_H_ */ diff --git a/common/_SessionDescription.cc b/common/_SessionDescription.cc new file mode 100755 index 0000000..d709249 --- /dev/null +++ b/common/_SessionDescription.cc @@ -0,0 +1,102 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "_SessionDescription.h" +#include "_Buffer.h" +#include "_Debug.h" + +#include "talk/base/json.h" + +_SessionDescription::_SessionDescription() + : m_pSdp(NULL) + , m_pType(NULL) +{ + Init(NULL, NULL, NULL, NULL); +} + +_SessionDescription::_SessionDescription(const void* sdpPtr, size_t sdpSize, const void* typePtr, size_t typeSize) + : m_pSdp(NULL) + , m_pType(NULL) +{ + Init(sdpPtr, sdpSize, typePtr, typeSize); +} + +_SessionDescription::~_SessionDescription() +{ + SafeFree(&m_pSdp); + SafeFree(&m_pType); +} + +WeError _SessionDescription::Init(const void* sdpPtr, size_t sdpSize, const void* typePtr /*= NULL*/, size_t typeSize /*= 0*/) +{ +#if 1 + WeError err = WeError_Success; + SafeFree(&m_pSdp); + SafeFree(&m_pType); + + if (sdpPtr && sdpSize) { + err = _Buffer::New(sdpPtr, sdpSize, &m_pSdp); + if (err) { + goto bail; + } + } + if (typePtr && typeSize) { + err = _Buffer::New(typePtr, typeSize, &m_pType); + if (err) { + goto bail; + } + } + +bail: + return err; +#else + WeError err; + const char* _descriptionInitDictPtr; + Json::Value root, sdp, type; + Json::Reader reader; + + if (!sdpPtr || !sdpSize) { + WE_DEBUG_ERROR("Invalid argument"); + err = WeError_InvalidArgument; + goto bail; + } + + _descriptionInitDictPtr = (const char*)sdpPtr; + if (!(reader.parse(_descriptionInitDictPtr, (_descriptionInitDictPtr + sdpSize), root))) { + WE_DEBUG_ERROR("Invalid JSON content:%.*s", sdpSize, _descriptionInitDictPtr); + err = WeError_InvalidJsonContent; + goto bail; + } + + sdp = root["sdp"]; + type = root["type"]; + + if (sdp.isNull() || !sdp.isString()) { + WE_DEBUG_ERROR("'sdp' attribute is missing"); + err = WeError_InvalidJsonContent; + goto bail; + } + if (type.isNull() || !type.isString()) { + WE_DEBUG_ERROR("'type' attribute is missing"); + err = WeError_InvalidJsonContent; + goto bail; + } + if (type.asString().compare(kRTCSdpType_offer) && type.asString().compare(kRTCSdpType_pranswer) && type.asString().compare(kRTCSdpType_answer)) { + WE_DEBUG_ERROR("'%s' not a valid sdp type", type.asCString()); + err = WeError_InvalidJsonContent; + goto bail; + } + + SafeFree(&m_pSdp); + SafeFree(&m_pType); + err = _Buffer::New(type.asCString(), type.asString().length(), &m_pType); + if (err) { + goto bail; + } + err = _Buffer::New(sdp.asCString(), sdp.asString().length(), &m_pSdp); + if (err) { + goto bail; + } + +bail: + return err; +#endif +} diff --git a/common/_SessionDescription.h b/common/_SessionDescription.h new file mode 100755 index 0000000..c90ea30 --- /dev/null +++ b/common/_SessionDescription.h @@ -0,0 +1,30 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_COMMON_SESSIONDESCRIPTION_H_ +#define _WEBRTC_EVERYWHERE_COMMON_SESSIONDESCRIPTION_H_ + +#include "_Config.h" + +class _Buffer; + +class WEBRTC_EVERYWHERE_API _SessionDescription +{ +public: + _SessionDescription(); + _SessionDescription(const void* sdpPtr, size_t sdpSize, const void* typePtr, size_t typeSize); + virtual ~_SessionDescription(); + + WE_INLINE const _Buffer* getSdp()const { + return m_pSdp; + } + WE_INLINE const _Buffer* getType()const { + return m_pType; + } + + WeError Init(const void* sdpPtr, size_t sdpSize, const void* typePtr = NULL, size_t typeSize = 0); + +public: + _Buffer* m_pSdp; + _Buffer* m_pType; +}; + +#endif /* _WEBRTC_EVERYWHERE_COMMON_SESSIONDESCRIPTION_H_ */ diff --git a/common/_Utils.cc b/common/_Utils.cc new file mode 100755 index 0000000..627a1ac --- /dev/null +++ b/common/_Utils.cc @@ -0,0 +1,294 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "_Utils.h" +#include "_RTCDisplay.h" +#include "_AsyncEvent.h" +#include "_Debug.h" +#include "_Common.h" + +#if WE_UNDER_WINDOWS +# include "windows.h" +# include +# include "talk/base/win32socketinit.h" +#endif + +#include "talk/base/ssladapter.h" +#include "talk/base/thread.h" + +static bool g_bInitialized = false; +#if WE_UNDER_WINDOWS +static bool g_winCoInitialize = false; +#endif + +webrtc::CriticalSectionWrapper* _Utils::s_unique_objs_cs = webrtc::CriticalSectionWrapper::CreateCriticalSection(); +std::map _Utils::s_unique_objs; + +_Utils::_Utils() +{ + +} + +_Utils::~_Utils() +{ + +} + +WeError _Utils::Initialize(WeError(*InitializeAdditionals) (void) /*= NULL*/) +{ + if(!g_bInitialized) { +#if 0 + StartDebug(); +#endif + +#if WE_UNDER_WINDOWS + HRESULT hr = E_FAIL; // CoInitializeEx(NULL, COINIT_MULTITHREADED); + g_winCoInitialize = SUCCEEDED(hr); + talk_base::EnsureWinsockInit(); +#if 0 + static talk_base::Thread w32_thread; + talk_base::ThreadManager::Instance()->SetCurrentThread(&w32_thread); +#endif +#endif + talk_base::InitializeSSL(); + talk_base::InitializeSSLThread(); + g_bInitialized = true; + } + if (InitializeAdditionals) { + return InitializeAdditionals(); + } + return WeError_Success; +} + +WeError _Utils::DeInitialize(void) +{ + if (g_bInitialized) { + talk_base::CleanupSSL(); + g_bInitialized = false; +#if WE_UNDER_WINDOWS + if (g_winCoInitialize) { + CoUninitialize(); + } +#endif + } + return WeError_Success; +} + +WeError _Utils::StartDebug(void) +{ +#if WE_UNDER_WINDOWS + if (AllocConsole()) { + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + SetConsoleTitleA("WebRTC extension for Safari, Opera, FireFox and IE"); + return WeError_Success; + } + return WeError_OutOfMemory; +#else + return WeError_Success; +#endif +} + +WeError _Utils::StopDebug(void) +{ +#if WE_UNDER_WINDOWS + return (FreeConsole() == TRUE) ? WeError_Success : WeError_System; +#else + return WeError_Success; +#endif +} + +std::string _Utils::ToString(long val) +{ + char str[22]; + sprintf(str, "%ld", val); + return std::string(str); +} + +class _NPAsyncData { +public: + _NPAsyncData(HWND _hWnd, UINT _uMsg, WPARAM _wParam, LPARAM _lParam) + : hWnd(_hWnd) + , uMsg(_uMsg) + , wParam(_wParam) + , lParam(_lParam) + {} + HWND hWnd; + UINT uMsg; + WPARAM wParam; + LPARAM lParam; +}; +static void _NPWndProc(void *npdata) +{ + _NPAsyncData* _npdata = reinterpret_cast<_NPAsyncData*>(npdata); + _Utils::WndProc(_npdata->hWnd, _npdata->uMsg, _npdata->wParam, _npdata->lParam); + delete _npdata; +} + +bool _Utils::RaiseCallback(LONGLONG handle, _BrowserCallback* cb) +{ + if (!cb) { + return false; + } + HWND hWnd = reinterpret_cast(handle); + bool ret = false; + + // retain() callback object + cb->RetainObject(); + +#if WE_UNDER_WINDOWS + if (hWnd) { + ret = (PostMessage(hWnd, cb->GetMsgId(), reinterpret_cast(cb), NULL) == TRUE); + } + else { + WE_DEBUG_WARN("Not handle associated to the window yet"); + _Utils::WndProc(hWnd, cb->GetMsgId(), reinterpret_cast(cb), NULL); + ret = true; + } +#elif WE_UNDER_APPLE + _NPAsyncData* _npdata = new _NPAsyncData(hWnd, cb->GetMsgId(), reinterpret_cast(cb), NULL); + if (_npdata) { + dispatch_async(dispatch_get_main_queue(), ^{ + _NPWndProc(_npdata); + }); + ret = true; + } +#else +#error "Not implemented" +#endif + + // release() callback object + if (ret) { + // all is ok -> object will be freed by the async functin + } + else { + cb->ReleaseObject(); + } + return ret; +} + +LRESULT CALLBACK _Utils::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) { +#if WE_UNDER_WINDOWS + case WM_PAINT: + { + _RTCDisplay* display = dynamic_cast<_RTCDisplay*>(reinterpret_cast<_RTCDisplay*>(GetWindowLongPtr(hWnd, GWLP_USERDATA))); + if (display && display->PaintFrame()) { + return 0; + } + else { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hWnd, &ps); + + RECT rc; + GetClientRect(hWnd, &rc); + // Set Clip region to the rectangle specified by di.prcBounds + HRGN hRgnOld = NULL; + if (GetClipRgn(hdc, hRgnOld) != 1) { + hRgnOld = NULL; + } + bool bSelectOldRgn = false; + + HRGN hRgnNew = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom); + + if (hRgnNew != NULL) { + bSelectOldRgn = (SelectClipRgn(hdc, hRgnNew) != ERROR); + } + + Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); + SetTextAlign(hdc, TA_CENTER | TA_BASELINE); + LPCTSTR pszText = TEXT("ATL 8.0 : WebRTC Plugin"); +#ifndef _WIN32_WCE + TextOut(hdc, + (rc.left + rc.right) / 2, + (rc.top + rc.bottom) / 2, + pszText, + lstrlen(pszText)); +#else + ExtTextOut(hdc, + (rc.left + rc.right) / 2, + (rc.top + rc.bottom) / 2, + ETO_OPAQUE, + NULL, + pszText, + ATL::lstrlen(pszText), + NULL); +#endif + + if (bSelectOldRgn) { + SelectClipRgn(hdc, hRgnOld); + } + + EndPaint(hWnd, &ps); + } + break; + } +#endif /* WE_UNDER_WINDOWS */ + + case WM_SUCCESS: + case WM_ERROR: + case WM_GETUSERMEDIA_SUCESS: + case WM_GETUSERMEDIA_ERROR: + case WM_CREATEOFFER_SUCCESS: + case WM_CREATEOFFER_ERROR: + case WM_ONNEGOTIATIONNEEDED: + case WM_ONICECANDIDATE: + case WM_ONSIGNALINGSTATECHANGE: + case WM_ONADDSTREAM: + case WM_ONREMOVESTREAM: + case WM_ONICECONNECTIONSTATECHANGE: + { + _BrowserCallback* _cb = reinterpret_cast<_BrowserCallback*>(wParam); + if (_cb) { + _cb->Invoke(); + _cb->ReleaseObject(); + } + break; + } + } + +#if WE_UNDER_WINDOWS + return DefWindowProc(hWnd, uMsg, wParam, lParam); +#else + return 0; +#endif /* WE_UNDER_WINDOWS */ +} + +long _Utils::UniqueId() +{ + static long __unique_id = 1; + + _Utils::s_unique_objs_cs->Enter(); + long _id = __unique_id++; + _Utils::s_unique_objs_cs->Leave(); + + return _id; +} + +const _UniqueObject* _Utils::UniqueObjFind(long id) +{ + const _UniqueObject* obj = NULL; + _Utils::s_unique_objs_cs->Enter(); + std::map::iterator it = _Utils::s_unique_objs.find(id); + if (it != _Utils::s_unique_objs.end()) { + obj = (*it).second; + } + _Utils::s_unique_objs_cs->Leave(); + return obj; +} + +void _Utils::UniqueObjAdd(const _UniqueObject* obj) +{ + _Utils::s_unique_objs_cs->Enter(); + if (obj) { + _Utils::s_unique_objs[obj->UniqueId()] = obj; + } + _Utils::s_unique_objs_cs->Leave(); +} + +void _Utils::UniqueObjRemove(long id) +{ + _Utils::s_unique_objs_cs->Enter(); + _Utils::s_unique_objs.erase(id); + _Utils::s_unique_objs_cs->Leave(); +} diff --git a/common/_Utils.h b/common/_Utils.h new file mode 100755 index 0000000..eb066f0 --- /dev/null +++ b/common/_Utils.h @@ -0,0 +1,47 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_UTILS_H_ +#define _WEBRTC_EVERYWHERE_UTILS_H_ + +#include "_Config.h" +#include "_Common.h" + +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" + +#include + +class WEBRTC_EVERYWHERE_API _Utils +{ +public: + _Utils(); + virtual ~_Utils(); + +public: + static WeError Initialize(WeError(*InitializeAdditionals) (void) = NULL); + static WeError DeInitialize(void); + static WeError StartDebug(void); + static WeError StopDebug(void); + + static std::string ToString(long val); + + static bool RaiseCallback(LONGLONG handle, _BrowserCallback* cb); + static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + static long UniqueId(); + static const _UniqueObject* UniqueObjFind(long id); + static void UniqueObjAdd(const _UniqueObject* obj); + static void UniqueObjRemove(long id); + +private: +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + static webrtc::CriticalSectionWrapper* s_unique_objs_cs; + static std::map s_unique_objs; +#if _MSC_VER +#pragma warning(pop) +#endif +}; + +#endif /* _WEBRTC_EVERYWHERE_UTILS_H_ */ + diff --git a/common/jsoncpp/json/json-forwards.h b/common/jsoncpp/json/json-forwards.h new file mode 100644 index 0000000..262b7e2 --- /dev/null +++ b/common/jsoncpp/json/json-forwards.h @@ -0,0 +1,251 @@ +/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/). +/// It is intented to be used with #include +/// This header provides forward declaration for all JsonCpp types. + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED +# define JSON_FORWARD_AMALGATED_H_INCLUDED +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +#define JSON_IS_AMALGATED + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +# define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 +/// If defined, indicates that Json specific container should be used +/// (hash table & simple deque container with customizable allocator). +/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332 +//# define JSON_VALUE_USE_INTERNAL_MAP 1 +/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. +/// The memory pools allocator used optimization (initializing Value and ValueInternalLink +/// as if it was a POD) that may cause some validation tool to report errors. +/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. +//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 + +/// If defined, indicates that Json use exception to report invalid type manipulation +/// instead of C assert macro. +# define JSON_USE_EXCEPTION 1 + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + + +# ifdef JSON_IN_CPPTL +# include +# ifndef JSON_USE_CPPTL +# define JSON_USE_CPPTL 1 +# endif +# endif + +# ifdef JSON_IN_CPPTL +# define JSON_API CPPTL_API +# elif defined(JSON_DLL_BUILD) +# define JSON_API __declspec(dllexport) +# elif defined(JSON_DLL) +# define JSON_API __declspec(dllimport) +# else +# define JSON_API +# endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 + +#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 +/// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif + +#if !defined(JSONCPP_DEPRECATED) +# define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +namespace Json +{ +typedef int Int; +typedef unsigned int UInt; +# if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +# undef JSON_HAS_INT64 +# else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +# if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +# else // if defined(_MSC_VER) // Other platforms, use long long +typedef long long int Int64; +typedef unsigned long long int UInt64; +# endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +# define JSON_HAS_INT64 +# endif // if defined(JSON_NO_INT64) +} // end namespace Json + + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +# define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json +{ + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; +#ifdef JSON_VALUE_USE_INTERNAL_MAP +class ValueMapAllocator; +class ValueInternalLink; +class ValueInternalArray; +class ValueInternalMap; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + +} // namespace Json + + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED diff --git a/common/jsoncpp/json/json.h b/common/jsoncpp/json/json.h new file mode 100644 index 0000000..30dcb92 --- /dev/null +++ b/common/jsoncpp/json/json.h @@ -0,0 +1,1830 @@ +/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). +/// It is intented to be used with #include + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_AMALGATED_H_INCLUDED +# define JSON_AMALGATED_H_INCLUDED +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +#define JSON_IS_AMALGATED +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +# define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 +/// If defined, indicates that Json specific container should be used +/// (hash table & simple deque container with customizable allocator). +/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332 +//# define JSON_VALUE_USE_INTERNAL_MAP 1 +/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. +/// The memory pools allocator used optimization (initializing Value and ValueInternalLink +/// as if it was a POD) that may cause some validation tool to report errors. +/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. +//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 + +/// If defined, indicates that Json use exception to report invalid type manipulation +/// instead of C assert macro. +# define JSON_USE_EXCEPTION 1 + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + + +# ifdef JSON_IN_CPPTL +# include +# ifndef JSON_USE_CPPTL +# define JSON_USE_CPPTL 1 +# endif +# endif + +# ifdef JSON_IN_CPPTL +# define JSON_API CPPTL_API +# elif defined(JSON_DLL_BUILD) +# define JSON_API __declspec(dllexport) +# elif defined(JSON_DLL) +# define JSON_API __declspec(dllimport) +# else +# define JSON_API +# endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 + +#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 +/// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif + +#if !defined(JSONCPP_DEPRECATED) +# define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +namespace Json +{ +typedef int Int; +typedef unsigned int UInt; +# if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +# undef JSON_HAS_INT64 +# else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +# if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +# else // if defined(_MSC_VER) // Other platforms, use long long +typedef long long int Int64; +typedef unsigned long long int UInt64; +# endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +# define JSON_HAS_INT64 +# endif // if defined(JSON_NO_INT64) +} // end namespace Json + + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +# define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json +{ + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; +#ifdef JSON_VALUE_USE_INTERNAL_MAP +class ValueMapAllocator; +class ValueInternalLink; +class ValueInternalArray; +class ValueInternalMap; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + +} // namespace Json + + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +# define CPPTL_JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json +{ + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features +{ +public: + /** \brief A configuration that allows all features and assumes all strings are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c false. + bool strictRoot_; +}; + +} // namespace Json + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_H_INCLUDED +# define CPPTL_JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +# include +# include + +# ifndef JSON_USE_CPPTL_SMALLMAP +# include +# else +# include +# endif +# ifdef JSON_USE_CPPTL +# include +# endif + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json +{ + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for root value) + numberOfCommentPlacement +}; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString +{ +public: + explicit StaticString( const char *czstring ) + : str_( czstring ) { + } + + operator const char *() const { + return str_; + } + + const char *c_str() const { + return str_; + } + +private: + const char *str_; +}; + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. + * Non const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resize and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtanis default value in the case the required element + * does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + */ +class JSON_API Value +{ + friend class ValueIteratorBase; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + friend class ValueInternalLink; + friend class ValueInternalMap; +# endif +public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; +# if defined(JSON_HAS_INT64) + typedef Json::UInt64 UInt64; + typedef Json::Int64 Int64; +#endif // defined(JSON_HAS_INT64) + typedef Json::LargestInt LargestInt; + typedef Json::LargestUInt LargestUInt; + typedef Json::ArrayIndex ArrayIndex; + + static const Value null; + /// Minimum signed integer value that can be stored in a Json::Value. + static const LargestInt minLargestInt; + /// Maximum signed integer value that can be stored in a Json::Value. + static const LargestInt maxLargestInt; + /// Maximum unsigned integer value that can be stored in a Json::Value. + static const LargestUInt maxLargestUInt; + + /// Minimum signed int value that can be stored in a Json::Value. + static const Int minInt; + /// Maximum signed int value that can be stored in a Json::Value. + static const Int maxInt; + /// Maximum unsigned int value that can be stored in a Json::Value. + static const UInt maxUInt; + + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 minInt64; + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 maxInt64; + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static const UInt64 maxUInt64; + +private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION +# ifndef JSON_VALUE_USE_INTERNAL_MAP + class CZString + { + public: + enum DuplicationPolicy { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString( ArrayIndex index ); + CZString( const char *cstr, DuplicationPolicy allocate ); + CZString( const CZString &other ); + ~CZString(); + CZString &operator =( const CZString &other ); + bool operator<( const CZString &other ) const; + bool operator==( const CZString &other ) const; + ArrayIndex index() const; + const char *c_str() const; + bool isStaticString() const; + private: + void swap( CZString &other ); + const char *cstr_; + ArrayIndex index_; + }; + +public: +# ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +# else + typedef CppTL::SmallMap ObjectValues; +# endif // ifndef JSON_USE_CPPTL_SMALLMAP +# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. + This is useful since clear() and resize() will not alter types. + + Examples: + \code + Json::Value null_value; // null + Json::Value arr_value(Json::arrayValue); // [] + Json::Value obj_value(Json::objectValue); // {} + \endcode + */ + Value( ValueType type = nullValue ); + Value( Int value ); + Value( UInt value ); +#if defined(JSON_HAS_INT64) + Value( Int64 value ); + Value( UInt64 value ); +#endif // if defined(JSON_HAS_INT64) + Value( double value ); + Value( const char *value ); + Value( const char *beginValue, const char *endValue ); + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * \endcode + */ + Value( const StaticString &value ); + Value( const std::string &value ); +# ifdef JSON_USE_CPPTL + Value( const CppTL::ConstString &value ); +# endif + Value( bool value ); + Value( const Value &other ); + ~Value(); + + Value &operator=( const Value &other ); + /// Swap values. + /// \note Currently, comments are intentionally not swapped, for + /// both logic and efficiency. + void swap( Value &other ); + + ValueType type() const; + + bool operator <( const Value &other ) const; + bool operator <=( const Value &other ) const; + bool operator >=( const Value &other ) const; + bool operator >( const Value &other ) const; + + bool operator ==( const Value &other ) const; + bool operator !=( const Value &other ) const; + + int compare( const Value &other ) const; + + const char *asCString() const; + std::string asString() const; +# ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +# endif + Int asInt() const; + UInt asUInt() const; + Int64 asInt64() const; + UInt64 asUInt64() const; + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isUInt() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo( ValueType other ) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize( ArrayIndex size ); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value &operator[]( ArrayIndex index ); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value &operator[]( int index ); + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value &operator[]( ArrayIndex index ) const; + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value &operator[]( int index ) const; + + /// If the array contains at least index+1 elements, returns the element value, + /// otherwise returns defaultValue. + Value get( ArrayIndex index, + const Value &defaultValue ) const; + /// Return true if index < size(). + bool isValidIndex( ArrayIndex index ) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value &append( const Value &value ); + + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const char *key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const char *key ) const; + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const std::string &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const std::string &key ) const; + /** \brief Access an object value by name, create a null member if it does not exist. + + * If the object as no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value &operator[]( const StaticString &key ); +# ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const CppTL::ConstString &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const CppTL::ConstString &key ) const; +# endif + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const char *key, + const Value &defaultValue ) const; + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const std::string &key, + const Value &defaultValue ) const; +# ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const CppTL::ConstString &key, + const Value &defaultValue ) const; +# endif + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + Value removeMember( const char* key ); + /// Same as removeMember(const char*) + Value removeMember( const std::string &key ); + + /// Return true if the object has a member named key. + bool isMember( const char *key ) const; + /// Return true if the object has a member named key. + bool isMember( const std::string &key ) const; +# ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember( const CppTL::ConstString &key ) const; +# endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + +//# ifdef JSON_USE_CPPTL +// EnumMemberNames enumMemberNames() const; +// EnumValues enumValues() const; +//# endif + + /// Comments must be //... or /* ... */ + void setComment( const char *comment, + CommentPlacement placement ); + /// Comments must be //... or /* ... */ + void setComment( const std::string &comment, + CommentPlacement placement ); + bool hasComment( CommentPlacement placement ) const; + /// Include delimiters and embedded newlines. + std::string getComment( CommentPlacement placement ) const; + + std::string toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + +private: + Value &resolveReference( const char *key, + bool isStatic ); + +# ifdef JSON_VALUE_USE_INTERNAL_MAP + inline bool isItemAvailable() const { + return itemIsUsed_ == 0; + } + + inline void setItemUsed( bool isUsed = true ) { + itemIsUsed_ = isUsed ? 1 : 0; + } + + inline bool isMemberNameStatic() const { + return memberNameIsStatic_ == 0; + } + + inline void setMemberNameIsStatic( bool isStatic ) { + memberNameIsStatic_ = isStatic ? 1 : 0; + } +# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP + +private: + struct CommentInfo { + CommentInfo(); + ~CommentInfo(); + + void setComment( const char *text ); + + char *comment_; + }; + + //struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char *string_; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + ValueInternalArray *array_; + ValueInternalMap *map_; +#else + ObjectValues *map_; +# endif + } value_; + ValueType type_ : 8; + int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. +# ifdef JSON_VALUE_USE_INTERNAL_MAP + unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. + int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. +# endif + CommentInfo *comments_; +}; + + +/** \brief Experimental and untested: represents an element of the "path" to access a node. + */ +class PathArgument +{ +public: + friend class Path; + + PathArgument(); + PathArgument( ArrayIndex index ); + PathArgument( const char *key ); + PathArgument( const std::string &key ); + +private: + enum Kind { + kindNone = 0, + kindIndex, + kindKey + }; + std::string key_; + ArrayIndex index_; + Kind kind_; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ +class Path +{ +public: + Path( const std::string &path, + const PathArgument &a1 = PathArgument(), + const PathArgument &a2 = PathArgument(), + const PathArgument &a3 = PathArgument(), + const PathArgument &a4 = PathArgument(), + const PathArgument &a5 = PathArgument() ); + + const Value &resolve( const Value &root ) const; + Value resolve( const Value &root, + const Value &defaultValue ) const; + /// Creates the "path" to access the specified node and returns a reference on the node. + Value &make( Value &root ) const; + +private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath( const std::string &path, + const InArgs &in ); + void addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ); + void invalidPath( const std::string &path, + int location ); + + Args args_; +}; + + + +#ifdef JSON_VALUE_USE_INTERNAL_MAP +/** \brief Allocator to customize Value internal map. + * Below is an example of a simple implementation (default implementation actually + * use memory pool for speed). + * \code + class DefaultValueMapAllocator : public ValueMapAllocator + { + public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + return new ValueInternalMap(); + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + return new ValueInternalMap( other ); + } + + virtual void destructMap( ValueInternalMap *map ) + { + delete map; + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + return new ValueInternalLink(); + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + delete link; + } + }; + * \endcode + */ +class JSON_API ValueMapAllocator +{ +public: + virtual ~ValueMapAllocator(); + virtual ValueInternalMap *newMap() = 0; + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; + virtual void destructMap( ValueInternalMap *map ) = 0; + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; + virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; + virtual ValueInternalLink *allocateMapLink() = 0; + virtual void releaseMapLink( ValueInternalLink *link ) = 0; +}; + +/** \brief ValueInternalMap hash-map bucket chain link (for internal use only). + * \internal previous_ & next_ allows for bidirectional traversal. + */ +class JSON_API ValueInternalLink +{ +public: + enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. + enum InternalFlags { + flagAvailable = 0, + flagUsed = 1 + }; + + ValueInternalLink(); + + ~ValueInternalLink(); + + Value items_[itemPerLink]; + char *keys_[itemPerLink]; + ValueInternalLink *previous_; + ValueInternalLink *next_; +}; + + +/** \brief A linked page based hash-table implementation used internally by Value. + * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked + * list in each bucket to handle collision. There is an addional twist in that + * each node of the collision linked list is a page containing a fixed amount of + * value. This provides a better compromise between memory usage and speed. + * + * Each bucket is made up of a chained list of ValueInternalLink. The last + * link of a given bucket can be found in the 'previous_' field of the following bucket. + * The last link of the last bucket is stored in tailLink_ as it has no following bucket. + * Only the last link of a bucket may contains 'available' item. The last link always + * contains at least one element unless is it the bucket one very first link. + */ +class JSON_API ValueInternalMap +{ + friend class ValueIteratorBase; + friend class Value; +public: + typedef unsigned int HashKey; + typedef unsigned int BucketIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState { + IteratorState() + : map_(0) + , link_(0) + , itemIndex_(0) + , bucketIndex_(0) { + } + ValueInternalMap *map_; + ValueInternalLink *link_; + BucketIndex itemIndex_; + BucketIndex bucketIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalMap(); + ValueInternalMap( const ValueInternalMap &other ); + ValueInternalMap &operator =( const ValueInternalMap &other ); + ~ValueInternalMap(); + + void swap( ValueInternalMap &other ); + + BucketIndex size() const; + + void clear(); + + bool reserveDelta( BucketIndex growth ); + + bool reserve( BucketIndex newItemCount ); + + const Value *find( const char *key ) const; + + Value *find( const char *key ); + + Value &resolveReference( const char *key, + bool isStatic ); + + void remove( const char *key ); + + void doActualRemove( ValueInternalLink *link, + BucketIndex index, + BucketIndex bucketIndex ); + + ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); + + Value &setNewItem( const char *key, + bool isStatic, + ValueInternalLink *link, + BucketIndex index ); + + Value &unsafeAdd( const char *key, + bool isStatic, + HashKey hashedKey ); + + HashKey hash( const char *key ) const; + + int compare( const ValueInternalMap &other ) const; + +private: + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void incrementBucket( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static const char *key( const IteratorState &iterator ); + static const char *key( const IteratorState &iterator, bool &isStatic ); + static Value &value( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + +private: + ValueInternalLink *buckets_; + ValueInternalLink *tailLink_; + BucketIndex bucketsSize_; + BucketIndex itemCount_; +}; + +/** \brief A simplified deque implementation used internally by Value. +* \internal +* It is based on a list of fixed "page", each page contains a fixed number of items. +* Instead of using a linked-list, a array of pointer is used for fast item look-up. +* Look-up for an element is as follow: +* - compute page index: pageIndex = itemIndex / itemsPerPage +* - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] +* +* Insertion is amortized constant time (only the array containing the index of pointers +* need to be reallocated when items are appended). +*/ +class JSON_API ValueInternalArray +{ + friend class Value; + friend class ValueIteratorBase; +public: + enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. + typedef Value::ArrayIndex ArrayIndex; + typedef unsigned int PageIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState { // Must be a POD + IteratorState() + : array_(0) + , currentPageIndex_(0) + , currentItemIndex_(0) { + } + ValueInternalArray *array_; + Value **currentPageIndex_; + unsigned int currentItemIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalArray(); + ValueInternalArray( const ValueInternalArray &other ); + ValueInternalArray &operator =( const ValueInternalArray &other ); + ~ValueInternalArray(); + void swap( ValueInternalArray &other ); + + void clear(); + void resize( ArrayIndex newSize ); + + Value &resolveReference( ArrayIndex index ); + + Value *find( ArrayIndex index ) const; + + ArrayIndex size() const; + + int compare( const ValueInternalArray &other ) const; + +private: + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static Value &dereference( const IteratorState &iterator ); + static Value &unsafeDereference( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + static ArrayIndex indexOf( const IteratorState &iterator ); + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + void makeIterator( IteratorState &it, ArrayIndex index ) const; + + void makeIndexValid( ArrayIndex index ); + + Value **pages_; + ArrayIndex size_; + PageIndex pageCount_; +}; + +/** \brief Experimental: do not use. Allocator to customize Value internal array. + * Below is an example of a simple implementation (actual implementation use + * memory pool). + \code +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator +virtual ~DefaultValueArrayAllocator() +{ +} + +virtual ValueInternalArray *newArray() +{ + return new ValueInternalArray(); +} + +virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) +{ + return new ValueInternalArray( other ); +} + +virtual void destruct( ValueInternalArray *array ) +{ + delete array; +} + +virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) +{ + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast( newIndexes ); +} +virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) +{ + if ( indexes ) + free( indexes ); +} + +virtual Value *allocateArrayPage() +{ + return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); +} + +virtual void releaseArrayPage( Value *value ) +{ + if ( value ) + free( value ); +} +}; + \endcode + */ +class JSON_API ValueArrayAllocator +{ +public: + virtual ~ValueArrayAllocator(); + virtual ValueInternalArray *newArray() = 0; + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; + virtual void destructArray( ValueInternalArray *array ) = 0; + /** \brief Reallocate array page index. + * Reallocates an array of pointer on each page. + * \param indexes [input] pointer on the current index. May be \c NULL. + * [output] pointer on the new index of at least + * \a minNewIndexCount pages. + * \param indexCount [input] current number of pages in the index. + * [output] number of page the reallocated index can handle. + * \b MUST be >= \a minNewIndexCount. + * \param minNewIndexCount Minimum number of page the new index must be able to + * handle. + */ + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) = 0; + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) = 0; + virtual Value *allocateArrayPage() = 0; + virtual void releaseArrayPage( Value *value ) = 0; +}; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + + +/** \brief base class for Value iterators. + * + */ +class ValueIteratorBase +{ +public: + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + ValueIteratorBase(); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); +#else + ValueIteratorBase( const ValueInternalArray::IteratorState &state ); + ValueIteratorBase( const ValueInternalMap::IteratorState &state ); +#endif + + bool operator ==( const SelfType &other ) const { + return isEqual( other ); + } + + bool operator !=( const SelfType &other ) const { + return !isEqual( other ); + } + + difference_type operator -( const SelfType &other ) const { + return computeDistance( other ); + } + + /// Return either the index or the member name of the referenced value as a Value. + Value key() const; + + /// Return the index of the referenced Value. -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value. "" if it is not an objectValue. + const char *memberName() const; + +protected: + Value &deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance( const SelfType &other ) const; + + bool isEqual( const SelfType &other ) const; + + void copy( const SelfType &other ); + +private: +#ifndef JSON_VALUE_USE_INTERNAL_MAP + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; +#else + union { + ValueInternalArray::IteratorState array_; + ValueInternalMap::IteratorState map_; + } iterator_; + bool isArray_; +#endif +}; + +/** \brief const iterator for object and array value. + * + */ +class ValueConstIterator : public ValueIteratorBase +{ + friend class Value; +public: + typedef unsigned int size_t; + typedef int difference_type; + typedef const Value &reference; + typedef const Value *pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); +private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueConstIterator( const ValueInternalArray::IteratorState &state ); + ValueConstIterator( const ValueInternalMap::IteratorState &state ); +#endif +public: + SelfType &operator =( const ValueIteratorBase &other ); + + SelfType operator++( int ) { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() { + decrement(); + return *this; + } + + SelfType &operator++() { + increment(); + return *this; + } + + reference operator *() const { + return deref(); + } +}; + + +/** \brief Iterator for object and array value. + */ +class ValueIterator : public ValueIteratorBase +{ + friend class Value; +public: + typedef unsigned int size_t; + typedef int difference_type; + typedef Value &reference; + typedef Value *pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + ValueIterator( const ValueConstIterator &other ); + ValueIterator( const ValueIterator &other ); +private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueIterator( const ValueInternalArray::IteratorState &state ); + ValueIterator( const ValueInternalMap::IteratorState &state ); +#endif +public: + + SelfType &operator =( const SelfType &other ); + + SelfType operator++( int ) { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() { + decrement(); + return *this; + } + + SelfType &operator++() { + increment(); + return *this; + } + + reference operator *() const { + return deref(); + } +}; + + +} // namespace Json + + +#endif // CPPTL_JSON_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_READER_H_INCLUDED +# define CPPTL_JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "features.h" +# include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +# include +# include +# include +# include + +namespace Json +{ + +/** \brief Unserialize a JSON document into a Value. + * + */ +class JSON_API Reader +{ +public: + typedef char Char; + typedef const Char *Location; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader( const Features &features ); + + /** \brief Read a Value from a JSON document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const std::string &document, + Value &root, + bool collectComments = true ); + + /** \brief Read a Value from a JSON document. + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read. + \ Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments = true ); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse( std::istream &is, + Value &root, + bool collectComments = true ); + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead") + std::string getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + */ + std::string getFormattedErrorMessages() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token + { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo + { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool expectToken( TokenType type, Token &token, const char *message ); + bool readToken( Token &token ); + void skipSpaces(); + bool match( Location pattern, + int patternLength ); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject( Token &token ); + bool readArray( Token &token ); + bool decodeNumber( Token &token ); + bool decodeString( Token &token ); + bool decodeString( Token &token, std::string &decoded ); + bool decodeDouble( Token &token ); + bool decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool addError( const std::string &message, + Token &token, + Location extra = 0 ); + bool recoverFromError( TokenType skipUntilToken ); + bool addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ); + void skipUntilSpace(); + Value ¤tValue(); + Char getNextChar(); + void getLocationLineAndColumn( Location location, + int &line, + int &column ) const; + std::string getLocationLineAndColumn( Location location ) const; + void addComment( Location begin, + Location end, + CommentPlacement placement ); + void skipCommentTokens( Token &token ); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value *lastValue_; + std::string commentsBefore_; + Features features_; + bool collectComments_; +}; + +/** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() +*/ +std::istream& operator>>( std::istream&, Value& ); + +} // namespace Json + +#endif // CPPTL_JSON_READER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +# define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +# include +# include +# include + +namespace Json +{ + +class Value; + +/** \brief Abstract class for writers. + */ +class JSON_API Writer +{ +public: + virtual ~Writer(); + + virtual std::string write( const Value &root ) = 0; +}; + +/** \brief Outputs a Value in JSON format without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + */ +class JSON_API FastWriter : public Writer +{ +public: + FastWriter(); + virtual ~FastWriter() {} + + void enableYAMLCompatibility(); + +public: // overridden from Writer + virtual std::string write( const Value &root ); + +private: + void writeValue( const Value &value ); + + std::string document_; + bool yamlCompatiblityEnabled_; +}; + +/** \brief Writes a Value in JSON format in a human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + */ +class JSON_API StyledWriter: public Writer +{ +public: + StyledWriter(); + virtual ~StyledWriter() {} + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + virtual std::string write( const Value &root ); + +private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; +}; + +/** \brief Writes a Value in JSON format in a human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + */ +class JSON_API StyledStreamWriter +{ +public: + StyledStreamWriter( std::string indentation="\t" ); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not return a value. + */ + void write( std::ostream &out, const Value &root ); + +private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_; +}; + +# if defined(JSON_HAS_INT64) +std::string JSON_API valueToString( Int value ); +std::string JSON_API valueToString( UInt value ); +# endif // if defined(JSON_HAS_INT64) +std::string JSON_API valueToString( LargestInt value ); +std::string JSON_API valueToString( LargestUInt value ); +std::string JSON_API valueToString( double value ); +std::string JSON_API valueToString( bool value ); +std::string JSON_API valueToQuotedString( const char *value ); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +std::ostream& operator<<( std::ostream&, const Value &root ); + +} // namespace Json + + + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGATED_H_INCLUDED diff --git a/common/jsoncpp/jsoncpp.cc b/common/jsoncpp/jsoncpp.cc new file mode 100644 index 0000000..2907abd --- /dev/null +++ b/common/jsoncpp/jsoncpp.cc @@ -0,0 +1,4231 @@ +/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). +/// It is intented to be used with #include + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + + +#include "jsoncpp/json/json.h" + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED +# define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +/* This header provides common string manipulation support, such as UTF-8, + * portable conversion from/to string... + * + * It is an internal header that must not be exposed. + */ + +namespace Json +{ + +/// Converts a unicode code-point to UTF-8. +static inline std::string +codePointToUTF8(unsigned int cp) +{ + std::string result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast(cp); + } + else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } + else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); + result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); + } + else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + + +/// Returns true if ch is a control character (in range [0,32[). +static inline bool +isControlCharacter(char ch) +{ + return ch > 0 && ch <= 0x1F; +} + + +enum { + /// Constant that specify the size of the buffer that must be passed to uintToString. + uintToStringBufferSize = 3*sizeof(LargestUInt)+1 +}; + +// Defines a char buffer for use with uintToString(). +typedef char UIntToStringBuffer[uintToStringBufferSize]; + + +/** Converts an unsigned integer to string. + * @param value Unsigned interger to convert to string + * @param current Input/Output string buffer. + * Must have at least uintToStringBufferSize chars free. + */ +static inline void +uintToString( LargestUInt value, + char *¤t ) +{ + *--current = 0; + do { + *--current = char(value % 10) + '0'; + value /= 10; + } + while ( value != 0 ); +} + +} // namespace Json { + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +# include +# include +# include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include + +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#endif + +namespace Json +{ + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_( true ) + , strictRoot_( false ) +{ +} + + +Features +Features::all() +{ + return Features(); +} + + +Features +Features::strictMode() +{ + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + + +static inline bool +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) +{ + return c == c1 || c == c2 || c == c3 || c == c4; +} + +static inline bool +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) +{ + return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; +} + + +static bool +containsNewLine( Reader::Location begin, + Reader::Location end ) +{ + for ( ; begin < end; ++begin ) + if ( *begin == '\n' || *begin == '\r' ) { + return true; + } + return false; +} + + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : features_( Features::all() ) +{ +} + + +Reader::Reader( const Features &features ) + : features_( features ) +{ +} + + +bool +Reader::parse( const std::string &document, + Value &root, + bool collectComments ) +{ + document_ = document; + const char *begin = document_.c_str(); + const char *end = begin + document_.length(); + return parse( begin, end, root, collectComments ); +} + + +bool +Reader::parse( std::istream& sin, + Value &root, + bool collectComments ) +{ + //std::istream_iterator begin(sin); + //std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since std::string is reference-counted, this at least does not + // create an extra copy. + std::string doc; + std::getline(sin, doc, (char)EOF); + return parse( doc, root, collectComments ); +} + +bool +Reader::parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments ) +{ + if ( !features_.allowComments_ ) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while ( !nodes_.empty() ) { + nodes_.pop(); + } + nodes_.push( &root ); + + bool successful = readValue(); + Token token; + skipCommentTokens( token ); + if ( collectComments_ && !commentsBefore_.empty() ) { + root.setComment( commentsBefore_, commentAfter ); + } + if ( features_.strictRoot_ ) { + if ( !root.isArray() && !root.isObject() ) { + // Set error location to start of doc, ideally should be first token found in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( "A valid JSON document must be either an array or an object value.", + token ); + return false; + } + } + return successful; +} + + +bool +Reader::readValue() +{ + Token token; + skipCommentTokens( token ); + bool successful = true; + + if ( collectComments_ && !commentsBefore_.empty() ) { + currentValue().setComment( commentsBefore_, commentBefore ); + commentsBefore_ = ""; + } + + + switch ( token.type_ ) { + case tokenObjectBegin: + successful = readObject( token ); + break; + case tokenArrayBegin: + successful = readArray( token ); + break; + case tokenNumber: + successful = decodeNumber( token ); + break; + case tokenString: + successful = decodeString( token ); + break; + case tokenTrue: + currentValue() = true; + break; + case tokenFalse: + currentValue() = false; + break; + case tokenNull: + currentValue() = Value(); + break; + default: + return addError( "Syntax error: value, object or array expected.", token ); + } + + if ( collectComments_ ) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + + +void +Reader::skipCommentTokens( Token &token ) +{ + if ( features_.allowComments_ ) { + do { + readToken( token ); + } + while ( token.type_ == tokenComment ); + } + else { + readToken( token ); + } +} + + +bool +Reader::expectToken( TokenType type, Token &token, const char *message ) +{ + readToken( token ); + if ( token.type_ != type ) { + return addError( message, token ); + } + return true; +} + + +bool +Reader::readToken( Token &token ) +{ + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch ( c ) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match( "rue", 3 ); + break; + case 'f': + token.type_ = tokenFalse; + ok = match( "alse", 4 ); + break; + case 'n': + token.type_ = tokenNull; + ok = match( "ull", 3 ); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if ( !ok ) { + token.type_ = tokenError; + } + token.end_ = current_; + return true; +} + + +void +Reader::skipSpaces() +{ + while ( current_ != end_ ) { + Char c = *current_; + if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) { + ++current_; + } + else { + break; + } + } +} + + +bool +Reader::match( Location pattern, + int patternLength ) +{ + if ( end_ - current_ < patternLength ) { + return false; + } + int index = patternLength; + while ( index-- ) + if ( current_[index] != pattern[index] ) { + return false; + } + current_ += patternLength; + return true; +} + + +bool +Reader::readComment() +{ + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if ( c == '*' ) { + successful = readCStyleComment(); + } + else if ( c == '/' ) { + successful = readCppStyleComment(); + } + if ( !successful ) { + return false; + } + + if ( collectComments_ ) { + CommentPlacement placement = commentBefore; + if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) { + if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) { + placement = commentAfterOnSameLine; + } + } + + addComment( commentBegin, current_, placement ); + } + return true; +} + + +void +Reader::addComment( Location begin, + Location end, + CommentPlacement placement ) +{ + assert( collectComments_ ); + if ( placement == commentAfterOnSameLine ) { + assert( lastValue_ != 0 ); + lastValue_->setComment( std::string( begin, end ), placement ); + } + else { + if ( !commentsBefore_.empty() ) { + commentsBefore_ += "\n"; + } + commentsBefore_ += std::string( begin, end ); + } +} + + +bool +Reader::readCStyleComment() +{ + while ( current_ != end_ ) { + Char c = getNextChar(); + if ( c == '*' && *current_ == '/' ) { + break; + } + } + return getNextChar() == '/'; +} + + +bool +Reader::readCppStyleComment() +{ + while ( current_ != end_ ) { + Char c = getNextChar(); + if ( c == '\r' || c == '\n' ) { + break; + } + } + return true; +} + + +void +Reader::readNumber() +{ + while ( current_ != end_ ) { + if ( !(*current_ >= '0' && *current_ <= '9') && + !in( *current_, '.', 'e', 'E', '+', '-' ) ) { + break; + } + ++current_; + } +} + +bool +Reader::readString() +{ + Char c = 0; + while ( current_ != end_ ) { + c = getNextChar(); + if ( c == '\\' ) { + getNextChar(); + } + else if ( c == '"' ) { + break; + } + } + return c == '"'; +} + + +bool +Reader::readObject( Token &/*tokenStart*/ ) +{ + Token tokenName; + std::string name; + currentValue() = Value( objectValue ); + while ( readToken( tokenName ) ) { + bool initialTokenOk = true; + while ( tokenName.type_ == tokenComment && initialTokenOk ) { + initialTokenOk = readToken( tokenName ); + } + if ( !initialTokenOk ) { + break; + } + if ( tokenName.type_ == tokenObjectEnd && name.empty() ) { // empty object + return true; + } + if ( tokenName.type_ != tokenString ) { + break; + } + + name = ""; + if ( !decodeString( tokenName, name ) ) { + return recoverFromError( tokenObjectEnd ); + } + + Token colon; + if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) { + return addErrorAndRecover( "Missing ':' after object member name", + colon, + tokenObjectEnd ); + } + Value &value = currentValue()[ name ]; + nodes_.push( &value ); + bool ok = readValue(); + nodes_.pop(); + if ( !ok ) { // error already set + return recoverFromError( tokenObjectEnd ); + } + + Token comma; + if ( !readToken( comma ) + || ( comma.type_ != tokenObjectEnd && + comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment ) ) { + return addErrorAndRecover( "Missing ',' or '}' in object declaration", + comma, + tokenObjectEnd ); + } + bool finalizeTokenOk = true; + while ( comma.type_ == tokenComment && + finalizeTokenOk ) { + finalizeTokenOk = readToken( comma ); + } + if ( comma.type_ == tokenObjectEnd ) { + return true; + } + } + return addErrorAndRecover( "Missing '}' or object member name", + tokenName, + tokenObjectEnd ); +} + + +bool +Reader::readArray( Token &/*tokenStart*/ ) +{ + currentValue() = Value( arrayValue ); + skipSpaces(); + if ( *current_ == ']' ) { // empty array + Token endArray; + readToken( endArray ); + return true; + } + int index = 0; + for (;;) { + Value &value = currentValue()[ index++ ]; + nodes_.push( &value ); + bool ok = readValue(); + nodes_.pop(); + if ( !ok ) { // error already set + return recoverFromError( tokenArrayEnd ); + } + + Token token; + // Accept Comment after last item in the array. + ok = readToken( token ); + while ( token.type_ == tokenComment && ok ) { + ok = readToken( token ); + } + bool badTokenType = ( token.type_ != tokenArraySeparator && + token.type_ != tokenArrayEnd ); + if ( !ok || badTokenType ) { + return addErrorAndRecover( "Missing ',' or ']' in array declaration", + token, + tokenArrayEnd ); + } + if ( token.type_ == tokenArrayEnd ) { + break; + } + } + return true; +} + + +bool +Reader::decodeNumber( Token &token ) +{ + bool isDouble = false; + for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) { + isDouble = isDouble + || in( *inspect, '.', 'e', 'E', '+' ) + || ( *inspect == '-' && inspect != token.start_ ); + } + if ( isDouble ) { + return decodeDouble( token ); + } + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if ( isNegative ) { + ++current; + } + Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::UInt lastDigitThreshold = Value::UInt( maxIntegerValue % 10 ); + assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 ); + Value::LargestUInt value = 0; + while ( current < token.end_ ) { + Char c = *current++; + if ( c < '0' || c > '9' ) { + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); + } + Value::UInt digit(c - '0'); + if ( value >= threshold ) { + // If the current digit is not the last one, or if it is + // greater than the last digit of the maximum integer value, + // the parse the number as a double. + if ( current != token.end_ || digit > lastDigitThreshold ) { + return decodeDouble( token ); + } + } + value = value * 10 + digit; + } + if ( isNegative ) { + currentValue() = -Value::LargestInt( value ); + } + else if ( value <= Value::LargestUInt(Value::maxInt) ) { + currentValue() = Value::LargestInt( value ); + } + else { + currentValue() = value; + } + return true; +} + + +bool +Reader::decodeDouble( Token &token ) +{ + double value = 0; + const int bufferSize = 32; + int count; + int length = int(token.end_ - token.start_); + if ( length <= bufferSize ) { + Char buffer[bufferSize+1]; + memcpy( buffer, token.start_, length ); + buffer[length] = 0; + count = sscanf( buffer, "%lf", &value ); + } + else { + std::string buffer( token.start_, token.end_ ); + count = sscanf( buffer.c_str(), "%lf", &value ); + } + + if ( count != 1 ) { + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); + } + currentValue() = value; + return true; +} + + +bool +Reader::decodeString( Token &token ) +{ + std::string decoded; + if ( !decodeString( token, decoded ) ) { + return false; + } + currentValue() = decoded; + return true; +} + + +bool +Reader::decodeString( Token &token, std::string &decoded ) +{ + decoded.reserve( token.end_ - token.start_ - 2 ); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while ( current != end ) { + Char c = *current++; + if ( c == '"' ) { + break; + } + else if ( c == '\\' ) { + if ( current == end ) { + return addError( "Empty escape sequence in string", token, current ); + } + Char escape = *current++; + switch ( escape ) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) { + return false; + } + decoded += codePointToUTF8(unicode); + } + break; + default: + return addError( "Bad escape sequence in string", token, current ); + } + } + else { + decoded += c; + } + } + return true; +} + +bool +Reader::decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ) +{ + + if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) { + return false; + } + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) { + return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); + } + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++)== 'u') { + if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } + else { + return false; + } + } + else { + return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); + } + } + return true; +} + +bool +Reader::decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ) +{ + if ( end - current < 4 ) { + return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); + } + unicode = 0; + for ( int index =0; index < 4; ++index ) { + Char c = *current++; + unicode *= 16; + if ( c >= '0' && c <= '9' ) { + unicode += c - '0'; + } + else if ( c >= 'a' && c <= 'f' ) { + unicode += c - 'a' + 10; + } + else if ( c >= 'A' && c <= 'F' ) { + unicode += c - 'A' + 10; + } + else { + return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); + } + } + return true; +} + + +bool +Reader::addError( const std::string &message, + Token &token, + Location extra ) +{ + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back( info ); + return false; +} + + +bool +Reader::recoverFromError( TokenType skipUntilToken ) +{ + int errorCount = int(errors_.size()); + Token skip; + for (;;) { + if ( !readToken(skip) ) { + errors_.resize( errorCount ); // discard errors caused by recovery + } + if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) { + break; + } + } + errors_.resize( errorCount ); + return false; +} + + +bool +Reader::addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ) +{ + addError( message, token ); + return recoverFromError( skipUntilToken ); +} + + +Value & +Reader::currentValue() +{ + return *(nodes_.top()); +} + + +Reader::Char +Reader::getNextChar() +{ + if ( current_ == end_ ) { + return 0; + } + return *current_++; +} + + +void +Reader::getLocationLineAndColumn( Location location, + int &line, + int &column ) const +{ + Location current = begin_; + Location lastLineStart = current; + line = 0; + while ( current < location && current != end_ ) { + Char c = *current++; + if ( c == '\r' ) { + if ( *current == '\n' ) { + ++current; + } + lastLineStart = current; + ++line; + } + else if ( c == '\n' ) { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + + +std::string +Reader::getLocationLineAndColumn( Location location ) const +{ + int line, column; + getLocationLineAndColumn( location, line, column ); + char buffer[18+16+16+1]; + sprintf( buffer, "Line %d, Column %d", line, column ); + return buffer; +} + + +// Deprecated. Preserved for backward compatibility +std::string +Reader::getFormatedErrorMessages() const +{ + return getFormattedErrorMessages(); +} + + +std::string +Reader::getFormattedErrorMessages() const +{ + std::string formattedMessage; + for ( Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError ) { + const ErrorInfo &error = *itError; + formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if ( error.extra_ ) { + formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; + } + } + return formattedMessage; +} + + +std::istream& operator>>( std::istream &sin, Value &root ) +{ + Json::Reader reader; + bool ok = reader.parse(sin, root, true); + //JSON_ASSERT( ok ); + if (!ok) { + throw std::runtime_error(reader.getFormattedErrorMessages()); + } + return sin; +} + + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_batchallocator.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED +# define JSONCPP_BATCHALLOCATOR_H_INCLUDED + +# include +# include + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +namespace Json +{ + +/* Fast memory allocator. + * + * This memory allocator allocates memory for a batch of object (specified by + * the page size, the number of object in each page). + * + * It does not allow the destruction of a single object. All the allocated objects + * can be destroyed at once. The memory can be either released or reused for future + * allocation. + * + * The in-place new operator must be used to construct the object using the pointer + * returned by allocate. + */ +template +class BatchAllocator +{ +public: + typedef AllocatedType Type; + + BatchAllocator( unsigned int objectsPerPage = 255 ) + : freeHead_( 0 ) + , objectsPerPage_( objectsPerPage ) { +// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); + assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. + assert( objectsPerPage >= 16 ); + batches_ = allocateBatch( 0 ); // allocated a dummy page + currentBatch_ = batches_; + } + + ~BatchAllocator() { + for ( BatchInfo *batch = batches_; batch; ) { + BatchInfo *nextBatch = batch->next_; + free( batch ); + batch = nextBatch; + } + } + + /// allocate space for an array of objectPerAllocation object. + /// @warning it is the responsability of the caller to call objects constructors. + AllocatedType *allocate() { + if ( freeHead_ ) { // returns node from free list. + AllocatedType *object = freeHead_; + freeHead_ = *(AllocatedType **)object; + return object; + } + if ( currentBatch_->used_ == currentBatch_->end_ ) { + currentBatch_ = currentBatch_->next_; + while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) { + currentBatch_ = currentBatch_->next_; + } + + if ( !currentBatch_ ) { // no free batch found, allocate a new one + currentBatch_ = allocateBatch( objectsPerPage_ ); + currentBatch_->next_ = batches_; // insert at the head of the list + batches_ = currentBatch_; + } + } + AllocatedType *allocated = currentBatch_->used_; + currentBatch_->used_ += objectPerAllocation; + return allocated; + } + + /// Release the object. + /// @warning it is the responsability of the caller to actually destruct the object. + void release( AllocatedType *object ) { + assert( object != 0 ); + *(AllocatedType **)object = freeHead_; + freeHead_ = object; + } + +private: + struct BatchInfo { + BatchInfo *next_; + AllocatedType *used_; + AllocatedType *end_; + AllocatedType buffer_[objectPerAllocation]; + }; + + // disabled copy constructor and assignement operator. + BatchAllocator( const BatchAllocator & ); + void operator =( const BatchAllocator &); + + static BatchInfo *allocateBatch( unsigned int objectsPerPage ) { + const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation + + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; + BatchInfo *batch = static_cast( malloc( mallocSize ) ); + batch->next_ = 0; + batch->used_ = batch->buffer_; + batch->end_ = batch->buffer_ + objectsPerPage; + return batch; + } + + BatchInfo *batches_; + BatchInfo *currentBatch_; + /// Head of a single linked list within the allocated space of freeed object + AllocatedType *freeHead_; + unsigned int objectsPerPage_; +}; + + +} // namespace Json + +# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION + +#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED + + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_batchallocator.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +// included by json_value.cpp + +namespace Json +{ + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() +#ifndef JSON_VALUE_USE_INTERNAL_MAP + : current_() + , isNull_( true ) +{ +} +#else + : + isArray_( true ) + , isNull_( true ) +{ + iterator_.array_ = ValueInternalArray::IteratorState(); +} +#endif + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) + : current_( current ) + , isNull_( false ) +{ +} +#else +ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) + : isArray_( true ) +{ + iterator_.array_ = state; +} + + +ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) + : isArray_( false ) +{ + iterator_.map_ = state; +} +#endif + +Value & +ValueIteratorBase::deref() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + return current_->second; +#else + if ( isArray_ ) { + return ValueInternalArray::dereference( iterator_.array_ ); + } + return ValueInternalMap::value( iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::increment() +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ++current_; +#else + if ( isArray_ ) { + ValueInternalArray::increment( iterator_.array_ ); + } + ValueInternalMap::increment( iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::decrement() +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + --current_; +#else + if ( isArray_ ) { + ValueInternalArray::decrement( iterator_.array_ ); + } + ValueInternalMap::decrement( iterator_.map_ ); +#endif +} + + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance( const SelfType &other ) const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP +# ifdef JSON_USE_CPPTL_SMALLMAP + return current_ - other.current_; +# else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if ( isNull_ && other.isNull_ ) { + return 0; + } + + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) { + ++myDistance; + } + return myDistance; +# endif +#else + if ( isArray_ ) { + return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); + } + return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); +#endif +} + + +bool +ValueIteratorBase::isEqual( const SelfType &other ) const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + if ( isNull_ ) { + return other.isNull_; + } + return current_ == other.current_; +#else + if ( isArray_ ) { + return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); + } + return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::copy( const SelfType &other ) +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + current_ = other.current_; +#else + if ( isArray_ ) { + iterator_.array_ = other.iterator_.array_; + } + iterator_.map_ = other.iterator_.map_; +#endif +} + + +Value +ValueIteratorBase::key() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const Value::CZString czstring = (*current_).first; + if ( czstring.c_str() ) { + if ( czstring.isStaticString() ) { + return Value( StaticString( czstring.c_str() ) ); + } + return Value( czstring.c_str() ); + } + return Value( czstring.index() ); +#else + if ( isArray_ ) { + return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); + } + bool isStatic; + const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); + if ( isStatic ) { + return Value( StaticString( memberName ) ); + } + return Value( memberName ); +#endif +} + + +UInt +ValueIteratorBase::index() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const Value::CZString czstring = (*current_).first; + if ( !czstring.c_str() ) { + return czstring.index(); + } + return Value::UInt( -1 ); +#else + if ( isArray_ ) { + return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); + } + return Value::UInt( -1 ); +#endif +} + + +const char * +ValueIteratorBase::memberName() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const char *name = (*current_).first.c_str(); + return name ? name : ""; +#else + if ( !isArray_ ) { + return ValueInternalMap::key( iterator_.map_ ); + } + return ""; +#endif +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() +{ +} + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) + : ValueIteratorBase( current ) +{ +} +#else +ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} + +ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} +#endif + +ValueConstIterator & +ValueConstIterator::operator =( const ValueIteratorBase &other ) +{ + copy( other ); + return *this; +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() +{ +} + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) + : ValueIteratorBase( current ) +{ +} +#else +ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} + +ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} +#endif + +ValueIterator::ValueIterator( const ValueConstIterator &other ) + : ValueIteratorBase( other ) +{ +} + +ValueIterator::ValueIterator( const ValueIterator &other ) + : ValueIteratorBase( other ) +{ +} + +ValueIterator & +ValueIterator::operator =( const SelfType &other ) +{ + copy( other ); + return *this; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +# include +# include +# ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +# include "json_batchallocator.h" +# endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#ifdef JSON_USE_CPPTL +# include +#endif +#include // size_t + +#define JSON_ASSERT_UNREACHABLE assert( false ) +#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw +#define JSON_FAIL_MESSAGE( message ) throw std::runtime_error( message ); +#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) JSON_FAIL_MESSAGE( message ) + +namespace Json +{ + +const Value Value::null; +const Int Value::minInt = Int( ~(UInt(-1)/2) ); +const Int Value::maxInt = Int( UInt(-1)/2 ); +const UInt Value::maxUInt = UInt(-1); +const Int64 Value::minInt64 = Int64( ~(UInt64(-1)/2) ); +const Int64 Value::maxInt64 = Int64( UInt64(-1)/2 ); +const UInt64 Value::maxUInt64 = UInt64(-1); +const LargestInt Value::minLargestInt = LargestInt( ~(LargestUInt(-1)/2) ); +const LargestInt Value::maxLargestInt = LargestInt( LargestUInt(-1)/2 ); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + + +/// Unknown size marker +static const unsigned int unknown = (unsigned)-1; + + +/** Duplicates the specified string value. + * @param value Pointer to the string to duplicate. Must be zero-terminated if + * length is "unknown". + * @param length Length of the value. if equals to unknown, then it will be + * computed using strlen(value). + * @return Pointer on the duplicate instance of string. + */ +static inline char * +duplicateStringValue( const char *value, + unsigned int length = unknown ) +{ + if ( length == unknown ) { + length = (unsigned int)strlen(value); + } + char *newString = static_cast( malloc( length + 1 ) ); + JSON_ASSERT_MESSAGE( newString != 0, "Failed to allocate string value buffer" ); + memcpy( newString, value, length ); + newString[length] = 0; + return newString; +} + + +/** Free the string duplicated by duplicateStringValue(). + */ +static inline void +releaseStringValue( char *value ) +{ + if ( value ) { + free( value ); + } +} + +} // namespace Json + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) +# ifdef JSON_VALUE_USE_INTERNAL_MAP +# include "json_internalarray.inl" +# include "json_internalmap.inl" +# endif // JSON_VALUE_USE_INTERNAL_MAP + +# include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json +{ + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + + +Value::CommentInfo::CommentInfo() + : comment_( 0 ) +{ +} + +Value::CommentInfo::~CommentInfo() +{ + if ( comment_ ) { + releaseStringValue( comment_ ); + } +} + + +void +Value::CommentInfo::setComment( const char *text ) +{ + if ( comment_ ) { + releaseStringValue( comment_ ); + } + JSON_ASSERT( text != 0 ); + JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue( text ); +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +# ifndef JSON_VALUE_USE_INTERNAL_MAP + +// Notes: index_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString( ArrayIndex index ) + : cstr_( 0 ) + , index_( index ) +{ +} + +Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) + : cstr_( allocate == duplicate ? duplicateStringValue(cstr) + : cstr ) + , index_( allocate ) +{ +} + +Value::CZString::CZString( const CZString &other ) + : cstr_( other.index_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue( other.cstr_ ) + : other.cstr_ ) + , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) + : other.index_ ) +{ +} + +Value::CZString::~CZString() +{ + if ( cstr_ && index_ == duplicate ) { + releaseStringValue( const_cast( cstr_ ) ); + } +} + +void +Value::CZString::swap( CZString &other ) +{ + std::swap( cstr_, other.cstr_ ); + std::swap( index_, other.index_ ); +} + +Value::CZString & +Value::CZString::operator =( const CZString &other ) +{ + CZString temp( other ); + swap( temp ); + return *this; +} + +bool +Value::CZString::operator<( const CZString &other ) const +{ + if ( cstr_ ) { + return strcmp( cstr_, other.cstr_ ) < 0; + } + return index_ < other.index_; +} + +bool +Value::CZString::operator==( const CZString &other ) const +{ + if ( cstr_ ) { + return strcmp( cstr_, other.cstr_ ) == 0; + } + return index_ == other.index_; +} + + +ArrayIndex +Value::CZString::index() const +{ + return index_; +} + + +const char * +Value::CZString::c_str() const +{ + return cstr_; +} + +bool +Value::CZString::isStaticString() const +{ + return index_ == noDuplication; +} + +#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value( ValueType type ) + : type_( type ) + , allocated_( 0 ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + switch ( type ) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + value_.string_ = 0; + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; +#else + case arrayValue: + value_.array_ = arrayAllocator()->newArray(); + break; + case objectValue: + value_.map_ = mapAllocator()->newMap(); + break; +#endif + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + + +#if defined(JSON_HAS_INT64) +Value::Value( UInt value ) + : type_( uintValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.uint_ = value; +} + +Value::Value( Int value ) + : type_( intValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.int_ = value; +} + +#endif // if defined(JSON_HAS_INT64) + + +Value::Value( Int64 value ) + : type_( intValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.int_ = value; +} + + +Value::Value( UInt64 value ) + : type_( uintValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.uint_ = value; +} + +Value::Value( double value ) + : type_( realValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.real_ = value; +} + +Value::Value( const char *value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = duplicateStringValue( value ); +} + + +Value::Value( const char *beginValue, + const char *endValue ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = duplicateStringValue( beginValue, + (unsigned int)(endValue - beginValue) ); +} + + +Value::Value( const std::string &value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = duplicateStringValue( value.c_str(), + (unsigned int)value.length() ); + +} + +Value::Value( const StaticString &value ) + : type_( stringValue ) + , allocated_( false ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = const_cast( value.c_str() ); +} + + +# ifdef JSON_USE_CPPTL +Value::Value( const CppTL::ConstString &value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = duplicateStringValue( value, value.length() ); +} +# endif + +Value::Value( bool value ) + : type_( booleanValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.bool_ = value; +} + + +Value::Value( const Value &other ) + : type_( other.type_ ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + switch ( type_ ) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if ( other.value_.string_ ) { + value_.string_ = duplicateStringValue( other.value_.string_ ); + allocated_ = true; + } + else { + value_.string_ = 0; + } + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues( *other.value_.map_ ); + break; +#else + case arrayValue: + value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); + break; + case objectValue: + value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); + break; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + if ( other.comments_ ) { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) { + const CommentInfo &otherComment = other.comments_[comment]; + if ( otherComment.comment_ ) { + comments_[comment].setComment( otherComment.comment_ ); + } + } + } +} + + +Value::~Value() +{ + switch ( type_ ) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if ( allocated_ ) { + releaseStringValue( value_.string_ ); + } + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + delete value_.map_; + break; +#else + case arrayValue: + arrayAllocator()->destructArray( value_.array_ ); + break; + case objectValue: + mapAllocator()->destructMap( value_.map_ ); + break; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + + if ( comments_ ) { + delete[] comments_; + } +} + +Value & +Value::operator=( const Value &other ) +{ + Value temp( other ); + swap( temp ); + return *this; +} + +void +Value::swap( Value &other ) +{ + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap( value_, other.value_ ); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2; +} + +ValueType +Value::type() const +{ + return type_; +} + + +int +Value::compare( const Value &other ) const +{ + if ( *this < other ) { + return -1; + } + if ( *this > other ) { + return 1; + } + return 0; +} + + +bool +Value::operator <( const Value &other ) const +{ + int typeDelta = type_ - other.type_; + if ( typeDelta ) { + return typeDelta < 0 ? true : false; + } + switch ( type_ ) { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: + return ( value_.string_ == 0 && other.value_.string_ ) + || ( other.value_.string_ + && value_.string_ + && strcmp( value_.string_, other.value_.string_ ) < 0 ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: { + int delta = int( value_.map_->size() - other.value_.map_->size() ); + if ( delta ) { + return delta < 0; + } + return (*value_.map_) < (*other.value_.map_); + } +#else + case arrayValue: + return value_.array_->compare( *(other.value_.array_) ) < 0; + case objectValue: + return value_.map_->compare( *(other.value_.map_) ) < 0; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool +Value::operator <=( const Value &other ) const +{ + return !(other < *this); +} + +bool +Value::operator >=( const Value &other ) const +{ + return !(*this < other); +} + +bool +Value::operator >( const Value &other ) const +{ + return other < *this; +} + +bool +Value::operator ==( const Value &other ) const +{ + //if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if ( type_ != temp ) { + return false; + } + switch ( type_ ) { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: + return ( value_.string_ == other.value_.string_ ) + || ( other.value_.string_ + && value_.string_ + && strcmp( value_.string_, other.value_.string_ ) == 0 ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() + && (*value_.map_) == (*other.value_.map_); +#else + case arrayValue: + return value_.array_->compare( *(other.value_.array_) ) == 0; + case objectValue: + return value_.map_->compare( *(other.value_.map_) ) == 0; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool +Value::operator !=( const Value &other ) const +{ + return !( *this == other ); +} + +const char * +Value::asCString() const +{ + JSON_ASSERT( type_ == stringValue ); + return value_.string_; +} + + +std::string +Value::asString() const +{ + switch ( type_ ) { + case nullValue: + return ""; + case stringValue: + return value_.string_ ? value_.string_ : ""; + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + case uintValue: + case realValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to string" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return ""; // unreachable +} + +# ifdef JSON_USE_CPPTL +CppTL::ConstString +Value::asConstString() const +{ + return CppTL::ConstString( asString().c_str() ); +} +# endif + + +Value::Int +Value::asInt() const +{ + switch ( type_ ) { + case nullValue: + return 0; + case intValue: + JSON_ASSERT_MESSAGE( value_.int_ >= minInt && value_.int_ <= maxInt, "unsigned integer out of signed int range" ); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE( value_.uint_ <= UInt(maxInt), "unsigned integer out of signed int range" ); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); + return Int( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to int" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +Value::UInt +Value::asUInt() const +{ + switch ( type_ ) { + case nullValue: + return 0; + case intValue: + JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); + JSON_ASSERT_MESSAGE( value_.int_ <= maxUInt, "signed integer out of UInt range" ); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE( value_.uint_ <= maxUInt, "unsigned integer out of UInt range" ); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); + return UInt( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to uint" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +# if defined(JSON_HAS_INT64) + +Value::Int64 +Value::asInt64() const +{ + switch ( type_ ) { + case nullValue: + return 0; + case intValue: + return value_.int_; + case uintValue: + JSON_ASSERT_MESSAGE( value_.uint_ <= UInt64(maxInt64), "unsigned integer out of Int64 range" ); + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= minInt64 && value_.real_ <= maxInt64, "Real out of Int64 range" ); + return Int( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to Int64" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +Value::UInt64 +Value::asUInt64() const +{ + switch ( type_ ) { + case nullValue: + return 0; + case intValue: + JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to UInt64" ); + return value_.int_; + case uintValue: + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt64, "Real out of UInt64 range" ); + return UInt( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to UInt64" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} +# endif // if defined(JSON_HAS_INT64) + + +LargestInt +Value::asLargestInt() const +{ +#if defined(JSON_NO_INT64) + return asInt(); +#else + return asInt64(); +#endif +} + + +LargestUInt +Value::asLargestUInt() const +{ +#if defined(JSON_NO_INT64) + return asUInt(); +#else + return asUInt64(); +#endif +} + + +double +Value::asDouble() const +{ + switch ( type_ ) { + case nullValue: + return 0.0; + case intValue: + return static_cast( value_.int_ ); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast( value_.uint_ ); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to double" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +float +Value::asFloat() const +{ + switch ( type_ ) { + case nullValue: + return 0.0f; + case intValue: + return static_cast( value_.int_ ); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast( value_.uint_ ); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to float" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0.0f; // unreachable; +} + +bool +Value::asBool() const +{ + switch ( type_ ) { + case nullValue: + return false; + case intValue: + case uintValue: + return value_.int_ != 0; + case realValue: + return value_.real_ != 0.0; + case booleanValue: + return value_.bool_; + case stringValue: + return value_.string_ && value_.string_[0] != 0; + case arrayValue: + case objectValue: + return value_.map_->size() != 0; + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + + +bool +Value::isConvertibleTo( ValueType other ) const +{ + switch ( type_ ) { + case nullValue: + return true; + case intValue: + return ( other == nullValue && value_.int_ == 0 ) + || other == intValue + || ( other == uintValue && value_.int_ >= 0 ) + || other == realValue + || other == stringValue + || other == booleanValue; + case uintValue: + return ( other == nullValue && value_.uint_ == 0 ) + || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) + || other == uintValue + || other == realValue + || other == stringValue + || other == booleanValue; + case realValue: + return ( other == nullValue && value_.real_ == 0.0 ) + || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) + || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) + || other == realValue + || other == stringValue + || other == booleanValue; + case booleanValue: + return ( other == nullValue && value_.bool_ == false ) + || other == intValue + || other == uintValue + || other == realValue + || other == stringValue + || other == booleanValue; + case stringValue: + return other == stringValue + || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); + case arrayValue: + return other == arrayValue + || ( other == nullValue && value_.map_->size() == 0 ); + case objectValue: + return other == objectValue + || ( other == nullValue && value_.map_->size() == 0 ); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + + +/// Number of values in array or object +ArrayIndex +Value::size() const +{ + switch ( type_ ) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: // size of the array is highest index + 1 + if ( !value_.map_->empty() ) { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index()+1; + } + return 0; + case objectValue: + return ArrayIndex( value_.map_->size() ); +#else + case arrayValue: + return Int( value_.array_->size() ); + case objectValue: + return Int( value_.map_->size() ); +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +bool +Value::empty() const +{ + if ( isNull() || isArray() || isObject() ) { + return size() == 0u; + } + else { + return false; + } +} + + +bool +Value::operator!() const +{ + return isNull(); +} + + +void +Value::clear() +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); + + switch ( type_ ) { +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_->clear(); + break; +#else + case arrayValue: + value_.array_->clear(); + break; + case objectValue: + value_.map_->clear(); + break; +#endif + default: + break; + } +} + +void +Value::resize( ArrayIndex newSize ) +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) { + *this = Value( arrayValue ); + } +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ArrayIndex oldSize = size(); + if ( newSize == 0 ) { + clear(); + } + else if ( newSize > oldSize ) { + (*this)[ newSize - 1 ]; + } + else { + for ( ArrayIndex index = newSize; index < oldSize; ++index ) { + value_.map_->erase( index ); + } + assert( size() == newSize ); + } +#else + value_.array_->resize( newSize ); +#endif +} + + +Value & +Value::operator[]( ArrayIndex index ) +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) { + *this = Value( arrayValue ); + } +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString key( index ); + ObjectValues::iterator it = value_.map_->lower_bound( key ); + if ( it != value_.map_->end() && (*it).first == key ) { + return (*it).second; + } + + ObjectValues::value_type defaultValue( key, null ); + it = value_.map_->insert( it, defaultValue ); + return (*it).second; +#else + return value_.array_->resolveReference( index ); +#endif +} + + +Value & +Value::operator[]( int index ) +{ + JSON_ASSERT( index >= 0 ); + return (*this)[ ArrayIndex(index) ]; +} + + +const Value & +Value::operator[]( ArrayIndex index ) const +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) { + return null; + } +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString key( index ); + ObjectValues::const_iterator it = value_.map_->find( key ); + if ( it == value_.map_->end() ) { + return null; + } + return (*it).second; +#else + Value *value = value_.array_->find( index ); + return value ? *value : null; +#endif +} + + +const Value & +Value::operator[]( int index ) const +{ + JSON_ASSERT( index >= 0 ); + return (*this)[ ArrayIndex(index) ]; +} + + +Value & +Value::operator[]( const char *key ) +{ + return resolveReference( key, false ); +} + + +Value & +Value::resolveReference( const char *key, + bool isStatic ) +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) { + *this = Value( objectValue ); + } +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, isStatic ? CZString::noDuplication + : CZString::duplicateOnCopy ); + ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); + if ( it != value_.map_->end() && (*it).first == actualKey ) { + return (*it).second; + } + + ObjectValues::value_type defaultValue( actualKey, null ); + it = value_.map_->insert( it, defaultValue ); + Value &value = (*it).second; + return value; +#else + return value_.map_->resolveReference( key, isStatic ); +#endif +} + + +Value +Value::get( ArrayIndex index, + const Value &defaultValue ) const +{ + const Value *value = &((*this)[index]); + return value == &null ? defaultValue : *value; +} + + +bool +Value::isValidIndex( ArrayIndex index ) const +{ + return index < size(); +} + + + +const Value & +Value::operator[]( const char *key ) const +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) { + return null; + } +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, CZString::noDuplication ); + ObjectValues::const_iterator it = value_.map_->find( actualKey ); + if ( it == value_.map_->end() ) { + return null; + } + return (*it).second; +#else + const Value *value = value_.map_->find( key ); + return value ? *value : null; +#endif +} + + +Value & +Value::operator[]( const std::string &key ) +{ + return (*this)[ key.c_str() ]; +} + + +const Value & +Value::operator[]( const std::string &key ) const +{ + return (*this)[ key.c_str() ]; +} + +Value & +Value::operator[]( const StaticString &key ) +{ + return resolveReference( key, true ); +} + + +# ifdef JSON_USE_CPPTL +Value & +Value::operator[]( const CppTL::ConstString &key ) +{ + return (*this)[ key.c_str() ]; +} + + +const Value & +Value::operator[]( const CppTL::ConstString &key ) const +{ + return (*this)[ key.c_str() ]; +} +# endif + + +Value & +Value::append( const Value &value ) +{ + return (*this)[size()] = value; +} + + +Value +Value::get( const char *key, + const Value &defaultValue ) const +{ + const Value *value = &((*this)[key]); + return value == &null ? defaultValue : *value; +} + + +Value +Value::get( const std::string &key, + const Value &defaultValue ) const +{ + return get( key.c_str(), defaultValue ); +} + +Value +Value::removeMember( const char* key ) +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) { + return null; + } +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, CZString::noDuplication ); + ObjectValues::iterator it = value_.map_->find( actualKey ); + if ( it == value_.map_->end() ) { + return null; + } + Value old(it->second); + value_.map_->erase(it); + return old; +#else + Value *value = value_.map_->find( key ); + if (value) { + Value old(*value); + value_.map_.remove( key ); + return old; + } + else { + return null; + } +#endif +} + +Value +Value::removeMember( const std::string &key ) +{ + return removeMember( key.c_str() ); +} + +# ifdef JSON_USE_CPPTL +Value +Value::get( const CppTL::ConstString &key, + const Value &defaultValue ) const +{ + return get( key.c_str(), defaultValue ); +} +# endif + +bool +Value::isMember( const char *key ) const +{ + const Value *value = &((*this)[key]); + return value != &null; +} + + +bool +Value::isMember( const std::string &key ) const +{ + return isMember( key.c_str() ); +} + + +# ifdef JSON_USE_CPPTL +bool +Value::isMember( const CppTL::ConstString &key ) const +{ + return isMember( key.c_str() ); +} +#endif + +Value::Members +Value::getMemberNames() const +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) { + return Value::Members(); + } + Members members; + members.reserve( value_.map_->size() ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for ( ; it != itEnd; ++it ) { + members.push_back( std::string( (*it).first.c_str() ) ); + } +#else + ValueInternalMap::IteratorState it; + ValueInternalMap::IteratorState itEnd; + value_.map_->makeBeginIterator( it ); + value_.map_->makeEndIterator( itEnd ); + for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) { + members.push_back( std::string( ValueInternalMap::key( it ) ) ); + } +#endif + return members; +} +// +//# ifdef JSON_USE_CPPTL +//EnumMemberNames +//Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +//EnumValues +//Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type() ); +// return EnumValues(); +//} +// +//# endif + + +bool +Value::isNull() const +{ + return type_ == nullValue; +} + + +bool +Value::isBool() const +{ + return type_ == booleanValue; +} + + +bool +Value::isInt() const +{ + return type_ == intValue; +} + + +bool +Value::isUInt() const +{ + return type_ == uintValue; +} + + +bool +Value::isIntegral() const +{ + return type_ == intValue + || type_ == uintValue + || type_ == booleanValue; +} + + +bool +Value::isDouble() const +{ + return type_ == realValue; +} + + +bool +Value::isNumeric() const +{ + return isIntegral() || isDouble(); +} + + +bool +Value::isString() const +{ + return type_ == stringValue; +} + + +bool +Value::isArray() const +{ + return type_ == nullValue || type_ == arrayValue; +} + + +bool +Value::isObject() const +{ + return type_ == nullValue || type_ == objectValue; +} + + +void +Value::setComment( const char *comment, + CommentPlacement placement ) +{ + if ( !comments_ ) { + comments_ = new CommentInfo[numberOfCommentPlacement]; + } + comments_[placement].setComment( comment ); +} + + +void +Value::setComment( const std::string &comment, + CommentPlacement placement ) +{ + setComment( comment.c_str(), placement ); +} + + +bool +Value::hasComment( CommentPlacement placement ) const +{ + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +std::string +Value::getComment( CommentPlacement placement ) const +{ + if ( hasComment(placement) ) { + return comments_[placement].comment_; + } + return ""; +} + + +std::string +Value::toStyledString() const +{ + StyledWriter writer; + return writer.write( *this ); +} + + +Value::const_iterator +Value::begin() const +{ + switch ( type_ ) { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator( it ); + return const_iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator( it ); + return const_iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) { + return const_iterator( value_.map_->begin() ); + } + break; +#endif + default: + break; + } + return const_iterator(); +} + +Value::const_iterator +Value::end() const +{ + switch ( type_ ) { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator( it ); + return const_iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator( it ); + return const_iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) { + return const_iterator( value_.map_->end() ); + } + break; +#endif + default: + break; + } + return const_iterator(); +} + + +Value::iterator +Value::begin() +{ + switch ( type_ ) { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator( it ); + return iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator( it ); + return iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) { + return iterator( value_.map_->begin() ); + } + break; +#endif + default: + break; + } + return iterator(); +} + +Value::iterator +Value::end() +{ + switch ( type_ ) { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator( it ); + return iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator( it ); + return iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) { + return iterator( value_.map_->end() ); + } + break; +#endif + default: + break; + } + return iterator(); +} + + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() + : kind_( kindNone ) +{ +} + + +PathArgument::PathArgument( ArrayIndex index ) + : index_( index ) + , kind_( kindIndex ) +{ +} + + +PathArgument::PathArgument( const char *key ) + : key_( key ) + , kind_( kindKey ) +{ +} + + +PathArgument::PathArgument( const std::string &key ) + : key_( key.c_str() ) + , kind_( kindKey ) +{ +} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path( const std::string &path, + const PathArgument &a1, + const PathArgument &a2, + const PathArgument &a3, + const PathArgument &a4, + const PathArgument &a5 ) +{ + InArgs in; + in.push_back( &a1 ); + in.push_back( &a2 ); + in.push_back( &a3 ); + in.push_back( &a4 ); + in.push_back( &a5 ); + makePath( path, in ); +} + + +void +Path::makePath( const std::string &path, + const InArgs &in ) +{ + const char *current = path.c_str(); + const char *end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while ( current != end ) { + if ( *current == '[' ) { + ++current; + if ( *current == '%' ) { + addPathInArg( path, in, itInArg, PathArgument::kindIndex ); + } + else { + ArrayIndex index = 0; + for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) { + index = index * 10 + ArrayIndex(*current - '0'); + } + args_.push_back( index ); + } + if ( current == end || *current++ != ']' ) { + invalidPath( path, int(current - path.c_str()) ); + } + } + else if ( *current == '%' ) { + addPathInArg( path, in, itInArg, PathArgument::kindKey ); + ++current; + } + else if ( *current == '.' ) { + ++current; + } + else { + const char *beginName = current; + while ( current != end && !strchr( "[.", *current ) ) { + ++current; + } + args_.push_back( std::string( beginName, current ) ); + } + } +} + + +void +Path::addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ) +{ + if ( itInArg == in.end() ) { + // Error: missing argument %d + } + else if ( (*itInArg)->kind_ != kind ) { + // Error: bad argument type + } + else { + args_.push_back( **itInArg ); + } +} + + +void +Path::invalidPath( const std::string &path, + int location ) +{ + // Error: invalid path. +} + + +const Value & +Path::resolve( const Value &root ) const +{ + const Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) { + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) { + // Error: unable to resolve path (array value expected at position... + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) { + if ( !node->isObject() ) { + // Error: unable to resolve path (object value expected at position...) + } + node = &((*node)[arg.key_]); + if ( node == &Value::null ) { + // Error: unable to resolve path (object has no member named '' at position...) + } + } + } + return *node; +} + + +Value +Path::resolve( const Value &root, + const Value &defaultValue ) const +{ + const Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) { + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) { + return defaultValue; + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) { + if ( !node->isObject() ) { + return defaultValue; + } + node = &((*node)[arg.key_]); + if ( node == &Value::null ) { + return defaultValue; + } + } + } + return *node; +} + + +Value & +Path::make( Value &root ) const +{ + Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) { + if ( !node->isArray() ) { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) { + if ( !node->isObject() ) { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +# include +# include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include + +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#endif + +namespace Json +{ + +static bool containsControlCharacter( const char* str ) +{ + while ( *str ) { + if ( isControlCharacter( *(str++) ) ) { + return true; + } + } + return false; +} + + +std::string valueToString( LargestInt value ) +{ + UIntToStringBuffer buffer; + char *current = buffer + sizeof(buffer); + bool isNegative = value < 0; + if ( isNegative ) { + value = -value; + } + uintToString( LargestUInt(value), current ); + if ( isNegative ) { + *--current = '-'; + } + assert( current >= buffer ); + return current; +} + + +std::string valueToString( LargestUInt value ) +{ + UIntToStringBuffer buffer; + char *current = buffer + sizeof(buffer); + uintToString( value, current ); + assert( current >= buffer ); + return current; +} + +#if defined(JSON_HAS_INT64) + +std::string valueToString( Int value ) +{ + return valueToString( LargestInt(value) ); +} + + +std::string valueToString( UInt value ) +{ + return valueToString( LargestUInt(value) ); +} + +#endif // # if defined(JSON_HAS_INT64) + + +std::string valueToString( double value ) +{ + char buffer[32]; +#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. + sprintf_s(buffer, sizeof(buffer), "%#.16g", value); +#else + sprintf(buffer, "%#.16g", value); +#endif + char* ch = buffer + strlen(buffer) - 1; + if (*ch != '0') { + return buffer; // nothing to truncate, so save time + } + while(ch > buffer && *ch == '0') { + --ch; + } + char* last_nonzero = ch; + while(ch >= buffer) { + switch(*ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + --ch; + continue; + case '.': + // Truncate zeroes to save bytes in output, but keep one. + *(last_nonzero+2) = '\0'; + return buffer; + default: + return buffer; + } + } + return buffer; +} + + +std::string valueToString( bool value ) +{ + return value ? "true" : "false"; +} + +std::string valueToQuotedString( const char *value ) +{ + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) { + return std::string("\"") + value + "\""; + } + // We have to walk value and escape any special characters. + // Appending to std::string is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c=value; *c != 0; ++c) { + switch(*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + //case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something. + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } + else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() +{ +} + + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_( false ) +{ +} + + +void +FastWriter::enableYAMLCompatibility() +{ + yamlCompatiblityEnabled_ = true; +} + + +std::string +FastWriter::write( const Value &root ) +{ + document_ = ""; + writeValue( root ); + document_ += "\n"; + return document_; +} + + +void +FastWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) { + case nullValue: + document_ += "null"; + break; + case intValue: + document_ += valueToString( value.asLargestInt() ); + break; + case uintValue: + document_ += valueToString( value.asLargestUInt() ); + break; + case realValue: + document_ += valueToString( value.asDouble() ); + break; + case stringValue: + document_ += valueToQuotedString( value.asCString() ); + break; + case booleanValue: + document_ += valueToString( value.asBool() ); + break; + case arrayValue: { + document_ += "["; + int size = value.size(); + for ( int index =0; index < size; ++index ) { + if ( index > 0 ) { + document_ += ","; + } + writeValue( value[index] ); + } + document_ += "]"; + } + break; + case objectValue: { + Value::Members members( value.getMemberNames() ); + document_ += "{"; + for ( Value::Members::iterator it = members.begin(); + it != members.end(); + ++it ) { + const std::string &name = *it; + if ( it != members.begin() ) { + document_ += ","; + } + document_ += valueToQuotedString( name.c_str() ); + document_ += yamlCompatiblityEnabled_ ? ": " + : ":"; + writeValue( value[name] ); + } + document_ += "}"; + } + break; + } +} + + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_( 74 ) + , indentSize_( 3 ) +{ +} + + +std::string +StyledWriter::write( const Value &root ) +{ + document_ = ""; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue( root ); + writeValue( root ); + writeCommentAfterValueOnSameLine( root ); + document_ += "\n"; + return document_; +} + + +void +StyledWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) { + case nullValue: + pushValue( "null" ); + break; + case intValue: + pushValue( valueToString( value.asLargestInt() ) ); + break; + case uintValue: + pushValue( valueToString( value.asLargestUInt() ) ); + break; + case realValue: + pushValue( valueToString( value.asDouble() ) ); + break; + case stringValue: + pushValue( valueToQuotedString( value.asCString() ) ); + break; + case booleanValue: + pushValue( valueToString( value.asBool() ) ); + break; + case arrayValue: + writeArrayValue( value); + break; + case objectValue: { + Value::Members members( value.getMemberNames() ); + if ( members.empty() ) { + pushValue( "{}" ); + } + else { + writeWithIndent( "{" ); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const std::string &name = *it; + const Value &childValue = value[name]; + writeCommentBeforeValue( childValue ); + writeWithIndent( valueToQuotedString( name.c_str() ) ); + document_ += " : "; + writeValue( childValue ); + if ( ++it == members.end() ) { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "}" ); + } + } + break; + } +} + + +void +StyledWriter::writeArrayValue( const Value &value ) +{ + unsigned size = value.size(); + if ( size == 0 ) { + pushValue( "[]" ); + } + else { + bool isArrayMultiLine = isMultineArray( value ); + if ( isArrayMultiLine ) { + writeWithIndent( "[" ); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index =0; + for (;;) { + const Value &childValue = value[index]; + writeCommentBeforeValue( childValue ); + if ( hasChildValue ) { + writeWithIndent( childValues_[index] ); + } + else { + writeIndent(); + writeValue( childValue ); + } + if ( ++index == size ) { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "]" ); + } + else { // output on a single line + assert( childValues_.size() == size ); + document_ += "[ "; + for ( unsigned index =0; index < size; ++index ) { + if ( index > 0 ) { + document_ += ", "; + } + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + + +bool +StyledWriter::isMultineArray( const Value &value ) +{ + int size = value.size(); + bool isMultiLine = size*3 >= rightMargin_ ; + childValues_.clear(); + for ( int index =0; index < size && !isMultiLine; ++index ) { + const Value &childValue = value[index]; + isMultiLine = isMultiLine || + ( (childValue.isArray() || childValue.isObject()) && + childValue.size() > 0 ); + } + if ( !isMultiLine ) { // check if line length > max line length + childValues_.reserve( size ); + addChildValues_ = true; + int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' + for ( int index =0; index < size && !isMultiLine; ++index ) { + writeValue( value[index] ); + lineLength += int( childValues_[index].length() ); + isMultiLine = isMultiLine && hasCommentForValue( value[index] ); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + + +void +StyledWriter::pushValue( const std::string &value ) +{ + if ( addChildValues_ ) { + childValues_.push_back( value ); + } + else { + document_ += value; + } +} + + +void +StyledWriter::writeIndent() +{ + if ( !document_.empty() ) { + char last = document_[document_.length()-1]; + if ( last == ' ' ) { // already indented + return; + } + if ( last != '\n' ) { // Comments may add new-line + document_ += '\n'; + } + } + document_ += indentString_; +} + + +void +StyledWriter::writeWithIndent( const std::string &value ) +{ + writeIndent(); + document_ += value; +} + + +void +StyledWriter::indent() +{ + indentString_ += std::string( indentSize_, ' ' ); +} + + +void +StyledWriter::unindent() +{ + assert( int(indentString_.size()) >= indentSize_ ); + indentString_.resize( indentString_.size() - indentSize_ ); +} + + +void +StyledWriter::writeCommentBeforeValue( const Value &root ) +{ + if ( !root.hasComment( commentBefore ) ) { + return; + } + document_ += normalizeEOL( root.getComment( commentBefore ) ); + document_ += "\n"; +} + + +void +StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) +{ + if ( root.hasComment( commentAfterOnSameLine ) ) { + document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + } + + if ( root.hasComment( commentAfter ) ) { + document_ += "\n"; + document_ += normalizeEOL( root.getComment( commentAfter ) ); + document_ += "\n"; + } +} + + +bool +StyledWriter::hasCommentForValue( const Value &value ) +{ + return value.hasComment( commentBefore ) + || value.hasComment( commentAfterOnSameLine ) + || value.hasComment( commentAfter ); +} + + +std::string +StyledWriter::normalizeEOL( const std::string &text ) +{ + std::string normalized; + normalized.reserve( text.length() ); + const char *begin = text.c_str(); + const char *end = begin + text.length(); + const char *current = begin; + while ( current != end ) { + char c = *current++; + if ( c == '\r' ) { // mac or dos EOL + if ( *current == '\n' ) { // convert dos EOL + ++current; + } + normalized += '\n'; + } + else { // handle unix EOL & other char + normalized += c; + } + } + return normalized; +} + + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter( std::string indentation ) + : document_(NULL) + , rightMargin_( 74 ) + , indentation_( indentation ) +{ +} + + +void +StyledStreamWriter::write( std::ostream &out, const Value &root ) +{ + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue( root ); + writeValue( root ); + writeCommentAfterValueOnSameLine( root ); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + + +void +StyledStreamWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) { + case nullValue: + pushValue( "null" ); + break; + case intValue: + pushValue( valueToString( value.asLargestInt() ) ); + break; + case uintValue: + pushValue( valueToString( value.asLargestUInt() ) ); + break; + case realValue: + pushValue( valueToString( value.asDouble() ) ); + break; + case stringValue: + pushValue( valueToQuotedString( value.asCString() ) ); + break; + case booleanValue: + pushValue( valueToString( value.asBool() ) ); + break; + case arrayValue: + writeArrayValue( value); + break; + case objectValue: { + Value::Members members( value.getMemberNames() ); + if ( members.empty() ) { + pushValue( "{}" ); + } + else { + writeWithIndent( "{" ); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const std::string &name = *it; + const Value &childValue = value[name]; + writeCommentBeforeValue( childValue ); + writeWithIndent( valueToQuotedString( name.c_str() ) ); + *document_ << " : "; + writeValue( childValue ); + if ( ++it == members.end() ) { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "}" ); + } + } + break; + } +} + + +void +StyledStreamWriter::writeArrayValue( const Value &value ) +{ + unsigned size = value.size(); + if ( size == 0 ) { + pushValue( "[]" ); + } + else { + bool isArrayMultiLine = isMultineArray( value ); + if ( isArrayMultiLine ) { + writeWithIndent( "[" ); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index =0; + for (;;) { + const Value &childValue = value[index]; + writeCommentBeforeValue( childValue ); + if ( hasChildValue ) { + writeWithIndent( childValues_[index] ); + } + else { + writeIndent(); + writeValue( childValue ); + } + if ( ++index == size ) { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "]" ); + } + else { // output on a single line + assert( childValues_.size() == size ); + *document_ << "[ "; + for ( unsigned index =0; index < size; ++index ) { + if ( index > 0 ) { + *document_ << ", "; + } + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + + +bool +StyledStreamWriter::isMultineArray( const Value &value ) +{ + int size = value.size(); + bool isMultiLine = size*3 >= rightMargin_ ; + childValues_.clear(); + for ( int index =0; index < size && !isMultiLine; ++index ) { + const Value &childValue = value[index]; + isMultiLine = isMultiLine || + ( (childValue.isArray() || childValue.isObject()) && + childValue.size() > 0 ); + } + if ( !isMultiLine ) { // check if line length > max line length + childValues_.reserve( size ); + addChildValues_ = true; + int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' + for ( int index =0; index < size && !isMultiLine; ++index ) { + writeValue( value[index] ); + lineLength += int( childValues_[index].length() ); + isMultiLine = isMultiLine && hasCommentForValue( value[index] ); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + + +void +StyledStreamWriter::pushValue( const std::string &value ) +{ + if ( addChildValues_ ) { + childValues_.push_back( value ); + } + else { + *document_ << value; + } +} + + +void +StyledStreamWriter::writeIndent() +{ + /* + Some comments in this method would have been nice. ;-) + + if ( !document_.empty() ) + { + char last = document_[document_.length()-1]; + if ( last == ' ' ) // already indented + return; + if ( last != '\n' ) // Comments may add new-line + *document_ << '\n'; + } + */ + *document_ << '\n' << indentString_; +} + + +void +StyledStreamWriter::writeWithIndent( const std::string &value ) +{ + writeIndent(); + *document_ << value; +} + + +void +StyledStreamWriter::indent() +{ + indentString_ += indentation_; +} + + +void +StyledStreamWriter::unindent() +{ + assert( indentString_.size() >= indentation_.size() ); + indentString_.resize( indentString_.size() - indentation_.size() ); +} + + +void +StyledStreamWriter::writeCommentBeforeValue( const Value &root ) +{ + if ( !root.hasComment( commentBefore ) ) { + return; + } + *document_ << normalizeEOL( root.getComment( commentBefore ) ); + *document_ << "\n"; +} + + +void +StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) +{ + if ( root.hasComment( commentAfterOnSameLine ) ) { + *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + } + + if ( root.hasComment( commentAfter ) ) { + *document_ << "\n"; + *document_ << normalizeEOL( root.getComment( commentAfter ) ); + *document_ << "\n"; + } +} + + +bool +StyledStreamWriter::hasCommentForValue( const Value &value ) +{ + return value.hasComment( commentBefore ) + || value.hasComment( commentAfterOnSameLine ) + || value.hasComment( commentAfter ); +} + + +std::string +StyledStreamWriter::normalizeEOL( const std::string &text ) +{ + std::string normalized; + normalized.reserve( text.length() ); + const char *begin = text.c_str(); + const char *end = begin + text.length(); + const char *current = begin; + while ( current != end ) { + char c = *current++; + if ( c == '\r' ) { // mac or dos EOL + if ( *current == '\n' ) { // convert dos EOL + ++current; + } + normalized += '\n'; + } + else { // handle unix EOL & other char + normalized += c; + } + } + return normalized; +} + + +std::ostream& operator<<( std::ostream &sout, const Value &root ) +{ + Json::StyledStreamWriter writer; + writer.write(sout, root); + return sout; +} + + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + diff --git a/common/mac/.DS_Store b/common/mac/.DS_Store new file mode 100755 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 + +#if !defined(DISABLE_YUV) +#include "libyuv/scale_argb.h" +#endif +#include "talk/base/common.h" +#include "talk/base/logging.h" +#include "talk/base/systeminfo.h" +#include "talk/media/base/videoprocessor.h" + +#if defined(HAVE_WEBRTC_VIDEO) +#include "talk/media/webrtc/webrtcvideoframe.h" +#endif // HAVE_WEBRTC_VIDEO + + +namespace cricket { + +namespace { + +// TODO(thorcarpenter): This is a BIG hack to flush the system with black +// frames. Frontends should coordinate to update the video state of a muted +// user. When all frontends to this consider removing the black frame business. +const int kNumBlackFramesOnMute = 30; + +// MessageHandler constants. +enum { + MSG_DO_PAUSE = 0, + MSG_DO_UNPAUSE, + MSG_STATE_CHANGE +}; + +static const int64 kMaxDistance = ~(static_cast(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 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 + +///////////////////////////////////////////////////////////////////// +// Implementation of struct CapturedFrame +///////////////////////////////////////////////////////////////////// +CapturedFrame::CapturedFrame() + : width(0), + height(0), + fourcc(0), + pixel_width(0), + pixel_height(0), + elapsed_time(0), + time_stamp(0), + data_size(0), + rotation(0), + data(NULL) {} + +// TODO(fbarchard): Remove this function once lmimediaengine stops using it. +bool CapturedFrame::GetDataSize(uint32* size) const { + if (!size || data_size == CapturedFrame::kUnknownDataSize) { + return false; + } + *size = data_size; + return true; +} + +///////////////////////////////////////////////////////////////////// +// Implementation of class VideoCapturer +///////////////////////////////////////////////////////////////////// +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), + adapt_frame_drops_data_(kMaxAccumulatorSize), + effect_frame_drops_data_(kMaxAccumulatorSize), + frame_time_data_(kMaxAccumulatorSize) { + Construct(); +} + +void VideoCapturer::Construct() { + ClearAspectRatio(); + enable_camera_list_ = false; + square_pixel_aspect_ratio_ = false; + capture_state_ = CS_STOPPED; + SignalFrameCaptured.connect(this, &VideoCapturer::OnFrameCaptured); + scaled_width_ = 0; + scaled_height_ = 0; + 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* VideoCapturer::GetSupportedFormats() const { + return &filtered_supported_formats_; +} + +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) { + return false; + } + if (result == CS_RUNNING) { + SetCaptureState(result); + } + return true; +} + +void VideoCapturer::UpdateAspectRatio(int ratio_w, int ratio_h) { + if (ratio_w == 0 || ratio_h == 0) { + LOG(LS_WARNING) << "UpdateAspectRatio ignored invalid ratio: " + << ratio_w << "x" << ratio_h; + return; + } + ratio_w_ = ratio_w; + ratio_h_ = ratio_h; +} + +void VideoCapturer::ClearAspectRatio() { + ratio_w_ = 0; + ratio_h_ = 0; +} + +// Override this to have more control of how your device is started/stopped. +bool VideoCapturer::Pause(bool pause) { + if (pause) { + if (capture_state() == CS_PAUSED) { + return true; + } + bool is_running = capture_state() == CS_STARTING || + capture_state() == CS_RUNNING; + if (!is_running) { + LOG(LS_ERROR) << "Cannot pause a stopped camera."; + return false; + } + LOG(LS_INFO) << "Pausing a camera."; + talk_base::scoped_ptr capture_format_when_paused( + capture_format_ ? new VideoFormat(*capture_format_) : NULL); + Stop(); + SetCaptureState(CS_PAUSED); + // If you override this function be sure to restore the capture format + // after calling Stop(). + SetCaptureFormat(capture_format_when_paused.get()); + } else { // Unpause. + if (capture_state() != CS_PAUSED) { + LOG(LS_WARNING) << "Cannot unpause a camera that hasn't been paused."; + return false; + } + if (!capture_format_) { + LOG(LS_ERROR) << "Missing capture_format_, cannot unpause a camera."; + return false; + } + if (muted_) { + LOG(LS_WARNING) << "Camera cannot be unpaused while muted."; + return false; + } + LOG(LS_INFO) << "Unpausing a camera."; + if (!Start(*capture_format_)) { + LOG(LS_ERROR) << "Camera failed to start when unpausing."; + return false; + } + } + return true; +} + +bool VideoCapturer::Restart(const VideoFormat& capture_format) { + if (!IsRunning()) { + return StartCapturing(capture_format); + } + + if (GetCaptureFormat() != NULL && *GetCaptureFormat() == capture_format) { + // The reqested format is the same; nothing to do. + return true; + } + + Stop(); + return StartCapturing(capture_format); +} + +bool VideoCapturer::MuteToBlackThenPause(bool muted) { + if (muted == IsMuted()) { + return true; + } + + LOG(LS_INFO) << (muted ? "Muting" : "Unmuting") << " this video capturer."; + muted_ = muted; // Do this before calling Pause(). + if (muted) { + // Reset black frame count down. + black_frame_count_down_ = kNumBlackFramesOnMute; + // Following frames will be overritten with black, then the camera will be + // paused. + return true; + } + // Start the camera. + thread_->Clear(this, MSG_DO_PAUSE); + return Pause(false); +} + +void VideoCapturer::SetSupportedFormats( + const std::vector& formats) { + supported_formats_ = formats; + UpdateFilteredSupportedFormats(); +} + +bool VideoCapturer::GetBestCaptureFormat(const VideoFormat& format, + VideoFormat* best_format) { + // TODO(fbarchard): Directly support max_format. + UpdateFilteredSupportedFormats(); + const std::vector* supported_formats = GetSupportedFormats(); + + if (supported_formats->empty()) { + return false; + } + LOG(LS_INFO) << " Capture Requested " << format.ToString(); + int64 best_distance = kMaxDistance; + std::vector::const_iterator best = supported_formats->end(); + std::vector::const_iterator i; + for (i = supported_formats->begin(); i != supported_formats->end(); ++i) { + int64 distance = GetFormatDistance(format, *i); + // TODO(fbarchard): Reduce to LS_VERBOSE if/when camera capture is + // relatively bug free. + LOG(LS_INFO) << " Supported " << i->ToString() << " distance " << distance; + if (distance < best_distance) { + best_distance = distance; + best = i; + } + } + if (supported_formats->end() == best) { + LOG(LS_ERROR) << " No acceptable camera format found"; + return false; + } + + if (best_format) { + best_format->width = best->width; + best_format->height = best->height; + best_format->fourcc = best->fourcc; + best_format->interval = best->interval; + LOG(LS_INFO) << " Best " << best_format->ToString() << " Interval " + << best_format->interval << " distance " << best_distance; + } + return true; +} + +void VideoCapturer::AddVideoProcessor(VideoProcessor* video_processor) { + talk_base::CritScope cs(&crit_); + ASSERT(std::find(video_processors_.begin(), video_processors_.end(), + video_processor) == video_processors_.end()); + video_processors_.push_back(video_processor); +} + +bool VideoCapturer::RemoveVideoProcessor(VideoProcessor* video_processor) { + talk_base::CritScope cs(&crit_); + VideoProcessors::iterator found = std::find( + video_processors_.begin(), video_processors_.end(), video_processor); + if (found == video_processors_.end()) { + return false; + } + video_processors_.erase(found); + return true; +} + +void VideoCapturer::ConstrainSupportedFormats(const VideoFormat& max_format) { + max_format_.reset(new VideoFormat(max_format)); + LOG(LS_VERBOSE) << " ConstrainSupportedFormats " << max_format.ToString(); + UpdateFilteredSupportedFormats(); +} + +std::string VideoCapturer::ToString(const CapturedFrame* captured_frame) const { + std::string fourcc_name = GetFourccName(captured_frame->fourcc) + " "; + for (std::string::const_iterator i = fourcc_name.begin(); + i < fourcc_name.end(); ++i) { + // Test character is printable; Avoid isprint() which asserts on negatives. + if (*i < 32 || *i >= 127) { + fourcc_name = ""; + break; + } + } + + std::ostringstream ss; + ss << fourcc_name << captured_frame->width << "x" << captured_frame->height + << "x" << VideoFormat::IntervalToFpsFloat(captured_frame->elapsed_time); + return ss.str(); +} + +void VideoCapturer::GetStats(VariableInfo* adapt_drops_stats, + VariableInfo* effect_drops_stats, + VariableInfo* 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_) { + if (black_frame_count_down_ == 0) { + thread_->Post(this, MSG_DO_PAUSE, NULL); + } else { + --black_frame_count_down_; + } + } + + if (SignalVideoFrame.is_empty()) { + return; + } +#if defined(HAVE_WEBRTC_VIDEO) +#define VIDEO_FRAME_NAME WebRtcVideoFrame +#endif +#if defined(VIDEO_FRAME_NAME) +#if !defined(DISABLE_YUV) + if (IsScreencast()) { + int scaled_width, scaled_height; + if (screencast_max_pixels_ > 0) { + ComputeScaleMaxPixels(captured_frame->width, captured_frame->height, + screencast_max_pixels_, &scaled_width, &scaled_height); + } else { + int desired_screencast_fps = capture_format_.get() ? + VideoFormat::IntervalToFps(capture_format_->interval) : + kDefaultScreencastFps; + ComputeScale(captured_frame->width, captured_frame->height, + desired_screencast_fps, &scaled_width, &scaled_height); + } + + if (FOURCC_ARGB == captured_frame->fourcc && + (scaled_width != captured_frame->width || + scaled_height != captured_frame->height)) { + if (scaled_width != scaled_width_ || scaled_height != scaled_height_) { + LOG(LS_INFO) << "Scaling Screencast from " + << captured_frame->width << "x" + << captured_frame->height << " to " + << scaled_width << "x" << scaled_height; + scaled_width_ = scaled_width; + scaled_height_ = scaled_height; + } + CapturedFrame* modified_frame = + const_cast(captured_frame); + // Compute new width such that width * height is less than maximum but + // maintains original captured frame aspect ratio. + // Round down width to multiple of 4 so odd width won't round up beyond + // maximum, and so chroma channel is even width to simplify spatial + // resampling. + libyuv::ARGBScale(reinterpret_cast(captured_frame->data), + captured_frame->width * 4, captured_frame->width, + captured_frame->height, + reinterpret_cast(modified_frame->data), + scaled_width * 4, scaled_width, scaled_height, + libyuv::kFilterBilinear); + modified_frame->width = scaled_width; + modified_frame->height = scaled_height; + modified_frame->data_size = scaled_width * 4 * scaled_height; + } + } + + const int kYuy2Bpp = 2; + const int kArgbBpp = 4; + // TODO(fbarchard): Make a helper function to adjust pixels to square. + // TODO(fbarchard): Hook up experiment to scaling. + // TODO(fbarchard): Avoid scale and convert if muted. + // Temporary buffer is scoped here so it will persist until i420_frame.Init() + // makes a copy of the frame, converting to I420. + talk_base::scoped_ptr temp_buffer; + // YUY2 can be scaled vertically using an ARGB scaler. Aspect ratio is only + // a problem on OSX. OSX always converts webcams to YUY2 or UYVY. + bool can_scale = + FOURCC_YUY2 == CanonicalFourCC(captured_frame->fourcc) || + FOURCC_UYVY == CanonicalFourCC(captured_frame->fourcc); + + // If pixels are not square, optionally use vertical scaling to make them + // square. Square pixels simplify the rest of the pipeline, including + // effects and rendering. + if (can_scale && square_pixel_aspect_ratio_ && + captured_frame->pixel_width != captured_frame->pixel_height) { + int scaled_width, scaled_height; + // modified_frame points to the captured_frame but with const casted away + // so it can be modified. + CapturedFrame* modified_frame = const_cast(captured_frame); + // Compute the frame size that makes pixels square pixel aspect ratio. + ComputeScaleToSquarePixels(captured_frame->width, captured_frame->height, + captured_frame->pixel_width, + captured_frame->pixel_height, + &scaled_width, &scaled_height); + + if (scaled_width != scaled_width_ || scaled_height != scaled_height_) { + LOG(LS_INFO) << "Scaling WebCam from " + << captured_frame->width << "x" + << captured_frame->height << " to " + << scaled_width << "x" << scaled_height + << " for PAR " + << captured_frame->pixel_width << "x" + << captured_frame->pixel_height; + scaled_width_ = scaled_width; + scaled_height_ = scaled_height; + } + const int modified_frame_size = scaled_width * scaled_height * kYuy2Bpp; + uint8* temp_buffer_data; + // Pixels are wide and short; Increasing height. Requires temporary buffer. + if (scaled_height > captured_frame->height) { + temp_buffer.reset(new uint8[modified_frame_size]); + temp_buffer_data = temp_buffer.get(); + } else { + // Pixels are narrow and tall; Decreasing height. Scale will be done + // in place. + temp_buffer_data = reinterpret_cast(captured_frame->data); + } + + // Use ARGBScaler to vertically scale the YUY2 image, adjusting for 16 bpp. + libyuv::ARGBScale(reinterpret_cast(captured_frame->data), + captured_frame->width * kYuy2Bpp, // Stride for YUY2. + captured_frame->width * kYuy2Bpp / kArgbBpp, // Width. + abs(captured_frame->height), // Height. + temp_buffer_data, + scaled_width * kYuy2Bpp, // Stride for YUY2. + scaled_width * kYuy2Bpp / kArgbBpp, // Width. + abs(scaled_height), // New height. + libyuv::kFilterBilinear); + modified_frame->width = scaled_width; + modified_frame->height = scaled_height; + modified_frame->pixel_width = 1; + modified_frame->pixel_height = 1; + modified_frame->data_size = modified_frame_size; + modified_frame->data = temp_buffer_data; + } +#endif // !DISABLE_YUV + + // Size to crop captured frame to. This adjusts the captured frames + // aspect ratio to match the final view aspect ratio, considering pixel + // aspect ratio and rotation. The final size may be scaled down by video + // adapter to better match ratio_w_ x ratio_h_. + // Note that abs() of frame height is passed in, because source may be + // inverted, but output will be positive. + int desired_width = captured_frame->width; + int desired_height = captured_frame->height; + + // TODO(fbarchard): Improve logic to pad or crop. + // MJPG can crop vertically, but not horizontally. This logic disables crop. + // Alternatively we could pad the image with black, or implement a 2 step + // crop. + bool can_crop = true; + if (captured_frame->fourcc == FOURCC_MJPG) { + float cam_aspect = static_cast(captured_frame->width) / + static_cast(captured_frame->height); + float view_aspect = static_cast(ratio_w_) / + static_cast(ratio_h_); + can_crop = cam_aspect <= view_aspect; + } + if (can_crop && !IsScreencast()) { + // TODO(ronghuawu): The capturer should always produce the native + // resolution and the cropping should be done in downstream code. + ComputeCrop(ratio_w_, ratio_h_, captured_frame->width, + abs(captured_frame->height), captured_frame->pixel_width, + captured_frame->pixel_height, captured_frame->rotation, + &desired_width, &desired_height); + } + + VIDEO_FRAME_NAME i420_frame; + if (!i420_frame.Alias(captured_frame, desired_width, desired_height)) { + // TODO(fbarchard): LOG more information about captured frame attributes. + LOG(LS_ERROR) << "Couldn't convert to I420! " + << "From " << ToString(captured_frame) << " To " + << desired_width << " x " << desired_height; + return; + } + + VideoFrame* adapted_frame = &i420_frame; + if (enable_video_adapter_ && !IsScreencast()) { + VideoFrame* out_frame = NULL; + video_adapter_.AdaptFrame(adapted_frame, &out_frame); + if (!out_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 +} + +void VideoCapturer::SetCaptureState(CaptureState state) { + if (state == capture_state_) { + // Don't trigger a state changed callback if the state hasn't changed. + return; + } + StateChangeParams* state_params = new StateChangeParams(state); + capture_state_ = state; + thread_->Post(this, MSG_STATE_CHANGE, state_params); +} + +void VideoCapturer::OnMessage(talk_base::Message* message) { + switch (message->message_id) { + case MSG_STATE_CHANGE: { + talk_base::scoped_ptr p( + static_cast(message->pdata)); + SignalStateChange(this, p->data()); + break; + } + case MSG_DO_PAUSE: { + Pause(true); + break; + } + case MSG_DO_UNPAUSE: { + Pause(false); + break; + } + default: { + ASSERT(false); + } + } +} + +// Get the distance between the supported and desired formats. +// Prioritization is done according to this algorithm: +// 1) Width closeness. If not same, we prefer wider. +// 2) Height closeness. If not same, we prefer higher. +// 3) Framerate closeness. If not same, we prefer faster. +// 4) Compression. If desired format has a specific fourcc, we need exact match; +// otherwise, we use preference. +int64 VideoCapturer::GetFormatDistance(const VideoFormat& desired, + const VideoFormat& supported) { + int64 distance = kMaxDistance; + + // Check fourcc. + uint32 supported_fourcc = CanonicalFourCC(supported.fourcc); + int64 delta_fourcc = kMaxDistance; + if (FOURCC_ANY == desired.fourcc) { + // Any fourcc is OK for the desired. Use preference to find best fourcc. + std::vector preferred_fourccs; + if (!GetPreferredFourccs(&preferred_fourccs)) { + return distance; + } + + for (size_t i = 0; i < preferred_fourccs.size(); ++i) { + if (supported_fourcc == CanonicalFourCC(preferred_fourccs[i])) { + delta_fourcc = i; +#ifdef LINUX + // For HD avoid YU12 which is a software conversion and has 2 bugs + // b/7326348 b/6960899. Reenable when fixed. + if (supported.height >= 720 && (supported_fourcc == FOURCC_YU12 || + supported_fourcc == FOURCC_YV12)) { + delta_fourcc += kYU12Penalty; + } +#endif + break; + } + } + } else if (supported_fourcc == CanonicalFourCC(desired.fourcc)) { + delta_fourcc = 0; // Need exact match. + } + + if (kMaxDistance == delta_fourcc) { + // Failed to match fourcc. + return distance; + } + + // Check resolution and fps. + int desired_width = desired.width; + int desired_height = desired.height; + int64 delta_w = supported.width - desired_width; + 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 + : desired_height; + int64 delta_h = supported.height - aspect_h; + + distance = 0; + // Set high penalty if the supported format is lower than the desired format. + // 3x means we would prefer down to down to 3/4, than up to double. + // But we'd prefer up to double than down to 1/2. This is conservative, + // strongly avoiding going down in resolution, similar to + // the old method, but not completely ruling it out in extreme situations. + // It also ignores framerate, which is often very low at high resolutions. + // TODO(fbarchard): Improve logic to use weighted factors. + static const int kDownPenalty = -3; + if (delta_w < 0) { + delta_w = delta_w * kDownPenalty; + } + if (delta_h < 0) { + delta_h = delta_h * kDownPenalty; + } + // Require camera fps to be at least 80% of what is requested if resolution + // matches. + // 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) { + 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(1) << 62; + } else { + distance |= static_cast(1) << 15; + } + } + int64 idelta_fps = static_cast(delta_fps); + + // 12 bits for width and height and 8 bits for fps and fourcc. + distance |= + (delta_w << 28) | (delta_h << 16) | (idelta_fps << 8) | delta_fourcc; + + return distance; +} + +bool VideoCapturer::ApplyProcessors(VideoFrame* video_frame) { + bool drop_frame = false; + talk_base::CritScope cs(&crit_); + for (VideoProcessors::iterator iter = video_processors_.begin(); + iter != video_processors_.end(); ++iter) { + (*iter)->OnFrame(kDummyVideoSsrc, video_frame, &drop_frame); + if (drop_frame) { + return false; + } + } + return true; +} + +void VideoCapturer::UpdateFilteredSupportedFormats() { + filtered_supported_formats_.clear(); + filtered_supported_formats_ = supported_formats_; + if (!max_format_) { + return; + } + std::vector::iterator iter = filtered_supported_formats_.begin(); + while (iter != filtered_supported_formats_.end()) { + if (ShouldFilterFormat(*iter)) { + iter = filtered_supported_formats_.erase(iter); + } else { + ++iter; + } + } + if (filtered_supported_formats_.empty()) { + // The device only captures at resolutions higher than |max_format_| this + // indicates that |max_format_| should be ignored as it is better to capture + // at too high a resolution than to not capture at all. + filtered_supported_formats_ = supported_formats_; + } +} + +bool VideoCapturer::ShouldFilterFormat(const VideoFormat& format) const { + if (!enable_camera_list_) { + return false; + } + return format.width > max_format_->width || + 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 +void VideoCapturer::GetVariableSnapshot( + const talk_base::RollingAccumulator& data, + VariableInfo* stats) { + stats->max_val = data.ComputeMax(); + stats->mean = data.ComputeMean(); + stats->min_val = data.ComputeMin(); + stats->variance = data.ComputeVariance(); +} + +} // namespace cricket diff --git a/common/resource.h b/common/resource.h new file mode 100755 index 0000000..dafbd74 --- /dev/null +++ b/common/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by webrtc-everywhere-common.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/common/webrtc-everywhere-common.aps b/common/webrtc-everywhere-common.aps new file mode 100644 index 0000000000000000000000000000000000000000..ed0fc4bef58c1fd004686736e057cdb6a7f92191 GIT binary patch literal 2624 zcmb7G&5qMn6#i0DiPAwuty;m(&{@DDsRILr5o(pOJ;ji*M|LJK)kuc%n3+MDWaK2I zya9_Y`yed4>Ava{RNbLIK;NM0cdq03I;MkgWc%K8zVma>z2|cPz~DWbWjBYV%i(O5 z_X9k}2H&$;ZLVLb&j)yY9G2USHQ zQ#8|9e7)sej`h0=VWNn2RY|TQO-92>8Yj&oFrlcu9Y&t>q#FfJ=+7Oa->;qI1`n~V1qAkS%fJYZTXqgpSFdQK3! zz8AUPrjHgrN6odZDD1You7&H3)(tdJQ?~N_n;S5{Hu)~s;SZ(J>(J$5UC-+5*j%L2 zu5xd5>CJaaZ!M&P2ma!`9P1m_6EH6oHMg*iJ!~Vz5HFA*#uy_?rX256I;Nz-@k`z* zUQvFeMhP)7ZBF*osb1oCZ3OPvys*DLx+`B;s;J=8~0>2YmHj`)sFm`>&4&aes1< z7}xTyzIKs3fphQmB?$J9##y#63F()`>XAaokp6bv08j5a2wDiap7$Y2IL*JP8+ehdFd9{$``c1QBa*PPc6 z6|ODkBYTwb^8wjT_}QCRUSgE@sEk|Qqcv5>GG@7&%eAx_qsCMFjH}2qFHV;5UR`A& z%s$|*^!e8Jd!_!S{tFLtnIDT&oR6f}CDvL0Mcz{Xri7{fhmh~b_nnPT*6d&U-<1$mgqzHO*rlH$7k7ORnvJ$nCak5n<{q+;k~BK H|MAv;&2p~j literal 0 HcmV?d00001 diff --git a/common/webrtc-everywhere-common.rc b/common/webrtc-everywhere-common.rc new file mode 100644 index 0000000000000000000000000000000000000000..7eef383ab58cee7acf13bcb74e9ea6afdfdbd610 GIT binary patch literal 4588 zcmdUz+fEx-6o%JrD&-xf=7uN<*uV>bZ78b22-}oONC@x&OTXv?1@p`-t$B@vVl!_ zXUs2X`^?Q~MYp8)KtEz6Zex39&yKydpOCWa+AU@$tUj^3@Ag)5^gH%w6}MZITW;Ub z(TVq=U0BDu*0YA4TH9{z(wfXR=$~85erKk`@0lGj)1n{b3&Z9;0bOV#JHaliHXdT7 zseMBK1=f)rx@djP?(Np$lGQY>W>XCo;!Hcu6r_0)Z^DGt+`RG_;D@D=}z1NG4 zVEMpzv)X_zvSa60WzQqJZoBcF%cg<7EAaX}l|y4^pPw_i)Q86*T(09B>X0uzvZ+oS z-4abL9`XH~Cn}}v!sC*dy@k^y{dZ1ki{3f2J=zl&mtn^5Yr3fY#Xi8f!>%J_d5Y}1 zwD*3N2IYQM7F>b zwIhv22sI9^PI#T;b2Ogfk1!uJxgsxb+0!JeJMN@CXDrQ+$um)>SHirgRjE$N=jO_u z$ZF(!HGXSOV#H~F3BLw4pibmvxfW9d?#HfXoPh3(+R-8RBe?%*`*^VBxGO4?s-c?J zq|)@rk}S@Iljl(TMnB-DGRID@@2{rz>ok(oEJYi9p7#M5^&G@BiM6`iS}s87_wD7@ zeVxqi3X+R+Usbh@U1gaH2p0HT_pcEi8l%|&KTW_oUCG8`ZXqkOT%}2sGfC||zuCM_ zXwtRmjlIFshoI{@eJfzp?dF+V<;4CX#_kvm;HC3H$nQX|wLbesyvtZlo>S1Q0e$)& z>Z3ex{EgLnBCm_&2)VkCj+|{GXO9`Pk~(yf#}3CSScRv~`Ri|E12=9%?{CCWj8Q%v zvq!g*DG}*yQjRs7i2-AcyK^;uYo$C|NEspb$=UE3>&eF>FfO3+_S?okI?4CoSHn+U zw^fVoFt2L&#G^Z8;4*h3SyNj6!EYZ_WjZOM^kp!k6{=NVzOZ)B>H5JbC)GzK{ zE1P{}MbYqy-wBfX4pEuBHq=6@xR$)&e~r>H^k2)pK<*T5OVBQIT4v*`S)ipVUlMg? z+GVBu`#1@C7uw{MFQ3Wg^%eG;eY55|bt0SLUAQTO=V+~O$8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/webrtc-everywhere-common.vcxproj b/common/webrtc-everywhere-common.vcxproj new file mode 100644 index 0000000..d122a23 --- /dev/null +++ b/common/webrtc-everywhere-common.vcxproj @@ -0,0 +1,147 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {95230956-8581-4F03-A589-C6217119DE9E} + webrtceverywherecommon + Win32Proj + + + + DynamicLibrary + v120 + Unicode + true + + + DynamicLibrary + v120 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;../thirdparties/win32/include;../thirdparties\common\include\webrtc-sdk;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;_USRDLL;WEBRTC_EVERYWHERE_EXPORTS;V8_DEPRECATION_WARNINGS;BLINK_SCALE_FILTERS_AT_RECORD_TIME;EXPAT_RELATIVE_PATH;FEATURE_ENABLE_VOICEMAIL;GTEST_RELATIVE_PATH;LOGGING=1;SRTP_RELATIVE_PATH;FEATURE_ENABLE_SSL;FEATURE_ENABLE_PSTN;HAVE_SRTP;HAVE_WEBRTC_VIDEO;HAVE_WEBRTC_VOICE;USE_WEBRTC_DEV_BRANCH;_WIN32_WINNT=0x0602;WINVER=0x0602;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;USE_AURA=1;USE_ASH=1;USE_DEFAULT_RENDER_THEME=1;USE_LIBJPEG_TURBO=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_PEPPER_CDMS;ENABLE_CONFIGURATION_POLICY;ENABLE_NOTIFICATIONS;ENABLE_HIDPI=1;ENABLE_EGLIMAGE=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;NTDDI_VERSION=0x06020000;_USING_V110_SDK71_;ENABLE_TASK_MANAGER=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PLUGINS=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_AUTOFILL_DIALOG=1;ENABLE_BACKGROUND=1;ENABLE_GOOGLE_NOW=1;CLD_VERSION=2;ENABLE_FULL_PRINTING=1;ENABLE_PRINTING=1;WIN_PDF_METAFILE_FOR_PRINTING=1;ENABLE_SPELLCHECK=1;ENABLE_CAPTIVE_PORTAL_DETECTION=1;ENABLE_APP_LIST=1;ENABLE_SETTINGS_APP=1;ENABLE_MANAGED_USERS=1;ENABLE_MDNS=1;ENABLE_SERVICE_DISCOVERY=1;ENABLE_WIFI_BOOTSTRAPPING=1;LIBPEERCONNECTION_LIB=1;HAVE_SCTP;SSL_USE_NSS;HAVE_NSS_SSL_H;SSL_USE_NSS_RNG;NSS_PLATFORM_CLIENT_AUTH;NO_NSPR_10_SUPPORT;NSPR_STATIC;NSS_STATIC;NSS_USE_STATIC_LIBS;USE_UTIL_DIRECTLY;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + true + EditAndContinue + /MP %(AdditionalOptions) + + + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat /largeaddressaware %(AdditionalOptions) + wininet.lib;dnsapi.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;winmm.lib;shlwapi.lib;kernel32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib;odbc32.lib;odbccp32.lib;delayimp.lib;credui.lib;netapi32.lib;Strmiids.lib;crypt32.lib;iphlpapi.lib;secur32.lib;dmoguids.lib;wmcodecdspuuid.lib;amstrmid.lib;msdmo.lib;crssl.lib;crnspr.lib;crnss.lib;jsoncpp.lib;libjingle_peerconnection.lib;nss_static.lib;sqlite3.lib;icui18n.lib;icuuc.lib;icudata.lib;libjingle.lib;expat.lib;libjingle_media.lib;libyuv.lib;libjpeg.lib;usrsctplib.lib;video_capture_module.lib;webrtc_utility.lib;audio_coding_module.lib;CNG.lib;common_audio.lib;system_wrappers.lib;webrtc_base.lib;common_audio_sse2.lib;G711.lib;G722.lib;iLBC.lib;iSAC.lib;iSACFix.lib;PCM16B.lib;webrtc_opus.lib;opus.lib;NetEq4.lib;media_file.lib;webrtc_video_coding.lib;webrtc_i420.lib;common_video.lib;video_coding_utility.lib;webrtc_vp8.lib;libvpx.lib;libvpx_asm_offsets_vp8.lib;libvpx_intrinsics_mmx.lib;libvpx_intrinsics_sse2.lib;libvpx_intrinsics_ssse3.lib;directshow_baseclasses.lib;video_render_module.lib;webrtc.lib;webrtc_common.lib;video_engine_core.lib;rtp_rtcp.lib;paced_sender.lib;remote_bitrate_estimator.lib;rbe_components.lib;bitrate_controller.lib;video_processing.lib;video_processing_sse2.lib;voice_engine.lib;audio_conference_mixer.lib;audio_processing.lib;audioproc_debug_proto.lib;protobuf_lite.lib;audio_processing_sse2.lib;audio_device.lib;field_trial_default.lib;libjingle_sound.lib;libjingle_p2p.lib;libsrtp.lib;%(AdditionalDependencies) + ../thirdparties\win32\lib\debug;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + 5.01 + false + %(DelayLoadDLLs) + libcmtd.lib + + + + + MaxSpeed + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;WEBRTC_EVERYWHERE_EXPORTS;V8_DEPRECATION_WARNINGS;BLINK_SCALE_FILTERS_AT_RECORD_TIME;EXPAT_RELATIVE_PATH;FEATURE_ENABLE_VOICEMAIL;GTEST_RELATIVE_PATH;LOGGING=1;SRTP_RELATIVE_PATH;FEATURE_ENABLE_SSL;FEATURE_ENABLE_PSTN;HAVE_SRTP;HAVE_WEBRTC_VIDEO;HAVE_WEBRTC_VOICE;USE_WEBRTC_DEV_BRANCH;_WIN32_WINNT=0x0602;WINVER=0x0602;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;USE_AURA=1;USE_ASH=1;USE_DEFAULT_RENDER_THEME=1;USE_LIBJPEG_TURBO=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_PEPPER_CDMS;ENABLE_CONFIGURATION_POLICY;ENABLE_NOTIFICATIONS;ENABLE_HIDPI=1;ENABLE_EGLIMAGE=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;NTDDI_VERSION=0x06020000;_USING_V110_SDK71_;ENABLE_TASK_MANAGER=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PLUGINS=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_AUTOFILL_DIALOG=1;ENABLE_BACKGROUND=1;ENABLE_GOOGLE_NOW=1;CLD_VERSION=2;ENABLE_FULL_PRINTING=1;ENABLE_PRINTING=1;WIN_PDF_METAFILE_FOR_PRINTING=1;ENABLE_SPELLCHECK=1;ENABLE_CAPTIVE_PORTAL_DETECTION=1;ENABLE_APP_LIST=1;ENABLE_SETTINGS_APP=1;ENABLE_MANAGED_USERS=1;ENABLE_MDNS=1;ENABLE_SERVICE_DISCOVERY=1;ENABLE_WIFI_BOOTSTRAPPING=1;LIBPEERCONNECTION_LIB=1;HAVE_SCTP;SSL_USE_NSS;HAVE_NSS_SSL_H;SSL_USE_NSS_RNG;NSS_PLATFORM_CLIENT_AUTH;NO_NSPR_10_SUPPORT;NSPR_STATIC;NSS_STATIC;NSS_USE_STATIC_LIBS;USE_UTIL_DIRECTLY;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + true + ProgramDatabase + .;../thirdparties/win32/include;../thirdparties\common\include\webrtc-sdk;%(AdditionalIncludeDirectories) + + + true + Windows + true + true + MachineX86 + 5.01 + wininet.lib;dnsapi.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;winmm.lib;shlwapi.lib;kernel32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib;odbc32.lib;odbccp32.lib;delayimp.lib;credui.lib;netapi32.lib;Strmiids.lib;crypt32.lib;iphlpapi.lib;secur32.lib;dmoguids.lib;wmcodecdspuuid.lib;amstrmid.lib;msdmo.lib;crssl.lib;crnspr.lib;crnss.lib;jsoncpp.lib;libjingle_peerconnection.lib;nss_static.lib;sqlite3.lib;icui18n.lib;icuuc.lib;icudata.lib;libjingle.lib;expat.lib;libjingle_media.lib;libyuv.lib;libjpeg.lib;usrsctplib.lib;video_capture_module.lib;webrtc_utility.lib;audio_coding_module.lib;CNG.lib;common_audio.lib;system_wrappers.lib;webrtc_base.lib;common_audio_sse2.lib;G711.lib;G722.lib;iLBC.lib;iSAC.lib;iSACFix.lib;PCM16B.lib;webrtc_opus.lib;opus.lib;NetEq4.lib;media_file.lib;webrtc_video_coding.lib;webrtc_i420.lib;common_video.lib;video_coding_utility.lib;webrtc_vp8.lib;libvpx.lib;libvpx_asm_offsets_vp8.lib;libvpx_intrinsics_mmx.lib;libvpx_intrinsics_sse2.lib;libvpx_intrinsics_ssse3.lib;directshow_baseclasses.lib;video_render_module.lib;webrtc.lib;webrtc_common.lib;video_engine_core.lib;rtp_rtcp.lib;paced_sender.lib;remote_bitrate_estimator.lib;rbe_components.lib;bitrate_controller.lib;video_processing.lib;video_processing_sse2.lib;voice_engine.lib;audio_conference_mixer.lib;audio_processing.lib;audioproc_debug_proto.lib;protobuf_lite.lib;audio_processing_sse2.lib;audio_device.lib;field_trial_default.lib;libjingle_sound.lib;libjingle_p2p.lib;libsrtp.lib;%(AdditionalDependencies) + dbghelp.dll;dwmapi.dll;shell32.dll;uxtheme.dll;%(DelayLoadDLLs) + ../thirdparties\win32\lib;%(AdditionalLibraryDirectories) + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/common/webrtc-everywhere-common.vcxproj.filters b/common/webrtc-everywhere-common.vcxproj.filters new file mode 100644 index 0000000..01bbb6d --- /dev/null +++ b/common/webrtc-everywhere-common.vcxproj.filters @@ -0,0 +1,119 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/common/webrtc-everywhere-console.vcxproj b/common/webrtc-everywhere-console.vcxproj new file mode 100644 index 0000000..e0436c7 --- /dev/null +++ b/common/webrtc-everywhere-console.vcxproj @@ -0,0 +1,94 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {A5BD8595-2B82-42E3-90E8-4405D6425A29} + Win32Proj + webrtceverywhereconsole + + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;WE_DEBUG_LEVEL=WE_DEBUG_LEVEL_INFO;V8_DEPRECATION_WARNINGS;BLINK_SCALE_FILTERS_AT_RECORD_TIME;EXPAT_RELATIVE_PATH;FEATURE_ENABLE_VOICEMAIL;GTEST_RELATIVE_PATH;LOGGING=1;SRTP_RELATIVE_PATH;FEATURE_ENABLE_SSL;FEATURE_ENABLE_PSTN;HAVE_SRTP;HAVE_WEBRTC_VIDEO;HAVE_WEBRTC_VOICE;USE_WEBRTC_DEV_BRANCH;_WIN32_WINNT=0x0602;WINVER=0x0602;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;USE_AURA=1;USE_ASH=1;USE_DEFAULT_RENDER_THEME=1;USE_LIBJPEG_TURBO=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_PEPPER_CDMS;ENABLE_CONFIGURATION_POLICY;ENABLE_NOTIFICATIONS;ENABLE_HIDPI=1;ENABLE_EGLIMAGE=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;NTDDI_VERSION=0x06020000;_USING_V110_SDK71_;ENABLE_TASK_MANAGER=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PLUGINS=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_AUTOFILL_DIALOG=1;ENABLE_BACKGROUND=1;ENABLE_GOOGLE_NOW=1;CLD_VERSION=2;ENABLE_FULL_PRINTING=1;ENABLE_PRINTING=1;WIN_PDF_METAFILE_FOR_PRINTING=1;ENABLE_SPELLCHECK=1;ENABLE_CAPTIVE_PORTAL_DETECTION=1;ENABLE_APP_LIST=1;ENABLE_SETTINGS_APP=1;ENABLE_MANAGED_USERS=1;ENABLE_MDNS=1;ENABLE_SERVICE_DISCOVERY=1;ENABLE_WIFI_BOOTSTRAPPING=1;LIBPEERCONNECTION_LIB=1;HAVE_SCTP;SSL_USE_NSS;HAVE_NSS_SSL_H;SSL_USE_NSS_RNG;NSS_PLATFORM_CLIENT_AUTH;NO_NSPR_10_SUPPORT;NSPR_STATIC;NSS_STATIC;NSS_USE_STATIC_LIBS;USE_UTIL_DIRECTLY;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions) + .;../thirdparties/win32/include;../thirdparties\common\include\webrtc-sdk;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Console + true + $(OutDir)webrtc-everywhere-common.lib;%(AdditionalDependencies) + + + ../thirdparties\win32\lib\debug;%(AdditionalLibraryDirectories) + 5.01 + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + .;../thirdparties/win32/include;../thirdparties\common\include\webrtc-sdk;%(AdditionalIncludeDirectories) + + + Console + true + true + true + 5.01 + $(OutDir)webrtc-everywhere-common.lib;%(AdditionalDependencies) + + + + + + + + + \ No newline at end of file diff --git a/common/webrtc-everywhere-console.vcxproj.filters b/common/webrtc-everywhere-console.vcxproj.filters new file mode 100644 index 0000000..53a531a --- /dev/null +++ b/common/webrtc-everywhere-console.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/git.exe.stackdump b/git.exe.stackdump new file mode 100644 index 0000000..bd94d66 --- /dev/null +++ b/git.exe.stackdump @@ -0,0 +1,28 @@ +Exception: STATUS_ACCESS_VIOLATION at rip=00597FD8362 +rax=000000000000F7FA rbx=00000000FF82D000 rcx=000006FF0570FFC1 +rdx=0000000000000010 rsi=0000000000000041 rdi=000006FF05A0E871 +r8 =000006FF0570FFFE r9 =0000000000000001 r10=000000060005EDE0 +r11=000000060005E890 r12=000006FF05710001 r13=000006FF0570FFC4 +r14=0000000000237460 r15=000006FF057044E0 +rbp=000000060005F930 rsp=0000000000237260 +program=C:\cygwin64\lib\git-core\git.exe, pid 8740, thread main +cs=0033 ds=002B es=002B fs=0053 gs=002B ss=002B +Stack trace: +Frame Function Args +0060005F930 00597FD8362 (00000237460, 006FFFFFFFF, 00000000000, 0060005E904) +0060005E918 00597FD9E8C (000017C45D2, 6FF03F40010, 001800C46CD, 00000237460) +00000000000 0010048A09A (000002374F0, 00000000000, 0018013DEE5, 00000002000) +000017C25E0 0010048F45D (00180135C7F, 00000000000, 00000000000, 006000AAEC0) +6FF05710000 0010048FDB0 (006000AA8C0, 006001BE6D0, 006001EA4B0, 006001EA4B0) +00000239658 00100490870 (00180173357, 00000000000, 0018016C19B, 00000000000) +006001EA4B0 0010044785B (0018011197B, 00000239774, 0018004345D, 00200001000) +00000239720 00100447B7E (0010046B4E9, 00000000004, 00000000032, 001004697A2) +00600051900 00100448523 (001800BFCE3, 00000000000, 001802E7CE6, 00000000000) +00000000000 00100401817 (00180161BBC, 001802BC4E0, 004E76B1459, 00100000006) +001802DEAE0 001004E9431 (0000023AB08, 001802E02A8, 0000023CCF0, 0000023AB90) +0000023AB90 0018004820B (00000000000, 00000000000, 00000000000, 00000000000) +00000000000 0018004611B (00000000000, 00000000000, 00000000000, 00000000000) +00000000000 00180046274 (00000000000, 00000000000, 00000000000, 00000000000) +00000000000 001004E83C1 (00000000000, 00000000000, 00000000000, 00000000000) +00000000000 00100401010 (00000000000, 00000000000, 00000000000, 00000000000) +End of stack trace (more stack frames may be present) diff --git a/ie/BrowserCallback.cc b/ie/BrowserCallback.cc new file mode 100644 index 0000000..db46b60 --- /dev/null +++ b/ie/BrowserCallback.cc @@ -0,0 +1,56 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "BrowserCallback.h" +#include "../common/_AsyncEvent.h" +#include "../common/_Debug.h" + +BrowserCallback::BrowserCallback(unsigned msgid, CComPtr disp) + : _BrowserCallback(msgid) + , m_disp(disp) + , m_params_count(0) +{ + +} + +BrowserCallback::~BrowserCallback() +{ + m_disp = NULL; + for (unsigned i = 0; i < m_params_count; ++i) { + m_params[i].Clear(); + } + WE_DEBUG_INFO("BrowserCallback::~BrowserCallback"); +} + +HRESULT BrowserCallback::AddDispatch(CComPtr obj) +{ + if ((m_params_count + 1) >= kMaxParamArgs) { + return E_BOUNDS; + } + m_params[m_params_count++] = obj; + return S_OK; +} + +HRESULT BrowserCallback::AddBSTR(const CComBSTR& bstr) +{ + if ((m_params_count + 1) >= kMaxParamArgs) { + return E_BOUNDS; + } + m_params[m_params_count++] = bstr; + return S_OK; +} + +// _BrowserCallback implementation +bool BrowserCallback::Invoke() +{ + if (!m_disp) { + WE_DEBUG_ERROR("No dispatcher"); + return false; + } + + DISPPARAMS params = { m_params, NULL, m_params_count, 0 }; + HRESULT hr = m_disp->Invoke(0, + IID_NULL, + LOCALE_USER_DEFAULT, + DISPATCH_METHOD, + ¶ms, NULL, NULL, NULL); + return SUCCEEDED(hr); +} diff --git a/ie/BrowserCallback.h b/ie/BrowserCallback.h new file mode 100644 index 0000000..eb5bbe3 --- /dev/null +++ b/ie/BrowserCallback.h @@ -0,0 +1,33 @@ +#pragma once + +#include "../common/_Config.h" +#include "../common/_Common.h" + +#if WE_UNDER_WINDOWS +# include +# include +# include +#endif + +class _AsyncEventToken; + +class BrowserCallback + : public _BrowserCallback +{ +public: + BrowserCallback(unsigned msgid, CComPtr disp); + virtual ~BrowserCallback(); + + BrowserObjectImpl_Inline(); + + HRESULT AddDispatch(CComPtr obj); + HRESULT AddBSTR(const CComBSTR& bstr); + + // _BrowserCallback implementation + virtual bool Invoke(); + +private: + CComPtr m_disp; + unsigned m_params_count; + CComVariant m_params[kMaxParamArgs]; +}; diff --git a/ie/Debug/webrtc-everywhere.res b/ie/Debug/webrtc-everywhere.res new file mode 100644 index 0000000000000000000000000000000000000000..633f67da3ab6b9aa0e2787ccdf7652c46be089c4 GIT binary patch literal 25628 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 */ + +#include "stdafx.h" +#include "DictOptions.h" + + +// CDictOptions + diff --git a/ie/DictOptions.h b/ie/DictOptions.h new file mode 100644 index 0000000..0437649 --- /dev/null +++ b/ie/DictOptions.h @@ -0,0 +1,49 @@ +/* Copyright(C) 2014 Sarandogou */ + +#pragma once +#include "resource.h" // main symbols + +#include "webrtceverywhere_i.h" + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + + + +// CDictOptions + +class ATL_NO_VTABLE CDictOptions : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CDictOptions() { + } + + DECLARE_REGISTRY_RESOURCEID(IDR_DICTOPTIONS) + + + BEGIN_COM_MAP(CDictOptions) + COM_INTERFACE_ENTRY(IDictOptions) + COM_INTERFACE_ENTRY(IDispatch) + END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct() { + return S_OK; + } + + void FinalRelease() { + } + +public: + +}; + +OBJECT_ENTRY_AUTO(__uuidof(DictOptions), CDictOptions) diff --git a/ie/DictOptions.rgs b/ie/DictOptions.rgs new file mode 100644 index 0000000..381b9f1 --- /dev/null +++ b/ie/DictOptions.rgs @@ -0,0 +1,26 @@ +HKCR +{ + webrtceverywhere.DictOptions.1 = s 'DictOptions Class' + { + CLSID = s '{D6B8C652-7A2A-47B6-8C38-3BD5BB0E2872}' + } + webrtceverywhere.DictOptions = s 'DictOptions Class' + { + CLSID = s '{D6B8C652-7A2A-47B6-8C38-3BD5BB0E2872}' + CurVer = s 'webrtceverywhere.DictOptions.1' + } + NoRemove CLSID + { + ForceRemove {D6B8C652-7A2A-47B6-8C38-3BD5BB0E2872} = s 'DictOptions Class' + { + ProgID = s 'webrtceverywhere.DictOptions.1' + VersionIndependentProgID = s 'webrtceverywhere.DictOptions' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + } + } +} diff --git a/ie/MediaSourceStates.cc b/ie/MediaSourceStates.cc new file mode 100644 index 0000000..bd49454 --- /dev/null +++ b/ie/MediaSourceStates.cc @@ -0,0 +1,140 @@ +/* Copyright(C) 2014 Sarandogou */ + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-MediaSourceStates + +#include "stdafx.h" +#include "MediaSourceStates.h" +#include "Utils.h" + +#include "../common/_Debug.h" + +CMediaSourceStates::CMediaSourceStates() + : m_States(nullptr) +{ +} + +HRESULT CMediaSourceStates::FinalConstruct() +{ + return S_OK; +} + +void CMediaSourceStates::FinalRelease() +{ + m_States = nullptr; +} + +void CMediaSourceStates::SetStates(std::shared_ptr<_MediaSourceStates> & states) +{ + m_States = states; +} + +std::shared_ptr<_MediaSourceStates> CMediaSourceStates::GetStates() +{ + return m_States; +} + +STDMETHODIMP CMediaSourceStates::get_sourceType(__out BSTR* pVal) +{ + if (!m_States) { + CHECK_HR_RETURN(E_POINTER); + } + return Utils::CopyAnsiString(m_States->sourceType, pVal); +} + +STDMETHODIMP CMediaSourceStates::get_sourceId(__out BSTR* pVal) +{ + if (!m_States) { + CHECK_HR_RETURN(E_POINTER); + } + return Utils::CopyAnsiString(m_States->sourceId, pVal); +} + +STDMETHODIMP CMediaSourceStates::get_width(__out VARIANT* pVal) +{ + if (!m_States) { + CHECK_HR_RETURN(E_POINTER); + } + // nullable + if (m_States->width <= 0) { + *pVal = CComVariant(NULL); + } + else { + *pVal = CComVariant(m_States->width); + } + return S_OK; +} + +STDMETHODIMP CMediaSourceStates::get_height(__out VARIANT* pVal) +{ + if (!m_States) { + CHECK_HR_RETURN(E_POINTER); + } + // nullable + if (m_States->height <= 0) { + *pVal = CComVariant(NULL); + } + else { + *pVal = CComVariant(m_States->height); + } + return S_OK; +} + +STDMETHODIMP CMediaSourceStates::get_frameRate(__out VARIANT* pVal) +{ + if (!m_States) { + CHECK_HR_RETURN(E_POINTER); + } + // nullable + if (m_States->frameRate <= 0) { + *pVal = CComVariant(NULL); + } + else { + *pVal = CComVariant(m_States->frameRate); + } + return S_OK; +} + +STDMETHODIMP CMediaSourceStates::get_aspectRatio(__out VARIANT* pVal) +{ + if (!m_States) { + CHECK_HR_RETURN(E_POINTER); + } + // nullable + if (m_States->aspectRatio <= 0) { + *pVal = CComVariant(NULL); + } + else { + *pVal = CComVariant(m_States->aspectRatio); + } + return S_OK; +} + +STDMETHODIMP CMediaSourceStates::get_facingMode(__out VARIANT* pVal) +{ + if (!m_States) { + CHECK_HR_RETURN(E_POINTER); + } + // nullable + if (m_States->facingMode.empty()) { + *pVal = CComVariant(NULL); + } + else { + *pVal = CComVariant(CComBSTR(m_States->facingMode.c_str())); + } + return S_OK; +} + +STDMETHODIMP CMediaSourceStates::get_volume(__out VARIANT* pVal) +{ + if (!m_States) { + CHECK_HR_RETURN(E_POINTER); + } + // nullable + if (m_States->volume < 0) { + *pVal = CComVariant(NULL); + } + else { + *pVal = CComVariant(m_States->volume); + } + return S_OK; +} \ No newline at end of file diff --git a/ie/MediaSourceStates.h b/ie/MediaSourceStates.h new file mode 100644 index 0000000..0a88874 --- /dev/null +++ b/ie/MediaSourceStates.h @@ -0,0 +1,67 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#idl-def-MediaSourceStates + +#pragma once +#include "resource.h" // main symbols + +#include "../common/_Config.h" +#include "../common/_Common.h" + +#include "webrtceverywhere_i.h" + + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + +using namespace ATL; + + +// CMediaSourceStates + +class ATL_NO_VTABLE CMediaSourceStates : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CMediaSourceStates(); + +DECLARE_REGISTRY_RESOURCEID(IDR_MEDIASOURCESTATES) + + +BEGIN_COM_MAP(CMediaSourceStates) + COM_INTERFACE_ENTRY(IMediaSourceStates) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + + void FinalRelease(); + + void SetStates(std::shared_ptr<_MediaSourceStates> & states); + std::shared_ptr<_MediaSourceStates> GetStates(); + +public: + + + STDMETHOD(get_sourceType)(__out BSTR* pVal); + STDMETHOD(get_sourceId)(__out BSTR* pVal); + STDMETHOD(get_width)(__out VARIANT* pVal); + STDMETHOD(get_height)(__out VARIANT* pVal); + STDMETHOD(get_frameRate)(__out VARIANT* pVal); + STDMETHOD(get_aspectRatio)(__out VARIANT* pVal); + STDMETHOD(get_facingMode)(__out VARIANT* pVal); + STDMETHOD(get_volume)(__out VARIANT* pVal); + +private: + std::shared_ptr<_MediaSourceStates> m_States; + +}; + +OBJECT_ENTRY_AUTO(__uuidof(MediaSourceStates), CMediaSourceStates) diff --git a/ie/MediaSourceStates.rgs b/ie/MediaSourceStates.rgs new file mode 100644 index 0000000..0bd5c91 --- /dev/null +++ b/ie/MediaSourceStates.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {7F64ACB6-F21C-44C2-8EEA-EFCBEED5AEB7} = s 'MediaSourceStates Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/MediaStream.cc b/ie/MediaStream.cc new file mode 100644 index 0000000..75322b1 --- /dev/null +++ b/ie/MediaStream.cc @@ -0,0 +1,320 @@ +/* Copyright(C) 2014 Sarandogou */ + +// http://www.w3.org/TR/mediacapture-streams/#mediastream + +#include "stdafx.h" +#include "MediaStream.h" +#include "MediaStreamTrack.h" +#include "WebRTC.h" +#include "BrowserCallback.h" +#include "Utils.h" + +#include "../common/_Debug.h" + +CMediaStream::CMediaStream() + : m_Stream(nullptr) + , m_callback_onended(NULL) + , m_callback_onaddtrack(NULL) + , m_callback_onremovetrack(NULL) +{ + +} + +HRESULT CMediaStream::FinalConstruct() +{ + return S_OK; +} + +void CMediaStream::FinalRelease() +{ + m_callback_onended = NULL; + m_callback_onaddtrack = NULL; + m_callback_onremovetrack = NULL; + + m_Stream = nullptr; + + SetDispatcher(NULL); +} + +void CMediaStream::SetStream(std::shared_ptr<_MediaStream> & stream) +{ + if ((m_Stream = stream)) { + m_Stream->onendedSet(std::bind(&CMediaStream::onended, this)); + m_Stream->onaddtrackSet(std::bind(&CMediaStream::onaddtrack, this)); + m_Stream->onremovetrackSet(std::bind(&CMediaStream::onremovetrack, this)); + } +} + +std::shared_ptr<_MediaStream> CMediaStream::GetStream() +{ + return m_Stream; +} + + +STDMETHODIMP CMediaStream::get_id(BSTR* pVal) +{ + if (!m_Stream) { + return E_POINTER; + } + return Utils::CopyAnsiStr(m_Stream->id(), pVal); +} + +STDMETHODIMP CMediaStream::getAudioTracks(__out VARIANT* Tracks) +{ + return getTracks(FALSE/*video*/, Tracks); +} + +STDMETHODIMP CMediaStream::getVideoTracks(__out VARIANT* Tracks) +{ + return getTracks(TRUE/*video*/, Tracks); +} + +STDMETHODIMP CMediaStream::getTrackById(__in BSTR trackId, __out VARIANT* MediaStreamTrack) +{ + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + char* lpszTrackId = _com_util::ConvertBSTRToString(trackId); + + if (!lpszTrackId) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + std::shared_ptr<_MediaStreamTrack> track = m_Stream->getTrackById(lpszTrackId); + delete[] lpszTrackId; + if (track) { + CComObject* _track; + HRESULT hr = Utils::CreateInstanceWithRef(&_track); + if (SUCCEEDED(hr)) { + _track->SetDispatcher(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + _track->SetTrack(track); + *MediaStreamTrack = CComVariant(_track); + } + return hr; + } + else { + *MediaStreamTrack = CComVariant(NULL); + return S_OK; + } +} + + +STDMETHODIMP CMediaStream::addTrack(__in VARIANT MediaStreamTrack) +{ + HRESULT hr; + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + + CComPtr_track = Utils::VariantToDispatch(MediaStreamTrack); + if (!_track) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + CComPtr _mediaStreamTrack = NULL; + CHECK_HR_RETURN(hr = _track->QueryInterface(&_mediaStreamTrack)); + + CMediaStreamTrack* pTrack = dynamic_cast(_mediaStreamTrack.p); + assert(pTrack); + if (!pTrack) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + m_Stream->addTrack(pTrack->GetTrack().get()); + + return S_OK; +} + +STDMETHODIMP CMediaStream::removeTrack(__in VARIANT MediaStreamTrack) +{ + HRESULT hr; + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + + CComPtr_track = Utils::VariantToDispatch(MediaStreamTrack); + if (!_track) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + CComPtr _mediaStreamTrack = NULL; + CHECK_HR_RETURN(hr = _track->QueryInterface(&_mediaStreamTrack)); + + CMediaStreamTrack* pTrack = dynamic_cast(_mediaStreamTrack.p); + assert(pTrack); + if (!pTrack) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + m_Stream->removeTrack(pTrack->GetTrack().get()); + + return S_OK; +} + +STDMETHODIMP CMediaStream::clone(__out VARIANT* MediaStream) +{ + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + + std::shared_ptr<_MediaStream>stream = m_Stream->clone(); + if (!stream) { + *MediaStream = CComVariant(NULL); + return S_OK; + } + + CComObject* _stream; + HRESULT hr = Utils::CreateInstanceWithRef(&_stream); + if (SUCCEEDED(hr)) { + _stream->SetDispatcher(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + _stream->SetStream(stream); + *MediaStream = CComVariant(_stream); + } + return hr; +} + +STDMETHODIMP CMediaStream::get_ended(__out VARIANT_BOOL* pVal) +{ + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = m_Stream->ended() ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; +} + +STDMETHODIMP CMediaStream::get_onended(__out VARIANT* pVal) +{ + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = CComVariant(m_callback_onended); + return S_OK; +} + +STDMETHODIMP CMediaStream::put_onended(__in VARIANT newVal) +{ + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + m_callback_onended = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CMediaStream::get_onaddtrack(__out VARIANT* pVal) +{ + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = CComVariant(m_callback_onaddtrack); + return S_OK; +} + +STDMETHODIMP CMediaStream::put_onaddtrack(__in VARIANT newVal) +{ + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + m_callback_onaddtrack = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CMediaStream::get_onremovetrack(__out VARIANT* pVal) +{ + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = CComVariant(m_callback_onremovetrack); + return S_OK; +} + +STDMETHODIMP CMediaStream::put_onremovetrack(__in VARIANT newVal) +{ + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + m_callback_onremovetrack = Utils::VariantToDispatch(newVal); + return S_OK; +} + + +// not part of the standard but used by Chrome +STDMETHODIMP CMediaStream::stop() +{ + if (m_Stream) { + m_Stream->stop(); + } + return S_OK; +} + +HRESULT CMediaStream::getTracks(BOOL video, VARIANT* Tracks) +{ + HRESULT hr = S_OK; + if (!m_Stream) { + CHECK_HR_RETURN(E_POINTER); + } + + CComPtr pluginInstance = dynamic_cast(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + if (!pluginInstance) { + CHECK_HR_RETURN(E_POINTER); + } + + CComPtr spDispatch; + CHECK_HR_RETURN(hr = pluginInstance->GetDispatch(spDispatch)); + + std::vector vect; + std::shared_ptr<_Sequence<_MediaStreamTrack> > tracks = video ? m_Stream->getVideoTracks() : m_Stream->getAudioTracks(); + if (tracks) { + for (size_t i = 0; i < tracks->values.size(); ++i) { + if (!tracks->values[i]) { + continue; + } + CComObject* _track; + hr = Utils::CreateInstanceWithRef(&_track); + if (SUCCEEDED(hr)) { + _track->SetDispatcher(pluginInstance); + _track->SetTrack(tracks->values[i]); + vect.push_back(CComVariant(_track)); + SafeRelease(&_track); + } + } + } + + CComQIPtr spArray; + CHECK_HR_RETURN(hr = Utils::CreateJsArray(spDispatch, vect, spArray)); + + *Tracks = CComVariant(spArray.Detach()); + return hr; +} + +void CMediaStream::onended() +{ + if (m_callback_onended) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, m_callback_onended); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void CMediaStream::onaddtrack() +{ + if (m_callback_onaddtrack) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, m_callback_onaddtrack); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void CMediaStream::onremovetrack() +{ + if (m_callback_onremovetrack) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, m_callback_onremovetrack); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} \ No newline at end of file diff --git a/ie/MediaStream.h b/ie/MediaStream.h new file mode 100644 index 0000000..b5679eb --- /dev/null +++ b/ie/MediaStream.h @@ -0,0 +1,85 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#mediastream + +#pragma once +#include "resource.h" // main symbols + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_MediaStream.h" +#include "../common/_AsyncEvent.h" + +#include "webrtceverywhere_i.h" + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + +using namespace ATL; + + +// CMediaStream + +class ATL_NO_VTABLE CMediaStream : + public _AsyncEventRaiser, + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CMediaStream(); + +DECLARE_REGISTRY_RESOURCEID(IDR_MEDIASTREAM) + + +BEGIN_COM_MAP(CMediaStream) + COM_INTERFACE_ENTRY(IMediaStream) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + void FinalRelease(); + +public: + + void SetStream(std::shared_ptr<_MediaStream> & stream); + std::shared_ptr<_MediaStream> GetStream(); + + STDMETHOD(get_id)(__out BSTR* pVal); + STDMETHOD(getAudioTracks)(__out VARIANT* Tracks); + STDMETHOD(getVideoTracks)(__out VARIANT* Tracks); + STDMETHOD(getTrackById)(__in BSTR trackId, __out VARIANT* MediaStreamTrack); + STDMETHOD(addTrack)(__in VARIANT MediaStreamTrack); + STDMETHOD(removeTrack)(__in VARIANT MediaStreamTrack); + STDMETHOD(clone)(__out VARIANT* MediaStream); + STDMETHOD(get_ended)(__out VARIANT_BOOL* pVal); + STDMETHOD(get_onended)(__out VARIANT* pVal); + STDMETHOD(put_onended)(__in VARIANT newVal); + STDMETHOD(get_onaddtrack)(__out VARIANT* pVal); + STDMETHOD(put_onaddtrack)(__in VARIANT newVal); + STDMETHOD(get_onremovetrack)(__out VARIANT* pVal); + STDMETHOD(put_onremovetrack)(__in VARIANT newVal); + STDMETHOD(stop)(); + +private: + HRESULT getTracks(BOOL video, VARIANT* Tracks); + + // callbacks + void onended(); + void onaddtrack(); + void onremovetrack(); + +private: + std::shared_ptr<_MediaStream> m_Stream; + + // callbacks + CComPtrm_callback_onended; + CComPtrm_callback_onaddtrack; + CComPtrm_callback_onremovetrack; +}; + +OBJECT_ENTRY_AUTO(__uuidof(MediaStream), CMediaStream) diff --git a/ie/MediaStream.rgs b/ie/MediaStream.rgs new file mode 100644 index 0000000..e35b15f --- /dev/null +++ b/ie/MediaStream.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {BA5835A2-D1F8-466D-BB5E-8093E3E2EE0E} = s 'MediaStream Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/MediaStreamEvent.cc b/ie/MediaStreamEvent.cc new file mode 100644 index 0000000..77eea90 --- /dev/null +++ b/ie/MediaStreamEvent.cc @@ -0,0 +1,55 @@ +/* Copyright(C) 2014 Sarandogou */ + +// http://www.w3.org/TR/webrtc/#idl-def-MediaStreamEvent + +#include "stdafx.h" +#include "MediaStreamEvent.h" +#include "MediaStream.h" +#include "Utils.h" + +#include "../common/_Debug.h" + + +CMediaStreamEvent::CMediaStreamEvent() + : m_Event(nullptr) +{ +} + +HRESULT CMediaStreamEvent::FinalConstruct() +{ + return S_OK; +} + +void CMediaStreamEvent::FinalRelease() +{ + m_Event = nullptr; + SetDispatcher(NULL); +} + +void CMediaStreamEvent::SetEvent(std::shared_ptr<_MediaStreamEvent> & e) +{ + m_Event = e; +} + +std::shared_ptr<_MediaStreamEvent> CMediaStreamEvent::GetEvent() +{ + return m_Event; +} + +STDMETHODIMP CMediaStreamEvent::get_stream(__out VARIANT* pVal) +{ + if (!m_Event) { + CHECK_HR_RETURN(E_POINTER); + } + if (!m_Event->stream) { + return CComVariant(NULL).Detach(pVal); + } + + CComObject* _stream; + HRESULT _hr = Utils::CreateInstanceWithRef(&_stream); + CHECK_HR_RETURN(_hr); + _stream->SetStream(m_Event->stream); + _hr = CComVariant(_stream).Detach(pVal); + SafeRelease(&_stream); + return _hr; +} \ No newline at end of file diff --git a/ie/MediaStreamEvent.h b/ie/MediaStreamEvent.h new file mode 100644 index 0000000..ab2b1e9 --- /dev/null +++ b/ie/MediaStreamEvent.h @@ -0,0 +1,58 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/webrtc/#idl-def-MediaStreamEvent + +#pragma once +#include "resource.h" // main symbols + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_AsyncEvent.h" + +#include "webrtceverywhere_i.h" + + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + +using namespace ATL; + + +// CMediaStreamEvent + +class ATL_NO_VTABLE CMediaStreamEvent : + public _AsyncEventRaiser, + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CMediaStreamEvent(); + +DECLARE_REGISTRY_RESOURCEID(IDR_MEDIASTREAMEVENT) + + +BEGIN_COM_MAP(CMediaStreamEvent) + COM_INTERFACE_ENTRY(IMediaStreamEvent) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + + void FinalRelease(); + + void SetEvent(std::shared_ptr<_MediaStreamEvent> & e); + std::shared_ptr<_MediaStreamEvent> GetEvent(); + + STDMETHOD(get_stream)(__out VARIANT* pVal); + +public: + std::shared_ptr<_MediaStreamEvent> m_Event; +}; + +OBJECT_ENTRY_AUTO(__uuidof(MediaStreamEvent), CMediaStreamEvent) diff --git a/ie/MediaStreamEvent.rgs b/ie/MediaStreamEvent.rgs new file mode 100644 index 0000000..d7fb2e6 --- /dev/null +++ b/ie/MediaStreamEvent.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {C744BE59-7004-4B7E-BD9D-C83F594A1B69} = s 'MediaStreamEvent Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/MediaStreamTrack.cc b/ie/MediaStreamTrack.cc new file mode 100644 index 0000000..a133aae --- /dev/null +++ b/ie/MediaStreamTrack.cc @@ -0,0 +1,379 @@ +/* Copyright(C) 2014 Sarandogou */ + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-MediaStreamTrack + +#include "stdafx.h" +#include "MediaStreamTrack.h" +#include "BrowserCallback.h" +#include "MediaSourceStates.h" +#include "WebRTC.h" +#include "SourceInfo.h" +#include "Utils.h" + +#include "../common/_Debug.h" + + +CMediaStreamTrack::CMediaStreamTrack() + : m_Track(nullptr) + , m_callback_onmute(NULL) + , m_callback_onunmute(NULL) + , m_callback_onstarted(NULL) + , m_callback_onended(NULL) + , m_callback_onoverconstrained(NULL) +{ +} + +HRESULT CMediaStreamTrack::FinalConstruct() +{ + return S_OK; +} + +void CMediaStreamTrack::FinalRelease() +{ + m_callback_onmute = NULL; + m_callback_onunmute = NULL; + m_callback_onstarted = NULL; + m_callback_onended = NULL; + m_callback_onoverconstrained = NULL; + + m_Track = nullptr; + + SetDispatcher(NULL); +} + +void CMediaStreamTrack::SetTrack(std::shared_ptr<_MediaStreamTrack> & track) +{ + if ((m_Track = track)) { + m_Track->onmuteSet(std::bind(&CMediaStreamTrack::onmute, this)); + m_Track->onunmuteSet(std::bind(&CMediaStreamTrack::onunmute, this)); + m_Track->onstartedSet(std::bind(&CMediaStreamTrack::onstarted, this)); + m_Track->onendedSet(std::bind(&CMediaStreamTrack::onended, this)); + m_Track->onoverconstrainedSet(std::bind(&CMediaStreamTrack::onoverconstrained, this)); + } +} + +std::shared_ptr<_MediaStreamTrack> CMediaStreamTrack::GetTrack() +{ + return m_Track; +} + +STDMETHODIMP CMediaStreamTrack::get_kind(__out BSTR* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + return Utils::CopyAnsiStr(m_Track->kind(), pVal); +} + +STDMETHODIMP CMediaStreamTrack::get_id(__out BSTR* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + return Utils::CopyAnsiStr(m_Track->id(), pVal); +} + +STDMETHODIMP CMediaStreamTrack::get_label(__out BSTR* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + return Utils::CopyAnsiStr(m_Track->label(), pVal); +} + +STDMETHODIMP CMediaStreamTrack::get_enabled(__out VARIANT_BOOL* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + + *pVal = m_Track->enabled() ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::put_enabled(__in VARIANT_BOOL newVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + return m_Track->enabledSet(newVal != VARIANT_FALSE) ? S_OK : E_FAIL; +} + +STDMETHODIMP CMediaStreamTrack::get_muted(__out VARIANT_BOOL* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = m_Track->muted() ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::get_onmute(__out VARIANT* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = CComVariant(m_callback_onmute); + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::put_onmute(__in VARIANT newVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + m_callback_onmute = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::get_onunmute(__out VARIANT* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = CComVariant(m_callback_onunmute); + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::put_onunmute(__in VARIANT newVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + m_callback_onunmute = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::get_readonly(__out VARIANT_BOOL* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = m_Track->readonly() ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::get_remote(__out VARIANT_BOOL* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = m_Track->remote() ? VARIANT_TRUE : VARIANT_FALSE; + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::get_readyState(__out BSTR* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + return Utils::CopyAnsiStr(m_Track->readyState(), pVal); +} + +STDMETHODIMP CMediaStreamTrack::get_onstarted(__out VARIANT* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = CComVariant(m_callback_onstarted); + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::put_onstarted(__in VARIANT newVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + m_callback_onstarted = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::get_onended(__out VARIANT* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = CComVariant(m_callback_onended); + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::put_onended(__in VARIANT newVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + m_callback_onended = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::getSourceInfos(__out VARIANT* Infos) +{ + HRESULT hr = S_OK; + + CComPtr pluginInstance = dynamic_cast(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + if (!pluginInstance) { + CHECK_HR_RETURN(E_POINTER); + } + + CComPtr spDispatch; + CHECK_HR_RETURN(hr = pluginInstance->GetDispatch(spDispatch)); + + return CMediaStreamTrack::getSources(spDispatch, Infos); +} + +STDMETHODIMP CMediaStreamTrack::constraints(__out VARIANT* MediaTrackConstraints) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + return (E_NOTIMPL); +} + +STDMETHODIMP CMediaStreamTrack::states(__out VARIANT* MediaSourceStates) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + CComObject* _states; + HRESULT hr = Utils::CreateInstanceWithRef(&_states); + if (SUCCEEDED(hr)) { + _states->SetStates(m_Track->states()); + *MediaSourceStates = CComVariant(_states); + } + return hr; +} + +STDMETHODIMP CMediaStreamTrack::capabilities(__out VARIANT* AllCapabilities) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + return (E_NOTIMPL); +} + +STDMETHODIMP CMediaStreamTrack::applyConstraints(__in VARIANT MediaTrackConstraints) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + return (E_NOTIMPL); +} + +STDMETHODIMP CMediaStreamTrack::get_onoverconstrained(__out VARIANT* pVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + *pVal = CComVariant(m_callback_onoverconstrained); + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::put_onoverconstrained(__in VARIANT newVal) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + m_callback_onoverconstrained = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CMediaStreamTrack::clone(__out VARIANT* MediaStreamTrack) +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + return (E_NOTIMPL); +} + +STDMETHODIMP CMediaStreamTrack::stop() +{ + if (!m_Track) { + CHECK_HR_RETURN(E_POINTER); + } + m_Track->stop(); + return S_OK; +} + +// not part of the standard but used by Chrome +HRESULT CMediaStreamTrack::getSources(__in CComPtr spDispatch, __out VARIANT* Infos) +{ + HRESULT hr = S_OK; + + std::vector vect; + std::shared_ptr<_Sequence<_SourceInfo> > sources = _MediaStreamTrack::getSourceInfos(); + if (sources) { + for (size_t i = 0; i < sources->values.size(); ++i) { + if (!sources->values[i]) { + continue; + } + CComObject* _source; + hr = Utils::CreateInstanceWithRef(&_source); + if (SUCCEEDED(hr)) { + _source->SetInfo(sources->values[i]); + vect.push_back(CComVariant(_source)); + SafeRelease(&_source); + } + } + } + + CComQIPtr spArray; + CHECK_HR_RETURN(hr = Utils::CreateJsArray(spDispatch, vect, spArray)); + + *Infos = CComVariant(spArray.Detach()); + return hr; +} + +void CMediaStreamTrack::onmute() +{ + if (m_callback_onmute) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, m_callback_onmute); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void CMediaStreamTrack::onunmute() +{ + if (m_callback_onunmute) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, m_callback_onunmute); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void CMediaStreamTrack::onstarted() +{ + if (m_callback_onstarted) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, m_callback_onstarted); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void CMediaStreamTrack::onended() +{ + if (m_callback_onended) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, m_callback_onended); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void CMediaStreamTrack::onoverconstrained() +{ + if (m_callback_onoverconstrained) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, m_callback_onoverconstrained); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} \ No newline at end of file diff --git a/ie/MediaStreamTrack.h b/ie/MediaStreamTrack.h new file mode 100644 index 0000000..dd9e58c --- /dev/null +++ b/ie/MediaStreamTrack.h @@ -0,0 +1,104 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#idl-def-MediaStreamTrack + +#pragma once +#include "resource.h" // main symbols + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_MediaStreamTrack.h" +#include "../common/_AsyncEvent.h" + +#include "webrtceverywhere_i.h" + + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + +using namespace ATL; + + +// CMediaStreamTrack + +class ATL_NO_VTABLE CMediaStreamTrack : + public _AsyncEventRaiser, + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CMediaStreamTrack(); + +DECLARE_REGISTRY_RESOURCEID(IDR_MEDIASTREAMTRACK) + + +BEGIN_COM_MAP(CMediaStreamTrack) + COM_INTERFACE_ENTRY(IMediaStreamTrack) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + + void FinalRelease(); + +public: + void SetTrack(std::shared_ptr<_MediaStreamTrack> & track); + std::shared_ptr<_MediaStreamTrack> GetTrack(); + +private: + std::shared_ptr<_MediaStreamTrack> m_Track; +public: + + STDMETHOD(get_kind)(__out BSTR* pVal); + STDMETHOD(get_id)(__out BSTR* pVal); + STDMETHOD(get_label)(__out BSTR* pVal); + STDMETHOD(get_enabled)(__out VARIANT_BOOL* pVal); + STDMETHOD(put_enabled)(__in VARIANT_BOOL newVal); + STDMETHOD(get_muted)(__out VARIANT_BOOL* pVal); + STDMETHOD(get_onmute)(__out VARIANT* pVal); + STDMETHOD(put_onmute)(__in VARIANT newVal); + STDMETHOD(get_onunmute)(__out VARIANT* pVal); + STDMETHOD(put_onunmute)(__in VARIANT newVal); + STDMETHOD(get_readonly)(__out VARIANT_BOOL* pVal); + STDMETHOD(get_remote)(__out VARIANT_BOOL* pVal); + STDMETHOD(get_readyState)(__out BSTR* pVal); + STDMETHOD(get_onstarted)(__out VARIANT* pVal); + STDMETHOD(put_onstarted)(__in VARIANT newVal); + STDMETHOD(get_onended)(__out VARIANT* pVal); + STDMETHOD(put_onended)(__in VARIANT newVal); + STDMETHOD(getSourceInfos)(__out VARIANT* Infos); + STDMETHOD(constraints)(__out VARIANT* MediaTrackConstraints); + STDMETHOD(states)(__out VARIANT* MediaSourceStates); + STDMETHOD(capabilities)(__out VARIANT* AllCapabilities); + STDMETHOD(applyConstraints)(__in VARIANT MediaTrackConstraints); + STDMETHOD(get_onoverconstrained)(__out VARIANT* pVal); + STDMETHOD(put_onoverconstrained)(__in VARIANT newVal); + STDMETHOD(clone)(__out VARIANT* MediaStreamTrack); + STDMETHOD(stop)(); + + // not part of the standard but used by Chrome + static HRESULT getSources(__in CComPtr spDispatch, __out VARIANT* Infos); + +private: + + void onmute(); + void onunmute(); + void onstarted(); + void onended(); + void onoverconstrained(); + +private: + CComPtrm_callback_onmute; + CComPtrm_callback_onunmute; + CComPtrm_callback_onstarted; + CComPtrm_callback_onended; + CComPtrm_callback_onoverconstrained; +}; + +OBJECT_ENTRY_AUTO(__uuidof(MediaStreamTrack), CMediaStreamTrack) diff --git a/ie/MediaStreamTrack.rgs b/ie/MediaStreamTrack.rgs new file mode 100644 index 0000000..8c79c6e --- /dev/null +++ b/ie/MediaStreamTrack.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {DA1D1412-BC34-4288-8047-6FFE131C647F} = s 'MediaStreamTrack Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/PeerConnection.cc b/ie/PeerConnection.cc new file mode 100644 index 0000000..2816474 --- /dev/null +++ b/ie/PeerConnection.cc @@ -0,0 +1,860 @@ +/* Copyright(C) 2014 Sarandogou */ + + +// http://www.w3.org/TR/webrtc/#interface-definition +// http://www.w3.org/TR/webrtc/#rtcpeerconnection-interface-extensions-2 +#include "stdafx.h" +#include "PeerConnection.h" +#include "MediaStream.h" +#include "MediaStreamTrack.h" +#include "MediaStreamEvent.h" +#include "SessionDescription.h" +#include "BrowserCallback.h" +#include "RTCIceCandidate.h" +#include "RTCPeerConnectionIceEvent.h" +#include "RTCStatsReport.h" +#include "WebRTC.h" +#include "Utils.h" + +#include "../common/_Debug.h" + +#include + +CPeerConnection::CPeerConnection() + : m_Peer(nullptr) + , m_callback_onnegotiationneeded(NULL) + , m_callback_onicecandidate(NULL) + , m_callback_onsignalingstatechange(NULL) + , m_callback_onaddstream(NULL) + , m_callback_onremovestream(NULL) + , m_callback_oniceconnectionstatechange(NULL) +{ +} + +HRESULT CPeerConnection::FinalConstruct() +{ + return S_OK; +} + +void CPeerConnection::FinalRelease() +{ + m_callback_onnegotiationneeded = NULL; + m_callback_onicecandidate = NULL; + m_callback_onsignalingstatechange = NULL; + m_callback_onaddstream = NULL; + m_callback_onremovestream = NULL; + m_callback_oniceconnectionstatechange = NULL; + + m_Peer = nullptr; + + SetDispatcher(NULL); +} + +HRESULT CPeerConnection::Init(VARIANT RTCConfiguration, VARIANT MediaConstraints) +{ + HRESULT hr; + + std::shared_ptr<_MediaConstraintsObj> mediaConstraints; + CHECK_HR_RETURN (hr = Utils::BuildMediaConstraintsObjs(MediaConstraints, mediaConstraints)); + + std::shared_ptr<_RTCConfiguration> rtcConf; + CHECK_HR_RETURN(hr = Utils::BuildRTCConfiguration(RTCConfiguration, rtcConf)); + + m_Peer = std::make_shared<_PeerConnection>(); + if (!m_Peer->Init(rtcConf.get(), mediaConstraints.get())) { + m_Peer = nullptr; + return E_FAIL; + } + + // set callback functions + m_Peer->SetCallback_onnegotiationneeded(std::bind(&CPeerConnection::onnegotiationneeded, this)); + m_Peer->SetCallback_onicecandidate(std::bind(&CPeerConnection::onicecandidate, this, std::placeholders::_1)); + m_Peer->SetCallback_onsignalingstatechange(std::bind(&CPeerConnection::onsignalingstatechange, this)); + m_Peer->SetCallback_onaddstream(std::bind(&CPeerConnection::onaddstream, this, std::placeholders::_1)); + m_Peer->SetCallback_onremovestream(std::bind(&CPeerConnection::onremovestream, this, std::placeholders::_1)); + m_Peer->SetCallback_oniceconnectionstatechange(std::bind(&CPeerConnection::oniceconnectionstatechange, this)); + + return S_OK; +} + +STDMETHODIMP CPeerConnection::createOffer(__in_opt VARIANT successCallback, __in_opt VARIANT failureCallback, __in_opt VARIANT mediaConstraints) +{ + if (!m_Peer) { + CHECK_HR_RETURN(E_POINTER); + } + + HRESULT hr = S_OK; + + std::shared_ptr<_MediaConstraintsObj> _mediaConstraints; + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraintsObjs(mediaConstraints, _mediaConstraints)); + + CComPtr_successCallback = Utils::VariantToDispatch(successCallback); + CComPtr_failureCallback = Utils::VariantToDispatch(failureCallback); + + bool ret = m_Peer->CreateOffer( + [_successCallback, this](std::shared_ptr<_SessionDescription> sdp) { + if (_successCallback) { + CComObject* _sdp; + HRESULT _hr = Utils::CreateInstanceWithRef(&_sdp); + if (SUCCEEDED(_hr)) { + _sdp->SetSdp(sdp); + BrowserCallback* _cb = new BrowserCallback(WM_CREATEOFFER_SUCCESS, _successCallback); + if (_cb) { + _cb->AddDispatch(_sdp); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + SafeRelease(&_sdp); + } + } + }, + [_failureCallback, this](std::shared_ptr error) { + if (_failureCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_CREATEOFFER_ERROR, _failureCallback); + if (_cb) { + CComBSTR err(error->c_str()); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }, + _mediaConstraints.get() + ); + + if (!ret) { + if (_failureCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_ERROR, _failureCallback); + if (_cb) { + CComBSTR err("Failed to create offer"); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + return S_OK; + } + + return hr; +} + +STDMETHODIMP CPeerConnection::createAnswer(__in_opt VARIANT successCallback, __in_opt VARIANT failureCallback, __in_opt VARIANT mediaConstraints) +{ + if (!m_Peer) { + return E_POINTER; + } + + HRESULT hr = S_OK; + + std::shared_ptr<_MediaConstraintsObj> _mediaConstraints; + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraintsObjs(mediaConstraints, _mediaConstraints)); + + CComPtr_successCallback = Utils::VariantToDispatch(successCallback); + CComPtr_failureCallback = Utils::VariantToDispatch(failureCallback); + + bool ret = m_Peer->CreateAnswer( + [_successCallback, this](std::shared_ptr<_SessionDescription> sdp) { + if (_successCallback) { + CComObject* _sdp; + HRESULT _hr = Utils::CreateInstanceWithRef(&_sdp); + if (SUCCEEDED(_hr)) { + _sdp->SetSdp(sdp); + BrowserCallback* _cb = new BrowserCallback(WM_CREATEOFFER_SUCCESS, _successCallback); + if (_cb) { + _cb->AddDispatch(_sdp); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + SafeRelease(&_sdp); + } + } + }, + [_failureCallback, this](std::shared_ptr error) { + if (_failureCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_CREATEOFFER_ERROR, _failureCallback); + if (_cb) { + CComBSTR err(error->c_str()); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }, + _mediaConstraints.get() + ); + + if (!ret) { + if (_failureCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_ERROR, _failureCallback); + if (_cb) { + CComBSTR err("Failed to create answer"); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + return S_OK; + } + + return hr; +} + +STDMETHODIMP CPeerConnection::setLocalDescription(__in VARIANT RTCSessionDescription, __in_opt VARIANT successCallback, __in_opt VARIANT failureCallback) +{ + if (!m_Peer) { + return E_POINTER; + } + + HRESULT hr = S_OK; + + CComPtrsdp = Utils::VariantToDispatch(RTCSessionDescription); + if (!sdp) { + return E_INVALIDARG; + } + CComPtr _sdp = NULL; + hr = sdp->QueryInterface(&_sdp); + if (FAILED(hr)) { + return hr; + } + CSessionDescription* pSdp = dynamic_cast(_sdp.p); + if (!pSdp) { + return E_INVALIDARG; + } + + CComPtr_successCallback = Utils::VariantToDispatch(successCallback); + CComPtr_failureCallback = Utils::VariantToDispatch(failureCallback); + + bool ret = m_Peer->SetLocalDescription( + pSdp->GetSdp().get(), + [_successCallback, this]() { + if (_successCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, _successCallback); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }, + [_failureCallback, this](std::shared_ptr error) { + if (_failureCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_ERROR, _failureCallback); + if (_cb) { + CComBSTR err(error->c_str()); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + } + ); + + if (!ret) { + if (_failureCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_ERROR, _failureCallback); + if (_cb) { + CComBSTR err("Failed to set local description"); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + return S_OK; + } + + return hr; +} + +STDMETHODIMP CPeerConnection::get_localDescription(__out VARIANT* pVal) +{ + if (!m_Peer) { + return E_POINTER; + } + + std::shared_ptr<_SessionDescription>sdp = m_Peer->LocalDescription(); + if (sdp) { + CComObject* _sdp; + HRESULT hr = Utils::CreateInstanceWithRef(&_sdp); + if (FAILED(hr)) { + return hr; + } + _sdp->SetSdp(sdp); + *pVal = CComVariant(_sdp); + } + else { + *pVal = CComVariant(NULL); + } + + return S_OK; +} + +STDMETHODIMP CPeerConnection::setRemoteDescription(__in VARIANT RTCSessionDescription, __in_opt VARIANT successCallback, __in_opt VARIANT failureCallback) +{ + if (!m_Peer) { + return E_POINTER; + } + + HRESULT hr = S_OK; + + CComPtrsdp = Utils::VariantToDispatch(RTCSessionDescription); + if (!sdp) { + return E_INVALIDARG; + } + CComPtr _sdp = NULL; + hr = sdp->QueryInterface(&_sdp); + if (FAILED(hr)) { + return hr; + } + CSessionDescription* pSdp = dynamic_cast(_sdp.p); + if (!pSdp) { + return E_INVALIDARG; + } + + CComPtr_successCallback = Utils::VariantToDispatch(successCallback); + CComPtr_failureCallback = Utils::VariantToDispatch(failureCallback); + + bool ret = m_Peer->SetRemoteDescription( + pSdp->GetSdp().get(), + [_successCallback, this]() { + if (_successCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, _successCallback); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }, + [_failureCallback, this](std::shared_ptr error) { + if (_failureCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_CREATEOFFER_ERROR, _failureCallback); + if (_cb) { + CComBSTR err(error->c_str()); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + } + ); + + if (!ret) { + if (_failureCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_ERROR, _failureCallback); + if (_cb) { + CComBSTR err("Failed to set remote description"); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + return S_OK; + } + + return hr; +} + +STDMETHODIMP CPeerConnection::get_remoteDescription(__out VARIANT* pVal) +{ + if (!m_Peer) { + return E_POINTER; + } + + std::shared_ptr<_SessionDescription>sdp = m_Peer->RemoteDescription(); + if (sdp) { + CComObject* _sdp; + HRESULT hr = Utils::CreateInstanceWithRef(&_sdp); + if (FAILED(hr)) { + return hr; + } + _sdp->SetSdp(sdp); + *pVal = CComVariant(_sdp); + } + else { + *pVal = CComVariant(NULL); + } + + return S_OK; +} + +STDMETHODIMP CPeerConnection::get_signalingState(__out BSTR* pVal) +{ + if (!m_Peer) { + return E_POINTER; + } + return Utils::CopyAnsiStr(m_Peer->SignalingState(), pVal); +} + +STDMETHODIMP CPeerConnection::updateIce(__in VARIANT RTCConfiguration, __in_opt VARIANT mediaConstraints) +{ + if (!m_Peer) { + CHECK_HR_RETURN(E_POINTER); + } + + HRESULT hr; + + std::shared_ptr<_RTCConfiguration> _rtcConf; + CHECK_HR_RETURN(hr = Utils::BuildRTCConfiguration(RTCConfiguration, _rtcConf)); + + std::shared_ptr<_MediaConstraintsObj> _mediaConstraints; + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraintsObjs(mediaConstraints, _mediaConstraints)); + + return (m_Peer->UpdateIce(_rtcConf.get(), _mediaConstraints.get()) ? S_OK : E_FAIL); +} + +STDMETHODIMP CPeerConnection::addIceCandidate(__in VARIANT RTCIceCandidate, __in VARIANT successCallback, __in VARIANT failureCallback) +{ + if (!m_Peer) { + return E_POINTER; + } + + HRESULT hr = S_OK; + + CComPtriceCandidate = Utils::VariantToDispatch(RTCIceCandidate); + if (!iceCandidate) { + return E_INVALIDARG; + } + CComPtr _iceCandidate = NULL; + hr = iceCandidate->QueryInterface(&_iceCandidate); + if (FAILED(hr)) { + return hr; + } + CRTCIceCandidate* pIceCandidate = dynamic_cast(_iceCandidate.p); + if (!pIceCandidate) { + return E_INVALIDARG; + } + + CComPtr_successCallback = Utils::VariantToDispatch(successCallback); + CComPtr_failureCallback = Utils::VariantToDispatch(failureCallback); + + bool ret = m_Peer->AddIceCandidate( + pIceCandidate->GetCandidate().get(), + [_successCallback, this]() { + if (_successCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, _successCallback); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }, + [_failureCallback, this](std::shared_ptr error) { + if (_failureCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_CREATEOFFER_ERROR, _failureCallback); + if (_cb) { + CComBSTR err(error->c_str()); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + } + ); + + if (!ret) + { + return E_FAIL; + } + + return hr; +} + +STDMETHODIMP CPeerConnection::get_iceGatheringState(__out BSTR* pVal) +{ + if (!m_Peer) { + return E_POINTER; + } + return Utils::CopyAnsiStr(m_Peer->IceGatheringState(), pVal); +} + +STDMETHODIMP CPeerConnection::get_iceConnectionState(__out BSTR* pVal) +{ + if (!m_Peer) { + return E_POINTER; + } + return Utils::CopyAnsiStr(m_Peer->IceConnectionState(), pVal); +} + +STDMETHODIMP CPeerConnection::getLocalStreams(__out VARIANT* MediaStreams) +{ + return getStreams(FALSE/*local*/, MediaStreams); +} + +STDMETHODIMP CPeerConnection::getRemoteStreams(__out VARIANT* MediaStreams) +{ + return getStreams(TRUE/*remote*/, MediaStreams); +} + +STDMETHODIMP CPeerConnection::getStreamById(__in BSTR streamId, __out VARIANT* MediaStream) +{ + if (!m_Peer) { + CHECK_HR_RETURN(E_POINTER); + } + + char *_streamId = _com_util::ConvertBSTRToString(streamId); + if (!_streamId) { + CHECK_HR_RETURN(E_OUTOFMEMORY); + } + + std::shared_ptr<_MediaStream> stream = m_Peer->GetStreamById(_streamId); + delete[] _streamId; + if (stream) { + CComObject* _stream; + HRESULT hr = Utils::CreateInstanceWithRef(&_stream); + if (SUCCEEDED(hr)) { + _stream->SetDispatcher(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + _stream->SetStream(stream); + *MediaStream = CComVariant(_stream); + } + return hr; + } + else { + *MediaStream = CComVariant(NULL); + return S_OK; + } +} + +STDMETHODIMP CPeerConnection::addStream(__in VARIANT stream, __in_opt VARIANT mediaConstraints) +{ + if (!m_Peer) { + CHECK_HR_RETURN(E_POINTER); + } + + CComPtr_stream = Utils::VariantToDispatch(stream); + if (!_stream) { + CHECK_HR_RETURN(E_INVALIDARG); + } + CComPtr _mediaStream = NULL; + HRESULT hr = _stream->QueryInterface(&_mediaStream); + if (FAILED(hr)) { + return hr; + } + + CMediaStream* pStream = dynamic_cast(_mediaStream.p); + assert(pStream); + if (!pStream) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + std::shared_ptr<_MediaConstraintsObj> _mediaConstraints; + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraintsObjs(mediaConstraints, _mediaConstraints)); + if (!m_Peer->AddStream(pStream->GetStream().get(), _mediaConstraints.get())) { + CHECK_HR_RETURN(E_FAIL); + } + + return S_OK; +} + +STDMETHODIMP CPeerConnection::removeStream(__in VARIANT stream) +{ + if (!m_Peer) { + CHECK_HR_RETURN(E_POINTER); + } + + CComPtr_stream = Utils::VariantToDispatch(stream); + if (!_stream) { + CHECK_HR_RETURN(E_INVALIDARG); + } + CComPtr _mediaStream = NULL; + HRESULT hr = _stream->QueryInterface(&_mediaStream); + CHECK_HR_RETURN(hr); + + CMediaStream* pStream = dynamic_cast(_mediaStream.p); + assert(pStream); + if (!pStream) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + if (!m_Peer->RemoveStream(pStream->GetStream().get())) { + CHECK_HR_RETURN(E_FAIL); + } + + return S_OK; +} + +STDMETHODIMP CPeerConnection::close() +{ + if (!m_Peer) { + CHECK_HR_RETURN(E_POINTER); + } + return m_Peer->Close() ? S_OK : E_FAIL; +} + +STDMETHODIMP CPeerConnection::getStats(__in VARIANT selector, __in_opt VARIANT successCallback, __in_opt VARIANT failureCallback) +{ + if (!m_Peer) { + CHECK_HR_RETURN(E_POINTER); + } + + // http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-getStats-void-MediaStreamTrack-selector-RTCStatsCallback-successCallback-RTCPeerConnectionErrorCallback-failureCallback + // Standard: void getStats (MediaStreamTrack? selector, RTCStatsCallback successCallback, RTCPeerConnectionErrorCallback failureCallback); + // Chrome: void getStats (RTCStatsCallback successCallback, RTCPeerConnectionErrorCallback failureCallback); + // Chrome issue: "selector" is nullable and not optional + HRESULT hr; + CComPtr_selector = Utils::VariantToDispatch(selector); + CComPtr_successCallback = Utils::VariantToDispatch(successCallback); + CComPtr_failureCallback = Utils::VariantToDispatch(failureCallback); + if (!_selector && !_successCallback && !_failureCallback) { + return S_OK; + } + + CComPtr _mediaStreamTrack = NULL; + if (_selector) { + hr = _selector->QueryInterface(&_mediaStreamTrack); + if (FAILED(hr)) { + _failureCallback = _successCallback; + _successCallback = _selector; + _selector = NULL; + } + } + + _MediaStreamTrackBase* pSelector = NULL; + if (_mediaStreamTrack){ + CMediaStreamTrack* pTrack = dynamic_cast(_mediaStreamTrack.p); + if (pTrack) { + pSelector = dynamic_cast<_MediaStreamTrackBase*>(pTrack->GetTrack().get()); + } + } + + bool ret = m_Peer->GetStats( + pSelector, + [_successCallback, this](std::shared_ptr<_RTCStatsReport> report) { + if (_successCallback){ + CComObject* _report; + HRESULT _hr = Utils::CreateInstanceWithRef(&_report); + if (SUCCEEDED(_hr)) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, _successCallback); + if (_cb) { + _report->SetStats(report); + _report->SetDispatcher(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + _cb->AddDispatch(_report); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + SafeRelease(&_report); + } + } + }, + [_failureCallback, this](std::shared_ptr error) { + if (_failureCallback){ + BrowserCallback* _cb = new BrowserCallback(WM_ERROR, _failureCallback); + if (_cb) { + CComBSTR err(error->c_str()); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }); + + if (!ret && _failureCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_ERROR, _failureCallback); + if (_cb) { + CComBSTR err("Global error"); + _cb->AddBSTR(err); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + return S_OK; +} + +STDMETHODIMP CPeerConnection::put_onnegotiationneeded(VARIANT newVal) +{ + m_callback_onnegotiationneeded = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CPeerConnection::get_onnegotiationneeded(VARIANT* pVal) +{ + *pVal = CComVariant(m_callback_onnegotiationneeded); + return S_OK; +} + +STDMETHODIMP CPeerConnection::put_onicecandidate(VARIANT newVal) +{ + m_callback_onicecandidate = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CPeerConnection::get_onicecandidate(VARIANT* pVal) +{ + *pVal = CComVariant(m_callback_onicecandidate); + return S_OK; +} + +STDMETHODIMP CPeerConnection::put_onsignalingstatechange(VARIANT newVal) +{ + m_callback_onsignalingstatechange = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CPeerConnection::get_onsignalingstatechange(VARIANT* pVal) +{ + *pVal = CComVariant(m_callback_onsignalingstatechange); + return S_OK; +} + +STDMETHODIMP CPeerConnection::put_onaddstream(VARIANT newVal) +{ + m_callback_onaddstream = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CPeerConnection::get_onaddstream(VARIANT* pVal) +{ + *pVal = CComVariant(m_callback_onaddstream); + return S_OK; +} + +STDMETHODIMP CPeerConnection::put_onremovestream(VARIANT newVal) +{ + m_callback_onremovestream = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CPeerConnection::get_onremovestream(VARIANT* pVal) +{ + *pVal = CComVariant(m_callback_onremovestream); + return S_OK; +} + +STDMETHODIMP CPeerConnection::put_oniceconnectionstatechange(VARIANT newVal) +{ + m_callback_oniceconnectionstatechange = Utils::VariantToDispatch(newVal); + return S_OK; +} + +STDMETHODIMP CPeerConnection::get_oniceconnectionstatechange(VARIANT* pVal) +{ + *pVal = CComVariant(m_callback_oniceconnectionstatechange); + return S_OK; +} + + +void CPeerConnection::onnegotiationneeded() +{ + if (m_callback_onnegotiationneeded) { + BrowserCallback* _cb = new BrowserCallback(WM_ONNEGOTIATIONNEEDED, m_callback_onnegotiationneeded); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void CPeerConnection::onicecandidate(std::shared_ptr<_RTCPeerConnectionIceEvent> e) +{ + if (m_callback_onicecandidate) { + CComObject* _candidateEvent; + HRESULT _hr = Utils::CreateInstanceWithRef(&_candidateEvent); + if (SUCCEEDED(_hr)) { + _candidateEvent->SetEvent(e); + BrowserCallback* _cb = new BrowserCallback(WM_ONICECANDIDATE, m_callback_onicecandidate); + if (_cb) { + _cb->AddDispatch(_candidateEvent); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + SafeRelease(&_candidateEvent); + } + } +} + +void CPeerConnection::onsignalingstatechange() +{ + if (m_callback_onsignalingstatechange) { + BrowserCallback* _cb = new BrowserCallback(WM_ONSIGNALINGSTATECHANGE, m_callback_onsignalingstatechange); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void CPeerConnection::onaddstream(std::shared_ptr<_MediaStreamEvent> e) +{ + if (m_callback_onaddstream) { + CComObject* _event; + HRESULT _hr = Utils::CreateInstanceWithRef(&_event); + if (SUCCEEDED(_hr)) { + _event->SetEvent(e); + BrowserCallback* _cb = new BrowserCallback(WM_ONADDSTREAM, m_callback_onaddstream); + if (_cb) { + _event->SetDispatcher(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + _cb->AddDispatch(_event); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + SafeRelease(&_event); + } + } +} + +void CPeerConnection::onremovestream(std::shared_ptr<_MediaStreamEvent> e) +{ + if (m_callback_onremovestream) { + CComObject* _event; + HRESULT _hr = Utils::CreateInstanceWithRef(&_event); + if (SUCCEEDED(_hr)) { + _event->SetDispatcher(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + _event->SetEvent(e); + BrowserCallback* _cb = new BrowserCallback(WM_ONREMOVESTREAM, m_callback_onremovestream); + if (_cb) { + _cb->AddDispatch(_event); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + SafeRelease(&_event); + } + } +} + +void CPeerConnection::oniceconnectionstatechange() +{ + if (m_callback_oniceconnectionstatechange) { + BrowserCallback* _cb = new BrowserCallback(WM_ONICECONNECTIONSTATECHANGE, m_callback_oniceconnectionstatechange); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +HRESULT CPeerConnection::getStreams(__in BOOL remote, __out VARIANT* MediaStreams) +{ + HRESULT hr = S_OK; + if (!m_Peer) { + return E_POINTER; + } + + CComPtr pluginInstance = dynamic_cast(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + if (!pluginInstance) { + CHECK_HR_RETURN(E_POINTER); + } + + CComPtr spDispatch; + CHECK_HR_RETURN(hr = pluginInstance->GetDispatch(spDispatch)); + + std::vector vect; + std::shared_ptr<_Sequence<_MediaStream> > streams = remote ? m_Peer->GetRemoteStreams() : m_Peer->GetLocalStreams(); + if (streams) { + for (size_t i = 0; i < streams->values.size(); ++i) { + if (!streams->values[i]) { + continue; + } + CComObject* _stream; + hr = Utils::CreateInstanceWithRef(&_stream); + if (SUCCEEDED(hr)) { + _stream->SetDispatcher(pluginInstance); + _stream->SetStream(streams->values[i]); + vect.push_back(CComVariant(_stream)); + SafeRelease(&_stream); + } + } + } + + CComQIPtr spArray; + CHECK_HR_RETURN(hr = Utils::CreateJsArray(spDispatch, vect, spArray)); + + *MediaStreams = CComVariant(spArray.Detach()); + return hr; +} \ No newline at end of file diff --git a/ie/PeerConnection.h b/ie/PeerConnection.h new file mode 100644 index 0000000..309db9e --- /dev/null +++ b/ie/PeerConnection.h @@ -0,0 +1,112 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/webrtc/#interface-definition +// http://www.w3.org/TR/webrtc/#rtcpeerconnection-interface-extensions-2 + +#pragma once +#include "resource.h" // main symbols + +#include "webrtceverywhere_i.h" + +#include "../common/_Config.h" +#include "../common/_PeerConnection.h" +#include "../common/_AsyncEvent.h" +#include "../common/_Common.h" + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + + + +// CPeerConnection + +class ATL_NO_VTABLE CPeerConnection : + public _AsyncEventRaiser, + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CPeerConnection(); + + DECLARE_REGISTRY_RESOURCEID(IDR_PEERCONNECTION) + + + BEGIN_COM_MAP(CPeerConnection) + COM_INTERFACE_ENTRY(IPeerConnection) + COM_INTERFACE_ENTRY(IDispatch) + END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + + void FinalRelease(); + + BrowserObjectImpl_IUnknown(); + +public: + HRESULT Init(VARIANT RTCConfiguration, VARIANT MediaConstraints); + + STDMETHOD(createOffer)(__in_opt VARIANT successCallback, __in_opt VARIANT failureCallback, __in_opt VARIANT MediaConstraints); + STDMETHOD(createAnswer)(__in_opt VARIANT successCallback, __in_opt VARIANT failureCallback, __in_opt VARIANT MediaConstraints); + STDMETHOD(setLocalDescription)(__in VARIANT RTCSessionDescription, __in_opt VARIANT successCallback, __in_opt VARIANT failureCallback); + STDMETHOD(get_localDescription)(__out VARIANT* pVal); + STDMETHOD(setRemoteDescription)(__in VARIANT RTCSessionDescription, __in_opt VARIANT successCallback, __in_opt VARIANT failureCallback); + STDMETHOD(get_remoteDescription)(__out VARIANT* pVal); + STDMETHOD(get_signalingState)(__out BSTR* pVal); + STDMETHOD(updateIce)(__in VARIANT RTCConfiguration, __in_opt VARIANT MediaConstraints); + STDMETHOD(addIceCandidate)(__in VARIANT RTCIceCandidate, __in VARIANT successCallback, __in VARIANT failureCallback); + STDMETHOD(get_iceGatheringState)(__out BSTR* pVal); + STDMETHOD(get_iceConnectionState)(__out BSTR* pVal); + STDMETHOD(getLocalStreams)(__out VARIANT* MediaStreams); + STDMETHOD(getRemoteStreams)(__out VARIANT* MediaStreams); + STDMETHOD(getStreamById)(__in BSTR streamId, __out VARIANT* MediaStream); + STDMETHOD(addStream)(__in VARIANT stream, __in_opt VARIANT MediaConstraints); + STDMETHOD(removeStream)(__in VARIANT stream); + STDMETHOD(close)(); + STDMETHOD(getStats)(__in VARIANT selector, __in_opt VARIANT successCallback, __in_opt VARIANT failureCallback); + + STDMETHOD(put_onnegotiationneeded)(__in VARIANT newVal); + STDMETHOD(get_onnegotiationneeded)(__out VARIANT* pVal); + STDMETHOD(put_onicecandidate)(__in VARIANT newVal); + STDMETHOD(get_onicecandidate)(__out VARIANT* pVal); + STDMETHOD(put_onsignalingstatechange)(__in VARIANT newVal); + STDMETHOD(get_onsignalingstatechange)(__out VARIANT* pVal); + STDMETHOD(put_onaddstream)(__in VARIANT newVal); + STDMETHOD(get_onaddstream)(__out VARIANT* pVal); + STDMETHOD(put_onremovestream)(__in VARIANT newVal); + STDMETHOD(get_onremovestream)(__out VARIANT* pVal); + STDMETHOD(put_oniceconnectionstatechange)(__in VARIANT newVal); + STDMETHOD(get_oniceconnectionstatechange)(__out VARIANT* pVal); + +private: + // callbacks + void onnegotiationneeded(); + void onicecandidate(std::shared_ptr<_RTCPeerConnectionIceEvent> e); + void onsignalingstatechange(); + void onaddstream(std::shared_ptr<_MediaStreamEvent> stream); + void onremovestream(std::shared_ptr<_MediaStreamEvent> stream); + void oniceconnectionstatechange(); + + HRESULT getStreams(__in BOOL remote, __out VARIANT* MediaStreams); + +private: + std::shared_ptr<_PeerConnection> m_Peer; + + // callbacks + CComPtrm_callback_onnegotiationneeded; + CComPtrm_callback_onicecandidate; + CComPtrm_callback_onsignalingstatechange; + CComPtrm_callback_onaddstream; + CComPtrm_callback_onremovestream; + CComPtrm_callback_oniceconnectionstatechange; +public: + + +}; + +OBJECT_ENTRY_AUTO(__uuidof(PeerConnection), CPeerConnection) diff --git a/ie/PeerConnection.rgs b/ie/PeerConnection.rgs new file mode 100644 index 0000000..264d258 --- /dev/null +++ b/ie/PeerConnection.rgs @@ -0,0 +1,26 @@ +HKCR +{ + webrtceverywhereie.PeerConnection.1 = s 'PeerConnection Class' + { + CLSID = s '{017D6D0A-BDBC-45DC-9368-A7ED657DAC4D}' + } + webrtceverywhereie.PeerConnection = s 'PeerConnection Class' + { + CLSID = s '{017D6D0A-BDBC-45DC-9368-A7ED657DAC4D}' + CurVer = s 'webrtceverywhereie.PeerConnection.1' + } + NoRemove CLSID + { + ForceRemove {017D6D0A-BDBC-45DC-9368-A7ED657DAC4D} = s 'PeerConnection Class' + { + ProgID = s 'webrtceverywhereie.PeerConnection.1' + VersionIndependentProgID = s 'webrtceverywhereie.PeerConnection' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + } + } +} diff --git a/ie/RTCIceCandidate.cc b/ie/RTCIceCandidate.cc new file mode 100644 index 0000000..df83862 --- /dev/null +++ b/ie/RTCIceCandidate.cc @@ -0,0 +1,90 @@ +/* Copyright(C) 2014 Sarandogou */ + + +// http://www.w3.org/TR/webrtc/#rtcicecandidate-type + +#include "stdafx.h" +#include "RTCIceCandidate.h" +#include "Utils.h" + +#include "../common/_Debug.h" + +CRTCIceCandidate::CRTCIceCandidate() + : m_Candidate(nullptr) +{ +} + +HRESULT CRTCIceCandidate::FinalConstruct() +{ + return S_OK; +} + +void CRTCIceCandidate::FinalRelease() +{ + m_Candidate = nullptr; +} + +HRESULT CRTCIceCandidate::Init(VARIANT candidateInitDict) +{ + if (candidateInitDict.vt == VT_BSTR) { + char* lpszCandidate = _com_util::ConvertBSTRToString(candidateInitDict.bstrVal); + if (!lpszCandidate) { + CHECK_HR_RETURN(E_INVALIDARG); + } + m_Candidate = std::make_shared<_RTCIceCandidate>(lpszCandidate); + delete[]lpszCandidate; + } + else { + CComPtr_candidateInitDict = Utils::VariantToDispatch(candidateInitDict); // http://www.w3.org/TR/webrtc/#idl-def-RTCIceCandidateInit + if (!_candidateInitDict) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + + BSTR bstrCandidate; + HRESULT hr = Utils::DispatchGetPropBSTR(_candidateInitDict, L"candidate", bstrCandidate); + if (FAILED(hr)) { + return hr; + } + BSTR bstrSdpMid; + CHECK_HR_RETURN(hr = Utils::DispatchGetPropBSTR(_candidateInitDict, L"sdpMid", bstrSdpMid)); + + long longSdpMLineIndex; + CHECK_HR_RETURN(hr = Utils::DispatchGetPropInteger(_candidateInitDict, L"sdpMLineIndex", longSdpMLineIndex)); + + char* lpszCandidate = _com_util::ConvertBSTRToString(bstrCandidate); + char* lpszSdpMid = _com_util::ConvertBSTRToString(bstrSdpMid); + m_Candidate = std::make_shared<_RTCIceCandidate>((lpszCandidate ? lpszCandidate : ""), (lpszSdpMid ? lpszSdpMid : ""), (unsigned short)longSdpMLineIndex); + if (lpszCandidate) delete[]lpszCandidate; + if (lpszSdpMid) delete[]lpszSdpMid; + } + + return S_OK; +} + +STDMETHODIMP CRTCIceCandidate::get_candidate(BSTR* pVal) +{ + if (!m_Candidate) {// NULL candidate used as hack to signal end of gathering + *pVal = CComBSTR(NULL).Detach(); + return S_OK; + } + return Utils::CopyAnsiStr(m_Candidate->candidate(), pVal); +} + +STDMETHODIMP CRTCIceCandidate::get_sdpMid(BSTR* pVal) +{ + if (!m_Candidate) { + *pVal = CComBSTR(NULL).Detach(); + return S_OK; + } + return Utils::CopyAnsiStr(m_Candidate->sdpMid(), pVal); +} + +STDMETHODIMP CRTCIceCandidate::get_sdpMLineIndex(USHORT* pVal) +{ + if (!m_Candidate) { + *pVal = 0; + return S_OK; + } + *pVal = m_Candidate->sdpMLineIndex(); + return S_OK; +} diff --git a/ie/RTCIceCandidate.h b/ie/RTCIceCandidate.h new file mode 100644 index 0000000..e9597fe --- /dev/null +++ b/ie/RTCIceCandidate.h @@ -0,0 +1,62 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/webrtc/#rtcicecandidate-type + +#pragma once +#include "resource.h" // main symbols + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_RTCIceCandidate.h" + +#include "webrtceverywhere_i.h" + + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + +using namespace ATL; + + +// CRTCIceCandidate + +class ATL_NO_VTABLE CRTCIceCandidate : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CRTCIceCandidate(); + +DECLARE_REGISTRY_RESOURCEID(IDR_RTCICECANDIDATE) + + +BEGIN_COM_MAP(CRTCIceCandidate) + COM_INTERFACE_ENTRY(IRTCIceCandidate) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + + void FinalRelease(); + +public: + HRESULT Init(VARIANT candidateInitDict); + + WE_INLINE void SetCandidate(std::shared_ptr<_RTCIceCandidate> & candidate) { m_Candidate = candidate; } + WE_INLINE std::shared_ptr<_RTCIceCandidate> GetCandidate() { return m_Candidate; } + + STDMETHOD(get_candidate)(BSTR* pVal); + STDMETHOD(get_sdpMid)(BSTR* pVal); + STDMETHOD(get_sdpMLineIndex)(USHORT* pVal); + +private: + std::shared_ptr<_RTCIceCandidate> m_Candidate; +}; + +OBJECT_ENTRY_AUTO(__uuidof(RTCIceCandidate), CRTCIceCandidate) diff --git a/ie/RTCIceCandidate.rgs b/ie/RTCIceCandidate.rgs new file mode 100644 index 0000000..c607ef9 --- /dev/null +++ b/ie/RTCIceCandidate.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {11C7D108-E675-47C4-9C18-718DA7D249EA} = s 'RTCIceCandidate Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/RTCIceCandidate1.rgs b/ie/RTCIceCandidate1.rgs new file mode 100644 index 0000000..48c55be --- /dev/null +++ b/ie/RTCIceCandidate1.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {28A9AA4D-FF28-4D44-A3E6-DCFD12402B88} = s 'RTCIceCandidate Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/RTCIceCandidate2.rgs b/ie/RTCIceCandidate2.rgs new file mode 100644 index 0000000..c389b08 --- /dev/null +++ b/ie/RTCIceCandidate2.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {71019677-FEA0-4E32-AA54-A852DFAD2389} = s 'RTCIceCandidate Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/RTCIceCandidate3.rgs b/ie/RTCIceCandidate3.rgs new file mode 100644 index 0000000..850ec9a --- /dev/null +++ b/ie/RTCIceCandidate3.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {2664C70E-9C03-4AC5-9D15-38CFCD5D8008} = s 'RTCIceCandidate Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/RTCIceCandidate4.rgs b/ie/RTCIceCandidate4.rgs new file mode 100644 index 0000000..d931421 --- /dev/null +++ b/ie/RTCIceCandidate4.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {31074FC8-A7D4-4281-9C90-B7D20C53A023} = s 'RTCIceCandidate Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/RTCPeerConnectionIceEvent.cc b/ie/RTCPeerConnectionIceEvent.cc new file mode 100644 index 0000000..e31d47d --- /dev/null +++ b/ie/RTCPeerConnectionIceEvent.cc @@ -0,0 +1,53 @@ +/* Copyright(C) 2014 Sarandogou */ + + +// RTCPeerConnectionIceEvent.cc : Implementation of CRTCPeerConnectionIceEvent + +#include "stdafx.h" +#include "RTCIceCandidate.h" +#include "RTCPeerConnectionIceEvent.h" +#include "Utils.h" + +#include "../common/_Debug.h" + +CRTCPeerConnectionIceEvent::CRTCPeerConnectionIceEvent() + : m_Event(nullptr) +{ +} + +HRESULT CRTCPeerConnectionIceEvent::FinalConstruct() +{ + return S_OK; +} + +void CRTCPeerConnectionIceEvent::FinalRelease() +{ + m_Event = nullptr; +} + +void CRTCPeerConnectionIceEvent::SetEvent(std::shared_ptr<_RTCPeerConnectionIceEvent> & e) +{ + m_Event = e; +} + +std::shared_ptr<_RTCPeerConnectionIceEvent> CRTCPeerConnectionIceEvent::GetEvent() +{ + return m_Event; +} + + +STDMETHODIMP CRTCPeerConnectionIceEvent::get_candidate(__out VARIANT* pVal) +{ + if (!m_Event || !m_Event->candidate) { + CComVariant(NULL).Detach(pVal); + return S_OK; + } + + CComObject* _candidate; + HRESULT _hr = Utils::CreateInstanceWithRef(&_candidate); + CHECK_HR_RETURN(_hr); + _candidate->SetCandidate(m_Event->candidate); + _hr = CComVariant(_candidate).Detach(pVal); + SafeRelease(&_candidate); + return _hr; +} diff --git a/ie/RTCPeerConnectionIceEvent.h b/ie/RTCPeerConnectionIceEvent.h new file mode 100644 index 0000000..1874758 --- /dev/null +++ b/ie/RTCPeerConnectionIceEvent.h @@ -0,0 +1,58 @@ +/* Copyright(C) 2014 Sarandogou */ + +#pragma once +#include "resource.h" // main symbols + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_AsyncEvent.h" + +#include "webrtceverywhere_i.h" + + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + +using namespace ATL; + + +// CRTCPeerConnectionIceEvent + +class ATL_NO_VTABLE CRTCPeerConnectionIceEvent : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CRTCPeerConnectionIceEvent(); + +DECLARE_REGISTRY_RESOURCEID(IDR_RTCPEERCONNECTIONICEEVENT) + + +BEGIN_COM_MAP(CRTCPeerConnectionIceEvent) + COM_INTERFACE_ENTRY(IRTCPeerConnectionIceEvent) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + + void FinalRelease(); + +public: + void SetEvent(std::shared_ptr<_RTCPeerConnectionIceEvent> & e); + std::shared_ptr<_RTCPeerConnectionIceEvent> GetEvent(); + + STDMETHOD(get_candidate)(__out VARIANT* pVal); + +private: + std::shared_ptr<_RTCPeerConnectionIceEvent> m_Event; + +}; + +OBJECT_ENTRY_AUTO(__uuidof(RTCPeerConnectionIceEvent), CRTCPeerConnectionIceEvent) diff --git a/ie/RTCPeerConnectionIceEvent.rgs b/ie/RTCPeerConnectionIceEvent.rgs new file mode 100644 index 0000000..83737fb --- /dev/null +++ b/ie/RTCPeerConnectionIceEvent.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {1A225B63-CA8F-466E-A848-44A16A19706E} = s 'RTCPeerConnectionIceEvent Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/RTCStats.cc b/ie/RTCStats.cc new file mode 100644 index 0000000..ad9a585 --- /dev/null +++ b/ie/RTCStats.cc @@ -0,0 +1,98 @@ +/* Copyright(C) 2014 Sarandogou */ + +// http://www.w3.org/TR/webrtc/#rtcstats-dictionary + +#include "stdafx.h" +#include "RTCStats.h" +#include "Utils.h" +#include "WebRTC.h" + +#include "../common/_Debug.h" + +CRTCStats::CRTCStats() + : m_Stats(nullptr) +{ +} + +HRESULT CRTCStats::FinalConstruct() +{ + return S_OK; +} + +void CRTCStats::FinalRelease() +{ + m_Stats = nullptr; +} + +STDMETHODIMP CRTCStats::get_timestamp(__out DOUBLE* pVal) +{ + *pVal = m_Stats ? m_Stats->timestamp : 0.0; + return S_OK; +} + +STDMETHODIMP CRTCStats::get_type(__out BSTR* pVal) +{ + if (!m_Stats) { + *pVal = CComBSTR(NULL).Detach(); + return S_OK; + } + return Utils::CopyAnsiString(m_Stats->type, pVal); +} + +STDMETHODIMP CRTCStats::get_id(__out BSTR* pVal) +{ + if (!m_Stats) { + *pVal = CComBSTR(NULL).Detach(); + return S_OK; + } + return Utils::CopyAnsiString(m_Stats->id, pVal); +} + +STDMETHODIMP CRTCStats::names(__out VARIANT* Names) +{ + if (!m_Stats) { + return CComVariant(NULL).Detach(Names); + } + + HRESULT hr; + CComPtr pluginInstance = dynamic_cast(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + if (!pluginInstance) { + CHECK_HR_RETURN(E_POINTER); + } + + CComPtr spDispatch; + CHECK_HR_RETURN(hr = pluginInstance->GetDispatch(spDispatch)); + + std::vector vect; + std::map::iterator it = m_Stats->names.begin(); + for (; it != m_Stats->names.end(); ++it) { + vect.push_back(CComBSTR((*it).first.c_str())); + } + + CComQIPtr spArray; + CHECK_HR_RETURN(hr = Utils::CreateJsArray(spDispatch, vect, spArray)); + *Names = CComVariant(spArray.Detach()); + + return hr; +} + +STDMETHODIMP CRTCStats::stat(__in BSTR name, __out BSTR* pVal) +{ + if (!m_Stats) { + *pVal = CComBSTR(NULL).Detach(); + return S_OK; + } + char* lpszName = _com_util::ConvertBSTRToString(name); + if (!lpszName) { + CHECK_HR_RETURN(E_INVALIDARG); + } + std::map::iterator it = m_Stats->names.find(std::string(lpszName)); + delete[]lpszName; + if (it != m_Stats->names.end()) { + return Utils::CopyAnsiString((*it).second, pVal); + } + else { + *pVal = CComBSTR(NULL).Detach(); + return S_OK; + } +} \ No newline at end of file diff --git a/ie/RTCStats.h b/ie/RTCStats.h new file mode 100644 index 0000000..25baa6f --- /dev/null +++ b/ie/RTCStats.h @@ -0,0 +1,64 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/webrtc/#rtcstats-dictionary + +#pragma once +#include "resource.h" // main symbols + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_AsyncEvent.h" + +#include "webrtceverywhere_i.h" + + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + +using namespace ATL; + + +// CRTCStats + +class ATL_NO_VTABLE CRTCStats : + public _AsyncEventRaiser, + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CRTCStats(); + +DECLARE_REGISTRY_RESOURCEID(IDR_RTCSTATS) + + +BEGIN_COM_MAP(CRTCStats) + COM_INTERFACE_ENTRY(IRTCStats) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + + void FinalRelease(); + +public: + WE_INLINE void SetStats(std::shared_ptr<_RTCStats> & states) { m_Stats = states; } + WE_INLINE std::shared_ptr<_RTCStats> GetStats() { return m_Stats; } + + STDMETHOD(get_timestamp)(__out DOUBLE* pVal); + STDMETHOD(get_type)(__out BSTR* pVal); + STDMETHOD(get_id)(__out BSTR* pVal); + STDMETHOD(names)(__out VARIANT* Names); + STDMETHOD(stat)(__in BSTR name, __out BSTR* pVal); + +private: + std::shared_ptr<_RTCStats> m_Stats; + +}; + +OBJECT_ENTRY_AUTO(__uuidof(RTCStats), CRTCStats) diff --git a/ie/RTCStats.rgs b/ie/RTCStats.rgs new file mode 100644 index 0000000..e88fe9d --- /dev/null +++ b/ie/RTCStats.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {F752E29B-45CB-4753-AA0C-51D1A021143C} = s 'RTCStats Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/RTCStatsReport.cc b/ie/RTCStatsReport.cc new file mode 100644 index 0000000..a5b5140 --- /dev/null +++ b/ie/RTCStatsReport.cc @@ -0,0 +1,61 @@ +/* Copyright(C) 2014 Sarandogou */ + +// http://www.w3.org/TR/webrtc/#idl-def-RTCStatsReport + +#include "stdafx.h" +#include "RTCStatsReport.h" +#include "RTCStats.h" +#include "Utils.h" +#include "WebRTC.h" + +#include "../common/_Debug.h" + +CRTCStatsReport::CRTCStatsReport() + : m_Stats(nullptr) +{ +} + +HRESULT CRTCStatsReport::FinalConstruct() +{ + return S_OK; +} + +void CRTCStatsReport::FinalRelease() +{ + m_Stats = nullptr; +} + +STDMETHODIMP CRTCStatsReport::result(__out VARIANT* RTCStatsList) +{ + if (!m_Stats) { + return CComVariant(NULL).Detach(RTCStatsList); + } + + HRESULT hr; + CComPtr pluginInstance = dynamic_cast(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + if (!pluginInstance) { + CHECK_HR_RETURN(E_POINTER); + } + + CComPtr spDispatch; + CHECK_HR_RETURN(hr = pluginInstance->GetDispatch(spDispatch)); + + std::vector vect; + std::map >::iterator it = m_Stats->values.begin(); + for (; it != m_Stats->values.end(); ++it) { + CComObject* _stats; + hr = Utils::CreateInstanceWithRef(&_stats); + if (SUCCEEDED(hr)) { + _stats->SetStats((*it).second); + _stats->SetDispatcher(pluginInstance); + vect.push_back(CComVariant(_stats)); + SafeRelease(&_stats); + } + } + + CComQIPtr spArray; + CHECK_HR_RETURN(hr = Utils::CreateJsArray(spDispatch, vect, spArray)); + *RTCStatsList = CComVariant(spArray.Detach()); + + return hr; +} \ No newline at end of file diff --git a/ie/RTCStatsReport.h b/ie/RTCStatsReport.h new file mode 100644 index 0000000..3aa82c9 --- /dev/null +++ b/ie/RTCStatsReport.h @@ -0,0 +1,58 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/webrtc/#idl-def-RTCStatsReport + +#pragma once +#include "resource.h" // main symbols + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_AsyncEvent.h" + +#include "webrtceverywhere_i.h" + + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + +using namespace ATL; + + +// CRTCStatsReport + +class ATL_NO_VTABLE CRTCStatsReport : + public _AsyncEventRaiser, + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CRTCStatsReport(); + +DECLARE_REGISTRY_RESOURCEID(IDR_RTCSTATSREPORT) + + +BEGIN_COM_MAP(CRTCStatsReport) + COM_INTERFACE_ENTRY(IRTCStatsReport) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + + void FinalRelease(); + +public: + WE_INLINE void SetStats(std::shared_ptr<_RTCStatsReport> & states) { m_Stats = states; } + WE_INLINE std::shared_ptr<_RTCStatsReport> GetStats() { return m_Stats; } + + STDMETHOD(result)(__out VARIANT* RTCStatsList); + +private: + std::shared_ptr<_RTCStatsReport> m_Stats; + +}; + +OBJECT_ENTRY_AUTO(__uuidof(RTCStatsReport), CRTCStatsReport) diff --git a/ie/RTCStatsReport.rgs b/ie/RTCStatsReport.rgs new file mode 100644 index 0000000..98c1e14 --- /dev/null +++ b/ie/RTCStatsReport.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {419C32C7-EF29-42C3-9A02-7C64FF869FD6} = s 'RTCStatsReport Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/SessionDescription.cc b/ie/SessionDescription.cc new file mode 100644 index 0000000..737d392 --- /dev/null +++ b/ie/SessionDescription.cc @@ -0,0 +1,124 @@ +/* Copyright(C) 2014 Sarandogou */ + +// http://www.w3.org/TR/webrtc/#session-description-model + +#include "stdafx.h" +#include "SessionDescription.h" +#include "Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" + +#include +#include +#include + +CSessionDescription::CSessionDescription() + : m_Sdp(NULL) +{ + +} + +HRESULT CSessionDescription::FinalConstruct() +{ + return S_OK; +} + +void CSessionDescription::FinalRelease() +{ + m_Sdp = NULL; +} + +HRESULT CSessionDescription::Init(VARIANT RTCSessionDescriptionInit) +{ + CComPtrrtcSessionDescriptionInit = Utils::VariantToDispatch(RTCSessionDescriptionInit); + if (!rtcSessionDescriptionInit) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + HRESULT hr; + + BSTR bstrType; + CHECK_HR_RETURN(hr = Utils::DispatchGetPropBSTR(rtcSessionDescriptionInit, L"type", bstrType)); + BSTR bstrSdp; + CHECK_HR_RETURN(hr = Utils::DispatchGetPropBSTR(rtcSessionDescriptionInit, L"sdp", bstrSdp)); + + char* lpszType = _com_util::ConvertBSTRToString(bstrType); + char* lpszSdp = _com_util::ConvertBSTRToString(bstrSdp); + + m_Sdp = std::make_shared<_SessionDescription>( + lpszSdp, + lpszSdp ? strlen(lpszSdp) : 0, + lpszType, + lpszType ? strlen(lpszType) : 0); + if (lpszType) delete[] lpszType; + if (lpszSdp) delete[] lpszSdp; + + return S_OK; +} + +STDMETHODIMP CSessionDescription::get_type(__out BSTR* pVal) +{ + if (!m_Sdp) { + CHECK_HR_RETURN(E_POINTER); + } + const _Buffer* pcType = m_Sdp->getType(); + if (pcType && pcType->getPtr()) { + std::string type((const char*)pcType->getPtr(), pcType->getSize()); + return Utils::CopyAnsiString(type, pVal); + } + else { + *pVal = NULL; + return S_OK; + } +} + +STDMETHODIMP CSessionDescription::put_type(__in BSTR newVal) +{ + char* lpszType = _com_util::ConvertBSTRToString(newVal); + if (!lpszType) { + CHECK_HR_RETURN(E_OUTOFMEMORY); + } + const _Buffer* _sdp = m_Sdp ? m_Sdp->getSdp() : NULL; + std::shared_ptr<_SessionDescription> newSdp = std::make_shared<_SessionDescription>( + _sdp ? _sdp->getPtr() : NULL, + _sdp ? _sdp->getSize() : 0, + lpszType, + lpszType ? strlen(lpszType) : 0); + delete[] lpszType; + m_Sdp = newSdp; + return S_OK; +} + +STDMETHODIMP CSessionDescription::get_sdp(__out BSTR* pVal) +{ + if (!m_Sdp) { + CHECK_HR_RETURN(E_POINTER); + } + const _Buffer* pcSdp = m_Sdp->getSdp(); + if (pcSdp && pcSdp->getPtr()) { + std::string sdp((const char*)pcSdp->getPtr(), pcSdp->getSize()); + return Utils::CopyAnsiString(sdp, pVal); + } + else { + *pVal = NULL; + return S_OK; + } +} + +STDMETHODIMP CSessionDescription::put_sdp(__in BSTR newVal) +{ + char* lpszSdp = _com_util::ConvertBSTRToString(newVal); + if (!lpszSdp) { + CHECK_HR_RETURN(E_OUTOFMEMORY); + } + const _Buffer* _type = m_Sdp ? m_Sdp->getType() : NULL; + std::shared_ptr<_SessionDescription> newSdp = std::make_shared<_SessionDescription>( + lpszSdp, + lpszSdp ? strlen(lpszSdp) : 0, + _type ? _type->getPtr() : NULL, + _type ? _type->getSize() : 0); + delete[] lpszSdp; + m_Sdp = newSdp; + return S_OK; +} + diff --git a/ie/SessionDescription.h b/ie/SessionDescription.h new file mode 100644 index 0000000..67de8c9 --- /dev/null +++ b/ie/SessionDescription.h @@ -0,0 +1,60 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/webrtc/#session-description-model + +#pragma once +#include "../common/_Config.h" +#include "../common/_SessionDescription.h" +#include "resource.h" // main symbols + +#include "webrtceverywhere_i.h" + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + + + +// CSessionDescription + +class ATL_NO_VTABLE CSessionDescription : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CSessionDescription(); + + DECLARE_REGISTRY_RESOURCEID(IDR_SESSIONDESCRIPTION) + + + BEGIN_COM_MAP(CSessionDescription) + COM_INTERFACE_ENTRY(ISessionDescription) + COM_INTERFACE_ENTRY(IDispatch) + END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + void FinalRelease(); + + HRESULT Init(VARIANT RTCSessionDescriptionInit); + +public: + WE_INLINE void SetSdp(std::shared_ptr<_SessionDescription> & sdp) { m_Sdp = sdp; } + WE_INLINE std::shared_ptr<_SessionDescription> GetSdp() { return m_Sdp; } + + STDMETHOD(get_type)(__out BSTR* pVal); + STDMETHOD(put_type)(__in BSTR newVal); + STDMETHOD(get_sdp)(__out BSTR* pVal); + STDMETHOD(put_sdp)(__in BSTR newVal); + + + +private: + std::shared_ptr<_SessionDescription> m_Sdp; +}; + +OBJECT_ENTRY_AUTO(__uuidof(SessionDescription), CSessionDescription) diff --git a/ie/SessionDescription.rgs b/ie/SessionDescription.rgs new file mode 100644 index 0000000..7ba9c58 --- /dev/null +++ b/ie/SessionDescription.rgs @@ -0,0 +1,26 @@ +HKCR +{ + webrtceverywhere.SessionDescription.1 = s 'SessionDescription Class' + { + CLSID = s '{3F7C50A7-7B5C-4631-8988-17B43A938667}' + } + webrtceverywhere.SessionDescription = s 'SessionDescription Class' + { + CLSID = s '{3F7C50A7-7B5C-4631-8988-17B43A938667}' + CurVer = s 'webrtceverywhere.SessionDescription.1' + } + NoRemove CLSID + { + ForceRemove {3F7C50A7-7B5C-4631-8988-17B43A938667} = s 'SessionDescription Class' + { + ProgID = s 'webrtceverywhere.SessionDescription.1' + VersionIndependentProgID = s 'webrtceverywhere.SessionDescription' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + } + } +} diff --git a/ie/SourceInfo.cc b/ie/SourceInfo.cc new file mode 100644 index 0000000..d5fffdd --- /dev/null +++ b/ie/SourceInfo.cc @@ -0,0 +1,71 @@ +/* Copyright(C) 2014 Sarandogou */ + +// http://www.w3.org/TR/mediacapture-streams/#idl-def-SourceInfo + +#include "stdafx.h" +#include "SourceInfo.h" +#include "Utils.h" + +#include "../common/_Debug.h" + +CSourceInfo::CSourceInfo() + : m_Info(nullptr) +{ +} + +HRESULT CSourceInfo::FinalConstruct() +{ + return S_OK; +} + +void CSourceInfo::FinalRelease() +{ + m_Info = nullptr; +} + +void CSourceInfo::SetInfo(std::shared_ptr<_SourceInfo> & info) +{ + m_Info = info; +} + +std::shared_ptr<_SourceInfo> CSourceInfo::GetInfo() +{ + return m_Info; +} + +STDMETHODIMP CSourceInfo::get_sourceId(__out BSTR* pVal) +{ + if (!m_Info) { + CHECK_HR_RETURN(E_POINTER); + } + return Utils::CopyAnsiString(m_Info->sourceId, pVal); +} + +STDMETHODIMP CSourceInfo::get_id(__out BSTR* pVal) +{ + return get_sourceId(pVal); +} + +STDMETHODIMP CSourceInfo::get_kind(__out BSTR* pVal) +{ + if (!m_Info) { + CHECK_HR_RETURN(E_POINTER); + } + return Utils::CopyAnsiString(m_Info->kind, pVal); +} + +STDMETHODIMP CSourceInfo::get_label(__out BSTR* pVal) +{ + if (!m_Info) { + CHECK_HR_RETURN(E_POINTER); + } + return Utils::CopyAnsiString(m_Info->label, pVal); +} + +STDMETHODIMP CSourceInfo::get_facing(__out BSTR* pVal) +{ + if (!m_Info) { + CHECK_HR_RETURN(E_POINTER); + } + return Utils::CopyAnsiString(m_Info->facing, pVal); +} diff --git a/ie/SourceInfo.h b/ie/SourceInfo.h new file mode 100644 index 0000000..1e61b70 --- /dev/null +++ b/ie/SourceInfo.h @@ -0,0 +1,62 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/TR/mediacapture-streams/#idl-def-SourceInfo + +#pragma once +#include "resource.h" // main symbols + +#include "../common/_Config.h" +#include "../common/_Common.h" + +#include "webrtceverywhere_i.h" + + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + +using namespace ATL; + + +// CSourceInfo + +class ATL_NO_VTABLE CSourceInfo : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CSourceInfo(); + +DECLARE_REGISTRY_RESOURCEID(IDR_SOURCEINFO) + + +BEGIN_COM_MAP(CSourceInfo) + COM_INTERFACE_ENTRY(ISourceInfo) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct(); + + void FinalRelease(); + + void SetInfo(std::shared_ptr<_SourceInfo> & info); + std::shared_ptr<_SourceInfo> GetInfo(); + +public: + STDMETHOD(get_sourceId)(__out BSTR* pVal); + STDMETHOD(get_id)(__out BSTR* pVal); + STDMETHOD(get_kind)(__out BSTR* pVal); + STDMETHOD(get_label)(__out BSTR* pVal); + STDMETHOD(get_facing)(__out BSTR* pVal); + +private: + std::shared_ptr<_SourceInfo> m_Info; + +}; + +OBJECT_ENTRY_AUTO(__uuidof(SourceInfo), CSourceInfo) diff --git a/ie/SourceInfo.rgs b/ie/SourceInfo.rgs new file mode 100644 index 0000000..161723a --- /dev/null +++ b/ie/SourceInfo.rgs @@ -0,0 +1,16 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {E66A3288-4BFB-41E2-850D-61C63208DD80} = s 'SourceInfo Class' + { + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + Version = s '1.0' + } + } +} diff --git a/ie/Utils.cc b/ie/Utils.cc new file mode 100644 index 0000000..5628750 --- /dev/null +++ b/ie/Utils.cc @@ -0,0 +1,439 @@ +/* Copyright(C) 2014 Sarandogou */ + +#include "stdafx.h" +#include "Utils.h" + +#include "../common/_Debug.h" + +Utils::Utils() + : _Utils() +{ +} + +Utils::~Utils() +{ + +} + +HRESULT Utils::ToString(__in BSTR* bstr, __out std::string & str) +{ + if (!bstr || !*bstr) { + CHECK_HR_RETURN(E_INVALIDARG); + } + char* lpszStr = _com_util::ConvertBSTRToString(*bstr); + if (!lpszStr) { + CHECK_HR_RETURN(E_OUTOFMEMORY); + } + str = std::string(lpszStr); + + delete[]lpszStr; + return S_OK; +} + +HRESULT Utils::CopyAnsiStr(__in LPCSTR psz, __out BSTR* bstr) +{ + *bstr = NULL; + if (psz) { + CComBSTR _bstr(psz); + return _bstr.CopyTo(bstr); + } + return S_OK; +} + + +HRESULT Utils::CopyAnsiString(__in std::string str, __out BSTR* bstr) +{ + return Utils::CopyAnsiStr(str.c_str(), bstr); +} + +CComPtr Utils::VariantToDispatch(VARIANT var) +{ + CComPtr disp = (var.vt == VT_DISPATCH && var.pdispVal) ? var.pdispVal : NULL; + return disp; +} + +BOOL Utils::VariantIsBool(__in const VARIANT &var) +{ + return var.vt == VT_BOOL; +} + +BOOL Utils::VariantIsInteger(__in const VARIANT &var) +{ + switch (var.vt) { + case VT_I2: case VT_I4: case VT_I1: case VT_UI1: case VT_UI2: case VT_UI4: case VT_I8: case VT_UI8: case VT_INT: case VT_UINT: return TRUE; + default: return FALSE; + } +} + +BOOL Utils::VariantIsFloat(__in const VARIANT &var) +{ + switch (var.vt) { + case VT_R4: case VT_R8: return TRUE; + default: return FALSE; + } +} + +BOOL Utils::VariantIsBSTR(__in const VARIANT &var) +{ + return var.vt == VT_BSTR; +} + +HRESULT Utils::VariantToInteger(VARIANT var, long &integer) +{ + CComVariant _var; + HRESULT hr = VariantChangeType(&_var, &var, 0, VT_I4); + CHECK_HR_RETURN(hr); + integer = _var.lVal; + return S_OK; +} + +HRESULT Utils::VariantToDouble(VARIANT var, double &val) +{ + CComVariant _var; + HRESULT hr = VariantChangeType(&_var, &var, 0, VT_I4); + CHECK_HR_RETURN(hr); + val = _var.dblVal; + return S_OK; +} + +HRESULT Utils::VariantToBSTR(VARIANT var, BSTR &bstr) +{ + if (var.vt != VT_BSTR) { + CHECK_HR_RETURN(E_INVALIDARG); + } + bstr = var.bstrVal; + return S_OK; +} + +HRESULT Utils::VariantToArray(__in const CComVariant& var, __out std::vector& vecVars) +{ + HRESULT hr = S_OK; + CComPtr disp = Utils::VariantToDispatch(var); + if (!disp) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + CComVariant varLength; + hr = Utils::DispatchGetProp(disp, L"length", &varLength); + CHECK_HR_RETURN(hr); + + long intLength; + hr = Utils::VariantToInteger(varLength, intLength); + CHECK_HR_RETURN(hr); + + // Arrays are essentially handled as objects that implement the IDispatch interface pointer, and have a property named "length", + // which describes the length of the array, and the property "0" will be the first element, property "1" the second element, and so on. + WCHAR wcharIndex[25]; + CComVariant varItem; + for (long index = 0 ; index < intLength ; ++index) { + wsprintf(wcharIndex, _T("%ld\0"), index); + hr = Utils::DispatchGetProp(disp, CComBSTR(wcharIndex), &varItem); + CHECK_HR_RETURN(hr); + vecVars.push_back(varItem); + } + + return hr; +} + +HRESULT Utils::DispatchGetProp(CComPtr disp, LPOLESTR name, VARIANT *pVar) +{ + HRESULT hr = S_OK; + + if (!pVar) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + DISPID dispid = 0; + hr = disp->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); + CHECK_HR_RETURN(hr); + + DISPPARAMS dispParams = {0}; + hr = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, pVar, NULL, NULL); + CHECK_HR_RETURN(hr); + return hr; +} + +HRESULT Utils::DispatchGetPropBSTR(__in CComPtr disp, __in LPOLESTR name, __out BSTR &bstr) +{ + VARIANT varBSTR; + HRESULT hr = Utils::DispatchGetProp(disp, name, &varBSTR); + CHECK_HR_RETURN(hr); + return Utils::VariantToBSTR(varBSTR, bstr); +} + +HRESULT Utils::DispatchGetPropInteger(__in CComPtr disp, __in LPOLESTR name, __out long &_long) +{ + VARIANT varLONG; + HRESULT hr = Utils::DispatchGetProp(disp, name, &varLONG); + CHECK_HR_RETURN(hr); + return Utils::VariantToInteger(varLONG, _long); +} + +HRESULT Utils::CreateJsObject(__in CComPtr spDispatch, __in LPOLESTR className, __out CComQIPtr& spObject) +{ + HRESULT hr = S_OK; + + DISPID classID; + CHECK_HR_RETURN(hr = spDispatch->GetIDsOfNames(IID_NULL, &className, 1, LOCALE_USER_DEFAULT, &classID)); + + CComVariant vtRet; + DISPPARAMS params = { 0 }; + CComVariant vtResult; + CHECK_HR_RETURN(hr = spDispatch->Invoke(classID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms, &vtResult, NULL, NULL)); + if (!vtResult.pdispVal || (vtResult.vt != VT_DISPATCH)) { + CHECK_HR_RETURN(DISP_E_TYPEMISMATCH); + } + + CComQIPtr spPrototype(vtResult.pdispVal); + if (!spPrototype) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + + vtResult.Clear(); + CHECK_HR_RETURN(hr = spPrototype->InvokeEx(DISPID_VALUE, LOCALE_USER_DEFAULT, DISPATCH_CONSTRUCT, ¶ms, &vtResult, NULL, NULL)); + + if (!vtResult.pdispVal || (vtResult.vt != VT_DISPATCH)) { + CHECK_HR_RETURN(DISP_E_TYPEMISMATCH); + } + + spObject = CComQIPtr(vtResult.pdispVal); + if (!spObject) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + + return hr; +} + +HRESULT Utils::CreateJsArray(__in CComPtr spDispatch, __in std::vector &vecValues, __out CComQIPtr& spArray) +{ + HRESULT hr = S_OK; + static LPOLESTR __ArrayClassName = L"Array"; + + CHECK_HR_RETURN(hr = Utils::CreateJsObject(spDispatch, __ArrayClassName, spArray)); + + // Values + WCHAR wcharIndex[25]; + DISPID dispID; + DISPID indexNamedArgs[] = { DISPID_PROPERTYPUT }; + DISPPARAMS params = { NULL, indexNamedArgs, 1, 1 }; + for (size_t index = 0; index < vecValues.size(); ++index) { + wsprintf(wcharIndex, _T("%ld\0"), index); + CHECK_HR_RETURN(hr = spArray->GetDispID(CComBSTR(wcharIndex), fdexNameEnsure, &dispID)); + params.rgvarg = &vecValues[index]; + CHECK_HR_RETURN(hr = spArray->InvokeEx(dispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, NULL)); + } + + // "length" property + CHECK_HR_RETURN(hr = spArray->GetDispID(L"length", fdexNameEnsure, &dispID)); + CComVariant varLength(vecValues.size()); + params.rgvarg = &varLength; + CHECK_HR_RETURN(hr = spArray->InvokeEx(dispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, NULL)); + + return hr; +} + +// e.g. varConstraints = "{ maxWidth: 320, maxHeight : 180 }" +HRESULT Utils::BuildMediaConstraints(__in VARIANT varConstraints, __out std::shared_ptr<_MediaConstraints>& constraints) +{ + if (varConstraints.vt == VT_EMPTY || varConstraints.vt == VT_NULL || varConstraints.vt == VT_ERROR /* optional parameter */) { + return S_OK; + } + + CComQIPtr spConstraints = CComQIPtr(Utils::VariantToDispatch(varConstraints)); + if (!spConstraints) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + + if (!constraints) { + constraints = std::make_shared<_MediaConstraints>(); + } + + CComVariant var; + CComBSTR bstrName; + std::string strName, strVal; + DISPID dispid; + HRESULT hr; + hr = spConstraints->GetNextDispID(fdexEnumAll, DISPID_STARTENUM, &dispid); + while (hr != S_FALSE) { + CHECK_HR_RETURN(hr = spConstraints->GetMemberName(dispid, &bstrName)); + CHECK_HR_RETURN(hr = Utils::DispatchGetProp(spConstraints.p, bstrName, &var)); + CHECK_HR_RETURN(hr = Utils::ToString(&bstrName, strName)); + if (Utils::VariantIsBool(var)) { + strVal = (var.boolVal != VARIANT_FALSE) ? "true" : "false"; + } + else if (Utils::VariantIsInteger(var)) { + long v; + CHECK_HR_RETURN(hr = Utils::VariantToInteger(var, v)); + char s[25]; + sprintf(s, "%ld", v); + strVal = std::string(s); + } + else if (Utils::VariantIsFloat(var)) { + double v; + CHECK_HR_RETURN(hr = Utils::VariantToDouble(var, v)); + char s[25]; + sprintf(s, "%f", v); + strVal = std::string(s); + } + else if (Utils::VariantIsBSTR(var)) { + CHECK_HR_RETURN(hr = Utils::ToString(&var.bstrVal, strVal)); + } + else if (var.vt == VT_DISPATCH && var.pdispVal) { + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraints(var, constraints)); + goto next; + } + else { + goto next; + } + + constraints->insert(std::pair(strName, strVal)); + + next: + hr = spConstraints->GetNextDispID(fdexEnumAll, dispid, &dispid); + } + + return S_OK; +} + +HRESULT Utils::BuildMediaStreamConstraints(__in VARIANT varConstraints, __out std::shared_ptr<_MediaStreamConstraints> &constraints) +{ + if (varConstraints.vt == VT_EMPTY || varConstraints.vt == VT_NULL || varConstraints.vt == VT_ERROR /* optional parameter */) { + return S_OK; + } + + HRESULT hr = S_OK; + CComQIPtr spConstraints = CComQIPtr(Utils::VariantToDispatch(varConstraints)); + if (!spConstraints) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + + std::shared_ptr<_MediaTrackConstraints> audio; + std::shared_ptr<_MediaTrackConstraints> video; + CComVariant var; + + hr = Utils::DispatchGetProp(spConstraints.p, L"video", &var); + if (SUCCEEDED(hr)) { + if (Utils::VariantIsBool(var)) { + video = std::make_shared<_MediaTrackConstraints>(var.boolVal != VARIANT_FALSE); + } + else { + std::shared_ptr<_MediaConstraints> mandatory; + std::shared_ptr<_MediaConstraints> optional; + CComQIPtr spVideo = CComQIPtr(Utils::VariantToDispatch(var)); + if (!spVideo) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + hr = Utils::DispatchGetProp(spVideo.p, L"mandatory", &var); + if (SUCCEEDED(hr)) { + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraints(var, mandatory)); + } + hr = Utils::DispatchGetProp(spVideo.p, L"optional", &var); + if (SUCCEEDED(hr)) { + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraints(var, optional)); + } + video = std::make_shared<_MediaTrackConstraints>(mandatory, optional); + } + } + hr = Utils::DispatchGetProp(spConstraints.p, L"audio", &var); + if (SUCCEEDED(hr)) { + if (Utils::VariantIsBool(var)) { + audio = std::make_shared<_MediaTrackConstraints>(var.boolVal != VARIANT_FALSE); + } + else { + std::shared_ptr<_MediaConstraints> mandatory; + std::shared_ptr<_MediaConstraints> optional; + CComQIPtr spAudio = CComQIPtr(Utils::VariantToDispatch(var)); + if (!spAudio) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + hr = Utils::DispatchGetProp(spAudio.p, L"mandatory", &var); + if (SUCCEEDED(hr)) { + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraints(var, mandatory)); + } + hr = Utils::DispatchGetProp(spAudio.p, L"optional", &var); + if (SUCCEEDED(hr)) { + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraints(var, optional)); + } + audio = std::make_shared<_MediaTrackConstraints>(mandatory, optional); + } + } + + constraints = std::make_shared<_MediaStreamConstraints>(audio, video); + return S_OK; +} + +HRESULT Utils::BuildMediaConstraintsObjs(__in VARIANT varConstraints, __out std::shared_ptr<_MediaConstraintsObj> &constraints) +{ + HRESULT hr; + + if (varConstraints.vt == VT_EMPTY || varConstraints.vt == VT_NULL || varConstraints.vt == VT_ERROR /* optional parameter */) { + return S_OK; + } + + CComQIPtr spConstraints = CComQIPtr(Utils::VariantToDispatch(varConstraints)); + if (!spConstraints) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + + std::shared_ptr<_MediaConstraints> mandatory; + std::shared_ptr<_MediaConstraints> optional; + VARIANT var; + hr = Utils::DispatchGetProp(spConstraints.p, L"mandatory", &var); + if (SUCCEEDED(hr)) { + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraints(var, mandatory)); + } + hr = Utils::DispatchGetProp(spConstraints.p, L"optional", &var); + if (SUCCEEDED(hr)) { + CHECK_HR_RETURN(hr = Utils::BuildMediaConstraints(var, optional)); + } + + constraints = std::make_shared<_MediaConstraintsObj>(optional, mandatory); + return S_OK; +} + +HRESULT Utils::BuildRTCConfiguration(__in VARIANT varConfiguration, __out std::shared_ptr<_RTCConfiguration> &configuration) +{ + if (varConfiguration.vt == VT_EMPTY || varConfiguration.vt == VT_NULL || varConfiguration.vt == VT_ERROR /* optional parameter */) { + return S_OK; + } + + CComQIPtr spConfiguration = CComQIPtr(Utils::VariantToDispatch(varConfiguration)); + if (!spConfiguration) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + + configuration = std::make_shared<_RTCConfiguration>(); + + VARIANT varIceServers; + HRESULT hr; + hr = Utils::DispatchGetProp(spConfiguration.p, L"iceServers", &varIceServers); + if (SUCCEEDED(hr)) { + std::vectorvectIceServers; + hr = Utils::VariantToArray(varIceServers, vectIceServers); + if (SUCCEEDED(hr)) { + CComPtrdispServer; + for (unsigned i = 0; i < vectIceServers.size(); i++) { + dispServer = Utils::VariantToDispatch(vectIceServers[i]); + if (dispServer) { + BSTR bstr; + std::string uri, username, password; + hr = Utils::DispatchGetPropBSTR(dispServer, L"url", bstr); + if (SUCCEEDED(hr)) { + CHECK_HR_RETURN(hr = Utils::ToString(&bstr, uri)); + } + hr = Utils::DispatchGetPropBSTR(dispServer, L"username", bstr); + if (SUCCEEDED(hr)) { + CHECK_HR_RETURN(hr = Utils::ToString(&bstr, username)); + } + hr = Utils::DispatchGetPropBSTR(dispServer, L"credential", bstr); + if (SUCCEEDED(hr)) { + CHECK_HR_RETURN(hr = Utils::ToString(&bstr, password)); + } + configuration->iceServers.push_back(__RTCIceServer(uri, username, password)); + } + } + } + } + + return S_OK; +} \ No newline at end of file diff --git a/ie/Utils.h b/ie/Utils.h new file mode 100644 index 0000000..f117969 --- /dev/null +++ b/ie/Utils.h @@ -0,0 +1,51 @@ +/* Copyright(C) 2014 Sarandogou */ +#pragma once +#include "../common/_Config.h" +#include "../common/_Utils.h" +#include "../common/_MediaStreamConstraints.h" + +#include +#include +#include +#include + +class Utils : public _Utils +{ +public: + Utils(); + virtual ~Utils(); + + static HRESULT ToString(__in BSTR* bstr, __out std::string & str); + static HRESULT CopyAnsiStr(__in LPCSTR psz, __out BSTR* bstr); + static HRESULT CopyAnsiString(__in std::string str, __out BSTR* bstr); + static CComPtr VariantToDispatch(VARIANT var); + static BOOL VariantIsBool(__in const VARIANT &var); + static BOOL VariantIsInteger(__in const VARIANT &var); + static BOOL VariantIsFloat(__in const VARIANT &var); + static BOOL VariantIsBSTR(__in const VARIANT &var); + static HRESULT VariantToInteger(VARIANT var, long &integer); + static HRESULT VariantToDouble(VARIANT var, double &val); + static HRESULT VariantToBSTR(VARIANT var, BSTR &bstr); + static HRESULT VariantToArray(__in const CComVariant& var, __out std::vector& vecVars); + static HRESULT DispatchGetProp(CComPtr disp, LPOLESTR name, VARIANT *pVar); + static HRESULT DispatchGetPropBSTR(__in CComPtr disp, __in LPOLESTR name, __out BSTR &bstr); + static HRESULT DispatchGetPropInteger(__in CComPtr disp, __in LPOLESTR name, __out long &_long); + static HRESULT CreateJsObject(__in CComPtr spDispatch, __in LPOLESTR className, __out CComQIPtr& spObject); + static HRESULT CreateJsArray(__in CComPtr spDispatch, __in std::vector &vecValues, __out CComQIPtr& spArray); + static HRESULT BuildMediaConstraints(__in VARIANT varConstraints, __out std::shared_ptr<_MediaConstraints>& constraints); + static HRESULT BuildMediaStreamConstraints(__in VARIANT varConstraints, __out std::shared_ptr<_MediaStreamConstraints> &constraints); + static HRESULT BuildMediaConstraintsObjs(__in VARIANT varConstraints, __out std::shared_ptr<_MediaConstraintsObj> &constraints); + static HRESULT BuildRTCConfiguration(__in VARIANT varConfiguration, __out std::shared_ptr<_RTCConfiguration> &configuration); + + template + static HRESULT CreateInstanceWithRef(T** ppObject) + { + CComObject *pObject; + HRESULT hr = CComObject::CreateInstance(&pObject); + if (SUCCEEDED(hr)) { + pObject->AddRef(); + *ppObject = pObject; + } + return hr; + } +}; diff --git a/ie/WebRTC.bmp b/ie/WebRTC.bmp new file mode 100644 index 0000000000000000000000000000000000000000..122976492c7c0572b0bab819e7a01b7c59a56c22 GIT binary patch literal 246 zcmZvTu@S={3`M{1a>w~-Oz90WNBZodDsCCUl-fd_3mT?MOTHkb1z%6nmtOBLW_*Yz zwf(i=F^oL&U83V=&J)Zm(OM(j=;NbzuP8nrd2dAIz<@|O9Wa}$vyYd+g5Ww13Dg-R lBFL&IBCx8eaZ`(GWv_ctBa7~-@={Amew7$okj0rc#}8UDI@bUI literal 0 HcmV?d00001 diff --git a/ie/WebRTC.cc b/ie/WebRTC.cc new file mode 100644 index 0000000..bdc2f69 --- /dev/null +++ b/ie/WebRTC.cc @@ -0,0 +1,388 @@ +/* Copyright(C) 2014 Sarandogou */ + +// http://www.w3.org/wiki/HTML/Elements/video +#include "stdafx.h" +#include "WebRTC.h" +#include "MediaStream.h" +#include "SessionDescription.h" +#include "DictOptions.h" +#include "PeerConnection.h" +#include "RTCIceCandidate.h" +#include "BrowserCallback.h" +#include "MediaStreamTrack.h" +#include "Utils.h" + +#include "../common/_NavigatorUserMedia.h" +#include "../common/_Debug.h" + +#include + +CWebRTC::CWebRTC() + : _AsyncEventDispatcher() + , _RTCDisplay() + , m_pTempVideoBuff(NULL) +{ + m_bWindowOnly = TRUE; +} + +HRESULT CWebRTC::FinalConstruct() +{ + _Utils::Initialize(); + TakeFakePeerConnectionFactory(); + return S_OK; +} + +// _RTCDisplay::Handle() implementation +HWND CWebRTC::Handle() +{ + return m_hWnd; +} + +// _RTCDisplay::OnStartVideoRenderer() implementation +void CWebRTC::OnStartVideoRenderer() +{ + if (m_callbacks_onplay.size()) { + for (size_t i = 0; i < m_callbacks_onplay.size(); ++i) { + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, m_callbacks_onplay[i]); + if (_cb) { + _cb->AddDispatch(this); // not part of the standard: no arg to the callback + dynamic_cast<_AsyncEventDispatcher*>(this)->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + } +} + +// _RTCDisplay::OnStopVideoRenderer() implementation +void CWebRTC::OnStopVideoRenderer() +{ + +} + +LRESULT CWebRTC::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + SetWindow(m_hWnd); + return S_OK; +} + +void CWebRTC::FinalRelease() +{ + StopVideoRenderer(); + SetDispatcher(NULL); + m_callbacks_onplay.clear(); + SafeDelete(&m_pTempVideoBuff); + ReleaseFakePeerConnectionFactory(); +} + +STDMETHODIMP CWebRTC::get_versionName(BSTR* pVal) +{ + return Utils::CopyAnsiStr(kPluginVersionString, pVal); +} + +STDMETHODIMP CWebRTC::createSessionDescription(VARIANT RTCSessionDescriptionInit, IDispatch** ppSdp) +{ + CComObject* pSdp = NULL; + HRESULT hr; + + CHECK_HR_BAIL(hr = Utils::CreateInstanceWithRef(&pSdp)); + CHECK_HR_BAIL(hr = pSdp->Init(RTCSessionDescriptionInit)); + + *ppSdp = pSdp, pSdp = NULL; + +bail: + SafeRelease(&pSdp); + return hr; +} + +STDMETHODIMP CWebRTC::createDisplay(__out IDispatch** ppDisplay) +{ + CComObject* pDisplay = NULL; + HRESULT hr; + + CHECK_HR_BAIL(hr = Utils::CreateInstanceWithRef(&pDisplay)); + + pDisplay->SetDispatcher(this); + + *ppDisplay = pDisplay, pDisplay = NULL; + +bail: + SafeRelease(&pDisplay); + return hr; +} + +STDMETHODIMP CWebRTC::getUserMedia(VARIANT constraints, VARIANT successCallback, VARIANT errorCallback) +{ + HRESULT hr = S_OK; + + CComPtr_constraints = Utils::VariantToDispatch(constraints); + CComPtr_successCallback = Utils::VariantToDispatch(successCallback); + CComPtr_errorCallback = Utils::VariantToDispatch(errorCallback); + + std::shared_ptr<_MediaStreamConstraints> mediaStreamConstraints; + + hr = Utils::BuildMediaStreamConstraints(constraints, mediaStreamConstraints); + + _NavigatorUserMedia::getUserMedia( + mediaStreamConstraints.get(), + [_successCallback, this](std::shared_ptr<_MediaStream> stream) { + if (_successCallback) { + CComObject* _stream; + HRESULT _hr = Utils::CreateInstanceWithRef(&_stream); + if (SUCCEEDED(_hr)) { + BrowserCallback* _cb = new BrowserCallback(WM_GETUSERMEDIA_SUCESS, _successCallback); + if (_cb) { + _stream->SetStream(stream); + _stream->SetDispatcher(this); + _cb->AddDispatch(_stream); + dynamic_cast<_AsyncEventDispatcher*>(this)->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + SafeRelease(&_stream); + } + } + }, + [_errorCallback, this](std::shared_ptr<_NavigatorUserMediaError> e) { + if (_errorCallback) { + BrowserCallback* _cb = new BrowserCallback(WM_GETUSERMEDIA_ERROR, _errorCallback); + if (_cb) { + CComBSTR err(e->constraintName.c_str()); + _cb->AddBSTR(err); + dynamic_cast<_AsyncEventDispatcher*>(this)->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + } + ); + + return hr; +} + +STDMETHODIMP CWebRTC::createDictOptions(IDispatch** ppDictOptions) +{ + CComObject* pDictOptions; + HRESULT hr; + + CHECK_HR_RETURN(hr = Utils::CreateInstanceWithRef(&pDictOptions)); + + *ppDictOptions = pDictOptions; + return S_OK; +} + + +STDMETHODIMP CWebRTC::createPeerConnection(VARIANT RTCConfiguration, VARIANT/*optional*/ MediaConstraints, IDispatch** ppPeerConnection) +{ + CComObject* pPeerConnection; + HRESULT hr; + CHECK_HR_RETURN(hr = Utils::CreateInstanceWithRef(&pPeerConnection)); + + hr = pPeerConnection->Init(RTCConfiguration, MediaConstraints); + if (FAILED(hr)) { + SafeRelease(&pPeerConnection); + return hr; + } + pPeerConnection->SetDispatcher(this); + + *ppPeerConnection = pPeerConnection; + return S_OK; +} + +STDMETHODIMP CWebRTC::createIceCandidate(VARIANT RTCIceCandidateInit, IDispatch** ppIceCandidate) +{ + CComObject* pIceCandidate; + HRESULT hr; + + CHECK_HR_BAIL(hr = Utils::CreateInstanceWithRef(&pIceCandidate)); + CHECK_HR_BAIL(hr = pIceCandidate->Init(RTCIceCandidateInit)); + + *ppIceCandidate = pIceCandidate, pIceCandidate = NULL; + +bail: + SafeRelease(&pIceCandidate); + return hr; +} + +STDMETHODIMP CWebRTC::createMediaStreamTrack(__out IDispatch** ppMediaStreamTrack) +{ + CComObject* pMediaStreamTrack; + HRESULT hr; + + CHECK_HR_BAIL(hr = Utils::CreateInstanceWithRef(&pMediaStreamTrack)); + *ppMediaStreamTrack = pMediaStreamTrack, pMediaStreamTrack = NULL; + +bail: + SafeRelease(&pMediaStreamTrack); + return hr; +} + +STDMETHODIMP CWebRTC::bindEventListener(__in BSTR type, __in_opt VARIANT listenerCallback, __in_opt VARIANT useCapture) +{ + if (!type) { + CHECK_HR_RETURN(E_INVALIDARG); + } + char* lpszType = _com_util::ConvertBSTRToString(type); + if (!lpszType) { + CHECK_HR_RETURN(E_OUTOFMEMORY); + } + if (!strcmp(lpszType, "play")) { + CComPtr callback = Utils::VariantToDispatch(listenerCallback); + if (callback) { + m_callbacks_onplay.push_back(callback); + } + } + + delete[]lpszType; + + return S_OK; +} + +STDMETHODIMP CWebRTC::getSources(__in_opt VARIANT successCallback) +{ + CComPtr_successCallback = Utils::VariantToDispatch(successCallback); + if (!_successCallback) { + return S_OK; + } + HRESULT hr; + CComVariant var; + CComPtr spDispatch; + CHECK_HR_RETURN(hr = GetDispatch(spDispatch)); + CHECK_HR_RETURN(hr = CMediaStreamTrack::getSources(spDispatch, &var)); + + CComPtr_sources = Utils::VariantToDispatch(var); + if (!_sources) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + + BrowserCallback* _cb = new BrowserCallback(WM_SUCCESS, _successCallback); + if (!_cb) { + CHECK_HR_RETURN(E_OUTOFMEMORY); + } + _cb->AddDispatch(_sources); + dynamic_cast<_AsyncEventDispatcher*>(this)->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + + return S_OK; +} + +STDMETHODIMP CWebRTC::put_src(VARIANT newVal) +{ + CComPtrmediaStream = Utils::VariantToDispatch(newVal); + if (mediaStream) { + CComPtr _mediaStream = NULL; + HRESULT hr; + CHECK_HR_RETURN(hr = mediaStream->QueryInterface(&_mediaStream)); + + CMediaStream* pStream = dynamic_cast(_mediaStream.p); + if (!pStream) { + CHECK_HR_RETURN(E_INVALIDARG); + } + std::shared_ptr<_MediaStream> stream = pStream->GetStream(); + if (stream) { + StartVideoRenderer(stream->GetVideoTrack()); + } + } + else { + StopVideoRenderer(); + } + return S_OK; +} + +STDMETHODIMP CWebRTC::get_videoWidth(__out LONG* pVal) +{ + *pVal = (LONG)GetVideoWidth(); + return S_OK; +} + +STDMETHODIMP CWebRTC::get_videoHeight(__out LONG* pVal) +{ + *pVal = (LONG)GetVideoHeight(); + return S_OK; +} + +STDMETHODIMP CWebRTC::fillImageData(__in VARIANT imageData) +{ + HRESULT hr = S_OK; + + CComQIPtr spImageData = CComQIPtr(Utils::VariantToDispatch(imageData)); + if (!spImageData) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + + int videoWidth = GetVideoWidth(); + int videoHeight = GetVideoHeight(); + + if (videoHeight <= 0 || videoWidth <= 0) { + return S_OK; + } + + long index, width = 0, height = 0; + VARIANT varData; + CHECK_HR_RETURN(hr = Utils::DispatchGetProp(spImageData.p, L"data", &varData)); + CHECK_HR_RETURN(hr = Utils::DispatchGetPropInteger(spImageData.p, L"width", width)); + CHECK_HR_RETURN(hr = Utils::DispatchGetPropInteger(spImageData.p, L"height", height)); + + CComQIPtr spDataArray = CComQIPtr(Utils::VariantToDispatch(varData)); + if (!spDataArray) { + CHECK_HR_RETURN(E_NOINTERFACE); + } + + if (width != videoWidth || height != videoHeight) { + CHECK_HR_RETURN(E_INVALIDARG); + } + + size_t videoSize = (videoWidth * videoHeight * 4); + + if (!m_pTempVideoBuff || m_pTempVideoBuff->getSize() < videoSize){ + SafeDelete(&m_pTempVideoBuff); + if ((_Buffer::New(NULL, videoSize, &m_pTempVideoBuff))) { + CHECK_HR_RETURN(E_OUTOFMEMORY); + } + } + + if (CopyFromFrame(const_cast(m_pTempVideoBuff->getPtr()), videoSize) != videoSize) { + memset(const_cast(m_pTempVideoBuff->getPtr()), 0, videoSize); + } + + WCHAR wcharIndex[25]; + DISPID dispID; + VARIANT vParam; + vParam.vt = VT_I4; + DISPID indexNamedArgs[] = { DISPID_PROPERTYPUT }; + DISPPARAMS params = { &vParam, indexNamedArgs, 1, 1 }; + const uint8_t* imageDataPtr = (const uint8_t*)m_pTempVideoBuff->getPtr(); + for (long x = 0; x < width; ++x) { + for (long y = 0; y < height; ++y) { + index = (x + y * width) * 4; + for (long comp = 0; comp < 4; ++comp) { // (a, r, g, b) -> (r, g, b, a) + wsprintf(wcharIndex, _T("%ld\0"), index + comp); + CHECK_HR_RETURN(hr = spDataArray->GetDispID(CComBSTR(wcharIndex), fdexNameEnsure, &dispID)); + vParam.lVal = imageDataPtr[index + ((comp + 0) & 3)]; + CHECK_HR_RETURN(hr = spDataArray->InvokeEx(dispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, NULL)); + } + } + } + return hr; +} + +STDMETHODIMP CWebRTC::get_isWebRtcPlugin(__out VARIANT_BOOL* pVal) +{ + *pVal = VARIANT_TRUE; + return S_OK; +} + +HRESULT CWebRTC::GetDispatch(CComPtr &spDispatch) +{ + HRESULT hr = S_OK; + IHTMLDocument2* pDoc = NULL; + + CComPtr spContainer; + CComPtr spDoc; + CComPtr spWindow; + + CHECK_HR_BAIL(hr = m_spClientSite->GetContainer(&spContainer)); + CHECK_HR_BAIL(hr = spContainer->QueryInterface(IID_IHTMLDocument2, (void**)&pDoc)); + CHECK_HR_BAIL(hr = pDoc->get_parentWindow(&spWindow)); + CHECK_HR_BAIL(hr = spWindow->QueryInterface(IID_IDispatch, (void**)&spDispatch)); + +bail: + return hr; +} \ No newline at end of file diff --git a/ie/WebRTC.h b/ie/WebRTC.h new file mode 100644 index 0000000..8f982e7 --- /dev/null +++ b/ie/WebRTC.h @@ -0,0 +1,221 @@ +/* Copyright(C) 2014 Sarandogou */ +// http://www.w3.org/wiki/HTML/Elements/video +#pragma once +#include "../common/_Config.h" +#include "../common/_AsyncEvent.h" +#include "../common/_RTCDisplay.h" +#include "../common/_Common.h" +#include "../common/_Buffer.h" +#include "resource.h" // main symbols +#include +#include "webrtceverywhere_i.h" +#include "_IWebRTCEvents_CP.h" + +#include +#include + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + + +// CWebRTC +class ATL_NO_VTABLE CWebRTC : + public _AsyncEventDispatcher, + public _AsyncEventRaiser, + public _RTCDisplay, + public CComObjectRootEx, + public IDispatchImpl, + public IPersistStreamInitImpl, + public IOleControlImpl, + public IOleObjectImpl, + public IOleInPlaceActiveObjectImpl, + public IViewObjectExImpl, + public IOleInPlaceObjectWindowlessImpl, + public ISupportErrorInfo, + public IConnectionPointContainerImpl, + public CProxy_IWebRTCEvents, + public IPersistStorageImpl, + public ISpecifyPropertyPagesImpl, + public IQuickActivateImpl, +#ifndef _WIN32_WCE + public IDataObjectImpl, +#endif + public IProvideClassInfo2Impl<&CLSID_WebRTC, &__uuidof(_IWebRTCEvents), &LIBID_webrtceverywhereLib>, +#ifdef _WIN32_WCE // IObjectSafety is required on Windows CE for the control to be loaded correctly + public IObjectSafetyImpl, +#endif + public CComCoClass, + public CComControl, + public IObjectSafetyImpl +{ +public: + + + CWebRTC(); + + DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE | + OLEMISC_CANTLINKINSIDE | + OLEMISC_INSIDEOUT | + OLEMISC_ACTIVATEWHENVISIBLE | + OLEMISC_SETCLIENTSITEFIRST + ) + + DECLARE_REGISTRY_RESOURCEID(IDR_WEBRTC) + + + BEGIN_COM_MAP(CWebRTC) + COM_INTERFACE_ENTRY(IWebRTC) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IViewObjectEx) + COM_INTERFACE_ENTRY(IViewObject2) + COM_INTERFACE_ENTRY(IViewObject) + COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless) + COM_INTERFACE_ENTRY(IOleInPlaceObject) + COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless) + COM_INTERFACE_ENTRY(IOleInPlaceActiveObject) + COM_INTERFACE_ENTRY(IOleControl) + COM_INTERFACE_ENTRY(IOleObject) + COM_INTERFACE_ENTRY(IPersistStreamInit) + COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit) + COM_INTERFACE_ENTRY(ISupportErrorInfo) + COM_INTERFACE_ENTRY(IConnectionPointContainer) + COM_INTERFACE_ENTRY(ISpecifyPropertyPages) + COM_INTERFACE_ENTRY(IQuickActivate) + COM_INTERFACE_ENTRY(IPersistStorage) +#ifndef _WIN32_WCE + COM_INTERFACE_ENTRY(IDataObject) +#endif + COM_INTERFACE_ENTRY(IProvideClassInfo) + COM_INTERFACE_ENTRY(IProvideClassInfo2) +#ifdef _WIN32_WCE // IObjectSafety is required on Windows CE for the control to be loaded correctly + COM_INTERFACE_ENTRY_IID(IID_IObjectSafety, IObjectSafety) +#endif + COM_INTERFACE_ENTRY(IObjectSafety) + END_COM_MAP() + + BEGIN_PROP_MAP(CWebRTC) + PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4) + PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4) + // Example entries + // PROP_ENTRY_TYPE("Property Name", dispid, clsid, vtType) + // PROP_PAGE(CLSID_StockColorPage) + END_PROP_MAP() + + BEGIN_CONNECTION_POINT_MAP(CWebRTC) + CONNECTION_POINT_ENTRY(__uuidof(_IWebRTCEvents)) + END_CONNECTION_POINT_MAP() + + BEGIN_MSG_MAP(CWebRTC) + CHAIN_MSG_MAP(CComControl) + DEFAULT_REFLECTION_HANDLER() + MESSAGE_HANDLER(WM_CREATE, OnCreate) + END_MSG_MAP() +// Handler prototypes: +// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); +// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); +// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled); + +// ISupportsErrorInfo + STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) { + static const IID* arr[] = { + &IID_IWebRTC, + }; + + for (int i=0; i &spDispatch); + + private: + _Buffer *m_pTempVideoBuff; + std::vector>m_callbacks_onplay; +}; + +OBJECT_ENTRY_AUTO(__uuidof(WebRTC), CWebRTC) diff --git a/ie/WebRTC.rgs b/ie/WebRTC.rgs new file mode 100644 index 0000000..9aaa71b --- /dev/null +++ b/ie/WebRTC.rgs @@ -0,0 +1,34 @@ +HKCR +{ + webrtceverywhere.WebRTC.1 = s 'WebRTC Class' + { + CLSID = s '{7FD49E23-C8D7-4C4F-93A1-F7EACFA1EC53}' + } + webrtceverywhere.WebRTC = s 'WebRTC Class' + { + CLSID = s '{7FD49E23-C8D7-4C4F-93A1-F7EACFA1EC53}' + CurVer = s 'webrtceverywhere.WebRTC.1' + } + NoRemove CLSID + { + ForceRemove {7FD49E23-C8D7-4C4F-93A1-F7EACFA1EC53} = s 'WebRTC Class' + { + ProgID = s 'webrtceverywhere.WebRTC.1' + VersionIndependentProgID = s 'webrtceverywhere.WebRTC' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + val AppID = s '%APPID%' + ForceRemove 'Control' + ForceRemove 'ToolboxBitmap32' = s '%MODULE%, 102' + 'MiscStatus' = s '0' + { + '1' = s '%OLEMISC%' + } + 'TypeLib' = s '{12E5324E-D53E-4C89-BFA4-E3020902DD62}' + 'Version' = s '1.0' + } + } +} diff --git a/ie/_IWebRTCEvents_CP.h b/ie/_IWebRTCEvents_CP.h new file mode 100644 index 0000000..b6aec27 --- /dev/null +++ b/ie/_IWebRTCEvents_CP.h @@ -0,0 +1,8 @@ +#pragma once + +template +class CProxy_IWebRTCEvents : public IConnectionPointImpl +{ + //Warning this class will be regenerated by the wizard. +public: +}; diff --git a/ie/dlldata.c b/ie/dlldata.c new file mode 100644 index 0000000..7888905 --- /dev/null +++ b/ie/dlldata.c @@ -0,0 +1,40 @@ +/********************************************************* + DllData file -- generated by MIDL compiler + + DO NOT ALTER THIS FILE + + This file is regenerated by MIDL on every IDL file compile. + + To completely reconstruct this file, delete it and rerun MIDL + on all the IDL files in this DLL, specifying this file for the + /dlldata command line option + +*********************************************************/ + +#define PROXY_DELEGATION + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +EXTERN_PROXY_FILE( aProxyFileList2C_GET_DLL_CLSID ) +EXTERN_PROXY_FILE( webrtceverywhere ) + + +PROXYFILE_LIST_START +/* Start of list */ + REFERENCE_PROXY_FILE( aProxyFileList2C_GET_DLL_CLSID ), + REFERENCE_PROXY_FILE( webrtceverywhere ), +/* End of list */ +PROXYFILE_LIST_END + + +DLLDATA_ROUTINES( aProxyFileList, GET_DLL_CLSID ) + +#ifdef __cplusplus +} /*extern "C" */ +#endif + +/* end of generated dlldata file */ diff --git a/ie/dllmain.cc b/ie/dllmain.cc new file mode 100644 index 0000000..66c8d2f --- /dev/null +++ b/ie/dllmain.cc @@ -0,0 +1,37 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "stdafx.h" +#include "resource.h" +#include "webrtceverywhere_i.h" +#include "dllmain.h" + +CwebrtceverywhereModule _AtlModule; + +// DLL Entry Point +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ +#if 0 + switch (dwReason) { + case DLL_PROCESS_ATTACH: + { + _Utils::Initialize(); + break; + } + case DLL_PROCESS_DETACH: + { + _Utils::DeInitialize(); + break; + } + case DLL_THREAD_ATTACH: + { + break; + } + case DLL_THREAD_DETACH: + { + break; + } + } +#endif + hInstance; + return _AtlModule.DllMain(dwReason, lpReserved); +} diff --git a/ie/dllmain.h b/ie/dllmain.h new file mode 100644 index 0000000..fbb2b55 --- /dev/null +++ b/ie/dllmain.h @@ -0,0 +1,10 @@ +/* Copyright(C) 2014 Sarandogou */ + +class CwebrtceverywhereModule : public CAtlDllModuleT< CwebrtceverywhereModule > +{ +public : + DECLARE_LIBID(LIBID_webrtceverywhereLib) + DECLARE_REGISTRY_APPID_RESOURCEID(IDR_WEBRTCEVERYWHERE, "{CD79082C-21B8-4EBF-81D8-F0E36B6F4090}") +}; + +extern class CwebrtceverywhereModule _AtlModule; diff --git a/ie/resource.h b/ie/resource.h new file mode 100644 index 0000000..75ea089 --- /dev/null +++ b/ie/resource.h @@ -0,0 +1,32 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by webrtc-everywhere.rc +// +#define IDS_PROJNAME 100 +#define IDR_WEBRTCEVERYWHERE 101 +#define IDB_WEBRTC 102 +#define IDR_WEBRTC 103 +#define IDR_SESSIONDESCRIPTION 104 +#define IDR_DICTOPTIONS 105 +#define IDR_PEERCONNECTION 106 +#define IDR_NAVIGATORUSERMEDIA 107 +#define IDR_MEDIASTREAM 108 +#define IDR_RTCICECANDIDATE 109 +#define IDR_MEDIASTREAMTRACK 110 +#define IDR_SOURCEINFO 111 +#define IDR_MEDIASOURCESTATES 112 +#define IDR_MEDIASTREAMEVENT 113 +#define IDR_RTCPEERCONNECTIONICEEVENT 114 +#define IDR_RTCSTATSREPORT 115 +#define IDR_RTCSTATS 116 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 117 +#endif +#endif diff --git a/ie/stdafx.cc b/ie/stdafx.cc new file mode 100644 index 0000000..0b3c6c1 --- /dev/null +++ b/ie/stdafx.cc @@ -0,0 +1,7 @@ +/* Copyright(C) 2014 Sarandogou */ + +// stdafx.cpp : source file that includes just the standard includes +// webrtc-everywhere.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/ie/stdafx.h b/ie/stdafx.h new file mode 100644 index 0000000..3c3cd44 --- /dev/null +++ b/ie/stdafx.h @@ -0,0 +1,24 @@ +/* Copyright(C) 2014 Sarandogou */ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#pragma once + +#ifndef STRICT +#define STRICT +#endif + +#include "targetver.h" + +#define _ATL_APARTMENT_THREADED +#define _ATL_NO_AUTOMATIC_NAMESPACE + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#include "resource.h" +#include +#include +#include + +using namespace ATL; diff --git a/ie/targetver.h b/ie/targetver.h new file mode 100644 index 0000000..8bee2d7 --- /dev/null +++ b/ie/targetver.h @@ -0,0 +1,26 @@ +/* Copyright(C) 2014 Sarandogou */ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Specifies that the minimum required platform is Windows Vista. +#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. +#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. +#endif + diff --git a/ie/webrtc-everywhere-ie.vcproj b/ie/webrtc-everywhere-ie.vcproj new file mode 100644 index 0000000..4bbb0d2 --- /dev/null +++ b/ie/webrtc-everywhere-ie.vcproj @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ie/webrtc-everywhere-ie.vcxproj b/ie/webrtc-everywhere-ie.vcxproj new file mode 100644 index 0000000..a813afb --- /dev/null +++ b/ie/webrtc-everywhere-ie.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {FEF60750-96B0-4124-9007-B90780B6267D} + webrtc-everywhere + AtlProj + + + + DynamicLibrary + v120 + Dynamic + Unicode + + + DynamicLibrary + v120 + Dynamic + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + false + + + + _DEBUG;%(PreprocessorDefinitions) + false + Win32 + true + $(IntDir)webrtceverywhere.tlb + webrtceverywhere_i.h + + webrtceverywhere_i.c + webrtceverywhere_p.c + true + + + Disabled + ../thirdparties/win32/include;../thirdparties/common/include;../thirdparties\common\include\webrtc-sdk;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;_USRDLL;JSONCPP_RELATIVE_PATH;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + true + EditAndContinue + 4996;%(DisableSpecificWarnings) + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + + + true + comsuppw.lib;Oleacc.lib;RpcRT4.lib;$(OutDir)webrtc-everywhere-common.lib;%(AdditionalDependencies) + .\webrtc-everywhere.def + true + Windows + MachineX86 + 5.01 + AsInvoker + + + + + NDEBUG;%(PreprocessorDefinitions) + false + Win32 + true + $(IntDir)webrtceverywhere.tlb + webrtceverywhere_i.h + + webrtceverywhere_i.c + webrtceverywhere_p.c + true + + + MaxSpeed + WIN32;_WINDOWS;NDEBUG;_USRDLL;JSONCPP_RELATIVE_PATH;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreaded + + Level3 + true + ProgramDatabase + ../thirdparties/win32/include;../thirdparties/common/include;../thirdparties\common\include\webrtc-sdk;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + + + true + .\webrtc-everywhere.def + true + Windows + true + true + MachineX86 + 5.01 + AsInvoker + comsuppw.lib;Oleacc.lib;RpcRT4.lib;$(OutDir)webrtc-everywhere-common.lib;%(AdditionalDependencies) + + + + + + + + + false + + + false + + + + + + + + + + + + + + Create + Create + + + + + + + + false + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {95230956-8581-4f03-a589-c6217119de9e} + false + + + + + + \ No newline at end of file diff --git a/ie/webrtc-everywhere-ie.vcxproj.filters b/ie/webrtc-everywhere-ie.vcxproj.filters new file mode 100644 index 0000000..3dc8f77 --- /dev/null +++ b/ie/webrtc-everywhere-ie.vcxproj.filters @@ -0,0 +1,207 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {852ec013-933a-4acd-9fcc-59f6799bc7df} + False + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Generated Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Generated Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/ie/webrtc-everywhere.aps b/ie/webrtc-everywhere.aps new file mode 100644 index 0000000000000000000000000000000000000000..ede43abb52ef65cd498563a92296bc92801fd85d GIT binary patch literal 13468 zcmds7O>7&-6&@u{6xwkkCuvcmMZv@|8jJKvJ?@7!W9GEz_Y$ zhNSHnX@DGZ$|(kNsDNAw^w6VjDG(IMp@%f5qQ{;JvpgouU-V7-&$t6W8X@O{@ zE93)S@{75(G9CdnSwcdCoL?@8+7hbM?6j<2@_Fv}2`qL-Lh|lL z?uuJ36xU0xC?F z>H!Pc7HhLEtAc&V?&E5+hwK5nBc4K*!ut;EfFh2^4tQJ_Jc{7#AA)@c*d<_h@K<9^ z)?k5ntD=n>Ye5QGJG;#qxCFqg0>2QU>KxMgUC^zeJ?fz^T5sT)xXjaP9bT~t{B2-Y zpvNw_gm~ILq}5%}N!{eoR*04>=r?iM##0wH<{=y!Q(G=Wh6=d8eF%ppIF!)id%!0d za**IQ-e>E%HP-Hso_a53KTPNEjPV$1jSE|AfYWR#+TbAdH*4&qZs+CMIp8_yNe9*) z!j_uQ&|wmFW2lFH==Gj}Z{42oi!E46OZer#o*4JnuO|GpjM$XR`zz}Kf~bJL0Mh9<8j{_=Wax}A9Hf6j`K7H&zSk; zcrtH~^G^%@(HZJ^jKgupmS8+K#~qLNZNXc|_~~GJFe4w2*{)z_F@GZ(qIU;1htFfT5OG6bQq=B5Vqpq1 z9df7$-yPskTu-trXzBt#$u6;XnZqphDtKH+J;m@Q+U)@E8s4QG4x*U`42rN-(B1^{+)SWaN@5pGdTZ z>^1U=;-+j{Lnr`a@{;Ks)Nv|New~9QJ00p6R1*AK&5s{MZQ)jjAwq?y2FoX2Pm9`^P)|zh3i#>Jex&VE z!v6%xbXtJMEmu=B5`1QyQrfKsgBIk^3V6h7HBFO{vk}Uu&1$e_LHeBtf)GlYp{5xU z{+xhMw^t1oEf_5g5Tn+rX=w>PHv(lELXe<(KC;vrSqf=l;+VM(gF=UJtnkK`S!3YI zWttd}gB6q_Y#%E_*f1g{)4l?X@uV2!OJf5WRNk+m;op2O&6#E#Nm zsNHUChqsehbC%bGTmdV*jlwk^oIQP^)~MF+ZHLL1yOs7%*u|ejc2ExQ4-B_Z}hE1!hhmeM5@KCTXL#_bVW%TZiF}x(O zCFYv~_ZRFucn#+L_|+*Pj`AGfC&g^v!OTCpo|U{+Y;z2GZ$P^C!8(|DYRDbb{zWbMU%Q5GZf5|WB`0k$Ct zL+jsz3^WF`Qf&)u)g#(HJnu?@6SYP%biBHvoVr^Y>F9 z;jZF}+h36uJnG9=uldEZr{6n!I+1S{!`;No)fXUR@- zdEDQZ1xSYxfvuRnnN>1|t0`HVyMETyxSuxO zCrT1`N@L%2QwjfGdn0U1wo}?nX#=4SMo)BW(8p{O+pPUzov)Mey^tD9U}tz|ptG40 zB@&RlQ)@PIn5ozENcVu!U|u_mHd9!q_E57 zhplj>w$;aZPt$qY&`qucX@kRjos8mTT~pzPs;e1Q4+2XU<_mxB4@{p_OUb5*FE0GU z$Nq`Aahe~}`j*O^epm`SWClUlskUpaE*=LyISHBJpGMa9)2eGLwwLx5(=s&0$vBRp z*`8^*8N;zGd%AzdG$n#rO#So_F}Db_{dTg=Bl+-LQb;qOY-y?f3|)ls%W3{mlkPFEe+0E^w;=qYGjNPZ)o{QjW~{*S9N$XoitXyIV%nai zIKJU1h8LtgPvyE}OP43HCt`K94dDvWis?QuccZg?Akx^8jDN1?rSV6a7%FidtB(*K z)7&E*zU6lQml<|`_egeL3sY-h*v8!1z?bF7EHGL-9I6R>S2a7Z0@YQ#z{3oX4t!*2 zmZP{f53IBuxV{-oodG7Amqzlv z9`k8EN+tSjVYoJ#BQy8hv}2@QT?w?TgY?D<6wga@#ZfZ`H@MEZ%HNk`yBcoSDy1&6 z+TEeI^anPYI7jDGk>LJs(&m05DrGxL9@d(;ku2lE&^=;tfhMDy#dIY9o z>W-#l{EVu2cA%?R>ba_J^z}{Ktkux3U=MA((hX0v&Vv~`Z+u;y2d)-qrlu>NZwQ?` zFmKaVtZbHRhUQzQot?Dta=TJ}`y?y<%^5nUeM&0Fjw{@f1c@Pcf!b z3|r0iiMDvg-k70t`o=}&*gDVJX`SmCOr>cbKX%$sTvzp#G*TPr9-p@je@y2mIlerG zE|a(hrxfuxvhQ^X?@RrQj)YM8K>Wu207AeIK9D#3;*ovv#TU2}fDX3PttW5zm1o^? z-^b$_RO~Z$1{dAw#`gE+{d4(#=Cc;tUu?0@9z19*;`(^8b%rgr5_=!hA@9WA-rhbi z_a5!-eUA6N^N;rSaeuUT{@mxF+P-+y&#{5%^rXZmIEL}&a1T(i#j{~G@Bn-QEZ1()dgZaM>A2h$;+ z$ur<|?(~N^jX%WsYJv})!838*euy)929M6Gy@rntL!8O;YIG*4j)V3?oXImubQa^c z&mHY7#u{iI&!mx>jehI60Gj&JtaczQN|c7qLhOTP+F6K?fbYCG|2JFuPWtaD_;KG! z>3hyEzaP&(?t2dHZ-4rOc>K8iZQ3XN@JI3Zar=a{m-6vT@%V9jDYO?r2UX&}X~*pa zP_Eg1B_2O+9ZPGl#~0)AIehe6et literal 0 HcmV?d00001 diff --git a/ie/webrtc-everywhere.cc b/ie/webrtc-everywhere.cc new file mode 100644 index 0000000..e9f10ec --- /dev/null +++ b/ie/webrtc-everywhere.cc @@ -0,0 +1,65 @@ +// webrtc-everywhere.cpp : Implementation of DLL Exports. + + +#include "stdafx.h" +#include "resource.h" +#include "webrtceverywhere_i.h" +#include "dllmain.h" + +// Used to determine whether the DLL can be unloaded by OLE +STDAPI DllCanUnloadNow(void) +{ + return _AtlModule.DllCanUnloadNow(); +} + + +// Returns a class factory to create an object of the requested type +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _AtlModule.DllGetClassObject(rclsid, riid, ppv); +} + + +// DllRegisterServer - Adds entries to the system registry +STDAPI DllRegisterServer(void) +{ + // registers object, typelib and all interfaces in typelib + HRESULT hr = _AtlModule.DllRegisterServer(); + return hr; +} + + +// DllUnregisterServer - Removes entries from the system registry +STDAPI DllUnregisterServer(void) +{ + HRESULT hr = _AtlModule.DllUnregisterServer(); + return hr; +} + +// DllInstall - Adds/Removes entries to the system registry per user +// per machine. +STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine) +{ + HRESULT hr = E_FAIL; + static const wchar_t szUserSwitch[] = _T("user"); + + if (pszCmdLine != NULL) { + if (_wcsnicmp(pszCmdLine, szUserSwitch, _countof(szUserSwitch)) == 0) { + AtlSetPerUserRegistration(true); + } + } + + if (bInstall) { + hr = DllRegisterServer(); + if (FAILED(hr)) { + DllUnregisterServer(); + } + } + else { + hr = DllUnregisterServer(); + } + + return hr; +} + + diff --git a/ie/webrtc-everywhere.def b/ie/webrtc-everywhere.def new file mode 100644 index 0000000..52b1fd3 --- /dev/null +++ b/ie/webrtc-everywhere.def @@ -0,0 +1,10 @@ +; webrtc-everywhere.def : Declares the module parameters. + +LIBRARY "webrtc-everywhere.DLL" + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + DllInstall PRIVATE diff --git a/ie/webrtc-everywhere.rc b/ie/webrtc-everywhere.rc new file mode 100644 index 0000000..f7f2499 --- /dev/null +++ b/ie/webrtc-everywhere.rc @@ -0,0 +1,160 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#ifndef APSTUDIO_INVOKED +#include "targetver.h" +#endif +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#ifndef APSTUDIO_INVOKED\r\n" + "#include ""targetver.h""\r\n" + "#endif\r\n" + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "1 TYPELIB ""webrtceverywhere.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Sarandogou" + VALUE "FileDescription", "WebRTC plugin for Safari, IE, Chrome, Opera and Firefox" + VALUE "FileVersion", "1.0.0.1" + VALUE "LegalCopyright", "(c) 2014 Sarandogou. All rights reserved." + VALUE "InternalName", "webrtc-everywhere.dll" + VALUE "OriginalFilename", "webrtc-everywhere.dll" + VALUE "ProductName", "WebRTC Everywhere Plugin" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// REGISTRY +// + +IDR_WEBRTCEVERYWHERE REGISTRY "webrtc-everywhere.rgs" +IDR_WEBRTC REGISTRY "WebRTC.rgs" +IDR_SESSIONDESCRIPTION REGISTRY "SessionDescription.rgs" +IDR_DICTOPTIONS REGISTRY "DictOptions.rgs" +IDR_PEERCONNECTION REGISTRY "PeerConnection.rgs" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_WEBRTC BITMAP "WebRTC.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_PROJNAME "webrtc-everywhere" +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// French (France) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) +LANGUAGE LANG_FRENCH, SUBLANG_FRENCH +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// REGISTRY +// + +IDR_MEDIASTREAM REGISTRY "MediaStream.rgs" +IDR_RTCICECANDIDATE REGISTRY "RTCIceCandidate4.rgs" +IDR_MEDIASTREAMTRACK REGISTRY "MediaStreamTrack.rgs" +IDR_SOURCEINFO REGISTRY "SourceInfo.rgs" +IDR_MEDIASOURCESTATES REGISTRY "MediaSourceStates.rgs" +IDR_MEDIASTREAMEVENT REGISTRY "MediaStreamEvent.rgs" +IDR_RTCPEERCONNECTIONICEEVENT REGISTRY "RTCPeerConnectionIceEvent.rgs" +IDR_RTCSTATSREPORT REGISTRY "RTCStatsReport.rgs" +IDR_RTCSTATS REGISTRY "RTCStats.rgs" +#endif // French (France) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +1 TYPELIB "webrtceverywhere.tlb" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/ie/webrtc-everywhere.rgs b/ie/webrtc-everywhere.rgs new file mode 100644 index 0000000..6a8b763 --- /dev/null +++ b/ie/webrtc-everywhere.rgs @@ -0,0 +1,11 @@ +HKCR +{ + NoRemove AppID + { + '%APPID%' = s 'webrtceverywhere' + 'webrtc-everywhere.DLL' + { + val AppID = s '%APPID%' + } + } +} diff --git a/ie/webrtc-everywherePS.vcproj b/ie/webrtc-everywherePS.vcproj new file mode 100644 index 0000000..8849e1c --- /dev/null +++ b/ie/webrtc-everywherePS.vcproj @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ie/webrtc-everywherePS.vcxproj b/ie/webrtc-everywherePS.vcxproj new file mode 100644 index 0000000..cd615a0 --- /dev/null +++ b/ie/webrtc-everywherePS.vcxproj @@ -0,0 +1,104 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {D287DCCF-9020-46BD-A740-28C012A01D75} + webrtc-everywherePS + AtlPSProj + + + + DynamicLibrary + v120 + Unicode + + + DynamicLibrary + v120 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + $(Configuration)PS\ + $(Configuration)PS\ + + + $(Configuration)PS\ + $(Configuration)PS\ + + + + Checking for required files + if exist dlldata.c goto :END +echo Error: MIDL will not generate DLLDATA.C unless you have at least 1 interface in the main project. +Exit 1 +:END + + + + WIN32;_WIN32_WINNT=0x0500;REGISTER_PROXY_DLL;_DEBUG;%(PreprocessorDefinitions) + MultiThreadedDebug + + + true + kernel32.lib;rpcns4.lib;rpcrt4.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) + webrtc-everywherePS.def + 5.01 + + + + + Checking for required files + if exist dlldata.c goto :END +echo Error: MIDL will not generate DLLDATA.C unless you have at least 1 interface in the main project. +Exit 1 +:END + + + + MaxSpeed + WIN32;_WIN32_WINNT=0x0500;REGISTER_PROXY_DLL;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + + + true + kernel32.lib;rpcns4.lib;rpcrt4.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) + webrtc-everywherePS.def + true + true + 5.01 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ie/webrtc-everywherePS.vcxproj.filters b/ie/webrtc-everywherePS.vcxproj.filters new file mode 100644 index 0000000..94f3497 --- /dev/null +++ b/ie/webrtc-everywherePS.vcxproj.filters @@ -0,0 +1,26 @@ + + + + + {f5dc4c32-06e8-46a1-bc37-63a003070dcb} + + + {70fd2b84-8d84-47b3-84d5-6ac031a0976b} + False + + + + + Generated Files + + + Generated Files + + + Generated Files + + + + + + \ No newline at end of file diff --git a/ie/webrtc-everywhereps.def b/ie/webrtc-everywhereps.def new file mode 100644 index 0000000..cd35f5c --- /dev/null +++ b/ie/webrtc-everywhereps.def @@ -0,0 +1,8 @@ + +LIBRARY "webrtc-everywherePS" + +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/ie/webrtceverywhere.idl b/ie/webrtceverywhere.idl new file mode 100644 index 0000000..c661b62 --- /dev/null +++ b/ie/webrtceverywhere.idl @@ -0,0 +1,365 @@ +// webrtceverywhere.idl : IDL source for webrtc-everywhere +// + +// This file will be processed by the MIDL tool to +// produce the type library (webrtceverywhere.tlb) and marshalling code. + +#include "olectl.h" +import "oaidl.idl"; +import "ocidl.idl"; + +[ + object, + uuid(4994FB92-A5F5-4292-AB60-472AA4937C9E), + dual, + nonextensible, + helpstring("IWebRTC Interface"), + pointer_default(unique) +] +interface IWebRTC : IDispatch{ + [propget, id(1), helpstring("property versionName")] HRESULT versionName([out, retval] BSTR* pVal); + [id(2), helpstring("method getUserMedia")] HRESULT getUserMedia([in, optional] VARIANT constraints, [in, optional]VARIANT successCallback, [in, optional]VARIANT errorCallback); + + [id(3), helpstring("method createDisplay")] HRESULT createDisplay([out, retval] IDispatch** ppDisplay); + [id(4), helpstring("method createSessionDescription")] HRESULT createSessionDescription([in] VARIANT RTCSessionDescriptionInit, [out, retval] IDispatch** ppSdp); + [id(5), helpstring("method createDictOptions")] HRESULT createDictOptions([out, retval] IDispatch** ppDictOptions); + [id(6), helpstring("method createPeerConnection")] HRESULT createPeerConnection([in, optional] VARIANT RTCConfiguration, [in, optional]VARIANT MediaConstraints, [out,retval] IDispatch** ppPeerConnection); + [id(7), helpstring("method createIceCandidate")] HRESULT createIceCandidate([in] VARIANT RTCIceCandidateInit, [out, retval] IDispatch** ppIceCandidate); + [id(8), helpstring("method createMediaStreamTrack")] HRESULT createMediaStreamTrack([out, retval] IDispatch** ppMediaStreamTrack); + + [id(40), helpstring("method bindEventListener")] HRESULT bindEventListener([in] BSTR type, [in, optional]VARIANT listenerCallback, [in, optional]VARIANT useCapture); + [id(41), helpstring("method getSources")] HRESULT getSources([in, optional]VARIANT successCallback); + + [propput, id(50), helpstring("property src")] HRESULT src([in] VARIANT newVal); + [propget, id(51), helpstring("property videoWidth")] HRESULT videoWidth([out, retval] LONG* pVal); + [propget, id(52), helpstring("property videoHeight")] HRESULT videoHeight([out, retval] LONG* pVal); + [id(53), helpstring("method fillImageData")] HRESULT fillImageData([in] VARIANT imageData); + [propget, id(54), helpstring("property isWebRtcPlugin")] HRESULT isWebRtcPlugin([out, retval] VARIANT_BOOL* pVal); +}; + +[ + object, + uuid(E7CFEF92-42B8-40FB-BCA9-E79D39ABCF72), + dual, + nonextensible, + helpstring("ISessionDescription Interface"), + pointer_default(unique) +] +interface ISessionDescription : IDispatch{ + [propget, id(1), helpstring("property type")] HRESULT type([out, retval] BSTR* pVal); + [propput, id(1), helpstring("property type")] HRESULT type([in] BSTR newVal); + [propget, id(2), helpstring("property sdp")] HRESULT sdp([out, retval] BSTR* pVal); + [propput, id(2), helpstring("property sdp")] HRESULT sdp([in] BSTR newVal); +}; +[ + object, + uuid(FA4B099C-3A15-4659-B288-565AD5258D4B), + dual, + nonextensible, + helpstring("IDictOptions Interface"), + pointer_default(unique) +] +interface IDictOptions : IDispatch{ +}; +[ + object, + uuid(462E3805-373B-46EE-9BEE-43E6110CB751), + dual, + nonextensible, + helpstring("IPeerConnection Interface"), + pointer_default(unique) +] +interface IPeerConnection : IDispatch{ + [id(1), helpstring("method createOffer")] HRESULT createOffer([in, optional] VARIANT successCallback, [in, optional] VARIANT failureCallback, [in, optional] VARIANT MediaConstraints); + [id(2), helpstring("method createAnswer")] HRESULT createAnswer([in, optional] VARIANT successCallback, [in, optional] VARIANT failureCallback, [in, optional] VARIANT MediaConstraints); + [id(3), helpstring("method setLocalDescription")] HRESULT setLocalDescription([in] VARIANT RTCSessionDescription, [in, optional] VARIANT successCallback, [in, optional] VARIANT failureCallback); + [propget, id(4), helpstring("property localDescription")] HRESULT localDescription([out, retval] VARIANT* pVal); + [id(5), helpstring("method setRemoteDescription")] HRESULT setRemoteDescription([in] VARIANT RTCSessionDescription, [in, optional] VARIANT successCallback, [in, optional] VARIANT failureCallback); + [propget, id(6), helpstring("property remoteDescription")] HRESULT remoteDescription([out, retval] VARIANT* pVal); + [propget, id(7), helpstring("property signalingState")] HRESULT signalingState([out, retval] BSTR* pVal); + [id(8), helpstring("method updateIce")] HRESULT updateIce([in] VARIANT RTCConfiguration, [in, optional] VARIANT MediaConstraints); + [id(9), helpstring("method addIceCandidate")] HRESULT addIceCandidate([in] VARIANT RTCIceCandidate, [in, optional] VARIANT successCallback, [in, optional] VARIANT failureCallback); + [propget, id(10), helpstring("property iceGatheringState")] HRESULT iceGatheringState([out, retval] BSTR* pVal); + [propget, id(11), helpstring("property iceConnectionState")] HRESULT iceConnectionState([out, retval] BSTR* pVal); + [id(12), helpstring("method getLocalStreams")] HRESULT getLocalStreams([out, retval] VARIANT* MediaStreams); + [id(13), helpstring("method getRemoteStreams")] HRESULT getRemoteStreams([out, retval] VARIANT* MediaStreams); + [id(14), helpstring("method getStreamById")] HRESULT getStreamById([in] BSTR streamId, [out, retval] VARIANT* MediaStream); + [id(15), helpstring("method addStream")] HRESULT addStream([in] VARIANT stream, [in, optional] VARIANT MediaConstraints); + [id(16), helpstring("method removeStream")] HRESULT removeStream([in] VARIANT stream); + [id(17), helpstring("method close")] HRESULT close(); + [id(18), helpstring("method getStats")] HRESULT getStats([in] VARIANT selector, [in, optional] VARIANT successCallback, [in, optional] VARIANT failureCallback); + + [propget, id(50), helpstring("property onnegotiationneeded")] HRESULT onnegotiationneeded([out, retval] VARIANT* pVal); + [propput, id(50), helpstring("property onnegotiationneeded")] HRESULT onnegotiationneeded([in] VARIANT newVal); + [propget, id(51), helpstring("property onicecandidate")] HRESULT onicecandidate([out, retval] VARIANT* pVal); + [propput, id(51), helpstring("property onicecandidate")] HRESULT onicecandidate([in] VARIANT newVal); + [propget, id(52), helpstring("property onsignalingstatechange")] HRESULT onsignalingstatechange([out, retval] VARIANT* pVal); + [propput, id(52), helpstring("property onsignalingstatechange")] HRESULT onsignalingstatechange([in] VARIANT newVal); + [propget, id(53), helpstring("property onaddstream")] HRESULT onaddstream([out, retval] VARIANT* pVal); + [propput, id(53), helpstring("property onaddstream")] HRESULT onaddstream([in] VARIANT newVal); + [propget, id(54), helpstring("property onremovestream")] HRESULT onremovestream([out, retval] VARIANT* pVal); + [propput, id(54), helpstring("property onremovestream")] HRESULT onremovestream([in] VARIANT newVal); + [propget, id(55), helpstring("property oniceconnectionstatechange")] HRESULT oniceconnectionstatechange([out, retval] VARIANT* pVal); + [propput, id(55), helpstring("property oniceconnectionstatechange")] HRESULT oniceconnectionstatechange([in] VARIANT newVal); +}; +[ + object, + uuid(21745AC4-2C31-481C-AB07-834C4D0E287A), + dual, + nonextensible, + pointer_default(unique) +] +interface IMediaStream : IDispatch{ + [propget, id(1), helpstring("property id")] HRESULT id([out, retval] BSTR* pVal); + [id(2), helpstring("method getAudioTracks")] HRESULT getAudioTracks([out, retval] VARIANT* Tracks); + [id(3), helpstring("method getVideoTracks")] HRESULT getVideoTracks([out, retval] VARIANT* Tracks); + [id(4), helpstring("method getTrackById")] HRESULT getTrackById([in] BSTR trackId, [out, retval] VARIANT* MediaStreamTrack); + [id(5), helpstring("method addTrack")] HRESULT addTrack([in] VARIANT MediaStreamTrack); + [id(6), helpstring("method removeTrack")] HRESULT removeTrack([in] VARIANT MediaStreamTrack); + [id(7), helpstring("method clone")] HRESULT clone([out, retval] VARIANT* MediaStream); + [propget, id(8), helpstring("property ended")] HRESULT ended([out, retval] VARIANT_BOOL* pVal); + [propget, id(9), helpstring("property onended")] HRESULT onended([out, retval] VARIANT* pVal); + [propput, id(9), helpstring("property onended")] HRESULT onended([in] VARIANT newVal); + [propget, id(10), helpstring("property onaddtrack")] HRESULT onaddtrack([out, retval] VARIANT* pVal); + [propput, id(10), helpstring("property onaddtrack")] HRESULT onaddtrack([in] VARIANT newVal); + [propget, id(11), helpstring("property onremovetrack")] HRESULT onremovetrack([out, retval] VARIANT* pVal); + [propput, id(11), helpstring("property onremovetrack")] HRESULT onremovetrack([in] VARIANT newVal); + [id(12), helpstring("method stop")] HRESULT stop(); // not part of the standard but used by Chrome +}; +[ + object, + uuid(FBE8F87D-BD47-4325-9196-7A36F339EE2A), + dual, + nonextensible, + pointer_default(unique) +] +interface IRTCIceCandidate : IDispatch{ + [propget, id(1)] HRESULT candidate([out, retval] BSTR* pVal); + [propget, id(2)] HRESULT sdpMid([out, retval] BSTR* pVal); + [propget, id(3)] HRESULT sdpMLineIndex([out, retval] USHORT* pVal); +}; +[ + object, + uuid(EDD26AE0-B068-4918-826D-E75BBE844B71), + dual, + nonextensible, + pointer_default(unique) +] +interface IMediaStreamTrack : IDispatch{ + [propget, id(1), helpstring("property kind")] HRESULT kind([out, retval] BSTR* pVal); + [propget, id(2), helpstring("property id")] HRESULT id([out, retval] BSTR* pVal); + [propget, id(3), helpstring("property label")] HRESULT label([out, retval] BSTR* pVal); + [propget, id(4), helpstring("property enabled")] HRESULT enabled([out, retval] VARIANT_BOOL* pVal); + [propput, id(4), helpstring("property enabled")] HRESULT enabled([in] VARIANT_BOOL newVal); + [propget, id(5), helpstring("property muted")] HRESULT muted([out, retval] VARIANT_BOOL* pVal); + [propget, id(6), helpstring("property onmute")] HRESULT onmute([out, retval] VARIANT* pVal); + [propput, id(6), helpstring("property onmute")] HRESULT onmute([in] VARIANT newVal); + [propget, id(7), helpstring("property onunmute")] HRESULT onunmute([out, retval] VARIANT* pVal); + [propput, id(7), helpstring("property onunmute")] HRESULT onunmute([in] VARIANT newVal); + [propget, id(8), helpstring("property readonly")] HRESULT readonly([out, retval] VARIANT_BOOL* pVal); + [propget, id(9), helpstring("property remote")] HRESULT remote([out, retval] VARIANT_BOOL* pVal); + [propget, id(10), helpstring("property readyState")] HRESULT readyState([out, retval] BSTR* pVal); + [propget, id(11), helpstring("property onstarted")] HRESULT onstarted([out, retval] VARIANT* pVal); + [propput, id(11), helpstring("property onstarted")] HRESULT onstarted([in] VARIANT newVal); + [propget, id(12), helpstring("property onended")] HRESULT onended([out, retval] VARIANT* pVal); + [propput, id(12), helpstring("property onended")] HRESULT onended([in] VARIANT newVal); + [id(13), helpstring("method getSourceInfos")] HRESULT getSourceInfos([out, retval] VARIANT* Infos); + [id(14), helpstring("method constraints")] HRESULT constraints([out, retval] VARIANT* MediaTrackConstraints); + [id(15), helpstring("method states")] HRESULT states([out, retval] VARIANT* MediaSourceStates); + [id(16), helpstring("method capabilities")] HRESULT capabilities([out, retval] VARIANT* AllCapabilities); + [id(17), helpstring("method applyConstraints")] HRESULT applyConstraints([in] VARIANT MediaTrackConstraints); + [propget, id(18), helpstring("property onoverconstrained")] HRESULT onoverconstrained([out, retval] VARIANT* pVal); + [propput, id(18), helpstring("property onoverconstrained")] HRESULT onoverconstrained([in] VARIANT newVal); + [id(19), helpstring("method clone")] HRESULT clone([out, retval] VARIANT* MediaStreamTrack); + [id(20), helpstring("method stop")] HRESULT stop(); +}; +[ + object, + uuid(BCD116DA-B4BC-472E-A6AE-363D13B78667), + dual, + nonextensible, + pointer_default(unique) +] +interface ISourceInfo : IDispatch{ + [propget, id(1), helpstring("property sourceId")] HRESULT sourceId([out, retval] BSTR* pVal); + [propget, id(2), helpstring("property id")] HRESULT id([out, retval] BSTR* pVal); + [propget, id(3), helpstring("property kind")] HRESULT kind([out, retval] BSTR* pVal); + [propget, id(4), helpstring("property label")] HRESULT label([out, retval] BSTR* pVal); + [propget, id(5), helpstring("property facing")] HRESULT facing([out, retval] BSTR* pVal); +}; +[ + object, + uuid(7A2B697F-688A-4CBE-B36F-4820D12BAE61), + dual, + nonextensible, + pointer_default(unique) +] +interface IMediaSourceStates : IDispatch{ + [propget, id(1), helpstring("method sourceType")] HRESULT sourceType([out, retval] BSTR* pVal); + [propget, id(2), helpstring("method sourceId")] HRESULT sourceId([out, retval] BSTR* pVal); + [propget, id(3), helpstring("method width")] HRESULT width([out, retval] VARIANT* pVal); + [propget, id(4), helpstring("method height")] HRESULT height([out, retval] VARIANT* pVal); + [propget, id(5), helpstring("method frameRate")] HRESULT frameRate([out, retval] VARIANT* pVal); + [propget, id(6), helpstring("method aspectRatio")] HRESULT aspectRatio([out, retval] VARIANT* pVal); + [propget, id(7), helpstring("method facingMode")] HRESULT facingMode([out, retval] VARIANT* pVal); + [propget, id(8), helpstring("method volume")] HRESULT volume([out, retval] VARIANT* pVal); +}; +[ + object, + uuid(EAB6AB59-5B8E-4096-AA67-0D557AA6BB32), + dual, + nonextensible, + pointer_default(unique) +] +interface IMediaStreamEvent : IDispatch{ + [propget, id(1), helpstring("method stream")] HRESULT stream([out, retval] VARIANT* pVal); +}; +[ + object, + uuid(354C2E39-380F-4F24-AEEA-687EB67F759D), + dual, + nonextensible, + pointer_default(unique) +] +interface IRTCPeerConnectionIceEvent : IDispatch{ + [propget, id(1), helpstring("method candidate")] HRESULT candidate([out, retval] VARIANT* pVal); +}; +[ + object, + uuid(455118D0-A29F-44DB-ACF7-FE22BFAE2167), + dual, + nonextensible, + pointer_default(unique) +] +interface IRTCStatsReport : IDispatch{ + [id(1), helpstring("method result")] HRESULT result([out, retval] VARIANT* RTCStatsList); +}; +[ + object, + uuid(CEFEB782-AFEC-4D0D-8C62-F1E255A73841), + dual, + nonextensible, + pointer_default(unique) +] +interface IRTCStats : IDispatch{ + [propget, id(1), helpstring("property timestamp")] HRESULT timestamp([out, retval] DOUBLE* pVal); + [propget, id(2), helpstring("property type")] HRESULT type([out, retval] BSTR* pVal); + [propget, id(3), helpstring("property id")] HRESULT id([out, retval] BSTR* pVal); + [id(4), helpstring("method names")] HRESULT names([out, retval] VARIANT* Names); + [id(5), helpstring("method stat")] HRESULT stat([in]BSTR name, [out, retval] BSTR* pVal); +}; +[ + uuid(12E5324E-D53E-4C89-BFA4-E3020902DD62), + version(1.0), + helpstring("webrtceverywhere 1.0 Type Library") +] +library webrtceverywhereLib +{ + importlib("stdole2.tlb"); + [ + uuid(20B33168-3B94-49C3-9E55-A60B9EA0E886), + helpstring("_IWebRTCEvents Interface") + ] + dispinterface _IWebRTCEvents + { + properties: + methods: + }; + [ + uuid(7FD49E23-C8D7-4C4F-93A1-F7EACFA1EC53), + control, + helpstring("WebRTC Class") + ] + coclass WebRTC + { + [default] interface IWebRTC; + [default, source] dispinterface _IWebRTCEvents; + }; + [ + uuid(3F7C50A7-7B5C-4631-8988-17B43A938667), + helpstring("SessionDescription Class") + ] + coclass SessionDescription + { + [default] interface ISessionDescription; + }; + [ + uuid(D6B8C652-7A2A-47B6-8C38-3BD5BB0E2872), + helpstring("DictOptions Class") + ] + coclass DictOptions + { + [default] interface IDictOptions; + }; + [ + uuid(017D6D0A-BDBC-45DC-9368-A7ED657DAC4D), + helpstring("PeerConnection Class") + ] + coclass PeerConnection + { + [default] interface IPeerConnection; + }; + [ + uuid(BA5835A2-D1F8-466D-BB5E-8093E3E2EE0E) + ] + coclass MediaStream + { + [default] interface IMediaStream; + }; + [ + uuid(31074FC8-A7D4-4281-9C90-B7D20C53A023) + ] + coclass RTCIceCandidate + { + [default] interface IRTCIceCandidate; + }; + [ + uuid(DA1D1412-BC34-4288-8047-6FFE131C647F) + ] + coclass MediaStreamTrack + { + [default] interface IMediaStreamTrack; + }; + [ + uuid(E66A3288-4BFB-41E2-850D-61C63208DD80) + ] + coclass SourceInfo + { + [default] interface ISourceInfo; + }; + [ + uuid(7F64ACB6-F21C-44C2-8EEA-EFCBEED5AEB7) + ] + coclass MediaSourceStates + { + [default] interface IMediaSourceStates; + }; + [ + uuid(C744BE59-7004-4B7E-BD9D-C83F594A1B69) + ] + coclass MediaStreamEvent + { + [default] interface IMediaStreamEvent; + }; + [ + uuid(1A225B63-CA8F-466E-A848-44A16A19706E) + ] + coclass RTCPeerConnectionIceEvent + { + [default] interface IRTCPeerConnectionIceEvent; + }; + [ + uuid(419C32C7-EF29-42C3-9A02-7C64FF869FD6) + ] + coclass RTCStatsReport + { + [default] interface IRTCStatsReport; + }; + [ + uuid(F752E29B-45CB-4753-AA0C-51D1A021143C) + ] + coclass RTCStats + { + [default] interface IRTCStats; + }; +}; diff --git a/ie/webrtceverywhere_i.c b/ie/webrtceverywhere_i.c new file mode 100644 index 0000000..b925abd --- /dev/null +++ b/ie/webrtceverywhere_i.c @@ -0,0 +1,160 @@ + + +/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ + +/* link this file in with the server and any clients */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Wed Jul 23 09:29:21 2014 + */ +/* Compiler settings for webrtceverywhere.idl: + Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0603 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +#ifdef __cplusplus +extern "C"{ +#endif + + +#include +#include + +#ifdef _MIDL_USE_GUIDDEF_ + +#ifndef INITGUID +#define INITGUID +#include +#undef INITGUID +#else +#include +#endif + +#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ + DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) + +#else // !_MIDL_USE_GUIDDEF_ + +#ifndef __IID_DEFINED__ +#define __IID_DEFINED__ + +typedef struct _IID +{ + unsigned long x; + unsigned short s1; + unsigned short s2; + unsigned char c[8]; +} IID; + +#endif // __IID_DEFINED__ + +#ifndef CLSID_DEFINED +#define CLSID_DEFINED +typedef IID CLSID; +#endif // CLSID_DEFINED + +#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ + const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} + +#endif !_MIDL_USE_GUIDDEF_ + +MIDL_DEFINE_GUID(IID, IID_IWebRTC,0x4994FB92,0xA5F5,0x4292,0xAB,0x60,0x47,0x2A,0xA4,0x93,0x7C,0x9E); + + +MIDL_DEFINE_GUID(IID, IID_ISessionDescription,0xE7CFEF92,0x42B8,0x40FB,0xBC,0xA9,0xE7,0x9D,0x39,0xAB,0xCF,0x72); + + +MIDL_DEFINE_GUID(IID, IID_IDictOptions,0xFA4B099C,0x3A15,0x4659,0xB2,0x88,0x56,0x5A,0xD5,0x25,0x8D,0x4B); + + +MIDL_DEFINE_GUID(IID, IID_IPeerConnection,0x462E3805,0x373B,0x46EE,0x9B,0xEE,0x43,0xE6,0x11,0x0C,0xB7,0x51); + + +MIDL_DEFINE_GUID(IID, IID_IMediaStream,0x21745AC4,0x2C31,0x481C,0xAB,0x07,0x83,0x4C,0x4D,0x0E,0x28,0x7A); + + +MIDL_DEFINE_GUID(IID, IID_IRTCIceCandidate,0xFBE8F87D,0xBD47,0x4325,0x91,0x96,0x7A,0x36,0xF3,0x39,0xEE,0x2A); + + +MIDL_DEFINE_GUID(IID, IID_IMediaStreamTrack,0xEDD26AE0,0xB068,0x4918,0x82,0x6D,0xE7,0x5B,0xBE,0x84,0x4B,0x71); + + +MIDL_DEFINE_GUID(IID, IID_ISourceInfo,0xBCD116DA,0xB4BC,0x472E,0xA6,0xAE,0x36,0x3D,0x13,0xB7,0x86,0x67); + + +MIDL_DEFINE_GUID(IID, IID_IMediaSourceStates,0x7A2B697F,0x688A,0x4CBE,0xB3,0x6F,0x48,0x20,0xD1,0x2B,0xAE,0x61); + + +MIDL_DEFINE_GUID(IID, IID_IMediaStreamEvent,0xEAB6AB59,0x5B8E,0x4096,0xAA,0x67,0x0D,0x55,0x7A,0xA6,0xBB,0x32); + + +MIDL_DEFINE_GUID(IID, IID_IRTCPeerConnectionIceEvent,0x354C2E39,0x380F,0x4F24,0xAE,0xEA,0x68,0x7E,0xB6,0x7F,0x75,0x9D); + + +MIDL_DEFINE_GUID(IID, IID_IRTCStatsReport,0x455118D0,0xA29F,0x44DB,0xAC,0xF7,0xFE,0x22,0xBF,0xAE,0x21,0x67); + + +MIDL_DEFINE_GUID(IID, IID_IRTCStats,0xCEFEB782,0xAFEC,0x4D0D,0x8C,0x62,0xF1,0xE2,0x55,0xA7,0x38,0x41); + + +MIDL_DEFINE_GUID(IID, LIBID_webrtceverywhereLib,0x12E5324E,0xD53E,0x4C89,0xBF,0xA4,0xE3,0x02,0x09,0x02,0xDD,0x62); + + +MIDL_DEFINE_GUID(IID, DIID__IWebRTCEvents,0x20B33168,0x3B94,0x49C3,0x9E,0x55,0xA6,0x0B,0x9E,0xA0,0xE8,0x86); + + +MIDL_DEFINE_GUID(CLSID, CLSID_WebRTC,0x7FD49E23,0xC8D7,0x4C4F,0x93,0xA1,0xF7,0xEA,0xCF,0xA1,0xEC,0x53); + + +MIDL_DEFINE_GUID(CLSID, CLSID_SessionDescription,0x3F7C50A7,0x7B5C,0x4631,0x89,0x88,0x17,0xB4,0x3A,0x93,0x86,0x67); + + +MIDL_DEFINE_GUID(CLSID, CLSID_DictOptions,0xD6B8C652,0x7A2A,0x47B6,0x8C,0x38,0x3B,0xD5,0xBB,0x0E,0x28,0x72); + + +MIDL_DEFINE_GUID(CLSID, CLSID_PeerConnection,0x017D6D0A,0xBDBC,0x45DC,0x93,0x68,0xA7,0xED,0x65,0x7D,0xAC,0x4D); + + +MIDL_DEFINE_GUID(CLSID, CLSID_MediaStream,0xBA5835A2,0xD1F8,0x466D,0xBB,0x5E,0x80,0x93,0xE3,0xE2,0xEE,0x0E); + + +MIDL_DEFINE_GUID(CLSID, CLSID_RTCIceCandidate,0x31074FC8,0xA7D4,0x4281,0x9C,0x90,0xB7,0xD2,0x0C,0x53,0xA0,0x23); + + +MIDL_DEFINE_GUID(CLSID, CLSID_MediaStreamTrack,0xDA1D1412,0xBC34,0x4288,0x80,0x47,0x6F,0xFE,0x13,0x1C,0x64,0x7F); + + +MIDL_DEFINE_GUID(CLSID, CLSID_SourceInfo,0xE66A3288,0x4BFB,0x41E2,0x85,0x0D,0x61,0xC6,0x32,0x08,0xDD,0x80); + + +MIDL_DEFINE_GUID(CLSID, CLSID_MediaSourceStates,0x7F64ACB6,0xF21C,0x44C2,0x8E,0xEA,0xEF,0xCB,0xEE,0xD5,0xAE,0xB7); + + +MIDL_DEFINE_GUID(CLSID, CLSID_MediaStreamEvent,0xC744BE59,0x7004,0x4B7E,0xBD,0x9D,0xC8,0x3F,0x59,0x4A,0x1B,0x69); + + +MIDL_DEFINE_GUID(CLSID, CLSID_RTCPeerConnectionIceEvent,0x1A225B63,0xCA8F,0x466E,0xA8,0x48,0x44,0xA1,0x6A,0x19,0x70,0x6E); + + +MIDL_DEFINE_GUID(CLSID, CLSID_RTCStatsReport,0x419C32C7,0xEF29,0x42C3,0x9A,0x02,0x7C,0x64,0xFF,0x86,0x9F,0xD6); + + +MIDL_DEFINE_GUID(CLSID, CLSID_RTCStats,0xF752E29B,0x45CB,0x4753,0xAA,0x0C,0x51,0xD1,0xA0,0x21,0x14,0x3C); + +#undef MIDL_DEFINE_GUID + +#ifdef __cplusplus +} +#endif + + + diff --git a/ie/webrtceverywhere_i.h b/ie/webrtceverywhere_i.h new file mode 100644 index 0000000..a1061cc --- /dev/null +++ b/ie/webrtceverywhere_i.h @@ -0,0 +1,3305 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Wed Jul 23 09:29:21 2014 + */ +/* Compiler settings for webrtceverywhere.idl: + Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0603 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif // __RPCNDR_H_VERSION__ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifndef __webrtceverywhere_i_h__ +#define __webrtceverywhere_i_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __IWebRTC_FWD_DEFINED__ +#define __IWebRTC_FWD_DEFINED__ +typedef interface IWebRTC IWebRTC; + +#endif /* __IWebRTC_FWD_DEFINED__ */ + + +#ifndef __ISessionDescription_FWD_DEFINED__ +#define __ISessionDescription_FWD_DEFINED__ +typedef interface ISessionDescription ISessionDescription; + +#endif /* __ISessionDescription_FWD_DEFINED__ */ + + +#ifndef __IDictOptions_FWD_DEFINED__ +#define __IDictOptions_FWD_DEFINED__ +typedef interface IDictOptions IDictOptions; + +#endif /* __IDictOptions_FWD_DEFINED__ */ + + +#ifndef __IPeerConnection_FWD_DEFINED__ +#define __IPeerConnection_FWD_DEFINED__ +typedef interface IPeerConnection IPeerConnection; + +#endif /* __IPeerConnection_FWD_DEFINED__ */ + + +#ifndef __IMediaStream_FWD_DEFINED__ +#define __IMediaStream_FWD_DEFINED__ +typedef interface IMediaStream IMediaStream; + +#endif /* __IMediaStream_FWD_DEFINED__ */ + + +#ifndef __IRTCIceCandidate_FWD_DEFINED__ +#define __IRTCIceCandidate_FWD_DEFINED__ +typedef interface IRTCIceCandidate IRTCIceCandidate; + +#endif /* __IRTCIceCandidate_FWD_DEFINED__ */ + + +#ifndef __IMediaStreamTrack_FWD_DEFINED__ +#define __IMediaStreamTrack_FWD_DEFINED__ +typedef interface IMediaStreamTrack IMediaStreamTrack; + +#endif /* __IMediaStreamTrack_FWD_DEFINED__ */ + + +#ifndef __ISourceInfo_FWD_DEFINED__ +#define __ISourceInfo_FWD_DEFINED__ +typedef interface ISourceInfo ISourceInfo; + +#endif /* __ISourceInfo_FWD_DEFINED__ */ + + +#ifndef __IMediaSourceStates_FWD_DEFINED__ +#define __IMediaSourceStates_FWD_DEFINED__ +typedef interface IMediaSourceStates IMediaSourceStates; + +#endif /* __IMediaSourceStates_FWD_DEFINED__ */ + + +#ifndef __IMediaStreamEvent_FWD_DEFINED__ +#define __IMediaStreamEvent_FWD_DEFINED__ +typedef interface IMediaStreamEvent IMediaStreamEvent; + +#endif /* __IMediaStreamEvent_FWD_DEFINED__ */ + + +#ifndef __IRTCPeerConnectionIceEvent_FWD_DEFINED__ +#define __IRTCPeerConnectionIceEvent_FWD_DEFINED__ +typedef interface IRTCPeerConnectionIceEvent IRTCPeerConnectionIceEvent; + +#endif /* __IRTCPeerConnectionIceEvent_FWD_DEFINED__ */ + + +#ifndef __IRTCStatsReport_FWD_DEFINED__ +#define __IRTCStatsReport_FWD_DEFINED__ +typedef interface IRTCStatsReport IRTCStatsReport; + +#endif /* __IRTCStatsReport_FWD_DEFINED__ */ + + +#ifndef __IRTCStats_FWD_DEFINED__ +#define __IRTCStats_FWD_DEFINED__ +typedef interface IRTCStats IRTCStats; + +#endif /* __IRTCStats_FWD_DEFINED__ */ + + +#ifndef ___IWebRTCEvents_FWD_DEFINED__ +#define ___IWebRTCEvents_FWD_DEFINED__ +typedef interface _IWebRTCEvents _IWebRTCEvents; + +#endif /* ___IWebRTCEvents_FWD_DEFINED__ */ + + +#ifndef __WebRTC_FWD_DEFINED__ +#define __WebRTC_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class WebRTC WebRTC; +#else +typedef struct WebRTC WebRTC; +#endif /* __cplusplus */ + +#endif /* __WebRTC_FWD_DEFINED__ */ + + +#ifndef __SessionDescription_FWD_DEFINED__ +#define __SessionDescription_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class SessionDescription SessionDescription; +#else +typedef struct SessionDescription SessionDescription; +#endif /* __cplusplus */ + +#endif /* __SessionDescription_FWD_DEFINED__ */ + + +#ifndef __DictOptions_FWD_DEFINED__ +#define __DictOptions_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class DictOptions DictOptions; +#else +typedef struct DictOptions DictOptions; +#endif /* __cplusplus */ + +#endif /* __DictOptions_FWD_DEFINED__ */ + + +#ifndef __PeerConnection_FWD_DEFINED__ +#define __PeerConnection_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class PeerConnection PeerConnection; +#else +typedef struct PeerConnection PeerConnection; +#endif /* __cplusplus */ + +#endif /* __PeerConnection_FWD_DEFINED__ */ + + +#ifndef __MediaStream_FWD_DEFINED__ +#define __MediaStream_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class MediaStream MediaStream; +#else +typedef struct MediaStream MediaStream; +#endif /* __cplusplus */ + +#endif /* __MediaStream_FWD_DEFINED__ */ + + +#ifndef __RTCIceCandidate_FWD_DEFINED__ +#define __RTCIceCandidate_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class RTCIceCandidate RTCIceCandidate; +#else +typedef struct RTCIceCandidate RTCIceCandidate; +#endif /* __cplusplus */ + +#endif /* __RTCIceCandidate_FWD_DEFINED__ */ + + +#ifndef __MediaStreamTrack_FWD_DEFINED__ +#define __MediaStreamTrack_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class MediaStreamTrack MediaStreamTrack; +#else +typedef struct MediaStreamTrack MediaStreamTrack; +#endif /* __cplusplus */ + +#endif /* __MediaStreamTrack_FWD_DEFINED__ */ + + +#ifndef __SourceInfo_FWD_DEFINED__ +#define __SourceInfo_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class SourceInfo SourceInfo; +#else +typedef struct SourceInfo SourceInfo; +#endif /* __cplusplus */ + +#endif /* __SourceInfo_FWD_DEFINED__ */ + + +#ifndef __MediaSourceStates_FWD_DEFINED__ +#define __MediaSourceStates_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class MediaSourceStates MediaSourceStates; +#else +typedef struct MediaSourceStates MediaSourceStates; +#endif /* __cplusplus */ + +#endif /* __MediaSourceStates_FWD_DEFINED__ */ + + +#ifndef __MediaStreamEvent_FWD_DEFINED__ +#define __MediaStreamEvent_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class MediaStreamEvent MediaStreamEvent; +#else +typedef struct MediaStreamEvent MediaStreamEvent; +#endif /* __cplusplus */ + +#endif /* __MediaStreamEvent_FWD_DEFINED__ */ + + +#ifndef __RTCPeerConnectionIceEvent_FWD_DEFINED__ +#define __RTCPeerConnectionIceEvent_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class RTCPeerConnectionIceEvent RTCPeerConnectionIceEvent; +#else +typedef struct RTCPeerConnectionIceEvent RTCPeerConnectionIceEvent; +#endif /* __cplusplus */ + +#endif /* __RTCPeerConnectionIceEvent_FWD_DEFINED__ */ + + +#ifndef __RTCStatsReport_FWD_DEFINED__ +#define __RTCStatsReport_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class RTCStatsReport RTCStatsReport; +#else +typedef struct RTCStatsReport RTCStatsReport; +#endif /* __cplusplus */ + +#endif /* __RTCStatsReport_FWD_DEFINED__ */ + + +#ifndef __RTCStats_FWD_DEFINED__ +#define __RTCStats_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class RTCStats RTCStats; +#else +typedef struct RTCStats RTCStats; +#endif /* __cplusplus */ + +#endif /* __RTCStats_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "oaidl.h" +#include "ocidl.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +#ifndef __IWebRTC_INTERFACE_DEFINED__ +#define __IWebRTC_INTERFACE_DEFINED__ + +/* interface IWebRTC */ +/* [unique][helpstring][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IWebRTC; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4994FB92-A5F5-4292-AB60-472AA4937C9E") + IWebRTC : public IDispatch + { + public: + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_versionName( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getUserMedia( + /* [optional][in] */ VARIANT constraints, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT errorCallback) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE createDisplay( + /* [retval][out] */ IDispatch **ppDisplay) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE createSessionDescription( + /* [in] */ VARIANT RTCSessionDescriptionInit, + /* [retval][out] */ IDispatch **ppSdp) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE createDictOptions( + /* [retval][out] */ IDispatch **ppDictOptions) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE createPeerConnection( + /* [optional][in] */ VARIANT RTCConfiguration, + /* [optional][in] */ VARIANT MediaConstraints, + /* [retval][out] */ IDispatch **ppPeerConnection) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE createIceCandidate( + /* [in] */ VARIANT RTCIceCandidateInit, + /* [retval][out] */ IDispatch **ppIceCandidate) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE createMediaStreamTrack( + /* [retval][out] */ IDispatch **ppMediaStreamTrack) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE bindEventListener( + /* [in] */ BSTR type, + /* [optional][in] */ VARIANT listenerCallback, + /* [optional][in] */ VARIANT useCapture) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getSources( + /* [optional][in] */ VARIANT successCallback) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_src( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_videoWidth( + /* [retval][out] */ LONG *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_videoHeight( + /* [retval][out] */ LONG *pVal) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE fillImageData( + /* [in] */ VARIANT imageData) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_isWebRtcPlugin( + /* [retval][out] */ VARIANT_BOOL *pVal) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IWebRTCVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IWebRTC * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IWebRTC * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IWebRTC * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IWebRTC * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IWebRTC * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IWebRTC * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IWebRTC * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_versionName )( + IWebRTC * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *getUserMedia )( + IWebRTC * This, + /* [optional][in] */ VARIANT constraints, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT errorCallback); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *createDisplay )( + IWebRTC * This, + /* [retval][out] */ IDispatch **ppDisplay); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *createSessionDescription )( + IWebRTC * This, + /* [in] */ VARIANT RTCSessionDescriptionInit, + /* [retval][out] */ IDispatch **ppSdp); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *createDictOptions )( + IWebRTC * This, + /* [retval][out] */ IDispatch **ppDictOptions); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *createPeerConnection )( + IWebRTC * This, + /* [optional][in] */ VARIANT RTCConfiguration, + /* [optional][in] */ VARIANT MediaConstraints, + /* [retval][out] */ IDispatch **ppPeerConnection); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *createIceCandidate )( + IWebRTC * This, + /* [in] */ VARIANT RTCIceCandidateInit, + /* [retval][out] */ IDispatch **ppIceCandidate); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *createMediaStreamTrack )( + IWebRTC * This, + /* [retval][out] */ IDispatch **ppMediaStreamTrack); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *bindEventListener )( + IWebRTC * This, + /* [in] */ BSTR type, + /* [optional][in] */ VARIANT listenerCallback, + /* [optional][in] */ VARIANT useCapture); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *getSources )( + IWebRTC * This, + /* [optional][in] */ VARIANT successCallback); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_src )( + IWebRTC * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_videoWidth )( + IWebRTC * This, + /* [retval][out] */ LONG *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_videoHeight )( + IWebRTC * This, + /* [retval][out] */ LONG *pVal); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *fillImageData )( + IWebRTC * This, + /* [in] */ VARIANT imageData); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_isWebRtcPlugin )( + IWebRTC * This, + /* [retval][out] */ VARIANT_BOOL *pVal); + + END_INTERFACE + } IWebRTCVtbl; + + interface IWebRTC + { + CONST_VTBL struct IWebRTCVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IWebRTC_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IWebRTC_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IWebRTC_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IWebRTC_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IWebRTC_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IWebRTC_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IWebRTC_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define IWebRTC_get_versionName(This,pVal) \ + ( (This)->lpVtbl -> get_versionName(This,pVal) ) + +#define IWebRTC_getUserMedia(This,constraints,successCallback,errorCallback) \ + ( (This)->lpVtbl -> getUserMedia(This,constraints,successCallback,errorCallback) ) + +#define IWebRTC_createDisplay(This,ppDisplay) \ + ( (This)->lpVtbl -> createDisplay(This,ppDisplay) ) + +#define IWebRTC_createSessionDescription(This,RTCSessionDescriptionInit,ppSdp) \ + ( (This)->lpVtbl -> createSessionDescription(This,RTCSessionDescriptionInit,ppSdp) ) + +#define IWebRTC_createDictOptions(This,ppDictOptions) \ + ( (This)->lpVtbl -> createDictOptions(This,ppDictOptions) ) + +#define IWebRTC_createPeerConnection(This,RTCConfiguration,MediaConstraints,ppPeerConnection) \ + ( (This)->lpVtbl -> createPeerConnection(This,RTCConfiguration,MediaConstraints,ppPeerConnection) ) + +#define IWebRTC_createIceCandidate(This,RTCIceCandidateInit,ppIceCandidate) \ + ( (This)->lpVtbl -> createIceCandidate(This,RTCIceCandidateInit,ppIceCandidate) ) + +#define IWebRTC_createMediaStreamTrack(This,ppMediaStreamTrack) \ + ( (This)->lpVtbl -> createMediaStreamTrack(This,ppMediaStreamTrack) ) + +#define IWebRTC_bindEventListener(This,type,listenerCallback,useCapture) \ + ( (This)->lpVtbl -> bindEventListener(This,type,listenerCallback,useCapture) ) + +#define IWebRTC_getSources(This,successCallback) \ + ( (This)->lpVtbl -> getSources(This,successCallback) ) + +#define IWebRTC_put_src(This,newVal) \ + ( (This)->lpVtbl -> put_src(This,newVal) ) + +#define IWebRTC_get_videoWidth(This,pVal) \ + ( (This)->lpVtbl -> get_videoWidth(This,pVal) ) + +#define IWebRTC_get_videoHeight(This,pVal) \ + ( (This)->lpVtbl -> get_videoHeight(This,pVal) ) + +#define IWebRTC_fillImageData(This,imageData) \ + ( (This)->lpVtbl -> fillImageData(This,imageData) ) + +#define IWebRTC_get_isWebRtcPlugin(This,pVal) \ + ( (This)->lpVtbl -> get_isWebRtcPlugin(This,pVal) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IWebRTC_INTERFACE_DEFINED__ */ + + +#ifndef __ISessionDescription_INTERFACE_DEFINED__ +#define __ISessionDescription_INTERFACE_DEFINED__ + +/* interface ISessionDescription */ +/* [unique][helpstring][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_ISessionDescription; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("E7CFEF92-42B8-40FB-BCA9-E79D39ABCF72") + ISessionDescription : public IDispatch + { + public: + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_type( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_type( + /* [in] */ BSTR newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_sdp( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_sdp( + /* [in] */ BSTR newVal) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ISessionDescriptionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISessionDescription * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISessionDescription * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISessionDescription * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + ISessionDescription * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + ISessionDescription * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + ISessionDescription * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + ISessionDescription * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_type )( + ISessionDescription * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_type )( + ISessionDescription * This, + /* [in] */ BSTR newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_sdp )( + ISessionDescription * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_sdp )( + ISessionDescription * This, + /* [in] */ BSTR newVal); + + END_INTERFACE + } ISessionDescriptionVtbl; + + interface ISessionDescription + { + CONST_VTBL struct ISessionDescriptionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISessionDescription_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISessionDescription_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISessionDescription_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISessionDescription_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define ISessionDescription_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define ISessionDescription_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define ISessionDescription_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define ISessionDescription_get_type(This,pVal) \ + ( (This)->lpVtbl -> get_type(This,pVal) ) + +#define ISessionDescription_put_type(This,newVal) \ + ( (This)->lpVtbl -> put_type(This,newVal) ) + +#define ISessionDescription_get_sdp(This,pVal) \ + ( (This)->lpVtbl -> get_sdp(This,pVal) ) + +#define ISessionDescription_put_sdp(This,newVal) \ + ( (This)->lpVtbl -> put_sdp(This,newVal) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISessionDescription_INTERFACE_DEFINED__ */ + + +#ifndef __IDictOptions_INTERFACE_DEFINED__ +#define __IDictOptions_INTERFACE_DEFINED__ + +/* interface IDictOptions */ +/* [unique][helpstring][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IDictOptions; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("FA4B099C-3A15-4659-B288-565AD5258D4B") + IDictOptions : public IDispatch + { + public: + }; + + +#else /* C style interface */ + + typedef struct IDictOptionsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDictOptions * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDictOptions * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDictOptions * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IDictOptions * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IDictOptions * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IDictOptions * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IDictOptions * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + END_INTERFACE + } IDictOptionsVtbl; + + interface IDictOptions + { + CONST_VTBL struct IDictOptionsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDictOptions_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDictOptions_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDictOptions_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDictOptions_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IDictOptions_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IDictOptions_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IDictOptions_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDictOptions_INTERFACE_DEFINED__ */ + + +#ifndef __IPeerConnection_INTERFACE_DEFINED__ +#define __IPeerConnection_INTERFACE_DEFINED__ + +/* interface IPeerConnection */ +/* [unique][helpstring][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IPeerConnection; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("462E3805-373B-46EE-9BEE-43E6110CB751") + IPeerConnection : public IDispatch + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE createOffer( + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback, + /* [optional][in] */ VARIANT MediaConstraints) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE createAnswer( + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback, + /* [optional][in] */ VARIANT MediaConstraints) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE setLocalDescription( + /* [in] */ VARIANT RTCSessionDescription, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_localDescription( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE setRemoteDescription( + /* [in] */ VARIANT RTCSessionDescription, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_remoteDescription( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_signalingState( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE updateIce( + /* [in] */ VARIANT RTCConfiguration, + /* [optional][in] */ VARIANT MediaConstraints) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE addIceCandidate( + /* [in] */ VARIANT RTCIceCandidate, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_iceGatheringState( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_iceConnectionState( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getLocalStreams( + /* [retval][out] */ VARIANT *MediaStreams) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getRemoteStreams( + /* [retval][out] */ VARIANT *MediaStreams) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getStreamById( + /* [in] */ BSTR streamId, + /* [retval][out] */ VARIANT *MediaStream) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE addStream( + /* [in] */ VARIANT stream, + /* [optional][in] */ VARIANT MediaConstraints) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE removeStream( + /* [in] */ VARIANT stream) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE close( void) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getStats( + /* [in] */ VARIANT selector, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onnegotiationneeded( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onnegotiationneeded( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onicecandidate( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onicecandidate( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onsignalingstatechange( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onsignalingstatechange( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onaddstream( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onaddstream( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onremovestream( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onremovestream( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_oniceconnectionstatechange( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_oniceconnectionstatechange( + /* [in] */ VARIANT newVal) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IPeerConnectionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPeerConnection * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPeerConnection * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPeerConnection * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IPeerConnection * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IPeerConnection * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IPeerConnection * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IPeerConnection * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *createOffer )( + IPeerConnection * This, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback, + /* [optional][in] */ VARIANT MediaConstraints); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *createAnswer )( + IPeerConnection * This, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback, + /* [optional][in] */ VARIANT MediaConstraints); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *setLocalDescription )( + IPeerConnection * This, + /* [in] */ VARIANT RTCSessionDescription, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_localDescription )( + IPeerConnection * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *setRemoteDescription )( + IPeerConnection * This, + /* [in] */ VARIANT RTCSessionDescription, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_remoteDescription )( + IPeerConnection * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_signalingState )( + IPeerConnection * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *updateIce )( + IPeerConnection * This, + /* [in] */ VARIANT RTCConfiguration, + /* [optional][in] */ VARIANT MediaConstraints); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *addIceCandidate )( + IPeerConnection * This, + /* [in] */ VARIANT RTCIceCandidate, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_iceGatheringState )( + IPeerConnection * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_iceConnectionState )( + IPeerConnection * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *getLocalStreams )( + IPeerConnection * This, + /* [retval][out] */ VARIANT *MediaStreams); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *getRemoteStreams )( + IPeerConnection * This, + /* [retval][out] */ VARIANT *MediaStreams); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *getStreamById )( + IPeerConnection * This, + /* [in] */ BSTR streamId, + /* [retval][out] */ VARIANT *MediaStream); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *addStream )( + IPeerConnection * This, + /* [in] */ VARIANT stream, + /* [optional][in] */ VARIANT MediaConstraints); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *removeStream )( + IPeerConnection * This, + /* [in] */ VARIANT stream); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *close )( + IPeerConnection * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *getStats )( + IPeerConnection * This, + /* [in] */ VARIANT selector, + /* [optional][in] */ VARIANT successCallback, + /* [optional][in] */ VARIANT failureCallback); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onnegotiationneeded )( + IPeerConnection * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onnegotiationneeded )( + IPeerConnection * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onicecandidate )( + IPeerConnection * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onicecandidate )( + IPeerConnection * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onsignalingstatechange )( + IPeerConnection * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onsignalingstatechange )( + IPeerConnection * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onaddstream )( + IPeerConnection * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onaddstream )( + IPeerConnection * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onremovestream )( + IPeerConnection * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onremovestream )( + IPeerConnection * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_oniceconnectionstatechange )( + IPeerConnection * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_oniceconnectionstatechange )( + IPeerConnection * This, + /* [in] */ VARIANT newVal); + + END_INTERFACE + } IPeerConnectionVtbl; + + interface IPeerConnection + { + CONST_VTBL struct IPeerConnectionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPeerConnection_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPeerConnection_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPeerConnection_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPeerConnection_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IPeerConnection_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IPeerConnection_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IPeerConnection_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define IPeerConnection_createOffer(This,successCallback,failureCallback,MediaConstraints) \ + ( (This)->lpVtbl -> createOffer(This,successCallback,failureCallback,MediaConstraints) ) + +#define IPeerConnection_createAnswer(This,successCallback,failureCallback,MediaConstraints) \ + ( (This)->lpVtbl -> createAnswer(This,successCallback,failureCallback,MediaConstraints) ) + +#define IPeerConnection_setLocalDescription(This,RTCSessionDescription,successCallback,failureCallback) \ + ( (This)->lpVtbl -> setLocalDescription(This,RTCSessionDescription,successCallback,failureCallback) ) + +#define IPeerConnection_get_localDescription(This,pVal) \ + ( (This)->lpVtbl -> get_localDescription(This,pVal) ) + +#define IPeerConnection_setRemoteDescription(This,RTCSessionDescription,successCallback,failureCallback) \ + ( (This)->lpVtbl -> setRemoteDescription(This,RTCSessionDescription,successCallback,failureCallback) ) + +#define IPeerConnection_get_remoteDescription(This,pVal) \ + ( (This)->lpVtbl -> get_remoteDescription(This,pVal) ) + +#define IPeerConnection_get_signalingState(This,pVal) \ + ( (This)->lpVtbl -> get_signalingState(This,pVal) ) + +#define IPeerConnection_updateIce(This,RTCConfiguration,MediaConstraints) \ + ( (This)->lpVtbl -> updateIce(This,RTCConfiguration,MediaConstraints) ) + +#define IPeerConnection_addIceCandidate(This,RTCIceCandidate,successCallback,failureCallback) \ + ( (This)->lpVtbl -> addIceCandidate(This,RTCIceCandidate,successCallback,failureCallback) ) + +#define IPeerConnection_get_iceGatheringState(This,pVal) \ + ( (This)->lpVtbl -> get_iceGatheringState(This,pVal) ) + +#define IPeerConnection_get_iceConnectionState(This,pVal) \ + ( (This)->lpVtbl -> get_iceConnectionState(This,pVal) ) + +#define IPeerConnection_getLocalStreams(This,MediaStreams) \ + ( (This)->lpVtbl -> getLocalStreams(This,MediaStreams) ) + +#define IPeerConnection_getRemoteStreams(This,MediaStreams) \ + ( (This)->lpVtbl -> getRemoteStreams(This,MediaStreams) ) + +#define IPeerConnection_getStreamById(This,streamId,MediaStream) \ + ( (This)->lpVtbl -> getStreamById(This,streamId,MediaStream) ) + +#define IPeerConnection_addStream(This,stream,MediaConstraints) \ + ( (This)->lpVtbl -> addStream(This,stream,MediaConstraints) ) + +#define IPeerConnection_removeStream(This,stream) \ + ( (This)->lpVtbl -> removeStream(This,stream) ) + +#define IPeerConnection_close(This) \ + ( (This)->lpVtbl -> close(This) ) + +#define IPeerConnection_getStats(This,selector,successCallback,failureCallback) \ + ( (This)->lpVtbl -> getStats(This,selector,successCallback,failureCallback) ) + +#define IPeerConnection_get_onnegotiationneeded(This,pVal) \ + ( (This)->lpVtbl -> get_onnegotiationneeded(This,pVal) ) + +#define IPeerConnection_put_onnegotiationneeded(This,newVal) \ + ( (This)->lpVtbl -> put_onnegotiationneeded(This,newVal) ) + +#define IPeerConnection_get_onicecandidate(This,pVal) \ + ( (This)->lpVtbl -> get_onicecandidate(This,pVal) ) + +#define IPeerConnection_put_onicecandidate(This,newVal) \ + ( (This)->lpVtbl -> put_onicecandidate(This,newVal) ) + +#define IPeerConnection_get_onsignalingstatechange(This,pVal) \ + ( (This)->lpVtbl -> get_onsignalingstatechange(This,pVal) ) + +#define IPeerConnection_put_onsignalingstatechange(This,newVal) \ + ( (This)->lpVtbl -> put_onsignalingstatechange(This,newVal) ) + +#define IPeerConnection_get_onaddstream(This,pVal) \ + ( (This)->lpVtbl -> get_onaddstream(This,pVal) ) + +#define IPeerConnection_put_onaddstream(This,newVal) \ + ( (This)->lpVtbl -> put_onaddstream(This,newVal) ) + +#define IPeerConnection_get_onremovestream(This,pVal) \ + ( (This)->lpVtbl -> get_onremovestream(This,pVal) ) + +#define IPeerConnection_put_onremovestream(This,newVal) \ + ( (This)->lpVtbl -> put_onremovestream(This,newVal) ) + +#define IPeerConnection_get_oniceconnectionstatechange(This,pVal) \ + ( (This)->lpVtbl -> get_oniceconnectionstatechange(This,pVal) ) + +#define IPeerConnection_put_oniceconnectionstatechange(This,newVal) \ + ( (This)->lpVtbl -> put_oniceconnectionstatechange(This,newVal) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPeerConnection_INTERFACE_DEFINED__ */ + + +#ifndef __IMediaStream_INTERFACE_DEFINED__ +#define __IMediaStream_INTERFACE_DEFINED__ + +/* interface IMediaStream */ +/* [unique][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IMediaStream; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("21745AC4-2C31-481C-AB07-834C4D0E287A") + IMediaStream : public IDispatch + { + public: + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_id( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getAudioTracks( + /* [retval][out] */ VARIANT *Tracks) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getVideoTracks( + /* [retval][out] */ VARIANT *Tracks) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getTrackById( + /* [in] */ BSTR trackId, + /* [retval][out] */ VARIANT *MediaStreamTrack) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE addTrack( + /* [in] */ VARIANT MediaStreamTrack) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE removeTrack( + /* [in] */ VARIANT MediaStreamTrack) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE clone( + /* [retval][out] */ VARIANT *MediaStream) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_ended( + /* [retval][out] */ VARIANT_BOOL *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onended( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onended( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onaddtrack( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onaddtrack( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onremovetrack( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onremovetrack( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE stop( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IMediaStreamVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMediaStream * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMediaStream * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMediaStream * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IMediaStream * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IMediaStream * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IMediaStream * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IMediaStream * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_id )( + IMediaStream * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *getAudioTracks )( + IMediaStream * This, + /* [retval][out] */ VARIANT *Tracks); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *getVideoTracks )( + IMediaStream * This, + /* [retval][out] */ VARIANT *Tracks); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *getTrackById )( + IMediaStream * This, + /* [in] */ BSTR trackId, + /* [retval][out] */ VARIANT *MediaStreamTrack); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *addTrack )( + IMediaStream * This, + /* [in] */ VARIANT MediaStreamTrack); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *removeTrack )( + IMediaStream * This, + /* [in] */ VARIANT MediaStreamTrack); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *clone )( + IMediaStream * This, + /* [retval][out] */ VARIANT *MediaStream); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_ended )( + IMediaStream * This, + /* [retval][out] */ VARIANT_BOOL *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onended )( + IMediaStream * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onended )( + IMediaStream * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onaddtrack )( + IMediaStream * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onaddtrack )( + IMediaStream * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onremovetrack )( + IMediaStream * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onremovetrack )( + IMediaStream * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *stop )( + IMediaStream * This); + + END_INTERFACE + } IMediaStreamVtbl; + + interface IMediaStream + { + CONST_VTBL struct IMediaStreamVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMediaStream_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMediaStream_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMediaStream_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMediaStream_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IMediaStream_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IMediaStream_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IMediaStream_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define IMediaStream_get_id(This,pVal) \ + ( (This)->lpVtbl -> get_id(This,pVal) ) + +#define IMediaStream_getAudioTracks(This,Tracks) \ + ( (This)->lpVtbl -> getAudioTracks(This,Tracks) ) + +#define IMediaStream_getVideoTracks(This,Tracks) \ + ( (This)->lpVtbl -> getVideoTracks(This,Tracks) ) + +#define IMediaStream_getTrackById(This,trackId,MediaStreamTrack) \ + ( (This)->lpVtbl -> getTrackById(This,trackId,MediaStreamTrack) ) + +#define IMediaStream_addTrack(This,MediaStreamTrack) \ + ( (This)->lpVtbl -> addTrack(This,MediaStreamTrack) ) + +#define IMediaStream_removeTrack(This,MediaStreamTrack) \ + ( (This)->lpVtbl -> removeTrack(This,MediaStreamTrack) ) + +#define IMediaStream_clone(This,MediaStream) \ + ( (This)->lpVtbl -> clone(This,MediaStream) ) + +#define IMediaStream_get_ended(This,pVal) \ + ( (This)->lpVtbl -> get_ended(This,pVal) ) + +#define IMediaStream_get_onended(This,pVal) \ + ( (This)->lpVtbl -> get_onended(This,pVal) ) + +#define IMediaStream_put_onended(This,newVal) \ + ( (This)->lpVtbl -> put_onended(This,newVal) ) + +#define IMediaStream_get_onaddtrack(This,pVal) \ + ( (This)->lpVtbl -> get_onaddtrack(This,pVal) ) + +#define IMediaStream_put_onaddtrack(This,newVal) \ + ( (This)->lpVtbl -> put_onaddtrack(This,newVal) ) + +#define IMediaStream_get_onremovetrack(This,pVal) \ + ( (This)->lpVtbl -> get_onremovetrack(This,pVal) ) + +#define IMediaStream_put_onremovetrack(This,newVal) \ + ( (This)->lpVtbl -> put_onremovetrack(This,newVal) ) + +#define IMediaStream_stop(This) \ + ( (This)->lpVtbl -> stop(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMediaStream_INTERFACE_DEFINED__ */ + + +#ifndef __IRTCIceCandidate_INTERFACE_DEFINED__ +#define __IRTCIceCandidate_INTERFACE_DEFINED__ + +/* interface IRTCIceCandidate */ +/* [unique][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IRTCIceCandidate; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("FBE8F87D-BD47-4325-9196-7A36F339EE2A") + IRTCIceCandidate : public IDispatch + { + public: + virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_candidate( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_sdpMid( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_sdpMLineIndex( + /* [retval][out] */ USHORT *pVal) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IRTCIceCandidateVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IRTCIceCandidate * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IRTCIceCandidate * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IRTCIceCandidate * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IRTCIceCandidate * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IRTCIceCandidate * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IRTCIceCandidate * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IRTCIceCandidate * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_candidate )( + IRTCIceCandidate * This, + /* [retval][out] */ BSTR *pVal); + + /* [id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_sdpMid )( + IRTCIceCandidate * This, + /* [retval][out] */ BSTR *pVal); + + /* [id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_sdpMLineIndex )( + IRTCIceCandidate * This, + /* [retval][out] */ USHORT *pVal); + + END_INTERFACE + } IRTCIceCandidateVtbl; + + interface IRTCIceCandidate + { + CONST_VTBL struct IRTCIceCandidateVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IRTCIceCandidate_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IRTCIceCandidate_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IRTCIceCandidate_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IRTCIceCandidate_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IRTCIceCandidate_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IRTCIceCandidate_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IRTCIceCandidate_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define IRTCIceCandidate_get_candidate(This,pVal) \ + ( (This)->lpVtbl -> get_candidate(This,pVal) ) + +#define IRTCIceCandidate_get_sdpMid(This,pVal) \ + ( (This)->lpVtbl -> get_sdpMid(This,pVal) ) + +#define IRTCIceCandidate_get_sdpMLineIndex(This,pVal) \ + ( (This)->lpVtbl -> get_sdpMLineIndex(This,pVal) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IRTCIceCandidate_INTERFACE_DEFINED__ */ + + +#ifndef __IMediaStreamTrack_INTERFACE_DEFINED__ +#define __IMediaStreamTrack_INTERFACE_DEFINED__ + +/* interface IMediaStreamTrack */ +/* [unique][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IMediaStreamTrack; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("EDD26AE0-B068-4918-826D-E75BBE844B71") + IMediaStreamTrack : public IDispatch + { + public: + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_kind( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_id( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_label( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_enabled( + /* [retval][out] */ VARIANT_BOOL *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_enabled( + /* [in] */ VARIANT_BOOL newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_muted( + /* [retval][out] */ VARIANT_BOOL *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onmute( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onmute( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onunmute( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onunmute( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_readonly( + /* [retval][out] */ VARIANT_BOOL *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_remote( + /* [retval][out] */ VARIANT_BOOL *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_readyState( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onstarted( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onstarted( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onended( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onended( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getSourceInfos( + /* [retval][out] */ VARIANT *Infos) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE constraints( + /* [retval][out] */ VARIANT *MediaTrackConstraints) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE states( + /* [retval][out] */ VARIANT *MediaSourceStates) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE capabilities( + /* [retval][out] */ VARIANT *AllCapabilities) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE applyConstraints( + /* [in] */ VARIANT MediaTrackConstraints) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_onoverconstrained( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_onoverconstrained( + /* [in] */ VARIANT newVal) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE clone( + /* [retval][out] */ VARIANT *MediaStreamTrack) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE stop( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IMediaStreamTrackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMediaStreamTrack * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMediaStreamTrack * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMediaStreamTrack * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IMediaStreamTrack * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IMediaStreamTrack * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IMediaStreamTrack * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IMediaStreamTrack * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_kind )( + IMediaStreamTrack * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_id )( + IMediaStreamTrack * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_label )( + IMediaStreamTrack * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_enabled )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT_BOOL *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_enabled )( + IMediaStreamTrack * This, + /* [in] */ VARIANT_BOOL newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_muted )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT_BOOL *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onmute )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onmute )( + IMediaStreamTrack * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onunmute )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onunmute )( + IMediaStreamTrack * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_readonly )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT_BOOL *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_remote )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT_BOOL *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_readyState )( + IMediaStreamTrack * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onstarted )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onstarted )( + IMediaStreamTrack * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onended )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onended )( + IMediaStreamTrack * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *getSourceInfos )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT *Infos); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *constraints )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT *MediaTrackConstraints); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *states )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT *MediaSourceStates); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *capabilities )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT *AllCapabilities); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *applyConstraints )( + IMediaStreamTrack * This, + /* [in] */ VARIANT MediaTrackConstraints); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_onoverconstrained )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_onoverconstrained )( + IMediaStreamTrack * This, + /* [in] */ VARIANT newVal); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *clone )( + IMediaStreamTrack * This, + /* [retval][out] */ VARIANT *MediaStreamTrack); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *stop )( + IMediaStreamTrack * This); + + END_INTERFACE + } IMediaStreamTrackVtbl; + + interface IMediaStreamTrack + { + CONST_VTBL struct IMediaStreamTrackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMediaStreamTrack_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMediaStreamTrack_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMediaStreamTrack_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMediaStreamTrack_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IMediaStreamTrack_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IMediaStreamTrack_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IMediaStreamTrack_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define IMediaStreamTrack_get_kind(This,pVal) \ + ( (This)->lpVtbl -> get_kind(This,pVal) ) + +#define IMediaStreamTrack_get_id(This,pVal) \ + ( (This)->lpVtbl -> get_id(This,pVal) ) + +#define IMediaStreamTrack_get_label(This,pVal) \ + ( (This)->lpVtbl -> get_label(This,pVal) ) + +#define IMediaStreamTrack_get_enabled(This,pVal) \ + ( (This)->lpVtbl -> get_enabled(This,pVal) ) + +#define IMediaStreamTrack_put_enabled(This,newVal) \ + ( (This)->lpVtbl -> put_enabled(This,newVal) ) + +#define IMediaStreamTrack_get_muted(This,pVal) \ + ( (This)->lpVtbl -> get_muted(This,pVal) ) + +#define IMediaStreamTrack_get_onmute(This,pVal) \ + ( (This)->lpVtbl -> get_onmute(This,pVal) ) + +#define IMediaStreamTrack_put_onmute(This,newVal) \ + ( (This)->lpVtbl -> put_onmute(This,newVal) ) + +#define IMediaStreamTrack_get_onunmute(This,pVal) \ + ( (This)->lpVtbl -> get_onunmute(This,pVal) ) + +#define IMediaStreamTrack_put_onunmute(This,newVal) \ + ( (This)->lpVtbl -> put_onunmute(This,newVal) ) + +#define IMediaStreamTrack_get_readonly(This,pVal) \ + ( (This)->lpVtbl -> get_readonly(This,pVal) ) + +#define IMediaStreamTrack_get_remote(This,pVal) \ + ( (This)->lpVtbl -> get_remote(This,pVal) ) + +#define IMediaStreamTrack_get_readyState(This,pVal) \ + ( (This)->lpVtbl -> get_readyState(This,pVal) ) + +#define IMediaStreamTrack_get_onstarted(This,pVal) \ + ( (This)->lpVtbl -> get_onstarted(This,pVal) ) + +#define IMediaStreamTrack_put_onstarted(This,newVal) \ + ( (This)->lpVtbl -> put_onstarted(This,newVal) ) + +#define IMediaStreamTrack_get_onended(This,pVal) \ + ( (This)->lpVtbl -> get_onended(This,pVal) ) + +#define IMediaStreamTrack_put_onended(This,newVal) \ + ( (This)->lpVtbl -> put_onended(This,newVal) ) + +#define IMediaStreamTrack_getSourceInfos(This,Infos) \ + ( (This)->lpVtbl -> getSourceInfos(This,Infos) ) + +#define IMediaStreamTrack_constraints(This,MediaTrackConstraints) \ + ( (This)->lpVtbl -> constraints(This,MediaTrackConstraints) ) + +#define IMediaStreamTrack_states(This,MediaSourceStates) \ + ( (This)->lpVtbl -> states(This,MediaSourceStates) ) + +#define IMediaStreamTrack_capabilities(This,AllCapabilities) \ + ( (This)->lpVtbl -> capabilities(This,AllCapabilities) ) + +#define IMediaStreamTrack_applyConstraints(This,MediaTrackConstraints) \ + ( (This)->lpVtbl -> applyConstraints(This,MediaTrackConstraints) ) + +#define IMediaStreamTrack_get_onoverconstrained(This,pVal) \ + ( (This)->lpVtbl -> get_onoverconstrained(This,pVal) ) + +#define IMediaStreamTrack_put_onoverconstrained(This,newVal) \ + ( (This)->lpVtbl -> put_onoverconstrained(This,newVal) ) + +#define IMediaStreamTrack_clone(This,MediaStreamTrack) \ + ( (This)->lpVtbl -> clone(This,MediaStreamTrack) ) + +#define IMediaStreamTrack_stop(This) \ + ( (This)->lpVtbl -> stop(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMediaStreamTrack_INTERFACE_DEFINED__ */ + + +#ifndef __ISourceInfo_INTERFACE_DEFINED__ +#define __ISourceInfo_INTERFACE_DEFINED__ + +/* interface ISourceInfo */ +/* [unique][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_ISourceInfo; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("BCD116DA-B4BC-472E-A6AE-363D13B78667") + ISourceInfo : public IDispatch + { + public: + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_sourceId( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_id( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_kind( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_label( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_facing( + /* [retval][out] */ BSTR *pVal) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ISourceInfoVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISourceInfo * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISourceInfo * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISourceInfo * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + ISourceInfo * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + ISourceInfo * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + ISourceInfo * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + ISourceInfo * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_sourceId )( + ISourceInfo * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_id )( + ISourceInfo * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_kind )( + ISourceInfo * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_label )( + ISourceInfo * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_facing )( + ISourceInfo * This, + /* [retval][out] */ BSTR *pVal); + + END_INTERFACE + } ISourceInfoVtbl; + + interface ISourceInfo + { + CONST_VTBL struct ISourceInfoVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISourceInfo_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISourceInfo_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISourceInfo_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISourceInfo_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define ISourceInfo_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define ISourceInfo_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define ISourceInfo_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define ISourceInfo_get_sourceId(This,pVal) \ + ( (This)->lpVtbl -> get_sourceId(This,pVal) ) + +#define ISourceInfo_get_id(This,pVal) \ + ( (This)->lpVtbl -> get_id(This,pVal) ) + +#define ISourceInfo_get_kind(This,pVal) \ + ( (This)->lpVtbl -> get_kind(This,pVal) ) + +#define ISourceInfo_get_label(This,pVal) \ + ( (This)->lpVtbl -> get_label(This,pVal) ) + +#define ISourceInfo_get_facing(This,pVal) \ + ( (This)->lpVtbl -> get_facing(This,pVal) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISourceInfo_INTERFACE_DEFINED__ */ + + +#ifndef __IMediaSourceStates_INTERFACE_DEFINED__ +#define __IMediaSourceStates_INTERFACE_DEFINED__ + +/* interface IMediaSourceStates */ +/* [unique][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IMediaSourceStates; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7A2B697F-688A-4CBE-B36F-4820D12BAE61") + IMediaSourceStates : public IDispatch + { + public: + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_sourceType( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_sourceId( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_width( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_height( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_frameRate( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_aspectRatio( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_facingMode( + /* [retval][out] */ VARIANT *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_volume( + /* [retval][out] */ VARIANT *pVal) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IMediaSourceStatesVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMediaSourceStates * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMediaSourceStates * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMediaSourceStates * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IMediaSourceStates * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IMediaSourceStates * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IMediaSourceStates * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IMediaSourceStates * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_sourceType )( + IMediaSourceStates * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_sourceId )( + IMediaSourceStates * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_width )( + IMediaSourceStates * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_height )( + IMediaSourceStates * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_frameRate )( + IMediaSourceStates * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_aspectRatio )( + IMediaSourceStates * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_facingMode )( + IMediaSourceStates * This, + /* [retval][out] */ VARIANT *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_volume )( + IMediaSourceStates * This, + /* [retval][out] */ VARIANT *pVal); + + END_INTERFACE + } IMediaSourceStatesVtbl; + + interface IMediaSourceStates + { + CONST_VTBL struct IMediaSourceStatesVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMediaSourceStates_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMediaSourceStates_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMediaSourceStates_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMediaSourceStates_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IMediaSourceStates_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IMediaSourceStates_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IMediaSourceStates_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define IMediaSourceStates_get_sourceType(This,pVal) \ + ( (This)->lpVtbl -> get_sourceType(This,pVal) ) + +#define IMediaSourceStates_get_sourceId(This,pVal) \ + ( (This)->lpVtbl -> get_sourceId(This,pVal) ) + +#define IMediaSourceStates_get_width(This,pVal) \ + ( (This)->lpVtbl -> get_width(This,pVal) ) + +#define IMediaSourceStates_get_height(This,pVal) \ + ( (This)->lpVtbl -> get_height(This,pVal) ) + +#define IMediaSourceStates_get_frameRate(This,pVal) \ + ( (This)->lpVtbl -> get_frameRate(This,pVal) ) + +#define IMediaSourceStates_get_aspectRatio(This,pVal) \ + ( (This)->lpVtbl -> get_aspectRatio(This,pVal) ) + +#define IMediaSourceStates_get_facingMode(This,pVal) \ + ( (This)->lpVtbl -> get_facingMode(This,pVal) ) + +#define IMediaSourceStates_get_volume(This,pVal) \ + ( (This)->lpVtbl -> get_volume(This,pVal) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMediaSourceStates_INTERFACE_DEFINED__ */ + + +#ifndef __IMediaStreamEvent_INTERFACE_DEFINED__ +#define __IMediaStreamEvent_INTERFACE_DEFINED__ + +/* interface IMediaStreamEvent */ +/* [unique][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IMediaStreamEvent; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("EAB6AB59-5B8E-4096-AA67-0D557AA6BB32") + IMediaStreamEvent : public IDispatch + { + public: + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_stream( + /* [retval][out] */ VARIANT *pVal) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IMediaStreamEventVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMediaStreamEvent * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMediaStreamEvent * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMediaStreamEvent * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IMediaStreamEvent * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IMediaStreamEvent * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IMediaStreamEvent * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IMediaStreamEvent * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_stream )( + IMediaStreamEvent * This, + /* [retval][out] */ VARIANT *pVal); + + END_INTERFACE + } IMediaStreamEventVtbl; + + interface IMediaStreamEvent + { + CONST_VTBL struct IMediaStreamEventVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMediaStreamEvent_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMediaStreamEvent_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMediaStreamEvent_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMediaStreamEvent_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IMediaStreamEvent_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IMediaStreamEvent_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IMediaStreamEvent_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define IMediaStreamEvent_get_stream(This,pVal) \ + ( (This)->lpVtbl -> get_stream(This,pVal) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMediaStreamEvent_INTERFACE_DEFINED__ */ + + +#ifndef __IRTCPeerConnectionIceEvent_INTERFACE_DEFINED__ +#define __IRTCPeerConnectionIceEvent_INTERFACE_DEFINED__ + +/* interface IRTCPeerConnectionIceEvent */ +/* [unique][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IRTCPeerConnectionIceEvent; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("354C2E39-380F-4F24-AEEA-687EB67F759D") + IRTCPeerConnectionIceEvent : public IDispatch + { + public: + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_candidate( + /* [retval][out] */ VARIANT *pVal) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IRTCPeerConnectionIceEventVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IRTCPeerConnectionIceEvent * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IRTCPeerConnectionIceEvent * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IRTCPeerConnectionIceEvent * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IRTCPeerConnectionIceEvent * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IRTCPeerConnectionIceEvent * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IRTCPeerConnectionIceEvent * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IRTCPeerConnectionIceEvent * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_candidate )( + IRTCPeerConnectionIceEvent * This, + /* [retval][out] */ VARIANT *pVal); + + END_INTERFACE + } IRTCPeerConnectionIceEventVtbl; + + interface IRTCPeerConnectionIceEvent + { + CONST_VTBL struct IRTCPeerConnectionIceEventVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IRTCPeerConnectionIceEvent_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IRTCPeerConnectionIceEvent_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IRTCPeerConnectionIceEvent_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IRTCPeerConnectionIceEvent_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IRTCPeerConnectionIceEvent_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IRTCPeerConnectionIceEvent_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IRTCPeerConnectionIceEvent_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define IRTCPeerConnectionIceEvent_get_candidate(This,pVal) \ + ( (This)->lpVtbl -> get_candidate(This,pVal) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IRTCPeerConnectionIceEvent_INTERFACE_DEFINED__ */ + + +#ifndef __IRTCStatsReport_INTERFACE_DEFINED__ +#define __IRTCStatsReport_INTERFACE_DEFINED__ + +/* interface IRTCStatsReport */ +/* [unique][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IRTCStatsReport; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("455118D0-A29F-44DB-ACF7-FE22BFAE2167") + IRTCStatsReport : public IDispatch + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE result( + /* [retval][out] */ VARIANT *RTCStatsList) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IRTCStatsReportVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IRTCStatsReport * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IRTCStatsReport * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IRTCStatsReport * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IRTCStatsReport * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IRTCStatsReport * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IRTCStatsReport * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IRTCStatsReport * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *result )( + IRTCStatsReport * This, + /* [retval][out] */ VARIANT *RTCStatsList); + + END_INTERFACE + } IRTCStatsReportVtbl; + + interface IRTCStatsReport + { + CONST_VTBL struct IRTCStatsReportVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IRTCStatsReport_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IRTCStatsReport_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IRTCStatsReport_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IRTCStatsReport_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IRTCStatsReport_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IRTCStatsReport_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IRTCStatsReport_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define IRTCStatsReport_result(This,RTCStatsList) \ + ( (This)->lpVtbl -> result(This,RTCStatsList) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IRTCStatsReport_INTERFACE_DEFINED__ */ + + +#ifndef __IRTCStats_INTERFACE_DEFINED__ +#define __IRTCStats_INTERFACE_DEFINED__ + +/* interface IRTCStats */ +/* [unique][nonextensible][dual][uuid][object] */ + + +EXTERN_C const IID IID_IRTCStats; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("CEFEB782-AFEC-4D0D-8C62-F1E255A73841") + IRTCStats : public IDispatch + { + public: + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_timestamp( + /* [retval][out] */ DOUBLE *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_type( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_id( + /* [retval][out] */ BSTR *pVal) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE names( + /* [retval][out] */ VARIANT *Names) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE stat( + /* [in] */ BSTR name, + /* [retval][out] */ BSTR *pVal) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IRTCStatsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IRTCStats * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IRTCStats * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IRTCStats * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + IRTCStats * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + IRTCStats * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + IRTCStats * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + IRTCStats * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_timestamp )( + IRTCStats * This, + /* [retval][out] */ DOUBLE *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_type )( + IRTCStats * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_id )( + IRTCStats * This, + /* [retval][out] */ BSTR *pVal); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *names )( + IRTCStats * This, + /* [retval][out] */ VARIANT *Names); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *stat )( + IRTCStats * This, + /* [in] */ BSTR name, + /* [retval][out] */ BSTR *pVal); + + END_INTERFACE + } IRTCStatsVtbl; + + interface IRTCStats + { + CONST_VTBL struct IRTCStatsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IRTCStats_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IRTCStats_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IRTCStats_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IRTCStats_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define IRTCStats_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define IRTCStats_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define IRTCStats_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + + +#define IRTCStats_get_timestamp(This,pVal) \ + ( (This)->lpVtbl -> get_timestamp(This,pVal) ) + +#define IRTCStats_get_type(This,pVal) \ + ( (This)->lpVtbl -> get_type(This,pVal) ) + +#define IRTCStats_get_id(This,pVal) \ + ( (This)->lpVtbl -> get_id(This,pVal) ) + +#define IRTCStats_names(This,Names) \ + ( (This)->lpVtbl -> names(This,Names) ) + +#define IRTCStats_stat(This,name,pVal) \ + ( (This)->lpVtbl -> stat(This,name,pVal) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IRTCStats_INTERFACE_DEFINED__ */ + + + +#ifndef __webrtceverywhereLib_LIBRARY_DEFINED__ +#define __webrtceverywhereLib_LIBRARY_DEFINED__ + +/* library webrtceverywhereLib */ +/* [helpstring][version][uuid] */ + + +EXTERN_C const IID LIBID_webrtceverywhereLib; + +#ifndef ___IWebRTCEvents_DISPINTERFACE_DEFINED__ +#define ___IWebRTCEvents_DISPINTERFACE_DEFINED__ + +/* dispinterface _IWebRTCEvents */ +/* [helpstring][uuid] */ + + +EXTERN_C const IID DIID__IWebRTCEvents; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("20B33168-3B94-49C3-9E55-A60B9EA0E886") + _IWebRTCEvents : public IDispatch + { + }; + +#else /* C style interface */ + + typedef struct _IWebRTCEventsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + _IWebRTCEvents * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + _IWebRTCEvents * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + _IWebRTCEvents * This); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( + _IWebRTCEvents * This, + /* [out] */ UINT *pctinfo); + + HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( + _IWebRTCEvents * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo **ppTInfo); + + HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( + _IWebRTCEvents * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR *rgszNames, + /* [range][in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID *rgDispId); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( + _IWebRTCEvents * This, + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS *pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT *pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO *pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT *puArgErr); + + END_INTERFACE + } _IWebRTCEventsVtbl; + + interface _IWebRTCEvents + { + CONST_VTBL struct _IWebRTCEventsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define _IWebRTCEvents_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define _IWebRTCEvents_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define _IWebRTCEvents_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define _IWebRTCEvents_GetTypeInfoCount(This,pctinfo) \ + ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) + +#define _IWebRTCEvents_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ + ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) + +#define _IWebRTCEvents_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ + ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) + +#define _IWebRTCEvents_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ + ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + +#endif /* ___IWebRTCEvents_DISPINTERFACE_DEFINED__ */ + + +EXTERN_C const CLSID CLSID_WebRTC; + +#ifdef __cplusplus + +class DECLSPEC_UUID("7FD49E23-C8D7-4C4F-93A1-F7EACFA1EC53") +WebRTC; +#endif + +EXTERN_C const CLSID CLSID_SessionDescription; + +#ifdef __cplusplus + +class DECLSPEC_UUID("3F7C50A7-7B5C-4631-8988-17B43A938667") +SessionDescription; +#endif + +EXTERN_C const CLSID CLSID_DictOptions; + +#ifdef __cplusplus + +class DECLSPEC_UUID("D6B8C652-7A2A-47B6-8C38-3BD5BB0E2872") +DictOptions; +#endif + +EXTERN_C const CLSID CLSID_PeerConnection; + +#ifdef __cplusplus + +class DECLSPEC_UUID("017D6D0A-BDBC-45DC-9368-A7ED657DAC4D") +PeerConnection; +#endif + +EXTERN_C const CLSID CLSID_MediaStream; + +#ifdef __cplusplus + +class DECLSPEC_UUID("BA5835A2-D1F8-466D-BB5E-8093E3E2EE0E") +MediaStream; +#endif + +EXTERN_C const CLSID CLSID_RTCIceCandidate; + +#ifdef __cplusplus + +class DECLSPEC_UUID("31074FC8-A7D4-4281-9C90-B7D20C53A023") +RTCIceCandidate; +#endif + +EXTERN_C const CLSID CLSID_MediaStreamTrack; + +#ifdef __cplusplus + +class DECLSPEC_UUID("DA1D1412-BC34-4288-8047-6FFE131C647F") +MediaStreamTrack; +#endif + +EXTERN_C const CLSID CLSID_SourceInfo; + +#ifdef __cplusplus + +class DECLSPEC_UUID("E66A3288-4BFB-41E2-850D-61C63208DD80") +SourceInfo; +#endif + +EXTERN_C const CLSID CLSID_MediaSourceStates; + +#ifdef __cplusplus + +class DECLSPEC_UUID("7F64ACB6-F21C-44C2-8EEA-EFCBEED5AEB7") +MediaSourceStates; +#endif + +EXTERN_C const CLSID CLSID_MediaStreamEvent; + +#ifdef __cplusplus + +class DECLSPEC_UUID("C744BE59-7004-4B7E-BD9D-C83F594A1B69") +MediaStreamEvent; +#endif + +EXTERN_C const CLSID CLSID_RTCPeerConnectionIceEvent; + +#ifdef __cplusplus + +class DECLSPEC_UUID("1A225B63-CA8F-466E-A848-44A16A19706E") +RTCPeerConnectionIceEvent; +#endif + +EXTERN_C const CLSID CLSID_RTCStatsReport; + +#ifdef __cplusplus + +class DECLSPEC_UUID("419C32C7-EF29-42C3-9A02-7C64FF869FD6") +RTCStatsReport; +#endif + +EXTERN_C const CLSID CLSID_RTCStats; + +#ifdef __cplusplus + +class DECLSPEC_UUID("F752E29B-45CB-4753-AA0C-51D1A021143C") +RTCStats; +#endif +#endif /* __webrtceverywhereLib_LIBRARY_DEFINED__ */ + +/* Additional Prototypes for ALL interfaces */ + +unsigned long __RPC_USER BSTR_UserSize( unsigned long *, unsigned long , BSTR * ); +unsigned char * __RPC_USER BSTR_UserMarshal( unsigned long *, unsigned char *, BSTR * ); +unsigned char * __RPC_USER BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * ); +void __RPC_USER BSTR_UserFree( unsigned long *, BSTR * ); + +unsigned long __RPC_USER VARIANT_UserSize( unsigned long *, unsigned long , VARIANT * ); +unsigned char * __RPC_USER VARIANT_UserMarshal( unsigned long *, unsigned char *, VARIANT * ); +unsigned char * __RPC_USER VARIANT_UserUnmarshal(unsigned long *, unsigned char *, VARIANT * ); +void __RPC_USER VARIANT_UserFree( unsigned long *, VARIANT * ); + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/ie/webrtceverywhere_p.c b/ie/webrtceverywhere_p.c new file mode 100644 index 0000000..e2dcc09 --- /dev/null +++ b/ie/webrtceverywhere_p.c @@ -0,0 +1,5162 @@ + + +/* this ALWAYS GENERATED file contains the proxy stub code */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Wed Jul 23 09:29:21 2014 + */ +/* Compiler settings for webrtceverywhere.idl: + Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0603 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#if !defined(_M_IA64) && !defined(_M_AMD64) && !defined(_ARM_) + + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif + +#pragma warning( disable: 4211 ) /* redefine extern to static */ +#pragma warning( disable: 4232 ) /* dllimport identity*/ +#pragma warning( disable: 4024 ) /* array to pointer mapping*/ +#pragma warning( disable: 4152 ) /* function/data pointer conversion in expression */ +#pragma warning( disable: 4100 ) /* unreferenced arguments in x86 call */ + +#pragma optimize("", off ) + +#define USE_STUBLESS_PROXY + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REDQ_RPCPROXY_H_VERSION__ +#define __REQUIRED_RPCPROXY_H_VERSION__ 475 +#endif + + +#include "rpcproxy.h" +#ifndef __RPCPROXY_H_VERSION__ +#error this stub requires an updated version of +#endif /* __RPCPROXY_H_VERSION__ */ + + +#include "webrtceverywhere_i.h" + +#define TYPE_FORMAT_STRING_SIZE 1097 +#define PROC_FORMAT_STRING_SIZE 3037 +#define EXPR_FORMAT_STRING_SIZE 1 +#define TRANSMIT_AS_TABLE_SIZE 0 +#define WIRE_MARSHAL_TABLE_SIZE 2 + +typedef struct _webrtceverywhere_MIDL_TYPE_FORMAT_STRING + { + short Pad; + unsigned char Format[ TYPE_FORMAT_STRING_SIZE ]; + } webrtceverywhere_MIDL_TYPE_FORMAT_STRING; + +typedef struct _webrtceverywhere_MIDL_PROC_FORMAT_STRING + { + short Pad; + unsigned char Format[ PROC_FORMAT_STRING_SIZE ]; + } webrtceverywhere_MIDL_PROC_FORMAT_STRING; + +typedef struct _webrtceverywhere_MIDL_EXPR_FORMAT_STRING + { + long Pad; + unsigned char Format[ EXPR_FORMAT_STRING_SIZE ]; + } webrtceverywhere_MIDL_EXPR_FORMAT_STRING; + + +static const RPC_SYNTAX_IDENTIFIER _RpcTransferSyntax = +{{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}; + + +extern const webrtceverywhere_MIDL_TYPE_FORMAT_STRING webrtceverywhere__MIDL_TypeFormatString; +extern const webrtceverywhere_MIDL_PROC_FORMAT_STRING webrtceverywhere__MIDL_ProcFormatString; +extern const webrtceverywhere_MIDL_EXPR_FORMAT_STRING webrtceverywhere__MIDL_ExprFormatString; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IWebRTC_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IWebRTC_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO ISessionDescription_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO ISessionDescription_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IDictOptions_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IDictOptions_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IPeerConnection_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IPeerConnection_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IMediaStream_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IMediaStream_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IRTCIceCandidate_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IRTCIceCandidate_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IMediaStreamTrack_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IMediaStreamTrack_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO ISourceInfo_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO ISourceInfo_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IMediaSourceStates_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IMediaSourceStates_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IMediaStreamEvent_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IMediaStreamEvent_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IRTCPeerConnectionIceEvent_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IRTCPeerConnectionIceEvent_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IRTCStatsReport_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IRTCStatsReport_ProxyInfo; + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +extern const MIDL_SERVER_INFO IRTCStats_ServerInfo; +extern const MIDL_STUBLESS_PROXY_INFO IRTCStats_ProxyInfo; + + +extern const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[ WIRE_MARSHAL_TABLE_SIZE ]; + +#if !defined(__RPC_WIN32__) +#error Invalid build platform for this stub. +#endif + +#if !(TARGET_IS_NT50_OR_LATER) +#error You need Windows 2000 or later to run this stub because it uses these features: +#error /robust command line switch. +#error However, your C/C++ compilation flags indicate you intend to run this app on earlier systems. +#error This app will fail with the RPC_X_WRONG_STUB_VERSION error. +#endif + + +static const webrtceverywhere_MIDL_PROC_FORMAT_STRING webrtceverywhere__MIDL_ProcFormatString = + { + 0, + { + + /* Procedure get_sourceType */ + + + /* Procedure get_sourceId */ + + + /* Procedure get_kind */ + + + /* Procedure get_candidate */ + + + /* Procedure get_id */ + + + /* Procedure get_type */ + + + /* Procedure get_versionName */ + + 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2 */ NdrFcLong( 0x0 ), /* 0 */ +/* 6 */ NdrFcShort( 0x7 ), /* 7 */ +/* 8 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 10 */ NdrFcShort( 0x0 ), /* 0 */ +/* 12 */ NdrFcShort( 0x8 ), /* 8 */ +/* 14 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 16 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 18 */ NdrFcShort( 0x1 ), /* 1 */ +/* 20 */ NdrFcShort( 0x0 ), /* 0 */ +/* 22 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + +/* 24 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 26 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 28 */ NdrFcShort( 0x20 ), /* Type Offset=32 */ + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + +/* 30 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 32 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 34 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure createAnswer */ + + + /* Procedure getUserMedia */ + +/* 36 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 38 */ NdrFcLong( 0x0 ), /* 0 */ +/* 42 */ NdrFcShort( 0x8 ), /* 8 */ +/* 44 */ NdrFcShort( 0x38 ), /* x86 Stack size/offset = 56 */ +/* 46 */ NdrFcShort( 0x0 ), /* 0 */ +/* 48 */ NdrFcShort( 0x8 ), /* 8 */ +/* 50 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x4, /* 4 */ +/* 52 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 54 */ NdrFcShort( 0x0 ), /* 0 */ +/* 56 */ NdrFcShort( 0x1 ), /* 1 */ +/* 58 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter successCallback */ + + + /* Parameter constraints */ + +/* 60 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 62 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 64 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter failureCallback */ + + + /* Parameter successCallback */ + +/* 66 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 68 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 70 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter MediaConstraints */ + + + /* Parameter errorCallback */ + +/* 72 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 74 */ NdrFcShort( 0x24 ), /* x86 Stack size/offset = 36 */ +/* 76 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + + + /* Return value */ + +/* 78 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 80 */ NdrFcShort( 0x34 ), /* x86 Stack size/offset = 52 */ +/* 82 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure createDisplay */ + +/* 84 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 86 */ NdrFcLong( 0x0 ), /* 0 */ +/* 90 */ NdrFcShort( 0x9 ), /* 9 */ +/* 92 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 94 */ NdrFcShort( 0x0 ), /* 0 */ +/* 96 */ NdrFcShort( 0x8 ), /* 8 */ +/* 98 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 100 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 102 */ NdrFcShort( 0x0 ), /* 0 */ +/* 104 */ NdrFcShort( 0x0 ), /* 0 */ +/* 106 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter ppDisplay */ + +/* 108 */ NdrFcShort( 0x13 ), /* Flags: must size, must free, out, */ +/* 110 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 112 */ NdrFcShort( 0x41c ), /* Type Offset=1052 */ + + /* Return value */ + +/* 114 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 116 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 118 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure createSessionDescription */ + +/* 120 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 122 */ NdrFcLong( 0x0 ), /* 0 */ +/* 126 */ NdrFcShort( 0xa ), /* 10 */ +/* 128 */ NdrFcShort( 0x1c ), /* x86 Stack size/offset = 28 */ +/* 130 */ NdrFcShort( 0x0 ), /* 0 */ +/* 132 */ NdrFcShort( 0x8 ), /* 8 */ +/* 134 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */ + 0x3, /* 3 */ +/* 136 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 138 */ NdrFcShort( 0x0 ), /* 0 */ +/* 140 */ NdrFcShort( 0x1 ), /* 1 */ +/* 142 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter RTCSessionDescriptionInit */ + +/* 144 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 146 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 148 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter ppSdp */ + +/* 150 */ NdrFcShort( 0x13 ), /* Flags: must size, must free, out, */ +/* 152 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 154 */ NdrFcShort( 0x41c ), /* Type Offset=1052 */ + + /* Return value */ + +/* 156 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 158 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 160 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure createDictOptions */ + +/* 162 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 164 */ NdrFcLong( 0x0 ), /* 0 */ +/* 168 */ NdrFcShort( 0xb ), /* 11 */ +/* 170 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 172 */ NdrFcShort( 0x0 ), /* 0 */ +/* 174 */ NdrFcShort( 0x8 ), /* 8 */ +/* 176 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 178 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 180 */ NdrFcShort( 0x0 ), /* 0 */ +/* 182 */ NdrFcShort( 0x0 ), /* 0 */ +/* 184 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter ppDictOptions */ + +/* 186 */ NdrFcShort( 0x13 ), /* Flags: must size, must free, out, */ +/* 188 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 190 */ NdrFcShort( 0x41c ), /* Type Offset=1052 */ + + /* Return value */ + +/* 192 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 194 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 196 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure createPeerConnection */ + +/* 198 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 200 */ NdrFcLong( 0x0 ), /* 0 */ +/* 204 */ NdrFcShort( 0xc ), /* 12 */ +/* 206 */ NdrFcShort( 0x2c ), /* x86 Stack size/offset = 44 */ +/* 208 */ NdrFcShort( 0x0 ), /* 0 */ +/* 210 */ NdrFcShort( 0x8 ), /* 8 */ +/* 212 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */ + 0x4, /* 4 */ +/* 214 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 216 */ NdrFcShort( 0x0 ), /* 0 */ +/* 218 */ NdrFcShort( 0x1 ), /* 1 */ +/* 220 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter RTCConfiguration */ + +/* 222 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 224 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 226 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter MediaConstraints */ + +/* 228 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 230 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 232 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter ppPeerConnection */ + +/* 234 */ NdrFcShort( 0x13 ), /* Flags: must size, must free, out, */ +/* 236 */ NdrFcShort( 0x24 ), /* x86 Stack size/offset = 36 */ +/* 238 */ NdrFcShort( 0x41c ), /* Type Offset=1052 */ + + /* Return value */ + +/* 240 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 242 */ NdrFcShort( 0x28 ), /* x86 Stack size/offset = 40 */ +/* 244 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure createIceCandidate */ + +/* 246 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 248 */ NdrFcLong( 0x0 ), /* 0 */ +/* 252 */ NdrFcShort( 0xd ), /* 13 */ +/* 254 */ NdrFcShort( 0x1c ), /* x86 Stack size/offset = 28 */ +/* 256 */ NdrFcShort( 0x0 ), /* 0 */ +/* 258 */ NdrFcShort( 0x8 ), /* 8 */ +/* 260 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */ + 0x3, /* 3 */ +/* 262 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 264 */ NdrFcShort( 0x0 ), /* 0 */ +/* 266 */ NdrFcShort( 0x1 ), /* 1 */ +/* 268 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter RTCIceCandidateInit */ + +/* 270 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 272 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 274 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter ppIceCandidate */ + +/* 276 */ NdrFcShort( 0x13 ), /* Flags: must size, must free, out, */ +/* 278 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 280 */ NdrFcShort( 0x41c ), /* Type Offset=1052 */ + + /* Return value */ + +/* 282 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 284 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 286 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure createMediaStreamTrack */ + +/* 288 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 290 */ NdrFcLong( 0x0 ), /* 0 */ +/* 294 */ NdrFcShort( 0xe ), /* 14 */ +/* 296 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 298 */ NdrFcShort( 0x0 ), /* 0 */ +/* 300 */ NdrFcShort( 0x8 ), /* 8 */ +/* 302 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 304 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 306 */ NdrFcShort( 0x0 ), /* 0 */ +/* 308 */ NdrFcShort( 0x0 ), /* 0 */ +/* 310 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter ppMediaStreamTrack */ + +/* 312 */ NdrFcShort( 0x13 ), /* Flags: must size, must free, out, */ +/* 314 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 316 */ NdrFcShort( 0x41c ), /* Type Offset=1052 */ + + /* Return value */ + +/* 318 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 320 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 322 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure bindEventListener */ + +/* 324 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 326 */ NdrFcLong( 0x0 ), /* 0 */ +/* 330 */ NdrFcShort( 0xf ), /* 15 */ +/* 332 */ NdrFcShort( 0x2c ), /* x86 Stack size/offset = 44 */ +/* 334 */ NdrFcShort( 0x0 ), /* 0 */ +/* 336 */ NdrFcShort( 0x8 ), /* 8 */ +/* 338 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x4, /* 4 */ +/* 340 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 342 */ NdrFcShort( 0x0 ), /* 0 */ +/* 344 */ NdrFcShort( 0x1 ), /* 1 */ +/* 346 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter type */ + +/* 348 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 350 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 352 */ NdrFcShort( 0x420 ), /* Type Offset=1056 */ + + /* Parameter listenerCallback */ + +/* 354 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 356 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 358 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter useCapture */ + +/* 360 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 362 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 364 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 366 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 368 */ NdrFcShort( 0x28 ), /* x86 Stack size/offset = 40 */ +/* 370 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_onunmute */ + + + /* Procedure put_onended */ + + + /* Procedure getSources */ + +/* 372 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 374 */ NdrFcLong( 0x0 ), /* 0 */ +/* 378 */ NdrFcShort( 0x10 ), /* 16 */ +/* 380 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 382 */ NdrFcShort( 0x0 ), /* 0 */ +/* 384 */ NdrFcShort( 0x8 ), /* 8 */ +/* 386 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 388 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 390 */ NdrFcShort( 0x0 ), /* 0 */ +/* 392 */ NdrFcShort( 0x1 ), /* 1 */ +/* 394 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + + + /* Parameter newVal */ + + + /* Parameter successCallback */ + +/* 396 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 398 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 400 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + +/* 402 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 404 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 406 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_src */ + +/* 408 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 410 */ NdrFcLong( 0x0 ), /* 0 */ +/* 414 */ NdrFcShort( 0x11 ), /* 17 */ +/* 416 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 418 */ NdrFcShort( 0x0 ), /* 0 */ +/* 420 */ NdrFcShort( 0x8 ), /* 8 */ +/* 422 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 424 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 426 */ NdrFcShort( 0x0 ), /* 0 */ +/* 428 */ NdrFcShort( 0x1 ), /* 1 */ +/* 430 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 432 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 434 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 436 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 438 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 440 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 442 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_videoWidth */ + +/* 444 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 446 */ NdrFcLong( 0x0 ), /* 0 */ +/* 450 */ NdrFcShort( 0x12 ), /* 18 */ +/* 452 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 454 */ NdrFcShort( 0x0 ), /* 0 */ +/* 456 */ NdrFcShort( 0x24 ), /* 36 */ +/* 458 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 460 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 462 */ NdrFcShort( 0x0 ), /* 0 */ +/* 464 */ NdrFcShort( 0x0 ), /* 0 */ +/* 466 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 468 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 470 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 472 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Return value */ + +/* 474 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 476 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 478 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_videoHeight */ + +/* 480 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 482 */ NdrFcLong( 0x0 ), /* 0 */ +/* 486 */ NdrFcShort( 0x13 ), /* 19 */ +/* 488 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 490 */ NdrFcShort( 0x0 ), /* 0 */ +/* 492 */ NdrFcShort( 0x24 ), /* 36 */ +/* 494 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 496 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 498 */ NdrFcShort( 0x0 ), /* 0 */ +/* 500 */ NdrFcShort( 0x0 ), /* 0 */ +/* 502 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 504 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 506 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 508 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Return value */ + +/* 510 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 512 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 514 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_onremovetrack */ + + + /* Procedure fillImageData */ + +/* 516 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 518 */ NdrFcLong( 0x0 ), /* 0 */ +/* 522 */ NdrFcShort( 0x14 ), /* 20 */ +/* 524 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 526 */ NdrFcShort( 0x0 ), /* 0 */ +/* 528 */ NdrFcShort( 0x8 ), /* 8 */ +/* 530 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 532 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 534 */ NdrFcShort( 0x0 ), /* 0 */ +/* 536 */ NdrFcShort( 0x1 ), /* 1 */ +/* 538 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + + + /* Parameter imageData */ + +/* 540 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 542 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 544 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + + + /* Return value */ + +/* 546 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 548 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 550 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_isWebRtcPlugin */ + +/* 552 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 554 */ NdrFcLong( 0x0 ), /* 0 */ +/* 558 */ NdrFcShort( 0x15 ), /* 21 */ +/* 560 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 562 */ NdrFcShort( 0x0 ), /* 0 */ +/* 564 */ NdrFcShort( 0x22 ), /* 34 */ +/* 566 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 568 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 570 */ NdrFcShort( 0x0 ), /* 0 */ +/* 572 */ NdrFcShort( 0x0 ), /* 0 */ +/* 574 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 576 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 578 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 580 */ 0x6, /* FC_SHORT */ + 0x0, /* 0 */ + + /* Return value */ + +/* 582 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 584 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 586 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_type */ + +/* 588 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 590 */ NdrFcLong( 0x0 ), /* 0 */ +/* 594 */ NdrFcShort( 0x8 ), /* 8 */ +/* 596 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 598 */ NdrFcShort( 0x0 ), /* 0 */ +/* 600 */ NdrFcShort( 0x8 ), /* 8 */ +/* 602 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 604 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 606 */ NdrFcShort( 0x0 ), /* 0 */ +/* 608 */ NdrFcShort( 0x1 ), /* 1 */ +/* 610 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 612 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 614 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 616 */ NdrFcShort( 0x420 ), /* Type Offset=1056 */ + + /* Return value */ + +/* 618 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 620 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 622 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_id */ + + + /* Procedure get_kind */ + + + /* Procedure get_label */ + + + /* Procedure get_sdp */ + +/* 624 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 626 */ NdrFcLong( 0x0 ), /* 0 */ +/* 630 */ NdrFcShort( 0x9 ), /* 9 */ +/* 632 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 634 */ NdrFcShort( 0x0 ), /* 0 */ +/* 636 */ NdrFcShort( 0x8 ), /* 8 */ +/* 638 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 640 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 642 */ NdrFcShort( 0x1 ), /* 1 */ +/* 644 */ NdrFcShort( 0x0 ), /* 0 */ +/* 646 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + +/* 648 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 650 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 652 */ NdrFcShort( 0x20 ), /* Type Offset=32 */ + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + +/* 654 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 656 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 658 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_sdp */ + +/* 660 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 662 */ NdrFcLong( 0x0 ), /* 0 */ +/* 666 */ NdrFcShort( 0xa ), /* 10 */ +/* 668 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 670 */ NdrFcShort( 0x0 ), /* 0 */ +/* 672 */ NdrFcShort( 0x8 ), /* 8 */ +/* 674 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 676 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 678 */ NdrFcShort( 0x0 ), /* 0 */ +/* 680 */ NdrFcShort( 0x1 ), /* 1 */ +/* 682 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 684 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 686 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 688 */ NdrFcShort( 0x420 ), /* Type Offset=1056 */ + + /* Return value */ + +/* 690 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 692 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 694 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure createOffer */ + +/* 696 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 698 */ NdrFcLong( 0x0 ), /* 0 */ +/* 702 */ NdrFcShort( 0x7 ), /* 7 */ +/* 704 */ NdrFcShort( 0x38 ), /* x86 Stack size/offset = 56 */ +/* 706 */ NdrFcShort( 0x0 ), /* 0 */ +/* 708 */ NdrFcShort( 0x8 ), /* 8 */ +/* 710 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x4, /* 4 */ +/* 712 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 714 */ NdrFcShort( 0x0 ), /* 0 */ +/* 716 */ NdrFcShort( 0x1 ), /* 1 */ +/* 718 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter successCallback */ + +/* 720 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 722 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 724 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter failureCallback */ + +/* 726 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 728 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 730 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter MediaConstraints */ + +/* 732 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 734 */ NdrFcShort( 0x24 ), /* x86 Stack size/offset = 36 */ +/* 736 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 738 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 740 */ NdrFcShort( 0x34 ), /* x86 Stack size/offset = 52 */ +/* 742 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure setLocalDescription */ + +/* 744 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 746 */ NdrFcLong( 0x0 ), /* 0 */ +/* 750 */ NdrFcShort( 0x9 ), /* 9 */ +/* 752 */ NdrFcShort( 0x38 ), /* x86 Stack size/offset = 56 */ +/* 754 */ NdrFcShort( 0x0 ), /* 0 */ +/* 756 */ NdrFcShort( 0x8 ), /* 8 */ +/* 758 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x4, /* 4 */ +/* 760 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 762 */ NdrFcShort( 0x0 ), /* 0 */ +/* 764 */ NdrFcShort( 0x1 ), /* 1 */ +/* 766 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter RTCSessionDescription */ + +/* 768 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 770 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 772 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter successCallback */ + +/* 774 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 776 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 778 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter failureCallback */ + +/* 780 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 782 */ NdrFcShort( 0x24 ), /* x86 Stack size/offset = 36 */ +/* 784 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 786 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 788 */ NdrFcShort( 0x34 ), /* x86 Stack size/offset = 52 */ +/* 790 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure names */ + + + /* Procedure get_height */ + + + /* Procedure get_localDescription */ + +/* 792 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 794 */ NdrFcLong( 0x0 ), /* 0 */ +/* 798 */ NdrFcShort( 0xa ), /* 10 */ +/* 800 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 802 */ NdrFcShort( 0x0 ), /* 0 */ +/* 804 */ NdrFcShort( 0x8 ), /* 8 */ +/* 806 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 808 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 810 */ NdrFcShort( 0x1 ), /* 1 */ +/* 812 */ NdrFcShort( 0x0 ), /* 0 */ +/* 814 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter Names */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + +/* 816 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 818 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 820 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + +/* 822 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 824 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 826 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure setRemoteDescription */ + +/* 828 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 830 */ NdrFcLong( 0x0 ), /* 0 */ +/* 834 */ NdrFcShort( 0xb ), /* 11 */ +/* 836 */ NdrFcShort( 0x38 ), /* x86 Stack size/offset = 56 */ +/* 838 */ NdrFcShort( 0x0 ), /* 0 */ +/* 840 */ NdrFcShort( 0x8 ), /* 8 */ +/* 842 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x4, /* 4 */ +/* 844 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 846 */ NdrFcShort( 0x0 ), /* 0 */ +/* 848 */ NdrFcShort( 0x1 ), /* 1 */ +/* 850 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter RTCSessionDescription */ + +/* 852 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 854 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 856 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter successCallback */ + +/* 858 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 860 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 862 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter failureCallback */ + +/* 864 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 866 */ NdrFcShort( 0x24 ), /* x86 Stack size/offset = 36 */ +/* 868 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 870 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 872 */ NdrFcShort( 0x34 ), /* x86 Stack size/offset = 52 */ +/* 874 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_aspectRatio */ + + + /* Procedure get_remoteDescription */ + +/* 876 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 878 */ NdrFcLong( 0x0 ), /* 0 */ +/* 882 */ NdrFcShort( 0xc ), /* 12 */ +/* 884 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 886 */ NdrFcShort( 0x0 ), /* 0 */ +/* 888 */ NdrFcShort( 0x8 ), /* 8 */ +/* 890 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 892 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 894 */ NdrFcShort( 0x1 ), /* 1 */ +/* 896 */ NdrFcShort( 0x0 ), /* 0 */ +/* 898 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + + + /* Parameter pVal */ + +/* 900 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 902 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 904 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + +/* 906 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 908 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 910 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_signalingState */ + +/* 912 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 914 */ NdrFcLong( 0x0 ), /* 0 */ +/* 918 */ NdrFcShort( 0xd ), /* 13 */ +/* 920 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 922 */ NdrFcShort( 0x0 ), /* 0 */ +/* 924 */ NdrFcShort( 0x8 ), /* 8 */ +/* 926 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 928 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 930 */ NdrFcShort( 0x1 ), /* 1 */ +/* 932 */ NdrFcShort( 0x0 ), /* 0 */ +/* 934 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 936 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 938 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 940 */ NdrFcShort( 0x20 ), /* Type Offset=32 */ + + /* Return value */ + +/* 942 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 944 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 946 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure updateIce */ + +/* 948 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 950 */ NdrFcLong( 0x0 ), /* 0 */ +/* 954 */ NdrFcShort( 0xe ), /* 14 */ +/* 956 */ NdrFcShort( 0x28 ), /* x86 Stack size/offset = 40 */ +/* 958 */ NdrFcShort( 0x0 ), /* 0 */ +/* 960 */ NdrFcShort( 0x8 ), /* 8 */ +/* 962 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x3, /* 3 */ +/* 964 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 966 */ NdrFcShort( 0x0 ), /* 0 */ +/* 968 */ NdrFcShort( 0x1 ), /* 1 */ +/* 970 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter RTCConfiguration */ + +/* 972 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 974 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 976 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter MediaConstraints */ + +/* 978 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 980 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 982 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 984 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 986 */ NdrFcShort( 0x24 ), /* x86 Stack size/offset = 36 */ +/* 988 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure addIceCandidate */ + +/* 990 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 992 */ NdrFcLong( 0x0 ), /* 0 */ +/* 996 */ NdrFcShort( 0xf ), /* 15 */ +/* 998 */ NdrFcShort( 0x38 ), /* x86 Stack size/offset = 56 */ +/* 1000 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1002 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1004 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x4, /* 4 */ +/* 1006 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1008 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1010 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1012 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter RTCIceCandidate */ + +/* 1014 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1016 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1018 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter successCallback */ + +/* 1020 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1022 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1024 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter failureCallback */ + +/* 1026 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1028 */ NdrFcShort( 0x24 ), /* x86 Stack size/offset = 36 */ +/* 1030 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 1032 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1034 */ NdrFcShort( 0x34 ), /* x86 Stack size/offset = 52 */ +/* 1036 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_iceGatheringState */ + +/* 1038 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1040 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1044 */ NdrFcShort( 0x10 ), /* 16 */ +/* 1046 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1048 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1050 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1052 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1054 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1056 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1058 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1060 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 1062 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 1064 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1066 */ NdrFcShort( 0x20 ), /* Type Offset=32 */ + + /* Return value */ + +/* 1068 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1070 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1072 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_iceConnectionState */ + +/* 1074 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1076 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1080 */ NdrFcShort( 0x11 ), /* 17 */ +/* 1082 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1084 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1086 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1088 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1090 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1092 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1094 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1096 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 1098 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 1100 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1102 */ NdrFcShort( 0x20 ), /* Type Offset=32 */ + + /* Return value */ + +/* 1104 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1106 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1108 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure getLocalStreams */ + +/* 1110 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1112 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1116 */ NdrFcShort( 0x12 ), /* 18 */ +/* 1118 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1120 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1122 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1124 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1126 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1128 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1130 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1132 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter MediaStreams */ + +/* 1134 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1136 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1138 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 1140 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1142 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1144 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_onremovetrack */ + + + /* Procedure getRemoteStreams */ + +/* 1146 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1148 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1152 */ NdrFcShort( 0x13 ), /* 19 */ +/* 1154 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1156 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1158 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1160 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1162 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1164 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1166 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1168 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + + + /* Parameter MediaStreams */ + +/* 1170 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1172 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1174 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + +/* 1176 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1178 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1180 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure getStreamById */ + +/* 1182 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1184 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1188 */ NdrFcShort( 0x14 ), /* 20 */ +/* 1190 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */ +/* 1192 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1194 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1196 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */ + 0x3, /* 3 */ +/* 1198 */ 0x8, /* 8 */ + 0x7, /* Ext Flags: new corr desc, clt corr check, srv corr check, */ +/* 1200 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1202 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1204 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter streamId */ + +/* 1206 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1208 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1210 */ NdrFcShort( 0x420 ), /* Type Offset=1056 */ + + /* Parameter MediaStream */ + +/* 1212 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1214 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1216 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 1218 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1220 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1222 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure addStream */ + +/* 1224 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1226 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1230 */ NdrFcShort( 0x15 ), /* 21 */ +/* 1232 */ NdrFcShort( 0x28 ), /* x86 Stack size/offset = 40 */ +/* 1234 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1236 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1238 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x3, /* 3 */ +/* 1240 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1242 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1244 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1246 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter stream */ + +/* 1248 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1250 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1252 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter MediaConstraints */ + +/* 1254 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1256 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1258 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 1260 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1262 */ NdrFcShort( 0x24 ), /* x86 Stack size/offset = 36 */ +/* 1264 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure removeStream */ + +/* 1266 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1268 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1272 */ NdrFcShort( 0x16 ), /* 22 */ +/* 1274 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 1276 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1278 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1280 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1282 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1284 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1286 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1288 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter stream */ + +/* 1290 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1292 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1294 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 1296 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1298 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1300 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure close */ + +/* 1302 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1304 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1308 */ NdrFcShort( 0x17 ), /* 23 */ +/* 1310 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1312 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1314 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1316 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x1, /* 1 */ +/* 1318 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 1320 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1322 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1324 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Return value */ + +/* 1326 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1328 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1330 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure getStats */ + +/* 1332 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1334 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1338 */ NdrFcShort( 0x18 ), /* 24 */ +/* 1340 */ NdrFcShort( 0x38 ), /* x86 Stack size/offset = 56 */ +/* 1342 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1344 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1346 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x4, /* 4 */ +/* 1348 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1350 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1352 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1354 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter selector */ + +/* 1356 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1358 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1360 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter successCallback */ + +/* 1362 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1364 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1366 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Parameter failureCallback */ + +/* 1368 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1370 */ NdrFcShort( 0x24 ), /* x86 Stack size/offset = 36 */ +/* 1372 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 1374 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1376 */ NdrFcShort( 0x34 ), /* x86 Stack size/offset = 52 */ +/* 1378 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure constraints */ + + + /* Procedure get_onnegotiationneeded */ + +/* 1380 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1382 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1386 */ NdrFcShort( 0x19 ), /* 25 */ +/* 1388 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1390 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1392 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1394 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1396 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1398 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1400 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1402 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter MediaTrackConstraints */ + + + /* Parameter pVal */ + +/* 1404 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1406 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1408 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + +/* 1410 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1412 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1414 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_onnegotiationneeded */ + +/* 1416 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1418 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1422 */ NdrFcShort( 0x1a ), /* 26 */ +/* 1424 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 1426 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1428 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1430 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1432 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1434 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1436 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1438 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 1440 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1442 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1444 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 1446 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1448 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1450 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure capabilities */ + + + /* Procedure get_onicecandidate */ + +/* 1452 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1454 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1458 */ NdrFcShort( 0x1b ), /* 27 */ +/* 1460 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1462 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1464 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1466 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1468 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1470 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1472 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1474 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter AllCapabilities */ + + + /* Parameter pVal */ + +/* 1476 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1478 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1480 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + +/* 1482 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1484 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1486 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure applyConstraints */ + + + /* Procedure put_onicecandidate */ + +/* 1488 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1490 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1494 */ NdrFcShort( 0x1c ), /* 28 */ +/* 1496 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 1498 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1500 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1502 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1504 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1506 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1508 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1510 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter MediaTrackConstraints */ + + + /* Parameter newVal */ + +/* 1512 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1514 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1516 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + + + /* Return value */ + +/* 1518 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1520 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1522 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_onoverconstrained */ + + + /* Procedure get_onsignalingstatechange */ + +/* 1524 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1526 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1530 */ NdrFcShort( 0x1d ), /* 29 */ +/* 1532 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1534 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1536 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1538 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1540 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1542 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1544 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1546 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + + + /* Parameter pVal */ + +/* 1548 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1550 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1552 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + +/* 1554 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1556 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1558 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_onoverconstrained */ + + + /* Procedure put_onsignalingstatechange */ + +/* 1560 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1562 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1566 */ NdrFcShort( 0x1e ), /* 30 */ +/* 1568 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 1570 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1572 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1574 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1576 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1578 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1580 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1582 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + + + /* Parameter newVal */ + +/* 1584 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1586 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1588 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + + + /* Return value */ + +/* 1590 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1592 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1594 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure clone */ + + + /* Procedure get_onaddstream */ + +/* 1596 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1598 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1602 */ NdrFcShort( 0x1f ), /* 31 */ +/* 1604 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1606 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1608 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1610 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1612 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1614 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1616 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1618 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter MediaStreamTrack */ + + + /* Parameter pVal */ + +/* 1620 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1622 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1624 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + +/* 1626 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1628 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1630 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_onaddstream */ + +/* 1632 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1634 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1638 */ NdrFcShort( 0x20 ), /* 32 */ +/* 1640 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 1642 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1644 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1646 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1648 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1650 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1652 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1654 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 1656 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1658 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1660 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 1662 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1664 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1666 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_onremovestream */ + +/* 1668 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1670 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1674 */ NdrFcShort( 0x21 ), /* 33 */ +/* 1676 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1678 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1680 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1682 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1684 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1686 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1688 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1690 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 1692 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1694 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1696 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 1698 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1700 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1702 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_onremovestream */ + +/* 1704 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1706 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1710 */ NdrFcShort( 0x22 ), /* 34 */ +/* 1712 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 1714 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1716 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1718 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1720 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1722 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1724 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1726 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 1728 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1730 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1732 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 1734 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1736 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1738 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_oniceconnectionstatechange */ + +/* 1740 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1742 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1746 */ NdrFcShort( 0x23 ), /* 35 */ +/* 1748 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1750 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1752 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1754 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1756 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1758 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1760 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1762 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 1764 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1766 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1768 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 1770 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1772 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1774 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_oniceconnectionstatechange */ + +/* 1776 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1778 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1782 */ NdrFcShort( 0x24 ), /* 36 */ +/* 1784 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 1786 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1788 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1790 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1792 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1794 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1796 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1798 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 1800 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1802 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1804 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 1806 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1808 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1810 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure getAudioTracks */ + +/* 1812 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1814 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1818 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1820 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1822 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1824 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1826 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1828 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1830 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1832 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1834 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter Tracks */ + +/* 1836 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1838 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1840 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 1842 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1844 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1846 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_width */ + + + /* Procedure getVideoTracks */ + +/* 1848 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1850 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1854 */ NdrFcShort( 0x9 ), /* 9 */ +/* 1856 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1858 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1860 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1862 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1864 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 1866 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1868 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1870 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + + + /* Parameter Tracks */ + +/* 1872 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1874 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1876 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + +/* 1878 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1880 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1882 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure getTrackById */ + +/* 1884 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1886 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1890 */ NdrFcShort( 0xa ), /* 10 */ +/* 1892 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */ +/* 1894 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1896 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1898 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */ + 0x3, /* 3 */ +/* 1900 */ 0x8, /* 8 */ + 0x7, /* Ext Flags: new corr desc, clt corr check, srv corr check, */ +/* 1902 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1904 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1906 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter trackId */ + +/* 1908 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1910 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1912 */ NdrFcShort( 0x420 ), /* Type Offset=1056 */ + + /* Parameter MediaStreamTrack */ + +/* 1914 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 1916 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 1918 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 1920 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1922 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 1924 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure addTrack */ + +/* 1926 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1928 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1932 */ NdrFcShort( 0xb ), /* 11 */ +/* 1934 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 1936 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1938 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1940 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1942 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1944 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1946 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1948 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter MediaStreamTrack */ + +/* 1950 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1952 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1954 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 1956 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1958 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1960 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure removeTrack */ + +/* 1962 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 1964 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1968 */ NdrFcShort( 0xc ), /* 12 */ +/* 1970 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 1972 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1974 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1976 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 1978 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 1980 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1982 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1984 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter MediaStreamTrack */ + +/* 1986 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 1988 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 1990 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 1992 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 1994 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 1996 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_facingMode */ + + + /* Procedure get_onmute */ + + + /* Procedure clone */ + +/* 1998 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2000 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2004 */ NdrFcShort( 0xd ), /* 13 */ +/* 2006 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2008 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2010 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2012 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2014 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2016 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2018 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2020 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter MediaStream */ + +/* 2022 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 2024 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2026 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + +/* 2028 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2030 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2032 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_ended */ + +/* 2034 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2036 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2040 */ NdrFcShort( 0xe ), /* 14 */ +/* 2042 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2044 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2046 */ NdrFcShort( 0x22 ), /* 34 */ +/* 2048 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 2050 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 2052 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2054 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2056 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2058 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 2060 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2062 */ 0x6, /* FC_SHORT */ + 0x0, /* 0 */ + + /* Return value */ + +/* 2064 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2066 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2068 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_onunmute */ + + + /* Procedure get_onended */ + +/* 2070 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2072 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2076 */ NdrFcShort( 0xf ), /* 15 */ +/* 2078 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2080 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2082 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2084 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2086 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2088 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2090 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2092 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + + + /* Parameter pVal */ + +/* 2094 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 2096 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2098 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + +/* 2100 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2102 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2104 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_onaddtrack */ + +/* 2106 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2108 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2112 */ NdrFcShort( 0x11 ), /* 17 */ +/* 2114 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2116 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2118 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2120 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2122 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2124 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2126 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2128 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2130 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 2132 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2134 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 2136 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2138 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2140 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_onaddtrack */ + +/* 2142 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2144 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2148 */ NdrFcShort( 0x12 ), /* 18 */ +/* 2150 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 2152 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2154 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2156 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2158 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 2160 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2162 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2164 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 2166 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 2168 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2170 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 2172 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2174 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 2176 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure stop */ + +/* 2178 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2180 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2184 */ NdrFcShort( 0x15 ), /* 21 */ +/* 2186 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2188 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2190 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2192 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x1, /* 1 */ +/* 2194 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 2196 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2198 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2200 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Return value */ + +/* 2202 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2204 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2206 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_type */ + + + /* Procedure get_sourceId */ + + + /* Procedure get_id */ + + + /* Procedure get_id */ + + + /* Procedure get_sdpMid */ + +/* 2208 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2210 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2214 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2216 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2218 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2220 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2222 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2224 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2226 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2228 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2230 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + +/* 2232 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 2234 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2236 */ NdrFcShort( 0x20 ), /* Type Offset=32 */ + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + +/* 2238 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2240 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2242 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_sdpMLineIndex */ + +/* 2244 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2246 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2250 */ NdrFcShort( 0x9 ), /* 9 */ +/* 2252 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2254 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2256 */ NdrFcShort( 0x22 ), /* 34 */ +/* 2258 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 2260 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 2262 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2264 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2266 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2268 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 2270 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2272 */ 0x6, /* FC_SHORT */ + 0x0, /* 0 */ + + /* Return value */ + +/* 2274 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2276 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2278 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_enabled */ + +/* 2280 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2282 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2286 */ NdrFcShort( 0xa ), /* 10 */ +/* 2288 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2290 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2292 */ NdrFcShort( 0x22 ), /* 34 */ +/* 2294 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 2296 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 2298 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2300 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2302 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2304 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 2306 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2308 */ 0x6, /* FC_SHORT */ + 0x0, /* 0 */ + + /* Return value */ + +/* 2310 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2312 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2314 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_enabled */ + +/* 2316 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2318 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2322 */ NdrFcShort( 0xb ), /* 11 */ +/* 2324 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2326 */ NdrFcShort( 0x6 ), /* 6 */ +/* 2328 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2330 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 2332 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 2334 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2336 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2338 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 2340 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 2342 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2344 */ 0x6, /* FC_SHORT */ + 0x0, /* 0 */ + + /* Return value */ + +/* 2346 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2348 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2350 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_muted */ + +/* 2352 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2354 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2358 */ NdrFcShort( 0xc ), /* 12 */ +/* 2360 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2362 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2364 */ NdrFcShort( 0x22 ), /* 34 */ +/* 2366 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 2368 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 2370 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2372 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2374 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2376 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 2378 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2380 */ 0x6, /* FC_SHORT */ + 0x0, /* 0 */ + + /* Return value */ + +/* 2382 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2384 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2386 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_onmute */ + +/* 2388 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2390 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2394 */ NdrFcShort( 0xe ), /* 14 */ +/* 2396 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 2398 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2400 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2402 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2404 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 2406 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2408 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2410 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 2412 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 2414 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2416 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 2418 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2420 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 2422 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_readonly */ + +/* 2424 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2426 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2430 */ NdrFcShort( 0x11 ), /* 17 */ +/* 2432 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2434 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2436 */ NdrFcShort( 0x22 ), /* 34 */ +/* 2438 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 2440 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 2442 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2444 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2446 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2448 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 2450 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2452 */ 0x6, /* FC_SHORT */ + 0x0, /* 0 */ + + /* Return value */ + +/* 2454 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2456 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2458 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_remote */ + +/* 2460 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2462 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2466 */ NdrFcShort( 0x12 ), /* 18 */ +/* 2468 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2470 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2472 */ NdrFcShort( 0x22 ), /* 34 */ +/* 2474 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 2476 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 2478 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2480 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2482 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2484 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 2486 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2488 */ 0x6, /* FC_SHORT */ + 0x0, /* 0 */ + + /* Return value */ + +/* 2490 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2492 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2494 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_readyState */ + +/* 2496 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2498 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2502 */ NdrFcShort( 0x13 ), /* 19 */ +/* 2504 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2506 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2508 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2510 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2512 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2514 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2516 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2518 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2520 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 2522 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2524 */ NdrFcShort( 0x20 ), /* Type Offset=32 */ + + /* Return value */ + +/* 2526 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2528 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2530 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_onstarted */ + +/* 2532 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2534 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2538 */ NdrFcShort( 0x14 ), /* 20 */ +/* 2540 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2542 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2544 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2546 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2548 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2550 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2552 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2554 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2556 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 2558 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2560 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 2562 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2564 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2566 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_onstarted */ + +/* 2568 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2570 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2574 */ NdrFcShort( 0x15 ), /* 21 */ +/* 2576 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 2578 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2580 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2582 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2584 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 2586 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2588 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2590 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 2592 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 2594 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2596 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 2598 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2600 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 2602 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_onended */ + +/* 2604 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2606 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2610 */ NdrFcShort( 0x16 ), /* 22 */ +/* 2612 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2614 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2616 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2618 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2620 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2622 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2624 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2626 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2628 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 2630 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2632 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 2634 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2636 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2638 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure put_onended */ + +/* 2640 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2642 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2646 */ NdrFcShort( 0x17 ), /* 23 */ +/* 2648 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 2650 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2652 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2654 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2656 */ 0x8, /* 8 */ + 0x5, /* Ext Flags: new corr desc, srv corr check, */ +/* 2658 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2660 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2662 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter newVal */ + +/* 2664 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 2666 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2668 */ NdrFcShort( 0x412 ), /* Type Offset=1042 */ + + /* Return value */ + +/* 2670 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2672 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 2674 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure getSourceInfos */ + +/* 2676 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2678 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2682 */ NdrFcShort( 0x18 ), /* 24 */ +/* 2684 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2686 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2688 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2690 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2692 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2694 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2696 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2698 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter Infos */ + +/* 2700 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 2702 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2704 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 2706 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2708 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2710 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure states */ + +/* 2712 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2714 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2718 */ NdrFcShort( 0x1a ), /* 26 */ +/* 2720 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2722 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2724 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2726 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2728 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2730 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2732 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2734 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter MediaSourceStates */ + +/* 2736 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 2738 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2740 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 2742 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2744 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2746 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure stop */ + +/* 2748 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2750 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2754 */ NdrFcShort( 0x20 ), /* 32 */ +/* 2756 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2758 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2760 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2762 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x1, /* 1 */ +/* 2764 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 2766 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2768 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2770 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Return value */ + +/* 2772 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2774 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2776 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_label */ + +/* 2778 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2780 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2784 */ NdrFcShort( 0xa ), /* 10 */ +/* 2786 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2788 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2790 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2792 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2794 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2796 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2798 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2800 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2802 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 2804 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2806 */ NdrFcShort( 0x20 ), /* Type Offset=32 */ + + /* Return value */ + +/* 2808 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2810 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2812 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_facing */ + +/* 2814 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2816 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2820 */ NdrFcShort( 0xb ), /* 11 */ +/* 2822 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2824 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2826 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2828 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2830 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2832 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2834 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2836 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2838 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 2840 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2842 */ NdrFcShort( 0x20 ), /* Type Offset=32 */ + + /* Return value */ + +/* 2844 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2846 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2848 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_frameRate */ + +/* 2850 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2852 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2856 */ NdrFcShort( 0xb ), /* 11 */ +/* 2858 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2860 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2862 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2864 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2866 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2868 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2870 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2872 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2874 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 2876 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2878 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 2880 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2882 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2884 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_volume */ + +/* 2886 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2888 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2892 */ NdrFcShort( 0xe ), /* 14 */ +/* 2894 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2896 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2898 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2900 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2902 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2904 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2906 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2908 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2910 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 2912 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2914 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + +/* 2916 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2918 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2920 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure result */ + + + /* Procedure get_candidate */ + + + /* Procedure get_stream */ + +/* 2922 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2924 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2928 */ NdrFcShort( 0x7 ), /* 7 */ +/* 2930 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2932 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2934 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2936 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x2, /* 2 */ +/* 2938 */ 0x8, /* 8 */ + 0x3, /* Ext Flags: new corr desc, clt corr check, */ +/* 2940 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2942 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2944 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter RTCStatsList */ + + + /* Parameter pVal */ + + + /* Parameter pVal */ + +/* 2946 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */ +/* 2948 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2950 */ NdrFcShort( 0x43a ), /* Type Offset=1082 */ + + /* Return value */ + + + /* Return value */ + + + /* Return value */ + +/* 2952 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2954 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2956 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure get_timestamp */ + +/* 2958 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2960 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2964 */ NdrFcShort( 0x7 ), /* 7 */ +/* 2966 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2968 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2970 */ NdrFcShort( 0x2c ), /* 44 */ +/* 2972 */ 0x44, /* Oi2 Flags: has return, has ext, */ + 0x2, /* 2 */ +/* 2974 */ 0x8, /* 8 */ + 0x1, /* Ext Flags: new corr desc, */ +/* 2976 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2978 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2980 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pVal */ + +/* 2982 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 2984 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2986 */ 0xc, /* FC_DOUBLE */ + 0x0, /* 0 */ + + /* Return value */ + +/* 2988 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2990 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2992 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure stat */ + +/* 2994 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2996 */ NdrFcLong( 0x0 ), /* 0 */ +/* 3000 */ NdrFcShort( 0xb ), /* 11 */ +/* 3002 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */ +/* 3004 */ NdrFcShort( 0x0 ), /* 0 */ +/* 3006 */ NdrFcShort( 0x8 ), /* 8 */ +/* 3008 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */ + 0x3, /* 3 */ +/* 3010 */ 0x8, /* 8 */ + 0x7, /* Ext Flags: new corr desc, clt corr check, srv corr check, */ +/* 3012 */ NdrFcShort( 0x1 ), /* 1 */ +/* 3014 */ NdrFcShort( 0x1 ), /* 1 */ +/* 3016 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter name */ + +/* 3018 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 3020 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 3022 */ NdrFcShort( 0x420 ), /* Type Offset=1056 */ + + /* Parameter pVal */ + +/* 3024 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 3026 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 3028 */ NdrFcShort( 0x20 ), /* Type Offset=32 */ + + /* Return value */ + +/* 3030 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 3032 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 3034 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + 0x0 + } + }; + +static const webrtceverywhere_MIDL_TYPE_FORMAT_STRING webrtceverywhere__MIDL_TypeFormatString = + { + 0, + { + NdrFcShort( 0x0 ), /* 0 */ +/* 2 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 4 */ NdrFcShort( 0x1c ), /* Offset= 28 (32) */ +/* 6 */ + 0x13, 0x0, /* FC_OP */ +/* 8 */ NdrFcShort( 0xe ), /* Offset= 14 (22) */ +/* 10 */ + 0x1b, /* FC_CARRAY */ + 0x1, /* 1 */ +/* 12 */ NdrFcShort( 0x2 ), /* 2 */ +/* 14 */ 0x9, /* Corr desc: FC_ULONG */ + 0x0, /* */ +/* 16 */ NdrFcShort( 0xfffc ), /* -4 */ +/* 18 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 20 */ 0x6, /* FC_SHORT */ + 0x5b, /* FC_END */ +/* 22 */ + 0x17, /* FC_CSTRUCT */ + 0x3, /* 3 */ +/* 24 */ NdrFcShort( 0x8 ), /* 8 */ +/* 26 */ NdrFcShort( 0xfff0 ), /* Offset= -16 (10) */ +/* 28 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 30 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 32 */ 0xb4, /* FC_USER_MARSHAL */ + 0x83, /* 131 */ +/* 34 */ NdrFcShort( 0x0 ), /* 0 */ +/* 36 */ NdrFcShort( 0x4 ), /* 4 */ +/* 38 */ NdrFcShort( 0x0 ), /* 0 */ +/* 40 */ NdrFcShort( 0xffde ), /* Offset= -34 (6) */ +/* 42 */ + 0x12, 0x0, /* FC_UP */ +/* 44 */ NdrFcShort( 0x3d2 ), /* Offset= 978 (1022) */ +/* 46 */ + 0x2b, /* FC_NON_ENCAPSULATED_UNION */ + 0x9, /* FC_ULONG */ +/* 48 */ 0x7, /* Corr desc: FC_USHORT */ + 0x0, /* */ +/* 50 */ NdrFcShort( 0xfff8 ), /* -8 */ +/* 52 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 54 */ NdrFcShort( 0x2 ), /* Offset= 2 (56) */ +/* 56 */ NdrFcShort( 0x10 ), /* 16 */ +/* 58 */ NdrFcShort( 0x2f ), /* 47 */ +/* 60 */ NdrFcLong( 0x14 ), /* 20 */ +/* 64 */ NdrFcShort( 0x800b ), /* Simple arm type: FC_HYPER */ +/* 66 */ NdrFcLong( 0x3 ), /* 3 */ +/* 70 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 72 */ NdrFcLong( 0x11 ), /* 17 */ +/* 76 */ NdrFcShort( 0x8001 ), /* Simple arm type: FC_BYTE */ +/* 78 */ NdrFcLong( 0x2 ), /* 2 */ +/* 82 */ NdrFcShort( 0x8006 ), /* Simple arm type: FC_SHORT */ +/* 84 */ NdrFcLong( 0x4 ), /* 4 */ +/* 88 */ NdrFcShort( 0x800a ), /* Simple arm type: FC_FLOAT */ +/* 90 */ NdrFcLong( 0x5 ), /* 5 */ +/* 94 */ NdrFcShort( 0x800c ), /* Simple arm type: FC_DOUBLE */ +/* 96 */ NdrFcLong( 0xb ), /* 11 */ +/* 100 */ NdrFcShort( 0x8006 ), /* Simple arm type: FC_SHORT */ +/* 102 */ NdrFcLong( 0xa ), /* 10 */ +/* 106 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 108 */ NdrFcLong( 0x6 ), /* 6 */ +/* 112 */ NdrFcShort( 0xe8 ), /* Offset= 232 (344) */ +/* 114 */ NdrFcLong( 0x7 ), /* 7 */ +/* 118 */ NdrFcShort( 0x800c ), /* Simple arm type: FC_DOUBLE */ +/* 120 */ NdrFcLong( 0x8 ), /* 8 */ +/* 124 */ NdrFcShort( 0xe2 ), /* Offset= 226 (350) */ +/* 126 */ NdrFcLong( 0xd ), /* 13 */ +/* 130 */ NdrFcShort( 0xe0 ), /* Offset= 224 (354) */ +/* 132 */ NdrFcLong( 0x9 ), /* 9 */ +/* 136 */ NdrFcShort( 0xec ), /* Offset= 236 (372) */ +/* 138 */ NdrFcLong( 0x2000 ), /* 8192 */ +/* 142 */ NdrFcShort( 0xf8 ), /* Offset= 248 (390) */ +/* 144 */ NdrFcLong( 0x24 ), /* 36 */ +/* 148 */ NdrFcShort( 0x320 ), /* Offset= 800 (948) */ +/* 150 */ NdrFcLong( 0x4024 ), /* 16420 */ +/* 154 */ NdrFcShort( 0x31a ), /* Offset= 794 (948) */ +/* 156 */ NdrFcLong( 0x4011 ), /* 16401 */ +/* 160 */ NdrFcShort( 0x318 ), /* Offset= 792 (952) */ +/* 162 */ NdrFcLong( 0x4002 ), /* 16386 */ +/* 166 */ NdrFcShort( 0x316 ), /* Offset= 790 (956) */ +/* 168 */ NdrFcLong( 0x4003 ), /* 16387 */ +/* 172 */ NdrFcShort( 0x314 ), /* Offset= 788 (960) */ +/* 174 */ NdrFcLong( 0x4014 ), /* 16404 */ +/* 178 */ NdrFcShort( 0x312 ), /* Offset= 786 (964) */ +/* 180 */ NdrFcLong( 0x4004 ), /* 16388 */ +/* 184 */ NdrFcShort( 0x310 ), /* Offset= 784 (968) */ +/* 186 */ NdrFcLong( 0x4005 ), /* 16389 */ +/* 190 */ NdrFcShort( 0x30e ), /* Offset= 782 (972) */ +/* 192 */ NdrFcLong( 0x400b ), /* 16395 */ +/* 196 */ NdrFcShort( 0x2f8 ), /* Offset= 760 (956) */ +/* 198 */ NdrFcLong( 0x400a ), /* 16394 */ +/* 202 */ NdrFcShort( 0x2f6 ), /* Offset= 758 (960) */ +/* 204 */ NdrFcLong( 0x4006 ), /* 16390 */ +/* 208 */ NdrFcShort( 0x300 ), /* Offset= 768 (976) */ +/* 210 */ NdrFcLong( 0x4007 ), /* 16391 */ +/* 214 */ NdrFcShort( 0x2f6 ), /* Offset= 758 (972) */ +/* 216 */ NdrFcLong( 0x4008 ), /* 16392 */ +/* 220 */ NdrFcShort( 0x2f8 ), /* Offset= 760 (980) */ +/* 222 */ NdrFcLong( 0x400d ), /* 16397 */ +/* 226 */ NdrFcShort( 0x2f6 ), /* Offset= 758 (984) */ +/* 228 */ NdrFcLong( 0x4009 ), /* 16393 */ +/* 232 */ NdrFcShort( 0x2f4 ), /* Offset= 756 (988) */ +/* 234 */ NdrFcLong( 0x6000 ), /* 24576 */ +/* 238 */ NdrFcShort( 0x2f2 ), /* Offset= 754 (992) */ +/* 240 */ NdrFcLong( 0x400c ), /* 16396 */ +/* 244 */ NdrFcShort( 0x2f0 ), /* Offset= 752 (996) */ +/* 246 */ NdrFcLong( 0x10 ), /* 16 */ +/* 250 */ NdrFcShort( 0x8002 ), /* Simple arm type: FC_CHAR */ +/* 252 */ NdrFcLong( 0x12 ), /* 18 */ +/* 256 */ NdrFcShort( 0x8006 ), /* Simple arm type: FC_SHORT */ +/* 258 */ NdrFcLong( 0x13 ), /* 19 */ +/* 262 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 264 */ NdrFcLong( 0x15 ), /* 21 */ +/* 268 */ NdrFcShort( 0x800b ), /* Simple arm type: FC_HYPER */ +/* 270 */ NdrFcLong( 0x16 ), /* 22 */ +/* 274 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 276 */ NdrFcLong( 0x17 ), /* 23 */ +/* 280 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 282 */ NdrFcLong( 0xe ), /* 14 */ +/* 286 */ NdrFcShort( 0x2ce ), /* Offset= 718 (1004) */ +/* 288 */ NdrFcLong( 0x400e ), /* 16398 */ +/* 292 */ NdrFcShort( 0x2d2 ), /* Offset= 722 (1014) */ +/* 294 */ NdrFcLong( 0x4010 ), /* 16400 */ +/* 298 */ NdrFcShort( 0x2d0 ), /* Offset= 720 (1018) */ +/* 300 */ NdrFcLong( 0x4012 ), /* 16402 */ +/* 304 */ NdrFcShort( 0x28c ), /* Offset= 652 (956) */ +/* 306 */ NdrFcLong( 0x4013 ), /* 16403 */ +/* 310 */ NdrFcShort( 0x28a ), /* Offset= 650 (960) */ +/* 312 */ NdrFcLong( 0x4015 ), /* 16405 */ +/* 316 */ NdrFcShort( 0x288 ), /* Offset= 648 (964) */ +/* 318 */ NdrFcLong( 0x4016 ), /* 16406 */ +/* 322 */ NdrFcShort( 0x27e ), /* Offset= 638 (960) */ +/* 324 */ NdrFcLong( 0x4017 ), /* 16407 */ +/* 328 */ NdrFcShort( 0x278 ), /* Offset= 632 (960) */ +/* 330 */ NdrFcLong( 0x0 ), /* 0 */ +/* 334 */ NdrFcShort( 0x0 ), /* Offset= 0 (334) */ +/* 336 */ NdrFcLong( 0x1 ), /* 1 */ +/* 340 */ NdrFcShort( 0x0 ), /* Offset= 0 (340) */ +/* 342 */ NdrFcShort( 0xffff ), /* Offset= -1 (341) */ +/* 344 */ + 0x15, /* FC_STRUCT */ + 0x7, /* 7 */ +/* 346 */ NdrFcShort( 0x8 ), /* 8 */ +/* 348 */ 0xb, /* FC_HYPER */ + 0x5b, /* FC_END */ +/* 350 */ + 0x12, 0x0, /* FC_UP */ +/* 352 */ NdrFcShort( 0xfeb6 ), /* Offset= -330 (22) */ +/* 354 */ + 0x2f, /* FC_IP */ + 0x5a, /* FC_CONSTANT_IID */ +/* 356 */ NdrFcLong( 0x0 ), /* 0 */ +/* 360 */ NdrFcShort( 0x0 ), /* 0 */ +/* 362 */ NdrFcShort( 0x0 ), /* 0 */ +/* 364 */ 0xc0, /* 192 */ + 0x0, /* 0 */ +/* 366 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 368 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 370 */ 0x0, /* 0 */ + 0x46, /* 70 */ +/* 372 */ + 0x2f, /* FC_IP */ + 0x5a, /* FC_CONSTANT_IID */ +/* 374 */ NdrFcLong( 0x20400 ), /* 132096 */ +/* 378 */ NdrFcShort( 0x0 ), /* 0 */ +/* 380 */ NdrFcShort( 0x0 ), /* 0 */ +/* 382 */ 0xc0, /* 192 */ + 0x0, /* 0 */ +/* 384 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 386 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 388 */ 0x0, /* 0 */ + 0x46, /* 70 */ +/* 390 */ + 0x12, 0x10, /* FC_UP [pointer_deref] */ +/* 392 */ NdrFcShort( 0x2 ), /* Offset= 2 (394) */ +/* 394 */ + 0x12, 0x0, /* FC_UP */ +/* 396 */ NdrFcShort( 0x216 ), /* Offset= 534 (930) */ +/* 398 */ + 0x2a, /* FC_ENCAPSULATED_UNION */ + 0x49, /* 73 */ +/* 400 */ NdrFcShort( 0x18 ), /* 24 */ +/* 402 */ NdrFcShort( 0xa ), /* 10 */ +/* 404 */ NdrFcLong( 0x8 ), /* 8 */ +/* 408 */ NdrFcShort( 0x5a ), /* Offset= 90 (498) */ +/* 410 */ NdrFcLong( 0xd ), /* 13 */ +/* 414 */ NdrFcShort( 0x7e ), /* Offset= 126 (540) */ +/* 416 */ NdrFcLong( 0x9 ), /* 9 */ +/* 420 */ NdrFcShort( 0x9e ), /* Offset= 158 (578) */ +/* 422 */ NdrFcLong( 0xc ), /* 12 */ +/* 426 */ NdrFcShort( 0xc8 ), /* Offset= 200 (626) */ +/* 428 */ NdrFcLong( 0x24 ), /* 36 */ +/* 432 */ NdrFcShort( 0x124 ), /* Offset= 292 (724) */ +/* 434 */ NdrFcLong( 0x800d ), /* 32781 */ +/* 438 */ NdrFcShort( 0x140 ), /* Offset= 320 (758) */ +/* 440 */ NdrFcLong( 0x10 ), /* 16 */ +/* 444 */ NdrFcShort( 0x15a ), /* Offset= 346 (790) */ +/* 446 */ NdrFcLong( 0x2 ), /* 2 */ +/* 450 */ NdrFcShort( 0x174 ), /* Offset= 372 (822) */ +/* 452 */ NdrFcLong( 0x3 ), /* 3 */ +/* 456 */ NdrFcShort( 0x18e ), /* Offset= 398 (854) */ +/* 458 */ NdrFcLong( 0x14 ), /* 20 */ +/* 462 */ NdrFcShort( 0x1a8 ), /* Offset= 424 (886) */ +/* 464 */ NdrFcShort( 0xffff ), /* Offset= -1 (463) */ +/* 466 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 468 */ NdrFcShort( 0x4 ), /* 4 */ +/* 470 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 472 */ NdrFcShort( 0x0 ), /* 0 */ +/* 474 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 476 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 478 */ + 0x48, /* FC_VARIABLE_REPEAT */ + 0x49, /* FC_FIXED_OFFSET */ +/* 480 */ NdrFcShort( 0x4 ), /* 4 */ +/* 482 */ NdrFcShort( 0x0 ), /* 0 */ +/* 484 */ NdrFcShort( 0x1 ), /* 1 */ +/* 486 */ NdrFcShort( 0x0 ), /* 0 */ +/* 488 */ NdrFcShort( 0x0 ), /* 0 */ +/* 490 */ 0x12, 0x0, /* FC_UP */ +/* 492 */ NdrFcShort( 0xfe2a ), /* Offset= -470 (22) */ +/* 494 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 496 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 498 */ + 0x16, /* FC_PSTRUCT */ + 0x3, /* 3 */ +/* 500 */ NdrFcShort( 0x8 ), /* 8 */ +/* 502 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 504 */ + 0x46, /* FC_NO_REPEAT */ + 0x5c, /* FC_PAD */ +/* 506 */ NdrFcShort( 0x4 ), /* 4 */ +/* 508 */ NdrFcShort( 0x4 ), /* 4 */ +/* 510 */ 0x11, 0x0, /* FC_RP */ +/* 512 */ NdrFcShort( 0xffd2 ), /* Offset= -46 (466) */ +/* 514 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 516 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 518 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 520 */ NdrFcShort( 0x0 ), /* 0 */ +/* 522 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 524 */ NdrFcShort( 0x0 ), /* 0 */ +/* 526 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 528 */ NdrFcLong( 0xffffffff ), /* -1 */ +/* 532 */ NdrFcShort( 0x0 ), /* Corr flags: */ +/* 534 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 536 */ NdrFcShort( 0xff4a ), /* Offset= -182 (354) */ +/* 538 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 540 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 542 */ NdrFcShort( 0x8 ), /* 8 */ +/* 544 */ NdrFcShort( 0x0 ), /* 0 */ +/* 546 */ NdrFcShort( 0x6 ), /* Offset= 6 (552) */ +/* 548 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 550 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 552 */ + 0x11, 0x0, /* FC_RP */ +/* 554 */ NdrFcShort( 0xffdc ), /* Offset= -36 (518) */ +/* 556 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 558 */ NdrFcShort( 0x0 ), /* 0 */ +/* 560 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 562 */ NdrFcShort( 0x0 ), /* 0 */ +/* 564 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 566 */ NdrFcLong( 0xffffffff ), /* -1 */ +/* 570 */ NdrFcShort( 0x0 ), /* Corr flags: */ +/* 572 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 574 */ NdrFcShort( 0xff36 ), /* Offset= -202 (372) */ +/* 576 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 578 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 580 */ NdrFcShort( 0x8 ), /* 8 */ +/* 582 */ NdrFcShort( 0x0 ), /* 0 */ +/* 584 */ NdrFcShort( 0x6 ), /* Offset= 6 (590) */ +/* 586 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 588 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 590 */ + 0x11, 0x0, /* FC_RP */ +/* 592 */ NdrFcShort( 0xffdc ), /* Offset= -36 (556) */ +/* 594 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 596 */ NdrFcShort( 0x4 ), /* 4 */ +/* 598 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 600 */ NdrFcShort( 0x0 ), /* 0 */ +/* 602 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 604 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 606 */ + 0x48, /* FC_VARIABLE_REPEAT */ + 0x49, /* FC_FIXED_OFFSET */ +/* 608 */ NdrFcShort( 0x4 ), /* 4 */ +/* 610 */ NdrFcShort( 0x0 ), /* 0 */ +/* 612 */ NdrFcShort( 0x1 ), /* 1 */ +/* 614 */ NdrFcShort( 0x0 ), /* 0 */ +/* 616 */ NdrFcShort( 0x0 ), /* 0 */ +/* 618 */ 0x12, 0x0, /* FC_UP */ +/* 620 */ NdrFcShort( 0x192 ), /* Offset= 402 (1022) */ +/* 622 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 624 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 626 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 628 */ NdrFcShort( 0x8 ), /* 8 */ +/* 630 */ NdrFcShort( 0x0 ), /* 0 */ +/* 632 */ NdrFcShort( 0x6 ), /* Offset= 6 (638) */ +/* 634 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 636 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 638 */ + 0x11, 0x0, /* FC_RP */ +/* 640 */ NdrFcShort( 0xffd2 ), /* Offset= -46 (594) */ +/* 642 */ + 0x2f, /* FC_IP */ + 0x5a, /* FC_CONSTANT_IID */ +/* 644 */ NdrFcLong( 0x2f ), /* 47 */ +/* 648 */ NdrFcShort( 0x0 ), /* 0 */ +/* 650 */ NdrFcShort( 0x0 ), /* 0 */ +/* 652 */ 0xc0, /* 192 */ + 0x0, /* 0 */ +/* 654 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 656 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 658 */ 0x0, /* 0 */ + 0x46, /* 70 */ +/* 660 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 662 */ NdrFcShort( 0x1 ), /* 1 */ +/* 664 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 666 */ NdrFcShort( 0x4 ), /* 4 */ +/* 668 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 670 */ 0x1, /* FC_BYTE */ + 0x5b, /* FC_END */ +/* 672 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 674 */ NdrFcShort( 0x10 ), /* 16 */ +/* 676 */ NdrFcShort( 0x0 ), /* 0 */ +/* 678 */ NdrFcShort( 0xa ), /* Offset= 10 (688) */ +/* 680 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 682 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 684 */ NdrFcShort( 0xffd6 ), /* Offset= -42 (642) */ +/* 686 */ 0x36, /* FC_POINTER */ + 0x5b, /* FC_END */ +/* 688 */ + 0x12, 0x0, /* FC_UP */ +/* 690 */ NdrFcShort( 0xffe2 ), /* Offset= -30 (660) */ +/* 692 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 694 */ NdrFcShort( 0x4 ), /* 4 */ +/* 696 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 698 */ NdrFcShort( 0x0 ), /* 0 */ +/* 700 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 702 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 704 */ + 0x48, /* FC_VARIABLE_REPEAT */ + 0x49, /* FC_FIXED_OFFSET */ +/* 706 */ NdrFcShort( 0x4 ), /* 4 */ +/* 708 */ NdrFcShort( 0x0 ), /* 0 */ +/* 710 */ NdrFcShort( 0x1 ), /* 1 */ +/* 712 */ NdrFcShort( 0x0 ), /* 0 */ +/* 714 */ NdrFcShort( 0x0 ), /* 0 */ +/* 716 */ 0x12, 0x0, /* FC_UP */ +/* 718 */ NdrFcShort( 0xffd2 ), /* Offset= -46 (672) */ +/* 720 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 722 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 724 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 726 */ NdrFcShort( 0x8 ), /* 8 */ +/* 728 */ NdrFcShort( 0x0 ), /* 0 */ +/* 730 */ NdrFcShort( 0x6 ), /* Offset= 6 (736) */ +/* 732 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 734 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 736 */ + 0x11, 0x0, /* FC_RP */ +/* 738 */ NdrFcShort( 0xffd2 ), /* Offset= -46 (692) */ +/* 740 */ + 0x1d, /* FC_SMFARRAY */ + 0x0, /* 0 */ +/* 742 */ NdrFcShort( 0x8 ), /* 8 */ +/* 744 */ 0x1, /* FC_BYTE */ + 0x5b, /* FC_END */ +/* 746 */ + 0x15, /* FC_STRUCT */ + 0x3, /* 3 */ +/* 748 */ NdrFcShort( 0x10 ), /* 16 */ +/* 750 */ 0x8, /* FC_LONG */ + 0x6, /* FC_SHORT */ +/* 752 */ 0x6, /* FC_SHORT */ + 0x4c, /* FC_EMBEDDED_COMPLEX */ +/* 754 */ 0x0, /* 0 */ + NdrFcShort( 0xfff1 ), /* Offset= -15 (740) */ + 0x5b, /* FC_END */ +/* 758 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 760 */ NdrFcShort( 0x18 ), /* 24 */ +/* 762 */ NdrFcShort( 0x0 ), /* 0 */ +/* 764 */ NdrFcShort( 0xa ), /* Offset= 10 (774) */ +/* 766 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 768 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 770 */ NdrFcShort( 0xffe8 ), /* Offset= -24 (746) */ +/* 772 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 774 */ + 0x11, 0x0, /* FC_RP */ +/* 776 */ NdrFcShort( 0xfefe ), /* Offset= -258 (518) */ +/* 778 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 780 */ NdrFcShort( 0x1 ), /* 1 */ +/* 782 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 784 */ NdrFcShort( 0x0 ), /* 0 */ +/* 786 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 788 */ 0x1, /* FC_BYTE */ + 0x5b, /* FC_END */ +/* 790 */ + 0x16, /* FC_PSTRUCT */ + 0x3, /* 3 */ +/* 792 */ NdrFcShort( 0x8 ), /* 8 */ +/* 794 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 796 */ + 0x46, /* FC_NO_REPEAT */ + 0x5c, /* FC_PAD */ +/* 798 */ NdrFcShort( 0x4 ), /* 4 */ +/* 800 */ NdrFcShort( 0x4 ), /* 4 */ +/* 802 */ 0x12, 0x0, /* FC_UP */ +/* 804 */ NdrFcShort( 0xffe6 ), /* Offset= -26 (778) */ +/* 806 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 808 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 810 */ + 0x1b, /* FC_CARRAY */ + 0x1, /* 1 */ +/* 812 */ NdrFcShort( 0x2 ), /* 2 */ +/* 814 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 816 */ NdrFcShort( 0x0 ), /* 0 */ +/* 818 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 820 */ 0x6, /* FC_SHORT */ + 0x5b, /* FC_END */ +/* 822 */ + 0x16, /* FC_PSTRUCT */ + 0x3, /* 3 */ +/* 824 */ NdrFcShort( 0x8 ), /* 8 */ +/* 826 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 828 */ + 0x46, /* FC_NO_REPEAT */ + 0x5c, /* FC_PAD */ +/* 830 */ NdrFcShort( 0x4 ), /* 4 */ +/* 832 */ NdrFcShort( 0x4 ), /* 4 */ +/* 834 */ 0x12, 0x0, /* FC_UP */ +/* 836 */ NdrFcShort( 0xffe6 ), /* Offset= -26 (810) */ +/* 838 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 840 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 842 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 844 */ NdrFcShort( 0x4 ), /* 4 */ +/* 846 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 848 */ NdrFcShort( 0x0 ), /* 0 */ +/* 850 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 852 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 854 */ + 0x16, /* FC_PSTRUCT */ + 0x3, /* 3 */ +/* 856 */ NdrFcShort( 0x8 ), /* 8 */ +/* 858 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 860 */ + 0x46, /* FC_NO_REPEAT */ + 0x5c, /* FC_PAD */ +/* 862 */ NdrFcShort( 0x4 ), /* 4 */ +/* 864 */ NdrFcShort( 0x4 ), /* 4 */ +/* 866 */ 0x12, 0x0, /* FC_UP */ +/* 868 */ NdrFcShort( 0xffe6 ), /* Offset= -26 (842) */ +/* 870 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 872 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 874 */ + 0x1b, /* FC_CARRAY */ + 0x7, /* 7 */ +/* 876 */ NdrFcShort( 0x8 ), /* 8 */ +/* 878 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 880 */ NdrFcShort( 0x0 ), /* 0 */ +/* 882 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 884 */ 0xb, /* FC_HYPER */ + 0x5b, /* FC_END */ +/* 886 */ + 0x16, /* FC_PSTRUCT */ + 0x3, /* 3 */ +/* 888 */ NdrFcShort( 0x8 ), /* 8 */ +/* 890 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 892 */ + 0x46, /* FC_NO_REPEAT */ + 0x5c, /* FC_PAD */ +/* 894 */ NdrFcShort( 0x4 ), /* 4 */ +/* 896 */ NdrFcShort( 0x4 ), /* 4 */ +/* 898 */ 0x12, 0x0, /* FC_UP */ +/* 900 */ NdrFcShort( 0xffe6 ), /* Offset= -26 (874) */ +/* 902 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 904 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 906 */ + 0x15, /* FC_STRUCT */ + 0x3, /* 3 */ +/* 908 */ NdrFcShort( 0x8 ), /* 8 */ +/* 910 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 912 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 914 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 916 */ NdrFcShort( 0x8 ), /* 8 */ +/* 918 */ 0x7, /* Corr desc: FC_USHORT */ + 0x0, /* */ +/* 920 */ NdrFcShort( 0xffd8 ), /* -40 */ +/* 922 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 924 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 926 */ NdrFcShort( 0xffec ), /* Offset= -20 (906) */ +/* 928 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 930 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 932 */ NdrFcShort( 0x28 ), /* 40 */ +/* 934 */ NdrFcShort( 0xffec ), /* Offset= -20 (914) */ +/* 936 */ NdrFcShort( 0x0 ), /* Offset= 0 (936) */ +/* 938 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 940 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 942 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 944 */ NdrFcShort( 0xfdde ), /* Offset= -546 (398) */ +/* 946 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 948 */ + 0x12, 0x0, /* FC_UP */ +/* 950 */ NdrFcShort( 0xfeea ), /* Offset= -278 (672) */ +/* 952 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 954 */ 0x1, /* FC_BYTE */ + 0x5c, /* FC_PAD */ +/* 956 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 958 */ 0x6, /* FC_SHORT */ + 0x5c, /* FC_PAD */ +/* 960 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 962 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 964 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 966 */ 0xb, /* FC_HYPER */ + 0x5c, /* FC_PAD */ +/* 968 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 970 */ 0xa, /* FC_FLOAT */ + 0x5c, /* FC_PAD */ +/* 972 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 974 */ 0xc, /* FC_DOUBLE */ + 0x5c, /* FC_PAD */ +/* 976 */ + 0x12, 0x0, /* FC_UP */ +/* 978 */ NdrFcShort( 0xfd86 ), /* Offset= -634 (344) */ +/* 980 */ + 0x12, 0x10, /* FC_UP [pointer_deref] */ +/* 982 */ NdrFcShort( 0xfd88 ), /* Offset= -632 (350) */ +/* 984 */ + 0x12, 0x10, /* FC_UP [pointer_deref] */ +/* 986 */ NdrFcShort( 0xfd88 ), /* Offset= -632 (354) */ +/* 988 */ + 0x12, 0x10, /* FC_UP [pointer_deref] */ +/* 990 */ NdrFcShort( 0xfd96 ), /* Offset= -618 (372) */ +/* 992 */ + 0x12, 0x10, /* FC_UP [pointer_deref] */ +/* 994 */ NdrFcShort( 0xfda4 ), /* Offset= -604 (390) */ +/* 996 */ + 0x12, 0x10, /* FC_UP [pointer_deref] */ +/* 998 */ NdrFcShort( 0x2 ), /* Offset= 2 (1000) */ +/* 1000 */ + 0x12, 0x0, /* FC_UP */ +/* 1002 */ NdrFcShort( 0x14 ), /* Offset= 20 (1022) */ +/* 1004 */ + 0x15, /* FC_STRUCT */ + 0x7, /* 7 */ +/* 1006 */ NdrFcShort( 0x10 ), /* 16 */ +/* 1008 */ 0x6, /* FC_SHORT */ + 0x1, /* FC_BYTE */ +/* 1010 */ 0x1, /* FC_BYTE */ + 0x8, /* FC_LONG */ +/* 1012 */ 0xb, /* FC_HYPER */ + 0x5b, /* FC_END */ +/* 1014 */ + 0x12, 0x0, /* FC_UP */ +/* 1016 */ NdrFcShort( 0xfff4 ), /* Offset= -12 (1004) */ +/* 1018 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 1020 */ 0x2, /* FC_CHAR */ + 0x5c, /* FC_PAD */ +/* 1022 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x7, /* 7 */ +/* 1024 */ NdrFcShort( 0x20 ), /* 32 */ +/* 1026 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1028 */ NdrFcShort( 0x0 ), /* Offset= 0 (1028) */ +/* 1030 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 1032 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1034 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1036 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1038 */ NdrFcShort( 0xfc20 ), /* Offset= -992 (46) */ +/* 1040 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1042 */ 0xb4, /* FC_USER_MARSHAL */ + 0x83, /* 131 */ +/* 1044 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1046 */ NdrFcShort( 0x10 ), /* 16 */ +/* 1048 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1050 */ NdrFcShort( 0xfc10 ), /* Offset= -1008 (42) */ +/* 1052 */ + 0x11, 0x10, /* FC_RP [pointer_deref] */ +/* 1054 */ NdrFcShort( 0xfd56 ), /* Offset= -682 (372) */ +/* 1056 */ 0xb4, /* FC_USER_MARSHAL */ + 0x83, /* 131 */ +/* 1058 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1060 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1062 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1064 */ NdrFcShort( 0xfd36 ), /* Offset= -714 (350) */ +/* 1066 */ + 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ +/* 1068 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 1070 */ + 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ +/* 1072 */ 0x6, /* FC_SHORT */ + 0x5c, /* FC_PAD */ +/* 1074 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1076 */ NdrFcShort( 0x6 ), /* Offset= 6 (1082) */ +/* 1078 */ + 0x13, 0x0, /* FC_OP */ +/* 1080 */ NdrFcShort( 0xffc6 ), /* Offset= -58 (1022) */ +/* 1082 */ 0xb4, /* FC_USER_MARSHAL */ + 0x83, /* 131 */ +/* 1084 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1086 */ NdrFcShort( 0x10 ), /* 16 */ +/* 1088 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1090 */ NdrFcShort( 0xfff4 ), /* Offset= -12 (1078) */ +/* 1092 */ + 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ +/* 1094 */ 0xc, /* FC_DOUBLE */ + 0x5c, /* FC_PAD */ + + 0x0 + } + }; + +static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[ WIRE_MARSHAL_TABLE_SIZE ] = + { + + { + BSTR_UserSize + ,BSTR_UserMarshal + ,BSTR_UserUnmarshal + ,BSTR_UserFree + }, + { + VARIANT_UserSize + ,VARIANT_UserMarshal + ,VARIANT_UserUnmarshal + ,VARIANT_UserFree + } + + }; + + + +/* Object interface: IUnknown, ver. 0.0, + GUID={0x00000000,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +/* Object interface: IDispatch, ver. 0.0, + GUID={0x00020400,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +/* Object interface: IWebRTC, ver. 0.0, + GUID={0x4994FB92,0xA5F5,0x4292,{0xAB,0x60,0x47,0x2A,0xA4,0x93,0x7C,0x9E}} */ + +#pragma code_seg(".orpc") +static const unsigned short IWebRTC_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 0, + 36, + 84, + 120, + 162, + 198, + 246, + 288, + 324, + 372, + 408, + 444, + 480, + 516, + 552 + }; + +static const MIDL_STUBLESS_PROXY_INFO IWebRTC_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IWebRTC_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IWebRTC_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IWebRTC_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(22) _IWebRTCProxyVtbl = +{ + &IWebRTC_ProxyInfo, + &IID_IWebRTC, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* IWebRTC::get_versionName */ , + (void *) (INT_PTR) -1 /* IWebRTC::getUserMedia */ , + (void *) (INT_PTR) -1 /* IWebRTC::createDisplay */ , + (void *) (INT_PTR) -1 /* IWebRTC::createSessionDescription */ , + (void *) (INT_PTR) -1 /* IWebRTC::createDictOptions */ , + (void *) (INT_PTR) -1 /* IWebRTC::createPeerConnection */ , + (void *) (INT_PTR) -1 /* IWebRTC::createIceCandidate */ , + (void *) (INT_PTR) -1 /* IWebRTC::createMediaStreamTrack */ , + (void *) (INT_PTR) -1 /* IWebRTC::bindEventListener */ , + (void *) (INT_PTR) -1 /* IWebRTC::getSources */ , + (void *) (INT_PTR) -1 /* IWebRTC::put_src */ , + (void *) (INT_PTR) -1 /* IWebRTC::get_videoWidth */ , + (void *) (INT_PTR) -1 /* IWebRTC::get_videoHeight */ , + (void *) (INT_PTR) -1 /* IWebRTC::fillImageData */ , + (void *) (INT_PTR) -1 /* IWebRTC::get_isWebRtcPlugin */ +}; + + +static const PRPC_STUB_FUNCTION IWebRTC_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2 +}; + +CInterfaceStubVtbl _IWebRTCStubVtbl = +{ + &IID_IWebRTC, + &IWebRTC_ServerInfo, + 22, + &IWebRTC_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: ISessionDescription, ver. 0.0, + GUID={0xE7CFEF92,0x42B8,0x40FB,{0xBC,0xA9,0xE7,0x9D,0x39,0xAB,0xCF,0x72}} */ + +#pragma code_seg(".orpc") +static const unsigned short ISessionDescription_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 0, + 588, + 624, + 660 + }; + +static const MIDL_STUBLESS_PROXY_INFO ISessionDescription_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &ISessionDescription_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO ISessionDescription_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &ISessionDescription_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(11) _ISessionDescriptionProxyVtbl = +{ + &ISessionDescription_ProxyInfo, + &IID_ISessionDescription, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* ISessionDescription::get_type */ , + (void *) (INT_PTR) -1 /* ISessionDescription::put_type */ , + (void *) (INT_PTR) -1 /* ISessionDescription::get_sdp */ , + (void *) (INT_PTR) -1 /* ISessionDescription::put_sdp */ +}; + + +static const PRPC_STUB_FUNCTION ISessionDescription_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2 +}; + +CInterfaceStubVtbl _ISessionDescriptionStubVtbl = +{ + &IID_ISessionDescription, + &ISessionDescription_ServerInfo, + 11, + &ISessionDescription_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: IDictOptions, ver. 0.0, + GUID={0xFA4B099C,0x3A15,0x4659,{0xB2,0x88,0x56,0x5A,0xD5,0x25,0x8D,0x4B}} */ + +#pragma code_seg(".orpc") +static const unsigned short IDictOptions_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 0 + }; + +static const MIDL_STUBLESS_PROXY_INFO IDictOptions_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IDictOptions_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IDictOptions_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IDictOptions_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(7) _IDictOptionsProxyVtbl = +{ + 0, + &IID_IDictOptions, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ +}; + + +static const PRPC_STUB_FUNCTION IDictOptions_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION +}; + +CInterfaceStubVtbl _IDictOptionsStubVtbl = +{ + &IID_IDictOptions, + &IDictOptions_ServerInfo, + 7, + &IDictOptions_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: IPeerConnection, ver. 0.0, + GUID={0x462E3805,0x373B,0x46EE,{0x9B,0xEE,0x43,0xE6,0x11,0x0C,0xB7,0x51}} */ + +#pragma code_seg(".orpc") +static const unsigned short IPeerConnection_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 696, + 36, + 744, + 792, + 828, + 876, + 912, + 948, + 990, + 1038, + 1074, + 1110, + 1146, + 1182, + 1224, + 1266, + 1302, + 1332, + 1380, + 1416, + 1452, + 1488, + 1524, + 1560, + 1596, + 1632, + 1668, + 1704, + 1740, + 1776 + }; + +static const MIDL_STUBLESS_PROXY_INFO IPeerConnection_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IPeerConnection_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IPeerConnection_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IPeerConnection_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(37) _IPeerConnectionProxyVtbl = +{ + &IPeerConnection_ProxyInfo, + &IID_IPeerConnection, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* IPeerConnection::createOffer */ , + (void *) (INT_PTR) -1 /* IPeerConnection::createAnswer */ , + (void *) (INT_PTR) -1 /* IPeerConnection::setLocalDescription */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_localDescription */ , + (void *) (INT_PTR) -1 /* IPeerConnection::setRemoteDescription */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_remoteDescription */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_signalingState */ , + (void *) (INT_PTR) -1 /* IPeerConnection::updateIce */ , + (void *) (INT_PTR) -1 /* IPeerConnection::addIceCandidate */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_iceGatheringState */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_iceConnectionState */ , + (void *) (INT_PTR) -1 /* IPeerConnection::getLocalStreams */ , + (void *) (INT_PTR) -1 /* IPeerConnection::getRemoteStreams */ , + (void *) (INT_PTR) -1 /* IPeerConnection::getStreamById */ , + (void *) (INT_PTR) -1 /* IPeerConnection::addStream */ , + (void *) (INT_PTR) -1 /* IPeerConnection::removeStream */ , + (void *) (INT_PTR) -1 /* IPeerConnection::close */ , + (void *) (INT_PTR) -1 /* IPeerConnection::getStats */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_onnegotiationneeded */ , + (void *) (INT_PTR) -1 /* IPeerConnection::put_onnegotiationneeded */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_onicecandidate */ , + (void *) (INT_PTR) -1 /* IPeerConnection::put_onicecandidate */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_onsignalingstatechange */ , + (void *) (INT_PTR) -1 /* IPeerConnection::put_onsignalingstatechange */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_onaddstream */ , + (void *) (INT_PTR) -1 /* IPeerConnection::put_onaddstream */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_onremovestream */ , + (void *) (INT_PTR) -1 /* IPeerConnection::put_onremovestream */ , + (void *) (INT_PTR) -1 /* IPeerConnection::get_oniceconnectionstatechange */ , + (void *) (INT_PTR) -1 /* IPeerConnection::put_oniceconnectionstatechange */ +}; + + +static const PRPC_STUB_FUNCTION IPeerConnection_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2 +}; + +CInterfaceStubVtbl _IPeerConnectionStubVtbl = +{ + &IID_IPeerConnection, + &IPeerConnection_ServerInfo, + 37, + &IPeerConnection_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: IMediaStream, ver. 0.0, + GUID={0x21745AC4,0x2C31,0x481C,{0xAB,0x07,0x83,0x4C,0x4D,0x0E,0x28,0x7A}} */ + +#pragma code_seg(".orpc") +static const unsigned short IMediaStream_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 0, + 1812, + 1848, + 1884, + 1926, + 1962, + 1998, + 2034, + 2070, + 372, + 2106, + 2142, + 1146, + 516, + 2178 + }; + +static const MIDL_STUBLESS_PROXY_INFO IMediaStream_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IMediaStream_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IMediaStream_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IMediaStream_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(22) _IMediaStreamProxyVtbl = +{ + &IMediaStream_ProxyInfo, + &IID_IMediaStream, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* IMediaStream::get_id */ , + (void *) (INT_PTR) -1 /* IMediaStream::getAudioTracks */ , + (void *) (INT_PTR) -1 /* IMediaStream::getVideoTracks */ , + (void *) (INT_PTR) -1 /* IMediaStream::getTrackById */ , + (void *) (INT_PTR) -1 /* IMediaStream::addTrack */ , + (void *) (INT_PTR) -1 /* IMediaStream::removeTrack */ , + (void *) (INT_PTR) -1 /* IMediaStream::clone */ , + (void *) (INT_PTR) -1 /* IMediaStream::get_ended */ , + (void *) (INT_PTR) -1 /* IMediaStream::get_onended */ , + (void *) (INT_PTR) -1 /* IMediaStream::put_onended */ , + (void *) (INT_PTR) -1 /* IMediaStream::get_onaddtrack */ , + (void *) (INT_PTR) -1 /* IMediaStream::put_onaddtrack */ , + (void *) (INT_PTR) -1 /* IMediaStream::get_onremovetrack */ , + (void *) (INT_PTR) -1 /* IMediaStream::put_onremovetrack */ , + (void *) (INT_PTR) -1 /* IMediaStream::stop */ +}; + + +static const PRPC_STUB_FUNCTION IMediaStream_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2 +}; + +CInterfaceStubVtbl _IMediaStreamStubVtbl = +{ + &IID_IMediaStream, + &IMediaStream_ServerInfo, + 22, + &IMediaStream_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: IRTCIceCandidate, ver. 0.0, + GUID={0xFBE8F87D,0xBD47,0x4325,{0x91,0x96,0x7A,0x36,0xF3,0x39,0xEE,0x2A}} */ + +#pragma code_seg(".orpc") +static const unsigned short IRTCIceCandidate_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 0, + 2208, + 2244 + }; + +static const MIDL_STUBLESS_PROXY_INFO IRTCIceCandidate_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IRTCIceCandidate_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IRTCIceCandidate_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IRTCIceCandidate_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(10) _IRTCIceCandidateProxyVtbl = +{ + &IRTCIceCandidate_ProxyInfo, + &IID_IRTCIceCandidate, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* IRTCIceCandidate::get_candidate */ , + (void *) (INT_PTR) -1 /* IRTCIceCandidate::get_sdpMid */ , + (void *) (INT_PTR) -1 /* IRTCIceCandidate::get_sdpMLineIndex */ +}; + + +static const PRPC_STUB_FUNCTION IRTCIceCandidate_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2 +}; + +CInterfaceStubVtbl _IRTCIceCandidateStubVtbl = +{ + &IID_IRTCIceCandidate, + &IRTCIceCandidate_ServerInfo, + 10, + &IRTCIceCandidate_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: IMediaStreamTrack, ver. 0.0, + GUID={0xEDD26AE0,0xB068,0x4918,{0x82,0x6D,0xE7,0x5B,0xBE,0x84,0x4B,0x71}} */ + +#pragma code_seg(".orpc") +static const unsigned short IMediaStreamTrack_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 0, + 2208, + 624, + 2280, + 2316, + 2352, + 1998, + 2388, + 2070, + 372, + 2424, + 2460, + 2496, + 2532, + 2568, + 2604, + 2640, + 2676, + 1380, + 2712, + 1452, + 1488, + 1524, + 1560, + 1596, + 2748 + }; + +static const MIDL_STUBLESS_PROXY_INFO IMediaStreamTrack_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IMediaStreamTrack_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IMediaStreamTrack_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IMediaStreamTrack_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(33) _IMediaStreamTrackProxyVtbl = +{ + &IMediaStreamTrack_ProxyInfo, + &IID_IMediaStreamTrack, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_kind */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_id */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_label */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_enabled */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::put_enabled */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_muted */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_onmute */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::put_onmute */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_onunmute */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::put_onunmute */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_readonly */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_remote */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_readyState */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_onstarted */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::put_onstarted */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_onended */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::put_onended */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::getSourceInfos */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::constraints */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::states */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::capabilities */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::applyConstraints */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::get_onoverconstrained */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::put_onoverconstrained */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::clone */ , + (void *) (INT_PTR) -1 /* IMediaStreamTrack::stop */ +}; + + +static const PRPC_STUB_FUNCTION IMediaStreamTrack_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2 +}; + +CInterfaceStubVtbl _IMediaStreamTrackStubVtbl = +{ + &IID_IMediaStreamTrack, + &IMediaStreamTrack_ServerInfo, + 33, + &IMediaStreamTrack_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: ISourceInfo, ver. 0.0, + GUID={0xBCD116DA,0xB4BC,0x472E,{0xA6,0xAE,0x36,0x3D,0x13,0xB7,0x86,0x67}} */ + +#pragma code_seg(".orpc") +static const unsigned short ISourceInfo_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 0, + 2208, + 624, + 2778, + 2814 + }; + +static const MIDL_STUBLESS_PROXY_INFO ISourceInfo_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &ISourceInfo_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO ISourceInfo_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &ISourceInfo_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(12) _ISourceInfoProxyVtbl = +{ + &ISourceInfo_ProxyInfo, + &IID_ISourceInfo, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* ISourceInfo::get_sourceId */ , + (void *) (INT_PTR) -1 /* ISourceInfo::get_id */ , + (void *) (INT_PTR) -1 /* ISourceInfo::get_kind */ , + (void *) (INT_PTR) -1 /* ISourceInfo::get_label */ , + (void *) (INT_PTR) -1 /* ISourceInfo::get_facing */ +}; + + +static const PRPC_STUB_FUNCTION ISourceInfo_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2 +}; + +CInterfaceStubVtbl _ISourceInfoStubVtbl = +{ + &IID_ISourceInfo, + &ISourceInfo_ServerInfo, + 12, + &ISourceInfo_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: IMediaSourceStates, ver. 0.0, + GUID={0x7A2B697F,0x688A,0x4CBE,{0xB3,0x6F,0x48,0x20,0xD1,0x2B,0xAE,0x61}} */ + +#pragma code_seg(".orpc") +static const unsigned short IMediaSourceStates_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 0, + 2208, + 1848, + 792, + 2850, + 876, + 1998, + 2886 + }; + +static const MIDL_STUBLESS_PROXY_INFO IMediaSourceStates_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IMediaSourceStates_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IMediaSourceStates_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IMediaSourceStates_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(15) _IMediaSourceStatesProxyVtbl = +{ + &IMediaSourceStates_ProxyInfo, + &IID_IMediaSourceStates, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* IMediaSourceStates::get_sourceType */ , + (void *) (INT_PTR) -1 /* IMediaSourceStates::get_sourceId */ , + (void *) (INT_PTR) -1 /* IMediaSourceStates::get_width */ , + (void *) (INT_PTR) -1 /* IMediaSourceStates::get_height */ , + (void *) (INT_PTR) -1 /* IMediaSourceStates::get_frameRate */ , + (void *) (INT_PTR) -1 /* IMediaSourceStates::get_aspectRatio */ , + (void *) (INT_PTR) -1 /* IMediaSourceStates::get_facingMode */ , + (void *) (INT_PTR) -1 /* IMediaSourceStates::get_volume */ +}; + + +static const PRPC_STUB_FUNCTION IMediaSourceStates_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2 +}; + +CInterfaceStubVtbl _IMediaSourceStatesStubVtbl = +{ + &IID_IMediaSourceStates, + &IMediaSourceStates_ServerInfo, + 15, + &IMediaSourceStates_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: IMediaStreamEvent, ver. 0.0, + GUID={0xEAB6AB59,0x5B8E,0x4096,{0xAA,0x67,0x0D,0x55,0x7A,0xA6,0xBB,0x32}} */ + +#pragma code_seg(".orpc") +static const unsigned short IMediaStreamEvent_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 2922 + }; + +static const MIDL_STUBLESS_PROXY_INFO IMediaStreamEvent_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IMediaStreamEvent_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IMediaStreamEvent_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IMediaStreamEvent_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(8) _IMediaStreamEventProxyVtbl = +{ + &IMediaStreamEvent_ProxyInfo, + &IID_IMediaStreamEvent, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* IMediaStreamEvent::get_stream */ +}; + + +static const PRPC_STUB_FUNCTION IMediaStreamEvent_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2 +}; + +CInterfaceStubVtbl _IMediaStreamEventStubVtbl = +{ + &IID_IMediaStreamEvent, + &IMediaStreamEvent_ServerInfo, + 8, + &IMediaStreamEvent_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: IRTCPeerConnectionIceEvent, ver. 0.0, + GUID={0x354C2E39,0x380F,0x4F24,{0xAE,0xEA,0x68,0x7E,0xB6,0x7F,0x75,0x9D}} */ + +#pragma code_seg(".orpc") +static const unsigned short IRTCPeerConnectionIceEvent_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 2922 + }; + +static const MIDL_STUBLESS_PROXY_INFO IRTCPeerConnectionIceEvent_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IRTCPeerConnectionIceEvent_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IRTCPeerConnectionIceEvent_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IRTCPeerConnectionIceEvent_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(8) _IRTCPeerConnectionIceEventProxyVtbl = +{ + &IRTCPeerConnectionIceEvent_ProxyInfo, + &IID_IRTCPeerConnectionIceEvent, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* IRTCPeerConnectionIceEvent::get_candidate */ +}; + + +static const PRPC_STUB_FUNCTION IRTCPeerConnectionIceEvent_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2 +}; + +CInterfaceStubVtbl _IRTCPeerConnectionIceEventStubVtbl = +{ + &IID_IRTCPeerConnectionIceEvent, + &IRTCPeerConnectionIceEvent_ServerInfo, + 8, + &IRTCPeerConnectionIceEvent_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: IRTCStatsReport, ver. 0.0, + GUID={0x455118D0,0xA29F,0x44DB,{0xAC,0xF7,0xFE,0x22,0xBF,0xAE,0x21,0x67}} */ + +#pragma code_seg(".orpc") +static const unsigned short IRTCStatsReport_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 2922 + }; + +static const MIDL_STUBLESS_PROXY_INFO IRTCStatsReport_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IRTCStatsReport_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IRTCStatsReport_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IRTCStatsReport_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(8) _IRTCStatsReportProxyVtbl = +{ + &IRTCStatsReport_ProxyInfo, + &IID_IRTCStatsReport, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* IRTCStatsReport::result */ +}; + + +static const PRPC_STUB_FUNCTION IRTCStatsReport_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2 +}; + +CInterfaceStubVtbl _IRTCStatsReportStubVtbl = +{ + &IID_IRTCStatsReport, + &IRTCStatsReport_ServerInfo, + 8, + &IRTCStatsReport_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + + +/* Object interface: IRTCStats, ver. 0.0, + GUID={0xCEFEB782,0xAFEC,0x4D0D,{0x8C,0x62,0xF1,0xE2,0x55,0xA7,0x38,0x41}} */ + +#pragma code_seg(".orpc") +static const unsigned short IRTCStats_FormatStringOffsetTable[] = + { + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + (unsigned short) -1, + 2958, + 2208, + 624, + 792, + 2994 + }; + +static const MIDL_STUBLESS_PROXY_INFO IRTCStats_ProxyInfo = + { + &Object_StubDesc, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IRTCStats_FormatStringOffsetTable[-3], + 0, + 0, + 0 + }; + + +static const MIDL_SERVER_INFO IRTCStats_ServerInfo = + { + &Object_StubDesc, + 0, + webrtceverywhere__MIDL_ProcFormatString.Format, + &IRTCStats_FormatStringOffsetTable[-3], + 0, + 0, + 0, + 0}; +CINTERFACE_PROXY_VTABLE(12) _IRTCStatsProxyVtbl = +{ + &IRTCStats_ProxyInfo, + &IID_IRTCStats, + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + 0 /* IDispatch::GetTypeInfoCount */ , + 0 /* IDispatch::GetTypeInfo */ , + 0 /* IDispatch::GetIDsOfNames */ , + 0 /* IDispatch_Invoke_Proxy */ , + (void *) (INT_PTR) -1 /* IRTCStats::get_timestamp */ , + (void *) (INT_PTR) -1 /* IRTCStats::get_type */ , + (void *) (INT_PTR) -1 /* IRTCStats::get_id */ , + (void *) (INT_PTR) -1 /* IRTCStats::names */ , + (void *) (INT_PTR) -1 /* IRTCStats::stat */ +}; + + +static const PRPC_STUB_FUNCTION IRTCStats_table[] = +{ + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + STUB_FORWARDING_FUNCTION, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2, + NdrStubCall2 +}; + +CInterfaceStubVtbl _IRTCStatsStubVtbl = +{ + &IID_IRTCStats, + &IRTCStats_ServerInfo, + 12, + &IRTCStats_table[-3], + CStdStubBuffer_DELEGATING_METHODS +}; + +static const MIDL_STUB_DESC Object_StubDesc = + { + 0, + NdrOleAllocate, + NdrOleFree, + 0, + 0, + 0, + 0, + 0, + webrtceverywhere__MIDL_TypeFormatString.Format, + 1, /* -error bounds_check flag */ + 0x50002, /* Ndr library version */ + 0, + 0x800025b, /* MIDL Version 8.0.603 */ + 0, + UserMarshalRoutines, + 0, /* notify & notify_flag routine table */ + 0x1, /* MIDL flag */ + 0, /* cs routines */ + 0, /* proxy/server info */ + 0 + }; + +const CInterfaceProxyVtbl * const _webrtceverywhere_ProxyVtblList[] = +{ + ( CInterfaceProxyVtbl *) &_IPeerConnectionProxyVtbl, + ( CInterfaceProxyVtbl *) &_IRTCPeerConnectionIceEventProxyVtbl, + ( CInterfaceProxyVtbl *) &_IMediaStreamEventProxyVtbl, + ( CInterfaceProxyVtbl *) &_IRTCIceCandidateProxyVtbl, + ( CInterfaceProxyVtbl *) &_IMediaSourceStatesProxyVtbl, + ( CInterfaceProxyVtbl *) &_IRTCStatsProxyVtbl, + ( CInterfaceProxyVtbl *) &_ISessionDescriptionProxyVtbl, + ( CInterfaceProxyVtbl *) &_IWebRTCProxyVtbl, + ( CInterfaceProxyVtbl *) &_IDictOptionsProxyVtbl, + ( CInterfaceProxyVtbl *) &_IMediaStreamProxyVtbl, + ( CInterfaceProxyVtbl *) &_IRTCStatsReportProxyVtbl, + ( CInterfaceProxyVtbl *) &_ISourceInfoProxyVtbl, + ( CInterfaceProxyVtbl *) &_IMediaStreamTrackProxyVtbl, + 0 +}; + +const CInterfaceStubVtbl * const _webrtceverywhere_StubVtblList[] = +{ + ( CInterfaceStubVtbl *) &_IPeerConnectionStubVtbl, + ( CInterfaceStubVtbl *) &_IRTCPeerConnectionIceEventStubVtbl, + ( CInterfaceStubVtbl *) &_IMediaStreamEventStubVtbl, + ( CInterfaceStubVtbl *) &_IRTCIceCandidateStubVtbl, + ( CInterfaceStubVtbl *) &_IMediaSourceStatesStubVtbl, + ( CInterfaceStubVtbl *) &_IRTCStatsStubVtbl, + ( CInterfaceStubVtbl *) &_ISessionDescriptionStubVtbl, + ( CInterfaceStubVtbl *) &_IWebRTCStubVtbl, + ( CInterfaceStubVtbl *) &_IDictOptionsStubVtbl, + ( CInterfaceStubVtbl *) &_IMediaStreamStubVtbl, + ( CInterfaceStubVtbl *) &_IRTCStatsReportStubVtbl, + ( CInterfaceStubVtbl *) &_ISourceInfoStubVtbl, + ( CInterfaceStubVtbl *) &_IMediaStreamTrackStubVtbl, + 0 +}; + +PCInterfaceName const _webrtceverywhere_InterfaceNamesList[] = +{ + "IPeerConnection", + "IRTCPeerConnectionIceEvent", + "IMediaStreamEvent", + "IRTCIceCandidate", + "IMediaSourceStates", + "IRTCStats", + "ISessionDescription", + "IWebRTC", + "IDictOptions", + "IMediaStream", + "IRTCStatsReport", + "ISourceInfo", + "IMediaStreamTrack", + 0 +}; + +const IID * const _webrtceverywhere_BaseIIDList[] = +{ + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + &IID_IDispatch, + 0 +}; + + +#define _webrtceverywhere_CHECK_IID(n) IID_GENERIC_CHECK_IID( _webrtceverywhere, pIID, n) + +int __stdcall _webrtceverywhere_IID_Lookup( const IID * pIID, int * pIndex ) +{ + IID_BS_LOOKUP_SETUP + + IID_BS_LOOKUP_INITIAL_TEST( _webrtceverywhere, 13, 8 ) + IID_BS_LOOKUP_NEXT_TEST( _webrtceverywhere, 4 ) + IID_BS_LOOKUP_NEXT_TEST( _webrtceverywhere, 2 ) + IID_BS_LOOKUP_NEXT_TEST( _webrtceverywhere, 1 ) + IID_BS_LOOKUP_RETURN_RESULT( _webrtceverywhere, 13, *pIndex ) + +} + +const ExtendedProxyFileInfo webrtceverywhere_ProxyFileInfo = +{ + (PCInterfaceProxyVtblList *) & _webrtceverywhere_ProxyVtblList, + (PCInterfaceStubVtblList *) & _webrtceverywhere_StubVtblList, + (const PCInterfaceName * ) & _webrtceverywhere_InterfaceNamesList, + (const IID ** ) & _webrtceverywhere_BaseIIDList, + & _webrtceverywhere_IID_Lookup, + 13, + 2, + 0, /* table of [async_uuid] interfaces */ + 0, /* Filler1 */ + 0, /* Filler2 */ + 0 /* Filler3 */ +}; +#pragma optimize("", on ) +#if _MSC_VER >= 1200 +#pragma warning(pop) +#endif + + +#endif /* !defined(_M_IA64) && !defined(_M_AMD64) && !defined(_ARM_) */ + diff --git a/npapi/BrowserCallback.cc b/npapi/BrowserCallback.cc new file mode 100755 index 0000000..7efaeec --- /dev/null +++ b/npapi/BrowserCallback.cc @@ -0,0 +1,104 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Debug.h" +#include "Utils.h" +#include "BrowserCallback.h" + +extern NPNetscapeFuncs* BrowserFuncs; + +BrowserCallback::BrowserCallback(NPP npp, unsigned msgid, NPObject* callback) + : _BrowserCallback(msgid) + , m_npp(npp) + , m_callback(NULL) + , m_params_count(0) +{ + Utils::NPObjectSet(&m_callback, callback); + memset(m_params, 0, sizeof(m_params)); +} + +BrowserCallback::~BrowserCallback() +{ + Utils::NPObjectRelease(&m_callback); + for (size_t i = 0; i < m_params_count; ++i) { + switch (m_params[i].type) { + case NPParamTypeString: + { + Utils::MemFree(&m_params[i].value.string.ptr); + break; + } + case NPParamTypeObject: + { + if (m_params[i].value.object) { + BrowserFuncs->releaseobject(m_params[i].value.object), m_params[i].value.object = NULL; + } + break; + } + default: + { + WE_DEBUG_ERROR("%d not a valid value for NPParamType", m_params[i].type); + break; + } + } + } +} + +NPError BrowserCallback::AddObject(NPObject* obj) +{ + if ((m_params_count + 1) >= kMaxParamArgs) { + WE_DEBUG_ERROR("Too much params"); + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + NPParam* newParam = &m_params[m_params_count++]; + newParam->type = NPParamTypeObject; + BrowserFuncs->retainobject(obj); + newParam->value.object = obj; + return NPERR_NO_ERROR; +} + +NPError BrowserCallback::AddString(void* ptr, size_t size) +{ + if ((m_params_count + 1) >= kMaxParamArgs) { + WE_DEBUG_ERROR("Too much params"); + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + NPParam* newParam = &m_params[m_params_count++]; + newParam->type = NPParamTypeString; + newParam->value.string.ptr = Utils::MemDup(ptr, size); + newParam->value.string.size = size; + return NPERR_NO_ERROR; +} + +// _BrowserCallback implementation +bool BrowserCallback::Invoke() +{ + bool ret = false; + if (m_callback) { + NPVariant result; + VOID_TO_NPVARIANT(result); + NPVariant args[kMaxParamArgs]; + for (size_t i = 0; i < m_params_count; ++i) { + switch (m_params[i].type) { + case NPParamTypeString: + { + STRINGN_TO_NPVARIANT((const NPUTF8 *)m_params[i].value.string.ptr, m_params[i].value.string.size, args[i]); + break; + } + case NPParamTypeObject: + { + if (m_params[i].value.object) { + OBJECT_TO_NPVARIANT(m_params[i].value.object, args[i]); + } + break; + } + default: + { + WE_DEBUG_ERROR("%d not a valid value for NPParamType", m_params[i].type); + return false; + } + } + } + ret = BrowserFuncs->invokeDefault(m_npp, m_callback, args, m_params_count, &result); + BrowserFuncs->releasevariantvalue(&result); + } + return ret; +} \ No newline at end of file diff --git a/npapi/BrowserCallback.h b/npapi/BrowserCallback.h new file mode 100755 index 0000000..7132f67 --- /dev/null +++ b/npapi/BrowserCallback.h @@ -0,0 +1,49 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_BROWSERCALLBACK_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_BROWSERCALLBACK_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" + +#include "npapi-includes.h" + +typedef enum NPParamType_ +{ + NPParamTypeString, + NPParamTypeObject +} NPParamType; + +typedef struct NPParam_ { + NPParamType type; + union { + NPObject *object; + struct { + void* ptr; + size_t size; + } string; + } value; +} NPParam; + +class BrowserCallback + : public _BrowserCallback +{ +public: + BrowserCallback(NPP npp, unsigned msgid, NPObject* callback); + virtual ~BrowserCallback(); + + BrowserObjectImpl_Inline(); + + NPError AddObject(NPObject* obj); + NPError AddString(void* ptr, size_t size); + + // _BrowserCallback implementation + virtual bool Invoke(); + +private: + NPP m_npp; + NPObject* m_callback; + size_t m_params_count; + NPParam m_params[kMaxParamArgs]; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_BROWSERCALLBACK_H_ */ diff --git a/npapi/MediaSourceStates.cc b/npapi/MediaSourceStates.cc new file mode 100755 index 0000000..93bd600 --- /dev/null +++ b/npapi/MediaSourceStates.cc @@ -0,0 +1,245 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "NPCommon.h" +#include "MediaSourceStates.h" +#include "Utils.h" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +#define kPropSourceType "sourceType" +#define kPropSourceId "sourceId" +#define kPropWidth "width" +#define kPropHeight "height" +#define kPropFrameRate "frameRate" +#define kPropAspectRatio "aspectRatio" +#define kPropFacingMode "facingMode" +#define kPropVolume "volume" + + +NPClass MediaSourceStatesClass = { + NP_CLASS_STRUCT_VERSION, + MediaSourceStates::Allocate, + MediaSourceStates::Deallocate, + MediaSourceStates::Invalidate, + MediaSourceStates::HasMethod, + MediaSourceStates::Invoke, + MediaSourceStates::InvokeDefault, + MediaSourceStates::HasProperty, + MediaSourceStates::GetProperty, + MediaSourceStates::SetProperty, + MediaSourceStates::RemoveProperty, + MediaSourceStates::NPEnumeration, + MediaSourceStates::Construct, +}; + +void MediaSourceStates::Invalidate(NPObject *npobj) +{ +} + +bool MediaSourceStates::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool MediaSourceStates::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +MediaSourceStates::MediaSourceStates(NPP instance) + : m_npp(instance) + , m_States(nullPtr) +{ + WE_DEBUG_INFO("MediaSourceStates::NewInstance()"); +} + +MediaSourceStates::~MediaSourceStates() +{ + m_States = nullPtr; +} + +void MediaSourceStates::SetStates(cpp11::shared_ptr<_MediaSourceStates> & states) +{ + m_States = states; +} + +cpp11::shared_ptr<_MediaSourceStates> MediaSourceStates::GetStates() +{ + return m_States; +} + +NPObject* MediaSourceStates::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new MediaSourceStates(instance)); +} + +void MediaSourceStates::Deallocate(NPObject* obj) +{ + delete (MediaSourceStates*)obj; +} + +bool MediaSourceStates::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = false; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaSourceStates::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool MediaSourceStates::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaSourceStates::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId) || + !strcmp(name, kPropSourceType) || + !strcmp(name, kPropSourceId) || + !strcmp(name, kPropWidth) || + !strcmp(name, kPropHeight) || + !strcmp(name, kPropFrameRate) || + !strcmp(name, kPropAspectRatio) || + !strcmp(name, kPropFacingMode) || + !strcmp(name, kPropVolume) + ; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaSourceStates::SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) +{ + // all properties are readonly + return false; +} + +bool MediaSourceStates::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + MediaSourceStates *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropSourceType)) { + if (This->m_States) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_States->sourceType.c_str(), This->m_States->sourceType.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropSourceId)) { + if (This->m_States) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_States->sourceId.c_str(), This->m_States->sourceId.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropWidth)) { + if (This->m_States) { + if (This->m_States->width <= 0) { + NULL_TO_NPVARIANT(*result); + } + else { + INT32_TO_NPVARIANT((int32_t)This->m_States->width, *result); + } + ret_val = true; + } + } + else if (!strcmp(name, kPropHeight)) { + if (This->m_States) { + if (This->m_States->height <= 0) { + NULL_TO_NPVARIANT(*result); + } + else { + INT32_TO_NPVARIANT((int32_t)This->m_States->height, *result); + } + ret_val = true; + } + } + else if (!strcmp(name, kPropFrameRate)) { + if (This->m_States) { + if (This->m_States->frameRate <= 0) { + NULL_TO_NPVARIANT(*result); + } + else { + DOUBLE_TO_NPVARIANT(This->m_States->frameRate, *result); + } + ret_val = true; + } + } + else if (!strcmp(name, kPropAspectRatio)) { + if (This->m_States) { + if (This->m_States->aspectRatio <= 0) { + NULL_TO_NPVARIANT(*result); + } + else { + DOUBLE_TO_NPVARIANT(This->m_States->aspectRatio, *result); + } + ret_val = true; + } + } + else if (!strcmp(name, kPropFacingMode)) { + if (This->m_States) { + if (This->m_States->facingMode.empty()) { + NULL_TO_NPVARIANT(*result); + } + else { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_States->facingMode.c_str(), This->m_States->facingMode.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + ret_val = true; + } + } + else if (!strcmp(name, kPropVolume)) { + if (This->m_States) { + DOUBLE_TO_NPVARIANT((double)This->m_States->volume, *result); + ret_val = true; + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaSourceStates::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} diff --git a/npapi/MediaSourceStates.h b/npapi/MediaSourceStates.h new file mode 100755 index 0000000..cdfe8ed --- /dev/null +++ b/npapi/MediaSourceStates.h @@ -0,0 +1,49 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_MEDIASOURCESTATES_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_MEDIASOURCESTATES_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" + +#include "npapi-includes.h" + +class MediaSourceStates + : public NPObject + , public _UniqueObject +{ +public: + MediaSourceStates(NPP instance); + virtual ~MediaSourceStates(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(MediaSourceStates); + NPObjectImpl_NPObjectRelease(MediaSourceStates); + NPObjectImpl_IsInstanceOf(MediaSourceStates); + + void SetStates(cpp11::shared_ptr<_MediaSourceStates> & states); + cpp11::shared_ptr<_MediaSourceStates> GetStates(); + +private: + NPP m_npp; + cpp11::shared_ptr<_MediaSourceStates> m_States; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_MEDIASOURCESTATES_H_ */ diff --git a/npapi/MediaStream.cc b/npapi/MediaStream.cc new file mode 100755 index 0000000..41f5177 --- /dev/null +++ b/npapi/MediaStream.cc @@ -0,0 +1,393 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "MediaStream.h" +#include "MediaStreamTrack.h" +#include "WebRTC.h" +#include "BrowserCallback.h" +#include "NPCommon.h" +#include "Utils.h" + +extern void* NPMemDup(const void* mem, size_t n); +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +#define kPropId "id" +#define kPropEnded "ended" +#define kPropOnended "onended" +#define kPropOnaddtrack "onaddtrack" +#define kPropOnremovetrack "onremovetrack" + +#define kFuncGetAudioTracks "getAudioTracks" +#define kFuncGetVideoTracks "getVideoTracks" +#define kFuncGetTrackById "getTrackById" +#define kFuncAddTrack "addTrack" +#define kFuncRemoveTrack "removeTrack" +#define kFuncClone "clone" +#define kFuncStop "stop" + +NPClass MediaStreamClass = { + NP_CLASS_STRUCT_VERSION, + MediaStream::Allocate, + MediaStream::Deallocate, + MediaStream::Invalidate, + MediaStream::HasMethod, + MediaStream::Invoke, + MediaStream::InvokeDefault, + MediaStream::HasProperty, + MediaStream::GetProperty, + MediaStream::SetProperty, + MediaStream::RemoveProperty, + MediaStream::NPEnumeration, + MediaStream::Construct, +}; + +void MediaStream::Invalidate(NPObject *npobj) +{ +} + +bool MediaStream::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool MediaStream::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + MediaStream *This = static_cast(npobj); + NPObject* _this = NULL; + Utils::NPObjectSet(&_this, This); + OBJECT_TO_NPVARIANT(_this, *result); + return true; +} + +MediaStream::MediaStream(NPP instance) + : m_npp(instance) + , m_callback_onended(NULL) + , m_callback_onaddtrack(NULL) + , m_callback_onremovetrack(NULL) + , m_Stream(nullPtr) +{ + WE_DEBUG_INFO("MediaStream::NewInstance()"); +} + +MediaStream::~MediaStream() +{ + Utils::NPObjectRelease(&m_callback_onended); + Utils::NPObjectRelease(&m_callback_onaddtrack); + Utils::NPObjectRelease(&m_callback_onremovetrack); + + m_Stream = nullPtr; + + SetDispatcher(NULL); +} + +NPObject* MediaStream::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new MediaStream(instance)); +} + +void MediaStream::Deallocate(NPObject* obj) +{ + delete (MediaStream*)obj; +} + +bool MediaStream::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = !strcmp(name, kFuncGetAudioTracks) || + !strcmp(name, kFuncGetVideoTracks) || + !strcmp(name, kFuncGetTrackById) || + !strcmp(name, kFuncAddTrack) || + !strcmp(name, kFuncRemoveTrack) || + !strcmp(name, kFuncClone) || + !strcmp(name, kFuncStop) + ; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStream::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool MediaStream::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + MediaStream *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + if (!strcmp(name, kFuncGetAudioTracks)) { + ret_val = (This->getTracks(false, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kFuncGetVideoTracks)) { + ret_val = (This->getTracks(true, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kFuncGetTrackById)) { + if (This->m_Stream && argCount > 0) { + std::string trackId = Utils::VariantToString((NPVariant*)&args[0]); + if (!trackId.empty()) { + cpp11::shared_ptr<_MediaStreamTrack> track = This->m_Stream->getTrackById(trackId.c_str()); + if (track) { + MediaStreamTrack* _track; + NPError err = MediaStreamTrack::CreateInstanceWithRef(This->m_npp, &_track); + if (err == NPERR_NO_ERROR) { + _track->SetDispatcher(const_cast<_AsyncEventDispatcher*>(This->GetDispatcher())); + _track->SetTrack(track); + ret_val = true; + OBJECT_TO_NPVARIANT(_track, *result); + } + } + else { + ret_val = true; + VOID_TO_NPVARIANT(*result); + } + } + } + } + else if (!strcmp(name, kFuncAddTrack)) { + if (This->m_Stream && argCount > 0) { + NPObject* npObj = Utils::VariantToObject((NPVariant*)&args[0]); + MediaStreamTrack* _mediaStreamTrack = (MediaStreamTrack*)(MediaStreamTrack::IsInstanceOf(npObj) ? npObj : Utils::NPObjectUpCast(npObj)); + if (_mediaStreamTrack) { + This->m_Stream->addTrack(_mediaStreamTrack->GetTrack().get()); + ret_val = true; + } + } + } + else if (!strcmp(name, kFuncRemoveTrack)) { + if (This->m_Stream && argCount > 0) { + NPObject* npObj = Utils::VariantToObject((NPVariant*)&args[0]); + MediaStreamTrack* _mediaStreamTrack = (MediaStreamTrack*)(MediaStreamTrack::IsInstanceOf(npObj) ? npObj : Utils::NPObjectUpCast(npObj)); + if (_mediaStreamTrack) { + This->m_Stream->removeTrack(_mediaStreamTrack->GetTrack().get()); + ret_val = true; + } + } + } + else if (!strcmp(name, kFuncClone)) { + if (This->m_Stream) { + cpp11::shared_ptr<_MediaStream>stream = This->m_Stream->clone(); + if (stream) { + MediaStream* _stream; + NPError err = MediaStream::CreateInstanceWithRef(This->m_npp, &_stream); + if (err == NPERR_NO_ERROR) { + _stream->SetDispatcher(const_cast<_AsyncEventDispatcher*>(This->GetDispatcher())); + _stream->SetStream(stream); + OBJECT_TO_NPVARIANT(_stream, *result); + ret_val = true; + } + } + } + } + else if (!strcmp(name, kFuncStop)) { + if (This->m_Stream) { + This->m_Stream->stop(); + } + ret_val = true; + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStream::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId) || + !strcmp(name, kPropId) || + !strcmp(name, kPropEnded) || + !strcmp(name, kPropOnended) || + !strcmp(name, kPropOnaddtrack) || + !strcmp(name, kPropOnremovetrack) + ; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStream::SetProperty(NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) +{ + MediaStream *This = static_cast(npobj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + // readonly + } + else if (!strcmp(name, kPropId)) { + // readonly + } + else if (!strcmp(name, kPropEnded)) { + // readonly + } + else if (!strcmp(name, kPropOnended)) { + Utils::NPObjectSet(&This->m_callback_onended, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropOnaddtrack)) { + Utils::NPObjectSet(&This->m_callback_onaddtrack, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropOnremovetrack)){ + Utils::NPObjectSet(&This->m_callback_onremovetrack, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + + BrowserFuncs->memfree(name); + return ret_val; +} + + +bool MediaStream::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + MediaStream *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropId)) { + if (This->m_Stream) { + NPUTF8* npStrId = (NPUTF8*)Utils::MemDup(This->m_Stream->id(), strlen(This->m_Stream->id())); + if (npStrId) { + STRINGZ_TO_NPVARIANT(npStrId, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropEnded)) { + if (This->m_Stream) { + BOOLEAN_TO_NPVARIANT(This->m_Stream->ended(), *result); + ret_val = true; + } + } + else if (!strcmp(name, kPropOnended)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onended, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropOnaddtrack)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onaddtrack, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropOnremovetrack)){ + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onremovetrack, result) == NPERR_NO_ERROR); + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStream::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} + +void MediaStream::SetStream(cpp11::shared_ptr<_MediaStream> & stream) +{ + if ((m_Stream = stream)) { + m_Stream->onendedSet(cpp11::bind(&MediaStream::onended, this)); + m_Stream->onaddtrackSet(cpp11::bind(&MediaStream::onaddtrack, this)); + m_Stream->onremovetrackSet(cpp11::bind(&MediaStream::onremovetrack, this)); + } +} + +cpp11::shared_ptr<_MediaStream> MediaStream::GetStream() +{ + return m_Stream; +} + +void MediaStream::onended() +{ + if (m_callback_onended) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_SUCCESS, m_callback_onended); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void MediaStream::onaddtrack() +{ + if (m_callback_onaddtrack) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_SUCCESS, m_callback_onaddtrack); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void MediaStream::onremovetrack() +{ + if (m_callback_onremovetrack) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_SUCCESS, m_callback_onremovetrack); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +NPError MediaStream::getTracks(bool video, NPVariant* Tracks) +{ + if (!m_Stream) { + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + _AsyncEventDispatcher* dispatcher = dynamic_cast<_AsyncEventDispatcher*>(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + if (!dispatcher) { + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + + NPError err; + std::vector vect; + cpp11::shared_ptr<_Sequence<_MediaStreamTrack> > tracks = video ? m_Stream->getVideoTracks() : m_Stream->getAudioTracks(); + if (tracks) { + for (size_t i = 0; i < tracks->values.size(); ++i) { + if (!tracks->values[i]) { + continue; + } + MediaStreamTrack* _track; + err = MediaStreamTrack::CreateInstanceWithRef(m_npp, &_track); + if (err == NPERR_NO_ERROR) { + _track->SetDispatcher(dispatcher); + _track->SetTrack(tracks->values[i]); + + NPVariant var; + OBJECT_TO_NPVARIANT(_track, var); + BrowserFuncs->retainobject(var.value.objectValue); // will be release by "NPVecClear()" + + vect.push_back(var); + MediaStreamTrack::ReleaseInstance(&_track); + } + } + } + + NPObject* arrayObj = NULL; + err = Utils::CreateJsArray(m_npp, vect, &arrayObj); + if (err == NPERR_NO_ERROR) { + OBJECT_TO_NPVARIANT(arrayObj, *Tracks); + } + + Utils::NPVecClear(vect); + + return err; +} \ No newline at end of file diff --git a/npapi/MediaStream.h b/npapi/MediaStream.h new file mode 100755 index 0000000..c608756 --- /dev/null +++ b/npapi/MediaStream.h @@ -0,0 +1,65 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_MEDIASTREAM_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_MEDIASTREAM_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_MediaStream.h" +#include "../common/_AsyncEvent.h" + +#include "npapi-includes.h" + +class MediaStream + : public NPObject + , public _AsyncEventRaiser + , public _UniqueObject +{ +public: + MediaStream(NPP instance); + virtual ~MediaStream(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(MediaStream); + NPObjectImpl_NPObjectRelease(MediaStream); + NPObjectImpl_IsInstanceOf(MediaStream); + + void SetStream(cpp11::shared_ptr<_MediaStream> & stream); + cpp11::shared_ptr<_MediaStream> GetStream(); + +private: + NPError getTracks(bool video, NPVariant* Tracks); + + // callbacks + void onended(); + void onaddtrack(); + void onremovetrack(); + +private: + cpp11::shared_ptr<_MediaStream> m_Stream; + NPP m_npp; + + // callbacks + NPObject* m_callback_onended; + NPObject* m_callback_onaddtrack; + NPObject* m_callback_onremovetrack; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_MEDIASTREAM_H_ */ diff --git a/npapi/MediaStreamEvent.cc b/npapi/MediaStreamEvent.cc new file mode 100755 index 0000000..7916400 --- /dev/null +++ b/npapi/MediaStreamEvent.cc @@ -0,0 +1,165 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "NPCommon.h" +#include "MediaStream.h" +#include "MediaStreamEvent.h" +#include "Utils.h" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +#define kPropStream "stream" + +NPClass MediaStreamEventClass = { + NP_CLASS_STRUCT_VERSION, + MediaStreamEvent::Allocate, + MediaStreamEvent::Deallocate, + MediaStreamEvent::Invalidate, + MediaStreamEvent::HasMethod, + MediaStreamEvent::Invoke, + MediaStreamEvent::InvokeDefault, + MediaStreamEvent::HasProperty, + MediaStreamEvent::GetProperty, + MediaStreamEvent::SetProperty, + MediaStreamEvent::RemoveProperty, + MediaStreamEvent::NPEnumeration, + MediaStreamEvent::Construct, +}; + +void MediaStreamEvent::Invalidate(NPObject *npobj) +{ +} + +bool MediaStreamEvent::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool MediaStreamEvent::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +MediaStreamEvent::MediaStreamEvent(NPP instance) + : m_npp(instance) + , m_Event(nullPtr) +{ + WE_DEBUG_INFO("MediaStreamEvent::NewInstance()"); +} + +MediaStreamEvent::~MediaStreamEvent() +{ + m_Event = nullPtr; + SetDispatcher(NULL); +} + +void MediaStreamEvent::SetEvent(cpp11::shared_ptr<_MediaStreamEvent> & e) +{ + m_Event = e; +} + +cpp11::shared_ptr<_MediaStreamEvent> MediaStreamEvent::GetEvent() +{ + return m_Event; +} + +NPObject* MediaStreamEvent::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new MediaStreamEvent(instance)); +} + +void MediaStreamEvent::Deallocate(NPObject* obj) +{ + delete (MediaStreamEvent*)obj; +} + +bool MediaStreamEvent::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = false; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStreamEvent::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool MediaStreamEvent::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStreamEvent::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId) || !strcmp(name, kPropStream); + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStreamEvent::SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) +{ + // all properties are readonly + return false; +} + + +bool MediaStreamEvent::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + MediaStreamEvent *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropStream)) { + if (This->m_Event) { + if (This->m_Event->stream) { + MediaStream* _stream; + NPError err = MediaStream::CreateInstanceWithRef(This->m_npp, &_stream); + if (err == NPERR_NO_ERROR) { + _stream->SetStream(This->m_Event->stream); + OBJECT_TO_NPVARIANT(_stream, *result); + ret_val = true; + } + } + else { + NULL_TO_NPVARIANT(*result); + ret_val = true; + } + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStreamEvent::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} diff --git a/npapi/MediaStreamEvent.h b/npapi/MediaStreamEvent.h new file mode 100755 index 0000000..062247c --- /dev/null +++ b/npapi/MediaStreamEvent.h @@ -0,0 +1,51 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_MEDIASTREAMEVENT_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_MEDIASTREAMEVENT_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_AsyncEvent.h" + +#include "npapi-includes.h" + +class MediaStreamEvent + : public NPObject + , public _AsyncEventRaiser + , public _UniqueObject +{ +public: + MediaStreamEvent(NPP instance); + virtual ~MediaStreamEvent(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(MediaStreamEvent); + NPObjectImpl_NPObjectRelease(MediaStreamEvent); + NPObjectImpl_IsInstanceOf(MediaStreamEvent); + + void SetEvent(cpp11::shared_ptr<_MediaStreamEvent> & e); + cpp11::shared_ptr<_MediaStreamEvent> GetEvent(); + +private: + NPP m_npp; + cpp11::shared_ptr<_MediaStreamEvent> m_Event; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_MEDIASTREAMEVENT_H_ */ diff --git a/npapi/MediaStreamTrack.cc b/npapi/MediaStreamTrack.cc new file mode 100755 index 0000000..c27264a --- /dev/null +++ b/npapi/MediaStreamTrack.cc @@ -0,0 +1,484 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "NPCommon.h" +#include "MediaStreamTrack.h" +#include "BrowserCallback.h" +#include "MediaSourceStates.h" +#include "WebRTC.h" +#include "SourceInfo.h" +#include "Utils.h" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +#define kPropKind "kind" +#define kPropId "id" +#define kPropLabel "label" +#define kPropEnabled "enabled" +#define kPropMuted "muted" +#define kPropOnmute "onmute" +#define kPropOnunmute "onunmute" +#define kPropReadonly "readonly" +#define kPropRemote "remote" +#define kPropReadyState "readyState" +#define kPropOnstarted "onstarted" +#define kPropOnended "onended" +#define kPropOnoverconstrained "onoverconstrained" + +#define kFuncGetSourceInfos "getSourceInfos" +#define kFuncConstraints "constraints" +#define kFuncStates "states" +#define kFuncCapabilities "capabilities" +#define kFuncApplyConstraints "applyConstraints" +#define kFuncClone "clone" +#define kFuncStop "stop" + +NPClass MediaStreamTrackClass = { + NP_CLASS_STRUCT_VERSION, + MediaStreamTrack::Allocate, + MediaStreamTrack::Deallocate, + MediaStreamTrack::Invalidate, + MediaStreamTrack::HasMethod, + MediaStreamTrack::Invoke, + MediaStreamTrack::InvokeDefault, + MediaStreamTrack::HasProperty, + MediaStreamTrack::GetProperty, + MediaStreamTrack::SetProperty, + MediaStreamTrack::RemoveProperty, + MediaStreamTrack::NPEnumeration, + MediaStreamTrack::Construct, +}; + +void MediaStreamTrack::Invalidate(NPObject *npobj) +{ +} + +bool MediaStreamTrack::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool MediaStreamTrack::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +MediaStreamTrack::MediaStreamTrack(NPP instance) + : m_npp(instance) + , m_Track(nullPtr) + , m_callback_onmute(NULL) + , m_callback_onunmute(NULL) + , m_callback_onstarted(NULL) + , m_callback_onended(NULL) + , m_callback_onoverconstrained(NULL) +{ + WE_DEBUG_INFO("MediaStreamTrack::NewInstance()"); +} + +MediaStreamTrack::~MediaStreamTrack() +{ + m_Track = nullPtr; + + Utils::NPObjectRelease(&m_callback_onmute); + Utils::NPObjectRelease(&m_callback_onunmute); + Utils::NPObjectRelease(&m_callback_onstarted); + Utils::NPObjectRelease(&m_callback_onended); + Utils::NPObjectRelease(&m_callback_onoverconstrained); + + SetDispatcher(NULL); +} + +void MediaStreamTrack::SetTrack(cpp11::shared_ptr<_MediaStreamTrack> & track) +{ + if ((m_Track = track)) { + m_Track->onmuteSet(cpp11::bind(&MediaStreamTrack::onmute, this)); + m_Track->onunmuteSet(cpp11::bind(&MediaStreamTrack::onunmute, this)); + m_Track->onstartedSet(cpp11::bind(&MediaStreamTrack::onstarted, this)); + m_Track->onendedSet(cpp11::bind(&MediaStreamTrack::onended, this)); + m_Track->onoverconstrainedSet(cpp11::bind(&MediaStreamTrack::onoverconstrained, this)); + } +} + +cpp11::shared_ptr<_MediaStreamTrack> MediaStreamTrack::GetTrack() +{ + return m_Track; +} +NPObject* MediaStreamTrack::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new MediaStreamTrack(instance)); +} + +void MediaStreamTrack::Deallocate(NPObject* obj) +{ + delete (MediaStreamTrack*)obj; +} + +bool MediaStreamTrack::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = !strcmp(name, kFuncGetSourceInfos) || + !strcmp(name, kFuncConstraints) || + !strcmp(name, kFuncStates) || + !strcmp(name, kFuncCapabilities) || + !strcmp(name, kFuncApplyConstraints) || + !strcmp(name, kFuncClone) || + !strcmp(name, kFuncStop) + ; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStreamTrack::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool MediaStreamTrack::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + MediaStreamTrack *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + if (!strcmp(name, kFuncGetSourceInfos)) { + NPObject* obj = NULL; + NPError err = MediaStreamTrack::getSources(This->m_npp, const_cast<_AsyncEventDispatcher*>(This->GetDispatcher()), &obj); + if (err == NPERR_NO_ERROR) { + OBJECT_TO_NPVARIANT(obj, *result); + ret_val = true; + } + } + else if (!strcmp(name, kFuncConstraints)) { + if (This->m_Track) { + // TODO: not implemented yet + NULL_TO_NPVARIANT(*result); + ret_val = false; + } + } + else if (!!strcmp(name, kFuncStates)) { + if (This->m_Track) { + MediaSourceStates* _states; + NPError err = MediaSourceStates::CreateInstanceWithRef(This->m_npp, &_states); + if (err == NPERR_NO_ERROR) { + cpp11::shared_ptr<_MediaSourceStates> states = This->m_Track->states(); + _states->SetStates(states); + OBJECT_TO_NPVARIANT(_states, *result); + ret_val = true; + } + } + } + else if (!!strcmp(name, kFuncCapabilities)) { + if (This->m_Track) { + // TODO: not implemented yet + NULL_TO_NPVARIANT(*result); + ret_val = false; + } + } + else if (!!strcmp(name, kFuncApplyConstraints)) { + if (This->m_Track) { + // TODO: not implemented yet + NULL_TO_NPVARIANT(*result); + ret_val = false; + } + } + else if (!!strcmp(name, kFuncClone)) { + if (This->m_Track) { + // TODO: not implemented yet + NULL_TO_NPVARIANT(*result); + ret_val = false; + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStreamTrack::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId) || + !strcmp(name, kPropKind) || + !strcmp(name, kPropId) || + !strcmp(name, kPropLabel) || + !strcmp(name, kPropEnabled) || + !strcmp(name, kPropMuted) || + !strcmp(name, kPropOnmute) || + !strcmp(name, kPropOnunmute) || + !strcmp(name, kPropReadonly) || + !strcmp(name, kPropRemote) || + !strcmp(name, kPropReadyState) || + !strcmp(name, kPropOnstarted) || + !strcmp(name, kPropOnended) || + !strcmp(name, kPropOnoverconstrained) + ; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStreamTrack::SetProperty(NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) +{ + MediaStreamTrack *This = static_cast(npobj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropKind)) { + // readonly + ret_val = false; + } + else if (!strcmp(name, kPropId)) { + // readonly + ret_val = false; + } + else if (!strcmp(name, kPropLabel)) { + // readonly + ret_val = false; + } + else if (!strcmp(name, kPropEnabled)) { + if (This->m_Track && NPVARIANT_IS_BOOLEAN(*value)) { + This->m_Track->enabledSet(value->value.boolValue); + ret_val = true; + } + } + else if (!strcmp(name, kPropMuted)) { + // readonly + ret_val = false; + } + else if (!strcmp(name, kPropOnmute)) { + Utils::NPObjectSet(&This->m_callback_onmute, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropOnunmute)) { + Utils::NPObjectSet(&This->m_callback_onunmute, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropReadonly)) { + // readonly + ret_val = false; + } + else if (!strcmp(name, kPropRemote)) { + // readonly + ret_val = false; + } + else if (!strcmp(name, kPropReadyState)) { + // readonly + ret_val = false; + } + else if (!strcmp(name, kPropOnstarted)) { + Utils::NPObjectSet(&This->m_callback_onstarted, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropOnended)) { + Utils::NPObjectSet(&This->m_callback_onended, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropOnoverconstrained)) { + Utils::NPObjectSet(&This->m_callback_onoverconstrained, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStreamTrack::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + MediaStreamTrack *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropKind)) { + if (This->m_Track) { + NPUTF8* npStrKind = (NPUTF8*)Utils::MemDup(This->m_Track->kind(), strlen(This->m_Track->kind())); + if (npStrKind) { + STRINGZ_TO_NPVARIANT(npStrKind, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropId)) { + if (This->m_Track) { + NPUTF8* npStrId = (NPUTF8*)Utils::MemDup(This->m_Track->id(), strlen(This->m_Track->id())); + if (npStrId) { + STRINGZ_TO_NPVARIANT(npStrId, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropLabel)) { + if (This->m_Track) { + NPUTF8* npStrLabel = (NPUTF8*)Utils::MemDup(This->m_Track->label(), strlen(This->m_Track->label())); + if (npStrLabel) { + STRINGZ_TO_NPVARIANT(npStrLabel, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropEnabled)) { + if (This->m_Track) { + BOOLEAN_TO_NPVARIANT(This->m_Track->enabled(), *result); + ret_val = true; + } + } + else if (!strcmp(name, kPropMuted)) { + if (This->m_Track) { + BOOLEAN_TO_NPVARIANT(This->m_Track->muted(), *result); + ret_val = true; + } + } + else if (!strcmp(name, kPropOnmute)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onmute, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropOnunmute)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onunmute, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropReadonly)) { + if (This->m_Track) { + BOOLEAN_TO_NPVARIANT(This->m_Track->readonly(), *result); + ret_val = true; + } + } + else if (!strcmp(name, kPropRemote)) { + if (This->m_Track) { + BOOLEAN_TO_NPVARIANT(This->m_Track->remote(), *result); + ret_val = true; + } + } + else if (!strcmp(name, kPropReadyState)) { + if (This->m_Track) { + NPUTF8* npStrState = (NPUTF8*)Utils::MemDup(This->m_Track->readyState(), strlen(This->m_Track->readyState())); + if (npStrState) { + STRINGZ_TO_NPVARIANT(npStrState, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropOnstarted)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onstarted, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropOnended)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onended, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropOnoverconstrained)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onoverconstrained, result) == NPERR_NO_ERROR); + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool MediaStreamTrack::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} + + +void MediaStreamTrack::onmute() +{ + if (m_callback_onmute) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_SUCCESS, m_callback_onmute); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void MediaStreamTrack::onunmute() +{ + if (m_callback_onunmute) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_SUCCESS, m_callback_onunmute); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void MediaStreamTrack::onstarted() +{ + if (m_callback_onstarted) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_SUCCESS, m_callback_onstarted); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void MediaStreamTrack::onended() +{ + if (m_callback_onended) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_SUCCESS, m_callback_onended); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void MediaStreamTrack::onoverconstrained() +{ + if (m_callback_onoverconstrained) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_SUCCESS, m_callback_onoverconstrained); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +NPError MediaStreamTrack::getSources(NPP npp, _AsyncEventDispatcher* dispatcher, NPObject** Infos) +{ + if (!dispatcher || !Infos || *Infos) { + CHECK_NPERR_RETURN(NPERR_INVALID_PARAM); + } + + std::vector vect; + NPError err; + cpp11::shared_ptr<_Sequence<_SourceInfo> > sources = _MediaStreamTrack::getSourceInfos(); + if (sources) { + for (size_t i = 0; i < sources->values.size(); ++i) { + if (!sources->values[i]) { + continue; + } + SourceInfo* _source; + err = SourceInfo::CreateInstanceWithRef(npp, &_source); + if (err == NPERR_NO_ERROR) { + _source->SetInfo(sources->values[i]); + + NPVariant var; + OBJECT_TO_NPVARIANT(_source, var); + BrowserFuncs->retainobject(var.value.objectValue); // will be release by "NPVecClear()" + vect.push_back(var); + SourceInfo::ReleaseInstance(&_source); + } + } + } + + err = Utils::CreateJsArray(npp, vect, Infos); + Utils::NPVecClear(vect); + + return err; +} \ No newline at end of file diff --git a/npapi/MediaStreamTrack.h b/npapi/MediaStreamTrack.h new file mode 100755 index 0000000..689e426 --- /dev/null +++ b/npapi/MediaStreamTrack.h @@ -0,0 +1,68 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_MEDIASTREAMTRACK_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_MEDIASTREAMTRACK_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_MediaStreamTrack.h" +#include "../common/_AsyncEvent.h" + +#include "npapi-includes.h" + +class MediaStreamTrack + : public NPObject + , public _AsyncEventRaiser + , public _UniqueObject +{ +public: + MediaStreamTrack(NPP instance); + virtual ~MediaStreamTrack(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(MediaStreamTrack); + NPObjectImpl_NPObjectRelease(MediaStreamTrack); + NPObjectImpl_IsInstanceOf(MediaStreamTrack); + + void SetTrack(cpp11::shared_ptr<_MediaStreamTrack> & track); + cpp11::shared_ptr<_MediaStreamTrack> GetTrack(); + + // not part of the standard but used by Chrome + static NPError getSources(NPP npp, _AsyncEventDispatcher* dispatcher, NPObject** Infos); + +private: + + void onmute(); + void onunmute(); + void onstarted(); + void onended(); + void onoverconstrained(); + +private: + NPP m_npp; + cpp11::shared_ptr<_MediaStreamTrack> m_Track; + NPObject* m_callback_onmute; + NPObject* m_callback_onunmute; + NPObject* m_callback_onstarted; + NPObject* m_callback_onended; + NPObject* m_callback_onoverconstrained; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_MEDIASTREAMTRACK_H_ */ diff --git a/npapi/NPCommon.h b/npapi/NPCommon.h new file mode 100755 index 0000000..3b0ced8 --- /dev/null +++ b/npapi/NPCommon.h @@ -0,0 +1,44 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_NPCOMMON_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_NPCOMMON_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_AsyncEvent.h" + +#include "Utils.h" + +#include "npapi-includes.h" + +#define kPropUniqueId "uniqueId" + +class NPObjectAutoRef { +public: + NPObjectAutoRef(NPObject *obj) : m_obj(NULL){ + Utils::NPObjectSet(&m_obj, obj); + } + NPObjectAutoRef(const NPObjectAutoRef& other) : m_obj(NULL) { + Utils::NPObjectSet(&m_obj, other); + } + virtual ~NPObjectAutoRef() { + Utils::NPObjectRelease(&m_obj); + } + + operator bool() const + { + return !!m_obj; + } + operator NPObject*() const + { + return m_obj; + } + NPObjectAutoRef& operator = (NPObject* obj) + { + Utils::NPObjectSet(&m_obj, obj); + return *this; + } +private: + NPObject *m_obj; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_NPCOMMON_H_ */ \ No newline at end of file diff --git a/npapi/PeerConnection.cc b/npapi/PeerConnection.cc new file mode 100755 index 0000000..2f89f47 --- /dev/null +++ b/npapi/PeerConnection.cc @@ -0,0 +1,817 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "NPCommon.h" +#include "PeerConnection.h" +#include "MediaStream.h" +#include "MediaStreamTrack.h" +#include "MediaStreamEvent.h" +#include "SessionDescription.h" +#include "BrowserCallback.h" +#include "RTCIceCandidate.h" +#include "RTCPeerConnectionIceEvent.h" +#include "RTCStatsReport.h" +#include "WebRTC.h" +#include "NPCommon.h" +#include "Utils.h" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +#define kPropLocalDescription "localDescription" +#define kPropRemoteDescription "remoteDescription" +#define kPropSignalingState "signalingState" +#define kPropIceGatheringState "iceGatheringState" +#define kPropIceConnectionState "iceConnectionState" +#define kPropOnnegotiationneeded "onnegotiationneeded" +#define kPropOnicecandidate "onicecandidate" +#define kPropOnsignalingstatechange "onsignalingstatechange" +#define kPropOnaddstream "onaddstream" +#define kPropOnremovestream "onremovestream" +#define kPropOniceconnectionstatechange "oniceconnectionstatechange" + +#define kFuncCreateOffer "createOffer" +#define kFuncCreateAnswer "createAnswer" +#define kFuncSetLocalDescription "setLocalDescription" +#define kFuncSetRemoteDescription "setRemoteDescription" +#define kFuncUpdateIce "updateIce" +#define kFuncAddIceCandidate "addIceCandidate" +#define kFuncGetLocalStreams "getLocalStreams" +#define kFuncGetRemoteStreams "getRemoteStreams" +#define kFuncGetStreamById "getStreamById" +#define kFuncAddStream "addStream" +#define kFuncRemoveStream "removeStream" +#define kFuncClose "close" +#define kFuncGetStats "getStats" + +NPClass PeerConnectionClass = { + NP_CLASS_STRUCT_VERSION, + PeerConnection::Allocate, + PeerConnection::Deallocate, + PeerConnection::Invalidate, + PeerConnection::HasMethod, + PeerConnection::Invoke, + PeerConnection::InvokeDefault, + PeerConnection::HasProperty, + PeerConnection::GetProperty, + PeerConnection::SetProperty, + PeerConnection::RemoveProperty, + PeerConnection::NPEnumeration, + PeerConnection::Construct, +}; + +void PeerConnection::Invalidate(NPObject *npobj) +{ +} + +bool PeerConnection::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool PeerConnection::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +PeerConnection::PeerConnection(NPP instance) + : m_npp(instance) + , m_Peer(nullPtr) + , m_callback_onnegotiationneeded(NULL) + , m_callback_onicecandidate(NULL) + , m_callback_onsignalingstatechange(NULL) + , m_callback_onaddstream(NULL) + , m_callback_onremovestream(NULL) + , m_callback_oniceconnectionstatechange(NULL) +{ + WE_DEBUG_INFO("PeerConnection::NewInstance()"); +} + +PeerConnection::~PeerConnection() +{ + Utils::NPObjectRelease(&m_callback_onnegotiationneeded); + Utils::NPObjectRelease(&m_callback_onicecandidate); + Utils::NPObjectRelease(&m_callback_onsignalingstatechange); + Utils::NPObjectRelease(&m_callback_onaddstream); + Utils::NPObjectRelease(&m_callback_onremovestream); + Utils::NPObjectRelease(&m_callback_oniceconnectionstatechange); + + m_Peer = nullPtr; + + SetDispatcher(NULL); +} + +NPError PeerConnection::Init(NPObject* RTCConfiguration, NPObject* MediaConstraints) +{ + NPError err = NPERR_NO_ERROR; + + cpp11::shared_ptr<_MediaConstraintsObj> mediaConstraints; + CHECK_NPERR_RETURN(err = Utils::BuildMediaConstraintsObjs(m_npp, MediaConstraints, mediaConstraints)); + + cpp11::shared_ptr<_RTCConfiguration> rtcConf; + CHECK_NPERR_RETURN(err = Utils::BuildRTCConfiguration(m_npp, RTCConfiguration, rtcConf)); + + m_Peer = cpp11::shared_ptr<_PeerConnection>(new _PeerConnection()); + if (!m_Peer->Init(rtcConf.get(), mediaConstraints.get())) { + m_Peer = nullPtr; + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + + // set callback functions + m_Peer->SetCallback_onnegotiationneeded(cpp11::bind(&PeerConnection::onnegotiationneeded, this)); + m_Peer->SetCallback_onicecandidate(cpp11::bind(&PeerConnection::onicecandidate, this, cpp11::placeholders::_1)); + m_Peer->SetCallback_onsignalingstatechange(cpp11::bind(&PeerConnection::onsignalingstatechange, this)); + m_Peer->SetCallback_onaddstream(cpp11::bind(&PeerConnection::onaddstream, this, cpp11::placeholders::_1)); + m_Peer->SetCallback_onremovestream(cpp11::bind(&PeerConnection::onremovestream, this, cpp11::placeholders::_1)); + m_Peer->SetCallback_oniceconnectionstatechange(cpp11::bind(&PeerConnection::oniceconnectionstatechange, this)); + + return NPERR_NO_ERROR; +} + +NPObject* PeerConnection::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new PeerConnection(instance)); +} + +void PeerConnection::Deallocate(NPObject* obj) +{ + delete (PeerConnection*)obj; +} + +bool PeerConnection::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = !strcmp(name, kFuncCreateOffer) || + !strcmp(name, kFuncCreateAnswer) || + !strcmp(name, kFuncSetLocalDescription) || + !strcmp(name, kFuncSetRemoteDescription) || + !strcmp(name, kFuncUpdateIce) || + !strcmp(name, kFuncAddIceCandidate) || + !strcmp(name, kFuncGetLocalStreams) || + !strcmp(name, kFuncGetRemoteStreams) || + !strcmp(name, kFuncGetStreamById) || + !strcmp(name, kFuncAddStream) || + !strcmp(name, kFuncRemoveStream) || + !strcmp(name, kFuncClose) || + !strcmp(name, kFuncGetStats) + ; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool PeerConnection::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool PeerConnection::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + PeerConnection *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + if (!strcmp(name, kFuncCreateOffer)) { + if (This->m_Peer) { + NPObjectAutoRef successCallback(argCount > 0 ? Utils::VariantToObject((NPVariant*)&args[0]) : NULL); + NPObjectAutoRef failureCallback(argCount > 1 ? Utils::VariantToObject((NPVariant*)&args[1]) : NULL); + NPObjectAutoRef mediaConstraints(argCount > 2 ? Utils::VariantToObject((NPVariant*)&args[2]) : NULL); + + NPError err; + + cpp11::shared_ptr<_MediaConstraintsObj> _mediaConstraints; + err = Utils::BuildMediaConstraintsObjs(This->m_npp, mediaConstraints, _mediaConstraints); + if (err == NPERR_NO_ERROR) { + ret_val = This->m_Peer->CreateOffer( + [successCallback, This](cpp11::shared_ptr<_SessionDescription> sdp) { + if (successCallback) { + SessionDescription* _sdp; + NPError _err = SessionDescription::CreateInstanceWithRef(This->m_npp, &_sdp); + if (_err == NPERR_NO_ERROR) { + _sdp->SetSdp(sdp); + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_CREATEOFFER_SUCCESS, successCallback); + if (_cb) { + _cb->AddObject(_sdp); + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + SessionDescription::ReleaseInstance(&_sdp); + } + } + }, + [failureCallback, This](cpp11::shared_ptr error) { + if (failureCallback) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_CREATEOFFER_ERROR, failureCallback); + if (_cb) { + _cb->AddString((void*)error->c_str(), error->length()); + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }, + _mediaConstraints.get()); + } + } + } + else if (!strcmp(name, kFuncCreateAnswer)) { + if (This->m_Peer) { + NPObjectAutoRef successCallback(argCount > 0 ? Utils::VariantToObject((NPVariant*)&args[0]) : NULL); + NPObjectAutoRef failureCallback(argCount > 1 ? Utils::VariantToObject((NPVariant*)&args[1]) : NULL); + NPObjectAutoRef mediaConstraints(argCount > 2 ? Utils::VariantToObject((NPVariant*)&args[2]) : NULL); + + NPError err; + + cpp11::shared_ptr<_MediaConstraintsObj> _mediaConstraints; + err = Utils::BuildMediaConstraintsObjs(This->m_npp, mediaConstraints, _mediaConstraints); + if (err == NPERR_NO_ERROR) { + ret_val = This->m_Peer->CreateAnswer( + [successCallback, This](cpp11::shared_ptr<_SessionDescription> sdp) { + if (successCallback) { + SessionDescription* _sdp; + NPError _err = SessionDescription::CreateInstanceWithRef(This->m_npp, &_sdp); + if (_err == NPERR_NO_ERROR) { + _sdp->SetSdp(sdp); + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_CREATEOFFER_SUCCESS, successCallback); + if (_cb) { + _cb->AddObject(_sdp); + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + SessionDescription::ReleaseInstance(&_sdp); + } + } + }, + [failureCallback, This](cpp11::shared_ptr error) { + if (failureCallback) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_CREATEOFFER_ERROR, failureCallback); + if (_cb) { + _cb->AddString((void*)error->c_str(), error->length()); + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }, + _mediaConstraints.get()); + } + } + } + else if (!strcmp(name, kFuncSetLocalDescription)) { + if (This->m_Peer && argCount > 0) { + NPObject* npObj = Utils::VariantToObject((NPVariant*)&args[0]); + SessionDescription* sdp = (SessionDescription*)(SessionDescription::IsInstanceOf(npObj) ? npObj : Utils::NPObjectUpCast(npObj)); + if (sdp) { + NPObjectAutoRef successCallback(argCount > 1 ? Utils::VariantToObject((NPVariant*)&args[1]) : NULL); + NPObjectAutoRef failureCallback(argCount > 2 ? Utils::VariantToObject((NPVariant*)&args[2]) : NULL); + ret_val = This->m_Peer->SetLocalDescription( + sdp->GetSdp().get(), + [successCallback, This]() { + if (successCallback) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_SUCCESS, successCallback); + if (_cb) { + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }, + [failureCallback, This](cpp11::shared_ptr error) { + if (failureCallback) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_CREATEOFFER_ERROR, failureCallback); + if (_cb) { + _cb->AddString((void*)error->c_str(), error->length()); + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + } + ); + } + } + } + else if (!strcmp(name, kFuncSetRemoteDescription)) { + if (This->m_Peer && argCount > 0) { + NPObject* npObj = Utils::VariantToObject((NPVariant*)&args[0]); + SessionDescription* sdp = (SessionDescription*)(SessionDescription::IsInstanceOf(npObj) ? npObj : Utils::NPObjectUpCast(npObj)); + if (sdp) { + NPObjectAutoRef successCallback(argCount > 1 ? Utils::VariantToObject((NPVariant*)&args[1]) : NULL); + NPObjectAutoRef failureCallback(argCount > 2 ? Utils::VariantToObject((NPVariant*)&args[2]) : NULL); + ret_val = This->m_Peer->SetRemoteDescription( + sdp->GetSdp().get(), + [successCallback, This]() { + if (successCallback) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_SUCCESS, successCallback); + if (_cb) { + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }, + [failureCallback, This](cpp11::shared_ptr error) { + if (failureCallback) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_CREATEOFFER_ERROR, failureCallback); + if (_cb) { + _cb->AddString((void*)error->c_str(), error->length()); + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + } + ); + } + } + } + else if (!strcmp(name, kFuncUpdateIce)) { + if (This->m_Peer) { + NPObject* RTCConfiguration = argCount > 0 ? Utils::VariantToObject((NPVariant*)&args[0]) : NULL; + NPObject* mediaConstraints = argCount > 1 ? Utils::VariantToObject((NPVariant*)&args[1]) : NULL; + cpp11::shared_ptr<_RTCConfiguration> _rtcConf; + NPError err = Utils::BuildRTCConfiguration(This->m_npp, RTCConfiguration, _rtcConf); + if (err == NPERR_NO_ERROR) { + cpp11::shared_ptr<_MediaConstraintsObj> _mediaConstraints; + err = Utils::BuildMediaConstraintsObjs(This->m_npp, mediaConstraints, _mediaConstraints); + if (err == NPERR_NO_ERROR) { + ret_val = This->m_Peer->UpdateIce(_rtcConf.get(), _mediaConstraints.get()); + } + } + } + } + else if (!strcmp(name, kFuncAddIceCandidate)) { + if (This->m_Peer && argCount > 0) { + NPObject* npObj = Utils::VariantToObject((NPVariant*)&args[0]); + RTCIceCandidate* candidate = (RTCIceCandidate*)(RTCIceCandidate::IsInstanceOf(npObj) ? npObj : Utils::NPObjectUpCast(npObj)); + if (candidate) { + NPObjectAutoRef successCallback(argCount > 1 ? Utils::VariantToObject((NPVariant*)&args[1]) : NULL); + NPObjectAutoRef failureCallback(argCount > 2 ? Utils::VariantToObject((NPVariant*)&args[2]) : NULL); + ret_val = This->m_Peer->AddIceCandidate( + candidate->GetCandidate().get(), + [successCallback, This]() { + if (successCallback) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_SUCCESS, successCallback); + if (_cb) { + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }, + [failureCallback, This](cpp11::shared_ptr error) { + if (failureCallback) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_CREATEOFFER_ERROR, failureCallback); + if (_cb) { + _cb->AddString((void*)error->c_str(), error->length()); + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + } + ); + } + } + } + else if (!strcmp(name, kFuncGetLocalStreams)) { + ret_val = (This->getStreams(false/*local*/, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kFuncGetRemoteStreams)) { + ret_val = (This->getStreams(true/*remote*/, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kFuncGetStreamById)) { + if (This->m_Peer && argCount > 0) { + std::string streamId = Utils::VariantToString((NPVariant*)&args[0]); + if (!streamId.empty()) { + cpp11::shared_ptr<_MediaStream> stream = This->m_Peer->GetStreamById(streamId.c_str()); + if (stream) { + MediaStream* _stream; + NPError err = MediaStream::CreateInstanceWithRef(This->m_npp, &_stream); + if (err == NPERR_NO_ERROR) { + _stream->SetDispatcher(const_cast<_AsyncEventDispatcher*>(This->GetDispatcher())); + _stream->SetStream(stream); + ret_val = true; + OBJECT_TO_NPVARIANT(_stream, *result); + } + } + else { + ret_val = true; + VOID_TO_NPVARIANT(*result); + } + } + } + } + else if (!strcmp(name, kFuncAddStream)) { + if (This->m_Peer) { + NPObject* stream = argCount > 0 ? Utils::VariantToObject((NPVariant*)&args[0]) : NULL; + MediaStream* _stream = (MediaStream*)(MediaStream::IsInstanceOf(stream) ? stream : Utils::NPObjectUpCast(stream)); + NPObject* mediaConstraints = argCount > 1 ? Utils::VariantToObject((NPVariant*)&args[1]) : NULL; + if (_stream) { + cpp11::shared_ptr<_MediaConstraintsObj> _mediaConstraints; + NPError err = Utils::BuildMediaConstraintsObjs(This->m_npp, mediaConstraints, _mediaConstraints); + if (err == NPERR_NO_ERROR) { + ret_val = This->m_Peer->AddStream(_stream->GetStream().get(), _mediaConstraints.get()); + } + } + } + } + else if (!strcmp(name, kFuncRemoveStream)) { + if (This->m_Peer && argCount > 0) { + NPObject* stream = Utils::VariantToObject((NPVariant*)&args[0]); + MediaStream* _stream = (MediaStream*)(MediaStream::IsInstanceOf(stream) ? stream : Utils::NPObjectUpCast(stream)); + if (_stream) { + ret_val = This->m_Peer->RemoveStream(_stream->GetStream().get()); + } + } + } + else if (!strcmp(name, kFuncClose)) { + if (This->m_Peer) { + ret_val = This->m_Peer->Close(); + } + } + else if (!strcmp(name, kFuncGetStats)) { + if (This->m_Peer) { + // http://www.w3.org/TR/webrtc/#widl-RTCPeerConnection-getStats-void-MediaStreamTrack-selector-RTCStatsCallback-successCallback-RTCPeerConnectionErrorCallback-failureCallback + // Standard: void getStats (MediaStreamTrack? selector, RTCStatsCallback successCallback, RTCPeerConnectionErrorCallback failureCallback); + // Chrome: void getStats (RTCStatsCallback successCallback, RTCPeerConnectionErrorCallback failureCallback); + // Chrome issue: "selector" is nullable and not optional + + NPObject* _selector = Utils::VariantToObject((NPVariant*)&args[0]); + NPObjectAutoRef _successCallback(argCount > 1 ? Utils::VariantToObject((NPVariant*)&args[1]) : NULL); + NPObjectAutoRef _failureCallback(argCount > 2 ? Utils::VariantToObject((NPVariant*)&args[2]) : NULL); + + if (_selector || _successCallback || _failureCallback) { + MediaStreamTrack* _mediaStreamTrack = (MediaStreamTrack*)(MediaStreamTrack::IsInstanceOf(_selector) ? _selector : Utils::NPObjectUpCast(_selector)); + if (!MediaStreamTrack::IsInstanceOf(_selector)) { + _failureCallback = _successCallback; + _successCallback = _selector; + _selector = NULL; + _mediaStreamTrack = NULL; + } + _MediaStreamTrackBase* pSelector = NULL; + if (_mediaStreamTrack){ + pSelector = dynamic_cast<_MediaStreamTrackBase*>(_mediaStreamTrack->GetTrack().get()); + } + ret_val = This->m_Peer->GetStats( + pSelector, + [_successCallback, This](cpp11::shared_ptr<_RTCStatsReport> report) { + if (_successCallback){ + RTCStatsReport* _report; + NPError err = RTCStatsReport::CreateInstanceWithRef(This->m_npp, &_report); + if (err == NPERR_NO_ERROR) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_SUCCESS, _successCallback); + if (_cb) { + _report->SetStats(report); + _report->SetDispatcher(const_cast<_AsyncEventDispatcher*>(This->GetDispatcher())); + _cb->AddObject(_report); + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + RTCStatsReport::ReleaseInstance(&_report); + } + } + }, + [_failureCallback, This](cpp11::shared_ptr error) { + if (_failureCallback){ + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_ERROR, _failureCallback); + if (_cb) { + _cb->AddString((void*)error->c_str(), error->length()); + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + }); + if (!ret_val && _failureCallback) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_ERROR, _failureCallback); + if (_cb) { + std::string err("Global error"); + _cb->AddString((void*)err.c_str(), err.length()); + This->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + ret_val = true; + } + else { + ret_val = true; + } + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool PeerConnection::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId) || + !strcmp(name, kPropLocalDescription) || + !strcmp(name, kPropRemoteDescription) || + !strcmp(name, kPropSignalingState) || + !strcmp(name, kPropIceGatheringState) || + !strcmp(name, kPropIceConnectionState) || + !strcmp(name, kPropOnnegotiationneeded) || + !strcmp(name, kPropOnicecandidate) || + !strcmp(name, kPropOnsignalingstatechange) || + !strcmp(name, kPropOnaddstream) || + !strcmp(name, kPropOnremovestream) || + !strcmp(name, kPropOniceconnectionstatechange) + ; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool PeerConnection::SetProperty(NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) +{ + PeerConnection *This = static_cast(npobj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropLocalDescription)) { + // readonly + } + else if (!strcmp(name, kPropRemoteDescription)) { + // readonly + } + else if (!strcmp(name, kPropSignalingState)) { + // readonly + } + else if (!strcmp(name, kPropIceGatheringState)) { + // readonly + } + else if (!strcmp(name, kPropIceConnectionState)) { + // readonly + } + else if (!strcmp(name, kPropOnnegotiationneeded)) { + Utils::NPObjectSet(&This->m_callback_onnegotiationneeded, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropOnicecandidate)) { + Utils::NPObjectSet(&This->m_callback_onicecandidate, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropOnsignalingstatechange)) { + Utils::NPObjectSet(&This->m_callback_onsignalingstatechange, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropOnaddstream)) { + Utils::NPObjectSet(&This->m_callback_onaddstream, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropOnremovestream)) { + Utils::NPObjectSet(&This->m_callback_onremovestream, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + else if (!strcmp(name, kPropOniceconnectionstatechange)) { + Utils::NPObjectSet(&This->m_callback_oniceconnectionstatechange, Utils::VariantToObject((NPVariant*)value)); + ret_val = true; + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool PeerConnection::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + PeerConnection *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropLocalDescription)) { + if (This->m_Peer) { + cpp11::shared_ptr<_SessionDescription>sdp = This->m_Peer->LocalDescription(); + if (sdp) { + SessionDescription* _sdp; + NPError err = SessionDescription::CreateInstanceWithRef(This->m_npp, &_sdp); + if (err == NPERR_NO_ERROR) { + _sdp->SetSdp(sdp); + OBJECT_TO_NPVARIANT(_sdp, *result); + ret_val = true; + } + } + else { + NULL_TO_NPVARIANT(*result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropRemoteDescription)) { + if (This->m_Peer) { + cpp11::shared_ptr<_SessionDescription>sdp = This->m_Peer->RemoteDescription(); + if (sdp) { + SessionDescription* _sdp; + NPError err = SessionDescription::CreateInstanceWithRef(This->m_npp, &_sdp); + if (err == NPERR_NO_ERROR) { + _sdp->SetSdp(sdp); + OBJECT_TO_NPVARIANT(_sdp, *result); + ret_val = true; + } + } + else { + NULL_TO_NPVARIANT(*result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropSignalingState)) { + if (This->m_Peer) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Peer->SignalingState(), strlen(This->m_Peer->SignalingState())); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropIceGatheringState)) { + if (This->m_Peer) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Peer->IceGatheringState(), strlen(This->m_Peer->IceGatheringState())); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropIceConnectionState)) { + if (This->m_Peer) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Peer->IceConnectionState(), strlen(This->m_Peer->IceConnectionState())); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropOnnegotiationneeded)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onnegotiationneeded, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropOnicecandidate)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onicecandidate, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropOnsignalingstatechange)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onsignalingstatechange, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropOnaddstream)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onaddstream, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropOnremovestream)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_onremovestream, result) == NPERR_NO_ERROR); + } + else if (!strcmp(name, kPropOniceconnectionstatechange)) { + ret_val = (Utils::NPObjectToVariantAndRetain(This->m_callback_oniceconnectionstatechange, result) == NPERR_NO_ERROR); + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool PeerConnection::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} + +void PeerConnection::onnegotiationneeded() +{ + if (m_callback_onnegotiationneeded) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_ONNEGOTIATIONNEEDED, m_callback_onnegotiationneeded); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void PeerConnection::onicecandidate(cpp11::shared_ptr<_RTCPeerConnectionIceEvent> e) +{ + if (m_callback_onicecandidate) { + RTCPeerConnectionIceEvent* candidateEvent; + NPError err = RTCPeerConnectionIceEvent::CreateInstanceWithRef(m_npp, &candidateEvent); + if (err == NPERR_NO_ERROR) { + candidateEvent->SetEvent(e); + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_ONICECANDIDATE, m_callback_onicecandidate); + if (_cb) { + _cb->AddObject(candidateEvent); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + RTCPeerConnectionIceEvent::ReleaseInstance(&candidateEvent); + } + } +} + +void PeerConnection::onsignalingstatechange() +{ + if (m_callback_onsignalingstatechange) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_ONSIGNALINGSTATECHANGE, m_callback_onsignalingstatechange); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +void PeerConnection::onaddstream(cpp11::shared_ptr<_MediaStreamEvent> e) +{ + if (m_callback_onaddstream) { + MediaStreamEvent* _event; + NPError err = MediaStreamEvent::CreateInstanceWithRef(m_npp, &_event); + if (err == NPERR_NO_ERROR) { + _event->SetEvent(e); + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_ONADDSTREAM, m_callback_onaddstream); + if (_cb) { + _event->SetDispatcher(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + _cb->AddObject(_event); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + MediaStreamEvent::ReleaseInstance(&_event); + } + } +} + +void PeerConnection::onremovestream(cpp11::shared_ptr<_MediaStreamEvent> e) +{ + if (m_callback_onremovestream) { + MediaStreamEvent* _event; + NPError err = MediaStreamEvent::CreateInstanceWithRef(m_npp, &_event); + if (err == NPERR_NO_ERROR) { + _event->SetDispatcher(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + _event->SetEvent(e); + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_ONREMOVESTREAM, m_callback_onremovestream); + if (_cb) { + _cb->AddObject(_event); + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + MediaStreamEvent::ReleaseInstance(&_event); + } + } +} + +void PeerConnection::oniceconnectionstatechange() +{ + if (m_callback_oniceconnectionstatechange) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_ONICECONNECTIONSTATECHANGE, m_callback_oniceconnectionstatechange); + if (_cb) { + this->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } +} + +NPError PeerConnection::getStreams(bool remote, NPVariant* MediaStreams) +{ + if (!m_Peer) { + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + _AsyncEventDispatcher* dispatcher = dynamic_cast<_AsyncEventDispatcher*>(const_cast<_AsyncEventDispatcher*>(GetDispatcher())); + if (!dispatcher) { + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + + NPError err; + std::vector vect; + cpp11::shared_ptr<_Sequence<_MediaStream> > streams = remote ? m_Peer->GetRemoteStreams() : m_Peer->GetLocalStreams(); + if (streams) { + for (size_t i = 0; i < streams->values.size(); ++i) { + if (!streams->values[i]) { + continue; + } + MediaStream* _stream; + err = MediaStream::CreateInstanceWithRef(m_npp, &_stream); + if (err == NPERR_NO_ERROR) { + _stream->SetDispatcher(dispatcher); + _stream->SetStream(streams->values[i]); + + NPVariant var; + OBJECT_TO_NPVARIANT(_stream, var); + BrowserFuncs->retainobject(var.value.objectValue); // will be release by "NPVecClear()" + vect.push_back(var); + MediaStream::ReleaseInstance(&_stream); + } + } + } + + NPObject* arrayObj = NULL; + err = Utils::CreateJsArray(m_npp, vect, &arrayObj); + if (err == NPERR_NO_ERROR) { + OBJECT_TO_NPVARIANT(arrayObj, *MediaStreams); + } + + Utils::NPVecClear(vect); + + return err; +} \ No newline at end of file diff --git a/npapi/PeerConnection.h b/npapi/PeerConnection.h new file mode 100755 index 0000000..c1a5d41 --- /dev/null +++ b/npapi/PeerConnection.h @@ -0,0 +1,70 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_PEERCONNECTION_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_PEERCONNECTION_H_ + +#include "../common/_Config.h" +#include "../common/_PeerConnection.h" +#include "../common/_AsyncEvent.h" +#include "../common/_Common.h" + +#include "npapi-includes.h" + +class PeerConnection + : public NPObject + , public _AsyncEventRaiser + , public _UniqueObject +{ +public: + PeerConnection(NPP instance); + virtual ~PeerConnection(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(PeerConnection); + NPObjectImpl_NPObjectRelease(PeerConnection); + NPObjectImpl_IsInstanceOf(PeerConnection); + + NPError Init(NPObject* RTCConfiguration, NPObject* MediaConstraints); + +private: + // callbacks + void onnegotiationneeded(); + void onicecandidate(cpp11::shared_ptr<_RTCPeerConnectionIceEvent> e); + void onsignalingstatechange(); + void onaddstream(cpp11::shared_ptr<_MediaStreamEvent> stream); + void onremovestream(cpp11::shared_ptr<_MediaStreamEvent> stream); + void oniceconnectionstatechange(); + + NPError getStreams(bool remote, NPVariant* MediaStreams); + +private: + NPP m_npp; + cpp11::shared_ptr<_PeerConnection> m_Peer; + + // callbacks + NPObject* m_callback_onnegotiationneeded; + NPObject* m_callback_onicecandidate; + NPObject* m_callback_onsignalingstatechange; + NPObject* m_callback_onaddstream; + NPObject* m_callback_onremovestream; + NPObject* m_callback_oniceconnectionstatechange; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_PEERCONNECTION_H_ */ diff --git a/npapi/Plugin.cc b/npapi/Plugin.cc new file mode 100755 index 0000000..8d18e4a --- /dev/null +++ b/npapi/Plugin.cc @@ -0,0 +1,306 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Debug.h" +#include "../common/_AsyncEvent.h" +#include "../common/_Common.h" +#include "../common/_Utils.h" +#include "plugin.h" +#include "WebRTC.h" + +#define kPluginName "WebRTC plugin for Safari, Opera, Firefox and IE[" kPluginVersionString "]" +#define kPluginDescription kPluginName " (DBG Telecom)" + +NPNetscapeFuncs* BrowserFuncs = NULL; + +extern NPClass WebRTCClass; + +typedef struct PluginInstance { + NPP npp; + NPWindow window; + NPObject* object; +#if WE_UNDER_APPLE + CALayer *rootLayer; +#endif +} PluginInstance; + +NPError OSCALL +NP_Initialize(NPNetscapeFuncs* browserFuncs) +{ + /* Save the browser function table. */ + BrowserFuncs = browserFuncs; + + _Utils::Initialize(); + TakeFakePeerConnectionFactory(); + + return NPERR_NO_ERROR; +} + +NPError OSCALL +NP_GetEntryPoints(NPPluginFuncs* pluginFuncs) +{ + /* Check the size of the provided structure based on the offset of the + last member we need. */ + if (pluginFuncs->size < (offsetof(NPPluginFuncs, setvalue) + sizeof(void*))) { + CHECK_NPERR_RETURN(NPERR_INVALID_FUNCTABLE_ERROR); + } + + pluginFuncs->newp = NPP_New; + pluginFuncs->destroy = NPP_Destroy; + pluginFuncs->setwindow = NPP_SetWindow; + pluginFuncs->newstream = NPP_NewStream; + pluginFuncs->destroystream = NPP_DestroyStream; + pluginFuncs->asfile = NPP_StreamAsFile; + pluginFuncs->writeready = NPP_WriteReady; + pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write; + pluginFuncs->print = NPP_Print; + pluginFuncs->event = NPP_HandleEvent; + pluginFuncs->urlnotify = NPP_URLNotify; + pluginFuncs->getvalue = NPP_GetValue; + pluginFuncs->setvalue = NPP_SetValue; + + return NPERR_NO_ERROR; +} + +char* +NP_GetPluginVersion() +{ + return ((char*)kPluginVersionString); +} + +const char* +NP_GetMIMEDescription() +{ + return (kPluginMIMEType); +} + +NP_EXPORT(NPError) +NP_GetValue(void* future, NPPVariable aVariable, void* aValue) +{ + switch (aVariable) { + case NPPVpluginNameString: + *((char**)aValue) = (kPluginName); + break; + case NPPVpluginDescriptionString: + *((char**)aValue) = (kPluginDescription); + break; + default: + CHECK_NPERR_RETURN(NPERR_INVALID_PARAM); + } + return NPERR_NO_ERROR; +} + +NP_EXPORT(NPError) OSCALL +NP_Shutdown() +{ + ReleaseFakePeerConnectionFactory(); + + return NPERR_NO_ERROR; +} + +NPError +NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved) +{ + NPBool browserSupportsWindowless = false; + if (we_stricmp(kPluginMIMEType, pluginType)) { + WE_DEBUG_ERROR("'%s' not valid MIME type. Expected '%s'", pluginType, kPluginMIMEType); + CHECK_NPERR_RETURN(NPERR_INCOMPATIBLE_VERSION_ERROR); + } + + // Make sure we can render this plugin + BrowserFuncs->getvalue(instance, NPNVSupportsWindowless, &browserSupportsWindowless); + if (!browserSupportsWindowless) { + printf("Windowless mode not supported by the browser\n"); + } + +#if WE_UNDER_APPLE + // Ask the browser if it supports the Core Animation drawing model + NPBool supportsCoreAnimation; + if (BrowserFuncs->getvalue(instance, NPNVsupportsCoreAnimationBool, &supportsCoreAnimation) != NPERR_NO_ERROR) { + supportsCoreAnimation = FALSE; + } + + if (!supportsCoreAnimation) { + WE_DEBUG_ERROR("CoreAnimation not supported"); + CHECK_NPERR_RETURN(NPERR_INCOMPATIBLE_VERSION_ERROR); + } + + // If the browser supports the Core Animation drawing model, enable it. + BrowserFuncs->setvalue(instance, NPPVpluginDrawingModel, (void *)NPDrawingModelCoreAnimation); + + // If the browser supports the Cocoa event model, enable it. + NPBool supportsCocoa; + if (BrowserFuncs->getvalue(instance, NPNVsupportsCocoaBool, &supportsCocoa) != NPERR_NO_ERROR) { + supportsCocoa = FALSE; + } + + if (!supportsCocoa) { + WE_DEBUG_ERROR("Cocoa not supported...but not required"); + // return NPERR_INCOMPATIBLE_VERSION_ERROR; + } + else { + BrowserFuncs->setvalue(instance, NPPVpluginEventModel, (void *)NPEventModelCocoa); + } +#endif + + if (browserSupportsWindowless) { + bool bWindowed = true/*(instanceData->type == PluginType_WebRtc4npapi || instanceData->type == PluginType_Display)*/; + BrowserFuncs->setvalue(instance, NPPVpluginWindowBool, (void*)bWindowed); + } + + // set up our our instance data + PluginInstance *newInstance = (PluginInstance*)malloc(sizeof(PluginInstance)); + if (!newInstance) { + CHECK_NPERR_RETURN(NPERR_OUT_OF_MEMORY_ERROR); + } + memset(newInstance, 0, sizeof(PluginInstance)); + newInstance->npp = instance; + instance->pdata = newInstance; + + return NPERR_NO_ERROR; +} + +NPError +NPP_Destroy(NPP instance, NPSavedData** save) +{ + PluginInstance* pluginInstance = (PluginInstance*)(instance->pdata); + if (pluginInstance) { + if (pluginInstance->object) { + SafeReleaseNPObject(&pluginInstance->object); + } +#if WE_UNDER_APPLE + if (pluginInstance->rootLayer) { + [pluginInstance->rootLayer release], pluginInstance->rootLayer = NULL; + } +#endif + free(pluginInstance); + } + return NPERR_NO_ERROR; +} + +NPError +NPP_SetWindow(NPP instance, NPWindow* window) +{ + PluginInstance* pluginInstance = (PluginInstance*)(instance->pdata); + if (pluginInstance) { + pluginInstance->window = *window; + } + return NPERR_NO_ERROR; +} + +NPError +NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype) +{ + return NPERR_GENERIC_ERROR; +} + +NPError +NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) +{ + return NPERR_GENERIC_ERROR; +} + +int32_t +NPP_WriteReady(NPP instance, NPStream* stream) +{ + return 0; +} + +int32_t +NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer) +{ + return 0; +} + +void +NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) +{ + +} + +void +NPP_Print(NPP instance, NPPrint* platformPrint) +{ + +} + +int16_t +NPP_HandleEvent(NPP instance, void* event) +{ + // PluginInstance* pluginInstance = (PluginInstance*)(instance->pdata); + return 1; +} + +void +NPP_URLNotify(NPP instance, const char* URL, NPReason reason, void* notifyData) +{ + +} + +NPError +NPP_GetValue(NPP instance, NPPVariable variable, void *value) +{ + PluginInstance* pluginInstance = (PluginInstance*)(instance->pdata); + + switch (variable) { + default: { + return NPERR_GENERIC_ERROR; + } + case NPPVpluginNameString: { + *((char **)value) = kPluginName; + return NPERR_NO_ERROR; + } + case NPPVpluginDescriptionString: { + *((char **)value) = kPluginDescription; + return NPERR_NO_ERROR; + } +#if WE_UNDER_APPLE + case NPPVpluginCoreAnimationLayer: { + if (!pluginInstance->rootLayer) { + pluginInstance->rootLayer = [[CALayer layer] retain]; + pluginInstance->rootLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; + } + *(CALayer **)value = pluginInstance->rootLayer; + return NPERR_NO_ERROR; + } +#endif /* WE_UNDER_APPLE */ + case NPPVpluginScriptableNPObject: { + if (!pluginInstance->object) { + if (!(pluginInstance->object = BrowserFuncs->createobject(pluginInstance->npp, &WebRTCClass))) { + return NPERR_OUT_OF_MEMORY_ERROR; + } + } + WebRTC* webrtc = reinterpret_cast((WebRTC*)pluginInstance->object); +#if WE_UNDER_WINDOWS + if (webrtc) { + if (!webrtc->SetWindow(reinterpret_cast(pluginInstance->window.window))) { + return NPERR_GENERIC_ERROR; + } + } +#endif /* WE_UNDER_WINDOWS */ + +#if WE_UNDER_APPLE + if (webrtc) { + webrtc->SetRootLayer(pluginInstance->rootLayer); + } + /*if (pluginInstance->rootLayer) { + [pluginInstance->rootLayer setBounds: CGRectMake(pluginInstance->window.x, pluginInstance->window.y, pluginInstance->window.width, pluginInstance->window.height)]; + }*/ +#endif /* WE_UNDER_APPLE */ + + BrowserFuncs->retainobject(pluginInstance->object); + *(NPObject **)value = pluginInstance->object; + return NPERR_NO_ERROR; + } + case NPPVpluginNeedsXEmbed: + { + *((char *)value) = 1; + return NPERR_NO_ERROR; + } + } +} + +NPError +NPP_SetValue(NPP instance, NPNVariable variable, void *value) +{ + return NPERR_GENERIC_ERROR; +} + diff --git a/npapi/Plugin.h b/npapi/Plugin.h new file mode 100755 index 0000000..e476887 --- /dev/null +++ b/npapi/Plugin.h @@ -0,0 +1,57 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_PLUGIN_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_PLUGIN_H_ + +#include "../common/_Config.h" +#if WE_UNDER_WINDOWS +#include +#endif +#include "npapi-includes.h" + +#if !defined(NP_EXPORT) +#define NP_EXPORT(__type) __type +#endif + +#if !defined(OSCALL) +# if WE_UNDER_WINDOWS +# define OSCALL WINAPI +# else +# define OSCALL +# endif +#endif + +#if defined(__GNUC__) +#pragma GCC visibility push(default) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +NPError OSCALL NP_Initialize(NPNetscapeFuncs* aNPNFuncs); +NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pluginFuncs); +NPError OSCALL NP_Shutdown(); + +NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved); +NPError NPP_Destroy(NPP instance, NPSavedData** save); +NPError NPP_SetWindow(NPP instance, NPWindow* window); +NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype); +NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason); +int32_t NPP_WriteReady(NPP instance, NPStream* stream); +int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer); +void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname); +void NPP_Print(NPP instance, NPPrint* platformPrint); +int16_t NPP_HandleEvent(NPP instance, void* event); +void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, void* notifyData); +NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value); +NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value); + +#ifdef __cplusplus +} +#endif + +#if defined(__GNUC__) +#pragma GCC visibility pop +#endif + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_PLUGIN_H_ */ diff --git a/npapi/RTCIceCandidate.cc b/npapi/RTCIceCandidate.cc new file mode 100755 index 0000000..de492b0 --- /dev/null +++ b/npapi/RTCIceCandidate.cc @@ -0,0 +1,194 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "NPCommon.h" +#include "RTCIceCandidate.h" +#include "Utils.h" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +#define kPropCandidate "candidate" +#define kPropSdpMid "sdpMid" +#define kPropSdpMLineIndex "sdpMLineIndex" + +NPClass RTCIceCandidateClass = { + NP_CLASS_STRUCT_VERSION, + RTCIceCandidate::Allocate, + RTCIceCandidate::Deallocate, + RTCIceCandidate::Invalidate, + RTCIceCandidate::HasMethod, + RTCIceCandidate::Invoke, + RTCIceCandidate::InvokeDefault, + RTCIceCandidate::HasProperty, + RTCIceCandidate::GetProperty, + RTCIceCandidate::SetProperty, + RTCIceCandidate::RemoveProperty, + RTCIceCandidate::NPEnumeration, + RTCIceCandidate::Construct, +}; + +void RTCIceCandidate::Invalidate(NPObject *npobj) +{ +} + +bool RTCIceCandidate::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool RTCIceCandidate::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +RTCIceCandidate::RTCIceCandidate(NPP instance) + : m_npp(instance) + , m_Candidate(nullPtr) +{ + WE_DEBUG_INFO("RTCIceCandidate::NewInstance()"); +} + +RTCIceCandidate::~RTCIceCandidate() +{ + m_Candidate = nullPtr; +} + +NPObject* RTCIceCandidate::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new RTCIceCandidate(instance)); +} + +void RTCIceCandidate::Deallocate(NPObject* obj) +{ + delete (RTCIceCandidate*)obj; +} + +bool RTCIceCandidate::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = false; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCIceCandidate::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool RTCIceCandidate::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCIceCandidate::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId) || + !strcmp(name, kPropCandidate) || + !strcmp(name, kPropSdpMid) || + !strcmp(name, kPropSdpMLineIndex) + ; + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCIceCandidate::SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) +{ + // all properties are readonly + return false; +} + +bool RTCIceCandidate::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + RTCIceCandidate *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropCandidate)) { + if (This->m_Candidate) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Candidate->candidate(), strlen(This->m_Candidate->candidate())); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropSdpMid)) { + if (This->m_Candidate) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Candidate->sdpMid(), strlen(This->m_Candidate->sdpMid())); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropSdpMLineIndex)) { + if (This->m_Candidate) { + INT32_TO_NPVARIANT(This->m_Candidate->sdpMLineIndex(), *result); + ret_val = true; + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCIceCandidate::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} + +NPError RTCIceCandidate::Init(NPVariant* candidateInitDict) +{ + if (NPVARIANT_IS_STRING(*candidateInitDict) && candidateInitDict->value.stringValue.UTF8Characters && candidateInitDict->value.stringValue.UTF8Length) { + std::string strCandidate(candidateInitDict->value.stringValue.UTF8Characters, candidateInitDict->value.stringValue.UTF8Length); + m_Candidate = cpp11::shared_ptr<_RTCIceCandidate>(new _RTCIceCandidate(strCandidate.c_str())); + } + else if (NPVARIANT_IS_OBJECT(*candidateInitDict) && candidateInitDict->value.objectValue) { + NPObject* npObj = candidateInitDict->value.objectValue; + RTCIceCandidate* _candidateInitDict = (RTCIceCandidate*)(RTCIceCandidate::IsInstanceOf(npObj) ? npObj : Utils::NPObjectUpCast(npObj)); + if (!_candidateInitDict) { + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + + std::string strCandidate, strSdpMid; + NPError err; + CHECK_NPERR_RETURN(err = Utils::NPObjectGetPropString(m_npp, _candidateInitDict, "candidate", strCandidate)); + CHECK_NPERR_RETURN(err = Utils::NPObjectGetPropString(m_npp, _candidateInitDict, "sdpMid", strSdpMid)); + double doubleSdpMLineIndex; + CHECK_NPERR_RETURN(err = Utils::NPObjectGetPropNumber(m_npp, _candidateInitDict, "sdpMLineIndex", doubleSdpMLineIndex)); + + m_Candidate = cpp11::shared_ptr<_RTCIceCandidate>(new _RTCIceCandidate(strCandidate.c_str(), strSdpMid.c_str(), (unsigned short)doubleSdpMLineIndex)); + } + + if (!m_Candidate) { + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + + return NPERR_NO_ERROR; +} \ No newline at end of file diff --git a/npapi/RTCIceCandidate.h b/npapi/RTCIceCandidate.h new file mode 100755 index 0000000..cee3b46 --- /dev/null +++ b/npapi/RTCIceCandidate.h @@ -0,0 +1,52 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_RTCICECANDIDATE_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_RTCICECANDIDATE_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_RTCIceCandidate.h" + +#include "npapi-includes.h" + +class RTCIceCandidate + : public NPObject + , public _UniqueObject +{ +public: + RTCIceCandidate(NPP instance); + virtual ~RTCIceCandidate(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(RTCIceCandidate); + NPObjectImpl_NPObjectRelease(RTCIceCandidate); + NPObjectImpl_IsInstanceOf(RTCIceCandidate); + + WE_INLINE void SetCandidate(cpp11::shared_ptr<_RTCIceCandidate> & candidate) { m_Candidate = candidate; } + WE_INLINE cpp11::shared_ptr<_RTCIceCandidate> GetCandidate() { return m_Candidate; } + + NPError Init(NPVariant* candidateInitDict); + +private: + NPP m_npp; + cpp11::shared_ptr<_RTCIceCandidate> m_Candidate; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_RTCICECANDIDATE_H_ */ diff --git a/npapi/RTCPeerConnectionIceEvent.cc b/npapi/RTCPeerConnectionIceEvent.cc new file mode 100755 index 0000000..9855a10 --- /dev/null +++ b/npapi/RTCPeerConnectionIceEvent.cc @@ -0,0 +1,162 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "NPCommon.h" +#include "RTCIceCandidate.h" +#include "RTCPeerConnectionIceEvent.h" +#include "Utils.h" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +#define kPropCandidate "candidate" + +NPClass RTCPeerConnectionIceEventClass = { + NP_CLASS_STRUCT_VERSION, + RTCPeerConnectionIceEvent::Allocate, + RTCPeerConnectionIceEvent::Deallocate, + RTCPeerConnectionIceEvent::Invalidate, + RTCPeerConnectionIceEvent::HasMethod, + RTCPeerConnectionIceEvent::Invoke, + RTCPeerConnectionIceEvent::InvokeDefault, + RTCPeerConnectionIceEvent::HasProperty, + RTCPeerConnectionIceEvent::GetProperty, + RTCPeerConnectionIceEvent::SetProperty, + RTCPeerConnectionIceEvent::RemoveProperty, + RTCPeerConnectionIceEvent::NPEnumeration, + RTCPeerConnectionIceEvent::Construct, +}; + +void RTCPeerConnectionIceEvent::Invalidate(NPObject *npobj) +{ +} + +bool RTCPeerConnectionIceEvent::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool RTCPeerConnectionIceEvent::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +RTCPeerConnectionIceEvent::RTCPeerConnectionIceEvent(NPP instance) + : m_npp(instance) + , m_Event(nullPtr) +{ + WE_DEBUG_INFO("RTCPeerConnectionIceEvent::NewInstance()"); +} + +RTCPeerConnectionIceEvent::~RTCPeerConnectionIceEvent() +{ + m_Event = nullPtr; +} + +void RTCPeerConnectionIceEvent::SetEvent(cpp11::shared_ptr<_RTCPeerConnectionIceEvent> & e) +{ + m_Event = e; +} + +cpp11::shared_ptr<_RTCPeerConnectionIceEvent> RTCPeerConnectionIceEvent::GetEvent() +{ + return m_Event; +} +NPObject* RTCPeerConnectionIceEvent::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new RTCPeerConnectionIceEvent(instance)); +} + +void RTCPeerConnectionIceEvent::Deallocate(NPObject* obj) +{ + delete (RTCPeerConnectionIceEvent*)obj; +} + +bool RTCPeerConnectionIceEvent::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = false; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCPeerConnectionIceEvent::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool RTCPeerConnectionIceEvent::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCPeerConnectionIceEvent::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId) || !strcmp(name, kPropCandidate); + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCPeerConnectionIceEvent::SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) +{ + // all properties are readonly + return false; +} + +bool RTCPeerConnectionIceEvent::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + RTCPeerConnectionIceEvent *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropCandidate)) { + if (This->m_Event) { + if (This->m_Event->candidate) { + RTCIceCandidate* _candidate; + NPError err = RTCIceCandidate::CreateInstanceWithRef(This->m_npp, &_candidate); + if (err == NPERR_NO_ERROR) { + _candidate->SetCandidate(This->m_Event->candidate); + OBJECT_TO_NPVARIANT(_candidate, *result); + ret_val = true; + } + } + else { + NULL_TO_NPVARIANT(*result); + ret_val = true; + } + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCPeerConnectionIceEvent::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} diff --git a/npapi/RTCPeerConnectionIceEvent.h b/npapi/RTCPeerConnectionIceEvent.h new file mode 100755 index 0000000..4c86a39 --- /dev/null +++ b/npapi/RTCPeerConnectionIceEvent.h @@ -0,0 +1,49 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_RTCPEERCONNECTIONICEEVENT_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_RTCPEERCONNECTIONICEEVENT_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" + +#include "npapi-includes.h" + +class RTCPeerConnectionIceEvent + : public NPObject + , public _UniqueObject +{ +public: + RTCPeerConnectionIceEvent(NPP instance); + virtual ~RTCPeerConnectionIceEvent(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(RTCPeerConnectionIceEvent); + NPObjectImpl_NPObjectRelease(RTCPeerConnectionIceEvent); + NPObjectImpl_IsInstanceOf(RTCPeerConnectionIceEvent); + + void SetEvent(cpp11::shared_ptr<_RTCPeerConnectionIceEvent> & e); + cpp11::shared_ptr<_RTCPeerConnectionIceEvent> GetEvent(); + +private: + NPP m_npp; + cpp11::shared_ptr<_RTCPeerConnectionIceEvent> m_Event; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_RTCPEERCONNECTIONICEEVENT_H_ */ diff --git a/npapi/RTCStats.cc b/npapi/RTCStats.cc new file mode 100755 index 0000000..39e75e0 --- /dev/null +++ b/npapi/RTCStats.cc @@ -0,0 +1,213 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "NPCommon.h" +#include "RTCStats.h" +#include "Utils.h" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +#define kPropTimestamp "timestamp" +#define kPropType "type" +#define kPropId "id" + +#define kFuncNames "names" +#define kFuncStat "stat" + +NPClass RTCStatsClass = { + NP_CLASS_STRUCT_VERSION, + RTCStats::Allocate, + RTCStats::Deallocate, + RTCStats::Invalidate, + RTCStats::HasMethod, + RTCStats::Invoke, + RTCStats::InvokeDefault, + RTCStats::HasProperty, + RTCStats::GetProperty, + RTCStats::SetProperty, + RTCStats::RemoveProperty, + RTCStats::NPEnumeration, + RTCStats::Construct, +}; + +void RTCStats::Invalidate(NPObject *npobj) +{ +} + +bool RTCStats::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool RTCStats::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +RTCStats::RTCStats(NPP instance) + : m_npp(instance) + , m_Stats(nullPtr) +{ + WE_DEBUG_INFO("RTCStats::NewInstance()"); +} + +RTCStats::~RTCStats() +{ + SetDispatcher(NULL); + m_Stats = nullPtr; +} + +NPObject* RTCStats::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new RTCStats(instance)); +} + +void RTCStats::Deallocate(NPObject* obj) +{ + delete (RTCStats*)obj; +} + +bool RTCStats::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = !strcmp(name, kFuncNames) || + !strcmp(name, kFuncStat) + ; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCStats::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool RTCStats::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + RTCStats *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + if (!strcmp(name, kFuncNames)) { + if (This->m_Stats) { + NPError err; + std::vector vect; + std::map::iterator it = This->m_Stats->names.begin(); + for (; it != This->m_Stats->names.end(); ++it) { + NPVariant var; + NPUTF8* npStr = (NPUTF8*)Utils::MemDup((*it).first.c_str(), (*it).first.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, var); + vect.push_back(var); + } + } + + NPObject* arrayObj = NULL; + err = Utils::CreateJsArray(This->m_npp, vect, &arrayObj); + if (err == NPERR_NO_ERROR) { + OBJECT_TO_NPVARIANT(arrayObj, *result); + ret_val = true; + } + + vect.clear(); // do not call VecClear() to free strings + } + } + else if (!strcmp(name, kFuncStat)) { + if (This->m_Stats) { + if (argCount > 0 && NPVARIANT_IS_STRING(args[0]) && args[0].value.stringValue.UTF8Characters && args[0].value.stringValue.UTF8Length) { + std::string strName(args[0].value.stringValue.UTF8Characters, args[0].value.stringValue.UTF8Length); + std::map::iterator it = This->m_Stats->names.find(strName); + if (it != This->m_Stats->names.end()) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup((*it).second.c_str(), (*it).second.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + else { + NULL_TO_NPVARIANT(*result); + ret_val = true; + } + } + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCStats::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId) || + !strcmp(name, kPropTimestamp) || + !strcmp(name, kPropType) || + !strcmp(name, kPropId) + ; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCStats::SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) +{ + // all properties are readonly + return false; +} + + +bool RTCStats::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + RTCStats *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropTimestamp)) { + if (This->m_Stats) { + DOUBLE_TO_NPVARIANT(This->m_Stats->timestamp, *result); + ret_val = true; + } + } + else if (!strcmp(name, kPropType)) { + if (This->m_Stats) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Stats->type.c_str(), This->m_Stats->type.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropId)) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Stats->id.c_str(), This->m_Stats->id.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCStats::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} diff --git a/npapi/RTCStats.h b/npapi/RTCStats.h new file mode 100755 index 0000000..38dad28 --- /dev/null +++ b/npapi/RTCStats.h @@ -0,0 +1,51 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_RTCSTATS_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_RTCSTATS_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_AsyncEvent.h" + +#include "npapi-includes.h" + +class RTCStats + : public NPObject + , public _AsyncEventRaiser + , public _UniqueObject +{ +public: + RTCStats(NPP instance); + virtual ~RTCStats(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(RTCStats); + NPObjectImpl_NPObjectRelease(RTCStats); + NPObjectImpl_IsInstanceOf(RTCStats); + + WE_INLINE void SetStats(cpp11::shared_ptr<_RTCStats> & states) { m_Stats = states; } + WE_INLINE cpp11::shared_ptr<_RTCStats> GetStats() { return m_Stats; } + +private: + NPP m_npp; + cpp11::shared_ptr<_RTCStats> m_Stats; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_RTCSTATS_H_ */ diff --git a/npapi/RTCStatsReport.cc b/npapi/RTCStatsReport.cc new file mode 100755 index 0000000..75d8122 --- /dev/null +++ b/npapi/RTCStatsReport.cc @@ -0,0 +1,171 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "NPCommon.h" +#include "RTCStats.h" +#include "RTCStatsReport.h" +#include "Utils.h" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +#define kFuncResult "result" + +NPClass RTCStatsReportClass = { + NP_CLASS_STRUCT_VERSION, + RTCStatsReport::Allocate, + RTCStatsReport::Deallocate, + RTCStatsReport::Invalidate, + RTCStatsReport::HasMethod, + RTCStatsReport::Invoke, + RTCStatsReport::InvokeDefault, + RTCStatsReport::HasProperty, + RTCStatsReport::GetProperty, + RTCStatsReport::SetProperty, + RTCStatsReport::RemoveProperty, + RTCStatsReport::NPEnumeration, + RTCStatsReport::Construct, +}; + +void RTCStatsReport::Invalidate(NPObject *npobj) +{ +} + +bool RTCStatsReport::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool RTCStatsReport::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +RTCStatsReport::RTCStatsReport(NPP instance) + : m_npp(instance) + , m_Stats(nullPtr) +{ + WE_DEBUG_INFO("RTCStatsReport::NewInstance()"); +} + +RTCStatsReport::~RTCStatsReport() +{ + SetDispatcher(NULL); + m_Stats = nullPtr; +} + +NPObject* RTCStatsReport::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new RTCStatsReport(instance)); +} + +void RTCStatsReport::Deallocate(NPObject* obj) +{ + delete (RTCStatsReport*)obj; +} + +bool RTCStatsReport::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = !strcmp(name, kFuncResult); + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCStatsReport::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool RTCStatsReport::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + RTCStatsReport *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + if (!strcmp(name, kFuncResult)) { + if (This->m_Stats) { + _AsyncEventDispatcher* dispatcher = dynamic_cast<_AsyncEventDispatcher*>(const_cast<_AsyncEventDispatcher*>(This->GetDispatcher())); + if (dispatcher) { + NPError err; + std::vector vect; + std::map >::iterator it = This->m_Stats->values.begin(); + for (; it != This->m_Stats->values.end(); ++it) { + RTCStats* _stats; + err = RTCStats::CreateInstanceWithRef(This->m_npp, &_stats); + if (err == NPERR_NO_ERROR) { + _stats->SetStats((*it).second); + _stats->SetDispatcher(dispatcher); + + NPVariant var; + OBJECT_TO_NPVARIANT(_stats, var); + BrowserFuncs->retainobject(var.value.objectValue); // will be released by "NPVecClear()" + vect.push_back(var); + RTCStats::ReleaseInstance(&_stats); + } + } + + NPObject* arrayObj = NULL; + err = Utils::CreateJsArray(This->m_npp, vect, &arrayObj); + if (err == NPERR_NO_ERROR) { + OBJECT_TO_NPVARIANT(arrayObj, *result); + ret_val = true; + } + + Utils::NPVecClear(vect); + } + } + } + + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCStatsReport::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId); + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCStatsReport::SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) +{ + // all properties are readonly + return false; +} + +bool RTCStatsReport::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + RTCStatsReport *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool RTCStatsReport::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} diff --git a/npapi/RTCStatsReport.h b/npapi/RTCStatsReport.h new file mode 100755 index 0000000..3cc209d --- /dev/null +++ b/npapi/RTCStatsReport.h @@ -0,0 +1,51 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_RTCSTATSREPORT_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_RTCSTATSREPORT_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" +#include "../common/_AsyncEvent.h" + +#include "npapi-includes.h" + +class RTCStatsReport + : public NPObject + , public _AsyncEventRaiser + , public _UniqueObject +{ +public: + RTCStatsReport(NPP instance); + virtual ~RTCStatsReport(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(RTCStatsReport); + NPObjectImpl_NPObjectRelease(RTCStatsReport); + NPObjectImpl_IsInstanceOf(RTCStatsReport); + + WE_INLINE void SetStats(cpp11::shared_ptr<_RTCStatsReport> & states) { m_Stats = states; } + WE_INLINE cpp11::shared_ptr<_RTCStatsReport> GetStats() { return m_Stats; } + +private: + NPP m_npp; + cpp11::shared_ptr<_RTCStatsReport> m_Stats; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_RTCSTATSREPORT_H_ */ diff --git a/npapi/Release/webrtc-everywhere-npapi.res b/npapi/Release/webrtc-everywhere-npapi.res new file mode 100644 index 0000000000000000000000000000000000000000..44fb14e308bf0b37f3042a43903cfee2d71c3891 GIT binary patch literal 1052 zcmb7@!A{#i5QhJh96(%p11`vi9zdlKstAF^1qF~I6@nlFZWRz?A{i6Kh8CWrkI@(C zoA3^OgVJv%S;dJsfUUJ>XaAZ1pV?hWiWo01gMm5rJWqx7k6m60p!<280cMFj%hdN3CF|_MpaYX#Ud112$MZ&|_#CfQ zoIAH^>A-JKTZ?cXP|X1yY{P2(5;}UkDGIKz!|trTp)Tp%`_mfo+v&3YgnhT!;H12_ zPsdt7>k)bH(0`AzqSSS1{M_ul(({Pu(P^^!>%RBnIVVrR */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "NPCommon.h" +#include "SessionDescription.h" +#include "Utils.h" + +#define kPropType "type" +#define kPropSdp "sdp" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +NPClass SessionDescriptionClass = { + NP_CLASS_STRUCT_VERSION, + SessionDescription::Allocate, + SessionDescription::Deallocate, + SessionDescription::Invalidate, + SessionDescription::HasMethod, + SessionDescription::Invoke, + SessionDescription::InvokeDefault, + SessionDescription::HasProperty, + SessionDescription::GetProperty, + SessionDescription::SetProperty, + SessionDescription::RemoveProperty, + SessionDescription::NPEnumeration, + SessionDescription::Construct, +}; + +void SessionDescription::Invalidate(NPObject *npobj) +{ +} + +bool SessionDescription::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool SessionDescription::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +SessionDescription::SessionDescription(NPP instance) + : m_npp(instance) + , m_Sdp(nullPtr) +{ + WE_DEBUG_INFO("SessionDescription::NewInstance()"); +} + +SessionDescription::~SessionDescription() +{ + m_Sdp = nullPtr; +} + +NPObject* SessionDescription::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new SessionDescription(instance)); +} + +void SessionDescription::Deallocate(NPObject* obj) +{ + delete (SessionDescription*)obj; +} + +bool SessionDescription::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = false; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool SessionDescription::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool SessionDescription::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool SessionDescription::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId) || + !strcmp(name, kPropType) || + !strcmp(name, kPropSdp); + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool SessionDescription::SetProperty(NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) +{ + SessionDescription *This = static_cast(npobj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropType) && NPVARIANT_IS_STRING(*value)) { + const _Buffer* _sdp = This->m_Sdp ? This->m_Sdp->getSdp() : NULL; + std::shared_ptr<_SessionDescription> newSdp = std::make_shared<_SessionDescription>( + _sdp ? _sdp->getPtr() : NULL, + _sdp ? _sdp->getSize() : 0, + value->value.stringValue.UTF8Characters, + value->value.stringValue.UTF8Length); + This->m_Sdp = newSdp; + ret_val = true; + } + else if (!strcmp(name, kPropSdp) && NPVARIANT_IS_STRING(*value)) { + const _Buffer* _type = This->m_Sdp ? This->m_Sdp->getType() : NULL; + std::shared_ptr<_SessionDescription> newSdp = std::make_shared<_SessionDescription>( + value->value.stringValue.UTF8Characters, + value->value.stringValue.UTF8Length, + _type ? _type->getPtr() : NULL, + _type ? _type->getSize() : 0); + This->m_Sdp = newSdp; + ret_val = true; + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool SessionDescription::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + SessionDescription *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropType)) { + const _Buffer* pcType = This->m_Sdp ? This->m_Sdp->getType() : NULL; + if (pcType && pcType->getPtr()) { + char* npStr = (char*)Utils::MemDup(pcType->getPtr(), pcType->getSize()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropSdp)) { + const _Buffer* pcSdp = This->m_Sdp ? This->m_Sdp->getSdp() : NULL; + if (pcSdp && pcSdp->getPtr()) { + char* npStr = (char*)Utils::MemDup(pcSdp->getPtr(), pcSdp->getSize()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool SessionDescription::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} + +NPError SessionDescription::Init(NPVariant* RTCSessionDescriptionInit) +{ + NPObject* rtcSessionDescriptionInit = Utils::VariantToObject(RTCSessionDescriptionInit); + if (!rtcSessionDescriptionInit) { + CHECK_NPERR_RETURN(NPERR_INVALID_PARAM); + } + + std::string strType, strSdp; + + CHECK_NPERR_RETURN(Utils::NPObjectGetPropString(m_npp, rtcSessionDescriptionInit, "type", strType)); + CHECK_NPERR_RETURN(Utils::NPObjectGetPropString(m_npp, rtcSessionDescriptionInit, "sdp", strSdp)); + + m_Sdp = cpp11::shared_ptr<_SessionDescription>(new _SessionDescription( + strSdp.c_str(), strSdp.length(), + strType.c_str(), strType.length())); + + return NPERR_NO_ERROR; +} \ No newline at end of file diff --git a/npapi/SessionDescription.h b/npapi/SessionDescription.h new file mode 100755 index 0000000..6d7de48 --- /dev/null +++ b/npapi/SessionDescription.h @@ -0,0 +1,56 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_SESSIONDESCRIPTION_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_SESSIONDESCRIPTION_H_ + +#include "../common/_Config.h" +#include "../common/_SessionDescription.h" + +#if WE_UNDER_WINDOWS +#include +#endif + +#include "npapi-includes.h" + +class SessionDescription + : public NPObject + , public _UniqueObject +{ +public: + SessionDescription(NPP instance); + virtual ~SessionDescription(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(SessionDescription); + NPObjectImpl_NPObjectRelease(SessionDescription); + NPObjectImpl_IsInstanceOf(SessionDescription); + + WE_INLINE void SetSdp(cpp11::shared_ptr<_SessionDescription> & sdp) { m_Sdp = sdp; } + WE_INLINE cpp11::shared_ptr<_SessionDescription> GetSdp() { return m_Sdp; } + + NPError Init(NPVariant* RTCSessionDescriptionInit); + +private: + NPP m_npp; + cpp11::shared_ptr<_SessionDescription> m_Sdp; +}; + + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_SESSIONDESCRIPTION_H_ */ diff --git a/npapi/SourceInfo.cc b/npapi/SourceInfo.cc new file mode 100755 index 0000000..b40a7e8 --- /dev/null +++ b/npapi/SourceInfo.cc @@ -0,0 +1,192 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_Buffer.h" +#include "../common/_Debug.h" +#include "NPCommon.h" +#include "SourceInfo.h" +#include "Utils.h" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +#define kPropSourceId "sourceId" +#define kPropId "id" +#define kPropKind "kind" +#define kPropLabel "label" +#define kPropFacing "facing" + +NPClass SourceInfoClass = { + NP_CLASS_STRUCT_VERSION, + SourceInfo::Allocate, + SourceInfo::Deallocate, + SourceInfo::Invalidate, + SourceInfo::HasMethod, + SourceInfo::Invoke, + SourceInfo::InvokeDefault, + SourceInfo::HasProperty, + SourceInfo::GetProperty, + SourceInfo::SetProperty, + SourceInfo::RemoveProperty, + SourceInfo::NPEnumeration, + SourceInfo::Construct, +}; + +void SourceInfo::Invalidate(NPObject *npobj) +{ +} + +bool SourceInfo::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool SourceInfo::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +SourceInfo::SourceInfo(NPP instance) + : m_npp(instance) + , m_Info(nullPtr) +{ + WE_DEBUG_INFO("SourceInfo::NewInstance()"); +} + +SourceInfo::~SourceInfo() +{ + m_Info = nullPtr; +} + +void SourceInfo::SetInfo(cpp11::shared_ptr<_SourceInfo> & info) +{ + m_Info = info; +} + +cpp11::shared_ptr<_SourceInfo> SourceInfo::GetInfo() +{ + return m_Info; +} + +NPObject* SourceInfo::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new SourceInfo(instance)); +} + +void SourceInfo::Deallocate(NPObject* obj) +{ + delete (SourceInfo*)obj; +} + +bool SourceInfo::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = false; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool SourceInfo::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return true; +} + +bool SourceInfo::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + // SourceInfo *This = dynamic_cast((SourceInfo*)obj); + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool SourceInfo::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + + bool ret_val = !strcmp(name, kPropUniqueId) || + !strcmp(name, kPropSourceId) || + !strcmp(name, kPropId) || + !strcmp(name, kPropKind) || + !strcmp(name, kPropLabel) || + !strcmp(name, kPropFacing) + ; + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool SourceInfo::SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) +{ + // all properties are readonly + return false; +} + +bool SourceInfo::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + SourceInfo *This = static_cast(obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropUniqueId)) { + DOUBLE_TO_NPVARIANT(This->UniqueId(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropSourceId) || !strcmp(name, kPropId)) { + if (This->m_Info) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Info->sourceId.c_str(), This->m_Info->sourceId.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropKind)) { + if (This->m_Info) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Info->kind.c_str(), This->m_Info->kind.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropLabel) ) { + if (This->m_Info) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Info->label.c_str(), This->m_Info->label.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + else if (!strcmp(name, kPropFacing)) { + if (This->m_Info) { + NPUTF8* npStr = (NPUTF8*)Utils::MemDup(This->m_Info->facing.c_str(), This->m_Info->facing.length()); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool SourceInfo::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} diff --git a/npapi/SourceInfo.h b/npapi/SourceInfo.h new file mode 100755 index 0000000..75aac2d --- /dev/null +++ b/npapi/SourceInfo.h @@ -0,0 +1,49 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_SOURCEINFO_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_SOURCEINFO_H_ + +#include "../common/_Config.h" +#include "../common/_Common.h" + +#include "npapi-includes.h" + +class SourceInfo + : public NPObject + , public _UniqueObject +{ +public: + SourceInfo(NPP instance); + virtual ~SourceInfo(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + NPObjectImpl_CreateInstanceWithRef(SourceInfo); + NPObjectImpl_NPObjectRelease(SourceInfo); + NPObjectImpl_IsInstanceOf(SourceInfo); + + void SetInfo(cpp11::shared_ptr<_SourceInfo> & info); + cpp11::shared_ptr<_SourceInfo> GetInfo(); + +private: + NPP m_npp; + cpp11::shared_ptr<_SourceInfo> m_Info; +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_SOURCEINFO_H_ */ diff --git a/npapi/Utils.cc b/npapi/Utils.cc new file mode 100755 index 0000000..2c03c74 --- /dev/null +++ b/npapi/Utils.cc @@ -0,0 +1,480 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "Utils.h" +#include "NPCommon.h" + +#include "../common/_Debug.h" + +extern NPNetscapeFuncs* BrowserFuncs; + +void Utils::NPObjectSet(NPObject** dst, NPObject* src) +{ + Utils::NPObjectRelease(dst); + if (src) { + BrowserFuncs->retainobject(src); + *dst = src; + } +} + +NPError Utils::NPObjectRelease(NPObject** obj) +{ + if (obj && *obj) { + if ((*obj)->_class->structVersion != NP_CLASS_STRUCT_VERSION) { + // FIXME: Safari: fails to free JS callback when browser is refreshed (referenceCount = 1). + WE_DEBUG_ERROR("Trying to free invalid NPObject. structVersion=%d", (*obj)->_class->structVersion); + *obj = NULL; + return NPERR_INVALID_PLUGIN_ERROR; + } + SafeReleaseNPObject(obj); + } + return NPERR_NO_ERROR; +} + +NPError Utils::CreateInstanceWithRef(NPP npp, NPClass *aClass, NPObject** obj) +{ + if (!obj || !aClass) { + CHECK_NPERR_RETURN(NPERR_INVALID_PARAM); + } + if (!(*obj = BrowserFuncs->createobject(npp, aClass))) { + CHECK_NPERR_RETURN(NPERR_OUT_OF_MEMORY_ERROR); + } + return NPERR_NO_ERROR; +} + +NPError Utils::CreateJsArray(NPP npp, std::vector &vecValues, NPObject** arrayObj) +{ + if (!arrayObj || *arrayObj) { + CHECK_NPERR_RETURN(NPERR_INVALID_PARAM); + } + NPObject* npWindow = NULL; + NPError err; + + CHECK_NPERR_RETURN(err = BrowserFuncs->getvalue(npp, NPNVWindowNPObject, &npWindow)); + + NPVariant var; + bool bRet = BrowserFuncs->invoke(npp, npWindow, BrowserFuncs->getstringidentifier("Array"), NULL, 0, &var); + BrowserFuncs->releaseobject(npWindow); + if (!bRet || var.type != NPVariantType_Object || !var.value.objectValue) { + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + *arrayObj = var.value.objectValue; + + NPIdentifier idPush = BrowserFuncs->getstringidentifier("push"); + VOID_TO_NPVARIANT(var); + for (size_t i = 0; i < vecValues.size(); ++i) { + BrowserFuncs->invoke(npp, *arrayObj, idPush, &vecValues[i], 1, &var); + BrowserFuncs->releasevariantvalue(&var); + } + return NPERR_NO_ERROR; +} + +NPError Utils::CreateDocumentElementObject(NPP npp, NPObject** jsObj) +{ + if (!jsObj || *jsObj) { + CHECK_NPERR_RETURN(NPERR_INVALID_PARAM); + } + NPObject* npWindow = NULL; + NPError err; + NPVariant var; + + CHECK_NPERR_RETURN(err = BrowserFuncs->getvalue(npp, NPNVWindowNPObject, &npWindow)); + + + if (!BrowserFuncs->getproperty(npp,npWindow, BrowserFuncs->getstringidentifier("document"), &var) || !NPVARIANT_IS_OBJECT(var)) { + Utils::NPObjectRelease(&npWindow); + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + Utils::NPObjectRelease(&npWindow); + + NPObject* npDoc = var.value.objectValue; + NPVariant varObjectString; + STRINGZ_TO_NPVARIANT("object", varObjectString); + bool ret = BrowserFuncs->invoke(npp, npDoc, BrowserFuncs->getstringidentifier("createElement"), &varObjectString, 1, &var); + Utils::NPObjectRelease(&npDoc); + + if (ret && NPVARIANT_IS_OBJECT(var)) { + *jsObj = var.value.objectValue; + } + else { + BrowserFuncs->releasevariantvalue(&var); + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + + return NPERR_NO_ERROR; +} + +void Utils::NPVecClear(std::vector& vecVars) +{ + for (size_t i = 0; i < vecVars.size(); ++i) { + BrowserFuncs->releasevariantvalue(&vecVars[i]); + } + vecVars.clear(); +} + +// No retain() +NPObject* Utils::VariantToObject(NPVariant* var) +{ + if (var && var->type == NPVariantType_Object) { + return NPVARIANT_TO_OBJECT(*var); + } + return NULL; +} + +// No retain() +NPError Utils::NPObjectToVariant(NPObject* obj, NPVariant* var) +{ + if (!var) { + CHECK_NPERR_RETURN(NPERR_INVALID_PARAM); + } + if (obj) { + OBJECT_TO_NPVARIANT(obj, *var); + } + else { + NULL_TO_NPVARIANT(*var); + } + return NPERR_NO_ERROR; +} + +NPError Utils::NPObjectToVariantAndRetain(NPObject* obj, NPVariant* var) +{ + NPError err = Utils::NPObjectToVariant(obj, var); + if (err == NPERR_NO_ERROR) { + if (NPVARIANT_IS_OBJECT(*var) && var->value.objectValue) { + BrowserFuncs->retainobject(var->value.objectValue); + } + } + return err; +} + +std::string Utils::VariantToString(NPVariant* var) +{ + if (var && var->type == NPVariantType_String && var->value.stringValue.UTF8Characters && var->value.stringValue.UTF8Length) { + return std::string(var->value.stringValue.UTF8Characters, var->value.stringValue.UTF8Length); + } + return std::string(""); +} + +// Up to the caller to call releasevariantvalue(vecVars[i=0...n]). +NPError Utils::NPObjectToArray(NPP npp, NPObject* obj, std::vector& vecVars) +{ + if (!obj) { + CHECK_NPERR_RETURN(NPERR_INVALID_PARAM); + } + + NPVariant var; + NPError err; + + double length = 0; + CHECK_NPERR_RETURN(err = Utils::NPObjectGetPropNumber(npp, obj, "length", length)); + + char s[25]; + for (double i = 0; i < length; ++i) { + sprintf(s, "%d", (int32_t)i); + err = Utils::NPObjectGetProp(npp, obj, s, &var); + if (err != NPERR_NO_ERROR) { + Utils::NPVecClear(vecVars); + CHECK_NPERR_RETURN(err); + } + vecVars.push_back(var); // "var" will be released later using NPVectClear() + } + + return NPERR_NO_ERROR; +} + +// Up to the caller to call releasevariantvalue(retVal). +NPError Utils::NPObjectGetProp(NPP npp, NPObject* obj, const NPUTF8* name, NPVariant* var) +{ + if (!npp || !name || !var) { + CHECK_NPERR_RETURN(NPERR_INVALID_PARAM); + } + VOID_TO_NPVARIANT(*var); + NPIdentifier indentifier = BrowserFuncs->getstringidentifier(name); + if (!BrowserFuncs->getproperty(npp, obj, indentifier, var)) { + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + return NPERR_NO_ERROR; +} + +NPError Utils::NPObjectGetPropString(NPP npp, NPObject* obj, const NPUTF8* name, std::string& str) +{ + NPVariant var; + CHECK_NPERR_RETURN(Utils::NPObjectGetProp(npp, obj, name, &var)); + if (var.type != NPVariantType_String) { + BrowserFuncs->releasevariantvalue(&var); + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + str = std::string(var.value.stringValue.UTF8Characters, var.value.stringValue.UTF8Length); + BrowserFuncs->releasevariantvalue(&var); + return NPERR_NO_ERROR; +} + +NPError Utils::NPObjectGetPropNumber(NPP npp, NPObject* obj, const NPUTF8* name, double& number) +{ + NPVariant var; + CHECK_NPERR_RETURN(Utils::NPObjectGetProp(npp, obj, name, &var)); + + if (var.type == NPVariantType_Double) { + number = var.value.doubleValue; + } + else if (var.type == NPVariantType_Int32) { + number = var.value.intValue; + } + else { + BrowserFuncs->releasevariantvalue(&var); + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + BrowserFuncs->releasevariantvalue(&var); + return NPERR_NO_ERROR; +} + +NPError Utils::BuildMediaConstraints(NPP npp, NPObject* varConstraints, cpp11::shared_ptr<_MediaConstraints>& constraints) +{ + if (!varConstraints) { + return NPERR_NO_ERROR; + } + + if (!constraints) { + constraints = cpp11::shared_ptr<_MediaConstraints>(new _MediaConstraints()); + } + + NPError err; + NPVariant var; + NPIdentifier *identifiers = NULL; + uint32_t count = 0; + std::string strName, strVal; + + if (BrowserFuncs->enumerate(npp, varConstraints, &identifiers, &count) != true){ + CHECK_NPERR_RETURN(NPERR_GENERIC_ERROR); + } + + for (uint32_t i = 0; i < count; ++i) { + NPUTF8* propName = BrowserFuncs->utf8fromidentifier(identifiers[i]); + if (!propName) { + continue; + } + + err = Utils::NPObjectGetProp(npp, varConstraints, propName, &var); + if (err != NPERR_NO_ERROR) { + BrowserFuncs->memfree(identifiers); + BrowserFuncs->memfree(propName); + CHECK_NPERR_RETURN(err); + } + strName = std::string(propName); + + if (var.type == NPVariantType_Bool) { + strVal = var.value.boolValue ? "true" : "false"; + } + else if (var.type == NPVariantType_Int32) { + char s[25]; + sprintf(s, "%d", var.value.intValue); + strVal = std::string(s); + } + else if (var.type == NPVariantType_Double) { + char s[25]; + sprintf(s, "%lf", var.value.doubleValue); + strVal = std::string(s); + } + else if (var.type == NPVariantType_String) { + if (var.value.stringValue.UTF8Characters && var.value.stringValue.UTF8Length) { + strVal = std::string(var.value.stringValue.UTF8Characters, var.value.stringValue.UTF8Length); + } + else { + strVal = std::string(""); + } + } + else if (var.type == NPVariantType_Object && var.value.objectValue) { + err = Utils::BuildMediaConstraints(npp, var.value.objectValue, constraints); + goto next; + } + else { + goto next; + } + + constraints->insert(std::pair(strName, strVal)); + + next: + BrowserFuncs->memfree(propName); + BrowserFuncs->releasevariantvalue(&var); + } + + BrowserFuncs->memfree(identifiers); + + return NPERR_NO_ERROR; +} + +NPError Utils::BuildMediaStreamConstraints(NPP npp, NPObject* varConstraints, cpp11::shared_ptr<_MediaStreamConstraints> &constraints) +{ + if (!varConstraints) { + return NPERR_NO_ERROR; + } + + NPError err; + cpp11::shared_ptr<_MediaTrackConstraints> audio; + cpp11::shared_ptr<_MediaTrackConstraints> video; + NPVariant var; + + err = Utils::NPObjectGetProp(npp, varConstraints, "video", &var); + if (err == NPERR_NO_ERROR) { + if (var.type == NPVariantType_Bool) { + video = cpp11::shared_ptr<_MediaTrackConstraints>(new _MediaTrackConstraints(var.value.boolValue)); + } + else if (var.type == NPVariantType_Object && var.value.objectValue) { + cpp11::shared_ptr<_MediaConstraints> mandatory; + cpp11::shared_ptr<_MediaConstraints> optional; + NPObject* objVideo = var.value.objectValue; + NPVariant varVideo; + + err = Utils::NPObjectGetProp(npp, objVideo, "mandatory", &varVideo); + if (err == NPERR_NO_ERROR && varVideo.type == NPVariantType_Object) { + err = Utils::BuildMediaConstraints(npp, varVideo.value.objectValue, mandatory); + BrowserFuncs->releasevariantvalue(&varVideo); + } + if (err == NPERR_NO_ERROR) { + err = Utils::NPObjectGetProp(npp, objVideo, "optional", &varVideo); + if (err == NPERR_NO_ERROR && varVideo.type == NPVariantType_Object) { + err = Utils::BuildMediaConstraints(npp, varVideo.value.objectValue, optional); + BrowserFuncs->releasevariantvalue(&varVideo); + } + } + BrowserFuncs->releasevariantvalue(&var); + CHECK_NPERR_RETURN(err); + video = cpp11::shared_ptr<_MediaTrackConstraints>(new _MediaTrackConstraints(mandatory, optional)); + } + } + err = Utils::NPObjectGetProp(npp, varConstraints, "audio", &var); + if (err == NPERR_NO_ERROR) { + if (var.type == NPVariantType_Bool) { + audio = cpp11::shared_ptr<_MediaTrackConstraints>(new _MediaTrackConstraints(var.value.boolValue)); + } + else if (var.type == NPVariantType_Object && var.value.objectValue) { + cpp11::shared_ptr<_MediaConstraints> mandatory; + cpp11::shared_ptr<_MediaConstraints> optional; + NPObject* objAudio = var.value.objectValue; + NPVariant varAudio; + + err = Utils::NPObjectGetProp(npp, objAudio, "mandatory", &varAudio); + if (err == NPERR_NO_ERROR && varAudio.type == NPVariantType_Object) { + err = Utils::BuildMediaConstraints(npp, varAudio.value.objectValue, mandatory); + BrowserFuncs->releasevariantvalue(&varAudio); + } + if (err == NPERR_NO_ERROR) { + err = Utils::NPObjectGetProp(npp, objAudio, "optional", &varAudio); + if (err == NPERR_NO_ERROR && varAudio.type == NPVariantType_Object) { + err = Utils::BuildMediaConstraints(npp, varAudio.value.objectValue, optional); + BrowserFuncs->releasevariantvalue(&varAudio); + } + } + BrowserFuncs->releasevariantvalue(&var); + CHECK_NPERR_RETURN(err); + audio = cpp11::shared_ptr<_MediaTrackConstraints>(new _MediaTrackConstraints(mandatory, optional)); + } + } + + constraints = cpp11::shared_ptr<_MediaStreamConstraints>(new _MediaStreamConstraints(audio, video)); + return NPERR_NO_ERROR; +} + +NPError Utils::BuildMediaConstraintsObjs(NPP npp, NPObject* varConstraints, cpp11::shared_ptr<_MediaConstraintsObj> &constraints) +{ + if (!varConstraints) { + return NPERR_NO_ERROR; + } + + NPError err; + cpp11::shared_ptr<_MediaConstraints> mandatory; + cpp11::shared_ptr<_MediaConstraints> optional; + NPVariant var; + NPObject* obj; + err = Utils::NPObjectGetProp(npp, varConstraints, "mandatory", &var); + if (err == NPERR_NO_ERROR && (obj = Utils::VariantToObject(&var))) { + err = Utils::BuildMediaConstraints(npp, obj, mandatory); + BrowserFuncs->releasevariantvalue(&var); + CHECK_NPERR_RETURN(err); + } + err = Utils::NPObjectGetProp(npp, varConstraints, "optional", &var); + if (err == NPERR_NO_ERROR && (obj = Utils::VariantToObject(&var))) { + err = Utils::BuildMediaConstraints(npp, obj, optional); + BrowserFuncs->releasevariantvalue(&var); + CHECK_NPERR_RETURN(err); + } + + constraints = cpp11::shared_ptr<_MediaConstraintsObj>(new _MediaConstraintsObj(optional, mandatory)); + + return NPERR_NO_ERROR; +} + +NPError Utils::BuildRTCConfiguration(NPP npp, NPObject* varConfiguration, cpp11::shared_ptr<_RTCConfiguration> &configuration) +{ + if (!varConfiguration) { + return NPERR_NO_ERROR; + } + + configuration = cpp11::shared_ptr<_RTCConfiguration>(new _RTCConfiguration()); + + NPVariant varIceServers; + NPError err; + err = Utils::NPObjectGetProp(npp, varConfiguration, "iceServers", &varIceServers); + if (err == NPERR_NO_ERROR) { + std::vectorvectIceServers; + err = Utils::NPObjectToArray(npp, Utils::VariantToObject(&varIceServers), vectIceServers); + if (err == NPERR_NO_ERROR) { + NPObject* objServer; + for (unsigned i = 0; i < vectIceServers.size(); i++) { + objServer = Utils::VariantToObject(&vectIceServers[i]); + if (objServer) { + std::string uri, username, password; + err = Utils::NPObjectGetPropString(npp, objServer, "url", uri); + err = Utils::NPObjectGetPropString(npp, objServer, "username", username); + err = Utils::NPObjectGetPropString(npp, objServer, "credential", password); + configuration->iceServers.push_back(__RTCIceServer(uri, username, password)); + } + } + } + Utils::NPVecClear(vectIceServers); + } + + return NPERR_NO_ERROR; +} + +NPObject* Utils::NPObjectUpCast(NPObject* pObj) +{ + if (pObj) { + NPVariant var; + if (pObj->_class->getProperty(pObj, BrowserFuncs->getstringidentifier(kPropUniqueId), &var)) { + long uniqueId = -1; + if (var.type == NPVariantType_Double) { + uniqueId = (long)var.value.doubleValue; + } + else if (var.type == NPVariantType_Int32) { + uniqueId = var.value.intValue; + } + else return NULL; + return dynamic_cast(const_cast<_UniqueObject*>(_Utils::UniqueObjFind(uniqueId))); + } + } + return NULL; +} + +void* Utils::MemAlloc(size_t n) +{ + return BrowserFuncs->memalloc((uint32_t)n); +} + +void* Utils::MemDup(const void* mem, size_t n) +{ + void *ret = NULL; + if (mem && n){ + if ((ret = Utils::MemAlloc((n + 1)))){ + memcpy(ret, mem, n); + ((uint8_t*)ret)[n] = '\0'; + } + } + return ret; +} + +void Utils::MemFree(void** mem) +{ + if (mem && *mem) { + BrowserFuncs->memfree(*mem); + *mem = NULL; + } +} \ No newline at end of file diff --git a/npapi/Utils.h b/npapi/Utils.h new file mode 100755 index 0000000..03efff1 --- /dev/null +++ b/npapi/Utils.h @@ -0,0 +1,44 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_UTILS_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_UTILS_H_ + +#include "../common/_Config.h" +#include "../common/_Utils.h" +#include "../common/_MediaStreamConstraints.h" + +#include "npapi-includes.h" + +class Utils : public _Utils +{ +public: + static void NPObjectSet(NPObject** dst, NPObject* src); + static NPError NPObjectRelease(NPObject** obj); + + static NPError CreateInstanceWithRef(NPP npp, NPClass *aClass, NPObject** obj); + static NPError CreateJsArray(NPP npp, std::vector &vecValues, NPObject** arrayObj); + static NPError CreateDocumentElementObject(NPP npp, NPObject** jsObj); + static void NPVecClear(std::vector& vecVars); + + static NPObject* VariantToObject(NPVariant* var); + static NPError NPObjectToVariant(NPObject* obj, NPVariant* var); + static NPError NPObjectToVariantAndRetain(NPObject* obj, NPVariant* var); + static std::string VariantToString(NPVariant* var); + static NPError NPObjectToArray(NPP npp, NPObject* obj, std::vector& vecVars); + + static NPError NPObjectGetProp(NPP npp, NPObject* obj, const NPUTF8* name, NPVariant* var); + static NPError NPObjectGetPropString(NPP npp, NPObject* obj, const NPUTF8* name, std::string& str); + static NPError NPObjectGetPropNumber(NPP npp, NPObject* obj, const NPUTF8* name, double& number); + + static NPError BuildMediaConstraints(NPP npp, NPObject* varConstraints, cpp11::shared_ptr<_MediaConstraints>& constraints); + static NPError BuildMediaStreamConstraints(NPP npp, NPObject* varConstraints, cpp11::shared_ptr<_MediaStreamConstraints> &constraints); + static NPError BuildMediaConstraintsObjs(NPP npp, NPObject* varConstraints, cpp11::shared_ptr<_MediaConstraintsObj> &constraints); + static NPError BuildRTCConfiguration(NPP npp, NPObject* varConfiguration, cpp11::shared_ptr<_RTCConfiguration> &configuration); + + static NPObject* NPObjectUpCast(NPObject* pObj); + + static void* MemAlloc(size_t n); + static void* MemDup(const void* mem, size_t n); + static void MemFree(void** mem); +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_UTILS_H_ */ diff --git a/npapi/WebRTC.cc b/npapi/WebRTC.cc new file mode 100755 index 0000000..2bb9121 --- /dev/null +++ b/npapi/WebRTC.cc @@ -0,0 +1,462 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Utils.h" +#include "../common/_NavigatorUserMedia.h" +#include "../common/_Debug.h" +#include "WebRTC.h" +#include "MediaStream.h" +#include "SessionDescription.h" +#include "PeerConnection.h" +#include "RTCIceCandidate.h" +#include "BrowserCallback.h" +#include "MediaStreamTrack.h" +#include "NPCommon.h" +#include "Utils.h" +#if WE_UNDER_WINDOWS +#include +#endif + +#define kPropVersion "versionName" +#define kPropSrc "src" +#define kPropVideoWidth "videoWidth" +#define kPropVideoHeight "videoHeight" +#define kPropIsWebRtcPlugin "isWebRtcPlugin" + +#define kFuncGetUserMedia "getUserMedia" +#define kFuncCreateSessionDescription "createSessionDescription" +#define kFuncCreatePeerConnection "createPeerConnection" +#define kFuncCreateIceCandidate "createIceCandidate" +#define kFuncCreateMediaStreamTrack "createMediaStreamTrack" +#define kFuncCreateDisplay "createDisplay" +#define kFuncBindEventListener "bindEventListener" +#define kFuncAddEventListener "addEventListener" +#define kFuncGetSources "getSources" +#define kFuncFillImageData "fillImageData" + +extern NPNetscapeFuncs* BrowserFuncs; +extern const char* kPluginVersion; + +extern NPClass SessionDescriptionClass; +extern NPClass MediaStreamClass; + +NPClass WebRTCClass = { + NP_CLASS_STRUCT_VERSION, + WebRTC::Allocate, + WebRTC::Deallocate, + WebRTC::Invalidate, + WebRTC::HasMethod, + WebRTC::Invoke, + WebRTC::InvokeDefault, + WebRTC::HasProperty, + WebRTC::GetProperty, + WebRTC::SetProperty, + WebRTC::RemoveProperty, + WebRTC::NPEnumeration, + WebRTC::Construct, +}; + +void WebRTC::Invalidate(NPObject *npobj) +{ +} + +bool WebRTC::RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +bool WebRTC::Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +WebRTC::WebRTC(NPP instance) + : _AsyncEventDispatcher() + , _AsyncEventRaiser() + , _RTCDisplay() + , m_npp(instance) +#if WE_UNDER_APPLE + , m_pRootLayer(NULL) +#endif + , m_pTempVideoBuff(NULL) +{ + WE_DEBUG_INFO("WebRTC::NewInstance()"); +} + +WebRTC::~WebRTC() +{ + for (size_t i = 0; i < m_callbacks_onplay.size(); ++i) { + Utils::NPObjectRelease(&m_callbacks_onplay[i]); + } + m_callbacks_onplay.clear(); + StopVideoRenderer(); + SetDispatcher(NULL); + SafeDelete(&m_pTempVideoBuff); +#if WE_UNDER_APPLE + SetRootLayer(NULL); +#endif + + WE_DEBUG_INFO("WebRTC::~WebRTC"); +} + +NPObject* WebRTC::Allocate(NPP instance, NPClass* npclass) +{ + return (NPObject*)(new WebRTC(instance)); +} + +void WebRTC::Deallocate(NPObject* obj) +{ + delete (WebRTC*)obj; +} + +bool WebRTC::HasMethod(NPObject* obj, NPIdentifier methodName) +{ + char* name = BrowserFuncs->utf8fromidentifier(methodName); + + bool ret_val = + !strcmp(name, kFuncGetUserMedia) || + !strcmp(name, kFuncCreateSessionDescription) || + !strcmp(name, kFuncCreatePeerConnection) || + !strcmp(name, kFuncCreateIceCandidate) || + !strcmp(name, kFuncCreateMediaStreamTrack) || + !strcmp(name, kFuncCreateDisplay) || + !strcmp(name, kFuncBindEventListener) || + !strcmp(name, kFuncAddEventListener) || + !strcmp(name, kFuncGetSources) || + !strcmp(name, kFuncFillImageData) + ; + BrowserFuncs->memfree(name); + return ret_val; +} + +bool WebRTC::InvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return false; +} + +bool WebRTC::Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + WebRTC *This = reinterpret_cast((WebRTC*)obj); + char* name = BrowserFuncs->utf8fromidentifier(methodName); + bool ret_val = false; + if (!name) { + return ret_val; + } + + if (!strcmp(name, kFuncGetUserMedia)) { + NPObjectAutoRef constraints(argCount > 0 ? Utils::VariantToObject((NPVariant*)&args[0]) : NULL); + NPObjectAutoRef successCallback(argCount > 1 ? Utils::VariantToObject((NPVariant*)&args[1]) : NULL); + NPObjectAutoRef errorCallback(argCount > 2 ? Utils::VariantToObject((NPVariant*)&args[2]) : NULL); + + cpp11::shared_ptr<_MediaStreamConstraints> mediaStreamConstraints; + + ret_val = (Utils::BuildMediaStreamConstraints(This->m_npp, constraints, mediaStreamConstraints) == NPERR_NO_ERROR); + if (ret_val) { + _NavigatorUserMedia::getUserMedia( + mediaStreamConstraints.get(), + [successCallback, This](cpp11::shared_ptr<_MediaStream> stream) { + if (successCallback) { + MediaStream* _stream; + NPError err = MediaStream::CreateInstanceWithRef(This->m_npp, &_stream); + if (err == NPERR_NO_ERROR) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_GETUSERMEDIA_SUCESS, successCallback); + if (_cb) { + _stream->SetStream(stream); + _stream->SetDispatcher(This); + _cb->AddObject(_stream); + dynamic_cast<_AsyncEventDispatcher*>(This)->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + MediaStream::ReleaseInstance(&_stream); + } + } + }, + [errorCallback, This](cpp11::shared_ptr<_NavigatorUserMediaError> e) { + if (errorCallback) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_GETUSERMEDIA_ERROR, errorCallback); + if (_cb) { + _cb->AddString((void*)e->constraintName.c_str(), e->constraintName.length()); + dynamic_cast<_AsyncEventDispatcher*>(This)->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + } + ); + } + } + else if (!strcmp(name, kFuncCreateSessionDescription)) { + if (argCount > 0) { + SessionDescription* sdp; + NPError err = SessionDescription::CreateInstanceWithRef(This->m_npp, &sdp); + if (err == NPERR_NO_ERROR) { + if ((err = sdp->Init((NPVariant*)&args[0])) == NPERR_NO_ERROR) { + OBJECT_TO_NPVARIANT(sdp, *result); sdp = NULL, ret_val = true; + } + SessionDescription::ReleaseInstance(&sdp); + } + } + } + else if (!strcmp(name, kFuncCreatePeerConnection)) { + NPObject* RTCConfiguration = argCount > 0 ? Utils::VariantToObject((NPVariant*)&args[0]) : NULL; + NPObject* MediaConstraints = argCount > 1 ? Utils::VariantToObject((NPVariant*)&args[1]) : NULL; + PeerConnection* pc; + NPError err = PeerConnection::CreateInstanceWithRef(This->m_npp, &pc); + if (err == NPERR_NO_ERROR) { + if ((err = pc->Init(RTCConfiguration, MediaConstraints)) == NPERR_NO_ERROR) { + pc->SetDispatcher(dynamic_cast<_AsyncEventDispatcher*>(This)); + OBJECT_TO_NPVARIANT(pc, *result); pc = NULL, ret_val = true; + } + PeerConnection::ReleaseInstance(&pc); + } + } + else if (!strcmp(name, kFuncCreateIceCandidate)) { + if (argCount > 0) { + RTCIceCandidate* cand; + NPError err = RTCIceCandidate::CreateInstanceWithRef(This->m_npp, &cand); + if (err == NPERR_NO_ERROR) { + if ((err = cand->Init((NPVariant*)&args[0])) == NPERR_NO_ERROR) { + OBJECT_TO_NPVARIANT(cand, *result); cand = NULL, ret_val = true; + } + RTCIceCandidate::ReleaseInstance(&cand); + } + } + } + else if (!strcmp(name, kFuncCreateMediaStreamTrack)) { + MediaStreamTrack* track; + NPError err = MediaStreamTrack::CreateInstanceWithRef(This->m_npp, &track); + if (err == NPERR_NO_ERROR) { + OBJECT_TO_NPVARIANT(track, *result); track = NULL, ret_val = true; + MediaStreamTrack::ReleaseInstance(&track); + } + } + else if (!strcmp(name, kFuncCreateDisplay)) { + NPObject* jsObj = NULL; + NPError err = Utils::CreateDocumentElementObject(This->m_npp, &jsObj); + if (err == NPERR_NO_ERROR) { + NPVariant val; + STRINGZ_TO_NPVARIANT("application/webrtc-everywhere", val); + ret_val = jsObj->_class->setProperty(jsObj, BrowserFuncs->getstringidentifier("type"), &val); + if (ret_val) { + OBJECT_TO_NPVARIANT(jsObj, *result); + } + else { + Utils::NPObjectRelease(&jsObj); + } + } + } + else if (!strcmp(name, kFuncBindEventListener) || !strcmp(name, kFuncAddEventListener)) { + if (argCount > 1 && NPVARIANT_IS_STRING(args[0])) { + if (args[0].value.stringValue.UTF8Length == 4 && !strncmp(args[0].value.stringValue.UTF8Characters, "play", 4)) { + NPObject* callback = NULL; + Utils::NPObjectSet(&callback, Utils::VariantToObject((NPVariant*)&args[1])); + if (callback) { + ret_val = true; + This->m_callbacks_onplay.push_back(callback); + } + } + } + } + else if (!strcmp(name, kFuncGetSources)) { + NPObjectAutoRef successCallback(argCount > 0 ? Utils::VariantToObject((NPVariant*)&args[0]) : NULL); + if (successCallback) { + NPObject* sources = NULL; + NPError err = MediaStreamTrack::getSources(This->m_npp, This, &sources); + if (err == NPERR_NO_ERROR) { + BrowserCallback* _cb = new BrowserCallback(This->m_npp, WM_SUCCESS, successCallback); + if (_cb) { + _cb->AddObject(sources); + dynamic_cast<_AsyncEventDispatcher*>(This)->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + ret_val = true; + } + } + Utils::NPObjectRelease(&sources); + } + else { + ret_val = true; + } + } + else if (!strcmp(name, kFuncFillImageData)) { + if (argCount > 0 && NPVARIANT_IS_OBJECT(args[0]) && args[0].value.objectValue) { + NPError err; + + int videoWidth = This->GetVideoWidth(); + int videoHeight = This->GetVideoHeight(); + + if (videoHeight > 0 && videoWidth > 0) { + double width = 0, height = 0; + NPVariant varData; + err = Utils::NPObjectGetProp(This->m_npp, args[0].value.objectValue, "data", &varData); + if (err == NPERR_NO_ERROR) { + err = Utils::NPObjectGetPropNumber(This->m_npp, args[0].value.objectValue, "width", width); + } + if (err == NPERR_NO_ERROR) { + err = Utils::NPObjectGetPropNumber(This->m_npp, args[0].value.objectValue, "height", height); + } + + if (err == NPERR_NO_ERROR && NPVARIANT_IS_OBJECT(varData) && varData.value.objectValue && (int)width == videoWidth && (int)height == videoHeight) { + size_t videoSize = (videoWidth * videoHeight * 4); + + if (!This->m_pTempVideoBuff || This->m_pTempVideoBuff->getSize() < videoSize){ + SafeDelete(&This->m_pTempVideoBuff); + if ((_Buffer::New(NULL, videoSize, &This->m_pTempVideoBuff))) { + err = NPERR_OUT_OF_MEMORY_ERROR; + } + } + + if (err == NPERR_NO_ERROR) { + if (This->CopyFromFrame(const_cast(This->m_pTempVideoBuff->getPtr()), videoSize) != videoSize) { + memset(const_cast(This->m_pTempVideoBuff->getPtr()), 0, videoSize); + } + + char s[25]; + const uint8_t* imageDataPtr = (const uint8_t*)This->m_pTempVideoBuff->getPtr(); + NPVariant var; + long index; + for (long x = 0; x < width; ++x) { + for (long y = 0; y < height; ++y) { + index = (long)(x + y * width) * 4; + for (long comp = 0; comp < 4; ++comp) { // (a, r, g, b) -> (r, g, b, a) + sprintf(s, "%ld", (int32_t)index + comp); + INT32_TO_NPVARIANT(imageDataPtr[index + ((comp + 0) & 3)], var); + if (!(ret_val = varData.value.objectValue->_class->setProperty(varData.value.objectValue, BrowserFuncs->getstringidentifier(s), &var))) { + break; + } + //if (!(ret_val = BrowserFuncs->setproperty(This->m_npp, varData.value.objectValue, BrowserFuncs->getstringidentifier(s), &var))) { + //break; + //} + } + } + } + } + } + } + } + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool WebRTC::HasProperty(NPObject* obj, NPIdentifier propertyName) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = !strcmp(name, kPropVersion) || + !strcmp(name, kPropSrc) || + !strcmp(name, kPropVideoWidth) || + !strcmp(name, kPropVideoHeight) || + !strcmp(name, kPropIsWebRtcPlugin); + BrowserFuncs->memfree(name); + return ret_val; +} + +bool WebRTC::GetProperty(NPObject* obj, NPIdentifier propertyName, NPVariant* result) +{ + WebRTC *This = reinterpret_cast((WebRTC*)obj); + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropVersion)) { + char* npStr = (char*)Utils::MemDup(kPluginVersionString, strlen(kPluginVersionString)); + if (npStr) { + STRINGZ_TO_NPVARIANT(npStr, *result); + ret_val = true; + } + } + else if (!strcmp(name, kPropSrc)) { + VOID_TO_NPVARIANT(*result); + ret_val = true; + } + else if (!strcmp(name, kPropVideoWidth)) { + INT32_TO_NPVARIANT(This->GetVideoWidth(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropVideoHeight)) { + INT32_TO_NPVARIANT(This->GetVideoHeight(), *result); + ret_val = true; + } + else if (!strcmp(name, kPropIsWebRtcPlugin)) { + BOOLEAN_TO_NPVARIANT(true, *result); + ret_val = true; + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool WebRTC::SetProperty(NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) +{ + char* name = BrowserFuncs->utf8fromidentifier(propertyName); + WebRTC *This = reinterpret_cast((WebRTC*)npobj); + bool ret_val = false; + + if (!name) { + return ret_val; + } + + if (!strcmp(name, kPropSrc)) { + NPObject* npObj = Utils::VariantToObject((NPVariant*)value); + MediaStream* _mediaStream = (MediaStream*)(MediaStream::IsInstanceOf(npObj) ? npObj : Utils::NPObjectUpCast(npObj)); + if (_mediaStream) { + cpp11::shared_ptr<_MediaStream> stream = _mediaStream->GetStream(); + if (stream) { + This->StartVideoRenderer(stream->GetVideoTrack()); + } + } + else { + This->StopVideoRenderer(); + } + ret_val = true; + } + + BrowserFuncs->memfree(name); + return ret_val; +} + +bool WebRTC::NPEnumeration(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} + + +// +// _RTCDisplay implementation +// +#if WE_UNDER_WINDOWS +HWND WebRTC::Handle() +{ + return reinterpret_cast(GetWindowHandle()); +} +#elif WE_UNDER_APPLE +CALayer* WebRTC::Layer() +{ + return m_pRootLayer; +} +#endif + + + +// _RTCDisplay::OnStartVideoRenderer() implementation +void WebRTC::OnStartVideoRenderer() +{ + if (m_callbacks_onplay.size()) { + for (size_t i = 0; i < m_callbacks_onplay.size(); ++i) { + BrowserCallback* _cb = new BrowserCallback(m_npp, WM_SUCCESS, m_callbacks_onplay[i]); + if (_cb) { + _cb->AddObject(this); // not part of the standard: no arg to the callback + dynamic_cast<_AsyncEventDispatcher*>(this)->RaiseCallback(_cb); + SafeReleaseObject(&_cb); + } + } + } +} + +// _RTCDisplay::OnStopVideoRenderer() implementation +void WebRTC::OnStopVideoRenderer() +{ + +} diff --git a/npapi/WebRTC.h b/npapi/WebRTC.h new file mode 100755 index 0000000..9ea9ac7 --- /dev/null +++ b/npapi/WebRTC.h @@ -0,0 +1,74 @@ +/* Copyright(C) 2014 Sarandogou */ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_WEBRTC_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_WEBRTC_H_ + +#include "../common/_Config.h" +#include "../common/_AsyncEvent.h" +#include "../common/_RTCDisplay.h" +#include "../common/_Common.h" +#include "../common/_Buffer.h" + +#if WE_UNDER_APPLE +#include +#include +#endif + +#include "npapi-includes.h" + +class WebRTC + : public NPObject + , public _AsyncEventDispatcher + , public _AsyncEventRaiser + , public _RTCDisplay + , public _UniqueObject +{ +public: + WebRTC(NPP instance); + virtual ~WebRTC(); + +public: + static NPObject* Allocate(NPP instance, NPClass* npclass); + static void Deallocate(NPObject* obj); + static bool HasMethod(NPObject* obj, NPIdentifier methodName); + static bool InvokeDefault(NPObject* obj, const NPVariant* args, + uint32_t argCount, NPVariant* result); + static bool Invoke(NPObject* obj, NPIdentifier methodName, + const NPVariant* args, uint32_t argCount, + NPVariant* result); + static bool HasProperty(NPObject* obj, NPIdentifier propertyName); + static bool GetProperty(NPObject* obj, NPIdentifier propertyName, + NPVariant* result); + static bool SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); + static bool RemoveProperty(NPObject *npobj, NPIdentifier name); + static bool NPEnumeration(NPObject *npobj, NPIdentifier **value, + uint32_t *count); + static void Invalidate(NPObject *npobj); + static bool Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); + + // _RTCDisplay implementation +#if WE_UNDER_WINDOWS + virtual HWND Handle(); +#elif WE_UNDER_APPLE + virtual CALayer *Layer(); +#endif + virtual void OnStartVideoRenderer(); + virtual void OnStopVideoRenderer(); + + // _BrowserObject implementation + BrowserObjectImpl_NPObject(); + +#if WE_UNDER_APPLE + CALayer * rootLayer() { return m_pRootLayer; } + void SetRootLayer(CALayer *rootLayer) { if (m_pRootLayer) { [m_pRootLayer release], m_pRootLayer = NULL; } if (rootLayer) { m_pRootLayer = [rootLayer retain]; } } +#endif + +private: + NPP m_npp; + _Buffer *m_pTempVideoBuff; + std::vector m_callbacks_onplay; +#if WE_UNDER_APPLE + CALayer *m_pRootLayer; +#endif +}; + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_WEBRTC_H_ */ diff --git a/npapi/dllmain.cc b/npapi/dllmain.cc new file mode 100755 index 0000000..c7a0727 --- /dev/null +++ b/npapi/dllmain.cc @@ -0,0 +1,39 @@ +/* Copyright(C) 2014 Sarandogou */ +#include "../common/_Config.h" +#include "../common/_Utils.h" + +# include +#include + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ +#if 1 + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH: + { + //CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + _Utils::Initialize(); + break; + } + case DLL_PROCESS_DETACH: + { + _Utils::DeInitialize(); + //CoUninitialize(); + break; + } + case DLL_THREAD_ATTACH: + { + break; + } + case DLL_THREAD_DETACH: + { + break; + } + } +#endif + return TRUE; +} + diff --git a/npapi/npapi-includes.h b/npapi/npapi-includes.h new file mode 100755 index 0000000..8239ca1 --- /dev/null +++ b/npapi/npapi-includes.h @@ -0,0 +1,15 @@ +#ifndef _WEBRTC_EVERYWHERE_NPAPI_INCLUDES_H_ +#define _WEBRTC_EVERYWHERE_NPAPI_INCLUDES_H_ + +#include "../common/_Config.h" + +#if WE_UNDER_APPLE +#include +#include +#include +#else +#include "npapi-sdk/headers/npapi.h" +#include "npapi-sdk/headers/npfunctions.h" +#endif + +#endif /* _WEBRTC_EVERYWHERE_NPAPI_INCLUDES_H_ */ \ No newline at end of file diff --git a/npapi/resource.h b/npapi/resource.h new file mode 100755 index 0000000..bacb36d --- /dev/null +++ b/npapi/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by webrtc-everywhere-npapi.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/npapi/webrtc-everywhere-npapi.aps b/npapi/webrtc-everywhere-npapi.aps new file mode 100755 index 0000000000000000000000000000000000000000..85c5c42f00dc59d4b210c3d174724d1beff4fbe7 GIT binary patch literal 20296 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 Vtx?Un4)qT3#+~k`YCdSr{{fxH2ABW< literal 0 HcmV?d00001 diff --git a/npapi/webrtc-everywhere-npapi.def b/npapi/webrtc-everywhere-npapi.def new file mode 100755 index 0000000..796321e --- /dev/null +++ b/npapi/webrtc-everywhere-npapi.def @@ -0,0 +1,6 @@ +LIBRARY "npwebrtc-everywhere" + +EXPORTS + NP_GetEntryPoints @1 + NP_Initialize @2 + NP_Shutdown @3 diff --git a/npapi/webrtc-everywhere-npapi.rc b/npapi/webrtc-everywhere-npapi.rc new file mode 100755 index 0000000..29468c6 --- /dev/null +++ b/npapi/webrtc-everywhere-npapi.rc @@ -0,0 +1,103 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "Sarandogou" + VALUE "FileDescription", "WebRTC plugin for Safari, IE, Chrome, Opera and Firefox" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "npwebrtc-everywhere.dll" + VALUE "LegalCopyright", "(c) 2014 Sarandogou. All rights reserved." + VALUE "MIMEType", "application/webrtc-everywhere" + VALUE "OriginalFilename", "npwebrtc-everywhere.dll" + VALUE "ProductName", "WebRTC Everywhere Plugin" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/npapi/webrtc-everywhere-npapi.vcproj b/npapi/webrtc-everywhere-npapi.vcproj new file mode 100755 index 0000000..0d9438d --- /dev/null +++ b/npapi/webrtc-everywhere-npapi.vcproj @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/npapi/webrtc-everywhere-npapi.vcxproj b/npapi/webrtc-everywhere-npapi.vcxproj new file mode 100755 index 0000000..cf7599b --- /dev/null +++ b/npapi/webrtc-everywhere-npapi.vcxproj @@ -0,0 +1,154 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {332AE24A-F021-4F30-A967-0CB91D94278D} + webrtceverywherenpapi + Win32Proj + + + + DynamicLibrary + v120 + Unicode + true + + + DynamicLibrary + v120 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + np$(ProjectName) + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + np$(ProjectName) + + + + Disabled + ../thirdparties/win32/include;../thirdparties/common/include;../thirdparties\common\include\webrtc-sdk;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;WEBRTCEVERYWHERENPAPI_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + true + EditAndContinue + + + $(OutDir)webrtc-everywhere-common.lib;%(AdditionalDependencies) + $(OutDir)np$(ProjectName).dll + webrtc-everywhere-npapi.def + true + Windows + MachineX86 + 5.01 + + + + + MaxSpeed + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;WEBRTCEVERYWHERENPAPI_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + true + ProgramDatabase + ../thirdparties/win32/include;../thirdparties/common/include;../thirdparties\common\include\webrtc-sdk;%(AdditionalIncludeDirectories) + + + $(OutDir)np$(ProjectName).dll + true + Windows + true + true + MachineX86 + 5.01 + webrtc-everywhere-npapi.def + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {95230956-8581-4f03-a589-c6217119de9e} + false + + + + + + \ No newline at end of file diff --git a/npapi/webrtc-everywhere-npapi.vcxproj.filters b/npapi/webrtc-everywhere-npapi.vcxproj.filters new file mode 100755 index 0000000..2fb2026 --- /dev/null +++ b/npapi/webrtc-everywhere-npapi.vcxproj.filters @@ -0,0 +1,130 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/thirdparties/common/include/npapi-sdk/headers/npapi.h b/thirdparties/common/include/npapi-sdk/headers/npapi.h new file mode 100644 index 0000000..d4b308b --- /dev/null +++ b/thirdparties/common/include/npapi-sdk/headers/npapi.h @@ -0,0 +1,925 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef npapi_h_ +#define npapi_h_ + +#if defined(__OS2__) +#pragma pack(1) +#endif + +#include "nptypes.h" + +#if defined(__OS2__) || defined(OS2) +#ifndef XP_OS2 +#define XP_OS2 1 +#endif +#endif + +#if defined(_WIN32) && !defined(__SYMBIAN32__) +#include +#ifndef XP_WIN +#define XP_WIN 1 +#endif +#endif + +#if defined(__SYMBIAN32__) +#ifndef XP_SYMBIAN +#define XP_SYMBIAN 1 +#undef XP_WIN +#endif +#endif + +#if defined(__APPLE_CC__) && !defined(XP_UNIX) +#ifndef XP_MACOSX +#define XP_MACOSX 1 +#endif +#endif + +#if defined(XP_MACOSX) && defined(__LP64__) +#define NP_NO_QUICKDRAW +#define NP_NO_CARBON +#endif + +#if defined(XP_MACOSX) +#include +#include +#ifndef NP_NO_CARBON +#include +#endif +#endif + +#if defined(XP_UNIX) +#include +#if defined(MOZ_X11) +#include +#include +#endif +#endif + +#if defined(XP_SYMBIAN) +#include +#include +#endif + +/*----------------------------------------------------------------------*/ +/* Plugin Version Constants */ +/*----------------------------------------------------------------------*/ + +#define NP_VERSION_MAJOR 0 +#define NP_VERSION_MINOR 27 + + +/* The OS/2 version of Netscape uses RC_DATA to define the + mime types, file extensions, etc that are required. + Use a vertical bar to separate types, end types with \0. + FileVersion and ProductVersion are 32bit ints, all other + entries are strings that MUST be terminated with a \0. + +AN EXAMPLE: + +RCDATA NP_INFO_ProductVersion { 1,0,0,1,} + +RCDATA NP_INFO_MIMEType { "video/x-video|", + "video/x-flick\0" } +RCDATA NP_INFO_FileExtents { "avi|", + "flc\0" } +RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|", + "MMOS2 Flc/Fli player(*.flc)\0" } + +RCDATA NP_INFO_FileVersion { 1,0,0,1 } +RCDATA NP_INFO_CompanyName { "Netscape Communications\0" } +RCDATA NP_INFO_FileDescription { "NPAVI32 Extension DLL\0" +RCDATA NP_INFO_InternalName { "NPAVI32\0" ) +RCDATA NP_INFO_LegalCopyright { "Copyright Netscape Communications \251 1996\0" +RCDATA NP_INFO_OriginalFilename { "NVAPI32.DLL" } +RCDATA NP_INFO_ProductName { "NPAVI32 Dynamic Link Library\0" } +*/ +/* RC_DATA types for version info - required */ +#define NP_INFO_ProductVersion 1 +#define NP_INFO_MIMEType 2 +#define NP_INFO_FileOpenName 3 +#define NP_INFO_FileExtents 4 +/* RC_DATA types for version info - used if found */ +#define NP_INFO_FileDescription 5 +#define NP_INFO_ProductName 6 +/* RC_DATA types for version info - optional */ +#define NP_INFO_CompanyName 7 +#define NP_INFO_FileVersion 8 +#define NP_INFO_InternalName 9 +#define NP_INFO_LegalCopyright 10 +#define NP_INFO_OriginalFilename 11 + +#ifndef RC_INVOKED + +/*----------------------------------------------------------------------*/ +/* Definition of Basic Types */ +/*----------------------------------------------------------------------*/ + +typedef unsigned char NPBool; +typedef int16_t NPError; +typedef int16_t NPReason; +typedef char* NPMIMEType; + +/*----------------------------------------------------------------------*/ +/* Structures and definitions */ +/*----------------------------------------------------------------------*/ + +#if !defined(__LP64__) +#if defined(XP_MACOSX) +#pragma options align=mac68k +#endif +#endif /* __LP64__ */ + +/* + * NPP is a plug-in's opaque instance handle + */ +typedef struct _NPP { + void* pdata; /* plug-in private data */ + void* ndata; /* netscape private data */ +} NPP_t; + +typedef NPP_t* NPP; + +typedef struct _NPStream { + void* pdata; /* plug-in private data */ + void* ndata; /* netscape private data */ + const char* url; + uint32_t end; + uint32_t lastmodified; + void* notifyData; + const char* headers; /* Response headers from host. + * Exists only for >= NPVERS_HAS_RESPONSE_HEADERS. + * Used for HTTP only; NULL for non-HTTP. + * Available from NPP_NewStream onwards. + * Plugin should copy this data before storing it. + * Includes HTTP status line and all headers, + * preferably verbatim as received from server, + * headers formatted as in HTTP ("Header: Value"), + * and newlines (\n, NOT \r\n) separating lines. + * Terminated by \n\0 (NOT \n\n\0). */ +} NPStream; + +typedef struct _NPByteRange { + int32_t offset; /* negative offset means from the end */ + uint32_t length; + struct _NPByteRange* next; +} NPByteRange; + +typedef struct _NPSavedData { + int32_t len; + void* buf; +} NPSavedData; + +typedef struct _NPRect { + uint16_t top; + uint16_t left; + uint16_t bottom; + uint16_t right; +} NPRect; + +typedef struct _NPSize { + int32_t width; + int32_t height; +} NPSize; + +typedef enum { + NPFocusNext = 0, + NPFocusPrevious = 1 +} NPFocusDirection; + +/* These formats describe the format in the memory byte-order. This means if + * a 32-bit value of a pixel is viewed on a little-endian system the layout will + * be 0xAARRGGBB. The Alpha channel will be stored in the most significant + * bits. */ +typedef enum { + /* 32-bit per pixel 8-bit per channel - premultiplied alpha */ + NPImageFormatBGRA32 = 0x1, + /* 32-bit per pixel 8-bit per channel - 1 unused channel */ + NPImageFormatBGRX32 = 0x2 +} NPImageFormat; + +typedef struct _NPAsyncSurface { + uint32_t version; + NPSize size; + NPImageFormat format; + union { + struct { + uint32_t stride; + void *data; + } bitmap; +#if defined(XP_WIN) + HANDLE sharedHandle; +#endif + }; +} NPAsyncSurface; + +/* Return values for NPP_HandleEvent */ +#define kNPEventNotHandled 0 +#define kNPEventHandled 1 +/* Exact meaning must be spec'd in event model. */ +#define kNPEventStartIME 2 + +#if defined(XP_UNIX) +/* + * Unix specific structures and definitions + */ + +/* + * Callback Structures. + * + * These are used to pass additional platform specific information. + */ +enum { + NP_SETWINDOW = 1, + NP_PRINT +}; + +typedef struct { + int32_t type; +} NPAnyCallbackStruct; + +typedef struct { + int32_t type; +#if defined(MOZ_X11) + Display* display; + Visual* visual; + Colormap colormap; + unsigned int depth; +#endif +} NPSetWindowCallbackStruct; + +typedef struct { + int32_t type; + FILE* fp; +} NPPrintCallbackStruct; + +#endif /* XP_UNIX */ + +typedef enum { +#if defined(XP_MACOSX) +#ifndef NP_NO_QUICKDRAW + NPDrawingModelQuickDraw = 0, +#endif + NPDrawingModelCoreGraphics = 1, + NPDrawingModelOpenGL = 2, + NPDrawingModelCoreAnimation = 3, + NPDrawingModelInvalidatingCoreAnimation = 4, +#endif +#if defined(XP_WIN) + NPDrawingModelSyncWin = 5, +#endif +#if defined(MOZ_X11) + NPDrawingModelSyncX = 6, +#endif + NPDrawingModelAsyncBitmapSurface = 7 +#if defined(XP_WIN) + , NPDrawingModelAsyncWindowsDXGISurface = 8 +#endif +} NPDrawingModel; + +#ifdef XP_MACOSX +typedef enum { +#ifndef NP_NO_CARBON + NPEventModelCarbon = 0, +#endif + NPEventModelCocoa = 1 +} NPEventModel; +#endif + +/* + * The following masks are applied on certain platforms to NPNV and + * NPPV selectors that pass around pointers to COM interfaces. Newer + * compilers on some platforms may generate vtables that are not + * compatible with older compilers. To prevent older plugins from + * not understanding a new browser's ABI, these masks change the + * values of those selectors on those platforms. To remain backwards + * compatible with different versions of the browser, plugins can + * use these masks to dynamically determine and use the correct C++ + * ABI that the browser is expecting. This does not apply to Windows + * as Microsoft's COM ABI will likely not change. + */ + +#define NP_ABI_GCC3_MASK 0x10000000 +/* + * gcc 3.x generated vtables on UNIX and OSX are incompatible with + * previous compilers. + */ +#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3)) +#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK +#else +#define _NP_ABI_MIXIN_FOR_GCC3 0 +#endif + +#if defined(XP_MACOSX) +#define NP_ABI_MACHO_MASK 0x01000000 +#define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK +#else +#define _NP_ABI_MIXIN_FOR_MACHO 0 +#endif + +#define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO) + +/* + * List of variable names for which NPP_GetValue shall be implemented + */ +typedef enum { + NPPVpluginNameString = 1, + NPPVpluginDescriptionString, + NPPVpluginWindowBool, + NPPVpluginTransparentBool, + NPPVjavaClass, + NPPVpluginWindowSize, + NPPVpluginTimerInterval, + NPPVpluginScriptableInstance = (10 | NP_ABI_MASK), + NPPVpluginScriptableIID = 11, + NPPVjavascriptPushCallerBool = 12, + NPPVpluginKeepLibraryInMemory = 13, + NPPVpluginNeedsXEmbed = 14, + + /* Get the NPObject for scripting the plugin. Introduced in NPAPI minor version 14. + */ + NPPVpluginScriptableNPObject = 15, + + /* Get the plugin value (as \0-terminated UTF-8 string data) for + * form submission if the plugin is part of a form. Use + * NPN_MemAlloc() to allocate memory for the string data. Introduced + * in NPAPI minor version 15. + */ + NPPVformValue = 16, + + NPPVpluginUrlRequestsDisplayedBool = 17, + + /* Checks if the plugin is interested in receiving the http body of + * all http requests (including failed ones, http status != 200). + */ + NPPVpluginWantsAllNetworkStreams = 18, + + /* Browsers can retrieve a native ATK accessibility plug ID via this variable. */ + NPPVpluginNativeAccessibleAtkPlugId = 19, + + /* Checks to see if the plug-in would like the browser to load the "src" attribute. */ + NPPVpluginCancelSrcStream = 20, + + NPPVsupportsAdvancedKeyHandling = 21, + + NPPVpluginUsesDOMForCursorBool = 22, + + /* Used for negotiating drawing models */ + NPPVpluginDrawingModel = 1000 +#if defined(XP_MACOSX) + /* Used for negotiating event models */ + , NPPVpluginEventModel = 1001 + /* In the NPDrawingModelCoreAnimation drawing model, the browser asks the plug-in for a Core Animation layer. */ + , NPPVpluginCoreAnimationLayer = 1003 +#endif + +#if defined(MOZ_PLATFORM_MAEMO) && ((MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)) + , NPPVpluginWindowlessLocalBool = 2002 +#endif +} NPPVariable; + +/* + * List of variable names for which NPN_GetValue should be implemented. + */ +typedef enum { + NPNVxDisplay = 1, + NPNVxtAppContext, + NPNVnetscapeWindow, + NPNVjavascriptEnabledBool, + NPNVasdEnabledBool, + NPNVisOfflineBool, + + NPNVserviceManager = (10 | NP_ABI_MASK), + NPNVDOMElement = (11 | NP_ABI_MASK), + NPNVDOMWindow = (12 | NP_ABI_MASK), + NPNVToolkit = (13 | NP_ABI_MASK), + NPNVSupportsXEmbedBool = 14, + + /* Get the NPObject wrapper for the browser window. */ + NPNVWindowNPObject = 15, + + /* Get the NPObject wrapper for the plugins DOM element. */ + NPNVPluginElementNPObject = 16, + + NPNVSupportsWindowless = 17, + + NPNVprivateModeBool = 18, + + NPNVsupportsAdvancedKeyHandling = 21, + + NPNVdocumentOrigin = 22, + + NPNVpluginDrawingModel = 1000 /* Get the current drawing model (NPDrawingModel) */ +#if defined(XP_MACOSX) + , NPNVcontentsScaleFactor = 1001 +#ifndef NP_NO_QUICKDRAW + , NPNVsupportsQuickDrawBool = 2000 +#endif + , NPNVsupportsCoreGraphicsBool = 2001 + , NPNVsupportsOpenGLBool = 2002 + , NPNVsupportsCoreAnimationBool = 2003 + , NPNVsupportsInvalidatingCoreAnimationBool = 2004 +#endif + , NPNVsupportsAsyncBitmapSurfaceBool = 2007 +#if defined(XP_WIN) + , NPNVsupportsAsyncWindowsDXGISurfaceBool = 2008 +#endif +#if defined(XP_MACOSX) +#ifndef NP_NO_CARBON + , NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */ +#endif + , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */ + , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated + Cocoa text input specification. */ + , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports + CA model compositing */ +#endif +#if defined(MOZ_PLATFORM_MAEMO) && ((MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)) + , NPNVSupportsWindowlessLocal = 2002 +#endif +} NPNVariable; + +typedef enum { + NPNURLVCookie = 501, + NPNURLVProxy +} NPNURLVariable; + +/* + * The type of Toolkit the widgets use + */ +typedef enum { + NPNVGtk12 = 1, + NPNVGtk2 +} NPNToolkitType; + +/* + * The type of a NPWindow - it specifies the type of the data structure + * returned in the window field. + */ +typedef enum { + NPWindowTypeWindow = 1, + NPWindowTypeDrawable +} NPWindowType; + +typedef struct _NPWindow { + void* window; /* Platform specific window handle */ + /* OS/2: x - Position of bottom left corner */ + /* OS/2: y - relative to visible netscape window */ + int32_t x; /* Position of top left corner relative */ + int32_t y; /* to a netscape page. */ + uint32_t width; /* Maximum window size */ + uint32_t height; + NPRect clipRect; /* Clipping rectangle in port coordinates */ +#if (defined(XP_UNIX) || defined(XP_SYMBIAN)) && !defined(XP_MACOSX) + void * ws_info; /* Platform-dependent additional data */ +#endif /* XP_UNIX */ + NPWindowType type; /* Is this a window or a drawable? */ +} NPWindow; + +typedef struct _NPImageExpose { + char* data; /* image pointer */ + int32_t stride; /* Stride of data image pointer */ + int32_t depth; /* Depth of image pointer */ + int32_t x; /* Expose x */ + int32_t y; /* Expose y */ + uint32_t width; /* Expose width */ + uint32_t height; /* Expose height */ + NPSize dataSize; /* Data buffer size */ + float translateX; /* translate X matrix value */ + float translateY; /* translate Y matrix value */ + float scaleX; /* scale X matrix value */ + float scaleY; /* scale Y matrix value */ +} NPImageExpose; + +typedef struct _NPFullPrint { + NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */ + NPBool printOne; /* TRUE if plugin should print one copy to default + printer */ + void* platformPrint; /* Platform-specific printing info */ +} NPFullPrint; + +typedef struct _NPEmbedPrint { + NPWindow window; + void* platformPrint; /* Platform-specific printing info */ +} NPEmbedPrint; + +typedef struct _NPPrint { + uint16_t mode; /* NP_FULL or NP_EMBED */ + union { + NPFullPrint fullPrint; /* if mode is NP_FULL */ + NPEmbedPrint embedPrint; /* if mode is NP_EMBED */ + } print; +} NPPrint; + +#if defined(XP_MACOSX) +#ifndef NP_NO_CARBON +typedef EventRecord NPEvent; +#endif +#elif defined(XP_SYMBIAN) +typedef QEvent NPEvent; +#elif defined(XP_WIN) +typedef struct _NPEvent { + uint16_t event; + uintptr_t wParam; + uintptr_t lParam; +} NPEvent; +#elif defined(XP_OS2) +typedef struct _NPEvent { + uint32_t event; + uint32_t wParam; + uint32_t lParam; +} NPEvent; +#elif defined(XP_UNIX) && defined(MOZ_X11) +typedef XEvent NPEvent; +#else +typedef void* NPEvent; +#endif + +#if defined(XP_MACOSX) +typedef void* NPRegion; +#ifndef NP_NO_QUICKDRAW +typedef RgnHandle NPQDRegion; +#endif +typedef CGPathRef NPCGRegion; +#elif defined(XP_WIN) +typedef HRGN NPRegion; +#elif defined(XP_UNIX) && defined(MOZ_X11) +typedef Region NPRegion; +#elif defined(XP_SYMBIAN) +typedef QRegion* NPRegion; +#else +typedef void *NPRegion; +#endif + +typedef struct _NPNSString NPNSString; +typedef struct _NPNSWindow NPNSWindow; +typedef struct _NPNSMenu NPNSMenu; + +#if defined(XP_MACOSX) +typedef NPNSMenu NPMenu; +#else +typedef void *NPMenu; +#endif + +typedef enum { + NPCoordinateSpacePlugin = 1, + NPCoordinateSpaceWindow, + NPCoordinateSpaceFlippedWindow, + NPCoordinateSpaceScreen, + NPCoordinateSpaceFlippedScreen +} NPCoordinateSpace; + +#if defined(XP_MACOSX) + +#ifndef NP_NO_QUICKDRAW +typedef struct NP_Port { + CGrafPtr port; + int32_t portx; /* position inside the topmost window */ + int32_t porty; +} NP_Port; +#endif /* NP_NO_QUICKDRAW */ + +/* + * NP_CGContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelCoreGraphics + * as its drawing model. + */ + +typedef struct NP_CGContext { + CGContextRef context; + void *window; /* A WindowRef under the Carbon event model. */ +} NP_CGContext; + +/* + * NP_GLContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelOpenGL as its + * drawing model. + */ + +typedef struct NP_GLContext { + CGLContextObj context; +#ifdef NP_NO_CARBON + NPNSWindow *window; +#else + void *window; /* Can be either an NSWindow or a WindowRef depending on the event model */ +#endif +} NP_GLContext; + +typedef enum { + NPCocoaEventDrawRect = 1, + NPCocoaEventMouseDown, + NPCocoaEventMouseUp, + NPCocoaEventMouseMoved, + NPCocoaEventMouseEntered, + NPCocoaEventMouseExited, + NPCocoaEventMouseDragged, + NPCocoaEventKeyDown, + NPCocoaEventKeyUp, + NPCocoaEventFlagsChanged, + NPCocoaEventFocusChanged, + NPCocoaEventWindowFocusChanged, + NPCocoaEventScrollWheel, + NPCocoaEventTextInput +} NPCocoaEventType; + +typedef struct _NPCocoaEvent { + NPCocoaEventType type; + uint32_t version; + union { + struct { + uint32_t modifierFlags; + double pluginX; + double pluginY; + int32_t buttonNumber; + int32_t clickCount; + double deltaX; + double deltaY; + double deltaZ; + } mouse; + struct { + uint32_t modifierFlags; + NPNSString *characters; + NPNSString *charactersIgnoringModifiers; + NPBool isARepeat; + uint16_t keyCode; + } key; + struct { + CGContextRef context; + double x; + double y; + double width; + double height; + } draw; + struct { + NPBool hasFocus; + } focus; + struct { + NPNSString *text; + } text; + } data; +} NPCocoaEvent; + +#ifndef NP_NO_CARBON +/* Non-standard event types that can be passed to HandleEvent */ +enum NPEventType { + NPEventType_GetFocusEvent = (osEvt + 16), + NPEventType_LoseFocusEvent, + NPEventType_AdjustCursorEvent, + NPEventType_MenuCommandEvent, + NPEventType_ClippingChangedEvent, + NPEventType_ScrollingBeginsEvent = 1000, + NPEventType_ScrollingEndsEvent +}; +#endif /* NP_NO_CARBON */ + +#endif /* XP_MACOSX */ + +/* + * Values for mode passed to NPP_New: + */ +#define NP_EMBED 1 +#define NP_FULL 2 + +/* + * Values for stream type passed to NPP_NewStream: + */ +#define NP_NORMAL 1 +#define NP_SEEK 2 +#define NP_ASFILE 3 +#define NP_ASFILEONLY 4 + +#define NP_MAXREADY (((unsigned)(~0)<<1)>>1) + +/* + * Flags for NPP_ClearSiteData. + */ +#define NP_CLEAR_ALL 0 +#define NP_CLEAR_CACHE (1 << 0) + +#if !defined(__LP64__) +#if defined(XP_MACOSX) +#pragma options align=reset +#endif +#endif /* __LP64__ */ + +/*----------------------------------------------------------------------*/ +/* Error and Reason Code definitions */ +/*----------------------------------------------------------------------*/ + +/* + * Values of type NPError: + */ +#define NPERR_BASE 0 +#define NPERR_NO_ERROR (NPERR_BASE + 0) +#define NPERR_GENERIC_ERROR (NPERR_BASE + 1) +#define NPERR_INVALID_INSTANCE_ERROR (NPERR_BASE + 2) +#define NPERR_INVALID_FUNCTABLE_ERROR (NPERR_BASE + 3) +#define NPERR_MODULE_LOAD_FAILED_ERROR (NPERR_BASE + 4) +#define NPERR_OUT_OF_MEMORY_ERROR (NPERR_BASE + 5) +#define NPERR_INVALID_PLUGIN_ERROR (NPERR_BASE + 6) +#define NPERR_INVALID_PLUGIN_DIR_ERROR (NPERR_BASE + 7) +#define NPERR_INCOMPATIBLE_VERSION_ERROR (NPERR_BASE + 8) +#define NPERR_INVALID_PARAM (NPERR_BASE + 9) +#define NPERR_INVALID_URL (NPERR_BASE + 10) +#define NPERR_FILE_NOT_FOUND (NPERR_BASE + 11) +#define NPERR_NO_DATA (NPERR_BASE + 12) +#define NPERR_STREAM_NOT_SEEKABLE (NPERR_BASE + 13) +#define NPERR_TIME_RANGE_NOT_SUPPORTED (NPERR_BASE + 14) +#define NPERR_MALFORMED_SITE (NPERR_BASE + 15) + +/* + * Values of type NPReason: + */ +#define NPRES_BASE 0 +#define NPRES_DONE (NPRES_BASE + 0) +#define NPRES_NETWORK_ERR (NPRES_BASE + 1) +#define NPRES_USER_BREAK (NPRES_BASE + 2) + +/* + * Don't use these obsolete error codes any more. + */ +#define NP_NOERR NP_NOERR_is_obsolete_use_NPERR_NO_ERROR +#define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR +#define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK + +/* + * Version feature information + */ +#define NPVERS_HAS_STREAMOUTPUT 8 +#define NPVERS_HAS_NOTIFICATION 9 +#define NPVERS_HAS_LIVECONNECT 9 +#define NPVERS_68K_HAS_LIVECONNECT 11 +#define NPVERS_HAS_WINDOWLESS 11 +#define NPVERS_HAS_XPCONNECT_SCRIPTING 13 +#define NPVERS_HAS_NPRUNTIME_SCRIPTING 14 +#define NPVERS_HAS_FORM_VALUES 15 +#define NPVERS_HAS_POPUPS_ENABLED_STATE 16 +#define NPVERS_HAS_RESPONSE_HEADERS 17 +#define NPVERS_HAS_NPOBJECT_ENUM 18 +#define NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL 19 +#define NPVERS_HAS_ALL_NETWORK_STREAMS 20 +#define NPVERS_HAS_URL_AND_AUTH_INFO 21 +#define NPVERS_HAS_PRIVATE_MODE 22 +#define NPVERS_MACOSX_HAS_COCOA_EVENTS 23 +#define NPVERS_HAS_ADVANCED_KEY_HANDLING 25 +#define NPVERS_HAS_URL_REDIRECT_HANDLING 26 +#define NPVERS_HAS_CLEAR_SITE_DATA 27 + +/*----------------------------------------------------------------------*/ +/* Function Prototypes */ +/*----------------------------------------------------------------------*/ + +#if defined(__OS2__) +#define NP_LOADDS _System +#else +#define NP_LOADDS +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* NPP_* functions are provided by the plugin and called by the navigator. */ + +#if defined(XP_UNIX) +const char* NPP_GetMIMEDescription(void); +#endif + +NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance, + uint16_t mode, int16_t argc, char* argn[], + char* argv[], NPSavedData* saved); +NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save); +NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window); +NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type, + NPStream* stream, NPBool seekable, + uint16_t* stype); +NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream, + NPReason reason); +int32_t NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream); +int32_t NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32_t offset, + int32_t len, void* buffer); +void NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream, + const char* fname); +void NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint); +int16_t NP_LOADDS NPP_HandleEvent(NPP instance, void* event); +void NP_LOADDS NPP_URLNotify(NPP instance, const char* url, + NPReason reason, void* notifyData); +NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value); +NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value); +NPBool NP_LOADDS NPP_GotFocus(NPP instance, NPFocusDirection direction); +void NP_LOADDS NPP_LostFocus(NPP instance); +void NP_LOADDS NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData); +NPError NP_LOADDS NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge); +char** NP_LOADDS NPP_GetSitesWithData(void); +void NP_LOADDS NPP_DidComposite(NPP instance); + +/* NPN_* functions are provided by the navigator and called by the plugin. */ +void NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor, + int* netscape_major, int* netscape_minor); +NPError NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url, + const char* target, void* notifyData); +NPError NP_LOADDS NPN_GetURL(NPP instance, const char* url, + const char* target); +NPError NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url, + const char* target, uint32_t len, + const char* buf, NPBool file, + void* notifyData); +NPError NP_LOADDS NPN_PostURL(NPP instance, const char* url, + const char* target, uint32_t len, + const char* buf, NPBool file); +NPError NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList); +NPError NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type, + const char* target, NPStream** stream); +int32_t NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32_t len, + void* buffer); +NPError NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream, + NPReason reason); +void NP_LOADDS NPN_Status(NPP instance, const char* message); +const char* NP_LOADDS NPN_UserAgent(NPP instance); +void* NP_LOADDS NPN_MemAlloc(uint32_t size); +void NP_LOADDS NPN_MemFree(void* ptr); +uint32_t NP_LOADDS NPN_MemFlush(uint32_t size); +void NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages); +NPError NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable, + void *value); +NPError NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable, + void *value); +void NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect); +void NP_LOADDS NPN_InvalidateRegion(NPP instance, + NPRegion invalidRegion); +void NP_LOADDS NPN_ForceRedraw(NPP instance); +void NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled); +void NP_LOADDS NPN_PopPopupsEnabledState(NPP instance); +void NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance, + void (*func) (void *), + void *userData); +NPError NP_LOADDS NPN_GetValueForURL(NPP instance, NPNURLVariable variable, + const char *url, char **value, + uint32_t *len); +NPError NP_LOADDS NPN_SetValueForURL(NPP instance, NPNURLVariable variable, + const char *url, const char *value, + uint32_t len); +NPError NP_LOADDS NPN_GetAuthenticationInfo(NPP instance, + const char *protocol, + const char *host, int32_t port, + const char *scheme, + const char *realm, + char **username, uint32_t *ulen, + char **password, + uint32_t *plen); +uint32_t NP_LOADDS NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID)); +void NP_LOADDS NPN_UnscheduleTimer(NPP instance, uint32_t timerID); +NPError NP_LOADDS NPN_PopUpContextMenu(NPP instance, NPMenu* menu); +NPBool NP_LOADDS NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); +NPBool NP_LOADDS NPN_HandleEvent(NPP instance, void *event, NPBool handled); +NPBool NP_LOADDS NPN_UnfocusInstance(NPP instance, NPFocusDirection direction); +void NP_LOADDS NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow); +NPError NP_LOADDS NPN_InitAsyncSurface(NPP instance, NPSize *size, + NPImageFormat format, void *initData, + NPAsyncSurface *surface); +NPError NP_LOADDS NPN_FinalizeAsyncSurface(NPP instance, NPAsyncSurface *surface); +void NP_LOADDS NPN_SetCurrentAsyncSurface(NPP instance, NPAsyncSurface *surface, NPRect *changed); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* RC_INVOKED */ +#if defined(__OS2__) +#pragma pack() +#endif + +#endif /* npapi_h_ */ diff --git a/thirdparties/common/include/npapi-sdk/headers/npfunctions.h b/thirdparties/common/include/npapi-sdk/headers/npfunctions.h new file mode 100644 index 0000000..30a3c62 --- /dev/null +++ b/thirdparties/common/include/npapi-sdk/headers/npfunctions.h @@ -0,0 +1,329 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef npfunctions_h_ +#define npfunctions_h_ + +#ifdef __OS2__ +#pragma pack(1) +#define NP_LOADDS _System +#else +#define NP_LOADDS +#endif + +#include "npapi.h" +#include "npruntime.h" + +typedef NPError (* NP_LOADDS NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved); +typedef NPError (* NP_LOADDS NPP_DestroyProcPtr)(NPP instance, NPSavedData** save); +typedef NPError (* NP_LOADDS NPP_SetWindowProcPtr)(NPP instance, NPWindow* window); +typedef NPError (* NP_LOADDS NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype); +typedef NPError (* NP_LOADDS NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason); +typedef int32_t (* NP_LOADDS NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream); +typedef int32_t (* NP_LOADDS NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer); +typedef void (* NP_LOADDS NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* fname); +typedef void (* NP_LOADDS NPP_PrintProcPtr)(NPP instance, NPPrint* platformPrint); +typedef int16_t (* NP_LOADDS NPP_HandleEventProcPtr)(NPP instance, void* event); +typedef void (* NP_LOADDS NPP_URLNotifyProcPtr)(NPP instance, const char* url, NPReason reason, void* notifyData); +/* Any NPObjects returned to the browser via NPP_GetValue should be retained + by the plugin on the way out. The browser is responsible for releasing. */ +typedef NPError (* NP_LOADDS NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value); +typedef NPError (* NP_LOADDS NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value); +typedef NPBool (* NP_LOADDS NPP_GotFocusPtr)(NPP instance, NPFocusDirection direction); +typedef void (* NP_LOADDS NPP_LostFocusPtr)(NPP instance); +typedef void (* NP_LOADDS NPP_URLRedirectNotifyPtr)(NPP instance, const char* url, int32_t status, void* notifyData); +typedef NPError (* NP_LOADDS NPP_ClearSiteDataPtr)(const char* site, uint64_t flags, uint64_t maxAge); +typedef char** (* NP_LOADDS NPP_GetSitesWithDataPtr)(void); +typedef void (* NP_LOADDS NPP_DidCompositePtr)(NPP instance); + +typedef NPError (*NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value); +typedef NPError (*NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value); +typedef NPError (*NPN_GetURLNotifyProcPtr)(NPP instance, const char* url, const char* window, void* notifyData); +typedef NPError (*NPN_PostURLNotifyProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file, void* notifyData); +typedef NPError (*NPN_GetURLProcPtr)(NPP instance, const char* url, const char* window); +typedef NPError (*NPN_PostURLProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file); +typedef NPError (*NPN_RequestReadProcPtr)(NPStream* stream, NPByteRange* rangeList); +typedef NPError (*NPN_NewStreamProcPtr)(NPP instance, NPMIMEType type, const char* window, NPStream** stream); +typedef int32_t (*NPN_WriteProcPtr)(NPP instance, NPStream* stream, int32_t len, void* buffer); +typedef NPError (*NPN_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason); +typedef void (*NPN_StatusProcPtr)(NPP instance, const char* message); +/* Browser manages the lifetime of the buffer returned by NPN_UserAgent, don't + depend on it sticking around and don't free it. */ +typedef const char* (*NPN_UserAgentProcPtr)(NPP instance); +typedef void* (*NPN_MemAllocProcPtr)(uint32_t size); +typedef void (*NPN_MemFreeProcPtr)(void* ptr); +typedef uint32_t (*NPN_MemFlushProcPtr)(uint32_t size); +typedef void (*NPN_ReloadPluginsProcPtr)(NPBool reloadPages); +typedef void* (*NPN_GetJavaEnvProcPtr)(void); +typedef void* (*NPN_GetJavaPeerProcPtr)(NPP instance); +typedef void (*NPN_InvalidateRectProcPtr)(NPP instance, NPRect *rect); +typedef void (*NPN_InvalidateRegionProcPtr)(NPP instance, NPRegion region); +typedef void (*NPN_ForceRedrawProcPtr)(NPP instance); +typedef NPIdentifier (*NPN_GetStringIdentifierProcPtr)(const NPUTF8* name); +typedef void (*NPN_GetStringIdentifiersProcPtr)(const NPUTF8** names, int32_t nameCount, NPIdentifier* identifiers); +typedef NPIdentifier (*NPN_GetIntIdentifierProcPtr)(int32_t intid); +typedef bool (*NPN_IdentifierIsStringProcPtr)(NPIdentifier identifier); +typedef NPUTF8* (*NPN_UTF8FromIdentifierProcPtr)(NPIdentifier identifier); +typedef int32_t (*NPN_IntFromIdentifierProcPtr)(NPIdentifier identifier); +typedef NPObject* (*NPN_CreateObjectProcPtr)(NPP npp, NPClass *aClass); +typedef NPObject* (*NPN_RetainObjectProcPtr)(NPObject *obj); +typedef void (*NPN_ReleaseObjectProcPtr)(NPObject *obj); +typedef bool (*NPN_InvokeProcPtr)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result); +typedef bool (*NPN_InvokeDefaultProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); +typedef bool (*NPN_EvaluateProcPtr)(NPP npp, NPObject *obj, NPString *script, NPVariant *result); +typedef bool (*NPN_GetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result); +typedef bool (*NPN_SetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value); +typedef bool (*NPN_RemovePropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName); +typedef bool (*NPN_HasPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName); +typedef bool (*NPN_HasMethodProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName); +typedef void (*NPN_ReleaseVariantValueProcPtr)(NPVariant *variant); +typedef void (*NPN_SetExceptionProcPtr)(NPObject *obj, const NPUTF8 *message); +typedef void (*NPN_PushPopupsEnabledStateProcPtr)(NPP npp, NPBool enabled); +typedef void (*NPN_PopPopupsEnabledStateProcPtr)(NPP npp); +typedef bool (*NPN_EnumerateProcPtr)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count); +typedef void (*NPN_PluginThreadAsyncCallProcPtr)(NPP instance, void (*func)(void *), void *userData); +typedef bool (*NPN_ConstructProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); +typedef NPError (*NPN_GetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, char **value, uint32_t *len); +typedef NPError (*NPN_SetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, const char *value, uint32_t len); +typedef NPError (*NPN_GetAuthenticationInfoPtr)(NPP npp, const char *protocol, const char *host, int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen); +typedef uint32_t (*NPN_ScheduleTimerPtr)(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID)); +typedef void (*NPN_UnscheduleTimerPtr)(NPP instance, uint32_t timerID); +typedef NPError (*NPN_PopUpContextMenuPtr)(NPP instance, NPMenu* menu); +typedef NPBool (*NPN_ConvertPointPtr)(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); +typedef NPBool (*NPN_HandleEventPtr)(NPP instance, void *event, NPBool handled); +typedef NPBool (*NPN_UnfocusInstancePtr)(NPP instance, NPFocusDirection direction); +typedef void (*NPN_URLRedirectResponsePtr)(NPP instance, void* notifyData, NPBool allow); +typedef NPError (*NPN_InitAsyncSurfacePtr)(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface); +typedef NPError (*NPN_FinalizeAsyncSurfacePtr)(NPP instance, NPAsyncSurface *surface); +typedef void (*NPN_SetCurrentAsyncSurfacePtr)(NPP instance, NPAsyncSurface *surface, NPRect *changed); + +typedef struct _NPPluginFuncs { + uint16_t size; + uint16_t version; + NPP_NewProcPtr newp; + NPP_DestroyProcPtr destroy; + NPP_SetWindowProcPtr setwindow; + NPP_NewStreamProcPtr newstream; + NPP_DestroyStreamProcPtr destroystream; + NPP_StreamAsFileProcPtr asfile; + NPP_WriteReadyProcPtr writeready; + NPP_WriteProcPtr write; + NPP_PrintProcPtr print; + NPP_HandleEventProcPtr event; + NPP_URLNotifyProcPtr urlnotify; + void* javaClass; + NPP_GetValueProcPtr getvalue; + NPP_SetValueProcPtr setvalue; + NPP_GotFocusPtr gotfocus; + NPP_LostFocusPtr lostfocus; + NPP_URLRedirectNotifyPtr urlredirectnotify; + NPP_ClearSiteDataPtr clearsitedata; + NPP_GetSitesWithDataPtr getsiteswithdata; + NPP_DidCompositePtr didComposite; +} NPPluginFuncs; + +typedef struct _NPNetscapeFuncs { + uint16_t size; + uint16_t version; + NPN_GetURLProcPtr geturl; + NPN_PostURLProcPtr posturl; + NPN_RequestReadProcPtr requestread; + NPN_NewStreamProcPtr newstream; + NPN_WriteProcPtr write; + NPN_DestroyStreamProcPtr destroystream; + NPN_StatusProcPtr status; + NPN_UserAgentProcPtr uagent; + NPN_MemAllocProcPtr memalloc; + NPN_MemFreeProcPtr memfree; + NPN_MemFlushProcPtr memflush; + NPN_ReloadPluginsProcPtr reloadplugins; + NPN_GetJavaEnvProcPtr getJavaEnv; + NPN_GetJavaPeerProcPtr getJavaPeer; + NPN_GetURLNotifyProcPtr geturlnotify; + NPN_PostURLNotifyProcPtr posturlnotify; + NPN_GetValueProcPtr getvalue; + NPN_SetValueProcPtr setvalue; + NPN_InvalidateRectProcPtr invalidaterect; + NPN_InvalidateRegionProcPtr invalidateregion; + NPN_ForceRedrawProcPtr forceredraw; + NPN_GetStringIdentifierProcPtr getstringidentifier; + NPN_GetStringIdentifiersProcPtr getstringidentifiers; + NPN_GetIntIdentifierProcPtr getintidentifier; + NPN_IdentifierIsStringProcPtr identifierisstring; + NPN_UTF8FromIdentifierProcPtr utf8fromidentifier; + NPN_IntFromIdentifierProcPtr intfromidentifier; + NPN_CreateObjectProcPtr createobject; + NPN_RetainObjectProcPtr retainobject; + NPN_ReleaseObjectProcPtr releaseobject; + NPN_InvokeProcPtr invoke; + NPN_InvokeDefaultProcPtr invokeDefault; + NPN_EvaluateProcPtr evaluate; + NPN_GetPropertyProcPtr getproperty; + NPN_SetPropertyProcPtr setproperty; + NPN_RemovePropertyProcPtr removeproperty; + NPN_HasPropertyProcPtr hasproperty; + NPN_HasMethodProcPtr hasmethod; + NPN_ReleaseVariantValueProcPtr releasevariantvalue; + NPN_SetExceptionProcPtr setexception; + NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate; + NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate; + NPN_EnumerateProcPtr enumerate; + NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall; + NPN_ConstructProcPtr construct; + NPN_GetValueForURLPtr getvalueforurl; + NPN_SetValueForURLPtr setvalueforurl; + NPN_GetAuthenticationInfoPtr getauthenticationinfo; + NPN_ScheduleTimerPtr scheduletimer; + NPN_UnscheduleTimerPtr unscheduletimer; + NPN_PopUpContextMenuPtr popupcontextmenu; + NPN_ConvertPointPtr convertpoint; + NPN_HandleEventPtr handleevent; + NPN_UnfocusInstancePtr unfocusinstance; + NPN_URLRedirectResponsePtr urlredirectresponse; + NPN_InitAsyncSurfacePtr initasyncsurface; + NPN_FinalizeAsyncSurfacePtr finalizeasyncsurface; + NPN_SetCurrentAsyncSurfacePtr setcurrentasyncsurface; +} NPNetscapeFuncs; + +#ifdef XP_MACOSX +/* + * Mac OS X version(s) of NP_GetMIMEDescription(const char *) + * These can be called to retreive MIME information from the plugin dynamically + * + * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way + * to get mime info from the plugin only on OSX and may not be supported + * in furture version -- use NP_GetMIMEDescription instead + */ +enum { + kBPSupportedMIMETypesStructVers_1 = 1 +}; +typedef struct _BPSupportedMIMETypes { + SInt32 structVersion; /* struct version */ + Handle typeStrings; /* STR# formated handle, allocated by plug-in */ + Handle infoStrings; /* STR# formated handle, allocated by plug-in */ +} BPSupportedMIMETypes; +OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags); +#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription" +typedef const char* (*NP_GetMIMEDescriptionProcPtr)(void); +typedef OSErr (*BP_GetSupportedMIMETypesProcPtr)(BPSupportedMIMETypes*, UInt32); +#endif + +#if defined(_WIN32) +#define OSCALL WINAPI +#define NP_EXPORT(__type) __type +#else +#if defined(__OS2__) +#define OSCALL _System +#else +#define OSCALL +#endif +#endif + +#if defined(XP_UNIX) +/* GCC 3.3 and later support the visibility attribute. */ +#if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) +#define NP_VISIBILITY_DEFAULT __attribute__((visibility("default"))) +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#define NP_VISIBILITY_DEFAULT __global +#else +#define NP_VISIBILITY_DEFAULT +#endif +#define NP_EXPORT(__type) NP_VISIBILITY_DEFAULT __type +#endif + +#if defined(_WIN32) || defined (__OS2__) +#ifdef __cplusplus +extern "C" { +#endif +/* plugin meta member functions */ +#if defined(__OS2__) +typedef struct _NPPluginData { /* Alternate OS2 Plugin interface */ + char *pMimeTypes; + char *pFileExtents; + char *pFileOpenTemplate; + char *pProductName; + char *pProductDescription; + unsigned long dwProductVersionMS; + unsigned long dwProductVersionLS; +} NPPluginData; +typedef NPError (OSCALL *NP_GetPluginDataFunc)(NPPluginData*); +NPError OSCALL NP_GetPluginData(NPPluginData * pPluginData); +#endif +typedef NPError (OSCALL *NP_GetEntryPointsFunc)(NPPluginFuncs*); +NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs); +typedef NPError (OSCALL *NP_InitializeFunc)(NPNetscapeFuncs*); +NPError OSCALL NP_Initialize(NPNetscapeFuncs* bFuncs); +typedef NPError (OSCALL *NP_ShutdownFunc)(void); +NPError OSCALL NP_Shutdown(void); +typedef const char* (*NP_GetMIMEDescriptionFunc)(void); +const char* NP_GetMIMEDescription(void); +#ifdef __cplusplus +} +#endif +#endif + +#if defined(__OS2__) +#pragma pack() +#endif + +#ifdef XP_UNIX +#ifdef __cplusplus +extern "C" { +#endif +typedef char* (*NP_GetPluginVersionFunc)(void); +NP_EXPORT(char*) NP_GetPluginVersion(void); +typedef const char* (*NP_GetMIMEDescriptionFunc)(void); +NP_EXPORT(const char*) NP_GetMIMEDescription(void); +#ifdef XP_MACOSX +typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*); +NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs); +typedef NPError (*NP_GetEntryPointsFunc)(NPPluginFuncs*); +NP_EXPORT(NPError) NP_GetEntryPoints(NPPluginFuncs* pFuncs); +#else +typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*); +NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs); +#endif +typedef NPError (*NP_ShutdownFunc)(void); +NP_EXPORT(NPError) NP_Shutdown(void); +typedef NPError (*NP_GetValueFunc)(void *, NPPVariable, void *); +NP_EXPORT(NPError) NP_GetValue(void *future, NPPVariable aVariable, void *aValue); +#ifdef __cplusplus +} +#endif +#endif + +#endif /* npfunctions_h_ */ diff --git a/thirdparties/common/include/npapi-sdk/headers/npruntime.h b/thirdparties/common/include/npapi-sdk/headers/npruntime.h new file mode 100644 index 0000000..dafefcc --- /dev/null +++ b/thirdparties/common/include/npapi-sdk/headers/npruntime.h @@ -0,0 +1,392 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Copyright (c) 2004, Apple Computer, Inc. and The Mozilla Foundation. + * All rights reserved. + * + * 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. Neither the names of Apple Computer, Inc. ("Apple") or The Mozilla + * Foundation ("Mozilla") nor the names of their contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "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 APPLE, MOZILLA OR + * THEIR CONTRIBUTORS 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 _NP_RUNTIME_H_ +#define _NP_RUNTIME_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "nptypes.h" + +/* + This API is used to facilitate binding code written in C to script + objects. The API in this header does not assume the presence of a + user agent. That is, it can be used to bind C code to scripting + environments outside of the context of a user agent. + + However, the normal use of the this API is in the context of a + scripting environment running in a browser or other user agent. + In particular it is used to support the extended Netscape + script-ability API for plugins (NP-SAP). NP-SAP is an extension + of the Netscape plugin API. As such we have adopted the use of + the "NP" prefix for this API. + + The following NP{N|P}Variables were added to the Netscape plugin + API (in npapi.h): + + NPNVWindowNPObject + NPNVPluginElementNPObject + NPPVpluginScriptableNPObject + + These variables are exposed through NPN_GetValue() and + NPP_GetValue() (respectively) and are used to establish the + initial binding between the user agent and native code. The DOM + objects in the user agent can be examined and manipulated using + the NPN_ functions that operate on NPObjects described in this + header. + + To the extent possible the assumptions about the scripting + language used by the scripting environment have been minimized. +*/ + +#define NP_BEGIN_MACRO do { +#define NP_END_MACRO } while (0) + +/* + Objects (non-primitive data) passed between 'C' and script is + always wrapped in an NPObject. The 'interface' of an NPObject is + described by an NPClass. +*/ +typedef struct NPObject NPObject; +typedef struct NPClass NPClass; + +typedef char NPUTF8; +typedef struct _NPString { + const NPUTF8 *UTF8Characters; + uint32_t UTF8Length; +} NPString; + +typedef enum { + NPVariantType_Void, + NPVariantType_Null, + NPVariantType_Bool, + NPVariantType_Int32, + NPVariantType_Double, + NPVariantType_String, + NPVariantType_Object +} NPVariantType; + +typedef struct _NPVariant { + NPVariantType type; + union { + bool boolValue; + int32_t intValue; + double doubleValue; + NPString stringValue; + NPObject *objectValue; + } value; +} NPVariant; + +/* + NPN_ReleaseVariantValue is called on all 'out' parameters + references. Specifically it is to be called on variants that own + their value, as is the case with all non-const NPVariant* + arguments after a successful call to any methods (except this one) + in this API. + + After calling NPN_ReleaseVariantValue, the type of the variant + will be NPVariantType_Void. +*/ +void NPN_ReleaseVariantValue(NPVariant *variant); + +#define NPVARIANT_IS_VOID(_v) ((_v).type == NPVariantType_Void) +#define NPVARIANT_IS_NULL(_v) ((_v).type == NPVariantType_Null) +#define NPVARIANT_IS_BOOLEAN(_v) ((_v).type == NPVariantType_Bool) +#define NPVARIANT_IS_INT32(_v) ((_v).type == NPVariantType_Int32) +#define NPVARIANT_IS_DOUBLE(_v) ((_v).type == NPVariantType_Double) +#define NPVARIANT_IS_STRING(_v) ((_v).type == NPVariantType_String) +#define NPVARIANT_IS_OBJECT(_v) ((_v).type == NPVariantType_Object) + +#define NPVARIANT_TO_BOOLEAN(_v) ((_v).value.boolValue) +#define NPVARIANT_TO_INT32(_v) ((_v).value.intValue) +#define NPVARIANT_TO_DOUBLE(_v) ((_v).value.doubleValue) +#define NPVARIANT_TO_STRING(_v) ((_v).value.stringValue) +#define NPVARIANT_TO_OBJECT(_v) ((_v).value.objectValue) + +#define VOID_TO_NPVARIANT(_v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Void; \ + (_v).value.objectValue = NULL; \ +NP_END_MACRO + +#define NULL_TO_NPVARIANT(_v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Null; \ + (_v).value.objectValue = NULL; \ +NP_END_MACRO + +#define BOOLEAN_TO_NPVARIANT(_val, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Bool; \ + (_v).value.boolValue = !!(_val); \ +NP_END_MACRO + +#define INT32_TO_NPVARIANT(_val, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Int32; \ + (_v).value.intValue = _val; \ +NP_END_MACRO + +#define DOUBLE_TO_NPVARIANT(_val, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Double; \ + (_v).value.doubleValue = _val; \ +NP_END_MACRO + +#define STRINGZ_TO_NPVARIANT(_val, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_String; \ + NPString str = { _val, (uint32_t)(strlen(_val)) }; \ + (_v).value.stringValue = str; \ +NP_END_MACRO + +#define STRINGN_TO_NPVARIANT(_val, _len, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_String; \ + NPString str = { _val, (uint32_t)(_len) }; \ + (_v).value.stringValue = str; \ +NP_END_MACRO + +#define OBJECT_TO_NPVARIANT(_val, _v) \ +NP_BEGIN_MACRO \ + (_v).type = NPVariantType_Object; \ + (_v).value.objectValue = _val; \ +NP_END_MACRO + + +/* + Type mappings (JavaScript types have been used for illustration + purposes): + + JavaScript to C (NPVariant with type:) + undefined NPVariantType_Void + null NPVariantType_Null + Boolean NPVariantType_Bool + Number NPVariantType_Double or NPVariantType_Int32 + String NPVariantType_String + Object NPVariantType_Object + + C (NPVariant with type:) to JavaScript + NPVariantType_Void undefined + NPVariantType_Null null + NPVariantType_Bool Boolean + NPVariantType_Int32 Number + NPVariantType_Double Number + NPVariantType_String String + NPVariantType_Object Object +*/ + +typedef void *NPIdentifier; + +/* + NPObjects have methods and properties. Methods and properties are + identified with NPIdentifiers. These identifiers may be reflected + in script. NPIdentifiers can be either strings or integers, IOW, + methods and properties can be identified by either strings or + integers (i.e. foo["bar"] vs foo[1]). NPIdentifiers can be + compared using ==. In case of any errors, the requested + NPIdentifier(s) will be NULL. NPIdentifier lifetime is controlled + by the browser. Plugins do not need to worry about memory management + with regards to NPIdentifiers. +*/ +NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name); +void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, + NPIdentifier *identifiers); +NPIdentifier NPN_GetIntIdentifier(int32_t intid); +bool NPN_IdentifierIsString(NPIdentifier identifier); + +/* + The NPUTF8 returned from NPN_UTF8FromIdentifier SHOULD be freed. +*/ +NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier); + +/* + Get the integer represented by identifier. If identifier is not an + integer identifier, the behaviour is undefined. +*/ +int32_t NPN_IntFromIdentifier(NPIdentifier identifier); + +/* + NPObject behavior is implemented using the following set of + callback functions. + + The NPVariant *result argument of these functions (where + applicable) should be released using NPN_ReleaseVariantValue(). +*/ +typedef NPObject *(*NPAllocateFunctionPtr)(NPP npp, NPClass *aClass); +typedef void (*NPDeallocateFunctionPtr)(NPObject *npobj); +typedef void (*NPInvalidateFunctionPtr)(NPObject *npobj); +typedef bool (*NPHasMethodFunctionPtr)(NPObject *npobj, NPIdentifier name); +typedef bool (*NPInvokeFunctionPtr)(NPObject *npobj, NPIdentifier name, + const NPVariant *args, uint32_t argCount, + NPVariant *result); +typedef bool (*NPInvokeDefaultFunctionPtr)(NPObject *npobj, + const NPVariant *args, + uint32_t argCount, + NPVariant *result); +typedef bool (*NPHasPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name); +typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name, + NPVariant *result); +typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name, + const NPVariant *value); +typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj, + NPIdentifier name); +typedef bool (*NPEnumerationFunctionPtr)(NPObject *npobj, NPIdentifier **value, + uint32_t *count); +typedef bool (*NPConstructFunctionPtr)(NPObject *npobj, + const NPVariant *args, + uint32_t argCount, + NPVariant *result); + +/* + NPObjects returned by create, retain, invoke, and getProperty pass + a reference count to the caller. That is, the callee adds a + reference count which passes to the caller. It is the caller's + responsibility to release the returned object. + + NPInvokeFunctionPtr function may return 0 to indicate a void + result. + + NPInvalidateFunctionPtr is called by the scripting environment + when the native code is shutdown. Any attempt to message a + NPObject instance after the invalidate callback has been + called will result in undefined behavior, even if the native code + is still retaining those NPObject instances. (The runtime + will typically return immediately, with 0 or NULL, from an attempt + to dispatch to a NPObject, but this behavior should not be + depended upon.) + + The NPEnumerationFunctionPtr function may pass an array of + NPIdentifiers back to the caller. The callee allocs the memory of + the array using NPN_MemAlloc(), and it's the caller's responsibility + to release it using NPN_MemFree(). +*/ +struct NPClass { + uint32_t structVersion; + NPAllocateFunctionPtr allocate; + NPDeallocateFunctionPtr deallocate; + NPInvalidateFunctionPtr invalidate; + NPHasMethodFunctionPtr hasMethod; + NPInvokeFunctionPtr invoke; + NPInvokeDefaultFunctionPtr invokeDefault; + NPHasPropertyFunctionPtr hasProperty; + NPGetPropertyFunctionPtr getProperty; + NPSetPropertyFunctionPtr setProperty; + NPRemovePropertyFunctionPtr removeProperty; + NPEnumerationFunctionPtr enumerate; + NPConstructFunctionPtr construct; +}; + +#define NP_CLASS_STRUCT_VERSION 3 + +#define NP_CLASS_STRUCT_VERSION_ENUM 2 +#define NP_CLASS_STRUCT_VERSION_CTOR 3 + +#define NP_CLASS_STRUCT_VERSION_HAS_ENUM(npclass) \ + ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM) + +#define NP_CLASS_STRUCT_VERSION_HAS_CTOR(npclass) \ + ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR) + +struct NPObject { + NPClass *_class; + uint32_t referenceCount; + /* + * Additional space may be allocated here by types of NPObjects + */ +}; + +/* + If the class has an allocate function, NPN_CreateObject invokes + that function, otherwise a NPObject is allocated and + returned. This method will initialize the referenceCount member of + the NPObject to 1. +*/ +NPObject *NPN_CreateObject(NPP npp, NPClass *aClass); + +/* + Increment the NPObject's reference count. +*/ +NPObject *NPN_RetainObject(NPObject *npobj); + +/* + Decremented the NPObject's reference count. If the reference + count goes to zero, the class's destroy function is invoke if + specified, otherwise the object is freed directly. +*/ +void NPN_ReleaseObject(NPObject *npobj); + +/* + Functions to access script objects represented by NPObject. + + Calls to script objects are synchronous. If a function returns a + value, it will be supplied via the result NPVariant + argument. Successful calls will return true, false will be + returned in case of an error. + + Calls made from plugin code to script must be made from the thread + on which the plugin was initialized. +*/ + +bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName, + const NPVariant *args, uint32_t argCount, NPVariant *result); +bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args, + uint32_t argCount, NPVariant *result); +bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script, + NPVariant *result); +bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, + NPVariant *result); +bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, + const NPVariant *value); +bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName); +bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName); +bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName); +bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, + uint32_t *count); +bool NPN_Construct(NPP npp, NPObject *npobj, const NPVariant *args, + uint32_t argCount, NPVariant *result); + +/* + NPN_SetException may be called to trigger a script exception upon + return from entry points into NPObjects. Typical usage: + + NPN_SetException (npobj, message); +*/ +void NPN_SetException(NPObject *npobj, const NPUTF8 *message); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/thirdparties/common/include/npapi-sdk/headers/nptypes.h b/thirdparties/common/include/npapi-sdk/headers/nptypes.h new file mode 100644 index 0000000..c9e8513 --- /dev/null +++ b/thirdparties/common/include/npapi-sdk/headers/nptypes.h @@ -0,0 +1,121 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * mozilla.org. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Johnny Stenback (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nptypes_h_ +#define nptypes_h_ + +/* + * Header file for ensuring that C99 types ([u]int32_t, [u]int64_t and bool) and + * true/false macros are available. + */ + +#if defined(WIN32) || defined(OS2) +/* + * Win32 and OS/2 don't know C99, so define [u]int_16/32/64 here. The bool + * is predefined tho, both in C and C++. + */ +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; +#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX) +/* + * AIX and SunOS ship a inttypes.h header that defines [u]int32_t, + * but not bool for C. + */ +#include + +#ifndef __cplusplus +typedef int bool; +#define true 1 +#define false 0 +#endif +#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD) +/* + * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and + * u_int32_t. + */ +#include + +/* + * BSD/OS ships no header that defines uint32_t, nor bool (for C) + */ +#if defined(bsdi) +typedef u_int32_t uint32_t; +typedef u_int64_t uint64_t; + +#if !defined(__cplusplus) +typedef int bool; +#define true 1 +#define false 0 +#endif +#else +/* + * FreeBSD and OpenBSD define uint32_t and bool. + */ +#include +#include +#endif +#elif defined(BEOS) +#include +#else +/* + * For those that ship a standard C99 stdint.h header file, include + * it. Can't do the same for stdbool.h tho, since some systems ship + * with a stdbool.h file that doesn't compile! + */ +#include + +#ifndef __cplusplus +#if !defined(__GNUC__) || (__GNUC__ > 2 || __GNUC_MINOR__ > 95) +#include +#else +/* + * GCC 2.91 can't deal with a typedef for bool, but a #define + * works. + */ +#define bool int +#define true 1 +#define false 0 +#endif +#endif +#endif + +#endif /* nptypes_h_ */ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/audiotrack.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/audiotrack.h new file mode 100644 index 0000000..5387946 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/audiotrack.h @@ -0,0 +1,70 @@ +/* + * 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_APP_WEBRTC_AUDIOTRACK_H_ +#define TALK_APP_WEBRTC_AUDIOTRACK_H_ + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/mediastreamtrack.h" +#include "talk/app/webrtc/notifier.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/scoped_ref_ptr.h" + +namespace webrtc { + +class AudioTrack : public MediaStreamTrack { + public: + static talk_base::scoped_refptr Create( + const std::string& id, AudioSourceInterface* source); + + // AudioTrackInterface implementation. + virtual AudioSourceInterface* GetSource() const OVERRIDE { + return audio_source_.get(); + } + // 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 GetAudioProcessor() + OVERRIDE { return NULL; } + virtual cricket::AudioRenderer* GetRenderer() OVERRIDE { + return NULL; + } + + // MediaStreamTrack implementation. + virtual std::string kind() const OVERRIDE; + + protected: + AudioTrack(const std::string& label, AudioSourceInterface* audio_source); + + private: + talk_base::scoped_refptr audio_source_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_AUDIOTRACK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/audiotrackrenderer.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/audiotrackrenderer.h new file mode 100644 index 0000000..32fc85d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/audiotrackrenderer.h @@ -0,0 +1,59 @@ +/* + * 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_APP_WEBRTC_AUDIOTRACKRENDERER_H_ +#define TALK_APP_WEBRTC_AUDIOTRACKRENDERER_H_ + +#include "talk/base/thread.h" +#include "talk/media/base/audiorenderer.h" + +namespace webrtc { + +// Class used for AudioTrack to get the ID of WebRtc voice channel that +// the AudioTrack is connecting to. +// Each AudioTrack owns a AudioTrackRenderer instance. +// AddChannel() will be called when an AudioTrack is added to a MediaStream. +// RemoveChannel will be called when the AudioTrack or WebRtc VoE channel is +// going away. +// This implementation only supports one channel, and it is only used by +// Chrome for remote audio tracks." +class AudioTrackRenderer : public cricket::AudioRenderer { + public: + AudioTrackRenderer(); + ~AudioTrackRenderer(); + + // Implements cricket::AudioRenderer. + virtual void AddChannel(int channel_id) OVERRIDE; + virtual void RemoveChannel(int channel_id) OVERRIDE; + + private: + int channel_id_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_AUDIOTRACKRENDERER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/datachannel.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/datachannel.h new file mode 100644 index 0000000..3fc3c8c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/datachannel.h @@ -0,0 +1,246 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_DATACHANNEL_H_ +#define TALK_APP_WEBRTC_DATACHANNEL_H_ + +#include +#include + +#include "talk/app/webrtc/datachannelinterface.h" +#include "talk/app/webrtc/proxy.h" +#include "talk/base/messagehandler.h" +#include "talk/base/scoped_ref_ptr.h" +#include "talk/base/sigslot.h" +#include "talk/media/base/mediachannel.h" +#include "talk/session/media/channel.h" + +namespace webrtc { + +class DataChannel; + +class DataChannelProviderInterface { + public: + // Sends the data to the transport. + virtual bool SendData(const cricket::SendDataParams& params, + const talk_base::Buffer& payload, + cricket::SendDataResult* result) = 0; + // Connects to the transport signals. + virtual bool ConnectDataChannel(DataChannel* data_channel) = 0; + // Disconnects from the transport signals. + virtual void DisconnectDataChannel(DataChannel* data_channel) = 0; + // Adds the data channel SID to the transport for SCTP. + virtual void AddSctpDataStream(uint32 sid) = 0; + // Removes the data channel SID from the transport for SCTP. + virtual void RemoveSctpDataStream(uint32 sid) = 0; + // Returns true if the transport channel is ready to send data. + virtual bool ReadyToSendData() const = 0; + + protected: + 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 +// both RtpDataEngine and SctpDataEngine. + +// DataChannel states: +// kConnecting: The channel has been created the transport might not yet be +// ready. +// kOpen: The channel have a local SSRC set by a call to UpdateSendSsrc +// and a remote SSRC set by call to UpdateReceiveSsrc and the transport +// has been writable once. +// kClosing: DataChannelInterface::Close has been called or UpdateReceiveSsrc +// has been called with SSRC==0 +// kClosed: Both UpdateReceiveSsrc and UpdateSendSsrc has been called with +// SSRC==0. +class DataChannel : public DataChannelInterface, + public sigslot::has_slots<>, + public talk_base::MessageHandler { + public: + static talk_base::scoped_refptr Create( + DataChannelProviderInterface* provider, + cricket::DataChannelType dct, + const std::string& label, + const InternalDataChannelInit& config); + + virtual void RegisterObserver(DataChannelObserver* observer); + virtual void UnregisterObserver(); + + virtual std::string label() const { return label_; } + virtual bool reliable() const; + virtual bool ordered() const { return config_.ordered; } + virtual uint16 maxRetransmitTime() const { + return config_.maxRetransmitTime; + } + virtual uint16 maxRetransmits() const { + return config_.maxRetransmits; + } + virtual std::string protocol() const { return config_.protocol; } + virtual bool negotiated() const { return config_.negotiated; } + virtual int id() const { return config_.id; } + virtual uint64 buffered_amount() const; + virtual void Close(); + virtual DataState state() const { return state_; } + virtual bool Send(const DataBuffer& buffer); + + // talk_base::MessageHandler override. + virtual void OnMessage(talk_base::Message* msg); + + // Called if the underlying data engine is closing. + void OnDataEngineClose(); + + // Called when the channel's ready to use. That can happen when the + // underlying DataMediaChannel becomes ready, or when this channel is a new + // stream on an existing DataMediaChannel, and we've finished negotiation. + void OnChannelReady(bool writable); + + // Sigslots from cricket::DataChannel + void OnDataReceived(cricket::DataChannel* channel, + const cricket::ReceiveDataParams& params, + const talk_base::Buffer& payload); + + // The remote peer request that this channel should be closed. + void RemotePeerRequestClose(); + + // The following methods are for SCTP only. + + // Sets the SCTP sid and adds to transport layer if not set yet. + void SetSctpSid(int sid); + // Called when the transport channel is created. + void OnTransportChannelCreated(); + + // The following methods are for RTP only. + + // Set the SSRC this channel should use to send data on the + // underlying data engine. |send_ssrc| == 0 means that the channel is no + // longer part of the session negotiation. + void SetSendSsrc(uint32 send_ssrc); + // Set the SSRC this channel should use to receive data from the + // underlying data engine. + void SetReceiveSsrc(uint32 receive_ssrc); + + cricket::DataChannelType data_channel_type() const { + return data_channel_type_; + } + + protected: + DataChannel(DataChannelProviderInterface* client, + cricket::DataChannelType dct, + const std::string& label); + virtual ~DataChannel(); + + private: + bool Init(const InternalDataChannelInit& config); + void DoClose(); + void UpdateState(); + void SetState(DataState state); + void DisconnectFromTransport(); + void DeliverQueuedControlData(); + void QueueControl(const talk_base::Buffer* buffer); + void ClearQueuedControlData(); + void DeliverQueuedReceivedData(); + void ClearQueuedReceivedData(); + void DeliverQueuedSendData(); + void ClearQueuedSendData(); + bool InternalSendWithoutQueueing(const DataBuffer& buffer, + 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_; + InternalDataChannelInit config_; + DataChannelObserver* observer_; + DataState state_; + cricket::DataChannelType data_channel_type_; + DataChannelProviderInterface* provider_; + bool waiting_for_open_ack_; + bool was_ever_writable_; + bool connected_to_provider_; + bool send_ssrc_set_; + bool receive_ssrc_set_; + uint32 send_ssrc_; + uint32 receive_ssrc_; + // Control messages that always have to get sent out before any queued + // data. + std::queue queued_control_data_; + std::queue queued_received_data_; + std::deque queued_send_data_; +}; + +class DataChannelFactory { + public: + virtual talk_base::scoped_refptr CreateDataChannel( + const std::string& label, + const InternalDataChannelInit* config) = 0; + + protected: + virtual ~DataChannelFactory() {} +}; + +// Define proxy for DataChannelInterface. +BEGIN_PROXY_MAP(DataChannel) + PROXY_METHOD1(void, RegisterObserver, DataChannelObserver*) + PROXY_METHOD0(void, UnregisterObserver) + PROXY_CONSTMETHOD0(std::string, label) + PROXY_CONSTMETHOD0(bool, reliable) + PROXY_CONSTMETHOD0(bool, ordered) + PROXY_CONSTMETHOD0(uint16, maxRetransmitTime) + PROXY_CONSTMETHOD0(uint16, maxRetransmits) + PROXY_CONSTMETHOD0(std::string, protocol) + PROXY_CONSTMETHOD0(bool, negotiated) + PROXY_CONSTMETHOD0(int, id) + PROXY_CONSTMETHOD0(DataState, state) + PROXY_CONSTMETHOD0(uint64, buffered_amount) + PROXY_METHOD0(void, Close) + PROXY_METHOD1(bool, Send, const DataBuffer&) +END_PROXY() + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_DATACHANNEL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/datachannelinterface.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/datachannelinterface.h new file mode 100644 index 0000000..8f4e031 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/datachannelinterface.h @@ -0,0 +1,141 @@ +/* + * 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. + */ + +// This file contains interfaces for DataChannels +// http://dev.w3.org/2011/webrtc/editor/webrtc.html#rtcdatachannel + +#ifndef TALK_APP_WEBRTC_DATACHANNELINTERFACE_H_ +#define TALK_APP_WEBRTC_DATACHANNELINTERFACE_H_ + +#include + +#include "talk/base/basictypes.h" +#include "talk/base/buffer.h" +#include "talk/base/refcount.h" + + +namespace webrtc { + +struct DataChannelInit { + DataChannelInit() + : reliable(false), + ordered(true), + maxRetransmitTime(-1), + maxRetransmits(-1), + negotiated(false), + id(-1) { + } + + bool reliable; // Deprecated. + bool ordered; // True if ordered delivery is required. + int maxRetransmitTime; // The max period of time in milliseconds in which + // retransmissions will be sent. After this time, no + // more retransmissions will be sent. -1 if unset. + int maxRetransmits; // The max number of retransmissions. -1 if unset. + std::string protocol; // This is set by the application and opaque to the + // WebRTC implementation. + bool negotiated; // True if the channel has been externally negotiated + // and we do not send an in-band signalling in the + // form of an "open" message. + int id; // The stream id, or SID, for SCTP data channels. -1 + // if unset. +}; + +struct DataBuffer { + DataBuffer(const talk_base::Buffer& data, bool binary) + : data(data), + binary(binary) { + } + // For convenience for unit tests. + explicit DataBuffer(const std::string& text) + : data(text.data(), text.length()), + binary(false) { + } + size_t size() const { return data.length(); } + + talk_base::Buffer data; + // Indicates if the received data contains UTF-8 or binary data. + // Note that the upper layers are left to verify the UTF-8 encoding. + // TODO(jiayl): prefer to use an enum instead of a bool. + bool binary; +}; + +class DataChannelObserver { + public: + // The data channel state have changed. + virtual void OnStateChange() = 0; + // A data buffer was successfully received. + virtual void OnMessage(const DataBuffer& buffer) = 0; + + protected: + virtual ~DataChannelObserver() {} +}; + +class DataChannelInterface : public talk_base::RefCountInterface { + public: + // Keep in sync with DataChannel.java:State and + // RTCDataChannel.h:RTCDataChannelState. + enum DataState { + kConnecting, + kOpen, // The DataChannel is ready to send data. + kClosing, + kClosed + }; + + virtual void RegisterObserver(DataChannelObserver* observer) = 0; + virtual void UnregisterObserver() = 0; + // The label attribute represents a label that can be used to distinguish this + // DataChannel object from other DataChannel objects. + virtual std::string label() const = 0; + virtual bool reliable() const = 0; + + // TODO(tommyw): Remove these dummy implementations when all classes have + // implemented these APIs. They should all just return the values the + // DataChannel was created with. + virtual bool ordered() const { return false; } + virtual uint16 maxRetransmitTime() const { return 0; } + virtual uint16 maxRetransmits() const { return 0; } + virtual std::string protocol() const { return std::string(); } + virtual bool negotiated() const { return false; } + + virtual int id() const = 0; + virtual DataState state() const = 0; + // The buffered_amount returns the number of bytes of application data + // (UTF-8 text and binary data) that have been queued using SendBuffer but + // have not yet been transmitted to the network. + virtual uint64 buffered_amount() const = 0; + virtual void Close() = 0; + // Sends |data| to the remote peer. + virtual bool Send(const DataBuffer& buffer) = 0; + + protected: + virtual ~DataChannelInterface() {} +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_DATACHANNELINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/dtmfsender.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/dtmfsender.h new file mode 100644 index 0000000..e47dcf2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/dtmfsender.h @@ -0,0 +1,138 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_DTMFSENDER_H_ +#define TALK_APP_WEBRTC_DTMFSENDER_H_ + +#include + +#include "talk/app/webrtc/dtmfsenderinterface.h" +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/proxy.h" +#include "talk/base/common.h" +#include "talk/base/messagehandler.h" +#include "talk/base/refcount.h" + +// DtmfSender is the native implementation of the RTCDTMFSender defined by +// the WebRTC W3C Editor's Draft. +// http://dev.w3.org/2011/webrtc/editor/webrtc.html + +namespace talk_base { +class Thread; +} + +namespace webrtc { + +// This interface is called by DtmfSender to talk to the actual audio channel +// to send DTMF. +class DtmfProviderInterface { + public: + // Returns true if the audio track with given id (|track_id|) is capable + // of sending DTMF. Otherwise returns false. + virtual bool CanInsertDtmf(const std::string& track_id) = 0; + // Sends DTMF |code| via the audio track with given id (|track_id|). + // The |duration| indicates the length of the DTMF tone in ms. + // Returns true on success and false on failure. + virtual bool InsertDtmf(const std::string& track_id, + int code, int duration) = 0; + // Returns a |sigslot::signal0<>| signal. The signal should fire before + // the provider is destroyed. + virtual sigslot::signal0<>* GetOnDestroyedSignal() = 0; + + protected: + virtual ~DtmfProviderInterface() {} +}; + +class DtmfSender + : public DtmfSenderInterface, + public sigslot::has_slots<>, + public talk_base::MessageHandler { + public: + static talk_base::scoped_refptr Create( + AudioTrackInterface* track, + talk_base::Thread* signaling_thread, + DtmfProviderInterface* provider); + + // Implements DtmfSenderInterface. + virtual void RegisterObserver(DtmfSenderObserverInterface* observer) OVERRIDE; + virtual void UnregisterObserver() OVERRIDE; + virtual bool CanInsertDtmf() OVERRIDE; + virtual bool InsertDtmf(const std::string& tones, int duration, + int inter_tone_gap) OVERRIDE; + virtual const AudioTrackInterface* track() const OVERRIDE; + virtual std::string tones() const OVERRIDE; + virtual int duration() const OVERRIDE; + virtual int inter_tone_gap() const OVERRIDE; + + protected: + DtmfSender(AudioTrackInterface* track, + talk_base::Thread* signaling_thread, + DtmfProviderInterface* provider); + virtual ~DtmfSender(); + + private: + DtmfSender(); + + // Implements MessageHandler. + virtual void OnMessage(talk_base::Message* msg); + + // The DTMF sending task. + void DoInsertDtmf(); + + void OnProviderDestroyed(); + + void StopSending(); + + talk_base::scoped_refptr track_; + DtmfSenderObserverInterface* observer_; + talk_base::Thread* signaling_thread_; + DtmfProviderInterface* provider_; + std::string tones_; + int duration_; + int inter_tone_gap_; + + DISALLOW_COPY_AND_ASSIGN(DtmfSender); +}; + +// Define proxy for DtmfSenderInterface. +BEGIN_PROXY_MAP(DtmfSender) + PROXY_METHOD1(void, RegisterObserver, DtmfSenderObserverInterface*) + PROXY_METHOD0(void, UnregisterObserver) + PROXY_METHOD0(bool, CanInsertDtmf) + PROXY_METHOD3(bool, InsertDtmf, const std::string&, int, int) + PROXY_CONSTMETHOD0(const AudioTrackInterface*, track) + PROXY_CONSTMETHOD0(std::string, tones) + PROXY_CONSTMETHOD0(int, duration) + PROXY_CONSTMETHOD0(int, inter_tone_gap) +END_PROXY() + +// Get DTMF code from the DTMF event character. +bool GetDtmfCode(char tone, int* code); + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_DTMFSENDER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/dtmfsenderinterface.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/dtmfsenderinterface.h new file mode 100644 index 0000000..bea6625 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/dtmfsenderinterface.h @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_DTMFSENDERINTERFACE_H_ +#define TALK_APP_WEBRTC_DTMFSENDERINTERFACE_H_ + +#include + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/base/common.h" +#include "talk/base/refcount.h" + +// This file contains interfaces for DtmfSender. + +namespace webrtc { + +// DtmfSender callback interface. Application should implement this interface +// to get notifications from the DtmfSender. +class DtmfSenderObserverInterface { + public: + // Triggered when DTMF |tone| is sent. + // If |tone| is empty that means the DtmfSender has sent out all the given + // tones. + virtual void OnToneChange(const std::string& tone) = 0; + + protected: + virtual ~DtmfSenderObserverInterface() {} +}; + +// The interface of native implementation of the RTCDTMFSender defined by the +// WebRTC W3C Editor's Draft. +class DtmfSenderInterface : public talk_base::RefCountInterface { + public: + virtual void RegisterObserver(DtmfSenderObserverInterface* observer) = 0; + virtual void UnregisterObserver() = 0; + + // Returns true if this DtmfSender is capable of sending DTMF. + // Otherwise returns false. + virtual bool CanInsertDtmf() = 0; + + // Queues a task that sends the DTMF |tones|. The |tones| parameter is treated + // as a series of characters. The characters 0 through 9, A through D, #, and + // * generate the associated DTMF tones. The characters a to d are equivalent + // to A to D. The character ',' indicates a delay of 2 seconds before + // processing the next character in the tones parameter. + // Unrecognized characters are ignored. + // The |duration| parameter indicates the duration in ms to use for each + // character passed in the |tones| parameter. + // The duration cannot be more than 6000 or less than 70. + // The |inter_tone_gap| parameter indicates the gap between tones in ms. + // The |inter_tone_gap| must be at least 50 ms but should be as short as + // possible. + // If InsertDtmf is called on the same object while an existing task for this + // object to generate DTMF is still running, the previous task is canceled. + // Returns true on success and false on failure. + virtual bool InsertDtmf(const std::string& tones, int duration, + int inter_tone_gap) = 0; + + // Returns the track given as argument to the constructor. + virtual const AudioTrackInterface* track() const = 0; + + // Returns the tones remaining to be played out. + virtual std::string tones() const = 0; + + // Returns the current tone duration value in ms. + // This value will be the value last set via the InsertDtmf() method, or the + // default value of 100 ms if InsertDtmf() was never called. + virtual int duration() const = 0; + + // Returns the current value of the between-tone gap in ms. + // This value will be the value last set via the InsertDtmf() method, or the + // default value of 50 ms if InsertDtmf() was never called. + virtual int inter_tone_gap() const = 0; + + protected: + virtual ~DtmfSenderInterface() {} +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_DTMFSENDERINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/fakeportallocatorfactory.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/fakeportallocatorfactory.h new file mode 100644 index 0000000..366f796 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/fakeportallocatorfactory.h @@ -0,0 +1,74 @@ +/* + * 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. + */ + +// This file defines a fake port allocator factory used for testing. +// This implementation creates instances of cricket::FakePortAllocator. + +#ifndef TALK_APP_WEBRTC_FAKEPORTALLOCATORFACTORY_H_ +#define TALK_APP_WEBRTC_FAKEPORTALLOCATORFACTORY_H_ + +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/p2p/client/fakeportallocator.h" + +namespace webrtc { + +class FakePortAllocatorFactory : public PortAllocatorFactoryInterface { + public: + static FakePortAllocatorFactory* Create() { + talk_base::RefCountedObject* allocator = + new talk_base::RefCountedObject(); + return allocator; + } + + virtual cricket::PortAllocator* CreatePortAllocator( + const std::vector& stun_configurations, + const std::vector& turn_configurations) { + stun_configs_ = stun_configurations; + turn_configs_ = turn_configurations; + return new cricket::FakePortAllocator(talk_base::Thread::Current(), NULL); + } + + const std::vector& stun_configs() const { + return stun_configs_; + } + + const std::vector& turn_configs() const { + return turn_configs_; + } + + protected: + FakePortAllocatorFactory() {} + ~FakePortAllocatorFactory() {} + + private: + std::vector stun_configs_; + std::vector turn_configs_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_FAKEPORTALLOCATORFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsep.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsep.h new file mode 100644 index 0000000..cb06b48 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsep.h @@ -0,0 +1,164 @@ +/* + * 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. + */ + +// Interfaces matching the draft-ietf-rtcweb-jsep-01. + +#ifndef TALK_APP_WEBRTC_JSEP_H_ +#define TALK_APP_WEBRTC_JSEP_H_ + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/refcount.h" + +namespace cricket { +class SessionDescription; +class Candidate; +} // namespace cricket + +namespace webrtc { + +struct SdpParseError { + public: + // The sdp line that causes the error. + std::string line; + // Explains the error. + std::string description; +}; + +// Class representation of an ICE candidate. +// An instance of this interface is supposed to be owned by one class at +// a time and is therefore not expected to be thread safe. +class IceCandidateInterface { + public: + virtual ~IceCandidateInterface() {} + /// If present, this contains the identierfier of the "media stream + // identification" as defined in [RFC 3388] for m-line this candidate is + // assocated with. + virtual std::string sdp_mid() const = 0; + // This indeicates the index (starting at zero) of m-line in the SDP this + // candidate is assocated with. + virtual int sdp_mline_index() const = 0; + virtual const cricket::Candidate& candidate() const = 0; + // Creates a SDP-ized form of this candidate. + virtual bool ToString(std::string* out) const = 0; +}; + +// Creates a IceCandidateInterface based on SDP string. +// Returns NULL if the sdp string can't be parsed. +// TODO(ronghuawu): Deprecated. +IceCandidateInterface* CreateIceCandidate(const std::string& sdp_mid, + int sdp_mline_index, + const std::string& sdp); + +// |error| can be NULL if doesn't care about the failure reason. +IceCandidateInterface* CreateIceCandidate(const std::string& sdp_mid, + int sdp_mline_index, + const std::string& sdp, + SdpParseError* error); + +// This class represents a collection of candidates for a specific m-line. +// This class is used in SessionDescriptionInterface to represent all known +// candidates for a certain m-line. +class IceCandidateCollection { + public: + virtual ~IceCandidateCollection() {} + virtual size_t count() const = 0; + // Returns true if an equivalent |candidate| exist in the collection. + virtual bool HasCandidate(const IceCandidateInterface* candidate) const = 0; + virtual const IceCandidateInterface* at(size_t index) const = 0; +}; + +// Class representation of a Session description. +// An instance of this interface is supposed to be owned by one class at +// a time and is therefore not expected to be thread safe. +class SessionDescriptionInterface { + public: + // Supported types: + static const char kOffer[]; + static const char kPrAnswer[]; + static const char kAnswer[]; + + virtual ~SessionDescriptionInterface() {} + virtual cricket::SessionDescription* description() = 0; + virtual const cricket::SessionDescription* description() const = 0; + // Get the session id and session version, which are defined based on + // RFC 4566 for the SDP o= line. + virtual std::string session_id() const = 0; + virtual std::string session_version() const = 0; + virtual std::string type() const = 0; + // Adds the specified candidate to the description. + // Ownership is not transferred. + // Returns false if the session description does not have a media section that + // corresponds to the |candidate| label. + virtual bool AddCandidate(const IceCandidateInterface* candidate) = 0; + // Returns the number of m- lines in the session description. + virtual size_t number_of_mediasections() const = 0; + // Returns a collection of all candidates that belong to a certain m-line + virtual const IceCandidateCollection* candidates( + size_t mediasection_index) const = 0; + // Serializes the description to SDP. + virtual bool ToString(std::string* out) const = 0; +}; + +// Creates a SessionDescriptionInterface based on SDP string and the type. +// Returns NULL if the sdp string can't be parsed or the type is unsupported. +// TODO(ronghuawu): Deprecated. +SessionDescriptionInterface* CreateSessionDescription(const std::string& type, + const std::string& sdp); + +// |error| can be NULL if doesn't care about the failure reason. +SessionDescriptionInterface* CreateSessionDescription(const std::string& type, + const std::string& sdp, + SdpParseError* error); + +// Jsep CreateOffer and CreateAnswer callback interface. +class CreateSessionDescriptionObserver : public talk_base::RefCountInterface { + public: + // The implementation of the CreateSessionDescriptionObserver takes + // the ownership of the |desc|. + virtual void OnSuccess(SessionDescriptionInterface* desc) = 0; + virtual void OnFailure(const std::string& error) = 0; + + protected: + ~CreateSessionDescriptionObserver() {} +}; + +// Jsep SetLocalDescription and SetRemoteDescription callback interface. +class SetSessionDescriptionObserver : public talk_base::RefCountInterface { + public: + virtual void OnSuccess() = 0; + virtual void OnFailure(const std::string& error) = 0; + + protected: + ~SetSessionDescriptionObserver() {} +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_JSEP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsepicecandidate.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsepicecandidate.h new file mode 100644 index 0000000..74bee11 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsepicecandidate.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +// Implements the IceCandidateInterface. + +#ifndef TALK_APP_WEBRTC_JSEPICECANDIDATE_H_ +#define TALK_APP_WEBRTC_JSEPICECANDIDATE_H_ + +#include + +#include "talk/app/webrtc/jsep.h" +#include "talk/base/constructormagic.h" +#include "talk/p2p/base/candidate.h" + +namespace webrtc { + +class JsepIceCandidate : public IceCandidateInterface { + public: + JsepIceCandidate(const std::string& sdp_mid, int sdp_mline_index); + JsepIceCandidate(const std::string& sdp_mid, int sdp_mline_index, + const cricket::Candidate& candidate); + ~JsepIceCandidate(); + // |error| can be NULL if don't care about the failure reason. + bool Initialize(const std::string& sdp, SdpParseError* err); + void SetCandidate(const cricket::Candidate& candidate) { + candidate_ = candidate; + } + + virtual std::string sdp_mid() const { return sdp_mid_; } + virtual int sdp_mline_index() const { return sdp_mline_index_; } + virtual const cricket::Candidate& candidate() const { + return candidate_; + } + + virtual bool ToString(std::string* out) const; + + private: + std::string sdp_mid_; + int sdp_mline_index_; + cricket::Candidate candidate_; + + DISALLOW_COPY_AND_ASSIGN(JsepIceCandidate); +}; + +// Implementation of IceCandidateCollection. +// This implementation stores JsepIceCandidates. +class JsepCandidateCollection : public IceCandidateCollection { + public: + ~JsepCandidateCollection(); + virtual size_t count() const { + return candidates_.size(); + } + virtual bool HasCandidate(const IceCandidateInterface* candidate) const; + // Adds and takes ownership of the JsepIceCandidate. + virtual void add(JsepIceCandidate* candidate) { + candidates_.push_back(candidate); + } + virtual const IceCandidateInterface* at(size_t index) const { + return candidates_[index]; + } + + private: + std::vector candidates_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_JSEPICECANDIDATE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsepsessiondescription.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsepsessiondescription.h new file mode 100644 index 0000000..767ae28 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/jsepsessiondescription.h @@ -0,0 +1,106 @@ +/* + * 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. + */ + +// Implements the SessionDescriptionInterface. + +#ifndef TALK_APP_WEBRTC_JSEPSESSIONDESCRIPTION_H_ +#define TALK_APP_WEBRTC_JSEPSESSIONDESCRIPTION_H_ + +#include +#include + +#include "talk/app/webrtc/jsep.h" +#include "talk/app/webrtc/jsepicecandidate.h" +#include "talk/base/scoped_ptr.h" + +namespace cricket { +class SessionDescription; +} + +namespace webrtc { + +class JsepSessionDescription : public SessionDescriptionInterface { + public: + explicit JsepSessionDescription(const std::string& type); + virtual ~JsepSessionDescription(); + + // |error| can be NULL if don't care about the failure reason. + bool Initialize(const std::string& sdp, SdpParseError* error); + + // Takes ownership of |description|. + bool Initialize(cricket::SessionDescription* description, + const std::string& session_id, + const std::string& session_version); + + virtual cricket::SessionDescription* description() { + return description_.get(); + } + virtual const cricket::SessionDescription* description() const { + return description_.get(); + } + virtual std::string session_id() const { + return session_id_; + } + virtual std::string session_version() const { + return session_version_; + } + virtual std::string type() const { + return type_; + } + // Allow changing the type. Used for testing. + void set_type(const std::string& type) { type_ = type; } + virtual bool AddCandidate(const IceCandidateInterface* candidate); + virtual size_t number_of_mediasections() const; + virtual const IceCandidateCollection* candidates( + size_t mediasection_index) const; + virtual bool ToString(std::string* out) const; + + // Default video encoder settings. The resolution is the max resolution. + // TODO(perkj): Implement proper negotiation of video resolution. + static const int kDefaultVideoCodecId; + static const int kDefaultVideoCodecFramerate; + static const char kDefaultVideoCodecName[]; + static const int kMaxVideoCodecWidth; + static const int kMaxVideoCodecHeight; + static const int kDefaultVideoCodecPreference; + + private: + talk_base::scoped_ptr description_; + std::string session_id_; + std::string session_version_; + std::string type_; + std::vector candidate_collection_; + + bool GetMediasectionIndex(const IceCandidateInterface* candidate, + size_t* index); + + DISALLOW_COPY_AND_ASSIGN(JsepSessionDescription); +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_JSEPSESSIONDESCRIPTION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/localaudiosource.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/localaudiosource.h new file mode 100644 index 0000000..5296633 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/localaudiosource.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_LOCALAUDIOSOURCE_H_ +#define TALK_APP_WEBRTC_LOCALAUDIOSOURCE_H_ + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/notifier.h" +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/base/scoped_ptr.h" +#include "talk/media/base/mediachannel.h" + +// LocalAudioSource implements AudioSourceInterface. +// This contains settings for switching audio processing on and off. + +namespace webrtc { + +class MediaConstraintsInterface; + +class LocalAudioSource : public Notifier { + public: + // Creates an instance of LocalAudioSource. + static talk_base::scoped_refptr Create( + const PeerConnectionFactoryInterface::Options& options, + const MediaConstraintsInterface* constraints); + + virtual SourceState state() const { return source_state_; } + virtual const cricket::AudioOptions& options() const { return options_; } + + protected: + LocalAudioSource() + : source_state_(kInitializing) { + } + + ~LocalAudioSource() { + } + + private: + void Initialize(const PeerConnectionFactoryInterface::Options& options, + const MediaConstraintsInterface* constraints); + + cricket::AudioOptions options_; + SourceState source_state_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_LOCALAUDIOSOURCE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediaconstraintsinterface.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediaconstraintsinterface.h new file mode 100644 index 0000000..097a555 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediaconstraintsinterface.h @@ -0,0 +1,145 @@ +/* + * 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. + */ + +// This file contains the interface for MediaConstraints, corresponding to +// the definition at +// http://www.w3.org/TR/mediacapture-streams/#mediastreamconstraints and also +// used in WebRTC: http://dev.w3.org/2011/webrtc/editor/webrtc.html#constraints. + +#ifndef TALK_APP_WEBRTC_MEDIACONSTRAINTSINTERFACE_H_ +#define TALK_APP_WEBRTC_MEDIACONSTRAINTSINTERFACE_H_ + +#include +#include + +namespace webrtc { + +// MediaConstraintsInterface +// Interface used for passing arguments about media constraints +// to the MediaStream and PeerConnection implementation. +class MediaConstraintsInterface { + public: + struct Constraint { + Constraint() {} + Constraint(const std::string& key, const std::string value) + : key(key), value(value) { + } + std::string key; + std::string value; + }; + + class Constraints : public std::vector { + public: + bool FindFirst(const std::string& key, std::string* value) const; + }; + + 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 + static const char kMaxAspectRatio[]; // maxAspectRatio + static const char kMaxWidth[]; // maxWidth + static const char kMinWidth[]; // minWidth + static const char kMaxHeight[]; // maxHeight + static const char kMinHeight[]; // minHeight + static const char kMaxFrameRate[]; // maxFrameRate + static const char kMinFrameRate[]; // minFrameRate + + // Constraint keys used by a local audio source. + // These keys are google specific. + static const char kEchoCancellation[]; // googEchoCancellation + static const char kExperimentalEchoCancellation[]; // googEchoCancellation2 + 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 + + // Google-specific constraint keys for a local video source + static const char kNoiseReduction[]; // googNoiseReduction + static const char kLeakyBucket[]; // googLeakyBucket + static const char kTemporalLayeredScreencast[]; + // googTemporalLayeredScreencast + + // Constraint keys for CreateOffer / CreateAnswer + // Specified by the W3C PeerConnection spec + static const char kOfferToReceiveVideo[]; // OfferToReceiveVideo + static const char kOfferToReceiveAudio[]; // OfferToReceiveAudio + static const char kVoiceActivityDetection[]; // VoiceActivityDetection + static const char kIceRestart[]; // IceRestart + // These keys are google specific. + static const char kUseRtpMux[]; // googUseRtpMUX + + // Constraints values. + 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 + // Google-specific constraint keys. + // Temporary pseudo-constraint for enabling DSCP through JS. + 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 + static const char kCpuOveruseEncodeUsage[]; // googCpuOveruseEncodeUsage + static const char kHighStartBitrate[]; // googHighStartBitrate + static const char kHighBitrate[]; // googHighBitrate + static const char kVeryHighBitrate[]; // googVeryHighBitrate + + // The prefix of internal-only constraints whose JS set values should be + // stripped by Chrome before passed down to Libjingle. + static const char kInternalConstraintPrefix[]; + + protected: + // Dtor protected as objects shouldn't be deleted via this interface + virtual ~MediaConstraintsInterface() {} +}; + +bool FindConstraint(const MediaConstraintsInterface* constraints, + const std::string& key, bool* value, + size_t* mandatory_constraints); + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_MEDIACONSTRAINTSINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastream.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastream.h new file mode 100644 index 0000000..3d53221 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastream.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +// This file contains the implementation of MediaStreamInterface interface. + +#ifndef TALK_APP_WEBRTC_MEDIASTREAM_H_ +#define TALK_APP_WEBRTC_MEDIASTREAM_H_ + +#include +#include + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/notifier.h" + +namespace webrtc { + +class MediaStream : public Notifier { + public: + static talk_base::scoped_refptr Create(const std::string& label); + + virtual std::string label() const OVERRIDE { return label_; } + + virtual bool AddTrack(AudioTrackInterface* track) OVERRIDE; + virtual bool AddTrack(VideoTrackInterface* track) OVERRIDE; + virtual bool RemoveTrack(AudioTrackInterface* track) OVERRIDE; + virtual bool RemoveTrack(VideoTrackInterface* track) OVERRIDE; + virtual talk_base::scoped_refptr + FindAudioTrack(const std::string& track_id); + virtual talk_base::scoped_refptr + FindVideoTrack(const std::string& track_id); + + virtual AudioTrackVector GetAudioTracks() OVERRIDE { return audio_tracks_; } + virtual VideoTrackVector GetVideoTracks() OVERRIDE { return video_tracks_; } + + protected: + explicit MediaStream(const std::string& label); + + private: + template + bool AddTrack(TrackVector* Tracks, Track* track); + template + bool RemoveTrack(TrackVector* Tracks, MediaStreamTrackInterface* track); + + std::string label_; + AudioTrackVector audio_tracks_; + VideoTrackVector video_tracks_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_MEDIASTREAM_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamhandler.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamhandler.h new file mode 100644 index 0000000..0345152 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamhandler.h @@ -0,0 +1,295 @@ +/* + * 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. + */ + +// This file contains classes for listening on changes on MediaStreams and +// MediaTracks that are connected to a certain PeerConnection. +// Example: If a user sets a rendererer on a remote video track the renderer is +// connected to the appropriate remote video stream. + +#ifndef TALK_APP_WEBRTC_MEDIASTREAMHANDLER_H_ +#define TALK_APP_WEBRTC_MEDIASTREAMHANDLER_H_ + +#include +#include + +#include "talk/app/webrtc/mediastreaminterface.h" +#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 { + +// TrackHandler listen to events on a MediaStreamTrackInterface that is +// connected to a certain PeerConnection. +class TrackHandler : public ObserverInterface { + public: + TrackHandler(MediaStreamTrackInterface* track, uint32 ssrc); + virtual ~TrackHandler(); + virtual void OnChanged(); + // Stop using |track_| on this PeerConnection. + virtual void Stop() = 0; + + MediaStreamTrackInterface* track() { return track_; } + uint32 ssrc() const { return ssrc_; } + + protected: + virtual void OnStateChanged() = 0; + virtual void OnEnabledChanged() = 0; + + private: + talk_base::scoped_refptr track_; + uint32 ssrc_; + MediaStreamTrackInterface::TrackState state_; + 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. +class LocalAudioTrackHandler : public TrackHandler { + public: + LocalAudioTrackHandler(AudioTrackInterface* track, + uint32 ssrc, + AudioProviderInterface* provider); + virtual ~LocalAudioTrackHandler(); + + virtual void Stop() OVERRIDE; + + protected: + virtual void OnStateChanged() OVERRIDE; + virtual void OnEnabledChanged() OVERRIDE; + + 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 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 AudioSourceInterface::AudioObserver, + public TrackHandler { + public: + RemoteAudioTrackHandler(AudioTrackInterface* track, + uint32 ssrc, + AudioProviderInterface* provider); + virtual ~RemoteAudioTrackHandler(); + virtual void Stop() OVERRIDE; + + protected: + virtual void OnStateChanged() OVERRIDE; + virtual void OnEnabledChanged() OVERRIDE; + + private: + // AudioSourceInterface::AudioObserver implementation. + virtual void OnSetVolume(double volume) OVERRIDE; + + AudioTrackInterface* audio_track_; + AudioProviderInterface* provider_; +}; + +// LocalVideoTrackHandler listen to events on a local VideoTrack instance +// connected to a PeerConnection and orders the |provider| to executes the +// requested change. +class LocalVideoTrackHandler : public TrackHandler { + public: + LocalVideoTrackHandler(VideoTrackInterface* track, + uint32 ssrc, + VideoProviderInterface* provider); + virtual ~LocalVideoTrackHandler(); + virtual void Stop() OVERRIDE; + + protected: + virtual void OnStateChanged() OVERRIDE; + virtual void OnEnabledChanged() OVERRIDE; + + private: + VideoTrackInterface* local_video_track_; + VideoProviderInterface* provider_; +}; + +// RemoteVideoTrackHandler listen to events on a remote VideoTrack instance +// connected to a PeerConnection and orders the |provider| to execute +// requested changes. +class RemoteVideoTrackHandler : public TrackHandler { + public: + RemoteVideoTrackHandler(VideoTrackInterface* track, + uint32 ssrc, + VideoProviderInterface* provider); + virtual ~RemoteVideoTrackHandler(); + virtual void Stop() OVERRIDE; + + protected: + virtual void OnStateChanged() OVERRIDE; + virtual void OnEnabledChanged() OVERRIDE; + + private: + VideoTrackInterface* remote_video_track_; + VideoProviderInterface* provider_; +}; + +class MediaStreamHandler : public ObserverInterface { + public: + MediaStreamHandler(MediaStreamInterface* stream, + AudioProviderInterface* audio_provider, + VideoProviderInterface* video_provider); + ~MediaStreamHandler(); + MediaStreamInterface* stream(); + void Stop(); + + virtual void AddAudioTrack(AudioTrackInterface* audio_track, uint32 ssrc) = 0; + virtual void AddVideoTrack(VideoTrackInterface* video_track, uint32 ssrc) = 0; + + virtual void RemoveTrack(MediaStreamTrackInterface* track); + virtual void OnChanged() OVERRIDE; + + protected: + TrackHandler* FindTrackHandler(MediaStreamTrackInterface* track); + talk_base::scoped_refptr stream_; + AudioProviderInterface* audio_provider_; + VideoProviderInterface* video_provider_; + typedef std::vector TrackHandlers; + TrackHandlers track_handlers_; +}; + +class LocalMediaStreamHandler : public MediaStreamHandler { + public: + LocalMediaStreamHandler(MediaStreamInterface* stream, + AudioProviderInterface* audio_provider, + VideoProviderInterface* video_provider); + ~LocalMediaStreamHandler(); + + virtual void AddAudioTrack(AudioTrackInterface* audio_track, + uint32 ssrc) OVERRIDE; + virtual void AddVideoTrack(VideoTrackInterface* video_track, + uint32 ssrc) OVERRIDE; +}; + +class RemoteMediaStreamHandler : public MediaStreamHandler { + public: + RemoteMediaStreamHandler(MediaStreamInterface* stream, + AudioProviderInterface* audio_provider, + VideoProviderInterface* video_provider); + ~RemoteMediaStreamHandler(); + virtual void AddAudioTrack(AudioTrackInterface* audio_track, + uint32 ssrc) OVERRIDE; + virtual void AddVideoTrack(VideoTrackInterface* video_track, + uint32 ssrc) OVERRIDE; +}; + +// Container for MediaStreamHandlers of currently known local and remote +// MediaStreams. +class MediaStreamHandlerContainer { + public: + MediaStreamHandlerContainer(AudioProviderInterface* audio_provider, + VideoProviderInterface* video_provider); + ~MediaStreamHandlerContainer(); + + // Notify all referenced objects that MediaStreamHandlerContainer will be + // destroyed. This method must be called prior to the dtor and prior to the + // |audio_provider| and |video_provider| is destroyed. + void TearDown(); + + // Remove all TrackHandlers for tracks in |stream| and make sure + // the audio_provider and video_provider is notified that the tracks has been + // removed. + void RemoveRemoteStream(MediaStreamInterface* stream); + + // Create a RemoteAudioTrackHandler and associate |audio_track| with |ssrc|. + void AddRemoteAudioTrack(MediaStreamInterface* stream, + AudioTrackInterface* audio_track, + uint32 ssrc); + // Create a RemoteVideoTrackHandler and associate |video_track| with |ssrc|. + void AddRemoteVideoTrack(MediaStreamInterface* stream, + VideoTrackInterface* video_track, + uint32 ssrc); + // Remove the TrackHandler for |track|. + void RemoveRemoteTrack(MediaStreamInterface* stream, + MediaStreamTrackInterface* track); + + // Remove all TrackHandlers for tracks in |stream| and make sure + // the audio_provider and video_provider is notified that the tracks has been + // removed. + void RemoveLocalStream(MediaStreamInterface* stream); + + // Create a LocalAudioTrackHandler and associate |audio_track| with |ssrc|. + void AddLocalAudioTrack(MediaStreamInterface* stream, + AudioTrackInterface* audio_track, + uint32 ssrc); + // Create a LocalVideoTrackHandler and associate |video_track| with |ssrc|. + void AddLocalVideoTrack(MediaStreamInterface* stream, + VideoTrackInterface* video_track, + uint32 ssrc); + // Remove the TrackHandler for |track|. + void RemoveLocalTrack(MediaStreamInterface* stream, + MediaStreamTrackInterface* track); + + private: + typedef std::list StreamHandlerList; + MediaStreamHandler* FindStreamHandler(const StreamHandlerList& handlers, + MediaStreamInterface* stream); + MediaStreamHandler* CreateRemoteStreamHandler(MediaStreamInterface* stream); + MediaStreamHandler* CreateLocalStreamHandler(MediaStreamInterface* stream); + void DeleteStreamHandler(StreamHandlerList* streamhandlers, + MediaStreamInterface* stream); + + StreamHandlerList local_streams_handlers_; + StreamHandlerList remote_streams_handlers_; + AudioProviderInterface* audio_provider_; + VideoProviderInterface* video_provider_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_MEDIASTREAMHANDLER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreaminterface.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreaminterface.h new file mode 100644 index 0000000..86e97f3 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreaminterface.h @@ -0,0 +1,264 @@ +/* + * 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. + */ + +// This file contains interfaces for MediaStream, MediaTrack and MediaSource. +// These interfaces are used for implementing MediaStream and MediaTrack as +// defined in http://dev.w3.org/2011/webrtc/editor/webrtc.html#stream-api. These +// interfaces must be used only with PeerConnection. PeerConnectionManager +// interface provides the factory methods to create MediaStream and MediaTracks. + +#ifndef TALK_APP_WEBRTC_MEDIASTREAMINTERFACE_H_ +#define TALK_APP_WEBRTC_MEDIASTREAMINTERFACE_H_ + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/refcount.h" +#include "talk/base/scoped_ref_ptr.h" + +namespace cricket { + +class AudioRenderer; +class VideoCapturer; +class VideoRenderer; +class VideoFrame; + +} // namespace cricket + +namespace webrtc { + +// Generic observer interface. +class ObserverInterface { + public: + virtual void OnChanged() = 0; + + protected: + virtual ~ObserverInterface() {} +}; + +class NotifierInterface { + public: + virtual void RegisterObserver(ObserverInterface* observer) = 0; + virtual void UnregisterObserver(ObserverInterface* observer) = 0; + + virtual ~NotifierInterface() {} +}; + +// Base class for sources. A MediaStreamTrack have an underlying source that +// provide media. A source can be shared with multiple tracks. +// TODO(perkj): Implement sources for local and remote audio tracks and +// remote video tracks. +class MediaSourceInterface : public talk_base::RefCountInterface, + public NotifierInterface { + public: + enum SourceState { + kInitializing, + kLive, + kEnded, + kMuted + }; + + virtual SourceState state() const = 0; + + protected: + virtual ~MediaSourceInterface() {} +}; + +// Information about a track. +class MediaStreamTrackInterface : public talk_base::RefCountInterface, + public NotifierInterface { + public: + enum TrackState { + kInitializing, // Track is beeing negotiated. + kLive = 1, // Track alive + kEnded = 2, // Track have ended + kFailed = 3, // Track negotiation failed. + }; + + virtual std::string kind() const = 0; + virtual std::string id() const = 0; + virtual bool enabled() const = 0; + virtual TrackState state() const = 0; + virtual bool set_enabled(bool enable) = 0; + // These methods should be called by implementation only. + virtual bool set_state(TrackState new_state) = 0; + + protected: + virtual ~MediaStreamTrackInterface() {} +}; + +// Interface for rendering VideoFrames from a VideoTrack +class VideoRendererInterface { + public: + virtual void SetSize(int width, int height) = 0; + virtual void RenderFrame(const cricket::VideoFrame* frame) = 0; + + protected: + // The destructor is protected to prevent deletion via the interface. + // This is so that we allow reference counted classes, where the destructor + // should never be public, to implement the interface. + virtual ~VideoRendererInterface() {} +}; + +class VideoSourceInterface; + +class VideoTrackInterface : public MediaStreamTrackInterface { + public: + // Register a renderer that will render all frames received on this track. + virtual void AddRenderer(VideoRendererInterface* renderer) = 0; + // Deregister a renderer. + virtual void RemoveRenderer(VideoRendererInterface* renderer) = 0; + + virtual VideoSourceInterface* GetSource() const = 0; + + protected: + virtual ~VideoTrackInterface() {} +}; + +// AudioSourceInterface is a reference counted source used for AudioTracks. +// The same source can be used in multiple AudioTracks. +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 { + public: + // TODO(xians): Figure out if the following interface should be const or not. + virtual AudioSourceInterface* GetSource() const = 0; + + // 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 + 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): Remove the following interface after Chrome switches to + // AddSink() and RemoveSink() interfaces. + virtual cricket::AudioRenderer* GetRenderer() { return NULL; } + + protected: + virtual ~AudioTrackInterface() {} +}; + +typedef std::vector > + AudioTrackVector; +typedef std::vector > + VideoTrackVector; + +class MediaStreamInterface : public talk_base::RefCountInterface, + public NotifierInterface { + public: + virtual std::string label() const = 0; + + virtual AudioTrackVector GetAudioTracks() = 0; + virtual VideoTrackVector GetVideoTracks() = 0; + virtual talk_base::scoped_refptr + FindAudioTrack(const std::string& track_id) = 0; + virtual talk_base::scoped_refptr + FindVideoTrack(const std::string& track_id) = 0; + + virtual bool AddTrack(AudioTrackInterface* track) = 0; + virtual bool AddTrack(VideoTrackInterface* track) = 0; + virtual bool RemoveTrack(AudioTrackInterface* track) = 0; + virtual bool RemoveTrack(VideoTrackInterface* track) = 0; + + protected: + virtual ~MediaStreamInterface() {} +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_MEDIASTREAMINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamprovider.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamprovider.h new file mode 100644 index 0000000..53de16e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamprovider.h @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_MEDIASTREAMPROVIDER_H_ +#define TALK_APP_WEBRTC_MEDIASTREAMPROVIDER_H_ + +namespace cricket { + +class AudioRenderer; +class VideoCapturer; +class VideoRenderer; +struct AudioOptions; +struct VideoOptions; + +} // namespace cricket + +namespace webrtc { + +// This interface is called by AudioTrackHandler classes in mediastreamhandler.h +// to change the settings of an audio track connected to certain PeerConnection. +class AudioProviderInterface { + public: + // Enable/disable the audio playout of a remote audio track with |ssrc|. + virtual void SetAudioPlayout(uint32 ssrc, bool enable, + cricket::AudioRenderer* renderer) = 0; + // Enable/disable sending audio on the local audio track with |ssrc|. + // When |enable| is true |options| should be applied to the audio track. + virtual void SetAudioSend(uint32 ssrc, bool enable, + 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() {} +}; + +// This interface is called by VideoTrackHandler classes in mediastreamhandler.h +// to change the settings of a video track connected to a certain +// PeerConnection. +class VideoProviderInterface { + public: + virtual bool SetCaptureDevice(uint32 ssrc, + cricket::VideoCapturer* camera) = 0; + // Enable/disable the video playout of a remote video track with |ssrc|. + virtual void SetVideoPlayout(uint32 ssrc, bool enable, + cricket::VideoRenderer* renderer) = 0; + // Enable sending video on the local video track with |ssrc|. + virtual void SetVideoSend(uint32 ssrc, bool enable, + const cricket::VideoOptions* options) = 0; + + protected: + virtual ~VideoProviderInterface() {} +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_MEDIASTREAMPROVIDER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamproxy.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamproxy.h new file mode 100644 index 0000000..c1e3728 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamproxy.h @@ -0,0 +1,54 @@ +/* + * 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_APP_WEBRTC_MEDIASTREAMPROXY_H_ +#define TALK_APP_WEBRTC_MEDIASTREAMPROXY_H_ + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/proxy.h" + +namespace webrtc { + +BEGIN_PROXY_MAP(MediaStream) + PROXY_CONSTMETHOD0(std::string, label) + PROXY_METHOD0(AudioTrackVector, GetAudioTracks) + PROXY_METHOD0(VideoTrackVector, GetVideoTracks) + PROXY_METHOD1(talk_base::scoped_refptr, + FindAudioTrack, const std::string&) + PROXY_METHOD1(talk_base::scoped_refptr, + FindVideoTrack, const std::string&) + PROXY_METHOD1(bool, AddTrack, AudioTrackInterface*) + PROXY_METHOD1(bool, AddTrack, VideoTrackInterface*) + PROXY_METHOD1(bool, RemoveTrack, AudioTrackInterface*) + PROXY_METHOD1(bool, RemoveTrack, VideoTrackInterface*) + PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) + PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) +END_PROXY() + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_MEDIASTREAMPROXY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamsignaling.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamsignaling.h new file mode 100644 index 0000000..9c3b25d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamsignaling.h @@ -0,0 +1,397 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_MEDIASTREAMSIGNALING_H_ +#define TALK_APP_WEBRTC_MEDIASTREAMSIGNALING_H_ + +#include +#include +#include + +#include "talk/app/webrtc/datachannel.h" +#include "talk/app/webrtc/mediastream.h" +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/app/webrtc/streamcollection.h" +#include "talk/base/scoped_ref_ptr.h" +#include "talk/session/media/mediasession.h" + +namespace talk_base { +class Thread; +} // namespace talk_base + +namespace webrtc { + +class RemoteMediaStreamFactory; + +// A MediaStreamSignalingObserver is notified when events happen to +// MediaStreams, MediaStreamTracks or DataChannels associated with the observed +// MediaStreamSignaling object. The notifications identify the stream, track or +// channel. +class MediaStreamSignalingObserver { + public: + // Triggered when the remote SessionDescription has a new stream. + virtual void OnAddRemoteStream(MediaStreamInterface* stream) = 0; + + // Triggered when the remote SessionDescription removes a stream. + virtual void OnRemoveRemoteStream(MediaStreamInterface* stream) = 0; + + // Triggered when the remote SessionDescription has a new data channel. + virtual void OnAddDataChannel(DataChannelInterface* data_channel) = 0; + + // Triggered when the remote SessionDescription has a new audio track. + virtual void OnAddRemoteAudioTrack(MediaStreamInterface* stream, + AudioTrackInterface* audio_track, + uint32 ssrc) = 0; + + // Triggered when the remote SessionDescription has a new video track. + virtual void OnAddRemoteVideoTrack(MediaStreamInterface* stream, + VideoTrackInterface* video_track, + uint32 ssrc) = 0; + + // Triggered when the remote SessionDescription has removed an audio track. + virtual void OnRemoveRemoteAudioTrack(MediaStreamInterface* stream, + AudioTrackInterface* audio_track) = 0; + + // Triggered when the remote SessionDescription has removed a video track. + virtual void OnRemoveRemoteVideoTrack(MediaStreamInterface* stream, + VideoTrackInterface* video_track) = 0; + + // Triggered when the local SessionDescription has a new audio track. + virtual void OnAddLocalAudioTrack(MediaStreamInterface* stream, + AudioTrackInterface* audio_track, + uint32 ssrc) = 0; + + // Triggered when the local SessionDescription has a new video track. + virtual void OnAddLocalVideoTrack(MediaStreamInterface* stream, + VideoTrackInterface* video_track, + uint32 ssrc) = 0; + + // Triggered when the local SessionDescription has removed an audio track. + virtual void OnRemoveLocalAudioTrack(MediaStreamInterface* stream, + AudioTrackInterface* audio_track, + uint32 ssrc) = 0; + + // Triggered when the local SessionDescription has removed a video track. + virtual void OnRemoveLocalVideoTrack(MediaStreamInterface* stream, + VideoTrackInterface* video_track) = 0; + + // Triggered when RemoveLocalStream is called. |stream| is no longer used + // when negotiating and all tracks in |stream| should stop providing data to + // this PeerConnection. This doesn't mean that the local session description + // has changed and OnRemoveLocalAudioTrack and OnRemoveLocalVideoTrack is not + // called for each individual track. + virtual void OnRemoveLocalStream(MediaStreamInterface* stream) = 0; + + protected: + ~MediaStreamSignalingObserver() {} +}; + +// MediaStreamSignaling works as a glue between MediaStreams and a cricket +// classes for SessionDescriptions. +// It is used for creating cricket::MediaSessionOptions given the local +// MediaStreams and data channels. +// +// It is responsible for creating remote MediaStreams given a remote +// SessionDescription and creating cricket::MediaSessionOptions given +// local MediaStreams. +// +// To signal that a DataChannel should be established: +// 1. Call AddDataChannel with the new DataChannel. Next time +// GetMediaSessionOptions will include the description of the DataChannel. +// 2. When a local session description is set, call UpdateLocalStreams with the +// session description. This will set the SSRC used for sending data on +// this DataChannel. +// 3. When remote session description is set, call UpdateRemoteStream with the +// session description. If the DataChannel label and a SSRC is included in +// the description, the DataChannel is updated with SSRC that will be used +// for receiving data. +// 4. When both the local and remote SSRC of a DataChannel is set the state of +// the DataChannel change to kOpen. +// +// To setup a DataChannel initialized by the remote end. +// 1. When remote session description is set, call UpdateRemoteStream with the +// session description. If a label and a SSRC of a new DataChannel is found +// MediaStreamSignalingObserver::OnAddDataChannel with the label and SSRC is +// triggered. +// 2. Create a DataChannel instance with the label and set the remote SSRC. +// 3. Call AddDataChannel with this new DataChannel. GetMediaSessionOptions +// will include the description of the DataChannel. +// 4. Create a local session description and call UpdateLocalStreams. This will +// set the local SSRC used by the DataChannel. +// 5. When both the local and remote SSRC of a DataChannel is set the state of +// the DataChannel change to kOpen. +// +// To close a DataChannel: +// 1. Call DataChannel::Close. This will change the state of the DataChannel to +// kClosing. GetMediaSessionOptions will not +// include the description of the DataChannel. +// 2. When a local session description is set, call UpdateLocalStreams with the +// session description. The description will no longer contain the +// DataChannel label or SSRC. +// 3. When remote session description is set, call UpdateRemoteStream with the +// session description. The description will no longer contain the +// DataChannel label or SSRC. The DataChannel SSRC is updated with SSRC=0. +// The DataChannel change state to kClosed. + +class MediaStreamSignaling { + public: + MediaStreamSignaling(talk_base::Thread* signaling_thread, + MediaStreamSignalingObserver* stream_observer, + cricket::ChannelManager* channel_manager); + virtual ~MediaStreamSignaling(); + + // Notify all referenced objects that MediaStreamSignaling will be teared + // down. This method must be called prior to the dtor. + void TearDown(); + + // Set a factory for creating data channels that are initiated by the remote + // peer. + void SetDataChannelFactory(DataChannelFactory* data_channel_factory) { + data_channel_factory_ = data_channel_factory; + } + + // Checks if |id| is available to be assigned to a new SCTP data channel. + bool IsSctpSidAvailable(int sid) const; + + // Gets the first available SCTP id that is not assigned to any existing + // data channels. + bool AllocateSctpSid(talk_base::SSLRole role, int* sid); + + // Adds |local_stream| to the collection of known MediaStreams that will be + // offered in a SessionDescription. + bool AddLocalStream(MediaStreamInterface* local_stream); + + // Removes |local_stream| from the collection of known MediaStreams that will + // be offered in a SessionDescription. + void RemoveLocalStream(MediaStreamInterface* local_stream); + + // Checks if any data channel has been added. + bool HasDataChannels() const; + // Adds |data_channel| to the collection of DataChannels that will be + // 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 cricket::ReceiveDataParams& params, + const talk_base::Buffer& payload); + + // Returns a MediaSessionOptions struct with options decided by |constraints|, + // the local MediaStreams and DataChannels. + virtual bool GetOptionsForOffer( + const MediaConstraintsInterface* constraints, + cricket::MediaSessionOptions* options); + + // Returns a MediaSessionOptions struct with options decided by + // |constraints|, the local MediaStreams and DataChannels. + virtual bool GetOptionsForAnswer( + const MediaConstraintsInterface* constraints, + cricket::MediaSessionOptions* options); + + // Called when the remote session description has changed. The purpose is to + // update remote MediaStreams and DataChannels with the current + // session state. + // If the remote SessionDescription contain information about a new remote + // MediaStreams a new remote MediaStream is created and + // MediaStreamSignalingObserver::OnAddStream is called. + // If a remote MediaStream is missing from + // the remote SessionDescription MediaStreamSignalingObserver::OnRemoveStream + // is called. + // If the SessionDescription contains information about a new DataChannel, + // MediaStreamSignalingObserver::OnAddDataChannel is called with the + // DataChannel. + void OnRemoteDescriptionChanged(const SessionDescriptionInterface* desc); + + // Called when the local session description has changed. The purpose is to + // update local and remote MediaStreams and DataChannels with the current + // session state. + // If |desc| indicates that the media type should be rejected, the method + // ends the remote MediaStreamTracks. + // It also updates local DataChannels with information about its local SSRC. + void OnLocalDescriptionChanged(const SessionDescriptionInterface* desc); + + // Called when the audio channel closes. + void OnAudioChannelClose(); + // Called when the video channel closes. + void OnVideoChannelClose(); + // Called when the data channel closes. + void OnDataChannelClose(); + + // Returns all current known local MediaStreams. + StreamCollectionInterface* local_streams() const { return local_streams_;} + + // Returns all current remote MediaStreams. + StreamCollectionInterface* remote_streams() const { + return remote_streams_.get(); + } + void OnDataTransportCreatedForSctp(); + void OnDtlsRoleReadyForSctp(talk_base::SSLRole role); + + private: + struct RemotePeerInfo { + RemotePeerInfo() + : msid_supported(false), + default_audio_track_needed(false), + default_video_track_needed(false) { + } + // True if it has been discovered that the remote peer support MSID. + bool msid_supported; + // The remote peer indicates in the session description that audio will be + // sent but no MSID is given. + bool default_audio_track_needed; + // The remote peer indicates in the session description that video will be + // sent but no MSID is given. + bool default_video_track_needed; + + bool IsDefaultMediaStreamNeeded() { + return !msid_supported && (default_audio_track_needed || + default_video_track_needed); + } + }; + + struct TrackInfo { + TrackInfo() : ssrc(0) {} + TrackInfo(const std::string& stream_label, + const std::string track_id, + uint32 ssrc) + : stream_label(stream_label), + track_id(track_id), + ssrc(ssrc) { + } + std::string stream_label; + std::string track_id; + uint32 ssrc; + }; + typedef std::vector TrackInfos; + + void UpdateSessionOptions(); + + // Makes sure a MediaStream Track is created for each StreamParam in + // |streams|. |media_type| is the type of the |streams| and can be either + // audio or video. + // If a new MediaStream is created it is added to |new_streams|. + void UpdateRemoteStreamsList( + const std::vector& streams, + cricket::MediaType media_type, + StreamCollection* new_streams); + + // Triggered when a remote track has been seen for the first time in a remote + // session description. It creates a remote MediaStreamTrackInterface + // implementation and triggers MediaStreamSignaling::OnAddRemoteAudioTrack or + // MediaStreamSignaling::OnAddRemoteVideoTrack. + void OnRemoteTrackSeen(const std::string& stream_label, + const std::string& track_id, + uint32 ssrc, + cricket::MediaType media_type); + + // Triggered when a remote track has been removed from a remote session + // description. It removes the remote track with id |track_id| from a remote + // MediaStream and triggers MediaStreamSignaling::OnRemoveRemoteAudioTrack or + // MediaStreamSignaling::OnRemoveRemoteVideoTrack. + void OnRemoteTrackRemoved(const std::string& stream_label, + const std::string& track_id, + cricket::MediaType media_type); + + // Set the MediaStreamTrackInterface::TrackState to |kEnded| on all remote + // tracks of type |media_type|. + void RejectRemoteTracks(cricket::MediaType media_type); + + // Finds remote MediaStreams without any tracks and removes them from + // |remote_streams_| and notifies the observer that the MediaStream no longer + // exist. + void UpdateEndedRemoteMediaStreams(); + void MaybeCreateDefaultStream(); + TrackInfos* GetRemoteTracks(cricket::MediaType type); + + // Returns a map of currently negotiated LocalTrackInfo of type |type|. + TrackInfos* GetLocalTracks(cricket::MediaType type); + bool FindLocalTrack(const std::string& track_id, cricket::MediaType type); + + // Loops through the vector of |streams| and finds added and removed + // StreamParams since last time this method was called. + // For each new or removed StreamParam NotifyLocalTrackAdded or + // NotifyLocalTrackRemoved in invoked. + void UpdateLocalTracks(const std::vector& streams, + cricket::MediaType media_type); + + // Triggered when a local track has been seen for the first time in a local + // session description. + // This method triggers MediaStreamSignaling::OnAddLocalAudioTrack or + // MediaStreamSignaling::OnAddLocalVideoTrack if the rtp streams in the local + // SessionDescription can be mapped to a MediaStreamTrack in a MediaStream in + // |local_streams_| + void OnLocalTrackSeen(const std::string& stream_label, + const std::string& track_id, + uint32 ssrc, + cricket::MediaType media_type); + + // Triggered when a local track has been removed from a local session + // description. + // This method triggers MediaStreamSignaling::OnRemoveLocalAudioTrack or + // MediaStreamSignaling::OnRemoveLocalVideoTrack if a stream has been removed + // from the local SessionDescription and the stream can be mapped to a + // 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); + void UpdateRemoteRtpDataChannels(const cricket::StreamParamsVec& streams); + void UpdateClosingDataChannels( + const std::vector& 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; + + RemotePeerInfo remote_info_; + talk_base::Thread* signaling_thread_; + DataChannelFactory* data_channel_factory_; + cricket::MediaSessionOptions options_; + MediaStreamSignalingObserver* stream_observer_; + talk_base::scoped_refptr local_streams_; + talk_base::scoped_refptr remote_streams_; + talk_base::scoped_ptr remote_stream_factory_; + + TrackInfos remote_audio_tracks_; + TrackInfos remote_video_tracks_; + TrackInfos local_audio_tracks_; + TrackInfos local_video_tracks_; + + int last_allocated_sctp_even_sid_; + int last_allocated_sctp_odd_sid_; + + typedef std::map > + RtpDataChannels; + typedef std::vector > SctpDataChannels; + RtpDataChannels rtp_data_channels_; + SctpDataChannels sctp_data_channels_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_MEDIASTREAMSIGNALING_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamtrack.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamtrack.h new file mode 100644 index 0000000..183b575 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamtrack.h @@ -0,0 +1,81 @@ +/* + * 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_APP_WEBRTC_MEDIASTREAMTRACK_H_ +#define TALK_APP_WEBRTC_MEDIASTREAMTRACK_H_ + +#include + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/notifier.h" + +namespace webrtc { + +// MediaTrack implements the interface common to AudioTrackInterface and +// VideoTrackInterface. +template +class MediaStreamTrack : public Notifier { + public: + typedef typename T::TrackState TypedTrackState; + + virtual std::string id() const { return id_; } + virtual MediaStreamTrackInterface::TrackState state() const { + return state_; + } + virtual bool enabled() const { return enabled_; } + virtual bool set_enabled(bool enable) { + bool fire_on_change = (enable != enabled_); + enabled_ = enable; + if (fire_on_change) { + Notifier::FireOnChanged(); + } + return fire_on_change; + } + virtual bool set_state(MediaStreamTrackInterface::TrackState new_state) { + bool fire_on_change = (state_ != new_state); + state_ = new_state; + if (fire_on_change) + Notifier::FireOnChanged(); + return true; + } + + protected: + explicit MediaStreamTrack(const std::string& id) + : enabled_(true), + id_(id), + state_(MediaStreamTrackInterface::kInitializing) { + } + + private: + bool enabled_; + std::string id_; + MediaStreamTrackInterface::TrackState state_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_MEDIASTREAMTRACK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamtrackproxy.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamtrackproxy.h new file mode 100644 index 0000000..cd3d8fa --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/mediastreamtrackproxy.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + +// This file includes proxy classes for tracks. The purpose is +// to make sure tracks are only accessed from the signaling thread. + +#ifndef TALK_APP_WEBRTC_MEDIASTREAMTRACKPROXY_H_ +#define TALK_APP_WEBRTC_MEDIASTREAMTRACKPROXY_H_ + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/proxy.h" + +namespace webrtc { + +BEGIN_PROXY_MAP(AudioTrack) + PROXY_CONSTMETHOD0(std::string, kind) + PROXY_CONSTMETHOD0(std::string, id) + 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, + GetAudioProcessor) + PROXY_METHOD0(cricket::AudioRenderer*, GetRenderer) + + PROXY_METHOD1(bool, set_enabled, bool) + PROXY_METHOD1(bool, set_state, TrackState) + + PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) + PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) +END_PROXY() + +BEGIN_PROXY_MAP(VideoTrack) + PROXY_CONSTMETHOD0(std::string, kind) + PROXY_CONSTMETHOD0(std::string, id) + PROXY_CONSTMETHOD0(TrackState, state) + PROXY_CONSTMETHOD0(bool, enabled) + PROXY_METHOD1(bool, set_enabled, bool) + PROXY_METHOD1(bool, set_state, TrackState) + + PROXY_METHOD1(void, AddRenderer, VideoRendererInterface*) + PROXY_METHOD1(void, RemoveRenderer, VideoRendererInterface*) + PROXY_CONSTMETHOD0(VideoSourceInterface*, GetSource) + + PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) + PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) +END_PROXY() + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_MEDIASTREAMTRACKPROXY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/notifier.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/notifier.h new file mode 100644 index 0000000..fa19a01 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/notifier.h @@ -0,0 +1,77 @@ +/* + * 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_APP_WEBRTC_NOTIFIER_H_ +#define TALK_APP_WEBRTC_NOTIFIER_H_ + +#include + +#include "talk/base/common.h" +#include "talk/app/webrtc/mediastreaminterface.h" + +namespace webrtc { + +// Implement a template version of a notifier. +template +class Notifier : public T { + public: + Notifier() { + } + + virtual void RegisterObserver(ObserverInterface* observer) { + ASSERT(observer != NULL); + observers_.push_back(observer); + } + + virtual void UnregisterObserver(ObserverInterface* observer) { + for (std::list::iterator it = observers_.begin(); + it != observers_.end(); it++) { + if (*it == observer) { + observers_.erase(it); + break; + } + } + } + + void FireOnChanged() { + // Copy the list of observers to avoid a crash if the observer object + // unregisters as a result of the OnChanged() call. If the same list is used + // UnregisterObserver will affect the list make the iterator invalid. + std::list observers = observers_; + for (std::list::iterator it = observers.begin(); + it != observers.end(); ++it) { + (*it)->OnChanged(); + } + } + + protected: + std::list observers_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_NOTIFIER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnection.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnection.h new file mode 100644 index 0000000..182e3ec --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnection.h @@ -0,0 +1,204 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_PEERCONNECTION_H_ +#define TALK_APP_WEBRTC_PEERCONNECTION_H_ + +#include + +#include "talk/app/webrtc/mediastreamsignaling.h" +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/app/webrtc/peerconnectionfactory.h" +#include "talk/app/webrtc/statscollector.h" +#include "talk/app/webrtc/streamcollection.h" +#include "talk/app/webrtc/webrtcsession.h" +#include "talk/base/scoped_ptr.h" + +namespace webrtc { +class MediaStreamHandlerContainer; + +typedef std::vector + StunConfigurations; +typedef std::vector + TurnConfigurations; + +// PeerConnectionImpl implements the PeerConnection interface. +// It uses MediaStreamSignaling and WebRtcSession to implement +// the PeerConnection functionality. +class PeerConnection : public PeerConnectionInterface, + public MediaStreamSignalingObserver, + public IceObserver, + public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + explicit PeerConnection(PeerConnectionFactory* factory); + + bool Initialize( + const PeerConnectionInterface::RTCConfiguration& configuration, + const MediaConstraintsInterface* constraints, + PortAllocatorFactoryInterface* allocator_factory, + DTLSIdentityServiceInterface* dtls_identity_service, + PeerConnectionObserver* observer); + virtual talk_base::scoped_refptr local_streams(); + virtual talk_base::scoped_refptr remote_streams(); + virtual bool AddStream(MediaStreamInterface* local_stream, + const MediaConstraintsInterface* constraints); + virtual void RemoveStream(MediaStreamInterface* local_stream); + + virtual talk_base::scoped_refptr CreateDtmfSender( + AudioTrackInterface* track); + + virtual talk_base::scoped_refptr CreateDataChannel( + const std::string& label, + const DataChannelInit* config); + virtual bool GetStats(StatsObserver* observer, + webrtc::MediaStreamTrackInterface* track, + StatsOutputLevel level); + + virtual SignalingState signaling_state(); + + // TODO(bemasc): Remove ice_state() when callers are removed. + virtual IceState ice_state(); + virtual IceConnectionState ice_connection_state(); + virtual IceGatheringState ice_gathering_state(); + + virtual const SessionDescriptionInterface* local_description() const; + virtual const SessionDescriptionInterface* remote_description() const; + + // JSEP01 + virtual void CreateOffer(CreateSessionDescriptionObserver* observer, + const MediaConstraintsInterface* constraints); + virtual void CreateAnswer(CreateSessionDescriptionObserver* observer, + const MediaConstraintsInterface* constraints); + virtual void SetLocalDescription(SetSessionDescriptionObserver* observer, + 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: + virtual ~PeerConnection(); + + private: + // Implements MessageHandler. + virtual void OnMessage(talk_base::Message* msg); + + // Implements MediaStreamSignalingObserver. + virtual void OnAddRemoteStream(MediaStreamInterface* stream) OVERRIDE; + virtual void OnRemoveRemoteStream(MediaStreamInterface* stream) OVERRIDE; + virtual void OnAddDataChannel(DataChannelInterface* data_channel) OVERRIDE; + virtual void OnAddRemoteAudioTrack(MediaStreamInterface* stream, + AudioTrackInterface* audio_track, + uint32 ssrc) OVERRIDE; + virtual void OnAddRemoteVideoTrack(MediaStreamInterface* stream, + VideoTrackInterface* video_track, + uint32 ssrc) OVERRIDE; + virtual void OnRemoveRemoteAudioTrack( + MediaStreamInterface* stream, + AudioTrackInterface* audio_track) OVERRIDE; + virtual void OnRemoveRemoteVideoTrack( + MediaStreamInterface* stream, + VideoTrackInterface* video_track) OVERRIDE; + virtual void OnAddLocalAudioTrack(MediaStreamInterface* stream, + AudioTrackInterface* audio_track, + uint32 ssrc) OVERRIDE; + virtual void OnAddLocalVideoTrack(MediaStreamInterface* stream, + VideoTrackInterface* video_track, + uint32 ssrc) OVERRIDE; + virtual void OnRemoveLocalAudioTrack( + MediaStreamInterface* stream, + AudioTrackInterface* audio_track, + uint32 ssrc) OVERRIDE; + virtual void OnRemoveLocalVideoTrack( + MediaStreamInterface* stream, + VideoTrackInterface* video_track) OVERRIDE; + virtual void OnRemoveLocalStream(MediaStreamInterface* stream); + + // Implements IceObserver + virtual void OnIceConnectionChange(IceConnectionState new_state); + virtual void OnIceGatheringChange(IceGatheringState new_state); + virtual void OnIceCandidate(const IceCandidateInterface* candidate); + virtual void OnIceComplete(); + + // Signals from WebRtcSession. + void OnSessionStateChange(cricket::BaseSession* session, + cricket::BaseSession::State state); + void ChangeSignalingState(SignalingState signaling_state); + + bool DoInitialize(IceTransportsType type, + const StunConfigurations& stun_config, + const TurnConfigurations& turn_config, + const MediaConstraintsInterface* constraints, + PortAllocatorFactoryInterface* allocator_factory, + DTLSIdentityServiceInterface* dtls_identity_service, + PeerConnectionObserver* observer); + + talk_base::Thread* signaling_thread() const { + return factory_->signaling_thread(); + } + + void PostSetSessionDescriptionFailure(SetSessionDescriptionObserver* observer, + const std::string& error); + + bool IsClosed() const { + return signaling_state_ == PeerConnectionInterface::kClosed; + } + + // Storing the factory as a scoped reference pointer ensures that the memory + // in the PeerConnectionFactoryImpl remains available as long as the + // PeerConnection is running. It is passed to PeerConnection as a raw pointer. + // However, since the reference counting is done in the + // PeerConnectionFactoryInteface all instances created using the raw pointer + // will refer to the same reference count. + talk_base::scoped_refptr factory_; + PeerConnectionObserver* observer_; + UMAObserver* uma_observer_; + SignalingState signaling_state_; + // TODO(bemasc): Remove ice_state_. + IceState ice_state_; + IceConnectionState ice_connection_state_; + IceGatheringState ice_gathering_state_; + + talk_base::scoped_ptr port_allocator_; + talk_base::scoped_ptr session_; + talk_base::scoped_ptr mediastream_signaling_; + talk_base::scoped_ptr stream_handler_container_; + StatsCollector stats_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_PEERCONNECTION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectionfactory.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectionfactory.h new file mode 100644 index 0000000..1e6889a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectionfactory.h @@ -0,0 +1,133 @@ +/* + * 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_APP_WEBRTC_PEERCONNECTIONFACTORY_H_ +#define TALK_APP_WEBRTC_PEERCONNECTIONFACTORY_H_ + +#include + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/thread.h" +#include "talk/session/media/channelmanager.h" + +namespace webrtc { + +class PeerConnectionFactory : public PeerConnectionFactoryInterface, + public talk_base::MessageHandler { + public: + virtual void SetOptions(const Options& options) { + options_ = options; + } + + virtual talk_base::scoped_refptr + CreatePeerConnection( + const PeerConnectionInterface::RTCConfiguration& configuration, + const MediaConstraintsInterface* constraints, + PortAllocatorFactoryInterface* allocator_factory, + DTLSIdentityServiceInterface* dtls_identity_service, + PeerConnectionObserver* observer); + + bool Initialize(); + + virtual talk_base::scoped_refptr + CreateLocalMediaStream(const std::string& label); + + virtual talk_base::scoped_refptr CreateAudioSource( + const MediaConstraintsInterface* constraints); + + virtual talk_base::scoped_refptr CreateVideoSource( + cricket::VideoCapturer* capturer, + const MediaConstraintsInterface* constraints); + + virtual talk_base::scoped_refptr + CreateVideoTrack(const std::string& id, + VideoSourceInterface* video_source); + + virtual talk_base::scoped_refptr + 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(); + const Options& options() const { return options_; } + + protected: + PeerConnectionFactory(); + PeerConnectionFactory( + talk_base::Thread* worker_thread, + talk_base::Thread* signaling_thread, + AudioDeviceModule* default_adm, + cricket::WebRtcVideoEncoderFactory* video_encoder_factory, + cricket::WebRtcVideoDecoderFactory* video_decoder_factory); + virtual ~PeerConnectionFactory(); + + private: + bool Initialize_s(); + void Terminate_s(); + talk_base::scoped_refptr CreateAudioSource_s( + const MediaConstraintsInterface* constraints); + talk_base::scoped_refptr CreateVideoSource_s( + cricket::VideoCapturer* capturer, + const MediaConstraintsInterface* constraints); + + talk_base::scoped_refptr CreatePeerConnection_s( + 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); + + bool owns_ptrs_; + talk_base::Thread* signaling_thread_; + talk_base::Thread* worker_thread_; + Options options_; + talk_base::scoped_refptr allocator_factory_; + // External Audio device used for audio playback. + talk_base::scoped_refptr default_adm_; + talk_base::scoped_ptr channel_manager_; + // External Video encoder factory. This can be NULL if the client has not + // injected any. In that case, video engine will use the internal SW encoder. + talk_base::scoped_ptr + video_encoder_factory_; + // External Video decoder factory. This can be NULL if the client has not + // injected any. In that case, video engine will use the internal SW decoder. + talk_base::scoped_ptr + video_decoder_factory_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_PEERCONNECTIONFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectioninterface.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectioninterface.h new file mode 100644 index 0000000..9093b9c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectioninterface.h @@ -0,0 +1,528 @@ +/* + * 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. + */ + +// This file contains the PeerConnection interface as defined in +// http://dev.w3.org/2011/webrtc/editor/webrtc.html#peer-to-peer-connections. +// Applications must use this interface to implement peerconnection. +// PeerConnectionFactory class provides factory methods to create +// peerconnection, mediastream and media tracks objects. +// +// The Following steps are needed to setup a typical call using Jsep. +// 1. Create a PeerConnectionFactoryInterface. Check constructors for more +// information about input parameters. +// 2. Create a PeerConnection object. Provide a configuration string which +// points either to stun or turn server to generate ICE candidates and provide +// an object that implements the PeerConnectionObserver interface. +// 3. Create local MediaStream and MediaTracks using the PeerConnectionFactory +// and add it to PeerConnection by calling AddStream. +// 4. Create an offer and serialize it and send it to the remote peer. +// 5. Once an ice candidate have been found PeerConnection will call the +// observer function OnIceCandidate. The candidates must also be serialized and +// sent to the remote peer. +// 6. Once an answer is received from the remote peer, call +// SetLocalSessionDescription with the offer and SetRemoteSessionDescription +// with the remote answer. +// 7. Once a remote candidate is received from the remote peer, provide it to +// the peerconnection by calling AddIceCandidate. + + +// The Receiver of a call can decide to accept or reject the call. +// This decision will be taken by the application not peerconnection. +// If application decides to accept the call +// 1. Create PeerConnectionFactoryInterface if it doesn't exist. +// 2. Create a new PeerConnection. +// 3. Provide the remote offer to the new PeerConnection object by calling +// SetRemoteSessionDescription. +// 4. Generate an answer to the remote offer by calling CreateAnswer and send it +// back to the remote peer. +// 5. Provide the local answer to the new PeerConnection by calling +// SetLocalSessionDescription with the answer. +// 6. Provide the remote ice candidates by calling AddIceCandidate. +// 7. Once a candidate have been found PeerConnection will call the observer +// function OnIceCandidate. Send these candidates to the remote peer. + +#ifndef TALK_APP_WEBRTC_PEERCONNECTIONINTERFACE_H_ +#define TALK_APP_WEBRTC_PEERCONNECTIONINTERFACE_H_ + +#include +#include + +#include "talk/app/webrtc/datachannelinterface.h" +#include "talk/app/webrtc/dtmfsenderinterface.h" +#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 { +class Thread; +} + +namespace cricket { +class PortAllocator; +class WebRtcVideoDecoderFactory; +class WebRtcVideoEncoderFactory; +} + +namespace webrtc { +class AudioDeviceModule; +class MediaConstraintsInterface; + +// MediaStream container interface. +class StreamCollectionInterface : public talk_base::RefCountInterface { + public: + // TODO(ronghuawu): Update the function names to c++ style, e.g. find -> Find. + virtual size_t count() = 0; + virtual MediaStreamInterface* at(size_t index) = 0; + virtual MediaStreamInterface* find(const std::string& label) = 0; + virtual MediaStreamTrackInterface* FindAudioTrack( + const std::string& id) = 0; + virtual MediaStreamTrackInterface* FindVideoTrack( + const std::string& id) = 0; + + protected: + // Dtor protected as objects shouldn't be deleted via this interface. + ~StreamCollectionInterface() {} +}; + +class StatsObserver : public talk_base::RefCountInterface { + public: + virtual void OnComplete(const std::vector& reports) = 0; + + protected: + 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 . + enum SignalingState { + kStable, + kHaveLocalOffer, + kHaveLocalPrAnswer, + kHaveRemoteOffer, + kHaveRemotePrAnswer, + kClosed, + }; + + // TODO(bemasc): Remove IceState when callers are changed to + // IceConnection/GatheringState. + enum IceState { + kIceNew, + kIceGathering, + kIceWaiting, + kIceChecking, + kIceConnected, + kIceCompleted, + kIceFailed, + kIceClosed, + }; + + enum IceGatheringState { + kIceGatheringNew, + kIceGatheringGathering, + kIceGatheringComplete + }; + + enum IceConnectionState { + kIceConnectionNew, + kIceConnectionChecking, + kIceConnectionConnected, + kIceConnectionCompleted, + kIceConnectionFailed, + kIceConnectionDisconnected, + kIceConnectionClosed, + }; + + struct IceServer { + std::string uri; + std::string username; + std::string password; + }; + typedef std::vector 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 + local_streams() = 0; + + // Accessor methods to remote streams. + virtual talk_base::scoped_refptr + remote_streams() = 0; + + // Add a new MediaStream to be sent on this PeerConnection. + // Note that a SessionDescription negotiation is needed before the + // remote peer can receive the stream. + virtual bool AddStream(MediaStreamInterface* stream, + const MediaConstraintsInterface* constraints) = 0; + + // Remove a MediaStream from this PeerConnection. + // Note that a SessionDescription negotiation is need before the + // remote peer is notified. + virtual void RemoveStream(MediaStreamInterface* stream) = 0; + + // Returns pointer to the created DtmfSender on success. + // Otherwise returns NULL. + virtual talk_base::scoped_refptr CreateDtmfSender( + AudioTrackInterface* track) = 0; + + virtual bool GetStats(StatsObserver* observer, + MediaStreamTrackInterface* track, + StatsOutputLevel level) = 0; + + virtual talk_base::scoped_refptr CreateDataChannel( + const std::string& label, + const DataChannelInit* config) = 0; + + virtual const SessionDescriptionInterface* local_description() const = 0; + virtual const SessionDescriptionInterface* remote_description() const = 0; + + // Create a new offer. + // The CreateSessionDescriptionObserver callback will be called when done. + virtual void CreateOffer(CreateSessionDescriptionObserver* observer, + const MediaConstraintsInterface* constraints) = 0; + // Create an answer to an offer. + // The CreateSessionDescriptionObserver callback will be called when done. + virtual void CreateAnswer(CreateSessionDescriptionObserver* observer, + const MediaConstraintsInterface* constraints) = 0; + // Sets the local session description. + // JsepInterface takes the ownership of |desc| even if it fails. + // The |observer| callback will be called when done. + virtual void SetLocalDescription(SetSessionDescriptionObserver* observer, + SessionDescriptionInterface* desc) = 0; + // Sets the remote session description. + // JsepInterface takes the ownership of |desc| even if it fails. + // The |observer| callback will be called when done. + virtual void SetRemoteDescription(SetSessionDescriptionObserver* observer, + SessionDescriptionInterface* desc) = 0; + // Restarts or updates the ICE Agent process of gathering local candidates + // and pinging remote candidates. + virtual bool UpdateIce(const IceServers& configuration, + const MediaConstraintsInterface* constraints) = 0; + // Provides a remote candidate to the ICE Agent. + // A copy of the |candidate| will be created and added to the remote + // description. So the caller of this method still has the ownership of the + // |candidate|. + // TODO(ronghuawu): Consider to change this so that the AddIceCandidate will + // 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; + + // TODO(bemasc): Remove ice_state when callers are changed to + // IceConnection/GatheringState. + // Returns the current IceState. + virtual IceState ice_state() = 0; + virtual IceConnectionState ice_connection_state() = 0; + virtual IceGatheringState ice_gathering_state() = 0; + + // Terminates all media and closes the transport. + virtual void Close() = 0; + + protected: + // Dtor protected as objects shouldn't be deleted via this interface. + ~PeerConnectionInterface() {} +}; + +// PeerConnection callback interface. Application should implement these +// methods. +class PeerConnectionObserver { + public: + enum StateType { + kSignalingState, + kIceState, + }; + + virtual void OnError() = 0; + + // Triggered when the SignalingState changed. + virtual void OnSignalingChange( + PeerConnectionInterface::SignalingState new_state) {} + + // Triggered when SignalingState or IceState have changed. + // TODO(bemasc): Remove once callers transition to OnSignalingChange. + virtual void OnStateChange(StateType state_changed) {} + + // Triggered when media is received on a new stream from remote peer. + virtual void OnAddStream(MediaStreamInterface* stream) = 0; + + // Triggered when a remote peer close a stream. + virtual void OnRemoveStream(MediaStreamInterface* stream) = 0; + + // Triggered when a remote peer open a data channel. + // TODO(perkj): Make pure virtual. + virtual void OnDataChannel(DataChannelInterface* data_channel) {} + + // Triggered when renegotiation is needed, for example the ICE has restarted. + virtual void OnRenegotiationNeeded() = 0; + + // Called any time the IceConnectionState changes + virtual void OnIceConnectionChange( + PeerConnectionInterface::IceConnectionState new_state) {} + + // Called any time the IceGatheringState changes + virtual void OnIceGatheringChange( + PeerConnectionInterface::IceGatheringState new_state) {} + + // New Ice candidate have been found. + virtual void OnIceCandidate(const IceCandidateInterface* candidate) = 0; + + // TODO(bemasc): Remove this once callers transition to OnIceGatheringChange. + // All Ice candidates have been found. + virtual void OnIceComplete() {} + + protected: + // Dtor protected as objects shouldn't be deleted via this interface. + ~PeerConnectionObserver() {} +}; + +// Factory class used for creating cricket::PortAllocator that is used +// for ICE negotiation. +class PortAllocatorFactoryInterface : public talk_base::RefCountInterface { + public: + struct StunConfiguration { + StunConfiguration(const std::string& address, int port) + : server(address, port) {} + // STUN server address and port. + talk_base::SocketAddress server; + }; + + struct TurnConfiguration { + TurnConfiguration(const std::string& address, + int port, + const std::string& username, + const std::string& password, + const std::string& transport_type, + bool secure) + : server(address, port), + username(username), + password(password), + transport_type(transport_type), + secure(secure) {} + talk_base::SocketAddress server; + std::string username; + std::string password; + std::string transport_type; + bool secure; + }; + + virtual cricket::PortAllocator* CreatePortAllocator( + const std::vector& stun_servers, + const std::vector& turn_configurations) = 0; + + protected: + PortAllocatorFactoryInterface() {} + ~PortAllocatorFactoryInterface() {} +}; + +// Used to receive callbacks of DTLS identity requests. +class DTLSIdentityRequestObserver : public talk_base::RefCountInterface { + public: + virtual void OnFailure(int error) = 0; + virtual void OnSuccess(const std::string& der_cert, + const std::string& der_private_key) = 0; + protected: + virtual ~DTLSIdentityRequestObserver() {} +}; + +class DTLSIdentityServiceInterface { + public: + // Asynchronously request a DTLS identity, including a self-signed certificate + // and the private key used to sign the certificate, from the identity store + // for the given identity name. + // DTLSIdentityRequestObserver::OnSuccess will be called with the identity if + // the request succeeded; DTLSIdentityRequestObserver::OnFailure will be + // called with an error code if the request failed. + // + // Only one request can be made at a time. If a second request is called + // before the first one completes, RequestIdentity will abort and return + // false. + // + // |identity_name| is an internal name selected by the client to identify an + // identity within an origin. E.g. an web site may cache the certificates used + // to communicate with differnent peers under different identity names. + // + // |common_name| is the common name used to generate the certificate. If the + // certificate already exists in the store, |common_name| is ignored. + // + // |observer| is the object to receive success or failure callbacks. + // + // Returns true if either OnFailure or OnSuccess will be called. + virtual bool RequestIdentity( + const std::string& identity_name, + const std::string& common_name, + DTLSIdentityRequestObserver* observer) = 0; + + virtual ~DTLSIdentityServiceInterface() {} +}; + +// PeerConnectionFactoryInterface is the factory interface use for creating +// PeerConnection, MediaStream and media tracks. +// PeerConnectionFactoryInterface will create required libjingle threads, +// socket and network manager factory classes for networking. +// If an application decides to provide its own threads and network +// implementation of these classes it should use the alternate +// CreatePeerConnectionFactory method which accepts threads as input and use the +// CreatePeerConnection version that takes a PortAllocatorFactoryInterface as +// argument. +class PeerConnectionFactoryInterface : public talk_base::RefCountInterface { + public: + class Options { + public: + Options() : + disable_encryption(false), + disable_sctp_data_channels(false) { + } + bool disable_encryption; + bool disable_sctp_data_channels; + }; + + virtual void SetOptions(const Options& options) = 0; + + virtual talk_base::scoped_refptr + CreatePeerConnection( + 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 + 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 + CreateLocalMediaStream(const std::string& label) = 0; + + // Creates a AudioSourceInterface. + // |constraints| decides audio processing settings but can be NULL. + virtual talk_base::scoped_refptr CreateAudioSource( + const MediaConstraintsInterface* constraints) = 0; + + // Creates a VideoSourceInterface. The new source take ownership of + // |capturer|. |constraints| decides video resolution and frame rate but can + // be NULL. + virtual talk_base::scoped_refptr CreateVideoSource( + cricket::VideoCapturer* capturer, + const MediaConstraintsInterface* constraints) = 0; + + // Creates a new local VideoTrack. The same |source| can be used in several + // tracks. + virtual talk_base::scoped_refptr + CreateVideoTrack(const std::string& label, + VideoSourceInterface* source) = 0; + + // Creates an new AudioTrack. At the moment |source| can be NULL. + virtual talk_base::scoped_refptr + 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. + PeerConnectionFactoryInterface() {} + ~PeerConnectionFactoryInterface() {} // NOLINT +}; + +// Create a new instance of PeerConnectionFactoryInterface. +talk_base::scoped_refptr +CreatePeerConnectionFactory(); + +// Create a new instance of PeerConnectionFactoryInterface. +// Ownership of |factory|, |default_adm|, and optionally |encoder_factory| and +// |decoder_factory| transferred to the returned factory. +talk_base::scoped_refptr +CreatePeerConnectionFactory( + talk_base::Thread* worker_thread, + talk_base::Thread* signaling_thread, + AudioDeviceModule* default_adm, + cricket::WebRtcVideoEncoderFactory* encoder_factory, + cricket::WebRtcVideoDecoderFactory* decoder_factory); + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_PEERCONNECTIONINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectionproxy.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectionproxy.h new file mode 100644 index 0000000..66276bb --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/peerconnectionproxy.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_PEERCONNECTIONPROXY_H_ +#define TALK_APP_WEBRTC_PEERCONNECTIONPROXY_H_ + +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/app/webrtc/proxy.h" + +namespace webrtc { + +// Define proxy for PeerConnectionInterface. +BEGIN_PROXY_MAP(PeerConnection) + PROXY_METHOD0(talk_base::scoped_refptr, + local_streams) + PROXY_METHOD0(talk_base::scoped_refptr, + remote_streams) + PROXY_METHOD2(bool, AddStream, MediaStreamInterface*, + const MediaConstraintsInterface*) + PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*) + PROXY_METHOD1(talk_base::scoped_refptr, + CreateDtmfSender, AudioTrackInterface*) + PROXY_METHOD3(bool, GetStats, StatsObserver*, + MediaStreamTrackInterface*, + StatsOutputLevel) + PROXY_METHOD2(talk_base::scoped_refptr, + CreateDataChannel, const std::string&, const DataChannelInit*) + PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description) + PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, remote_description) + PROXY_METHOD2(void, CreateOffer, CreateSessionDescriptionObserver*, + const MediaConstraintsInterface*) + PROXY_METHOD2(void, CreateAnswer, CreateSessionDescriptionObserver*, + const MediaConstraintsInterface*) + PROXY_METHOD2(void, SetLocalDescription, SetSessionDescriptionObserver*, + SessionDescriptionInterface*) + PROXY_METHOD2(void, SetRemoteDescription, SetSessionDescriptionObserver*, + SessionDescriptionInterface*) + 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) + PROXY_METHOD0(IceGatheringState, ice_gathering_state) + PROXY_METHOD0(void, Close) +END_PROXY() + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_PEERCONNECTIONPROXY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/portallocatorfactory.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/portallocatorfactory.h new file mode 100644 index 0000000..3f3bdb1 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/portallocatorfactory.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +// This file defines the default implementation of +// PortAllocatorFactoryInterface. +// This implementation creates instances of cricket::HTTPPortAllocator and uses +// the BasicNetworkManager and BasicPacketSocketFactory. + +#ifndef TALK_APP_WEBRTC_PORTALLOCATORFACTORY_H_ +#define TALK_APP_WEBRTC_PORTALLOCATORFACTORY_H_ + +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/base/scoped_ptr.h" + +namespace cricket { +class PortAllocator; +} + +namespace talk_base { +class BasicNetworkManager; +class BasicPacketSocketFactory; +} + +namespace webrtc { + +class PortAllocatorFactory : public PortAllocatorFactoryInterface { + public: + static talk_base::scoped_refptr Create( + talk_base::Thread* worker_thread); + + virtual cricket::PortAllocator* CreatePortAllocator( + const std::vector& stun, + const std::vector& turn); + + protected: + explicit PortAllocatorFactory(talk_base::Thread* worker_thread); + ~PortAllocatorFactory(); + + private: + talk_base::scoped_ptr network_manager_; + talk_base::scoped_ptr socket_factory_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_PORTALLOCATORFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/proxy.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/proxy.h new file mode 100644 index 0000000..e3833e6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/proxy.h @@ -0,0 +1,287 @@ +/* + * 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. + */ + +// This file contains Macros for creating proxies for webrtc MediaStream and +// PeerConnection classes. + +// +// Example usage: +// +// class TestInterface : public talk_base::RefCountInterface { +// public: +// std::string FooA() = 0; +// std::string FooB(bool arg1) const = 0; +// std::string FooC(bool arg1)= 0; +// }; +// +// Note that return types can not be a const reference. +// +// class Test : public TestInterface { +// ... implementation of the interface. +// }; +// +// BEGIN_PROXY_MAP(Test) +// PROXY_METHOD0(std::string, FooA) +// PROXY_CONSTMETHOD1(std::string, FooB, arg1) +// PROXY_METHOD1(std::string, FooC, arg1) +// END_PROXY() +// +// The proxy can be created using TestProxy::Create(Thread*, TestInterface*). + +#ifndef TALK_APP_WEBRTC_PROXY_H_ +#define TALK_APP_WEBRTC_PROXY_H_ + +#include "talk/base/thread.h" + +namespace webrtc { + +template +class ReturnType { + public: + template + void Invoke(C* c, M m) { r_ = (c->*m)(); } + template + void Invoke(C* c, M m, T1 a1) { r_ = (c->*m)(a1); } + template + void Invoke(C* c, M m, T1 a1, T2 a2) { r_ = (c->*m)(a1, a2); } + template + void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3) { r_ = (c->*m)(a1, a2, a3); } + + R value() { return r_; } + + private: + R r_; +}; + +template <> +class ReturnType { + public: + template + void Invoke(C* c, M m) { (c->*m)(); } + template + void Invoke(C* c, M m, T1 a1) { (c->*m)(a1); } + template + void Invoke(C* c, M m, T1 a1, T2 a2) { (c->*m)(a1, a2); } + template + void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3) { (c->*m)(a1, a2, a3); } + + void value() {} +}; + +template +class MethodCall0 : public talk_base::Message, + public talk_base::MessageHandler { + public: + typedef R (C::*Method)(); + MethodCall0(C* c, Method m) : c_(c), m_(m) {} + + R Marshal(talk_base::Thread* t) { + t->Send(this, 0); + return r_.value(); + } + + private: + void OnMessage(talk_base::Message*) { r_.Invoke(c_, m_);} + + C* c_; + Method m_; + ReturnType r_; +}; + +template +class ConstMethodCall0 : public talk_base::Message, + public talk_base::MessageHandler { + public: + typedef R (C::*Method)() const; + ConstMethodCall0(C* c, Method m) : c_(c), m_(m) {} + + R Marshal(talk_base::Thread* t) { + t->Send(this, 0); + return r_.value(); + } + + private: + void OnMessage(talk_base::Message*) { r_.Invoke(c_, m_); } + + C* c_; + Method m_; + ReturnType r_; +}; + +template +class MethodCall1 : public talk_base::Message, + public talk_base::MessageHandler { + public: + typedef R (C::*Method)(T1 a1); + MethodCall1(C* c, Method m, T1 a1) : c_(c), m_(m), a1_(a1) {} + + R Marshal(talk_base::Thread* t) { + t->Send(this, 0); + return r_.value(); + } + + private: + void OnMessage(talk_base::Message*) { r_.Invoke(c_, m_, a1_); } + + C* c_; + Method m_; + ReturnType r_; + T1 a1_; +}; + +template +class ConstMethodCall1 : public talk_base::Message, + public talk_base::MessageHandler { + public: + typedef R (C::*Method)(T1 a1) const; + ConstMethodCall1(C* c, Method m, T1 a1) : c_(c), m_(m), a1_(a1) {} + + R Marshal(talk_base::Thread* t) { + t->Send(this, 0); + return r_.value(); + } + + private: + void OnMessage(talk_base::Message*) { r_.Invoke(c_, m_, a1_); } + + C* c_; + Method m_; + ReturnType r_; + T1 a1_; +}; + +template +class MethodCall2 : public talk_base::Message, + public talk_base::MessageHandler { + public: + typedef R (C::*Method)(T1 a1, T2 a2); + MethodCall2(C* c, Method m, T1 a1, T2 a2) : c_(c), m_(m), a1_(a1), a2_(a2) {} + + R Marshal(talk_base::Thread* t) { + t->Send(this, 0); + return r_.value(); + } + + private: + void OnMessage(talk_base::Message*) { r_.Invoke(c_, m_, a1_, a2_); } + + C* c_; + Method m_; + ReturnType r_; + T1 a1_; + T2 a2_; +}; + +template +class MethodCall3 : public talk_base::Message, + public talk_base::MessageHandler { + public: + typedef R (C::*Method)(T1 a1, T2 a2, T3 a3); + MethodCall3(C* c, Method m, T1 a1, T2 a2, T3 a3) + : c_(c), m_(m), a1_(a1), a2_(a2), a3_(a3) {} + + R Marshal(talk_base::Thread* t) { + t->Send(this, 0); + return r_.value(); + } + + private: + void OnMessage(talk_base::Message*) { r_.Invoke(c_, m_, a1_, a2_, a3_); } + + C* c_; + Method m_; + ReturnType r_; + T1 a1_; + T2 a2_; + T3 a3_; +}; + +#define BEGIN_PROXY_MAP(c) \ + class c##Proxy : public c##Interface {\ + protected:\ + typedef c##Interface C;\ + c##Proxy(talk_base::Thread* thread, C* c)\ + : owner_thread_(thread), \ + c_(c) {}\ + ~c##Proxy() {\ + MethodCall0 call(this, &c##Proxy::Release_s);\ + call.Marshal(owner_thread_);\ + }\ + public:\ + static talk_base::scoped_refptr Create(talk_base::Thread* thread, \ + C* c) {\ + return new talk_base::RefCountedObject(thread, c);\ + }\ + +#define PROXY_METHOD0(r, method)\ + r method() OVERRIDE {\ + MethodCall0 call(c_.get(), &C::method);\ + return call.Marshal(owner_thread_);\ + }\ + +#define PROXY_CONSTMETHOD0(r, method)\ + r method() const OVERRIDE {\ + ConstMethodCall0 call(c_.get(), &C::method);\ + return call.Marshal(owner_thread_);\ + }\ + +#define PROXY_METHOD1(r, method, t1)\ + r method(t1 a1) OVERRIDE {\ + MethodCall1 call(c_.get(), &C::method, a1);\ + return call.Marshal(owner_thread_);\ + }\ + +#define PROXY_CONSTMETHOD1(r, method, t1)\ + r method(t1 a1) const OVERRIDE {\ + ConstMethodCall1 call(c_.get(), &C::method, a1);\ + return call.Marshal(owner_thread_);\ + }\ + +#define PROXY_METHOD2(r, method, t1, t2)\ + r method(t1 a1, t2 a2) OVERRIDE {\ + MethodCall2 call(c_.get(), &C::method, a1, a2);\ + return call.Marshal(owner_thread_);\ + }\ + +#define PROXY_METHOD3(r, method, t1, t2, t3)\ + r method(t1 a1, t2 a2, t3 a3) OVERRIDE {\ + MethodCall3 call(c_.get(), &C::method, a1, a2, a3);\ + return call.Marshal(owner_thread_);\ + }\ + +#define END_PROXY() \ + private:\ + void Release_s() {\ + c_ = NULL;\ + }\ + mutable talk_base::Thread* owner_thread_;\ + talk_base::scoped_refptr c_;\ + };\ + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_PROXY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/remoteaudiosource.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/remoteaudiosource.h new file mode 100644 index 0000000..f1793b0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/remoteaudiosource.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. + */ + +#ifndef TALK_APP_WEBRTC_REMOTEAUDIOSOURCE_H_ +#define TALK_APP_WEBRTC_REMOTEAUDIOSOURCE_H_ + +#include + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/notifier.h" + +namespace webrtc { + +using webrtc::AudioSourceInterface; + +// This class implements the audio source used by the remote audio track. +class RemoteAudioSource : public Notifier { + public: + // Creates an instance of RemoteAudioSource. + static talk_base::scoped_refptr Create(); + + protected: + RemoteAudioSource(); + virtual ~RemoteAudioSource(); + + private: + typedef std::list AudioObserverList; + + // MediaSourceInterface implementation. + virtual MediaSourceInterface::SourceState state() const OVERRIDE; + + // AudioSourceInterface implementation. + virtual void SetVolume(double volume) OVERRIDE; + virtual void RegisterAudioObserver(AudioObserver* observer) OVERRIDE; + virtual void UnregisterAudioObserver(AudioObserver* observer) OVERRIDE; + + AudioObserverList audio_observers_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_REMOTEAUDIOSOURCE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/remotevideocapturer.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/remotevideocapturer.h new file mode 100644 index 0000000..11a2a1e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/remotevideocapturer.h @@ -0,0 +1,65 @@ +/* + * 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_APP_WEBRTC_REMOTEVIDEOCAPTURER_H_ +#define TALK_APP_WEBRTC_REMOTEVIDEOCAPTURER_H_ + +#include + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/media/base/videocapturer.h" +#include "talk/media/base/videorenderer.h" + +namespace webrtc { + +// RemoteVideoCapturer implements a simple cricket::VideoCapturer which +// gets decoded remote video frames from media channel. +// It's used as the remote video source's VideoCapturer so that the remote video +// can be used as a cricket::VideoCapturer and in that way a remote video stream +// can implement the MediaStreamSourceInterface. +class RemoteVideoCapturer : public cricket::VideoCapturer { + public: + RemoteVideoCapturer(); + virtual ~RemoteVideoCapturer(); + + // cricket::VideoCapturer implementation. + virtual cricket::CaptureState Start( + const cricket::VideoFormat& capture_format) OVERRIDE; + virtual void Stop() OVERRIDE; + virtual bool IsRunning() OVERRIDE; + virtual bool GetPreferredFourccs(std::vector* fourccs) OVERRIDE; + virtual bool GetBestCaptureFormat(const cricket::VideoFormat& desired, + cricket::VideoFormat* best_format) OVERRIDE; + virtual bool IsScreencast() const OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(RemoteVideoCapturer); +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_REMOTEVIDEOCAPTURER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/sctputils.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/sctputils.h new file mode 100644 index 0000000..f4c8e06 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/sctputils.h @@ -0,0 +1,55 @@ +/* + * 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_APP_WEBRTC_SCTPUTILS_H_ +#define TALK_APP_WEBRTC_SCTPUTILS_H_ + +#include + +#include "talk/app/webrtc/datachannelinterface.h" + +namespace talk_base { +class Buffer; +} // namespace talk_base + +namespace webrtc { +struct DataChannelInit; + +bool ParseDataChannelOpenMessage(const talk_base::Buffer& payload, + std::string* label, + DataChannelInit* config); + +bool ParseDataChannelOpenAckMessage(const talk_base::Buffer& payload); + +bool WriteDataChannelOpenMessage(const std::string& label, + const DataChannelInit& config, + talk_base::Buffer* payload); + +void WriteDataChannelOpenAckMessage(talk_base::Buffer* payload); +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_SCTPUTILS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/statscollector.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/statscollector.h new file mode 100644 index 0000000..9b2a19c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/statscollector.h @@ -0,0 +1,129 @@ +/* + * 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. + */ + +// This file contains a class used for gathering statistics from an ongoing +// libjingle PeerConnection. + +#ifndef TALK_APP_WEBRTC_STATSCOLLECTOR_H_ +#define TALK_APP_WEBRTC_STATSCOLLECTOR_H_ + +#include +#include +#include + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/app/webrtc/statstypes.h" +#include "talk/app/webrtc/webrtcsession.h" + +#include "talk/base/timing.h" + +namespace webrtc { + +class StatsCollector { + public: + StatsCollector(); + + // Register the session Stats should operate on. + // Set to NULL if the session has ended. + void set_session(WebRtcSession* session) { + session_ = session; + } + + // Adds a MediaStream with tracks that can be used as a |selector| in a call + // 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(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); + + // Prepare an SSRC report for the given ssrc. Used internally + // in the ExtractStatsFromList template. + StatsReport* PrepareLocalReport(uint32 ssrc, const std::string& transport); + // Prepare an SSRC report for the given remote ssrc. Used internally. + StatsReport* PrepareRemoteReport(uint32 ssrc, const std::string& transport); + // Extracts the ID of a Transport belonging to an SSRC. Used internally. + bool GetTransportIdFromProxy(const std::string& proxy, + std::string* transport_id); + + private: + bool CopySelectedReports(const std::string& selector, StatsReports* reports); + + // Helper method for AddCertificateReports. + std::string AddOneCertificateReport( + const talk_base::SSLCertificate* cert, const std::string& issuer_id); + + // Adds a report for this certificate and every certificate in its chain, and + // returns the leaf certificate's report's ID. + std::string AddCertificateReports(const talk_base::SSLCertificate* cert); + + void ExtractSessionInfo(); + void ExtractVoiceInfo(); + void ExtractVideoInfo(PeerConnectionInterface::StatsOutputLevel level); + double GetTimeNow(); + void BuildSsrcToTransportId(); + WebRtcSession* session() { return session_; } + webrtc::StatsReport* GetOrCreateReport(const std::string& type, + const std::string& id); + webrtc::StatsReport* GetReport(const std::string& type, + const std::string& id); + + // Helper method to get stats from the local audio tracks. + void UpdateStatsFromExistingLocalAudioTracks(); + void UpdateReportFromAudioTrack(AudioTrackInterface* track, + StatsReport* report); + + // A map from the report id to the report. + std::map reports_; + // Raw pointer to the session the statistics are gathered from. + WebRtcSession* session_; + double stats_gathering_started_; + talk_base::Timing timing_; + cricket::ProxyTransportMap proxy_to_transport_; + + typedef std::vector > + LocalAudioTrackVector; + LocalAudioTrackVector local_audio_tracks_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_STATSCOLLECTOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/statstypes.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/statstypes.h new file mode 100644 index 0000000..b96989d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/statstypes.h @@ -0,0 +1,215 @@ +/* + * 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. + */ + +// This file contains structures used for retrieving statistics from an ongoing +// libjingle session. + +#ifndef TALK_APP_WEBRTC_STATSTYPES_H_ +#define TALK_APP_WEBRTC_STATSTYPES_H_ + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/stringencode.h" + +namespace webrtc { + +class StatsReport { + public: + StatsReport() : timestamp(0) { } + + std::string id; // See below for contents. + std::string type; // See below for contents. + + struct Value { + std::string name; + std::string value; + }; + + void AddValue(const std::string& name, const std::string& value); + void AddValue(const std::string& name, int64 value); + template + void AddValue(const std::string& name, const std::vector& 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 Values; + Values values; + + // StatsReport types. + // A StatsReport of |type| = "googSession" contains overall information + // about the thing libjingle calls a session (which may contain one + // or more RTP sessions. + static const char kStatsReportTypeSession[]; + + // A StatsReport of |type| = "googTransport" contains information + // about a libjingle "transport". + static const char kStatsReportTypeTransport[]; + + // A StatsReport of |type| = "googComponent" contains information + // about a libjingle "channel" (typically, RTP or RTCP for a transport). + // This is intended to be the same thing as an ICE "Component". + static const char kStatsReportTypeComponent[]; + + // A StatsReport of |type| = "googCandidatePair" contains information + // about a libjingle "connection" - a single source/destination port pair. + // This is intended to be the same thing as an ICE "candidate pair". + static const char kStatsReportTypeCandidatePair[]; + + // StatsReport of |type| = "VideoBWE" is statistics for video Bandwidth + // Estimation, which is global per-session. The |id| field is "bweforvideo" + // (will probably change in the future). + static const char kStatsReportTypeBwe[]; + + // StatsReport of |type| = "ssrc" is statistics for a specific rtp stream. + // The |id| field is the SSRC in decimal form of the rtp stream. + static const char kStatsReportTypeSsrc[]; + + // StatsReport of |type| = "remoteSsrc" is statistics for a specific + // rtp stream, generated by the remote end of the connection. + static const char kStatsReportTypeRemoteSsrc[]; + + // StatsReport of |type| = "googTrack" is statistics for a specific media + // track. The |id| field is the track id. + static const char kStatsReportTypeTrack[]; + + // StatsReport of |type| = "iceCandidate" is statistics on a specific + // ICE Candidate. It links to its transport. + static const char kStatsReportTypeIceCandidate[]; + + // The id of StatsReport of type VideoBWE. + static const char kStatsReportVideoBweId[]; + + // A StatsReport of |type| = "googCertificate" contains an SSL certificate + // transmitted by one of the endpoints of this connection. The |id| is + // controlled by the fingerprint, and is used to identify the certificate in + // the Channel stats (as "googLocalCertificateId" or + // "googRemoteCertificateId") and in any child certificates (as + // "googIssuerId"). + static const char kStatsReportTypeCertificate[]; + + // StatsValue names + static const char kStatsValueNameAudioOutputLevel[]; + static const char kStatsValueNameAudioInputLevel[]; + static const char kStatsValueNameBytesSent[]; + static const char kStatsValueNamePacketsSent[]; + static const char kStatsValueNameBytesReceived[]; + static const char kStatsValueNamePacketsReceived[]; + static const char kStatsValueNamePacketsLost[]; + static const char kStatsValueNameTransportId[]; + static const char kStatsValueNameLocalAddress[]; + static const char kStatsValueNameRemoteAddress[]; + static const char kStatsValueNameWritable[]; + static const char kStatsValueNameReadable[]; + static const char kStatsValueNameActiveConnection[]; + + + // Internal StatsValue names + static const char kStatsValueNameAvgEncodeMs[]; + static const char kStatsValueNameEncodeUsagePercent[]; + static const char kStatsValueNameCaptureJitterMs[]; + static const char kStatsValueNameCaptureQueueDelayMsPerS[]; + static const char kStatsValueNameCodecName[]; + static const char kStatsValueNameBandwidthLimitedResolution[]; + static const char kStatsValueNameCpuLimitedResolution[]; + static const char kStatsValueNameViewLimitedResolution[]; + static const char kStatsValueNameEchoCancellationQualityMin[]; + static const char kStatsValueNameEchoDelayMedian[]; + 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[]; + static const char kStatsValueNameFrameRateDecoded[]; + static const char kStatsValueNameFrameRateOutput[]; + static const char kStatsValueNameDecodeMs[]; + static const char kStatsValueNameMaxDecodeMs[]; + static const char kStatsValueNameCurrentDelayMs[]; + static const char kStatsValueNameTargetDelayMs[]; + 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[]; + static const char kStatsValueNameTargetEncBitrate[]; + static const char kStatsValueNameActualEncBitrate[]; + static const char kStatsValueNameRetransmitBitrate[]; + static const char kStatsValueNameTransmitBitrate[]; + static const char kStatsValueNameBucketDelay[]; + static const char kStatsValueNameInitiator[]; + static const char kStatsValueNameTransportType[]; + static const char kStatsValueNameContentName[]; + static const char kStatsValueNameComponent[]; + static const char kStatsValueNameChannelId[]; + static const char kStatsValueNameTrackId[]; + static const char kStatsValueNameSsrc[]; + static const char kStatsValueNameTypingNoiseState[]; + static const char kStatsValueNameDer[]; + static const char kStatsValueNameFingerprint[]; + static const char kStatsValueNameFingerprintAlgorithm[]; + static const char kStatsValueNameIssuerId[]; + static const char kStatsValueNameLocalCertificateId[]; + 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 StatsReports; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_STATSTYPES_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/streamcollection.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/streamcollection.h new file mode 100644 index 0000000..f38adc4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/streamcollection.h @@ -0,0 +1,125 @@ +/* + * 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_APP_WEBRTC_STREAMCOLLECTION_H_ +#define TALK_APP_WEBRTC_STREAMCOLLECTION_H_ + +#include +#include + +#include "talk/app/webrtc/peerconnectioninterface.h" + +namespace webrtc { + +// Implementation of StreamCollection. +class StreamCollection : public StreamCollectionInterface { + public: + static talk_base::scoped_refptr Create() { + talk_base::RefCountedObject* implementation = + new talk_base::RefCountedObject(); + return implementation; + } + + static talk_base::scoped_refptr Create( + StreamCollection* streams) { + talk_base::RefCountedObject* implementation = + new talk_base::RefCountedObject(streams); + return implementation; + } + + virtual size_t count() { + return media_streams_.size(); + } + + virtual MediaStreamInterface* at(size_t index) { + return media_streams_.at(index); + } + + virtual MediaStreamInterface* find(const std::string& label) { + for (StreamVector::iterator it = media_streams_.begin(); + it != media_streams_.end(); ++it) { + if ((*it)->label().compare(label) == 0) { + return (*it); + } + } + return NULL; + } + + virtual MediaStreamTrackInterface* FindAudioTrack( + const std::string& id) { + for (size_t i = 0; i < media_streams_.size(); ++i) { + MediaStreamTrackInterface* track = media_streams_[i]->FindAudioTrack(id); + if (track) { + return track; + } + } + return NULL; + } + + virtual MediaStreamTrackInterface* FindVideoTrack( + const std::string& id) { + for (size_t i = 0; i < media_streams_.size(); ++i) { + MediaStreamTrackInterface* track = media_streams_[i]->FindVideoTrack(id); + if (track) { + return track; + } + } + return NULL; + } + + void AddStream(MediaStreamInterface* stream) { + for (StreamVector::iterator it = media_streams_.begin(); + it != media_streams_.end(); ++it) { + if ((*it)->label().compare(stream->label()) == 0) + return; + } + media_streams_.push_back(stream); + } + + void RemoveStream(MediaStreamInterface* remove_stream) { + for (StreamVector::iterator it = media_streams_.begin(); + it != media_streams_.end(); ++it) { + if ((*it)->label().compare(remove_stream->label()) == 0) { + media_streams_.erase(it); + break; + } + } + } + + protected: + StreamCollection() {} + explicit StreamCollection(StreamCollection* original) + : media_streams_(original->media_streams_) { + } + typedef std::vector > + StreamVector; + StreamVector media_streams_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_STREAMCOLLECTION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/umametrics.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/umametrics.h new file mode 100644 index 0000000..a8e6a96 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/umametrics.h @@ -0,0 +1,59 @@ +/* + * 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 contains enums related to IPv4/IPv6 metrics. + +#ifndef TALK_APP_WEBRTC_UMAMETRICS_H_ +#define TALK_APP_WEBRTC_UMAMETRICS_H_ + +namespace webrtc { + +// Currently this contains information related to WebRTC network/transport +// information. + +// 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, +}; + +// 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. +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_UMA6METRICS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosource.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosource.h new file mode 100644 index 0000000..b68eca0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosource.h @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_VIDEOSOURCE_H_ +#define TALK_APP_WEBRTC_VIDEOSOURCE_H_ + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/notifier.h" +#include "talk/app/webrtc/videosourceinterface.h" +#include "talk/app/webrtc/videotrackrenderers.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sigslot.h" +#include "talk/media/base/videocapturer.h" +#include "talk/media/base/videocommon.h" + +// VideoSource implements VideoSourceInterface. It owns a +// cricket::VideoCapturer and make sure the camera is started at a resolution +// that honors the constraints. +// The state is set depending on the result of starting the capturer. +// If the constraint can't be met or the capturer fails to start, the state +// transition to kEnded, otherwise it transitions to kLive. + +namespace cricket { + +class ChannelManager; + +} // namespace cricket + +namespace webrtc { + +class MediaConstraintsInterface; + +class VideoSource : public Notifier, + public sigslot::has_slots<> { + public: + // Creates an instance of VideoSource. + // VideoSource take ownership of |capturer|. + // |constraints| can be NULL and in that case the camera is opened using a + // default resolution. + static talk_base::scoped_refptr Create( + cricket::ChannelManager* channel_manager, + cricket::VideoCapturer* capturer, + const webrtc::MediaConstraintsInterface* constraints); + + virtual SourceState state() const { return state_; } + virtual const cricket::VideoOptions* options() const { return &options_; } + virtual cricket::VideoRenderer* FrameInput(); + + virtual cricket::VideoCapturer* GetVideoCapturer() { + return video_capturer_.get(); + } + // |output| will be served video frames as long as the underlying capturer + // is running video frames. + virtual void AddSink(cricket::VideoRenderer* output); + virtual void RemoveSink(cricket::VideoRenderer* output); + + protected: + VideoSource(cricket::ChannelManager* channel_manager, + cricket::VideoCapturer* capturer); + virtual ~VideoSource(); + void Initialize(const webrtc::MediaConstraintsInterface* constraints); + + private: + void OnStateChange(cricket::VideoCapturer* capturer, + cricket::CaptureState capture_state); + void SetState(SourceState new_state); + + cricket::ChannelManager* channel_manager_; + talk_base::scoped_ptr video_capturer_; + talk_base::scoped_ptr frame_input_; + + cricket::VideoFormat format_; + cricket::VideoOptions options_; + SourceState state_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_VIDEOSOURCE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosourceinterface.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosourceinterface.h new file mode 100644 index 0000000..1568deb --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosourceinterface.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_VIDEOSOURCEINTERFACE_H_ +#define TALK_APP_WEBRTC_VIDEOSOURCEINTERFACE_H_ + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/media/base/mediachannel.h" + +namespace webrtc { + +// VideoSourceInterface is a reference counted source used for VideoTracks. +// The same source can be used in multiple VideoTracks. +// The methods are only supposed to be called by the PeerConnection +// implementation. +class VideoSourceInterface : public MediaSourceInterface { + public: + // Get access to the source implementation of cricket::VideoCapturer. + // This can be used for receiving frames and state notifications. + // But it should not be used for starting or stopping capturing. + virtual cricket::VideoCapturer* GetVideoCapturer() = 0; + // Adds |output| to the source to receive frames. + virtual void AddSink(cricket::VideoRenderer* output) = 0; + virtual void RemoveSink(cricket::VideoRenderer* output) = 0; + virtual const cricket::VideoOptions* options() const = 0; + virtual cricket::VideoRenderer* FrameInput() = 0; + + protected: + virtual ~VideoSourceInterface() {} +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_VIDEOSOURCEINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosourceproxy.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosourceproxy.h new file mode 100644 index 0000000..4c53f3c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videosourceproxy.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_VIDEOSOURCEPROXY_H_ +#define TALK_APP_WEBRTC_VIDEOSOURCEPROXY_H_ + +#include "talk/app/webrtc/proxy.h" +#include "talk/app/webrtc/videosourceinterface.h" + +namespace webrtc { + +// VideoSourceProxy makes sure the real VideoSourceInterface implementation is +// destroyed on the signaling thread and marshals all method calls to the +// signaling thread. +BEGIN_PROXY_MAP(VideoSource) + PROXY_CONSTMETHOD0(SourceState, state) + PROXY_METHOD0(cricket::VideoCapturer*, GetVideoCapturer) + PROXY_METHOD1(void, AddSink, cricket::VideoRenderer*) + PROXY_METHOD1(void, RemoveSink, cricket::VideoRenderer*) + PROXY_CONSTMETHOD0(const cricket::VideoOptions*, options) + PROXY_METHOD0(cricket::VideoRenderer*, FrameInput) + PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) + PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) +END_PROXY() + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_VIDEOSOURCEPROXY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videotrack.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videotrack.h new file mode 100644 index 0000000..06c69b7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videotrack.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_VIDEOTRACK_H_ +#define TALK_APP_WEBRTC_VIDEOTRACK_H_ + +#include + +#include "talk/app/webrtc/mediastreamtrack.h" +#include "talk/app/webrtc/videosourceinterface.h" +#include "talk/app/webrtc/videotrackrenderers.h" +#include "talk/base/scoped_ref_ptr.h" + +namespace webrtc { + +class VideoTrack : public MediaStreamTrack { + public: + static talk_base::scoped_refptr Create( + const std::string& label, VideoSourceInterface* source); + + virtual void AddRenderer(VideoRendererInterface* renderer); + virtual void RemoveRenderer(VideoRendererInterface* renderer); + virtual VideoSourceInterface* GetSource() const { + return video_source_.get(); + } + virtual bool set_enabled(bool enable); + virtual std::string kind() const; + + protected: + VideoTrack(const std::string& id, VideoSourceInterface* video_source); + ~VideoTrack(); + + private: + VideoTrackRenderers renderers_; + talk_base::scoped_refptr video_source_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_VIDEOTRACK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videotrackrenderers.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videotrackrenderers.h new file mode 100644 index 0000000..f1541fa --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/videotrackrenderers.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_VIDEOTRACKRENDERERS_H_ +#define TALK_APP_WEBRTC_VIDEOTRACKRENDERERS_H_ + +#include + +#include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/base/criticalsection.h" +#include "talk/media/base/videorenderer.h" + +namespace webrtc { + +// Class used for rendering cricket::VideoFrames to multiple renderers of type +// VideoRendererInterface. +// Each VideoTrack owns a VideoTrackRenderers instance. +// The class is thread safe. Rendering to the added VideoRendererInterfaces is +// done on the same thread as the cricket::VideoRenderer. +class VideoTrackRenderers : public cricket::VideoRenderer { + public: + VideoTrackRenderers(); + ~VideoTrackRenderers(); + + // Implements cricket::VideoRenderer + virtual bool SetSize(int width, int height, int reserved); + virtual bool RenderFrame(const cricket::VideoFrame* frame); + + void AddRenderer(VideoRendererInterface* renderer); + void RemoveRenderer(VideoRendererInterface* renderer); + void SetEnabled(bool enable); + + private: + struct RenderObserver { + explicit RenderObserver(VideoRendererInterface* renderer) + : renderer_(renderer), + size_set_(false) { + } + VideoRendererInterface* renderer_; + bool size_set_; + }; + + int width_; + int height_; + bool enabled_; + std::vector renderers_; + + talk_base::CriticalSection critical_section_; // Protects the above variables +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_VIDEOTRACKRENDERERS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsdp.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsdp.h new file mode 100644 index 0000000..9d348b7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsdp.h @@ -0,0 +1,81 @@ +/* + * 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. + */ + +// This file contain functions for parsing and serializing SDP messages. +// Related RFC/draft including: +// * RFC 4566 - SDP +// * RFC 5245 - ICE +// * RFC 3388 - Grouping of Media Lines in SDP +// * RFC 4568 - SDP Security Descriptions for Media Streams +// * draft-lennox-mmusic-sdp-source-selection-02 - +// Mechanisms for Media Source Selection in SDP + +#ifndef TALK_APP_WEBRTC_WEBRTCSDP_H_ +#define TALK_APP_WEBRTC_WEBRTCSDP_H_ + +#include + +namespace webrtc { + +class IceCandidateInterface; +class JsepIceCandidate; +class JsepSessionDescription; +struct SdpParseError; + +// Serializes the passed in JsepSessionDescription. +// Serialize SessionDescription including candidates if +// JsepSessionDescription has candidates. +// jdesc - The JsepSessionDescription object to be serialized. +// return - SDP string serialized from the arguments. +std::string SdpSerialize(const JsepSessionDescription& jdesc); + +// Serializes the passed in IceCandidateInterface to a SDP string. +// candidate - The candidate to be serialized. +std::string SdpSerializeCandidate(const IceCandidateInterface& candidate); + +// Deserializes the passed in SDP string to a JsepSessionDescription. +// message - SDP string to be Deserialized. +// jdesc - The JsepSessionDescription deserialized from the SDP string. +// error - The detail error information when parsing fails. +// return - true on success, false on failure. +bool SdpDeserialize(const std::string& message, + JsepSessionDescription* jdesc, + SdpParseError* error); + +// Deserializes the passed in SDP string to one JsepIceCandidate. +// The first line must be a=candidate line and only the first line will be +// parsed. +// message - The SDP string to be Deserialized. +// candidates - The JsepIceCandidate from the SDP string. +// error - The detail error information when parsing fails. +// return - true on success, false on failure. +bool SdpDeserializeCandidate(const std::string& message, + JsepIceCandidate* candidate, + SdpParseError* error); +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_WEBRTCSDP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsession.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsession.h new file mode 100644 index 0000000..fe3ce81 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsession.h @@ -0,0 +1,354 @@ +/* + * 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. + */ + +#ifndef TALK_APP_WEBRTC_WEBRTCSESSION_H_ +#define TALK_APP_WEBRTC_WEBRTCSESSION_H_ + +#include + +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/app/webrtc/dtmfsender.h" +#include "talk/app/webrtc/mediastreamprovider.h" +#include "talk/app/webrtc/datachannel.h" +#include "talk/app/webrtc/statstypes.h" +#include "talk/base/sigslot.h" +#include "talk/base/thread.h" +#include "talk/media/base/mediachannel.h" +#include "talk/p2p/base/session.h" +#include "talk/session/media/mediasession.h" + +namespace cricket { + +class BaseChannel; +class ChannelManager; +class DataChannel; +class StatsReport; +class Transport; +class VideoCapturer; +class VideoChannel; +class VoiceChannel; + +} // namespace cricket + +namespace webrtc { + +class IceRestartAnswerLatch; +class JsepIceCandidate; +class MediaStreamSignaling; +class WebRtcSessionDescriptionFactory; + +extern const char kBundleWithoutRtcpMux[]; +extern const char kCreateChannelFailed[]; +extern const char kInvalidCandidates[]; +extern const char kInvalidSdp[]; +extern const char kMlineMismatch[]; +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 kSessionErrorDesc[]; + +// ICE state callback interface. +class IceObserver { + public: + IceObserver() {} + // Called any time the IceConnectionState changes + virtual void OnIceConnectionChange( + PeerConnectionInterface::IceConnectionState new_state) {} + // Called any time the IceGatheringState changes + virtual void OnIceGatheringChange( + PeerConnectionInterface::IceGatheringState new_state) {} + // New Ice candidate have been found. + virtual void OnIceCandidate(const IceCandidateInterface* candidate) = 0; + // All Ice candidates have been found. + // TODO(bemasc): Remove this once callers transition to OnIceGatheringChange. + // (via PeerConnectionObserver) + virtual void OnIceComplete() {} + + protected: + ~IceObserver() {} + + private: + DISALLOW_COPY_AND_ASSIGN(IceObserver); +}; + +class WebRtcSession : public cricket::BaseSession, + public AudioProviderInterface, + public DataChannelFactory, + public VideoProviderInterface, + public DtmfProviderInterface, + public DataChannelProviderInterface { + public: + WebRtcSession(cricket::ChannelManager* channel_manager, + talk_base::Thread* signaling_thread, + talk_base::Thread* worker_thread, + cricket::PortAllocator* port_allocator, + MediaStreamSignaling* mediastream_signaling); + virtual ~WebRtcSession(); + + bool Initialize(const PeerConnectionFactoryInterface::Options& options, + const MediaConstraintsInterface* constraints, + 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(); + + void RegisterIceObserver(IceObserver* observer) { + ice_observer_ = observer; + } + + virtual cricket::VoiceChannel* voice_channel() { + return voice_channel_.get(); + } + virtual cricket::VideoChannel* video_channel() { + return video_channel_.get(); + } + virtual cricket::DataChannel* data_channel() { + return data_channel_.get(); + } + + void SetSdesPolicy(cricket::SecurePolicy secure_policy); + cricket::SecurePolicy SdesPolicy() const; + + // Get current ssl role from transport. + bool GetSslRole(talk_base::SSLRole* role); + + // Generic error message callback from WebRtcSession. + // TODO - It may be necessary to supply error code as well. + sigslot::signal0<> SignalError; + + void CreateOffer(CreateSessionDescriptionObserver* observer, + const MediaConstraintsInterface* constraints); + void CreateAnswer(CreateSessionDescriptionObserver* observer, + const MediaConstraintsInterface* constraints); + // The ownership of |desc| will be transferred after this call. + bool SetLocalDescription(SessionDescriptionInterface* desc, + std::string* err_desc); + // The ownership of |desc| will be transferred after this call. + 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(); + } + const SessionDescriptionInterface* remote_description() const { + return remote_desc_.get(); + } + + // Get the id used as a media stream track's "id" field from ssrc. + virtual bool GetTrackIdBySsrc(uint32 ssrc, std::string* id); + + // AudioMediaProviderInterface implementation. + virtual void SetAudioPlayout(uint32 ssrc, bool enable, + cricket::AudioRenderer* renderer) OVERRIDE; + 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, + cricket::VideoCapturer* camera) OVERRIDE; + virtual void SetVideoPlayout(uint32 ssrc, + bool enable, + cricket::VideoRenderer* renderer) OVERRIDE; + virtual void SetVideoSend(uint32 ssrc, bool enable, + const cricket::VideoOptions* options) OVERRIDE; + + // Implements DtmfProviderInterface. + virtual bool CanInsertDtmf(const std::string& track_id); + virtual bool InsertDtmf(const std::string& track_id, + int code, int duration); + virtual sigslot::signal0<>* GetOnDestroyedSignal(); + + // Implements DataChannelProviderInterface. + virtual bool SendData(const cricket::SendDataParams& params, + const talk_base::Buffer& payload, + cricket::SendDataResult* result) OVERRIDE; + virtual bool ConnectDataChannel(DataChannel* webrtc_data_channel) OVERRIDE; + virtual void DisconnectDataChannel(DataChannel* webrtc_data_channel) OVERRIDE; + virtual void AddSctpDataStream(uint32 sid) OVERRIDE; + virtual void RemoveSctpDataStream(uint32 sid) OVERRIDE; + virtual bool ReadyToSendData() const OVERRIDE; + + // Implements DataChannelFactory. + talk_base::scoped_refptr CreateDataChannel( + const std::string& label, + const InternalDataChannelInit* config) OVERRIDE; + + cricket::DataChannelType data_channel_type() const; + + bool IceRestartPending() const; + + void ResetIceRestartLatch(); + + // Called when an SSLIdentity is generated or retrieved by + // WebRTCSessionDescriptionFactory. Should happen before setLocalDescription. + void OnIdentityReady(talk_base::SSLIdentity* identity); + + // For unit test. + bool waiting_for_identity() const; + + private: + // Indicates the type of SessionDescription in a call to SetLocalDescription + // and SetRemoteDescription. + enum Action { + kOffer, + kPrAnswer, + kAnswer, + }; + + // Invokes ConnectChannels() on transport proxies, which initiates ice + // candidates allocation. + bool StartCandidatesAllocation(); + bool UpdateSessionState(Action action, cricket::ContentSource source, + std::string* err_desc); + static Action GetAction(const std::string& type); + + // Transport related callbacks, override from 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); + virtual void OnCandidatesAllocationDone(); + + // Creates local session description with audio and video contents. + bool CreateDefaultLocalDescription(); + // Enables media channels to allow sending of media. + void EnableChannels(); + // Creates a JsepIceCandidate and adds it to the local session description + // and notify observers. Called when a new local candidate have been found. + void ProcessNewLocalCandidate(const std::string& content_name, + const cricket::Candidates& candidates); + // Returns the media index for a local ice candidate given the content name. + // Returns false if the local session description does not have a media + // content called |content_name|. + bool GetLocalCandidateMediaIndex(const std::string& content_name, + int* sdp_mline_index); + // Uses all remote candidates in |remote_desc| in this session. + bool UseCandidatesInSessionDescription( + const SessionDescriptionInterface* remote_desc); + // Uses |candidate| in this session. + bool UseCandidate(const IceCandidateInterface* candidate); + // Deletes the corresponding channel of contents that don't exist in |desc|. + // |desc| can be null. This means that all channels are deleted. + void RemoveUnusedChannelsAndTransports( + const cricket::SessionDescription* desc); + + // Allocates media channels based on the |desc|. If |desc| doesn't have + // the BUNDLE option, this method will disable BUNDLE in PortAllocator. + // This method will also delete any existing media channels before creating. + bool CreateChannels(const cricket::SessionDescription* desc); + + // Helper methods to create media channels. + bool CreateVoiceChannel(const cricket::ContentInfo* content); + bool CreateVideoChannel(const cricket::ContentInfo* content); + bool CreateDataChannel(const cricket::ContentInfo* content); + + // Copy the candidates from |saved_candidates_| to |dest_desc|. + // The |saved_candidates_| will be cleared after this function call. + void CopySavedCandidates(SessionDescriptionInterface* dest_desc); + + // 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(State state); + void SetIceConnectionState(PeerConnectionInterface::IceConnectionState state); + + bool ValidateBundleSettings(const cricket::SessionDescription* desc); + bool HasRtcpMuxEnabled(const cricket::ContentInfo* content); + // Below methods are helper methods which verifies SDP. + bool ValidateSessionDescription(const SessionDescriptionInterface* sdesc, + cricket::ContentSource source, + std::string* err_desc); + + // Check if a call to SetLocalDescription is acceptable with |action|. + bool ExpectSetLocalDescription(Action action); + // Check if a call to SetRemoteDescription is acceptable with |action|. + bool ExpectSetRemoteDescription(Action action); + // Verifies a=setup attribute as per RFC 5763. + bool ValidateDtlsSetupAttribute(const cricket::SessionDescription* desc, + Action action); + + std::string GetSessionErrorMsg(); + + talk_base::scoped_ptr voice_channel_; + talk_base::scoped_ptr video_channel_; + talk_base::scoped_ptr data_channel_; + cricket::ChannelManager* channel_manager_; + MediaStreamSignaling* mediastream_signaling_; + IceObserver* ice_observer_; + PeerConnectionInterface::IceConnectionState ice_connection_state_; + talk_base::scoped_ptr local_desc_; + talk_base::scoped_ptr remote_desc_; + // Candidates that arrived before the remote description was set. + std::vector saved_candidates_; + // If the remote peer is using a older version of implementation. + bool older_version_remote_peer_; + bool dtls_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, + // constraint kEnableDtlsSrtp is true, and constaint kEnableRtpDataChannels is + // not set or false, SCTP is allowed (DCT_SCTP); + // 2. If constraint kEnableRtpDataChannels is true, RTP is allowed (DCT_RTP); + // 3. If both 1&2 are false, data channel is not allowed (DCT_NONE). + cricket::DataChannelType data_channel_type_; + talk_base::scoped_ptr ice_restart_latch_; + + talk_base::scoped_ptr + webrtc_session_desc_factory_; + + sigslot::signal0<> SignalVoiceChannelDestroyed; + 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 + +#endif // TALK_APP_WEBRTC_WEBRTCSESSION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsessiondescriptionfactory.h b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsessiondescriptionfactory.h new file mode 100644 index 0000000..d954669 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/app/webrtc/webrtcsessiondescriptionfactory.h @@ -0,0 +1,169 @@ +/* + * 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_APP_WEBRTC_WEBRTCSESSIONDESCRIPTIONFACTORY_H_ +#define TALK_APP_WEBRTC_WEBRTCSESSIONDESCRIPTIONFACTORY_H_ + +#include "talk/app/webrtc/peerconnectioninterface.h" +#include "talk/base/messagehandler.h" +#include "talk/p2p/base/transportdescriptionfactory.h" +#include "talk/session/media/mediasession.h" + +namespace cricket { +class ChannelManager; +class TransportDescriptionFactory; +} // namespace cricket + +namespace webrtc { +class CreateSessionDescriptionObserver; +class MediaConstraintsInterface; +class MediaStreamSignaling; +class SessionDescriptionInterface; +class WebRtcSession; + +// DTLS identity request callback class. +class WebRtcIdentityRequestObserver : public DTLSIdentityRequestObserver, + public sigslot::has_slots<> { + public: + // DTLSIdentityRequestObserver overrides. + virtual void OnFailure(int error) { + SignalRequestFailed(error); + } + virtual void OnSuccess(const std::string& der_cert, + const std::string& der_private_key) { + SignalIdentityReady(der_cert, der_private_key); + } + + sigslot::signal1 SignalRequestFailed; + sigslot::signal2 SignalIdentityReady; +}; + +struct CreateSessionDescriptionRequest { + enum Type { + kOffer, + kAnswer, + }; + + CreateSessionDescriptionRequest( + Type type, + CreateSessionDescriptionObserver* observer, + const cricket::MediaSessionOptions& options) + : type(type), + observer(observer), + options(options) {} + + Type type; + talk_base::scoped_refptr observer; + cricket::MediaSessionOptions options; +}; + +// This class is used to create offer/answer session description with regards to +// the async DTLS identity generation for WebRtcSession. +// It queues the create offer/answer request until the DTLS identity +// request has completed, i.e. when OnIdentityRequestFailed or OnIdentityReady +// is called. +class WebRtcSessionDescriptionFactory : public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + WebRtcSessionDescriptionFactory( + talk_base::Thread* signaling_thread, + cricket::ChannelManager* channel_manager, + MediaStreamSignaling* mediastream_signaling, + DTLSIdentityServiceInterface* dtls_identity_service, + // TODO(jiayl): remove the dependency on session once b/10226852 is fixed. + WebRtcSession* session, + const std::string& session_id, + cricket::DataChannelType dct, + bool dtls_enabled); + virtual ~WebRtcSessionDescriptionFactory(); + + static void CopyCandidatesFromSessionDescription( + const SessionDescriptionInterface* source_desc, + SessionDescriptionInterface* dest_desc); + + void CreateOffer( + CreateSessionDescriptionObserver* observer, + const MediaConstraintsInterface* constraints); + void CreateAnswer( + CreateSessionDescriptionObserver* observer, + const MediaConstraintsInterface* constraints); + + void SetSdesPolicy(cricket::SecurePolicy secure_policy); + cricket::SecurePolicy SdesPolicy() const; + + sigslot::signal1 SignalIdentityReady; + + // For testing. + bool waiting_for_identity() const { + return identity_request_state_ == IDENTITY_WAITING; + } + + private: + enum IdentityRequestState { + IDENTITY_NOT_NEEDED, + IDENTITY_WAITING, + IDENTITY_SUCCEEDED, + IDENTITY_FAILED, + }; + + // MessageHandler implementation. + virtual void OnMessage(talk_base::Message* msg); + + void InternalCreateOffer(CreateSessionDescriptionRequest request); + void InternalCreateAnswer(CreateSessionDescriptionRequest request); + void PostCreateSessionDescriptionFailed( + CreateSessionDescriptionObserver* observer, + const std::string& error); + void PostCreateSessionDescriptionSucceeded( + CreateSessionDescriptionObserver* observer, + SessionDescriptionInterface* description); + + void OnIdentityRequestFailed(int error); + void OnIdentityReady(const std::string& der_cert, + const std::string& der_private_key); + void SetIdentity(talk_base::SSLIdentity* identity); + + std::queue + create_session_description_requests_; + talk_base::Thread* signaling_thread_; + MediaStreamSignaling* mediastream_signaling_; + cricket::TransportDescriptionFactory transport_desc_factory_; + cricket::MediaSessionDescriptionFactory session_desc_factory_; + uint64 session_version_; + talk_base::scoped_ptr identity_service_; + talk_base::scoped_refptr + identity_request_observer_; + WebRtcSession* session_; + std::string session_id_; + cricket::DataChannelType data_channel_type_; + IdentityRequestState identity_request_state_; + + DISALLOW_COPY_AND_ASSIGN(WebRtcSessionDescriptionFactory); +}; +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_WEBRTCSESSIONDESCRIPTIONFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/asyncfile.h b/thirdparties/common/include/webrtc-sdk/talk/base/asyncfile.h new file mode 100644 index 0000000..cfc3e26 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/asyncfile.h @@ -0,0 +1,57 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_ASYNCFILE_H__ +#define TALK_BASE_ASYNCFILE_H__ + +#include "talk/base/sigslot.h" + +namespace talk_base { + +// Provides the ability to perform file I/O asynchronously. +// TODO: Create a common base class with AsyncSocket. +class AsyncFile { + public: + AsyncFile(); + virtual ~AsyncFile(); + + // Determines whether the file will receive read events. + virtual bool readable() = 0; + virtual void set_readable(bool value) = 0; + + // Determines whether the file will receive write events. + virtual bool writable() = 0; + virtual void set_writable(bool value) = 0; + + sigslot::signal1 SignalReadEvent; + sigslot::signal1 SignalWriteEvent; + sigslot::signal2 SignalCloseEvent; +}; + +} // namespace talk_base + +#endif // TALK_BASE_ASYNCFILE_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/asynchttprequest.h b/thirdparties/common/include/webrtc-sdk/talk/base/asynchttprequest.h new file mode 100644 index 0000000..d4de520 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/asynchttprequest.h @@ -0,0 +1,121 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_ASYNCHTTPREQUEST_H_ +#define TALK_BASE_ASYNCHTTPREQUEST_H_ + +#include +#include "talk/base/event.h" +#include "talk/base/httpclient.h" +#include "talk/base/signalthread.h" +#include "talk/base/socketpool.h" +#include "talk/base/sslsocketfactory.h" + +namespace talk_base { + +class FirewallManager; + +/////////////////////////////////////////////////////////////////////////////// +// AsyncHttpRequest +// Performs an HTTP request on a background thread. Notifies on the foreground +// thread once the request is done (successfully or unsuccessfully). +/////////////////////////////////////////////////////////////////////////////// + +class AsyncHttpRequest : public SignalThread { + public: + explicit AsyncHttpRequest(const std::string &user_agent); + ~AsyncHttpRequest(); + + // If start_delay is less than or equal to zero, this starts immediately. + // Start_delay defaults to zero. + int start_delay() const { return start_delay_; } + void set_start_delay(int delay) { start_delay_ = delay; } + + const ProxyInfo& proxy() const { return proxy_; } + void set_proxy(const ProxyInfo& proxy) { + proxy_ = proxy; + } + void set_firewall(FirewallManager * firewall) { + firewall_ = firewall; + } + + // The DNS name of the host to connect to. + const std::string& host() { return host_; } + void set_host(const std::string& host) { host_ = host; } + + // The port to connect to on the target host. + int port() { return port_; } + void set_port(int port) { port_ = port; } + + // Whether the request should use SSL. + bool secure() { return secure_; } + void set_secure(bool secure) { secure_ = secure; } + + // Time to wait on the download, in ms. + int timeout() { return timeout_; } + void set_timeout(int timeout) { timeout_ = timeout; } + + // Fail redirects to allow analysis of redirect urls, etc. + bool fail_redirect() const { return fail_redirect_; } + void set_fail_redirect(bool redirect) { fail_redirect_ = redirect; } + + // Returns the redirect when redirection occurs + const std::string& response_redirect() { return response_redirect_; } + + HttpRequestData& request() { return client_.request(); } + HttpResponseData& response() { return client_.response(); } + HttpErrorType error() { return error_; } + + protected: + void set_error(HttpErrorType error) { error_ = error; } + virtual void OnWorkStart(); + virtual void OnWorkStop(); + void OnComplete(HttpClient* client, HttpErrorType error); + virtual void OnMessage(Message* message); + virtual void DoWork(); + + private: + void LaunchRequest(); + + int start_delay_; + ProxyInfo proxy_; + FirewallManager* firewall_; + std::string host_; + int port_; + bool secure_; + int timeout_; + bool fail_redirect_; + SslSocketFactory factory_; + ReuseSocketPool pool_; + HttpClient client_; + HttpErrorType error_; + std::string response_redirect_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_ASYNCHTTPREQUEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/asyncinvoker-inl.h b/thirdparties/common/include/webrtc-sdk/talk/base/asyncinvoker-inl.h new file mode 100644 index 0000000..b676301 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/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 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& callback) { + CritScope cs(&crit_); + callback_ = callback; + } + bool CallbackCanceled() const { return calling_thread_ == NULL; } + + private: + Callback0 callback_; + CriticalSection crit_; + AsyncInvoker* invoker_; + Thread* calling_thread_; + + void CancelCallback(); +}; + +// Closures that have a non-void return value and require a callback. +template +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(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 NotifyingAsyncClosure + : 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(Bind(callback, callback_host))); + } + virtual void Execute() { + functor_(); + TriggerCallback(); + } + + private: + FunctorT functor_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_ASYNCINVOKER_INL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/asyncinvoker.h b/thirdparties/common/include/webrtc-sdk/talk/base/asyncinvoker.h new file mode 100644 index 0000000..4b692cd --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/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( +// thread, Bind(&MyClass::AsyncTaskWithResult, this, x), +// &MyClass::OnTaskComplete, this); +// } +// void FireAnotherAsyncTask(Thread* thread) { +// // No callback specified means fire-and-forget. +// invoker_.AsyncInvoke( +// 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 + void AsyncInvoke(Thread* thread, + const FunctorT& functor, + uint32 id = 0) { + AsyncClosure* closure = + new RefCountedObject >(functor); + DoInvoke(thread, closure, id); + } + + // Call |functor| asynchronously on |thread|, calling |callback| when done. + template + void AsyncInvoke(Thread* thread, + const FunctorT& functor, + void (HostT::*callback)(ReturnT), + HostT* callback_host, + uint32 id = 0) { + AsyncClosure* closure = + new RefCountedObject >( + 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 + void AsyncInvoke(Thread* thread, + const FunctorT& functor, + void (HostT::*callback)(), + HostT* callback_host, + uint32 id = 0) { + AsyncClosure* closure = + new RefCountedObject >( + 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/thirdparties/common/include/webrtc-sdk/talk/base/asyncpacketsocket.h b/thirdparties/common/include/webrtc-sdk/talk/base/asyncpacketsocket.h new file mode 100644 index 0000000..7e86f36 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/asyncpacketsocket.h @@ -0,0 +1,157 @@ +/* + * 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 TALK_BASE_ASYNCPACKETSOCKET_H_ +#define TALK_BASE_ASYNCPACKETSOCKET_H_ + +#include "talk/base/dscp.h" +#include "talk/base/sigslot.h" +#include "talk/base/socket.h" +#include "talk/base/timeutils.h" + +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 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 { + PacketTime() : timestamp(-1), not_before(-1) {} + PacketTime(int64 timestamp, int64 not_before) + : timestamp(timestamp), not_before(not_before) { + } + + int64 timestamp; // Receive time after socket delivers the data. + int64 not_before; // Earliest possible time the data could have arrived, + // indicating the potential error in the |timestamp| value, + // in case the system, is busy. For example, the time of + // the last select() call. + // If unknown, this value will be set to zero. +}; + +inline PacketTime CreatePacketTime(int64 not_before) { + return PacketTime(TimeMicros(), not_before); +} + +// Provides the ability to receive packets asynchronously. Sends are not +// buffered since it is acceptable to drop packets under high load. +class AsyncPacketSocket : public sigslot::has_slots<> { + public: + enum State { + STATE_CLOSED, + STATE_BINDING, + STATE_BOUND, + STATE_CONNECTING, + STATE_CONNECTED + }; + + AsyncPacketSocket() { } + virtual ~AsyncPacketSocket() { } + + // Returns current local address. Address may be set to NULL if the + // socket is not bound yet (GetState() returns STATE_BINDING). + virtual SocketAddress GetLocalAddress() const = 0; + + // Returns remote address. Returns zeroes if this is not a client TCP socket. + virtual SocketAddress GetRemoteAddress() const = 0; + + // Send a packet. + 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, + const PacketOptions& options) = 0; + + // Close the socket. + virtual int Close() = 0; + + // Returns current state of the socket. + virtual State GetState() const = 0; + + // Get/set options. + virtual int GetOption(Socket::Option opt, int* value) = 0; + virtual int SetOption(Socket::Option opt, int value) = 0; + + // Get/Set current error. + // TODO: Remove SetError(). + virtual int GetError() const = 0; + virtual void SetError(int error) = 0; + + // Emitted each time a packet is read. Used only for UDP and + // connected TCP sockets. + sigslot::signal5 SignalReadPacket; + + // Emitted when the socket is currently able to send. + sigslot::signal1 SignalReadyToSend; + + // Emitted after address for the socket is allocated, i.e. binding + // is finished. State of the socket is changed from BINDING to BOUND + // (for UDP and server TCP sockets) or CONNECTING (for client TCP + // sockets). + sigslot::signal2 SignalAddressReady; + + // Emitted for client TCP sockets when state is changed from + // CONNECTING to CONNECTED. + sigslot::signal1 SignalConnect; + + // Emitted for client TCP sockets when state is changed from + // CONNECTED to CLOSED. + sigslot::signal2 SignalClose; + + // Used only for listening TCP sockets. + sigslot::signal2 SignalNewConnection; + + private: + DISALLOW_EVIL_CONSTRUCTORS(AsyncPacketSocket); +}; + +} // namespace talk_base + +#endif // TALK_BASE_ASYNCPACKETSOCKET_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/asyncresolverinterface.h b/thirdparties/common/include/webrtc-sdk/talk/base/asyncresolverinterface.h new file mode 100644 index 0000000..00d7691 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/asyncresolverinterface.h @@ -0,0 +1,64 @@ +/* + * 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_ASYNCRESOLVERINTERFACE_H_ +#define TALK_BASE_ASYNCRESOLVERINTERFACE_H_ + +#include "talk/base/sigslot.h" +#include "talk/base/socketaddress.h" + +namespace talk_base { + +// This interface defines the methods to resolve the address asynchronously. +class AsyncResolverInterface { + public: + AsyncResolverInterface() {} + virtual ~AsyncResolverInterface() {} + + // Start address resolve process. + virtual void Start(const SocketAddress& addr) = 0; + // Returns top most resolved address of |family| + virtual bool GetResolvedAddress(int family, SocketAddress* addr) const = 0; + // Returns error from resolver. + virtual int GetError() const = 0; + // Delete the resolver. + virtual void Destroy(bool wait) = 0; + // Returns top most resolved IPv4 address if address is resolved successfully. + // Otherwise returns address set in SetAddress. + SocketAddress address() const { + SocketAddress addr; + GetResolvedAddress(AF_INET, &addr); + return addr; + } + + // This signal is fired when address resolve process is completed. + sigslot::signal1 SignalDone; +}; + +} // namespace talk_base + +#endif diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/asyncsocket.h b/thirdparties/common/include/webrtc-sdk/talk/base/asyncsocket.h new file mode 100644 index 0000000..3655fbc --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/asyncsocket.h @@ -0,0 +1,141 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_ASYNCSOCKET_H_ +#define TALK_BASE_ASYNCSOCKET_H_ + +#include "talk/base/common.h" +#include "talk/base/sigslot.h" +#include "talk/base/socket.h" + +namespace talk_base { + +// TODO: Remove Socket and rename AsyncSocket to Socket. + +// Provides the ability to perform socket I/O asynchronously. +class AsyncSocket : public Socket { + public: + AsyncSocket(); + virtual ~AsyncSocket(); + + virtual AsyncSocket* Accept(SocketAddress* paddr) = 0; + + // SignalReadEvent and SignalWriteEvent use multi_threaded_local to allow + // access concurrently from different thread. + // For example SignalReadEvent::connect will be called in AsyncUDPSocket ctor + // but at the same time the SocketDispatcher maybe signaling the read event. + // ready to read + sigslot::signal1 SignalReadEvent; + // ready to write + sigslot::signal1 SignalWriteEvent; + sigslot::signal1 SignalConnectEvent; // connected + sigslot::signal2 SignalCloseEvent; // closed +}; + +class AsyncSocketAdapter : public AsyncSocket, public sigslot::has_slots<> { + public: + // The adapted socket may explicitly be NULL, and later assigned using Attach. + // However, subclasses which support detached mode must override any methods + // that will be called during the detached period (usually GetState()), to + // avoid dereferencing a null pointer. + explicit AsyncSocketAdapter(AsyncSocket* socket); + virtual ~AsyncSocketAdapter(); + void Attach(AsyncSocket* socket); + virtual SocketAddress GetLocalAddress() const { + return socket_->GetLocalAddress(); + } + virtual SocketAddress GetRemoteAddress() const { + return socket_->GetRemoteAddress(); + } + virtual int Bind(const SocketAddress& addr) { + return socket_->Bind(addr); + } + virtual int Connect(const SocketAddress& addr) { + return socket_->Connect(addr); + } + virtual int Send(const void* pv, size_t cb) { + return socket_->Send(pv, cb); + } + virtual int SendTo(const void* pv, size_t cb, const SocketAddress& addr) { + return socket_->SendTo(pv, cb, addr); + } + virtual int Recv(void* pv, size_t cb) { + return socket_->Recv(pv, cb); + } + virtual int RecvFrom(void* pv, size_t cb, SocketAddress* paddr) { + return socket_->RecvFrom(pv, cb, paddr); + } + virtual int Listen(int backlog) { + return socket_->Listen(backlog); + } + virtual AsyncSocket* Accept(SocketAddress* paddr) { + return socket_->Accept(paddr); + } + virtual int Close() { + return socket_->Close(); + } + virtual int GetError() const { + return socket_->GetError(); + } + virtual void SetError(int error) { + return socket_->SetError(error); + } + virtual ConnState GetState() const { + return socket_->GetState(); + } + virtual int EstimateMTU(uint16* mtu) { + return socket_->EstimateMTU(mtu); + } + virtual int GetOption(Option opt, int* value) { + return socket_->GetOption(opt, value); + } + virtual int SetOption(Option opt, int value) { + return socket_->SetOption(opt, value); + } + + protected: + virtual void OnConnectEvent(AsyncSocket* socket) { + SignalConnectEvent(this); + } + virtual void OnReadEvent(AsyncSocket* socket) { + SignalReadEvent(this); + } + virtual void OnWriteEvent(AsyncSocket* socket) { + SignalWriteEvent(this); + } + virtual void OnCloseEvent(AsyncSocket* socket, int err) { + SignalCloseEvent(this, err); + } + + AsyncSocket* socket_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_ASYNCSOCKET_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/asynctcpsocket.h b/thirdparties/common/include/webrtc-sdk/talk/base/asynctcpsocket.h new file mode 100644 index 0000000..0fb4828 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/asynctcpsocket.h @@ -0,0 +1,117 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_ASYNCTCPSOCKET_H_ +#define TALK_BASE_ASYNCTCPSOCKET_H_ + +#include "talk/base/asyncpacketsocket.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/socketfactory.h" + +namespace talk_base { + +// Simulates UDP semantics over TCP. Send and Recv packet sizes +// are preserved, and drops packets silently on Send, rather than +// buffer them in user space. +class AsyncTCPSocketBase : public AsyncPacketSocket { + public: + AsyncTCPSocketBase(AsyncSocket* socket, bool listen, size_t max_packet_size); + virtual ~AsyncTCPSocketBase(); + + // Pure virtual methods to send and recv data. + 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; + + virtual SocketAddress GetLocalAddress() const; + virtual SocketAddress GetRemoteAddress() const; + virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr, + const talk_base::PacketOptions& options); + virtual int Close(); + + virtual State GetState() const; + virtual int GetOption(Socket::Option opt, int* value); + virtual int SetOption(Socket::Option opt, int value); + virtual int GetError() const; + virtual void SetError(int error); + + protected: + // Binds and connects |socket| and creates AsyncTCPSocket for + // it. Takes ownership of |socket|. Returns NULL if bind() or + // connect() fail (|socket| is destroyed in that case). + static AsyncSocket* ConnectSocket(AsyncSocket* socket, + const SocketAddress& bind_address, + const SocketAddress& remote_address); + virtual int SendRaw(const void* pv, size_t cb); + int FlushOutBuffer(); + // Add data to |outbuf_|. + void AppendToOutBuffer(const void* pv, size_t cb); + + // Helper methods for |outpos_|. + bool IsOutBufferEmpty() const { return outpos_ == 0; } + void ClearOutBuffer() { outpos_ = 0; } + + private: + // Called by the underlying socket + void OnConnectEvent(AsyncSocket* socket); + void OnReadEvent(AsyncSocket* socket); + void OnWriteEvent(AsyncSocket* socket); + void OnCloseEvent(AsyncSocket* socket, int error); + + scoped_ptr socket_; + bool listen_; + char* inbuf_, * outbuf_; + size_t insize_, inpos_, outsize_, outpos_; + + DISALLOW_EVIL_CONSTRUCTORS(AsyncTCPSocketBase); +}; + +class AsyncTCPSocket : public AsyncTCPSocketBase { + public: + // Binds and connects |socket| and creates AsyncTCPSocket for + // it. Takes ownership of |socket|. Returns NULL if bind() or + // connect() fail (|socket| is destroyed in that case). + static AsyncTCPSocket* Create(AsyncSocket* socket, + const SocketAddress& bind_address, + const SocketAddress& remote_address); + AsyncTCPSocket(AsyncSocket* socket, bool listen); + virtual ~AsyncTCPSocket() {} + + 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); + + private: + DISALLOW_EVIL_CONSTRUCTORS(AsyncTCPSocket); +}; + +} // namespace talk_base + +#endif // TALK_BASE_ASYNCTCPSOCKET_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/asyncudpsocket.h b/thirdparties/common/include/webrtc-sdk/talk/base/asyncudpsocket.h new file mode 100644 index 0000000..eb9b3d2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/asyncudpsocket.h @@ -0,0 +1,80 @@ +/* + * 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 TALK_BASE_ASYNCUDPSOCKET_H_ +#define TALK_BASE_ASYNCUDPSOCKET_H_ + +#include "talk/base/asyncpacketsocket.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/socketfactory.h" + +namespace talk_base { + +// Provides the ability to receive packets asynchronously. Sends are not +// buffered since it is acceptable to drop packets under high load. +class AsyncUDPSocket : public AsyncPacketSocket { + public: + // Binds |socket| and creates AsyncUDPSocket for it. Takes ownership + // of |socket|. Returns NULL if bind() fails (|socket| is destroyed + // in that case). + static AsyncUDPSocket* Create(AsyncSocket* socket, + const SocketAddress& bind_address); + // Creates a new socket for sending asynchronous UDP packets using an + // asynchronous socket from the given factory. + static AsyncUDPSocket* Create(SocketFactory* factory, + const SocketAddress& bind_address); + explicit AsyncUDPSocket(AsyncSocket* socket); + virtual ~AsyncUDPSocket(); + + virtual SocketAddress GetLocalAddress() const; + virtual SocketAddress GetRemoteAddress() const; + 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, + const talk_base::PacketOptions& options); + virtual int Close(); + + virtual State GetState() const; + virtual int GetOption(Socket::Option opt, int* value); + virtual int SetOption(Socket::Option opt, int value); + virtual int GetError() const; + virtual void SetError(int error); + + private: + // Called when the underlying socket is ready to be read from. + void OnReadEvent(AsyncSocket* socket); + // Called when the underlying socket is ready to send. + void OnWriteEvent(AsyncSocket* socket); + + scoped_ptr socket_; + char* buf_; + size_t size_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_ASYNCUDPSOCKET_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/atomicops.h b/thirdparties/common/include/webrtc-sdk/talk/base/atomicops.h new file mode 100644 index 0000000..f7d7d6c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/atomicops.h @@ -0,0 +1,166 @@ +/* + * 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_BASE_ATOMICOPS_H_ +#define TALK_BASE_ATOMICOPS_H_ + +#include + +#include "talk/base/basictypes.h" +#include "talk/base/common.h" +#include "talk/base/logging.h" +#include "talk/base/scoped_ptr.h" + +namespace talk_base { + +// A single-producer, single-consumer, fixed-size queue. +// All methods not ending in Unsafe can be safely called without locking, +// provided that calls to consumer methods (Peek/Pop) or producer methods (Push) +// only happen on a single thread per method type. If multiple threads need to +// read simultaneously or write simultaneously, other synchronization is +// necessary. Synchronization is also required if a call into any Unsafe method +// could happen at the same time as a call to any other method. +template +class FixedSizeLockFreeQueue { + private: +// Atomic primitives and memory barrier +#if defined(__arm__) + typedef uint32 Atomic32; + + // Copied from google3/base/atomicops-internals-arm-v6plus.h + static inline void MemoryBarrier() { + asm volatile("dmb":::"memory"); + } + + // Adapted from google3/base/atomicops-internals-arm-v6plus.h + static inline void AtomicIncrement(volatile Atomic32* ptr) { + Atomic32 str_success, value; + asm volatile ( + "1:\n" + "ldrex %1, [%2]\n" + "add %1, %1, #1\n" + "strex %0, %1, [%2]\n" + "teq %0, #0\n" + "bne 1b" + : "=&r"(str_success), "=&r"(value) + : "r" (ptr) + : "cc", "memory"); + } +#elif !defined(SKIP_ATOMIC_CHECK) +#error "No atomic operations defined for the given architecture." +#endif + + public: + // Constructs an empty queue, with capacity 0. + FixedSizeLockFreeQueue() : pushed_count_(0), + popped_count_(0), + capacity_(0), + data_() {} + // Constructs an empty queue with the given capacity. + FixedSizeLockFreeQueue(size_t capacity) : pushed_count_(0), + popped_count_(0), + capacity_(capacity), + data_(new T[capacity]) {} + + // Pushes a value onto the queue. Returns true if the value was successfully + // pushed (there was space in the queue). This method can be safely called at + // the same time as PeekFront/PopFront. + bool PushBack(T value) { + if (capacity_ == 0) { + LOG(LS_WARNING) << "Queue capacity is 0."; + return false; + } + if (IsFull()) { + return false; + } + + data_[pushed_count_ % capacity_] = value; + // Make sure the data is written before the count is incremented, so other + // threads can't see the value exists before being able to read it. + MemoryBarrier(); + AtomicIncrement(&pushed_count_); + return true; + } + + // Retrieves the oldest value pushed onto the queue. Returns true if there was + // an item to peek (the queue was non-empty). This method can be safely called + // at the same time as PushBack. + bool PeekFront(T* value_out) { + if (capacity_ == 0) { + LOG(LS_WARNING) << "Queue capacity is 0."; + return false; + } + if (IsEmpty()) { + return false; + } + + *value_out = data_[popped_count_ % capacity_]; + return true; + } + + // Retrieves the oldest value pushed onto the queue and removes it from the + // queue. Returns true if there was an item to pop (the queue was non-empty). + // This method can be safely called at the same time as PushBack. + bool PopFront(T* value_out) { + if (PeekFront(value_out)) { + AtomicIncrement(&popped_count_); + return true; + } + return false; + } + + // Clears the current items in the queue and sets the new (fixed) size. This + // method cannot be called at the same time as any other method. + void ClearAndResizeUnsafe(int new_capacity) { + capacity_ = new_capacity; + data_.reset(new T[new_capacity]); + pushed_count_ = 0; + popped_count_ = 0; + } + + // Returns true if there is no space left in the queue for new elements. + int IsFull() const { return pushed_count_ == popped_count_ + capacity_; } + // Returns true if there are no elements in the queue. + int IsEmpty() const { return pushed_count_ == popped_count_; } + // Returns the current number of elements in the queue. This is always in the + // range [0, capacity] + size_t Size() const { return pushed_count_ - popped_count_; } + + // Returns the capacity of the queue (max size). + size_t capacity() const { return capacity_; } + + private: + volatile Atomic32 pushed_count_; + volatile Atomic32 popped_count_; + size_t capacity_; + talk_base::scoped_ptr data_; + DISALLOW_COPY_AND_ASSIGN(FixedSizeLockFreeQueue); +}; + +} + +#endif // TALK_BASE_ATOMICOPS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/autodetectproxy.h b/thirdparties/common/include/webrtc-sdk/talk/base/autodetectproxy.h new file mode 100644 index 0000000..a5b32c4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/autodetectproxy.h @@ -0,0 +1,107 @@ +/* + * 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 TALK_BASE_AUTODETECTPROXY_H_ +#define TALK_BASE_AUTODETECTPROXY_H_ + +#include + +#include "talk/base/constructormagic.h" +#include "talk/base/cryptstring.h" +#include "talk/base/proxydetect.h" +#include "talk/base/proxyinfo.h" +#include "talk/base/signalthread.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// AutoDetectProxy +/////////////////////////////////////////////////////////////////////////////// + +class AsyncResolverInterface; +class AsyncSocket; + +class AutoDetectProxy : public SignalThread { + public: + explicit AutoDetectProxy(const std::string& user_agent); + + const ProxyInfo& proxy() const { return proxy_; } + + void set_server_url(const std::string& url) { + server_url_ = url; + } + void set_proxy(const SocketAddress& proxy) { + proxy_.type = PROXY_UNKNOWN; + proxy_.address = proxy; + } + void set_auth_info(bool use_auth, const std::string& username, + const CryptString& password) { + if (use_auth) { + proxy_.username = username; + proxy_.password = password; + } + } + // Default implementation of GetProxySettingsForUrl. Override for special + // implementation. + virtual bool GetProxyForUrl(const char* agent, const char* url, + talk_base::ProxyInfo* proxy) { + return GetProxySettingsForUrl(agent, url, proxy, true); + } + enum { MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE, + MSG_UNRESOLVABLE, + ADP_MSG_FIRST_AVAILABLE}; + + protected: + virtual ~AutoDetectProxy(); + + // SignalThread Interface + virtual void DoWork(); + virtual void OnMessage(Message *msg); + + void Next(); + void Complete(ProxyType type); + + void OnConnectEvent(AsyncSocket * socket); + void OnReadEvent(AsyncSocket * socket); + void OnCloseEvent(AsyncSocket * socket, int error); + void OnResolveResult(AsyncResolverInterface* resolver); + bool DoConnect(); + + private: + std::string agent_; + std::string server_url_; + ProxyInfo proxy_; + AsyncResolverInterface* resolver_; + AsyncSocket* socket_; + int next_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(AutoDetectProxy); +}; + +} // namespace talk_base + +#endif // TALK_BASE_AUTODETECTPROXY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/bandwidthsmoother.h b/thirdparties/common/include/webrtc-sdk/talk/base/bandwidthsmoother.h new file mode 100644 index 0000000..a9887cc --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/bandwidthsmoother.h @@ -0,0 +1,76 @@ +/* + * 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_BASE_BANDWIDTHSMOOTHER_H_ +#define TALK_BASE_BANDWIDTHSMOOTHER_H_ + +#include "talk/base/rollingaccumulator.h" +#include "talk/base/timeutils.h" + +namespace talk_base { + +// The purpose of BandwidthSmoother is to smooth out bandwidth +// estimations so that 'trstate' messages can be triggered when we +// are "sure" there is sufficient bandwidth. To avoid frequent fluctuations, +// we take a slightly pessimistic view of our bandwidth. We only increase +// our estimation when we have sampled bandwidth measurements of values +// at least as large as the current estimation * percent_increase +// for at least time_between_increase time. If a sampled bandwidth +// is less than our current estimation we immediately decrease our estimation +// to that sampled value. +// We retain the initial bandwidth guess as our current bandwidth estimation +// until we have received (min_sample_count_percent * samples_count_to_average) +// number of samples. Min_sample_count_percent must be in range [0, 1]. +class BandwidthSmoother { + public: + BandwidthSmoother(int initial_bandwidth_guess, + uint32 time_between_increase, + double percent_increase, + size_t samples_count_to_average, + double min_sample_count_percent); + + // Samples a new bandwidth measurement. + // bandwidth is expected to be non-negative. + // returns true if the bandwidth estimation changed + bool Sample(uint32 sample_time, int bandwidth); + + int get_bandwidth_estimation() const { + return bandwidth_estimation_; + } + + private: + uint32 time_between_increase_; + double percent_increase_; + uint32 time_at_last_change_; + int bandwidth_estimation_; + RollingAccumulator accumulator_; + double min_sample_count_percent_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_BANDWIDTHSMOOTHER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/base64.h b/thirdparties/common/include/webrtc-sdk/talk/base/base64.h new file mode 100644 index 0000000..65b0260 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/base64.h @@ -0,0 +1,104 @@ + +//********************************************************************* +//* C_Base64 - a simple base64 encoder and decoder. +//* +//* Copyright (c) 1999, Bob Withers - bwit@pobox.com +//* +//* This code may be freely used for any purpose, either personal +//* or commercial, provided the authors copyright notice remains +//* intact. +//********************************************************************* + +#ifndef TALK_BASE_BASE64_H__ +#define TALK_BASE_BASE64_H__ + +#include +#include + +namespace talk_base { + +class Base64 +{ +public: + enum DecodeOption { + DO_PARSE_STRICT = 1, // Parse only base64 characters + DO_PARSE_WHITE = 2, // Parse only base64 and whitespace characters + DO_PARSE_ANY = 3, // Parse all characters + DO_PARSE_MASK = 3, + + DO_PAD_YES = 4, // Padding is required + DO_PAD_ANY = 8, // Padding is optional + DO_PAD_NO = 12, // Padding is disallowed + DO_PAD_MASK = 12, + + DO_TERM_BUFFER = 16, // Must termiante at end of buffer + DO_TERM_CHAR = 32, // May terminate at any character boundary + DO_TERM_ANY = 48, // May terminate at a sub-character bit offset + DO_TERM_MASK = 48, + + // Strictest interpretation + DO_STRICT = DO_PARSE_STRICT | DO_PAD_YES | DO_TERM_BUFFER, + + DO_LAX = DO_PARSE_ANY | DO_PAD_ANY | DO_TERM_CHAR, + }; + typedef int DecodeFlags; + + static bool IsBase64Char(char ch); + + // Get the char next to the |ch| from the Base64Table. + // If the |ch| is the last one in the Base64Table then returns + // the first one from the table. + // Expects the |ch| be a base64 char. + // The result will be saved in |next_ch|. + // Returns true on success. + static bool GetNextBase64Char(char ch, char* next_ch); + + // Determines whether the given string consists entirely of valid base64 + // encoded characters. + static bool IsBase64Encoded(const std::string& str); + + static void EncodeFromArray(const void* data, size_t len, + std::string* result); + static bool DecodeFromArray(const char* data, size_t len, DecodeFlags flags, + std::string* result, size_t* data_used); + static bool DecodeFromArray(const char* data, size_t len, DecodeFlags flags, + std::vector* result, size_t* data_used); + + // Convenience Methods + static inline std::string Encode(const std::string& data) { + std::string result; + EncodeFromArray(data.data(), data.size(), &result); + return result; + } + static inline std::string Decode(const std::string& data, DecodeFlags flags) { + std::string result; + DecodeFromArray(data.data(), data.size(), flags, &result, NULL); + return result; + } + static inline bool Decode(const std::string& data, DecodeFlags flags, + std::string* result, size_t* data_used) + { + return DecodeFromArray(data.data(), data.size(), flags, result, data_used); + } + static inline bool Decode(const std::string& data, DecodeFlags flags, + std::vector* result, size_t* data_used) + { + return DecodeFromArray(data.data(), data.size(), flags, result, data_used); + } + +private: + static const char Base64Table[]; + static const unsigned char DecodeTable[]; + + static size_t GetNextQuantum(DecodeFlags parse_flags, bool illegal_pads, + const char* data, size_t len, size_t* dpos, + unsigned char qbuf[4], bool* padded); + template + static bool DecodeFromArrayTemplate(const char* data, size_t len, + DecodeFlags flags, T* result, + size_t* data_used); +}; + +} // namespace talk_base + +#endif // TALK_BASE_BASE64_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/basicdefs.h b/thirdparties/common/include/webrtc-sdk/talk/base/basicdefs.h new file mode 100644 index 0000000..5731080 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/basicdefs.h @@ -0,0 +1,37 @@ +/* + * 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_BASE_BASICDEFS_H_ +#define TALK_BASE_BASICDEFS_H_ + +#if HAVE_CONFIG_H +#include "config.h" // NOLINT +#endif + +#define ARRAY_SIZE(x) (static_cast(sizeof(x) / sizeof(x[0]))) + +#endif // TALK_BASE_BASICDEFS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/basictypes.h b/thirdparties/common/include/webrtc-sdk/talk/base/basictypes.h new file mode 100644 index 0000000..db4754b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/basictypes.h @@ -0,0 +1,171 @@ +/* + * 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_BASE_BASICTYPES_H_ +#define TALK_BASE_BASICTYPES_H_ + +#include // for NULL, size_t + +#if !(defined(_MSC_VER) && (_MSC_VER < 1600)) +#include // for uintptr_t +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" // NOLINT +#endif + +#include "talk/base/constructormagic.h" + +#if !defined(INT_TYPES_DEFINED) +#define INT_TYPES_DEFINED +#ifdef COMPILER_MSVC +typedef unsigned __int64 uint64; +typedef __int64 int64; +#ifndef INT64_C +#define INT64_C(x) x ## I64 +#endif +#ifndef UINT64_C +#define UINT64_C(x) x ## UI64 +#endif +#define INT64_F "I64" +#else // COMPILER_MSVC +// On Mac OS X, cssmconfig.h defines uint64 as uint64_t +// TODO(fbarchard): Use long long for compatibility with chromium on BSD/OSX. +#if defined(OSX) +typedef uint64_t uint64; +typedef int64_t int64; +#ifndef INT64_C +#define INT64_C(x) x ## LL +#endif +#ifndef UINT64_C +#define UINT64_C(x) x ## ULL +#endif +#define INT64_F "l" +#elif defined(__LP64__) +typedef unsigned long uint64; // NOLINT +typedef long int64; // NOLINT +#ifndef INT64_C +#define INT64_C(x) x ## L +#endif +#ifndef UINT64_C +#define UINT64_C(x) x ## UL +#endif +#define INT64_F "l" +#else // __LP64__ +typedef unsigned long long uint64; // NOLINT +typedef long long int64; // NOLINT +#ifndef INT64_C +#define INT64_C(x) x ## LL +#endif +#ifndef UINT64_C +#define UINT64_C(x) x ## ULL +#endif +#define INT64_F "ll" +#endif // __LP64__ +#endif // COMPILER_MSVC +typedef unsigned int uint32; +typedef int int32; +typedef unsigned short uint16; // NOLINT +typedef short int16; // NOLINT +typedef unsigned char uint8; +typedef signed char int8; +#endif // INT_TYPES_DEFINED + +// Detect compiler is for x86 or x64. +#if defined(__x86_64__) || defined(_M_X64) || \ + defined(__i386__) || defined(_M_IX86) +#define CPU_X86 1 +#endif +// Detect compiler is for arm. +#if defined(__arm__) || defined(_M_ARM) +#define CPU_ARM 1 +#endif +#if defined(CPU_X86) && defined(CPU_ARM) +#error CPU_X86 and CPU_ARM both defined. +#endif +#if !defined(ARCH_CPU_BIG_ENDIAN) && !defined(ARCH_CPU_LITTLE_ENDIAN) +// x86, arm or GCC provided __BYTE_ORDER__ macros +#if CPU_X86 || CPU_ARM || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define ARCH_CPU_LITTLE_ENDIAN +#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define ARCH_CPU_BIG_ENDIAN +#else +#error ARCH_CPU_BIG_ENDIAN or ARCH_CPU_LITTLE_ENDIAN should be defined. +#endif +#endif +#if defined(ARCH_CPU_BIG_ENDIAN) && defined(ARCH_CPU_LITTLE_ENDIAN) +#error ARCH_CPU_BIG_ENDIAN and ARCH_CPU_LITTLE_ENDIAN both defined. +#endif + +#ifdef WIN32 +typedef int socklen_t; +#endif + +// The following only works for C++ +#ifdef __cplusplus +namespace talk_base { + template inline T _min(T a, T b) { return (a > b) ? b : a; } + template inline T _max(T a, T b) { return (a < b) ? b : a; } + + // For wait functions that take a number of milliseconds, kForever indicates + // unlimited time. + const int kForever = -1; +} + +#define ALIGNP(p, t) \ + (reinterpret_cast(((reinterpret_cast(p) + \ + ((t) - 1)) & ~((t) - 1)))) +#define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1))) + +// Note: UNUSED is also defined in common.h +#ifndef UNUSED +#define UNUSED(x) Unused(static_cast(&x)) +#define UNUSED2(x, y) Unused(static_cast(&x)); \ + Unused(static_cast(&y)) +#define UNUSED3(x, y, z) Unused(static_cast(&x)); \ + Unused(static_cast(&y)); \ + Unused(static_cast(&z)) +#define UNUSED4(x, y, z, a) Unused(static_cast(&x)); \ + Unused(static_cast(&y)); \ + Unused(static_cast(&z)); \ + Unused(static_cast(&a)) +#define UNUSED5(x, y, z, a, b) Unused(static_cast(&x)); \ + Unused(static_cast(&y)); \ + Unused(static_cast(&z)); \ + Unused(static_cast(&a)); \ + Unused(static_cast(&b)) +inline void Unused(const void*) {} +#endif // UNUSED + +// Use these to declare and define a static local variable (static T;) so that +// it is leaked so that its destructors are not called at exit. +#define LIBJINGLE_DEFINE_STATIC_LOCAL(type, name, arguments) \ + static type& name = *new type arguments + +#endif // __cplusplus +#endif // TALK_BASE_BASICTYPES_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/bind.h b/thirdparties/common/include/webrtc-sdk/talk/base/bind.h new file mode 100644 index 0000000..b8b92b8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/bind.h @@ -0,0 +1,604 @@ +// This file was GENERATED by command: +// pump.py bind.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 bind.h from bind.h.pump, execute: +// /home/build/google3/third_party/gtest/scripts/pump.py bind.h.pump + +// Bind() is an overloaded function that converts method calls into function +// objects (aka functors). It captures any arguments to the method by value +// when Bind is called, producing a stateful, nullary function object. Care +// should be taken about the lifetime of objects captured by Bind(); the +// returned functor knows nothing about the lifetime of the method's object or +// any arguments passed by pointer, and calling the functor with a destroyed +// object will surely do bad things. +// +// Example usage: +// struct Foo { +// int Test1() { return 42; } +// int Test2() const { return 52; } +// int Test3(int x) { return x*x; } +// float Test4(int x, float y) { return x + y; } +// }; +// +// int main() { +// Foo foo; +// cout << talk_base::Bind(&Foo::Test1, &foo)() << endl; +// cout << talk_base::Bind(&Foo::Test2, &foo)() << endl; +// cout << talk_base::Bind(&Foo::Test3, &foo, 3)() << endl; +// cout << talk_base::Bind(&Foo::Test4, &foo, 7, 8.5f)() << endl; +// } + +#ifndef TALK_BASE_BIND_H_ +#define TALK_BASE_BIND_H_ + +#define NONAME + +namespace talk_base { +namespace detail { +// This is needed because the template parameters in Bind can't be resolved +// if they're used both as parameters of the function pointer type and as +// parameters to Bind itself: the function pointer parameters are exact +// matches to the function prototype, but the parameters to bind have +// references stripped. This trick allows the compiler to dictate the Bind +// parameter types rather than deduce them. +template struct identity { typedef T type; }; +} // namespace detail + +template +class MethodFunctor0 { + public: + MethodFunctor0(MethodT method, ObjectT* object) + : method_(method), object_(object) {} + R operator()() const { + return (object_->*method_)(); } + private: + MethodT method_; + ObjectT* object_; +}; + +template +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 +MethodFunctor0 +Bind(FP_T(method), ObjectT* object) { + return MethodFunctor0( + method, object); +} + +#undef FP_T +#define FP_T(x) R (ObjectT::*x)() const + +template +MethodFunctor0 +Bind(FP_T(method), const ObjectT* object) { + return MethodFunctor0( + method, object); +} + +#undef FP_T +#define FP_T(x) R (*x)() + +template +Functor0 +Bind(FP_T(function)) { + return Functor0( + function); +} + +#undef FP_T + +template +class MethodFunctor1 { + public: + MethodFunctor1(MethodT method, ObjectT* object, + P1 p1) + : method_(method), object_(object), + p1_(p1) {} + R operator()() const { + return (object_->*method_)(p1_); } + private: + MethodT method_; + ObjectT* object_; + P1 p1_; +}; + +template +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 +MethodFunctor1 +Bind(FP_T(method), ObjectT* object, + typename detail::identity::type p1) { + return MethodFunctor1( + method, object, p1); +} + +#undef FP_T +#define FP_T(x) R (ObjectT::*x)(P1) const + +template +MethodFunctor1 +Bind(FP_T(method), const ObjectT* object, + typename detail::identity::type p1) { + return MethodFunctor1( + method, object, p1); +} + +#undef FP_T +#define FP_T(x) R (*x)(P1) + +template +Functor1 +Bind(FP_T(function), + typename detail::identity::type p1) { + return Functor1( + function, p1); +} + +#undef FP_T + +template +class MethodFunctor2 { + public: + MethodFunctor2(MethodT method, ObjectT* object, + P1 p1, + P2 p2) + : method_(method), object_(object), + p1_(p1), + p2_(p2) {} + R operator()() const { + return (object_->*method_)(p1_, p2_); } + private: + MethodT method_; + ObjectT* object_; + P1 p1_; + P2 p2_; +}; + +template +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 +MethodFunctor2 +Bind(FP_T(method), ObjectT* object, + typename detail::identity::type p1, + typename detail::identity::type p2) { + return MethodFunctor2( + method, object, p1, p2); +} + +#undef FP_T +#define FP_T(x) R (ObjectT::*x)(P1, P2) const + +template +MethodFunctor2 +Bind(FP_T(method), const ObjectT* object, + typename detail::identity::type p1, + typename detail::identity::type p2) { + return MethodFunctor2( + method, object, p1, p2); +} + +#undef FP_T +#define FP_T(x) R (*x)(P1, P2) + +template +Functor2 +Bind(FP_T(function), + typename detail::identity::type p1, + typename detail::identity::type p2) { + return Functor2( + function, p1, p2); +} + +#undef FP_T + +template +class MethodFunctor3 { + public: + MethodFunctor3(MethodT method, ObjectT* object, + P1 p1, + P2 p2, + P3 p3) + : method_(method), object_(object), + p1_(p1), + p2_(p2), + p3_(p3) {} + R operator()() const { + return (object_->*method_)(p1_, p2_, p3_); } + private: + MethodT method_; + ObjectT* object_; + P1 p1_; + P2 p2_; + P3 p3_; +}; + +template +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 +MethodFunctor3 +Bind(FP_T(method), ObjectT* object, + typename detail::identity::type p1, + typename detail::identity::type p2, + typename detail::identity::type p3) { + return MethodFunctor3( + method, object, p1, p2, p3); +} + +#undef FP_T +#define FP_T(x) R (ObjectT::*x)(P1, P2, P3) const + +template +MethodFunctor3 +Bind(FP_T(method), const ObjectT* object, + typename detail::identity::type p1, + typename detail::identity::type p2, + typename detail::identity::type p3) { + return MethodFunctor3( + method, object, p1, p2, p3); +} + +#undef FP_T +#define FP_T(x) R (*x)(P1, P2, P3) + +template +Functor3 +Bind(FP_T(function), + typename detail::identity::type p1, + typename detail::identity::type p2, + typename detail::identity::type p3) { + return Functor3( + function, p1, p2, p3); +} + +#undef FP_T + +template +class MethodFunctor4 { + public: + MethodFunctor4(MethodT method, ObjectT* object, + P1 p1, + P2 p2, + P3 p3, + P4 p4) + : method_(method), object_(object), + p1_(p1), + p2_(p2), + p3_(p3), + p4_(p4) {} + R operator()() const { + return (object_->*method_)(p1_, p2_, p3_, p4_); } + private: + MethodT method_; + ObjectT* object_; + P1 p1_; + P2 p2_; + P3 p3_; + P4 p4_; +}; + +template +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 +MethodFunctor4 +Bind(FP_T(method), ObjectT* object, + typename detail::identity::type p1, + typename detail::identity::type p2, + typename detail::identity::type p3, + typename detail::identity::type p4) { + return MethodFunctor4( + method, object, p1, p2, p3, p4); +} + +#undef FP_T +#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4) const + +template +MethodFunctor4 +Bind(FP_T(method), const ObjectT* object, + typename detail::identity::type p1, + typename detail::identity::type p2, + typename detail::identity::type p3, + typename detail::identity::type p4) { + return MethodFunctor4( + method, object, p1, p2, p3, p4); +} + +#undef FP_T +#define FP_T(x) R (*x)(P1, P2, P3, P4) + +template +Functor4 +Bind(FP_T(function), + typename detail::identity::type p1, + typename detail::identity::type p2, + typename detail::identity::type p3, + typename detail::identity::type p4) { + return Functor4( + function, p1, p2, p3, p4); +} + +#undef FP_T + +template +class MethodFunctor5 { + public: + MethodFunctor5(MethodT method, ObjectT* object, + P1 p1, + P2 p2, + P3 p3, + P4 p4, + P5 p5) + : method_(method), object_(object), + p1_(p1), + p2_(p2), + p3_(p3), + p4_(p4), + p5_(p5) {} + R operator()() const { + return (object_->*method_)(p1_, p2_, p3_, p4_, p5_); } + private: + MethodT method_; + ObjectT* object_; + P1 p1_; + P2 p2_; + P3 p3_; + P4 p4_; + P5 p5_; +}; + +template +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 +MethodFunctor5 +Bind(FP_T(method), ObjectT* object, + typename detail::identity::type p1, + typename detail::identity::type p2, + typename detail::identity::type p3, + typename detail::identity::type p4, + typename detail::identity::type p5) { + return MethodFunctor5( + method, object, p1, p2, p3, p4, p5); +} + +#undef FP_T +#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4, P5) const + +template +MethodFunctor5 +Bind(FP_T(method), const ObjectT* object, + typename detail::identity::type p1, + typename detail::identity::type p2, + typename detail::identity::type p3, + typename detail::identity::type p4, + typename detail::identity::type p5) { + return MethodFunctor5( + method, object, p1, p2, p3, p4, p5); +} + +#undef FP_T +#define FP_T(x) R (*x)(P1, P2, P3, P4, P5) + +template +Functor5 +Bind(FP_T(function), + typename detail::identity::type p1, + typename detail::identity::type p2, + typename detail::identity::type p3, + typename detail::identity::type p4, + typename detail::identity::type p5) { + return Functor5( + function, p1, p2, p3, p4, p5); +} + +#undef FP_T + +} // namespace talk_base + +#undef NONAME + +#endif // TALK_BASE_BIND_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/buffer.h b/thirdparties/common/include/webrtc-sdk/talk/base/buffer.h new file mode 100644 index 0000000..6866005 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/buffer.h @@ -0,0 +1,119 @@ +/* + * libjingle + * Copyright 2004-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. + */ + +#ifndef TALK_BASE_BUFFER_H_ +#define TALK_BASE_BUFFER_H_ + +#include + +#include "talk/base/scoped_ptr.h" + +namespace talk_base { + +// Basic buffer class, can be grown and shrunk dynamically. +// Unlike std::string/vector, does not initialize data when expanding capacity. +class Buffer { + public: + Buffer() { + Construct(NULL, 0, 0); + } + Buffer(const void* data, size_t length) { + Construct(data, length, length); + } + Buffer(const void* data, size_t length, size_t capacity) { + Construct(data, length, capacity); + } + Buffer(const Buffer& buf) { + Construct(buf.data(), buf.length(), buf.length()); + } + + const char* data() const { return data_.get(); } + char* data() { return data_.get(); } + // TODO: should this be size(), like STL? + size_t length() const { return length_; } + size_t capacity() const { return capacity_; } + + Buffer& operator=(const Buffer& buf) { + if (&buf != this) { + Construct(buf.data(), buf.length(), buf.length()); + } + return *this; + } + bool operator==(const Buffer& buf) const { + return (length_ == buf.length() && + memcmp(data_.get(), buf.data(), length_) == 0); + } + bool operator!=(const Buffer& buf) const { + return !operator==(buf); + } + + void SetData(const void* data, size_t length) { + ASSERT(data != NULL || length == 0); + SetLength(length); + memcpy(data_.get(), data, length); + } + void AppendData(const void* data, size_t length) { + ASSERT(data != NULL || length == 0); + size_t old_length = length_; + SetLength(length_ + length); + memcpy(data_.get() + old_length, data, length); + } + void SetLength(size_t length) { + SetCapacity(length); + length_ = length; + } + void SetCapacity(size_t capacity) { + if (capacity > capacity_) { + talk_base::scoped_ptr data(new char[capacity]); + memcpy(data.get(), data_.get(), length_); + data_.swap(data); + capacity_ = capacity; + } + } + + void TransferTo(Buffer* buf) { + ASSERT(buf != NULL); + buf->data_.reset(data_.release()); + buf->length_ = length_; + buf->capacity_ = capacity_; + Construct(NULL, 0, 0); + } + + protected: + void Construct(const void* data, size_t length, size_t capacity) { + data_.reset(new char[capacity_ = capacity]); + SetData(data, length); + } + + scoped_ptr data_; + size_t length_; + size_t capacity_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_BUFFER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/bytebuffer.h b/thirdparties/common/include/webrtc-sdk/talk/base/bytebuffer.h new file mode 100644 index 0000000..22b80e0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/bytebuffer.h @@ -0,0 +1,136 @@ +/* + * 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 TALK_BASE_BYTEBUFFER_H_ +#define TALK_BASE_BYTEBUFFER_H_ + +#include + +#include "talk/base/basictypes.h" +#include "talk/base/constructormagic.h" + +namespace talk_base { + +class ByteBuffer { + public: + + enum ByteOrder { + ORDER_NETWORK = 0, // Default, use network byte order (big endian). + ORDER_HOST, // Use the native order of the host. + }; + + // |byte_order| defines order of bytes in the buffer. + ByteBuffer(); + explicit ByteBuffer(ByteOrder byte_order); + ByteBuffer(const char* bytes, size_t len); + ByteBuffer(const char* bytes, size_t len, ByteOrder byte_order); + + // Initializes buffer from a zero-terminated string. + explicit ByteBuffer(const char* bytes); + + ~ByteBuffer(); + + const char* Data() const { return bytes_ + start_; } + size_t Length() const { return end_ - start_; } + size_t Capacity() const { return size_ - start_; } + ByteOrder Order() const { return byte_order_; } + + // Read a next value from the buffer. Return false if there isn't + // enough data left for the specified type. + bool ReadUInt8(uint8* val); + bool ReadUInt16(uint16* val); + bool ReadUInt24(uint32* val); + bool ReadUInt32(uint32* val); + bool ReadUInt64(uint64* val); + bool ReadBytes(char* val, size_t len); + + // Appends next |len| bytes from the buffer to |val|. Returns false + // if there is less than |len| bytes left. + bool ReadString(std::string* val, size_t len); + + // Write value to the buffer. Resizes the buffer when it is + // neccessary. + void WriteUInt8(uint8 val); + void WriteUInt16(uint16 val); + void WriteUInt24(uint32 val); + void WriteUInt32(uint32 val); + void WriteUInt64(uint64 val); + void WriteString(const std::string& val); + void WriteBytes(const char* val, size_t len); + + // Reserves the given number of bytes and returns a char* that can be written + // into. Useful for functions that require a char* buffer and not a + // ByteBuffer. + char* ReserveWriteBuffer(size_t len); + + // Resize the buffer to the specified |size|. This invalidates any remembered + // seek positions. + void Resize(size_t size); + + // Moves current position |size| bytes forward. Returns false if + // there is less than |size| bytes left in the buffer. Consume doesn't + // permanently remove data, so remembered read positions are still valid + // after this call. + bool Consume(size_t size); + + // Clears the contents of the buffer. After this, Length() will be 0. + void Clear(); + + // Used with GetReadPosition/SetReadPosition. + class ReadPosition { + friend class ByteBuffer; + ReadPosition(size_t start, int version) + : start_(start), version_(version) { } + size_t start_; + int version_; + }; + + // Remembers the current read position for a future SetReadPosition. Any + // calls to Shift or Resize in the interim will invalidate the position. + ReadPosition GetReadPosition() const; + + // If the given position is still valid, restores that read position. + bool SetReadPosition(const ReadPosition &position); + + private: + void Construct(const char* bytes, size_t size, ByteOrder byte_order); + + char* bytes_; + size_t size_; + size_t start_; + size_t end_; + int version_; + ByteOrder byte_order_; + + // There are sensible ways to define these, but they aren't needed in our code + // base. + DISALLOW_COPY_AND_ASSIGN(ByteBuffer); +}; + +} // namespace talk_base + +#endif // TALK_BASE_BYTEBUFFER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/byteorder.h b/thirdparties/common/include/webrtc-sdk/talk/base/byteorder.h new file mode 100644 index 0000000..8d57c01 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/byteorder.h @@ -0,0 +1,185 @@ +/* + * 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_BASE_BYTEORDER_H_ +#define TALK_BASE_BYTEORDER_H_ + +#if defined(POSIX) && !defined(__native_client__) +#include +#endif + +#ifdef WIN32 +#include +#endif + +#include "talk/base/basictypes.h" + +namespace talk_base { + +// Reading and writing of little and big-endian numbers from memory +// TODO: Optimized versions, with direct read/writes of +// integers in host-endian format, when the platform supports it. + +inline void Set8(void* memory, size_t offset, uint8 v) { + static_cast(memory)[offset] = v; +} + +inline uint8 Get8(const void* memory, size_t offset) { + return static_cast(memory)[offset]; +} + +inline void SetBE16(void* memory, uint16 v) { + Set8(memory, 0, static_cast(v >> 8)); + Set8(memory, 1, static_cast(v >> 0)); +} + +inline void SetBE32(void* memory, uint32 v) { + Set8(memory, 0, static_cast(v >> 24)); + Set8(memory, 1, static_cast(v >> 16)); + Set8(memory, 2, static_cast(v >> 8)); + Set8(memory, 3, static_cast(v >> 0)); +} + +inline void SetBE64(void* memory, uint64 v) { + Set8(memory, 0, static_cast(v >> 56)); + Set8(memory, 1, static_cast(v >> 48)); + Set8(memory, 2, static_cast(v >> 40)); + Set8(memory, 3, static_cast(v >> 32)); + Set8(memory, 4, static_cast(v >> 24)); + Set8(memory, 5, static_cast(v >> 16)); + Set8(memory, 6, static_cast(v >> 8)); + Set8(memory, 7, static_cast(v >> 0)); +} + +inline uint16 GetBE16(const void* memory) { + return static_cast((Get8(memory, 0) << 8) | + (Get8(memory, 1) << 0)); +} + +inline uint32 GetBE32(const void* memory) { + return (static_cast(Get8(memory, 0)) << 24) | + (static_cast(Get8(memory, 1)) << 16) | + (static_cast(Get8(memory, 2)) << 8) | + (static_cast(Get8(memory, 3)) << 0); +} + +inline uint64 GetBE64(const void* memory) { + return (static_cast(Get8(memory, 0)) << 56) | + (static_cast(Get8(memory, 1)) << 48) | + (static_cast(Get8(memory, 2)) << 40) | + (static_cast(Get8(memory, 3)) << 32) | + (static_cast(Get8(memory, 4)) << 24) | + (static_cast(Get8(memory, 5)) << 16) | + (static_cast(Get8(memory, 6)) << 8) | + (static_cast(Get8(memory, 7)) << 0); +} + +inline void SetLE16(void* memory, uint16 v) { + Set8(memory, 0, static_cast(v >> 0)); + Set8(memory, 1, static_cast(v >> 8)); +} + +inline void SetLE32(void* memory, uint32 v) { + Set8(memory, 0, static_cast(v >> 0)); + Set8(memory, 1, static_cast(v >> 8)); + Set8(memory, 2, static_cast(v >> 16)); + Set8(memory, 3, static_cast(v >> 24)); +} + +inline void SetLE64(void* memory, uint64 v) { + Set8(memory, 0, static_cast(v >> 0)); + Set8(memory, 1, static_cast(v >> 8)); + Set8(memory, 2, static_cast(v >> 16)); + Set8(memory, 3, static_cast(v >> 24)); + Set8(memory, 4, static_cast(v >> 32)); + Set8(memory, 5, static_cast(v >> 40)); + Set8(memory, 6, static_cast(v >> 48)); + Set8(memory, 7, static_cast(v >> 56)); +} + +inline uint16 GetLE16(const void* memory) { + return static_cast((Get8(memory, 0) << 0) | + (Get8(memory, 1) << 8)); +} + +inline uint32 GetLE32(const void* memory) { + return (static_cast(Get8(memory, 0)) << 0) | + (static_cast(Get8(memory, 1)) << 8) | + (static_cast(Get8(memory, 2)) << 16) | + (static_cast(Get8(memory, 3)) << 24); +} + +inline uint64 GetLE64(const void* memory) { + return (static_cast(Get8(memory, 0)) << 0) | + (static_cast(Get8(memory, 1)) << 8) | + (static_cast(Get8(memory, 2)) << 16) | + (static_cast(Get8(memory, 3)) << 24) | + (static_cast(Get8(memory, 4)) << 32) | + (static_cast(Get8(memory, 5)) << 40) | + (static_cast(Get8(memory, 6)) << 48) | + (static_cast(Get8(memory, 7)) << 56); +} + +// Check if the current host is big endian. +inline bool IsHostBigEndian() { + static const int number = 1; + return 0 == *reinterpret_cast(&number); +} + +inline uint16 HostToNetwork16(uint16 n) { + uint16 result; + SetBE16(&result, n); + return result; +} + +inline uint32 HostToNetwork32(uint32 n) { + uint32 result; + SetBE32(&result, n); + return result; +} + +inline uint64 HostToNetwork64(uint64 n) { + uint64 result; + SetBE64(&result, n); + return result; +} + +inline uint16 NetworkToHost16(uint16 n) { + return GetBE16(&n); +} + +inline uint32 NetworkToHost32(uint32 n) { + return GetBE32(&n); +} + +inline uint64 NetworkToHost64(uint64 n) { + return GetBE64(&n); +} + +} // namespace talk_base + +#endif // TALK_BASE_BYTEORDER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/callback.h b/thirdparties/common/include/webrtc-sdk/talk/base/callback.h new file mode 100644 index 0000000..cd3daf5 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/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 +// 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 my_callback; +// cout << my_callback.empty() << endl; // true +// +// my_callback = Callback1(&sqr); +// cout << my_callback.empty() << endl; // false +// cout << my_callback(3) << endl; // 9 +// +// my_callback = Callback1(add_k); +// cout << my_callback(10) << endl; // 15 +// +// my_callback = Callback1(); +// 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 Callback0 { + public: + // Default copy operations are appropriate for this class. + Callback0() {} + template Callback0(const T& functor) + : helper_(new RefCountedObject< HelperImpl >(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 struct HelperImpl : Helper { + explicit HelperImpl(const T& functor) : functor_(functor) {} + virtual R Run() { + return functor_(); + } + T functor_; + }; + scoped_refptr helper_; +}; + +template +class Callback1 { + public: + // Default copy operations are appropriate for this class. + Callback1() {} + template Callback1(const T& functor) + : helper_(new RefCountedObject< HelperImpl >(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 struct HelperImpl : Helper { + explicit HelperImpl(const T& functor) : functor_(functor) {} + virtual R Run(P1 p1) { + return functor_(p1); + } + T functor_; + }; + scoped_refptr helper_; +}; + +template +class Callback2 { + public: + // Default copy operations are appropriate for this class. + Callback2() {} + template Callback2(const T& functor) + : helper_(new RefCountedObject< HelperImpl >(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 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_; +}; + +template +class Callback3 { + public: + // Default copy operations are appropriate for this class. + Callback3() {} + template Callback3(const T& functor) + : helper_(new RefCountedObject< HelperImpl >(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 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_; +}; + +template +class Callback4 { + public: + // Default copy operations are appropriate for this class. + Callback4() {} + template Callback4(const T& functor) + : helper_(new RefCountedObject< HelperImpl >(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 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_; +}; + +template +class Callback5 { + public: + // Default copy operations are appropriate for this class. + Callback5() {} + template Callback5(const T& functor) + : helper_(new RefCountedObject< HelperImpl >(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 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_; +}; +} // namespace talk_base + +#endif // TALK_BASE_CALLBACK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/checks.h b/thirdparties/common/include/webrtc-sdk/talk/base/checks.h new file mode 100644 index 0000000..382e4a0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/checks.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +// This module contains some basic debugging facilities. +// Originally comes from shared/commandlineflags/checks.h + +#ifndef TALK_BASE_CHECKS_H_ +#define TALK_BASE_CHECKS_H_ + +#include + +// Prints an error message to stderr and aborts execution. +void Fatal(const char* file, int line, const char* format, ...); + + +// The UNREACHABLE macro is very useful during development. +#define UNREACHABLE() \ + Fatal(__FILE__, __LINE__, "unreachable code") + +#endif // TALK_BASE_CHECKS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/common.h b/thirdparties/common/include/webrtc-sdk/talk/base/common.h new file mode 100644 index 0000000..4158ac2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/common.h @@ -0,0 +1,218 @@ +/* + * 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_BASE_COMMON_H_ // NOLINT +#define TALK_BASE_COMMON_H_ + +#include "talk/base/basictypes.h" +#include "talk/base/constructormagic.h" + +#if defined(_MSC_VER) +// warning C4355: 'this' : used in base member initializer list +#pragma warning(disable:4355) +#endif + +////////////////////////////////////////////////////////////////////// +// General Utilities +////////////////////////////////////////////////////////////////////// + +// Note: UNUSED is also defined in basictypes.h +#ifndef UNUSED +#define UNUSED(x) Unused(static_cast(&x)) +#define UNUSED2(x, y) Unused(static_cast(&x)); \ + Unused(static_cast(&y)) +#define UNUSED3(x, y, z) Unused(static_cast(&x)); \ + Unused(static_cast(&y)); \ + Unused(static_cast(&z)) +#define UNUSED4(x, y, z, a) Unused(static_cast(&x)); \ + Unused(static_cast(&y)); \ + Unused(static_cast(&z)); \ + Unused(static_cast(&a)) +#define UNUSED5(x, y, z, a, b) Unused(static_cast(&x)); \ + Unused(static_cast(&y)); \ + Unused(static_cast(&z)); \ + Unused(static_cast(&a)); \ + Unused(static_cast(&b)) +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 . +#define stdmax(x, y) std::max(x, y) +#else +#define stdmax(x, y) talk_base::_max(x, y) +#endif + +#define ARRAY_SIZE(x) (static_cast(sizeof(x) / sizeof(x[0]))) + +///////////////////////////////////////////////////////////////////////////// +// Assertions +///////////////////////////////////////////////////////////////////////////// + +#ifndef ENABLE_DEBUG +#define ENABLE_DEBUG _DEBUG +#endif // !defined(ENABLE_DEBUG) + +// Even for release builds, allow for the override of LogAssert. Though no +// macro is provided, this can still be used for explicit runtime asserts +// and allow applications to override the assert behavior. + +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.). +void LogAssert(const char* function, const char* file, int line, + const char* expression); + +typedef void (*AssertLogger)(const char* function, + const char* file, + int line, + const char* expression); + +// Sets a custom assert logger to be used instead of the default LogAssert +// behavior. To clear the custom assert logger, pass NULL for |logger| and the +// default behavior will be restored. Only one custom assert logger can be set +// at a time, so this should generally be set during application startup and +// only by one component. +void SetCustomAssertLogger(AssertLogger logger); + +} // namespace talk_base + +#if ENABLE_DEBUG + +namespace talk_base { + +inline bool Assert(bool result, const char* function, const char* file, + int line, const char* expression) { + if (!result) { + LogAssert(function, file, line, expression); + Break(); + return false; + } + return true; +} + +} // namespace talk_base + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#define __FUNCTION__ "" +#endif + +#ifndef ASSERT +#define ASSERT(x) \ + (void)talk_base::Assert((x), __FUNCTION__, __FILE__, __LINE__, #x) +#endif + +#ifndef VERIFY +#define VERIFY(x) talk_base::Assert((x), __FUNCTION__, __FILE__, __LINE__, #x) +#endif + +#else // !ENABLE_DEBUG + +namespace talk_base { + +inline bool ImplicitCastToBool(bool result) { return result; } + +} // namespace talk_base + +#ifndef ASSERT +#define ASSERT(x) (void)0 +#endif + +#ifndef VERIFY +#define VERIFY(x) talk_base::ImplicitCastToBool(x) +#endif + +#endif // !ENABLE_DEBUG + +#define COMPILE_TIME_ASSERT(expr) char CTA_UNIQUE_NAME[expr] +#define CTA_UNIQUE_NAME CTA_MAKE_NAME(__LINE__) +#define CTA_MAKE_NAME(line) CTA_MAKE_NAME2(line) +#define CTA_MAKE_NAME2(line) constraint_ ## line + +// Forces compiler to inline, even against its better judgement. Use wisely. +#if defined(__GNUC__) +#define FORCE_INLINE __attribute__((always_inline)) +#elif defined(WIN32) +#define FORCE_INLINE __forceinline +#else +#define FORCE_INLINE +#endif + +// Borrowed from Chromium's base/compiler_specific.h. +// Annotate a virtual method indicating it must be overriding a virtual +// method in the parent class. +// Use like: +// virtual void foo() OVERRIDE; +#if defined(WIN32) +#define OVERRIDE override +#elif defined(__clang__) +// Clang defaults to C++03 and warns about using override. Squelch that. +// Intentionally no push/pop here so all users of OVERRIDE ignore the warning +// too. This is like passing -Wno-c++11-extensions, except that GCC won't die +// (because it won't see this pragma). +#pragma clang diagnostic ignored "-Wc++11-extensions" +#define OVERRIDE override +#elif defined(__GNUC__) && __cplusplus >= 201103 && \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40700 +// GCC 4.7 supports explicit virtual overrides when C++11 support is enabled. +#define OVERRIDE override +#else +#define OVERRIDE +#endif + +// Annotate a function indicating the caller must examine the return value. +// Use like: +// int foo() WARN_UNUSED_RESULT; +// To explicitly ignore a result, see |ignore_result()| in . +// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and +// libjingle are merged. +#if !defined(WARN_UNUSED_RESULT) +#if defined(__GNUC__) +#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define WARN_UNUSED_RESULT +#endif +#endif // WARN_UNUSED_RESULT + +#endif // TALK_BASE_COMMON_H_ // NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/compile_assert.h b/thirdparties/common/include/webrtc-sdk/talk/base/compile_assert.h new file mode 100644 index 0000000..bb8227a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/compile_assert.h @@ -0,0 +1,99 @@ +/* + * 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. + */ + +// COMPILE_ASSERT macro, borrowed from google3/base/macros.h. +#ifndef TALK_BASE_COMPILE_ASSERT_H_ +#define TALK_BASE_COMPILE_ASSERT_H_ + +// The COMPILE_ASSERT macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and +// libjingle are merged. +#if !defined(COMPILE_ASSERT) +template +struct CompileAssert { +}; + +#define COMPILE_ASSERT(expr, msg) \ + typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] // NOLINT +#endif // COMPILE_ASSERT + +// Implementation details of COMPILE_ASSERT: +// +// - COMPILE_ASSERT works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outer parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// COMPILE_ASSERT(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +#endif // TALK_BASE_COMPILE_ASSERT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/constructormagic.h b/thirdparties/common/include/webrtc-sdk/talk/base/constructormagic.h new file mode 100644 index 0000000..15a240f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/constructormagic.h @@ -0,0 +1,58 @@ +/* + * 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 TALK_BASE_CONSTRUCTORMAGIC_H_ +#define TALK_BASE_CONSTRUCTORMAGIC_H_ + +#define DISALLOW_ASSIGN(TypeName) \ + void operator=(const TypeName&) + +// A macro to disallow the evil copy constructor and operator= functions +// This should be used in the private: declarations for a class. +// Undefine this, just in case. Some third-party includes have their own +// version. +#undef DISALLOW_COPY_AND_ASSIGN +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + DISALLOW_ASSIGN(TypeName) + +// Alternative, less-accurate legacy name. +#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \ + DISALLOW_COPY_AND_ASSIGN(TypeName) + +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// +// This should be used in the private: declarations for a class +// that wants to prevent anyone from instantiating it. This is +// especially useful for classes containing only static methods. +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName(); \ + DISALLOW_EVIL_CONSTRUCTORS(TypeName) + + +#endif // TALK_BASE_CONSTRUCTORMAGIC_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/cpumonitor.h b/thirdparties/common/include/webrtc-sdk/talk/base/cpumonitor.h new file mode 100644 index 0000000..8c0ec22 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/cpumonitor.h @@ -0,0 +1,140 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_CPUMONITOR_H_ +#define TALK_BASE_CPUMONITOR_H_ + +#include "talk/base/basictypes.h" +#include "talk/base/messagehandler.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sigslot.h" +#if defined(LINUX) || defined(ANDROID) +#include "talk/base/stream.h" +#endif // defined(LINUX) || defined(ANDROID) + +namespace talk_base { +class Thread; +class SystemInfo; + +struct CpuStats { + CpuStats() + : prev_total_times_(0), + prev_cpu_times_(0), + prev_load_(0.f), + prev_load_time_(0u) { + } + + uint64 prev_total_times_; + uint64 prev_cpu_times_; + float prev_load_; // Previous load value. + uint32 prev_load_time_; // Time previous load value was taken. +}; + +// CpuSampler samples the process and system load. +class CpuSampler { + public: + CpuSampler(); + ~CpuSampler(); + + // Initialize CpuSampler. Returns true if successful. + bool Init(); + + // Set minimum interval in ms between computing new load values. + // Default 950 ms. Set to 0 to disable interval. + void set_load_interval(int min_load_interval); + + // Return CPU load of current process as a float from 0 to 1. + float GetProcessLoad(); + + // Return CPU load of current process as a float from 0 to 1. + float GetSystemLoad(); + + // Return number of cpus. Includes hyperthreads. + int GetMaxCpus() const; + + // Return current number of cpus available to this process. + int GetCurrentCpus(); + + // For testing. Allows forcing of fallback to using NTDLL functions. + void set_force_fallback(bool fallback) { +#ifdef WIN32 + force_fallback_ = fallback; +#endif + } + + private: + float UpdateCpuLoad(uint64 current_total_times, + uint64 current_cpu_times, + uint64 *prev_total_times, + uint64 *prev_cpu_times); + CpuStats process_; + CpuStats system_; + int cpus_; + int min_load_interval_; // Minimum time between computing new load. + scoped_ptr sysinfo_; +#ifdef WIN32 + void* get_system_times_; + void* nt_query_system_information_; + bool force_fallback_; +#endif +#if defined(LINUX) || defined(ANDROID) + // File for reading /proc/stat + scoped_ptr sfile_; +#endif // defined(LINUX) || defined(ANDROID) +}; + +// CpuMonitor samples and signals the CPU load periodically. +class CpuMonitor + : public talk_base::MessageHandler, public sigslot::has_slots<> { + public: + explicit CpuMonitor(Thread* thread); + virtual ~CpuMonitor(); + void set_thread(Thread* thread); + + bool Start(int period_ms); + void Stop(); + // Signal parameters are current cpus, max cpus, process load and system load. + sigslot::signal4 SignalUpdate; + + protected: + // Override virtual method of parent MessageHandler. + virtual void OnMessage(talk_base::Message* msg); + // Clear the monitor thread and stop sending it messages if the thread goes + // away before our lifetime. + void OnMessageQueueDestroyed() { monitor_thread_ = NULL; } + + private: + Thread* monitor_thread_; + CpuSampler sampler_; + int period_ms_; + + DISALLOW_COPY_AND_ASSIGN(CpuMonitor); +}; + +} // namespace talk_base + +#endif // TALK_BASE_CPUMONITOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/crc32.h b/thirdparties/common/include/webrtc-sdk/talk/base/crc32.h new file mode 100644 index 0000000..b54e5e2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/crc32.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_CRC32_H_ +#define TALK_BASE_CRC32_H_ + +#include + +#include "talk/base/basictypes.h" + +namespace talk_base { + +// Updates a CRC32 checksum with |len| bytes from |buf|. |initial| holds the +// checksum result from the previous update; for the first call, it should be 0. +uint32 UpdateCrc32(uint32 initial, const void* buf, size_t len); + +// Computes a CRC32 checksum using |len| bytes from |buf|. +inline uint32 ComputeCrc32(const void* buf, size_t len) { + return UpdateCrc32(0, buf, len); +} +inline uint32 ComputeCrc32(const std::string& str) { + return ComputeCrc32(str.c_str(), str.size()); +} + +} // namespace talk_base + +#endif // TALK_BASE_CRC32_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/criticalsection.h b/thirdparties/common/include/webrtc-sdk/talk/base/criticalsection.h new file mode 100644 index 0000000..681655b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/criticalsection.h @@ -0,0 +1,196 @@ +/* + * 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_BASE_CRITICALSECTION_H__ +#define TALK_BASE_CRITICALSECTION_H__ + +#include "talk/base/constructormagic.h" + +#ifdef WIN32 +#include "talk/base/win32.h" +#endif + +#ifdef POSIX +#include +#endif + +#ifdef _DEBUG +#define CS_TRACK_OWNER 1 +#endif // _DEBUG + +#if CS_TRACK_OWNER +#define TRACK_OWNER(x) x +#else // !CS_TRACK_OWNER +#define TRACK_OWNER(x) +#endif // !CS_TRACK_OWNER + +namespace talk_base { + +#ifdef WIN32 +class CriticalSection { + public: + CriticalSection() { + InitializeCriticalSection(&crit_); + // Windows docs say 0 is not a valid thread id + TRACK_OWNER(thread_ = 0); + } + ~CriticalSection() { + DeleteCriticalSection(&crit_); + } + void Enter() { + EnterCriticalSection(&crit_); + TRACK_OWNER(thread_ = GetCurrentThreadId()); + } + bool TryEnter() { + if (TryEnterCriticalSection(&crit_) != FALSE) { + TRACK_OWNER(thread_ = GetCurrentThreadId()); + return true; + } + return false; + } + void Leave() { + TRACK_OWNER(thread_ = 0); + LeaveCriticalSection(&crit_); + } + +#if CS_TRACK_OWNER + bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); } +#endif // CS_TRACK_OWNER + + private: + CRITICAL_SECTION crit_; + TRACK_OWNER(DWORD thread_); // The section's owning thread id +}; +#endif // WIN32 + +#ifdef POSIX +class CriticalSection { + public: + CriticalSection() { + pthread_mutexattr_t mutex_attribute; + pthread_mutexattr_init(&mutex_attribute); + pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mutex_, &mutex_attribute); + pthread_mutexattr_destroy(&mutex_attribute); + TRACK_OWNER(thread_ = 0); + } + ~CriticalSection() { + pthread_mutex_destroy(&mutex_); + } + void Enter() { + pthread_mutex_lock(&mutex_); + TRACK_OWNER(thread_ = pthread_self()); + } + bool TryEnter() { + if (pthread_mutex_trylock(&mutex_) == 0) { + TRACK_OWNER(thread_ = pthread_self()); + return true; + } + return false; + } + void Leave() { + TRACK_OWNER(thread_ = 0); + pthread_mutex_unlock(&mutex_); + } + +#if CS_TRACK_OWNER + bool CurrentThreadIsOwner() const { return pthread_equal(thread_, pthread_self()); } +#endif // CS_TRACK_OWNER + + private: + pthread_mutex_t mutex_; + TRACK_OWNER(pthread_t thread_); +}; +#endif // POSIX + +// CritScope, for serializing execution through a scope. +class CritScope { + public: + explicit CritScope(CriticalSection *pcrit) { + pcrit_ = pcrit; + pcrit_->Enter(); + } + ~CritScope() { + pcrit_->Leave(); + } + private: + CriticalSection *pcrit_; + DISALLOW_COPY_AND_ASSIGN(CritScope); +}; + +// Tries to lock a critical section on construction via +// CriticalSection::TryEnter, and unlocks on destruction if the +// lock was taken. Never blocks. +// +// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in +// subsequent code. Users *must* check locked() to determine if the +// lock was taken. If you're not calling locked(), you're doing it wrong! +class TryCritScope { + public: + explicit TryCritScope(CriticalSection *pcrit) { + pcrit_ = pcrit; + locked_ = pcrit_->TryEnter(); + } + ~TryCritScope() { + if (locked_) { + pcrit_->Leave(); + } + } + bool locked() const { + return locked_; + } + private: + CriticalSection *pcrit_; + bool locked_; + DISALLOW_COPY_AND_ASSIGN(TryCritScope); +}; + +// TODO: Move this to atomicops.h, which can't be done easily because of +// complex compile rules. +class AtomicOps { + public: +#ifdef WIN32 + // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64. + static int Increment(int* i) { + return ::InterlockedIncrement(reinterpret_cast(i)); + } + static int Decrement(int* i) { + return ::InterlockedDecrement(reinterpret_cast(i)); + } +#else + static int Increment(int* i) { + return __sync_add_and_fetch(i, 1); + } + static int Decrement(int* i) { + return __sync_sub_and_fetch(i, 1); + } +#endif +}; + +} // namespace talk_base + +#endif // TALK_BASE_CRITICALSECTION_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/cryptstring.h b/thirdparties/common/include/webrtc-sdk/talk/base/cryptstring.h new file mode 100644 index 0000000..75d817a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/cryptstring.h @@ -0,0 +1,200 @@ +/* + * 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 _TALK_BASE_CRYPTSTRING_H_ +#define _TALK_BASE_CRYPTSTRING_H_ + +#include + +#include +#include + +#include "talk/base/linked_ptr.h" +#include "talk/base/scoped_ptr.h" + +namespace talk_base { + +class CryptStringImpl { +public: + virtual ~CryptStringImpl() {} + virtual size_t GetLength() const = 0; + virtual void CopyTo(char * dest, bool nullterminate) const = 0; + virtual std::string UrlEncode() const = 0; + virtual CryptStringImpl * Copy() const = 0; + virtual void CopyRawTo(std::vector * dest) const = 0; +}; + +class EmptyCryptStringImpl : public CryptStringImpl { +public: + virtual ~EmptyCryptStringImpl() {} + virtual size_t GetLength() const { return 0; } + virtual void CopyTo(char * dest, bool nullterminate) const { + if (nullterminate) { + *dest = '\0'; + } + } + virtual std::string UrlEncode() const { return ""; } + virtual CryptStringImpl * Copy() const { return new EmptyCryptStringImpl(); } + virtual void CopyRawTo(std::vector * dest) const { + dest->clear(); + } +}; + +class CryptString { +public: + CryptString() : impl_(new EmptyCryptStringImpl()) {} + size_t GetLength() const { return impl_->GetLength(); } + void CopyTo(char * dest, bool nullterminate) const { impl_->CopyTo(dest, nullterminate); } + CryptString(const CryptString & other) : impl_(other.impl_->Copy()) {} + explicit CryptString(const CryptStringImpl & impl) : impl_(impl.Copy()) {} + CryptString & operator=(const CryptString & other) { + if (this != &other) { + impl_.reset(other.impl_->Copy()); + } + return *this; + } + void Clear() { impl_.reset(new EmptyCryptStringImpl()); } + std::string UrlEncode() const { return impl_->UrlEncode(); } + void CopyRawTo(std::vector * dest) const { + return impl_->CopyRawTo(dest); + } + +private: + scoped_ptr impl_; +}; + + +// Used for constructing strings where a password is involved and we +// need to ensure that we zero memory afterwards +class FormatCryptString { +public: + FormatCryptString() { + storage_ = new char[32]; + capacity_ = 32; + length_ = 0; + storage_[0] = 0; + } + + void Append(const std::string & text) { + Append(text.data(), text.length()); + } + + void Append(const char * data, size_t length) { + EnsureStorage(length_ + length + 1); + memcpy(storage_ + length_, data, length); + length_ += length; + storage_[length_] = '\0'; + } + + void Append(const CryptString * password) { + size_t len = password->GetLength(); + EnsureStorage(length_ + len + 1); + password->CopyTo(storage_ + length_, true); + length_ += len; + } + + size_t GetLength() { + return length_; + } + + const char * GetData() { + return storage_; + } + + + // Ensures storage of at least n bytes + void EnsureStorage(size_t n) { + if (capacity_ >= n) { + return; + } + + size_t old_capacity = capacity_; + char * old_storage = storage_; + + for (;;) { + capacity_ *= 2; + if (capacity_ >= n) + break; + } + + storage_ = new char[capacity_]; + + if (old_capacity) { + memcpy(storage_, old_storage, length_); + + // zero memory in a way that an optimizer won't optimize it out + old_storage[0] = 0; + for (size_t i = 1; i < old_capacity; i++) { + old_storage[i] = old_storage[i - 1]; + } + delete[] old_storage; + } + } + + ~FormatCryptString() { + if (capacity_) { + storage_[0] = 0; + for (size_t i = 1; i < capacity_; i++) { + storage_[i] = storage_[i - 1]; + } + } + delete[] storage_; + } +private: + char * storage_; + size_t capacity_; + size_t length_; +}; + +class InsecureCryptStringImpl : public CryptStringImpl { + public: + std::string& password() { return password_; } + const std::string& password() const { return password_; } + + virtual ~InsecureCryptStringImpl() {} + virtual size_t GetLength() const { return password_.size(); } + virtual void CopyTo(char * dest, bool nullterminate) const { + memcpy(dest, password_.data(), password_.size()); + if (nullterminate) dest[password_.size()] = 0; + } + virtual std::string UrlEncode() const { return password_; } + virtual CryptStringImpl * Copy() const { + InsecureCryptStringImpl * copy = new InsecureCryptStringImpl; + copy->password() = password_; + return copy; + } + virtual void CopyRawTo(std::vector * dest) const { + dest->resize(password_.size()); + memcpy(&dest->front(), password_.data(), password_.size()); + } + private: + std::string password_; +}; + +} + +#endif // _TALK_BASE_CRYPTSTRING_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/dbus.h b/thirdparties/common/include/webrtc-sdk/talk/base/dbus.h new file mode 100644 index 0000000..3169e46 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/dbus.h @@ -0,0 +1,185 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_DBUS_H_ +#define TALK_BASE_DBUS_H_ + +#ifdef HAVE_DBUS_GLIB + +#include + +#include +#include + +#include "talk/base/libdbusglibsymboltable.h" +#include "talk/base/messagehandler.h" +#include "talk/base/thread.h" + +namespace talk_base { + +#define DBUS_TYPE "type" +#define DBUS_SIGNAL "signal" +#define DBUS_PATH "path" +#define DBUS_INTERFACE "interface" +#define DBUS_MEMBER "member" + +#ifdef CHROMEOS +#define CROS_PM_PATH "/" +#define CROS_PM_INTERFACE "org.chromium.PowerManager" +#define CROS_SIG_POWERCHANGED "PowerStateChanged" +#define CROS_VALUE_SLEEP "mem" +#define CROS_VALUE_RESUME "on" +#else +#define UP_PATH "/org/freedesktop/UPower" +#define UP_INTERFACE "org.freedesktop.UPower" +#define UP_SIG_SLEEPING "Sleeping" +#define UP_SIG_RESUMING "Resuming" +#endif // CHROMEOS + +// Wraps a DBus messages. +class DBusSigMessageData : public TypedMessageData { + public: + explicit DBusSigMessageData(DBusMessage *message); + ~DBusSigMessageData(); +}; + +// DBusSigFilter is an abstract class that defines the interface of DBus +// signal handling. +// The subclasses implement ProcessSignal() for various purposes. +// When a DBus signal comes, a DSM_SIGNAL message is posted to the caller thread +// which will then invokes ProcessSignal(). +class DBusSigFilter : protected MessageHandler { + public: + enum DBusSigMessage { DSM_SIGNAL }; + + // This filter string should ususally come from BuildFilterString() + explicit DBusSigFilter(const std::string &filter) + : caller_thread_(Thread::Current()), filter_(filter) { + } + + // Builds a DBus monitor filter string from given DBus path, interface, and + // member. + // See http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html + static std::string BuildFilterString(const std::string &path, + const std::string &interface, + const std::string &member); + + // Handles callback on DBus messages by DBus system. + static DBusHandlerResult DBusCallback(DBusConnection *dbus_conn, + DBusMessage *message, + void *instance); + + // Handles callback on DBus messages to each DBusSigFilter instance. + DBusHandlerResult Callback(DBusMessage *message); + + // From MessageHandler. + virtual void OnMessage(Message *message); + + // Returns the DBus monitor filter string. + const std::string &filter() const { return filter_; } + + private: + // On caller thread. + virtual void ProcessSignal(DBusMessage *message) = 0; + + Thread *caller_thread_; + const std::string filter_; +}; + +// DBusMonitor is a class for DBus signal monitoring. +// +// The caller-thread calls AddFilter() first to add the signals that it wants to +// monitor and then calls StartMonitoring() to start the monitoring. +// This will create a worker-thread which listens on DBus connection and sends +// DBus signals back through the callback. +// The worker-thread will be running forever until either StopMonitoring() is +// called from the caller-thread or the worker-thread hit some error. +// +// Programming model: +// 1. Caller-thread: Creates an object of DBusMonitor. +// 2. Caller-thread: Calls DBusMonitor::AddFilter() one or several times. +// 3. Caller-thread: StartMonitoring(). +// ... +// 4. Worker-thread: DBus signal recieved. Post a message to caller-thread. +// 5. Caller-thread: DBusFilterBase::ProcessSignal() is invoked. +// ... +// 6. Caller-thread: StopMonitoring(). +// +// Assumption: +// AddFilter(), StartMonitoring(), and StopMonitoring() methods are called by +// a single thread. Hence, there is no need to make them thread safe. +class DBusMonitor { + public: + // Status of DBus monitoring. + enum DBusMonitorStatus { + DMS_NOT_INITIALIZED, // Not initialized. + DMS_INITIALIZING, // Initializing the monitoring thread. + DMS_RUNNING, // Monitoring. + DMS_STOPPED, // Not monitoring. Stopped normally. + DMS_FAILED, // Not monitoring. Failed. + }; + + // Returns the DBus-Glib symbol table. + // We should only use this function to access DBus-Glib symbols. + static LibDBusGlibSymbolTable *GetDBusGlibSymbolTable(); + + // Creates an instance of DBusMonitor. + static DBusMonitor *Create(DBusBusType type); + ~DBusMonitor(); + + // Adds a filter to DBusMonitor. + bool AddFilter(DBusSigFilter *filter); + + // Starts DBus message monitoring. + bool StartMonitoring(); + + // Stops DBus message monitoring. + bool StopMonitoring(); + + // Gets the status of DBus monitoring. + DBusMonitorStatus GetStatus(); + + private: + // Forward declaration. Defined in the .cc file. + class DBusMonitoringThread; + + explicit DBusMonitor(DBusBusType type); + + // Updates status_ when monitoring status has changed. + void OnMonitoringStatusChanged(DBusMonitorStatus status); + + DBusBusType type_; + DBusMonitorStatus status_; + DBusMonitoringThread *monitoring_thread_; + std::vector filter_list_; +}; + +} // namespace talk_base + +#endif // HAVE_DBUS_GLIB + +#endif // TALK_BASE_DBUS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/diskcache.h b/thirdparties/common/include/webrtc-sdk/talk/base/diskcache.h new file mode 100644 index 0000000..a0e397d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/diskcache.h @@ -0,0 +1,142 @@ +/* + * 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 TALK_BASE_DISKCACHE_H__ +#define TALK_BASE_DISKCACHE_H__ + +#include +#include + +#ifdef WIN32 +#undef UnlockResource +#endif // WIN32 + +namespace talk_base { + +class StreamInterface; + +/////////////////////////////////////////////////////////////////////////////// +// DiskCache - An LRU cache of streams, stored on disk. +// +// Streams are identified by a unique resource id. Multiple streams can be +// associated with each resource id, distinguished by an index. When old +// resources are flushed from the cache, all streams associated with those +// resources are removed together. +// DiskCache is designed to persist across executions of the program. It is +// safe for use from an arbitrary number of users on a single thread, but not +// from multiple threads or other processes. +/////////////////////////////////////////////////////////////////////////////// + +class DiskCache { +public: + DiskCache(); + virtual ~DiskCache(); + + bool Initialize(const std::string& folder, size_t size); + bool Purge(); + + bool LockResource(const std::string& id); + StreamInterface* WriteResource(const std::string& id, size_t index); + bool UnlockResource(const std::string& id); + + StreamInterface* ReadResource(const std::string& id, size_t index) const; + + bool HasResource(const std::string& id) const; + bool HasResourceStream(const std::string& id, size_t index) const; + bool DeleteResource(const std::string& id); + + protected: + virtual bool InitializeEntries() = 0; + virtual bool PurgeFiles() = 0; + + virtual bool FileExists(const std::string& filename) const = 0; + virtual bool DeleteFile(const std::string& filename) const = 0; + + enum LockState { LS_UNLOCKED, LS_LOCKED, LS_UNLOCKING }; + struct Entry { + LockState lock_state; + mutable size_t accessors; + size_t size; + size_t streams; + time_t last_modified; + }; + typedef std::map EntryMap; + friend class DiskCacheAdapter; + + bool CheckLimit(); + + std::string IdToFilename(const std::string& id, size_t index) const; + bool FilenameToId(const std::string& filename, std::string* id, + size_t* index) const; + + const Entry* GetEntry(const std::string& id) const { + return const_cast(this)->GetOrCreateEntry(id, false); + } + Entry* GetOrCreateEntry(const std::string& id, bool create); + + void ReleaseResource(const std::string& id, size_t index) const; + + std::string folder_; + size_t max_cache_, total_size_; + EntryMap map_; + mutable size_t total_accessors_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// CacheLock - Automatically manage locking and unlocking, with optional +// rollback semantics +/////////////////////////////////////////////////////////////////////////////// + +class CacheLock { +public: + CacheLock(DiskCache* cache, const std::string& id, bool rollback = false) + : cache_(cache), id_(id), rollback_(rollback) + { + locked_ = cache_->LockResource(id_); + } + ~CacheLock() { + if (locked_) { + cache_->UnlockResource(id_); + if (rollback_) { + cache_->DeleteResource(id_); + } + } + } + bool IsLocked() const { return locked_; } + void Commit() { rollback_ = false; } + +private: + DiskCache* cache_; + std::string id_; + bool rollback_, locked_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_DISKCACHE_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/diskcache_win32.h b/thirdparties/common/include/webrtc-sdk/talk/base/diskcache_win32.h new file mode 100644 index 0000000..1dbfc67 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/diskcache_win32.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_DISKCACHEWIN32_H__ +#define TALK_BASE_DISKCACHEWIN32_H__ + +#include "talk/base/diskcache.h" + +namespace talk_base { + +class DiskCacheWin32 : public DiskCache { + protected: + virtual bool InitializeEntries(); + virtual bool PurgeFiles(); + + virtual bool FileExists(const std::string& filename) const; + virtual bool DeleteFile(const std::string& filename) const; +}; + +} + +#endif // TALK_BASE_DISKCACHEWIN32_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/dscp.h b/thirdparties/common/include/webrtc-sdk/talk/base/dscp.h new file mode 100644 index 0000000..4acef1b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/dscp.h @@ -0,0 +1,62 @@ +/* + * 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_DSCP_H_ +#define TALK_BASE_DSCP_H_ + +namespace talk_base { +// Differentiated Services Code Point. +// See http://tools.ietf.org/html/rfc2474 for details. +enum DiffServCodePoint { + DSCP_NO_CHANGE = -1, + DSCP_DEFAULT = 0, // Same as DSCP_CS0 + DSCP_CS0 = 0, // The default + DSCP_CS1 = 8, // Bulk/background traffic + DSCP_AF11 = 10, + DSCP_AF12 = 12, + DSCP_AF13 = 14, + DSCP_CS2 = 16, + DSCP_AF21 = 18, + DSCP_AF22 = 20, + DSCP_AF23 = 22, + DSCP_CS3 = 24, + DSCP_AF31 = 26, + DSCP_AF32 = 28, + DSCP_AF33 = 30, + DSCP_CS4 = 32, + DSCP_AF41 = 34, // Video + DSCP_AF42 = 36, // Video + DSCP_AF43 = 38, // Video + DSCP_CS5 = 40, // Video + DSCP_EF = 46, // Voice + DSCP_CS6 = 48, // Voice + DSCP_CS7 = 56, // Control messages +}; + +} // namespace talk_base + + #endif // TALK_BASE_DSCP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/event.h b/thirdparties/common/include/webrtc-sdk/talk/base/event.h new file mode 100644 index 0000000..3969e58 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/event.h @@ -0,0 +1,68 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_EVENT_H__ +#define TALK_BASE_EVENT_H__ + +#if defined(WIN32) +#include "talk/base/win32.h" // NOLINT: consider this a system header. +#elif defined(POSIX) +#include +#else +#error "Must define either WIN32 or POSIX." +#endif + +#include "talk/base/basictypes.h" +#include "talk/base/common.h" + +namespace talk_base { + +class Event { + public: + Event(bool manual_reset, bool initially_signaled); + ~Event(); + + void Set(); + void Reset(); + bool Wait(int cms); + + private: + bool is_manual_reset_; + +#if defined(WIN32) + bool is_initially_signaled_; + HANDLE event_handle_; +#elif defined(POSIX) + bool event_status_; + pthread_mutex_t event_mutex_; + pthread_cond_t event_cond_; +#endif +}; + +} // namespace talk_base + +#endif // TALK_BASE_EVENT_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/fakecpumonitor.h b/thirdparties/common/include/webrtc-sdk/talk/base/fakecpumonitor.h new file mode 100644 index 0000000..b73ff77 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/fakecpumonitor.h @@ -0,0 +1,49 @@ +/* + * 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_FAKECPUMONITOR_H_ +#define TALK_BASE_FAKECPUMONITOR_H_ + +#include "talk/base/cpumonitor.h" + +namespace talk_base { + +class FakeCpuMonitor : public talk_base::CpuMonitor { + public: + explicit FakeCpuMonitor(Thread* thread) + : CpuMonitor(thread) { + } + ~FakeCpuMonitor() { + } + + virtual void OnMessage(talk_base::Message* msg) { + } +}; + +} // namespace talk_base + +#endif // TALK_BASE_FAKECPUMONITOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/fakenetwork.h b/thirdparties/common/include/webrtc-sdk/talk/base/fakenetwork.h new file mode 100644 index 0000000..acb75d0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/fakenetwork.h @@ -0,0 +1,136 @@ +/* + * libjingle + * Copyright 2009 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_FAKENETWORK_H_ +#define TALK_BASE_FAKENETWORK_H_ + +#include +#include + +#include "talk/base/network.h" +#include "talk/base/messagehandler.h" +#include "talk/base/socketaddress.h" +#include "talk/base/stringencode.h" +#include "talk/base/thread.h" + +namespace talk_base { + +const int kFakeIPv4NetworkPrefixLength = 24; +const int kFakeIPv6NetworkPrefixLength = 64; + +// Fake network manager that allows us to manually specify the IPs to use. +class FakeNetworkManager : public NetworkManagerBase, + public MessageHandler { + public: + FakeNetworkManager() + : thread_(Thread::Current()), + next_index_(0), + started_(false), + sent_first_update_(false) { + } + + typedef std::vector IfaceList; + + void AddInterface(const SocketAddress& iface) { + // ensure a unique name for the interface + SocketAddress address("test" + talk_base::ToString(next_index_++), 0); + address.SetResolvedIP(iface.ipaddr()); + ifaces_.push_back(address); + DoUpdateNetworks(); + } + + void RemoveInterface(const SocketAddress& iface) { + for (IfaceList::iterator it = ifaces_.begin(); + it != ifaces_.end(); ++it) { + if (it->EqualIPs(iface)) { + ifaces_.erase(it); + break; + } + } + DoUpdateNetworks(); + } + + virtual void StartUpdating() { + if (started_) { + if (sent_first_update_) + SignalNetworksChanged(); + return; + } + + started_ = true; + sent_first_update_ = false; + thread_->Post(this); + } + + virtual void StopUpdating() { + started_ = false; + } + + // MessageHandler interface. + virtual void OnMessage(Message* msg) { + DoUpdateNetworks(); + } + + private: + void DoUpdateNetworks() { + if (!started_) + return; + std::vector networks; + for (IfaceList::iterator it = ifaces_.begin(); + it != ifaces_.end(); ++it) { + int prefix_length = 0; + if (it->ipaddr().family() == AF_INET) { + prefix_length = kFakeIPv4NetworkPrefixLength; + } else if (it->ipaddr().family() == AF_INET6) { + prefix_length = kFakeIPv6NetworkPrefixLength; + } + IPAddress prefix = TruncateIP(it->ipaddr(), prefix_length); + scoped_ptr net(new Network(it->hostname(), + it->hostname(), + prefix, + prefix_length)); + net->AddIP(it->ipaddr()); + networks.push_back(net.release()); + } + bool changed; + MergeNetworkList(networks, &changed); + if (changed || !sent_first_update_) { + SignalNetworksChanged(); + sent_first_update_ = true; + } + } + + Thread* thread_; + IfaceList ifaces_; + int next_index_; + bool started_; + bool sent_first_update_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_FAKENETWORK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/fakesslidentity.h b/thirdparties/common/include/webrtc-sdk/talk/base/fakesslidentity.h new file mode 100644 index 0000000..d625230 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/fakesslidentity.h @@ -0,0 +1,111 @@ +/* + * libjingle + * Copyright 2012, The Libjingle Authors. + * + * 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_FAKESSLIDENTITY_H_ +#define TALK_BASE_FAKESSLIDENTITY_H_ + +#include +#include + +#include "talk/base/messagedigest.h" +#include "talk/base/sslidentity.h" + +namespace talk_base { + +class FakeSSLCertificate : public talk_base::SSLCertificate { + public: + // 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& certs) + : data_(certs.front()), digest_algorithm_(DIGEST_SHA_1) { + std::vector::const_iterator it; + // Skip certs[0]. + for (it = certs.begin() + 1; it != certs.end(); ++it) { + certs_.push_back(FakeSSLCertificate(*it)); + } + } + virtual FakeSSLCertificate* GetReference() const { + return new FakeSSLCertificate(*this); + } + virtual std::string ToPEMString() const { + return data_; + } + virtual void ToDER(Buffer* der_buffer) const { + std::string der_string; + 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 { + *algorithm = digest_algorithm_; + return true; + } + 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); + } + virtual bool GetChain(SSLCertChain** chain) const { + if (certs_.empty()) + return false; + std::vector new_certs(certs_.size()); + std::transform(certs_.begin(), certs_.end(), new_certs.begin(), DupCert); + *chain = new SSLCertChain(new_certs); + return true; + } + + private: + static FakeSSLCertificate* DupCert(FakeSSLCertificate cert) { + return cert.GetReference(); + } + std::string data_; + std::vector certs_; + std::string digest_algorithm_; +}; + +class FakeSSLIdentity : public talk_base::SSLIdentity { + public: + explicit FakeSSLIdentity(const std::string& data) : cert_(data) {} + explicit FakeSSLIdentity(const FakeSSLCertificate& cert) : cert_(cert) {} + virtual FakeSSLIdentity* GetReference() const { + return new FakeSSLIdentity(*this); + } + virtual const FakeSSLCertificate& certificate() const { return cert_; } + private: + FakeSSLCertificate cert_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_FAKESSLIDENTITY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/faketaskrunner.h b/thirdparties/common/include/webrtc-sdk/talk/base/faketaskrunner.h new file mode 100644 index 0000000..52fa50d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/faketaskrunner.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +// A fake TaskRunner for use in unit tests. + +#ifndef TALK_BASE_FAKETASKRUNNER_H_ +#define TALK_BASE_FAKETASKRUNNER_H_ + +#include "talk/base/taskparent.h" +#include "talk/base/taskrunner.h" + +namespace talk_base { + +class FakeTaskRunner : public TaskRunner { + public: + FakeTaskRunner() : current_time_(0) {} + virtual ~FakeTaskRunner() {} + + virtual void WakeTasks() { RunTasks(); } + + virtual int64 CurrentTime() { + // Implement if needed. + return current_time_++; + } + + int64 current_time_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_FAKETASKRUNNER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/filelock.h b/thirdparties/common/include/webrtc-sdk/talk/base/filelock.h new file mode 100644 index 0000000..4bd732f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/filelock.h @@ -0,0 +1,70 @@ +/* + * libjingle + * Copyright 2009, 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_FILELOCK_H_ +#define TALK_BASE_FILELOCK_H_ + +#include + +#include "talk/base/constructormagic.h" +#include "talk/base/scoped_ptr.h" + +namespace talk_base { + +class FileStream; + +// Implements a very simple cross process lock based on a file. +// When Lock(...) is called we try to open/create the file in read/write +// mode without any sharing. (Or locking it with flock(...) on Unix) +// If the process crash the OS will make sure that the file descriptor +// is released and another process can accuire the lock. +// This doesn't work on ancient OSX/Linux versions if used on NFS. +// (Nfs-client before: ~2.6 and Linux Kernel < 2.6.) +class FileLock { + public: + virtual ~FileLock(); + + // Attempts to lock the file. The caller owns the returned + // lock object. Returns NULL if the file already was locked. + static FileLock* TryLock(const std::string& path); + void Unlock(); + + protected: + FileLock(const std::string& path, FileStream* file); + + private: + void MaybeUnlock(); + + std::string path_; + scoped_ptr file_; + + DISALLOW_EVIL_CONSTRUCTORS(FileLock); +}; + +} // namespace talk_base + +#endif // TALK_BASE_FILELOCK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/fileutils.h b/thirdparties/common/include/webrtc-sdk/talk/base/fileutils.h new file mode 100644 index 0000000..eb36e64 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/fileutils.h @@ -0,0 +1,476 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_FILEUTILS_H_ +#define TALK_BASE_FILEUTILS_H_ + +#include + +#ifdef WIN32 +#include "talk/base/win32.h" +#else +#include +#include +#include +#include +#include +#endif + +#include "talk/base/basictypes.h" +#include "talk/base/common.h" +#include "talk/base/scoped_ptr.h" + +namespace talk_base { + +class FileStream; +class Pathname; + +////////////////////////// +// Directory Iterator // +////////////////////////// + +// A DirectoryIterator is created with a given directory. It originally points +// to the first file in the directory, and can be advanecd with Next(). This +// allows you to get information about each file. + +class DirectoryIterator { + friend class Filesystem; + public: + // Constructor + DirectoryIterator(); + // Destructor + virtual ~DirectoryIterator(); + + // Starts traversing a directory + // dir is the directory to traverse + // returns true if the directory exists and is valid + // The iterator will point to the first entry in the directory + virtual bool Iterate(const Pathname &path); + + // Advances to the next file + // returns true if there were more files in the directory. + virtual bool Next(); + + // returns true if the file currently pointed to is a directory + virtual bool IsDirectory() const; + + // returns the name of the file currently pointed to + virtual std::string Name() const; + + // returns the size of the file currently pointed to + virtual size_t FileSize() const; + + // returns the last modified time of the file currently pointed to + virtual time_t FileModifyTime() const; + + // checks whether current file is a special directory file "." or ".." + bool IsDots() const { + std::string filename(Name()); + return (filename.compare(".") == 0) || (filename.compare("..") == 0); + } + + private: + std::string directory_; +#ifdef WIN32 + WIN32_FIND_DATA data_; + HANDLE handle_; +#else + DIR *dir_; + struct dirent *dirent_; + struct stat stat_; +#endif +}; + +enum FileTimeType { FTT_CREATED, FTT_MODIFIED, FTT_ACCESSED }; + +class FilesystemInterface { + public: + virtual ~FilesystemInterface() {} + + // Returns a DirectoryIterator for a given pathname. + // TODO: Do fancy abstracted stuff + virtual DirectoryIterator *IterateDirectory() { + return new DirectoryIterator(); + } + + // Opens a file. Returns an open StreamInterface if function succeeds. + // Otherwise, returns NULL. + // TODO: Add an error param to indicate failure reason, similar to + // FileStream::Open + virtual FileStream *OpenFile(const Pathname &filename, + const std::string &mode) = 0; + + // Atomically creates an empty file accessible only to the current user if one + // does not already exist at the given path, otherwise fails. This is the only + // secure way to create a file in a shared temp directory (e.g., C:\Temp on + // Windows or /tmp on Linux). + // Note that if it is essential that a file be successfully created then the + // app must generate random names and retry on failure, or else it will be + // vulnerable to a trivial DoS. + virtual bool CreatePrivateFile(const Pathname &filename) = 0; + + // This will attempt to delete the path located at filename. + // It ASSERTS and returns false if the path points to a folder or a + // non-existent file. + virtual bool DeleteFile(const Pathname &filename) = 0; + + // This will attempt to delete the empty folder located at 'folder' + // It ASSERTS and returns false if the path points to a file or a non-existent + // folder. It fails normally if the folder is not empty or can otherwise + // not be deleted. + virtual bool DeleteEmptyFolder(const Pathname &folder) = 0; + + // This will call IterateDirectory, to get a directory iterator, and then + // call DeleteFolderAndContents and DeleteFile on every path contained in this + // folder. If the folder is empty, this returns true. + virtual bool DeleteFolderContents(const Pathname &folder); + + // This deletes the contents of a folder, recursively, and then deletes + // the folder itself. + virtual bool DeleteFolderAndContents(const Pathname &folder) { + return DeleteFolderContents(folder) && DeleteEmptyFolder(folder); + } + + // This will delete whatever is located at path, be it a file or a folder. + // If it is a folder, it will delete it recursively by calling + // DeleteFolderAndContents + bool DeleteFileOrFolder(const Pathname &path) { + if (IsFolder(path)) + return DeleteFolderAndContents(path); + else + return DeleteFile(path); + } + + // Creates a directory. This will call itself recursively to create /foo/bar + // even if /foo does not exist. Returns true if the function succeeds. + virtual bool CreateFolder(const Pathname &pathname) = 0; + + // This moves a file from old_path to new_path, where "old_path" is a + // plain file. This ASSERTs and returns false if old_path points to a + // directory, and returns true if the function succeeds. + // If the new path is on a different volume than the old path, this function + // will attempt to copy and, if that succeeds, delete the old path. + virtual bool MoveFolder(const Pathname &old_path, + const Pathname &new_path) = 0; + + // This moves a directory from old_path to new_path, where "old_path" is a + // directory. This ASSERTs and returns false if old_path points to a plain + // file, and returns true if the function succeeds. + // If the new path is on a different volume, this function will attempt to + // copy and if that succeeds, delete the old path. + virtual bool MoveFile(const Pathname &old_path, const Pathname &new_path) = 0; + + // This attempts to move whatever is located at old_path to new_path, + // be it a file or folder. + bool MoveFileOrFolder(const Pathname &old_path, const Pathname &new_path) { + if (IsFile(old_path)) { + return MoveFile(old_path, new_path); + } else { + return MoveFolder(old_path, new_path); + } + } + + // This copies a file from old_path to new_path. This method ASSERTs and + // returns false if old_path is a folder, and returns true if the copy + // succeeds. + virtual bool CopyFile(const Pathname &old_path, const Pathname &new_path) = 0; + + // This copies a folder from old_path to new_path. + bool CopyFolder(const Pathname &old_path, const Pathname &new_path); + + bool CopyFileOrFolder(const Pathname &old_path, const Pathname &new_path) { + if (IsFile(old_path)) + return CopyFile(old_path, new_path); + else + return CopyFolder(old_path, new_path); + } + + // Returns true if pathname refers to a directory + virtual bool IsFolder(const Pathname& pathname) = 0; + + // Returns true if pathname refers to a file + virtual bool IsFile(const Pathname& pathname) = 0; + + // Returns true if pathname refers to no filesystem object, every parent + // directory either exists, or is also absent. + virtual bool IsAbsent(const Pathname& pathname) = 0; + + // Returns true if pathname represents a temporary location on the system. + virtual bool IsTemporaryPath(const Pathname& pathname) = 0; + + // A folder appropriate for storing temporary files (Contents are + // automatically deleted when the program exits) + virtual bool GetTemporaryFolder(Pathname &path, bool create, + const std::string *append) = 0; + + virtual std::string TempFilename(const Pathname &dir, + const std::string &prefix) = 0; + + // Determines the size of the file indicated by path. + virtual bool GetFileSize(const Pathname& path, size_t* size) = 0; + + // Determines a timestamp associated with the file indicated by path. + virtual bool GetFileTime(const Pathname& path, FileTimeType which, + time_t* time) = 0; + + // Returns the path to the running application. + // Note: This is not guaranteed to work on all platforms. Be aware of the + // limitations before using it, and robustly handle failure. + virtual bool GetAppPathname(Pathname* path) = 0; + + // Get a folder that is unique to the current application, which is suitable + // for sharing data between executions of the app. If the per_user arg is + // true, the folder is also specific to the current user. + virtual bool GetAppDataFolder(Pathname* path, bool per_user) = 0; + + // Get a temporary folder that is unique to the current user and application. + // TODO: Re-evaluate the goals of this function. We probably just need any + // directory that won't collide with another existing directory, and which + // will be cleaned up when the program exits. + virtual bool GetAppTempFolder(Pathname* path) = 0; + + // Delete the contents of the folder returned by GetAppTempFolder + bool CleanAppTempFolder(); + + virtual bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes) = 0; + + // Returns the absolute path of the current directory. + virtual Pathname GetCurrentDirectory() = 0; + + // Note: These might go into some shared config section later, but they're + // used by some methods in this interface, so we're leaving them here for now. + void SetOrganizationName(const std::string& organization) { + organization_name_ = organization; + } + void GetOrganizationName(std::string* organization) { + ASSERT(NULL != organization); + *organization = organization_name_; + } + void SetApplicationName(const std::string& application) { + application_name_ = application; + } + void GetApplicationName(std::string* application) { + ASSERT(NULL != application); + *application = application_name_; + } + + protected: + std::string organization_name_; + std::string application_name_; +}; + +class Filesystem { + public: + static FilesystemInterface *default_filesystem() { + ASSERT(default_filesystem_ != NULL); + return default_filesystem_; + } + + static void set_default_filesystem(FilesystemInterface *filesystem) { + default_filesystem_ = filesystem; + } + + static FilesystemInterface *swap_default_filesystem( + FilesystemInterface *filesystem) { + FilesystemInterface *cur = default_filesystem_; + default_filesystem_ = filesystem; + return cur; + } + + static DirectoryIterator *IterateDirectory() { + return EnsureDefaultFilesystem()->IterateDirectory(); + } + + static bool CreateFolder(const Pathname &pathname) { + return EnsureDefaultFilesystem()->CreateFolder(pathname); + } + + static FileStream *OpenFile(const Pathname &filename, + const std::string &mode) { + return EnsureDefaultFilesystem()->OpenFile(filename, mode); + } + + static bool CreatePrivateFile(const Pathname &filename) { + return EnsureDefaultFilesystem()->CreatePrivateFile(filename); + } + + static bool DeleteFile(const Pathname &filename) { + return EnsureDefaultFilesystem()->DeleteFile(filename); + } + + static bool DeleteEmptyFolder(const Pathname &folder) { + return EnsureDefaultFilesystem()->DeleteEmptyFolder(folder); + } + + static bool DeleteFolderContents(const Pathname &folder) { + return EnsureDefaultFilesystem()->DeleteFolderContents(folder); + } + + static bool DeleteFolderAndContents(const Pathname &folder) { + return EnsureDefaultFilesystem()->DeleteFolderAndContents(folder); + } + + static bool MoveFolder(const Pathname &old_path, const Pathname &new_path) { + return EnsureDefaultFilesystem()->MoveFolder(old_path, new_path); + } + + static bool MoveFile(const Pathname &old_path, const Pathname &new_path) { + return EnsureDefaultFilesystem()->MoveFile(old_path, new_path); + } + + static bool CopyFolder(const Pathname &old_path, const Pathname &new_path) { + return EnsureDefaultFilesystem()->CopyFolder(old_path, new_path); + } + + static bool CopyFile(const Pathname &old_path, const Pathname &new_path) { + return EnsureDefaultFilesystem()->CopyFile(old_path, new_path); + } + + static bool IsFolder(const Pathname& pathname) { + return EnsureDefaultFilesystem()->IsFolder(pathname); + } + + static bool IsFile(const Pathname &pathname) { + return EnsureDefaultFilesystem()->IsFile(pathname); + } + + static bool IsAbsent(const Pathname &pathname) { + return EnsureDefaultFilesystem()->IsAbsent(pathname); + } + + static bool IsTemporaryPath(const Pathname& pathname) { + return EnsureDefaultFilesystem()->IsTemporaryPath(pathname); + } + + static bool GetTemporaryFolder(Pathname &path, bool create, + const std::string *append) { + return EnsureDefaultFilesystem()->GetTemporaryFolder(path, create, append); + } + + static std::string TempFilename(const Pathname &dir, + const std::string &prefix) { + return EnsureDefaultFilesystem()->TempFilename(dir, prefix); + } + + static bool GetFileSize(const Pathname& path, size_t* size) { + return EnsureDefaultFilesystem()->GetFileSize(path, size); + } + + static bool GetFileTime(const Pathname& path, FileTimeType which, + time_t* time) { + return EnsureDefaultFilesystem()->GetFileTime(path, which, time); + } + + static bool GetAppPathname(Pathname* path) { + return EnsureDefaultFilesystem()->GetAppPathname(path); + } + + static bool GetAppDataFolder(Pathname* path, bool per_user) { + return EnsureDefaultFilesystem()->GetAppDataFolder(path, per_user); + } + + static bool GetAppTempFolder(Pathname* path) { + return EnsureDefaultFilesystem()->GetAppTempFolder(path); + } + + static bool CleanAppTempFolder() { + return EnsureDefaultFilesystem()->CleanAppTempFolder(); + } + + static bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes) { + return EnsureDefaultFilesystem()->GetDiskFreeSpace(path, freebytes); + } + + // Definition has to be in the .cc file due to returning forward-declared + // Pathname by value. + static Pathname GetCurrentDirectory(); + + static void SetOrganizationName(const std::string& organization) { + EnsureDefaultFilesystem()->SetOrganizationName(organization); + } + + static void GetOrganizationName(std::string* organization) { + EnsureDefaultFilesystem()->GetOrganizationName(organization); + } + + static void SetApplicationName(const std::string& application) { + EnsureDefaultFilesystem()->SetApplicationName(application); + } + + static void GetApplicationName(std::string* application) { + EnsureDefaultFilesystem()->GetApplicationName(application); + } + + private: + static FilesystemInterface* default_filesystem_; + + static FilesystemInterface *EnsureDefaultFilesystem(); + DISALLOW_IMPLICIT_CONSTRUCTORS(Filesystem); +}; + +class FilesystemScope{ + public: + explicit FilesystemScope(FilesystemInterface *new_fs) { + old_fs_ = Filesystem::swap_default_filesystem(new_fs); + } + ~FilesystemScope() { + Filesystem::set_default_filesystem(old_fs_); + } + private: + FilesystemInterface* old_fs_; + DISALLOW_IMPLICIT_CONSTRUCTORS(FilesystemScope); +}; + +// Generates a unique filename based on the input path. If no path component +// is specified, it uses the temporary directory. If a filename is provided, +// up to 100 variations of form basename-N.extension are tried. When +// create_empty is true, an empty file of this name is created (which +// decreases the chance of a temporary filename collision with another +// 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/thirdparties/common/include/webrtc-sdk/talk/base/fileutils_mock.h b/thirdparties/common/include/webrtc-sdk/talk/base/fileutils_mock.h new file mode 100644 index 0000000..01410af --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/fileutils_mock.h @@ -0,0 +1,270 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_FILEUTILS_MOCK_H_ +#define TALK_BASE_FILEUTILS_MOCK_H_ + +#include +#include +#include + +#include "talk/base/fileutils.h" +#include "talk/base/gunit.h" +#include "talk/base/pathutils.h" +#include "talk/base/stream.h" + +namespace talk_base { + +class FakeFileStream : public FileStream { + public: + explicit FakeFileStream(const std::string & contents) : + string_stream_(contents) + {} + + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error) { + return string_stream_.Read(buffer, buffer_len, read, error); + } + + virtual void Close() { + return string_stream_.Close(); + } + virtual bool GetSize(size_t* size) const { + return string_stream_.GetSize(size); + } + + private: + StringStream string_stream_; +}; + +class FakeDirectoryIterator : public DirectoryIterator { + public: + typedef std::pair File; + + /* + * files should be sorted by directory + * put '/' at the end of file if you want it to be a directory + * + * Sample list: + * /var/dir/file1 + * /var/dir/file2 + * /var/dir/subdir1/ + * /var/dir/subdir2/ + * /var/dir2/file2 + * /var/dir3/ + * + * you can call Iterate for any path: /var, /var/dir, /var/dir2 + * unrelated files will be ignored + */ + explicit FakeDirectoryIterator(const std::vector& all_files) : + all_files_(all_files) {} + + virtual bool Iterate(const Pathname& path) { + path_iterator_ = all_files_.begin(); + path_ = path.pathname(); + + // make sure path ends end with '/' + if (path_.rfind(Pathname::DefaultFolderDelimiter()) != path_.size() - 1) + path_ += Pathname::DefaultFolderDelimiter(); + + return FakeDirectoryIterator::Search(std::string("")); + } + + virtual bool Next() { + std::string current_name = Name(); + path_iterator_++; + return FakeDirectoryIterator::Search(current_name); + } + + bool Search(const std::string& current_name) { + for (; path_iterator_ != all_files_.end(); path_iterator_++) { + if (path_iterator_->first.find(path_) == 0 + && Name().compare(current_name) != 0) { + return true; + } + } + + return false; + } + + virtual bool IsDirectory() const { + std::string sub_path = path_iterator_->first; + + return std::string::npos != + sub_path.find(Pathname::DefaultFolderDelimiter(), path_.size()); + } + + virtual std::string Name() const { + std::string sub_path = path_iterator_->first; + + // path - top level path (ex. /var/lib) + // sub_path - subpath under top level path (ex. /var/lib/dir/dir/file ) + // find shortest non-trivial common path. (ex. /var/lib/dir) + size_t start = path_.size(); + size_t end = sub_path.find(Pathname::DefaultFolderDelimiter(), start); + + if (end != std::string::npos) { + return sub_path.substr(start, end - start); + } else { + return sub_path.substr(start); + } + } + + private: + const std::vector all_files_; + + std::string path_; + std::vector::const_iterator path_iterator_; +}; + +class FakeFileSystem : public FilesystemInterface { + public: + typedef std::pair File; + + explicit FakeFileSystem(const std::vector& all_files) : + all_files_(all_files) {} + + virtual DirectoryIterator *IterateDirectory() { + return new FakeDirectoryIterator(all_files_); + } + + virtual FileStream * OpenFile( + const Pathname &filename, + const std::string &mode) { + std::vector::const_iterator i_files = all_files_.begin(); + std::string path = filename.pathname(); + + for (; i_files != all_files_.end(); i_files++) { + if (i_files->first.compare(path) == 0) { + return new FakeFileStream(i_files->second); + } + } + + return NULL; + } + + bool CreatePrivateFile(const Pathname &filename) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool DeleteFile(const Pathname &filename) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool DeleteEmptyFolder(const Pathname &folder) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool DeleteFolderContents(const Pathname &folder) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool DeleteFolderAndContents(const Pathname &folder) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool CreateFolder(const Pathname &pathname) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool MoveFolder(const Pathname &old_path, const Pathname &new_path) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool MoveFile(const Pathname &old_path, const Pathname &new_path) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool CopyFile(const Pathname &old_path, const Pathname &new_path) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool IsFolder(const Pathname &pathname) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool IsFile(const Pathname &pathname) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool IsAbsent(const Pathname &pathname) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool IsTemporaryPath(const Pathname &pathname) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool GetTemporaryFolder(Pathname &path, bool create, + const std::string *append) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + std::string TempFilename(const Pathname &dir, const std::string &prefix) { + EXPECT_TRUE(false) << "Unsupported operation"; + return std::string(); + } + bool GetFileSize(const Pathname &path, size_t *size) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool GetFileTime(const Pathname &path, FileTimeType which, + time_t* time) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool GetAppPathname(Pathname *path) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool GetAppDataFolder(Pathname *path, bool per_user) { + EXPECT_TRUE(per_user) << "Unsupported operation"; +#ifdef WIN32 + path->SetPathname("c:\\Users\\test_user", ""); +#else + path->SetPathname("/home/user/test_user", ""); +#endif + return true; + } + bool GetAppTempFolder(Pathname *path) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + bool GetDiskFreeSpace(const Pathname &path, int64 *freebytes) { + EXPECT_TRUE(false) << "Unsupported operation"; + return false; + } + Pathname GetCurrentDirectory() { + return Pathname(); + } + + private: + const std::vector all_files_; +}; +} // namespace talk_base + +#endif // TALK_BASE_FILEUTILS_MOCK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/firewallsocketserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/firewallsocketserver.h new file mode 100644 index 0000000..5d5553e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/firewallsocketserver.h @@ -0,0 +1,137 @@ +/* + * 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 TALK_BASE_FIREWALLSOCKETSERVER_H_ +#define TALK_BASE_FIREWALLSOCKETSERVER_H_ + +#include +#include "talk/base/socketserver.h" +#include "talk/base/criticalsection.h" + +namespace talk_base { + +class FirewallManager; + +// This SocketServer shim simulates a rule-based firewall server. + +enum FirewallProtocol { FP_UDP, FP_TCP, FP_ANY }; +enum FirewallDirection { FD_IN, FD_OUT, FD_ANY }; + +class FirewallSocketServer : public SocketServer { + public: + FirewallSocketServer(SocketServer * server, + FirewallManager * manager = NULL, + bool should_delete_server = false); + virtual ~FirewallSocketServer(); + + SocketServer* socketserver() const { return server_; } + void set_socketserver(SocketServer* server) { + if (server_ && should_delete_server_) { + delete server_; + server_ = NULL; + should_delete_server_ = false; + } + server_ = server; + } + + // Settings to control whether CreateSocket or Socket::Listen succeed. + void set_udp_sockets_enabled(bool enabled) { udp_sockets_enabled_ = enabled; } + void set_tcp_sockets_enabled(bool enabled) { tcp_sockets_enabled_ = enabled; } + bool tcp_listen_enabled() const { return tcp_listen_enabled_; } + void set_tcp_listen_enabled(bool enabled) { tcp_listen_enabled_ = enabled; } + + // Rules govern the behavior of Connect/Accept/Send/Recv attempts. + void AddRule(bool allow, FirewallProtocol p = FP_ANY, + FirewallDirection d = FD_ANY, + const SocketAddress& addr = SocketAddress()); + void AddRule(bool allow, FirewallProtocol p, + const SocketAddress& src, const SocketAddress& dst); + void ClearRules(); + + bool Check(FirewallProtocol p, + const SocketAddress& src, const SocketAddress& dst); + + virtual Socket* CreateSocket(int type); + virtual Socket* CreateSocket(int family, int type); + + virtual AsyncSocket* CreateAsyncSocket(int type); + virtual AsyncSocket* CreateAsyncSocket(int family, int type); + + virtual void SetMessageQueue(MessageQueue* queue) { + server_->SetMessageQueue(queue); + } + virtual bool Wait(int cms, bool process_io) { + return server_->Wait(cms, process_io); + } + virtual void WakeUp() { + return server_->WakeUp(); + } + + Socket * WrapSocket(Socket * sock, int type); + AsyncSocket * WrapSocket(AsyncSocket * sock, int type); + + private: + SocketServer * server_; + FirewallManager * manager_; + CriticalSection crit_; + struct Rule { + bool allow; + FirewallProtocol p; + FirewallDirection d; + SocketAddress src; + SocketAddress dst; + }; + std::vector rules_; + bool should_delete_server_; + bool udp_sockets_enabled_; + bool tcp_sockets_enabled_; + bool tcp_listen_enabled_; +}; + +// FirewallManager allows you to manage firewalls in multiple threads together + +class FirewallManager { + public: + FirewallManager(); + ~FirewallManager(); + + void AddServer(FirewallSocketServer * server); + void RemoveServer(FirewallSocketServer * server); + + void AddRule(bool allow, FirewallProtocol p = FP_ANY, + FirewallDirection d = FD_ANY, + const SocketAddress& addr = SocketAddress()); + void ClearRules(); + + private: + CriticalSection crit_; + std::vector servers_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_FIREWALLSOCKETSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/flags.h b/thirdparties/common/include/webrtc-sdk/talk/base/flags.h new file mode 100644 index 0000000..c43036c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/flags.h @@ -0,0 +1,284 @@ +/* + * 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. + */ + + +// Originally comes from shared/commandlineflags/flags.h + +// Flags are defined and declared using DEFINE_xxx and DECLARE_xxx macros, +// where xxx is the flag type. Flags are referred to via FLAG_yyy, +// where yyy is the flag name. For intialization and iteration of flags, +// see the FlagList class. For full programmatic access to any +// flag, see the Flag class. +// +// The implementation only relies and basic C++ functionality +// and needs no special library or STL support. + +#ifndef TALK_BASE_FLAGS_H__ +#define TALK_BASE_FLAGS_H__ + +#include + +#include "talk/base/checks.h" +#include "talk/base/common.h" + +// Internal use only. +union FlagValue { + // Note: Because in C++ non-bool values are silently converted into + // bool values ('bool b = "false";' results in b == true!), we pass + // and int argument to New_BOOL as this appears to be safer - sigh. + // In particular, it prevents the (not uncommon!) bug where a bool + // flag is defined via: DEFINE_bool(flag, "false", "some comment");. + static FlagValue New_BOOL(int b) { + FlagValue v; + v.b = (b != 0); + return v; + } + + static FlagValue New_INT(int i) { + FlagValue v; + v.i = i; + return v; + } + + static FlagValue New_FLOAT(float f) { + FlagValue v; + v.f = f; + return v; + } + + static FlagValue New_STRING(const char* s) { + FlagValue v; + v.s = s; + return v; + } + + bool b; + int i; + double f; + const char* s; +}; + + +// Each flag can be accessed programmatically via a Flag object. +class Flag { + public: + enum Type { BOOL, INT, FLOAT, STRING }; + + // Internal use only. + Flag(const char* file, const char* name, const char* comment, + Type type, void* variable, FlagValue default_); + + // General flag information + const char* file() const { return file_; } + const char* name() const { return name_; } + const char* comment() const { return comment_; } + + // Flag type + Type type() const { return type_; } + + // Flag variables + bool* bool_variable() const { + assert(type_ == BOOL); + return &variable_->b; + } + + int* int_variable() const { + assert(type_ == INT); + return &variable_->i; + } + + double* float_variable() const { + assert(type_ == FLOAT); + return &variable_->f; + } + + const char** string_variable() const { + assert(type_ == STRING); + return &variable_->s; + } + + // Default values + bool bool_default() const { + assert(type_ == BOOL); + return default_.b; + } + + int int_default() const { + assert(type_ == INT); + return default_.i; + } + + double float_default() const { + assert(type_ == FLOAT); + return default_.f; + } + + const char* string_default() const { + assert(type_ == STRING); + return default_.s; + } + + // Resets a flag to its default value + void SetToDefault(); + + // Iteration support + Flag* next() const { return next_; } + + // Prints flag information. The current flag value is only printed + // if print_current_value is set. + void Print(bool print_current_value); + + private: + const char* file_; + const char* name_; + const char* comment_; + + Type type_; + FlagValue* variable_; + FlagValue default_; + + Flag* next_; + + friend class FlagList; // accesses next_ +}; + + +// Internal use only. +#define DEFINE_FLAG(type, c_type, name, default, comment) \ + /* define and initialize the flag */ \ + c_type FLAG_##name = (default); \ + /* register the flag */ \ + static Flag Flag_##name(__FILE__, #name, (comment), \ + Flag::type, &FLAG_##name, \ + FlagValue::New_##type(default)) + + +// Internal use only. +#define DECLARE_FLAG(c_type, name) \ + /* declare the external flag */ \ + extern c_type FLAG_##name + + +// Use the following macros to define a new flag: +#define DEFINE_bool(name, default, comment) \ + DEFINE_FLAG(BOOL, bool, name, default, comment) +#define DEFINE_int(name, default, comment) \ + DEFINE_FLAG(INT, int, name, default, comment) +#define DEFINE_float(name, default, comment) \ + DEFINE_FLAG(FLOAT, double, name, default, comment) +#define DEFINE_string(name, default, comment) \ + DEFINE_FLAG(STRING, const char*, name, default, comment) + + +// Use the following macros to declare a flag defined elsewhere: +#define DECLARE_bool(name) DECLARE_FLAG(bool, name) +#define DECLARE_int(name) DECLARE_FLAG(int, name) +#define DECLARE_float(name) DECLARE_FLAG(double, name) +#define DECLARE_string(name) DECLARE_FLAG(const char*, name) + + +// The global list of all flags. +class FlagList { + public: + FlagList(); + + // The NULL-terminated list of all flags. Traverse with Flag::next(). + static Flag* list() { return list_; } + + // If file != NULL, prints information for all flags defined in file; + // otherwise prints information for all flags in all files. The current + // flag value is only printed if print_current_value is set. + static void Print(const char* file, bool print_current_value); + + // Lookup a flag by name. Returns the matching flag or NULL. + static Flag* Lookup(const char* name); + + // Helper function to parse flags: Takes an argument arg and splits it into + // a flag name and flag value (or NULL if they are missing). is_bool is set + // if the arg started with "-no" or "--no". The buffer may be used to NUL- + // terminate the name, it must be large enough to hold any possible name. + static void SplitArgument(const char* arg, + char* buffer, int buffer_size, + const char** name, const char** value, + bool* is_bool); + + // Set the flag values by parsing the command line. If remove_flags + // is set, the flags and associated values are removed from (argc, + // argv). Returns 0 if no error occurred. Otherwise, returns the + // argv index > 0 for the argument where an error occurred. In that + // case, (argc, argv) will remain unchanged indepdendent of the + // remove_flags value, and no assumptions about flag settings should + // be made. + // + // The following syntax for flags is accepted (both '-' and '--' are ok): + // + // --flag (bool flags only) + // --noflag (bool flags only) + // --flag=value (non-bool flags only, no spaces around '=') + // --flag value (non-bool flags only) + static int SetFlagsFromCommandLine(int* argc, + const char** argv, + bool remove_flags); + static inline int SetFlagsFromCommandLine(int* argc, + char** argv, + bool remove_flags) { + return SetFlagsFromCommandLine(argc, const_cast(argv), + remove_flags); + } + + // Registers a new flag. Called during program initialization. Not + // thread-safe. + static void Register(Flag* flag); + + private: + static Flag* list_; +}; + +#ifdef WIN32 +// A helper class to translate Windows command line arguments into UTF8, +// which then allows us to just pass them to the flags system. +// This encapsulates all the work of getting the command line and translating +// it to an array of 8-bit strings; all you have to do is create one of these, +// and then call argc() and argv(). +class WindowsCommandLineArguments { + public: + WindowsCommandLineArguments(); + ~WindowsCommandLineArguments(); + + int argc() { return argc_; } + char **argv() { return argv_; } + private: + int argc_; + char **argv_; + + private: + DISALLOW_EVIL_CONSTRUCTORS(WindowsCommandLineArguments); +}; +#endif // WIN32 + + +#endif // SHARED_COMMANDLINEFLAGS_FLAGS_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/genericslot.h b/thirdparties/common/include/webrtc-sdk/talk/base/genericslot.h new file mode 100644 index 0000000..c0999a6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/genericslot.h @@ -0,0 +1,258 @@ +// This file was GENERATED by command: +// pump.py genericslot.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_GENERICSLOT_H_ +#define TALK_BASE_GENERICSLOT_H_ + +// To generate genericslot.h from genericslot.h.pump, execute: +// /home/build/google3/third_party/gtest/scripts/pump.py genericslot.h.pump + +// Generic-slots are pure slots that can be hooked up to signals. They're +// mainly intended to be used in tests where we want to check if a signal +// was invoked and what arguments were passed. NOTE: They do not do any +// lifetime management of the arguments received via callbacks. +// +// Example: +// /* Some signal */ +// sigslot::signal1 foo; +// +// /* We want to monitor foo in some test */ +// talk_base::GenericSlot1 slot(&foo, 0); +// foo.emit(5); +// EXPECT_TRUE(slot.callback_received()); +// EXPECT_EQ(5, *(slot.arg1())); +// + +#include "talk/base/constructormagic.h" +#include "talk/base/sigslot.h" + +namespace talk_base { + +template +class GenericSlot1 : public sigslot::has_slots<> { + public: + GenericSlot1(sigslot::signal1* signal, + const A1& arg1_initial) + : arg1_initial_(arg1_initial) { + Reset(); + signal->connect(this, &GenericSlot1::OnSignalCallback); + } + + void Reset() { + callback_received_ = false; + arg1_ = arg1_initial_; + } + + bool callback_received() const { return callback_received_; } + const A1& arg1() const { return arg1_; } + + private: + void OnSignalCallback(A1 arg1) { + callback_received_ = true; + arg1_ = arg1; + } + + bool callback_received_; + A1 arg1_initial_, arg1_; + + DISALLOW_COPY_AND_ASSIGN(GenericSlot1); +}; + +template +class GenericSlot2 : public sigslot::has_slots<> { + public: + GenericSlot2(sigslot::signal2* signal, + const A1& arg1_initial, const A2& arg2_initial) + : arg1_initial_(arg1_initial), arg2_initial_(arg2_initial) { + Reset(); + signal->connect(this, &GenericSlot2::OnSignalCallback); + } + + void Reset() { + callback_received_ = false; + arg1_ = arg1_initial_; + arg2_ = arg2_initial_; + } + + bool callback_received() const { return callback_received_; } + const A1& arg1() const { return arg1_; } + const A2& arg2() const { return arg2_; } + + private: + void OnSignalCallback(A1 arg1, A2 arg2) { + callback_received_ = true; + arg1_ = arg1; + arg2_ = arg2; + } + + bool callback_received_; + A1 arg1_initial_, arg1_; + A2 arg2_initial_, arg2_; + + DISALLOW_COPY_AND_ASSIGN(GenericSlot2); +}; + +template +class GenericSlot3 : public sigslot::has_slots<> { + public: + GenericSlot3(sigslot::signal3* signal, + const A1& arg1_initial, const A2& arg2_initial, + const A3& arg3_initial) + : arg1_initial_(arg1_initial), arg2_initial_(arg2_initial), + arg3_initial_(arg3_initial) { + Reset(); + signal->connect(this, &GenericSlot3::OnSignalCallback); + } + + void Reset() { + callback_received_ = false; + arg1_ = arg1_initial_; + arg2_ = arg2_initial_; + arg3_ = arg3_initial_; + } + + bool callback_received() const { return callback_received_; } + const A1& arg1() const { return arg1_; } + const A2& arg2() const { return arg2_; } + const A3& arg3() const { return arg3_; } + + private: + void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3) { + callback_received_ = true; + arg1_ = arg1; + arg2_ = arg2; + arg3_ = arg3; + } + + bool callback_received_; + A1 arg1_initial_, arg1_; + A2 arg2_initial_, arg2_; + A3 arg3_initial_, arg3_; + + DISALLOW_COPY_AND_ASSIGN(GenericSlot3); +}; + +template +class GenericSlot4 : public sigslot::has_slots<> { + public: + GenericSlot4(sigslot::signal4* signal, + const A1& arg1_initial, const A2& arg2_initial, + const A3& arg3_initial, const A4& arg4_initial) + : arg1_initial_(arg1_initial), arg2_initial_(arg2_initial), + arg3_initial_(arg3_initial), arg4_initial_(arg4_initial) { + Reset(); + signal->connect(this, &GenericSlot4::OnSignalCallback); + } + + void Reset() { + callback_received_ = false; + arg1_ = arg1_initial_; + arg2_ = arg2_initial_; + arg3_ = arg3_initial_; + arg4_ = arg4_initial_; + } + + bool callback_received() const { return callback_received_; } + const A1& arg1() const { return arg1_; } + const A2& arg2() const { return arg2_; } + const A3& arg3() const { return arg3_; } + const A4& arg4() const { return arg4_; } + + private: + void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3, A4 arg4) { + callback_received_ = true; + arg1_ = arg1; + arg2_ = arg2; + arg3_ = arg3; + arg4_ = arg4; + } + + bool callback_received_; + A1 arg1_initial_, arg1_; + A2 arg2_initial_, arg2_; + A3 arg3_initial_, arg3_; + A4 arg4_initial_, arg4_; + + DISALLOW_COPY_AND_ASSIGN(GenericSlot4); +}; + +template +class GenericSlot5 : public sigslot::has_slots<> { + public: + GenericSlot5(sigslot::signal5* signal, + const A1& arg1_initial, const A2& arg2_initial, + const A3& arg3_initial, const A4& arg4_initial, + const A5& arg5_initial) + : arg1_initial_(arg1_initial), arg2_initial_(arg2_initial), + arg3_initial_(arg3_initial), arg4_initial_(arg4_initial), + arg5_initial_(arg5_initial) { + Reset(); + signal->connect(this, &GenericSlot5::OnSignalCallback); + } + + void Reset() { + callback_received_ = false; + arg1_ = arg1_initial_; + arg2_ = arg2_initial_; + arg3_ = arg3_initial_; + arg4_ = arg4_initial_; + arg5_ = arg5_initial_; + } + + bool callback_received() const { return callback_received_; } + const A1& arg1() const { return arg1_; } + const A2& arg2() const { return arg2_; } + const A3& arg3() const { return arg3_; } + const A4& arg4() const { return arg4_; } + const A5& arg5() const { return arg5_; } + + private: + void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) { + callback_received_ = true; + arg1_ = arg1; + arg2_ = arg2; + arg3_ = arg3; + arg4_ = arg4; + arg5_ = arg5; + } + + bool callback_received_; + A1 arg1_initial_, arg1_; + A2 arg2_initial_, arg2_; + A3 arg3_initial_, arg3_; + A4 arg4_initial_, arg4_; + A5 arg5_initial_, arg5_; + + DISALLOW_COPY_AND_ASSIGN(GenericSlot5); +}; +} // namespace talk_base + +#endif // TALK_BASE_GENERICSLOT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/gunit.h b/thirdparties/common/include/webrtc-sdk/talk/base/gunit.h new file mode 100644 index 0000000..9edfd7e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/gunit.h @@ -0,0 +1,105 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_GUNIT_H_ +#define TALK_BASE_GUNIT_H_ + +#include "talk/base/logging.h" +#include "talk/base/thread.h" +#if defined(ANDROID) || defined(GTEST_RELATIVE_PATH) +#include "gtest/gtest.h" +#else +#include "testing/base/public/gunit.h" +#endif + +// Wait until "ex" is true, or "timeout" expires. +#define WAIT(ex, timeout) \ + for (uint32 start = talk_base::Time(); \ + !(ex) && talk_base::Time() < start + timeout;) \ + talk_base::Thread::Current()->ProcessMessages(1); + +// This returns the result of the test in res, so that we don't re-evaluate +// the expression in the XXXX_WAIT macros below, since that causes problems +// when the expression is only true the first time you check it. +#define WAIT_(ex, timeout, res) \ + do { \ + uint32 start = talk_base::Time(); \ + res = (ex); \ + while (!res && talk_base::Time() < start + timeout) { \ + talk_base::Thread::Current()->ProcessMessages(1); \ + res = (ex); \ + } \ + } while (0); + +// The typical EXPECT_XXXX and ASSERT_XXXXs, but done until true or a timeout. +#define EXPECT_TRUE_WAIT(ex, timeout) \ + do { \ + bool res; \ + WAIT_(ex, timeout, res); \ + if (!res) EXPECT_TRUE(ex); \ + } while (0); + +#define EXPECT_EQ_WAIT(v1, v2, timeout) \ + do { \ + bool res; \ + WAIT_(v1 == v2, timeout, res); \ + if (!res) EXPECT_EQ(v1, v2); \ + } while (0); + +#define ASSERT_TRUE_WAIT(ex, timeout) \ + do { \ + bool res; \ + WAIT_(ex, timeout, res); \ + if (!res) ASSERT_TRUE(ex); \ + } while (0); + +#define ASSERT_EQ_WAIT(v1, v2, timeout) \ + do { \ + bool res; \ + WAIT_(v1 == v2, timeout, res); \ + if (!res) ASSERT_EQ(v1, v2); \ + } while (0); + +// Version with a "soft" timeout and a margin. This logs if the timeout is +// exceeded, but it only fails if the expression still isn't true after the +// margin time passes. +#define EXPECT_TRUE_WAIT_MARGIN(ex, timeout, margin) \ + do { \ + bool res; \ + WAIT_(ex, timeout, res); \ + if (res) { \ + break; \ + } \ + LOG(LS_WARNING) << "Expression " << #ex << " still not true after " << \ + timeout << "ms; waiting an additional " << margin << "ms"; \ + WAIT_(ex, margin, res); \ + if (!res) { \ + EXPECT_TRUE(ex); \ + } \ + } while (0); + +#endif // TALK_BASE_GUNIT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/gunit_prod.h b/thirdparties/common/include/webrtc-sdk/talk/base/gunit_prod.h new file mode 100644 index 0000000..843148f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/gunit_prod.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_GUNIT_PROD_H_ +#define TALK_BASE_GUNIT_PROD_H_ + +#if defined(ANDROID) +// Android doesn't use gtest at all, so anything that relies on gtest should +// check this define first. +#define NO_GTEST +#elif defined (GTEST_RELATIVE_PATH) +#include "gtest/gtest_prod.h" +#else +#include "testing/base/gunit_prod.h" +#endif + +#endif // TALK_BASE_GUNIT_PROD_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/helpers.h b/thirdparties/common/include/webrtc-sdk/talk/base/helpers.h new file mode 100644 index 0000000..f4d2aaa --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/helpers.h @@ -0,0 +1,73 @@ +/* + * 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 TALK_BASE_HELPERS_H_ +#define TALK_BASE_HELPERS_H_ + +#include +#include "talk/base/basictypes.h" + +namespace talk_base { + +// For testing, we can return predictable data. +void SetRandomTestMode(bool test); + +// Initializes the RNG, and seeds it with the specified entropy. +bool InitRandom(int seed); +bool InitRandom(const char* seed, size_t len); + +// Generates a (cryptographically) random string of the given length. +// We generate base64 values so that they will be printable. +// WARNING: could silently fail. Use the version below instead. +std::string CreateRandomString(size_t length); + +// Generates a (cryptographically) random string of the given length. +// We generate base64 values so that they will be printable. +// Return false if the random number generator failed. +bool CreateRandomString(size_t length, std::string* str); + +// Generates a (cryptographically) random string of the given length, +// with characters from the given table. Return false if the random +// number generator failed. +bool CreateRandomString(size_t length, const std::string& table, + std::string* str); + +// Generates a random id. +uint32 CreateRandomId(); + +// Generates a 64 bit random id. +uint64 CreateRandomId64(); + +// Generates a random id > 0. +uint32 CreateRandomNonZeroId(); + +// Generates a random double between 0.0 (inclusive) and 1.0 (exclusive). +double CreateRandomDouble(); + +} // namespace talk_base + +#endif // TALK_BASE_HELPERS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/httpbase.h b/thirdparties/common/include/webrtc-sdk/talk/base/httpbase.h new file mode 100644 index 0000000..9fc725a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/httpbase.h @@ -0,0 +1,201 @@ +/* + * 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. + */ + +// Copyright 2005 Google Inc. All Rights Reserved. +// + + +#ifndef TALK_BASE_HTTPBASE_H__ +#define TALK_BASE_HTTPBASE_H__ + +#include "talk/base/httpcommon.h" + +namespace talk_base { + +class StreamInterface; + +/////////////////////////////////////////////////////////////////////////////// +// HttpParser - Parses an HTTP stream provided via Process and end_of_input, and +// generates events for: +// Structural Elements: Leader, Headers, Document Data +// Events: End of Headers, End of Document, Errors +/////////////////////////////////////////////////////////////////////////////// + +class HttpParser { +public: + enum ProcessResult { PR_CONTINUE, PR_BLOCK, PR_COMPLETE }; + HttpParser(); + virtual ~HttpParser(); + + void reset(); + ProcessResult Process(const char* buffer, size_t len, size_t* processed, + HttpError* error); + bool is_valid_end_of_input() const; + void complete(HttpError err); + + size_t GetDataRemaining() const { return data_size_; } + +protected: + ProcessResult ProcessLine(const char* line, size_t len, HttpError* error); + + // HttpParser Interface + virtual ProcessResult ProcessLeader(const char* line, size_t len, + HttpError* error) = 0; + virtual ProcessResult ProcessHeader(const char* name, size_t nlen, + const char* value, size_t vlen, + HttpError* error) = 0; + virtual ProcessResult ProcessHeaderComplete(bool chunked, size_t& data_size, + HttpError* error) = 0; + virtual ProcessResult ProcessData(const char* data, size_t len, size_t& read, + HttpError* error) = 0; + virtual void OnComplete(HttpError err) = 0; + +private: + enum State { + ST_LEADER, ST_HEADERS, + ST_CHUNKSIZE, ST_CHUNKTERM, ST_TRAILERS, + ST_DATA, ST_COMPLETE + } state_; + bool chunked_; + size_t data_size_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// IHttpNotify +/////////////////////////////////////////////////////////////////////////////// + +enum HttpMode { HM_NONE, HM_CONNECT, HM_RECV, HM_SEND }; + +class IHttpNotify { +public: + virtual ~IHttpNotify() {} + virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size) = 0; + virtual void onHttpComplete(HttpMode mode, HttpError err) = 0; + virtual void onHttpClosed(HttpError err) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// HttpBase - Provides a state machine for implementing HTTP-based components. +// Attach HttpBase to a StreamInterface which represents a bidirectional HTTP +// stream, and then call send() or recv() to initiate sending or receiving one +// side of an HTTP transaction. By default, HttpBase operates as an I/O pump, +// moving data from the HTTP stream to the HttpData object and vice versa. +// However, it can also operate in stream mode, in which case the user of the +// stream interface drives I/O via calls to Read(). +/////////////////////////////////////////////////////////////////////////////// + +class HttpBase +: private HttpParser, + public sigslot::has_slots<> +{ +public: + HttpBase(); + virtual ~HttpBase(); + + void notify(IHttpNotify* notify) { notify_ = notify; } + bool attach(StreamInterface* stream); + StreamInterface* stream() { return http_stream_; } + StreamInterface* detach(); + bool isConnected() const; + + void send(HttpData* data); + void recv(HttpData* data); + void abort(HttpError err); + + HttpMode mode() const { return mode_; } + + void set_ignore_data(bool ignore) { ignore_data_ = ignore; } + bool ignore_data() const { return ignore_data_; } + + // Obtaining this stream puts HttpBase into stream mode until the stream + // is closed. HttpBase can only expose one open stream interface at a time. + // Further calls will return NULL. + StreamInterface* GetDocumentStream(); + +protected: + // Do cleanup when the http stream closes (error may be 0 for a clean + // shutdown), and return the error code to signal. + HttpError HandleStreamClose(int error); + + // DoReceiveLoop acts as a data pump, pulling data from the http stream, + // pushing it through the HttpParser, and then populating the HttpData object + // based on the callbacks from the parser. One of the most interesting + // callbacks is ProcessData, which provides the actual http document body. + // This data is then written to the HttpData::document. As a result, data + // flows from the network to the document, with some incidental protocol + // parsing in between. + // Ideally, we would pass in the document* to DoReceiveLoop, to more easily + // support GetDocumentStream(). However, since the HttpParser is callback + // driven, we are forced to store the pointer somewhere until the callback + // is triggered. + // Returns true if the received document has finished, and + // HttpParser::complete should be called. + bool DoReceiveLoop(HttpError* err); + + void read_and_process_data(); + void flush_data(); + bool queue_headers(); + void do_complete(HttpError err = HE_NONE); + + void OnHttpStreamEvent(StreamInterface* stream, int events, int error); + void OnDocumentEvent(StreamInterface* stream, int events, int error); + + // HttpParser Interface + virtual ProcessResult ProcessLeader(const char* line, size_t len, + HttpError* error); + virtual ProcessResult ProcessHeader(const char* name, size_t nlen, + const char* value, size_t vlen, + HttpError* error); + virtual ProcessResult ProcessHeaderComplete(bool chunked, size_t& data_size, + HttpError* error); + virtual ProcessResult ProcessData(const char* data, size_t len, size_t& read, + HttpError* error); + virtual void OnComplete(HttpError err); + +private: + class DocumentStream; + friend class DocumentStream; + + enum { kBufferSize = 32 * 1024 }; + + HttpMode mode_; + HttpData* data_; + IHttpNotify* notify_; + StreamInterface* http_stream_; + DocumentStream* doc_stream_; + char buffer_[kBufferSize]; + size_t len_; + + bool ignore_data_, chunk_data_; + HttpData::const_iterator header_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_HTTPBASE_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/httpclient.h b/thirdparties/common/include/webrtc-sdk/talk/base/httpclient.h new file mode 100644 index 0000000..a1f48cc --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/httpclient.h @@ -0,0 +1,219 @@ +/* + * 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 TALK_BASE_HTTPCLIENT_H__ +#define TALK_BASE_HTTPCLIENT_H__ + +#include "talk/base/common.h" +#include "talk/base/httpbase.h" +#include "talk/base/nethelpers.h" +#include "talk/base/proxyinfo.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sigslot.h" +#include "talk/base/socketaddress.h" +#include "talk/base/socketpool.h" + +namespace talk_base { + +////////////////////////////////////////////////////////////////////// +// Client-specific http utilities +////////////////////////////////////////////////////////////////////// + +// Write cache-relevant response headers to output stream. If size is non-null, +// it contains the length of the output in bytes. output may be null if only +// the length is desired. +bool HttpWriteCacheHeaders(const HttpResponseData* response, + StreamInterface* output, size_t* size); +// Read cached headers from a stream, and them merge them into the response +// object using the specified combine operation. +bool HttpReadCacheHeaders(StreamInterface* input, + HttpResponseData* response, + HttpData::HeaderCombine combine); + +////////////////////////////////////////////////////////////////////// +// HttpClient +// Implements an HTTP 1.1 client. +////////////////////////////////////////////////////////////////////// + +class DiskCache; +class HttpClient; +class IPNetPool; + +class SignalThread; +// What to do: Define STRICT_HTTP_ERROR=1 in your makefile. Use HttpError in +// your code (HttpErrorType should only be used for code that is shared +// with groups which have not yet migrated). +#if STRICT_HTTP_ERROR +typedef HttpError HttpErrorType; +#else // !STRICT_HTTP_ERROR +typedef int HttpErrorType; +#endif // !STRICT_HTTP_ERROR + +class HttpClient : private IHttpNotify, public sigslot::has_slots<> { +public: + // If HttpRequestData and HttpResponseData objects are provided, they must + // be freed by the caller. Otherwise, an internal object is allocated. + HttpClient(const std::string& agent, StreamPool* pool, + HttpTransaction* transaction = NULL); + virtual ~HttpClient(); + + void set_pool(StreamPool* pool) { pool_ = pool; } + + void set_agent(const std::string& agent) { agent_ = agent; } + const std::string& agent() const { return agent_; } + + void set_proxy(const ProxyInfo& proxy) { proxy_ = proxy; } + const ProxyInfo& proxy() const { return proxy_; } + + // Request retries occur when the connection closes before the beginning of + // an http response is received. In these cases, the http server may have + // timed out the keepalive connection before it received our request. Note + // that if a request document cannot be rewound, no retry is made. The + // default is 1. + void set_request_retries(size_t retries) { retries_ = retries; } + size_t request_retries() const { return retries_; } + + enum RedirectAction { REDIRECT_DEFAULT, REDIRECT_ALWAYS, REDIRECT_NEVER }; + void set_redirect_action(RedirectAction action) { redirect_action_ = action; } + RedirectAction redirect_action() const { return redirect_action_; } + // Deprecated + void set_fail_redirect(bool fail_redirect) { + redirect_action_ = REDIRECT_NEVER; + } + bool fail_redirect() const { return (REDIRECT_NEVER == redirect_action_); } + + enum UriForm { URI_DEFAULT, URI_ABSOLUTE, URI_RELATIVE }; + void set_uri_form(UriForm form) { uri_form_ = form; } + UriForm uri_form() const { return uri_form_; } + + void set_cache(DiskCache* cache) { ASSERT(!IsCacheActive()); cache_ = cache; } + bool cache_enabled() const { return (NULL != cache_); } + + // reset clears the server, request, and response structures. It will also + // abort an active request. + void reset(); + + void set_server(const SocketAddress& address); + const SocketAddress& server() const { return server_; } + + // Note: in order for HttpClient to retry a POST in response to + // an authentication challenge, a redirect response, or socket disconnection, + // the request document must support 'replaying' by calling Rewind() on it. + // In the case where just a subset of a stream should be used as the request + // document, the stream may be wrapped with the StreamSegment adapter. + HttpTransaction* transaction() { return transaction_; } + const HttpTransaction* transaction() const { return transaction_; } + HttpRequestData& request() { return transaction_->request; } + const HttpRequestData& request() const { return transaction_->request; } + HttpResponseData& response() { return transaction_->response; } + const HttpResponseData& response() const { return transaction_->response; } + + // convenience methods + void prepare_get(const std::string& url); + void prepare_post(const std::string& url, const std::string& content_type, + StreamInterface* request_doc); + + // Convert HttpClient to a pull-based I/O model. + StreamInterface* GetDocumentStream(); + + // After you finish setting up your request, call start. + void start(); + + // Signalled when the header has finished downloading, before the document + // content is processed. You may change the response document in response + // to this signal. The second parameter indicates whether this is an + // intermediate (false) or final (true) header. An intermediate header is + // one that generates another request, such as a redirect or authentication + // challenge. The third parameter indicates the length of the response + // document, or else SIZE_UNKNOWN. Note: Do NOT abort the request in response + // to this signal. + sigslot::signal3 SignalHeaderAvailable; + // Signalled when the current request finishes. On success, err is 0. + sigslot::signal2 SignalHttpClientComplete; + +protected: + void connect(); + void release(); + + bool ShouldRedirect(std::string* location) const; + + bool BeginCacheFile(); + HttpError WriteCacheHeaders(const std::string& id); + void CompleteCacheFile(); + + bool CheckCache(); + HttpError ReadCacheHeaders(const std::string& id, bool override); + HttpError ReadCacheBody(const std::string& id); + + bool PrepareValidate(); + HttpError CompleteValidate(); + + HttpError OnHeaderAvailable(bool ignore_data, bool chunked, size_t data_size); + + void StartDNSLookup(); + void OnResolveResult(AsyncResolverInterface* resolver); + + // IHttpNotify Interface + virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size); + virtual void onHttpComplete(HttpMode mode, HttpError err); + virtual void onHttpClosed(HttpError err); + +private: + enum CacheState { CS_READY, CS_WRITING, CS_READING, CS_VALIDATING }; + bool IsCacheActive() const { return (cache_state_ > CS_READY); } + + std::string agent_; + StreamPool* pool_; + HttpBase base_; + SocketAddress server_; + ProxyInfo proxy_; + HttpTransaction* transaction_; + bool free_transaction_; + size_t retries_, attempt_, redirects_; + RedirectAction redirect_action_; + UriForm uri_form_; + scoped_ptr context_; + DiskCache* cache_; + CacheState cache_state_; + AsyncResolverInterface* resolver_; +}; + +////////////////////////////////////////////////////////////////////// +// HttpClientDefault - Default implementation of HttpClient +////////////////////////////////////////////////////////////////////// + +class HttpClientDefault : public ReuseSocketPool, public HttpClient { +public: + HttpClientDefault(SocketFactory* factory, const std::string& agent, + HttpTransaction* transaction = NULL); +}; + +////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_HTTPCLIENT_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/httpcommon-inl.h b/thirdparties/common/include/webrtc-sdk/talk/base/httpcommon-inl.h new file mode 100644 index 0000000..48d62d7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/httpcommon-inl.h @@ -0,0 +1,148 @@ +/* + * 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 TALK_BASE_HTTPCOMMON_INL_H__ +#define TALK_BASE_HTTPCOMMON_INL_H__ + +#include "talk/base/common.h" +#include "talk/base/httpcommon.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// Url +/////////////////////////////////////////////////////////////////////////////// + +template +void Url::do_set_url(const CTYPE* val, size_t len) { + if (ascnicmp(val, "http://", 7) == 0) { + val += 7; len -= 7; + secure_ = false; + } else if (ascnicmp(val, "https://", 8) == 0) { + val += 8; len -= 8; + secure_ = true; + } else { + clear(); + return; + } + const CTYPE* path = strchrn(val, len, static_cast('/')); + if (!path) { + path = val + len; + } + size_t address_length = (path - val); + do_set_address(val, address_length); + do_set_full_path(path, len - address_length); +} + +template +void Url::do_set_address(const CTYPE* val, size_t len) { + if (const CTYPE* at = strchrn(val, len, static_cast('@'))) { + // Everything before the @ is a user:password combo, so skip it. + len -= at - val + 1; + val = at + 1; + } + if (const CTYPE* colon = strchrn(val, len, static_cast(':'))) { + host_.assign(val, colon - val); + // Note: In every case, we're guaranteed that colon is followed by a null, + // or non-numeric character. + port_ = static_cast(::strtoul(colon + 1, NULL, 10)); + // TODO: Consider checking for invalid data following port number. + } else { + host_.assign(val, len); + port_ = HttpDefaultPort(secure_); + } +} + +template +void Url::do_set_full_path(const CTYPE* val, size_t len) { + const CTYPE* query = strchrn(val, len, static_cast('?')); + if (!query) { + query = val + len; + } + size_t path_length = (query - val); + if (0 == path_length) { + // TODO: consider failing in this case. + path_.assign(1, static_cast('/')); + } else { + ASSERT(val[0] == static_cast('/')); + path_.assign(val, path_length); + } + query_.assign(query, len - path_length); +} + +template +void Url::do_get_url(string* val) const { + CTYPE protocol[9]; + asccpyn(protocol, ARRAY_SIZE(protocol), secure_ ? "https://" : "http://"); + val->append(protocol); + do_get_address(val); + do_get_full_path(val); +} + +template +void Url::do_get_address(string* val) const { + val->append(host_); + if (port_ != HttpDefaultPort(secure_)) { + CTYPE format[5], port[32]; + asccpyn(format, ARRAY_SIZE(format), ":%hu"); + sprintfn(port, ARRAY_SIZE(port), format, port_); + val->append(port); + } +} + +template +void Url::do_get_full_path(string* val) const { + val->append(path_); + val->append(query_); +} + +template +bool Url::get_attribute(const string& name, string* value) const { + if (query_.empty()) + return false; + + std::string::size_type pos = query_.find(name, 1); + if (std::string::npos == pos) + return false; + + pos += name.length() + 1; + if ((pos > query_.length()) || (static_cast('=') != query_[pos-1])) + return false; + + std::string::size_type end = query_.find(static_cast('&'), pos); + if (std::string::npos == end) { + end = query_.length(); + } + value->assign(query_.substr(pos, end - pos)); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_HTTPCOMMON_INL_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/httpcommon.h b/thirdparties/common/include/webrtc-sdk/talk/base/httpcommon.h new file mode 100644 index 0000000..797dbc6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/httpcommon.h @@ -0,0 +1,463 @@ +/* + * 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 TALK_BASE_HTTPCOMMON_H__ +#define TALK_BASE_HTTPCOMMON_H__ + +#include +#include +#include +#include "talk/base/basictypes.h" +#include "talk/base/common.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/stringutils.h" +#include "talk/base/stream.h" + +namespace talk_base { + +class CryptString; +class SocketAddress; + +////////////////////////////////////////////////////////////////////// +// Constants +////////////////////////////////////////////////////////////////////// + +enum HttpCode { + HC_OK = 200, + HC_NON_AUTHORITATIVE = 203, + HC_NO_CONTENT = 204, + HC_PARTIAL_CONTENT = 206, + + HC_MULTIPLE_CHOICES = 300, + HC_MOVED_PERMANENTLY = 301, + HC_FOUND = 302, + HC_SEE_OTHER = 303, + HC_NOT_MODIFIED = 304, + HC_MOVED_TEMPORARILY = 307, + + HC_BAD_REQUEST = 400, + HC_UNAUTHORIZED = 401, + HC_FORBIDDEN = 403, + HC_NOT_FOUND = 404, + HC_PROXY_AUTHENTICATION_REQUIRED = 407, + HC_GONE = 410, + + HC_INTERNAL_SERVER_ERROR = 500, + HC_NOT_IMPLEMENTED = 501, + HC_SERVICE_UNAVAILABLE = 503, +}; + +enum HttpVersion { + HVER_1_0, HVER_1_1, HVER_UNKNOWN, + HVER_LAST = HVER_UNKNOWN +}; + +enum HttpVerb { + HV_GET, HV_POST, HV_PUT, HV_DELETE, HV_CONNECT, HV_HEAD, + HV_LAST = HV_HEAD +}; + +enum HttpError { + HE_NONE, + HE_PROTOCOL, // Received non-valid HTTP data + HE_DISCONNECTED, // Connection closed unexpectedly + HE_OVERFLOW, // Received too much data for internal buffers + HE_CONNECT_FAILED, // The socket failed to connect. + HE_SOCKET_ERROR, // An error occurred on a connected socket + HE_SHUTDOWN, // Http object is being destroyed + HE_OPERATION_CANCELLED, // Connection aborted locally + HE_AUTH, // Proxy Authentication Required + HE_CERTIFICATE_EXPIRED, // During SSL negotiation + HE_STREAM, // Problem reading or writing to the document + HE_CACHE, // Problem reading from cache + HE_DEFAULT +}; + +enum HttpHeader { + HH_AGE, + HH_CACHE_CONTROL, + HH_CONNECTION, + HH_CONTENT_DISPOSITION, + HH_CONTENT_LENGTH, + HH_CONTENT_RANGE, + HH_CONTENT_TYPE, + HH_COOKIE, + HH_DATE, + HH_ETAG, + HH_EXPIRES, + HH_HOST, + HH_IF_MODIFIED_SINCE, + HH_IF_NONE_MATCH, + HH_KEEP_ALIVE, + HH_LAST_MODIFIED, + HH_LOCATION, + HH_PROXY_AUTHENTICATE, + HH_PROXY_AUTHORIZATION, + HH_PROXY_CONNECTION, + HH_RANGE, + HH_SET_COOKIE, + HH_TE, + HH_TRAILERS, + HH_TRANSFER_ENCODING, + HH_UPGRADE, + HH_USER_AGENT, + HH_WWW_AUTHENTICATE, + HH_LAST = HH_WWW_AUTHENTICATE +}; + +const uint16 HTTP_DEFAULT_PORT = 80; +const uint16 HTTP_SECURE_PORT = 443; + +////////////////////////////////////////////////////////////////////// +// Utility Functions +////////////////////////////////////////////////////////////////////// + +inline HttpError mkerr(HttpError err, HttpError def_err = HE_DEFAULT) { + return (err != HE_NONE) ? err : def_err; +} + +const char* ToString(HttpVersion version); +bool FromString(HttpVersion& version, const std::string& str); + +const char* ToString(HttpVerb verb); +bool FromString(HttpVerb& verb, const std::string& str); + +const char* ToString(HttpHeader header); +bool FromString(HttpHeader& header, const std::string& str); + +inline bool HttpCodeIsInformational(uint32 code) { return ((code / 100) == 1); } +inline bool HttpCodeIsSuccessful(uint32 code) { return ((code / 100) == 2); } +inline bool HttpCodeIsRedirection(uint32 code) { return ((code / 100) == 3); } +inline bool HttpCodeIsClientError(uint32 code) { return ((code / 100) == 4); } +inline bool HttpCodeIsServerError(uint32 code) { return ((code / 100) == 5); } + +bool HttpCodeHasBody(uint32 code); +bool HttpCodeIsCacheable(uint32 code); +bool HttpHeaderIsEndToEnd(HttpHeader header); +bool HttpHeaderIsCollapsible(HttpHeader header); + +struct HttpData; +bool HttpShouldKeepAlive(const HttpData& data); + +typedef std::pair HttpAttribute; +typedef std::vector HttpAttributeList; +void HttpComposeAttributes(const HttpAttributeList& attributes, char separator, + std::string* composed); +void HttpParseAttributes(const char * data, size_t len, + HttpAttributeList& attributes); +bool HttpHasAttribute(const HttpAttributeList& attributes, + const std::string& name, + std::string* value); +bool HttpHasNthAttribute(HttpAttributeList& attributes, + size_t index, + std::string* name, + std::string* value); + +// Convert RFC1123 date (DoW, DD Mon YYYY HH:MM:SS TZ) to unix timestamp +bool HttpDateToSeconds(const std::string& date, time_t* seconds); + +inline uint16 HttpDefaultPort(bool secure) { + return secure ? HTTP_SECURE_PORT : HTTP_DEFAULT_PORT; +} + +// Returns the http server notation for a given address +std::string HttpAddress(const SocketAddress& address, bool secure); + +// functional for insensitive std::string compare +struct iless { + bool operator()(const std::string& lhs, const std::string& rhs) const { + return (::_stricmp(lhs.c_str(), rhs.c_str()) < 0); + } +}; + +// put quotes around a string and escape any quotes inside it +std::string quote(const std::string& str); + +////////////////////////////////////////////////////////////////////// +// Url +////////////////////////////////////////////////////////////////////// + +template +class Url { +public: + typedef typename Traits::string string; + + // TODO: Implement Encode/Decode + static int Encode(const CTYPE* source, CTYPE* destination, size_t len); + static int Encode(const string& source, string& destination); + static int Decode(const CTYPE* source, CTYPE* destination, size_t len); + static int Decode(const string& source, string& destination); + + Url(const string& url) { do_set_url(url.c_str(), url.size()); } + Url(const string& path, const string& host, uint16 port = HTTP_DEFAULT_PORT) + : host_(host), port_(port), secure_(HTTP_SECURE_PORT == port) + { set_full_path(path); } + + bool valid() const { return !host_.empty(); } + void clear() { + host_.clear(); + port_ = HTTP_DEFAULT_PORT; + secure_ = false; + path_.assign(1, static_cast('/')); + query_.clear(); + } + + void set_url(const string& val) { + do_set_url(val.c_str(), val.size()); + } + string url() const { + string val; do_get_url(&val); return val; + } + + void set_address(const string& val) { + do_set_address(val.c_str(), val.size()); + } + string address() const { + string val; do_get_address(&val); return val; + } + + void set_full_path(const string& val) { + do_set_full_path(val.c_str(), val.size()); + } + string full_path() const { + string val; do_get_full_path(&val); return val; + } + + void set_host(const string& val) { host_ = val; } + const string& host() const { return host_; } + + void set_port(uint16 val) { port_ = val; } + uint16 port() const { return port_; } + + void set_secure(bool val) { secure_ = val; } + bool secure() const { return secure_; } + + void set_path(const string& val) { + if (val.empty()) { + path_.assign(1, static_cast('/')); + } else { + ASSERT(val[0] == static_cast('/')); + path_ = val; + } + } + const string& path() const { return path_; } + + void set_query(const string& val) { + ASSERT(val.empty() || (val[0] == static_cast('?'))); + query_ = val; + } + const string& query() const { return query_; } + + bool get_attribute(const string& name, string* value) const; + +private: + void do_set_url(const CTYPE* val, size_t len); + void do_set_address(const CTYPE* val, size_t len); + void do_set_full_path(const CTYPE* val, size_t len); + + void do_get_url(string* val) const; + void do_get_address(string* val) const; + void do_get_full_path(string* val) const; + + string host_, path_, query_; + uint16 port_; + bool secure_; +}; + +////////////////////////////////////////////////////////////////////// +// HttpData +////////////////////////////////////////////////////////////////////// + +struct HttpData { + typedef std::multimap HeaderMap; + typedef HeaderMap::const_iterator const_iterator; + typedef HeaderMap::iterator iterator; + + HttpVersion version; + scoped_ptr document; + + HttpData() : version(HVER_1_1) { } + + enum HeaderCombine { HC_YES, HC_NO, HC_AUTO, HC_REPLACE, HC_NEW }; + void changeHeader(const std::string& name, const std::string& value, + HeaderCombine combine); + inline void addHeader(const std::string& name, const std::string& value, + bool append = true) { + changeHeader(name, value, append ? HC_AUTO : HC_NO); + } + inline void setHeader(const std::string& name, const std::string& value, + bool overwrite = true) { + changeHeader(name, value, overwrite ? HC_REPLACE : HC_NEW); + } + // Returns count of erased headers + size_t clearHeader(const std::string& name); + // Returns iterator to next header + iterator clearHeader(iterator header); + + // keep in mind, this may not do what you want in the face of multiple headers + bool hasHeader(const std::string& name, std::string* value) const; + + inline const_iterator begin() const { + return headers_.begin(); + } + inline const_iterator end() const { + return headers_.end(); + } + inline iterator begin() { + return headers_.begin(); + } + inline iterator end() { + return headers_.end(); + } + inline const_iterator begin(const std::string& name) const { + return headers_.lower_bound(name); + } + inline const_iterator end(const std::string& name) const { + return headers_.upper_bound(name); + } + inline iterator begin(const std::string& name) { + return headers_.lower_bound(name); + } + inline iterator end(const std::string& name) { + return headers_.upper_bound(name); + } + + // Convenience methods using HttpHeader + inline void changeHeader(HttpHeader header, const std::string& value, + HeaderCombine combine) { + changeHeader(ToString(header), value, combine); + } + inline void addHeader(HttpHeader header, const std::string& value, + bool append = true) { + addHeader(ToString(header), value, append); + } + inline void setHeader(HttpHeader header, const std::string& value, + bool overwrite = true) { + setHeader(ToString(header), value, overwrite); + } + inline void clearHeader(HttpHeader header) { + clearHeader(ToString(header)); + } + inline bool hasHeader(HttpHeader header, std::string* value) const { + return hasHeader(ToString(header), value); + } + inline const_iterator begin(HttpHeader header) const { + return headers_.lower_bound(ToString(header)); + } + inline const_iterator end(HttpHeader header) const { + return headers_.upper_bound(ToString(header)); + } + inline iterator begin(HttpHeader header) { + return headers_.lower_bound(ToString(header)); + } + inline iterator end(HttpHeader header) { + return headers_.upper_bound(ToString(header)); + } + + void setContent(const std::string& content_type, StreamInterface* document); + void setDocumentAndLength(StreamInterface* document); + + virtual size_t formatLeader(char* buffer, size_t size) const = 0; + virtual HttpError parseLeader(const char* line, size_t len) = 0; + +protected: + virtual ~HttpData() { } + void clear(bool release_document); + void copy(const HttpData& src); + +private: + HeaderMap headers_; +}; + +struct HttpRequestData : public HttpData { + HttpVerb verb; + std::string path; + + HttpRequestData() : verb(HV_GET) { } + + void clear(bool release_document); + void copy(const HttpRequestData& src); + + virtual size_t formatLeader(char* buffer, size_t size) const; + virtual HttpError parseLeader(const char* line, size_t len); + + bool getAbsoluteUri(std::string* uri) const; + bool getRelativeUri(std::string* host, std::string* path) const; +}; + +struct HttpResponseData : public HttpData { + uint32 scode; + std::string message; + + HttpResponseData() : scode(HC_INTERNAL_SERVER_ERROR) { } + void clear(bool release_document); + void copy(const HttpResponseData& src); + + // Convenience methods + void set_success(uint32 scode = HC_OK); + void set_success(const std::string& content_type, StreamInterface* document, + uint32 scode = HC_OK); + void set_redirect(const std::string& location, + uint32 scode = HC_MOVED_TEMPORARILY); + void set_error(uint32 scode); + + virtual size_t formatLeader(char* buffer, size_t size) const; + virtual HttpError parseLeader(const char* line, size_t len); +}; + +struct HttpTransaction { + HttpRequestData request; + HttpResponseData response; +}; + +////////////////////////////////////////////////////////////////////// +// Http Authentication +////////////////////////////////////////////////////////////////////// + +struct HttpAuthContext { + std::string auth_method; + HttpAuthContext(const std::string& auth) : auth_method(auth) { } + virtual ~HttpAuthContext() { } +}; + +enum HttpAuthResult { HAR_RESPONSE, HAR_IGNORE, HAR_CREDENTIALS, HAR_ERROR }; + +// 'context' is used by this function to record information between calls. +// Start by passing a null pointer, then pass the same pointer each additional +// call. When the authentication attempt is finished, delete the context. +HttpAuthResult HttpAuthenticate( + const char * challenge, size_t len, + const SocketAddress& server, + const std::string& method, const std::string& uri, + const std::string& username, const CryptString& password, + HttpAuthContext *& context, std::string& response, std::string& auth_method); + +////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_HTTPCOMMON_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/httprequest.h b/thirdparties/common/include/webrtc-sdk/talk/base/httprequest.h new file mode 100644 index 0000000..886dfa9 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/httprequest.h @@ -0,0 +1,132 @@ +/* + * 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. + */ + +#ifndef _HTTPREQUEST_H_ +#define _HTTPREQUEST_H_ + +#include "talk/base/httpclient.h" +#include "talk/base/logging.h" +#include "talk/base/proxyinfo.h" +#include "talk/base/socketserver.h" +#include "talk/base/thread.h" +#include "talk/base/sslsocketfactory.h" // Deprecated include + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// HttpRequest +/////////////////////////////////////////////////////////////////////////////// + +class FirewallManager; +class MemoryStream; + +class HttpRequest { +public: + HttpRequest(const std::string &user_agent); + + void Send(); + + void set_proxy(const ProxyInfo& proxy) { + proxy_ = proxy; + } + void set_firewall(FirewallManager * firewall) { + firewall_ = firewall; + } + + // The DNS name of the host to connect to. + const std::string& host() { return host_; } + void set_host(const std::string& host) { host_ = host; } + + // The port to connect to on the target host. + int port() { return port_; } + void set_port(int port) { port_ = port; } + + // Whether the request should use SSL. + bool secure() { return secure_; } + void set_secure(bool secure) { secure_ = secure; } + + // Returns the redirect when redirection occurs + const std::string& response_redirect() { return response_redirect_; } + + // Time to wait on the download, in ms. Default is 5000 (5s) + int timeout() { return timeout_; } + void set_timeout(int timeout) { timeout_ = timeout; } + + // Fail redirects to allow analysis of redirect urls, etc. + bool fail_redirect() const { return fail_redirect_; } + void set_fail_redirect(bool fail_redirect) { fail_redirect_ = fail_redirect; } + + HttpRequestData& request() { return client_.request(); } + HttpResponseData& response() { return client_.response(); } + HttpErrorType error() { return error_; } + +protected: + void set_error(HttpErrorType error) { error_ = error; } + +private: + ProxyInfo proxy_; + FirewallManager * firewall_; + std::string host_; + int port_; + bool secure_; + int timeout_; + bool fail_redirect_; + HttpClient client_; + HttpErrorType error_; + std::string response_redirect_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// HttpMonitor +/////////////////////////////////////////////////////////////////////////////// + +class HttpMonitor : public sigslot::has_slots<> { +public: + HttpMonitor(SocketServer *ss); + + void reset() { + complete_ = false; + error_ = HE_DEFAULT; + } + + bool done() const { return complete_; } + HttpErrorType error() const { return error_; } + + void Connect(HttpClient* http); + void OnHttpClientComplete(HttpClient * http, HttpErrorType error); + +private: + bool complete_; + HttpErrorType error_; + SocketServer *ss_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base_ + +#endif // _HTTPREQUEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/httpserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/httpserver.h new file mode 100644 index 0000000..272fead --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/httpserver.h @@ -0,0 +1,154 @@ +/* + * 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 TALK_BASE_HTTPSERVER_H__ +#define TALK_BASE_HTTPSERVER_H__ + +#include +#include "talk/base/httpbase.h" + +namespace talk_base { + +class AsyncSocket; +class HttpServer; +class SocketAddress; + +////////////////////////////////////////////////////////////////////// +// HttpServer +////////////////////////////////////////////////////////////////////// + +const int HTTP_INVALID_CONNECTION_ID = 0; + +struct HttpServerTransaction : public HttpTransaction { +public: + HttpServerTransaction(int id) : connection_id_(id) { } + int connection_id() const { return connection_id_; } + +private: + int connection_id_; +}; + +class HttpServer { +public: + HttpServer(); + virtual ~HttpServer(); + + int HandleConnection(StreamInterface* stream); + // Due to sigslot issues, we can't destroy some streams at an arbitrary time. + sigslot::signal3 SignalConnectionClosed; + + // This signal occurs when the HTTP request headers have been received, but + // before the request body is written to the request document. By default, + // the request document is a MemoryStream. By handling this signal, the + // document can be overridden, in which case the third signal argument should + // be set to true. In the case where the request body should be ignored, + // the document can be set to NULL. Note that the transaction object is still + // owened by the HttpServer at this point. + sigslot::signal3 + SignalHttpRequestHeader; + + // An HTTP request has been made, and is available in the transaction object. + // Populate the transaction's response, and then return the object via the + // Respond method. Note that during this time, ownership of the transaction + // object is transferred, so it may be passed between threads, although + // respond must be called on the server's active thread. + sigslot::signal2 SignalHttpRequest; + void Respond(HttpServerTransaction* transaction); + + // If you want to know when a request completes, listen to this event. + sigslot::signal3 + SignalHttpRequestComplete; + + // Stop processing the connection indicated by connection_id. + // Unless force is true, the server will complete sending a response that is + // in progress. + void Close(int connection_id, bool force); + void CloseAll(bool force); + + // After calling CloseAll, this event is signalled to indicate that all + // outstanding connections have closed. + sigslot::signal1 SignalCloseAllComplete; + +private: + class Connection : private IHttpNotify { + public: + Connection(int connection_id, HttpServer* server); + virtual ~Connection(); + + void BeginProcess(StreamInterface* stream); + StreamInterface* EndProcess(); + + void Respond(HttpServerTransaction* transaction); + void InitiateClose(bool force); + + // IHttpNotify Interface + virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size); + virtual void onHttpComplete(HttpMode mode, HttpError err); + virtual void onHttpClosed(HttpError err); + + int connection_id_; + HttpServer* server_; + HttpBase base_; + HttpServerTransaction* current_; + bool signalling_, close_; + }; + + Connection* Find(int connection_id); + void Remove(int connection_id); + + friend class Connection; + typedef std::map ConnectionMap; + + ConnectionMap connections_; + int next_connection_id_; + bool closing_; +}; + +////////////////////////////////////////////////////////////////////// + +class HttpListenServer : public HttpServer, public sigslot::has_slots<> { +public: + HttpListenServer(); + virtual ~HttpListenServer(); + + int Listen(const SocketAddress& address); + bool GetAddress(SocketAddress* address) const; + void StopListening(); + +private: + void OnReadEvent(AsyncSocket* socket); + void OnConnectionClosed(HttpServer* server, int connection_id, + StreamInterface* stream); + + scoped_ptr listener_; +}; + +////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_HTTPSERVER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/ifaddrs-android.h b/thirdparties/common/include/webrtc-sdk/talk/base/ifaddrs-android.h new file mode 100644 index 0000000..29f0926 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/ifaddrs-android.h @@ -0,0 +1,50 @@ +/* + * 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_IFADDRS_ANDROID_H_ +#define TALK_BASE_IFADDRS_ANDROID_H_ + +#include +#include +// Implementation of getifaddrs for Android. +// Fills out a list of ifaddr structs (see below) which contain information +// about every network interface available on the host. +// See 'man getifaddrs' on Linux or OS X (nb: it is not a POSIX function). +struct ifaddrs { + struct ifaddrs* ifa_next; + char* ifa_name; + unsigned int ifa_flags; + struct sockaddr* ifa_addr; + struct sockaddr* ifa_netmask; + // Real ifaddrs has broadcast, point to point and data members. + // We don't need them (yet?). +}; + +int getifaddrs(struct ifaddrs** result); +void freeifaddrs(struct ifaddrs* addrs); + +#endif // TALK_BASE_IFADDRS_ANDROID_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/ipaddress.h b/thirdparties/common/include/webrtc-sdk/talk/base/ipaddress.h new file mode 100644 index 0000000..5a9d9e7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/ipaddress.h @@ -0,0 +1,158 @@ +/* + * 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_BASE_IPADDRESS_H_ +#define TALK_BASE_IPADDRESS_H_ + +#ifdef POSIX +#include +#include +#include +#include +#endif +#ifdef WIN32 +#include +#include +#endif +#include +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/byteorder.h" +#ifdef WIN32 +#include "talk/base/win32.h" +#endif + +namespace talk_base { + +// Version-agnostic IP address class, wraps a union of in_addr and in6_addr. +class IPAddress { + public: + IPAddress() : family_(AF_UNSPEC) { + ::memset(&u_, 0, sizeof(u_)); + } + + explicit IPAddress(const in_addr &ip4) : family_(AF_INET) { + memset(&u_, 0, sizeof(u_)); + u_.ip4 = ip4; + } + + explicit IPAddress(const in6_addr &ip6) : family_(AF_INET6) { + u_.ip6 = ip6; + } + + explicit IPAddress(uint32 ip_in_host_byte_order) : family_(AF_INET) { + memset(&u_, 0, sizeof(u_)); + u_.ip4.s_addr = HostToNetwork32(ip_in_host_byte_order); + } + + IPAddress(const IPAddress &other) : family_(other.family_) { + ::memcpy(&u_, &other.u_, sizeof(u_)); + } + + ~IPAddress() {} + + const IPAddress & operator=(const IPAddress &other) { + family_ = other.family_; + ::memcpy(&u_, &other.u_, sizeof(u_)); + return *this; + } + + bool operator==(const IPAddress &other) const; + bool operator!=(const IPAddress &other) const; + bool operator <(const IPAddress &other) const; + bool operator >(const IPAddress &other) const; + friend std::ostream& operator<<(std::ostream& os, const IPAddress& addr); + + int family() const { return family_; } + in_addr ipv4_address() const; + in6_addr ipv6_address() const; + + // Returns the number of bytes needed to store the raw address. + size_t Size() const; + + // Wraps inet_ntop. + std::string ToString() const; + + // Same as ToString but anonymizes it by hiding the last part. + std::string ToSensitiveString() const; + + // Returns an unmapped address from a possibly-mapped address. + // Returns the same address if this isn't a mapped address. + IPAddress Normalized() const; + + // Returns this address as an IPv6 address. + // Maps v4 addresses (as ::ffff:a.b.c.d), returns v6 addresses unchanged. + IPAddress AsIPv6Address() const; + + // For socketaddress' benefit. Returns the IP in host byte order. + uint32 v4AddressAsHostOrderInteger() const; + + static void set_strip_sensitive(bool enable); + + private: + int family_; + union { + in_addr ip4; + in6_addr ip6; + } u_; + + static bool strip_sensitive_; +}; + +bool IPFromAddrInfo(struct addrinfo* info, IPAddress* out); +bool IPFromString(const std::string& str, IPAddress* out); +bool IPIsAny(const IPAddress& ip); +bool IPIsLoopback(const IPAddress& ip); +bool IPIsPrivate(const IPAddress& ip); +bool IPIsUnspec(const IPAddress& ip); +size_t HashIP(const IPAddress& ip); + +// These are only really applicable for IPv6 addresses. +bool IPIs6Bone(const IPAddress& ip); +bool IPIs6To4(const IPAddress& ip); +bool IPIsSiteLocal(const IPAddress& ip); +bool IPIsTeredo(const IPAddress& ip); +bool IPIsULA(const IPAddress& ip); +bool IPIsV4Compatibility(const IPAddress& ip); +bool IPIsV4Mapped(const IPAddress& ip); + +// Returns the precedence value for this IP as given in RFC3484. +int IPAddressPrecedence(const IPAddress& ip); + +// Returns 'ip' truncated to be 'length' bits long. +IPAddress TruncateIP(const IPAddress& ip, int length); + +// Returns the number of contiguously set bits, counting from the MSB in network +// byte order, in this IPAddress. Bits after the first 0 encountered are not +// counted. +int CountIPMaskBits(IPAddress mask); + +} // namespace talk_base + +#endif // TALK_BASE_IPADDRESS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/json.h b/thirdparties/common/include/webrtc-sdk/talk/base/json.h new file mode 100644 index 0000000..e2212b6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/json.h @@ -0,0 +1,106 @@ +/* + * 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 TALK_BASE_JSON_H_ +#define TALK_BASE_JSON_H_ + +#include +#include + +#ifdef JSONCPP_RELATIVE_PATH +#include "json/json.h" +#else +#include "third_party/jsoncpp/json.h" +#endif + +// TODO: Move to talk_base namespace + +/////////////////////////////////////////////////////////////////////////////// +// JSON Helpers +/////////////////////////////////////////////////////////////////////////////// + +// Robust conversion operators, better than the ones in JsonCpp. +bool GetIntFromJson(const Json::Value& in, int* out); +bool GetUIntFromJson(const Json::Value& in, unsigned int* out); +bool GetStringFromJson(const Json::Value& in, std::string* out); +bool GetBoolFromJson(const Json::Value& in, bool* out); +bool GetDoubleFromJson(const Json::Value& in, double* out); + +// Pull values out of a JSON array. +bool GetValueFromJsonArray(const Json::Value& in, size_t n, + Json::Value* out); +bool GetIntFromJsonArray(const Json::Value& in, size_t n, + int* out); +bool GetUIntFromJsonArray(const Json::Value& in, size_t n, + unsigned int* out); +bool GetStringFromJsonArray(const Json::Value& in, size_t n, + std::string* out); +bool GetBoolFromJsonArray(const Json::Value& in, size_t n, + bool* out); +bool GetDoubleFromJsonArray(const Json::Value& in, size_t n, + double* out); + +// Convert json arrays to std::vector +bool JsonArrayToValueVector(const Json::Value& in, + std::vector* out); +bool JsonArrayToIntVector(const Json::Value& in, + std::vector* out); +bool JsonArrayToUIntVector(const Json::Value& in, + std::vector* out); +bool JsonArrayToStringVector(const Json::Value& in, + std::vector* out); +bool JsonArrayToBoolVector(const Json::Value& in, + std::vector* out); +bool JsonArrayToDoubleVector(const Json::Value& in, + std::vector* out); + +// Convert std::vector to json array +Json::Value ValueVectorToJsonArray(const std::vector& in); +Json::Value IntVectorToJsonArray(const std::vector& in); +Json::Value UIntVectorToJsonArray(const std::vector& in); +Json::Value StringVectorToJsonArray(const std::vector& in); +Json::Value BoolVectorToJsonArray(const std::vector& in); +Json::Value DoubleVectorToJsonArray(const std::vector& in); + +// Pull values out of a JSON object. +bool GetValueFromJsonObject(const Json::Value& in, const std::string& k, + Json::Value* out); +bool GetIntFromJsonObject(const Json::Value& in, const std::string& k, + int* out); +bool GetUIntFromJsonObject(const Json::Value& in, const std::string& k, + unsigned int* out); +bool GetStringFromJsonObject(const Json::Value& in, const std::string& k, + std::string* out); +bool GetBoolFromJsonObject(const Json::Value& in, const std::string& k, + bool* out); +bool GetDoubleFromJsonObject(const Json::Value& in, const std::string& k, + double* out); + +// Writes out a Json value as a string. +std::string JsonValueToString(const Json::Value& json); + +#endif // TALK_BASE_JSON_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/latebindingsymboltable.h b/thirdparties/common/include/webrtc-sdk/talk/base/latebindingsymboltable.h new file mode 100644 index 0000000..683086d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/latebindingsymboltable.h @@ -0,0 +1,86 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_LATEBINDINGSYMBOLTABLE_H_ +#define TALK_BASE_LATEBINDINGSYMBOLTABLE_H_ + +#include + +#include "talk/base/common.h" + +namespace talk_base { + +#ifdef POSIX +typedef void *DllHandle; +#else +#error Not implemented for this platform +#endif + +// This is the base class for "symbol table" classes to simplify the dynamic +// loading of symbols from DLLs. Currently the implementation only supports +// Linux and OS X, and pure C symbols (or extern "C" symbols that wrap C++ +// functions). Sub-classes for specific DLLs are generated via the "supermacro" +// files latebindingsymboltable.h.def and latebindingsymboltable.cc.def. See +// talk/sound/pulseaudiosymboltable.(h|cc) for an example. +class LateBindingSymbolTable { + public: + struct TableInfo { + const char *dll_name; + int num_symbols; + // Array of size num_symbols. + const char *const *symbol_names; + }; + + LateBindingSymbolTable(const TableInfo *info, void **table); + ~LateBindingSymbolTable(); + + bool IsLoaded() const; + // Loads the DLL and the symbol table. Returns true iff the DLL and symbol + // table loaded successfully. + bool Load(); + // Like load, but allows overriding the dll path for when the dll path is + // dynamic. + bool LoadFromPath(const char *dll_path); + void Unload(); + + // Gets the raw OS handle to the DLL. Be careful what you do with it. + DllHandle GetDllHandle() const { return handle_; } + + private: + void ClearSymbols(); + + const TableInfo *info_; + void **table_; + DllHandle handle_; + bool undefined_symbols_; + + DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable); +}; + +} // namespace talk_base + +#endif // TALK_BASE_LATEBINDINGSYMBOLTABLE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/libdbusglibsymboltable.h b/thirdparties/common/include/webrtc-sdk/talk/base/libdbusglibsymboltable.h new file mode 100644 index 0000000..5bc79f4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/libdbusglibsymboltable.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_LIBDBUSGLIBSYMBOLTABLE_H_ +#define TALK_BASE_LIBDBUSGLIBSYMBOLTABLE_H_ + +#ifdef HAVE_DBUS_GLIB + +#include +#include + +#include "talk/base/latebindingsymboltable.h" + +namespace talk_base { + +#define LIBDBUS_GLIB_CLASS_NAME LibDBusGlibSymbolTable +// The libdbus-glib symbols we need, as an X-Macro list. +// This list must contain precisely every libdbus-glib function that is used in +// dbus.cc. +#define LIBDBUS_GLIB_SYMBOLS_LIST \ + X(dbus_bus_add_match) \ + X(dbus_connection_add_filter) \ + X(dbus_connection_close) \ + X(dbus_connection_remove_filter) \ + X(dbus_connection_set_exit_on_disconnect) \ + X(dbus_g_bus_get) \ + X(dbus_g_bus_get_private) \ + X(dbus_g_connection_get_connection) \ + X(dbus_g_connection_unref) \ + X(dbus_g_thread_init) \ + X(dbus_message_get_interface) \ + X(dbus_message_get_member) \ + X(dbus_message_get_path) \ + X(dbus_message_get_type) \ + X(dbus_message_iter_get_arg_type) \ + X(dbus_message_iter_get_basic) \ + X(dbus_message_iter_init) \ + X(dbus_message_ref) \ + X(dbus_message_unref) + +#define LATE_BINDING_SYMBOL_TABLE_CLASS_NAME LIBDBUS_GLIB_CLASS_NAME +#define LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST LIBDBUS_GLIB_SYMBOLS_LIST +#include "talk/base/latebindingsymboltable.h.def" + +} // namespace talk_base + +#endif // HAVE_DBUS_GLIB + +#endif // TALK_BASE_LIBDBUSGLIBSYMBOLTABLE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/linked_ptr.h b/thirdparties/common/include/webrtc-sdk/talk/base/linked_ptr.h new file mode 100644 index 0000000..a163a2a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/linked_ptr.h @@ -0,0 +1,142 @@ +/* + * 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. + */ + +/* + * linked_ptr - simple reference linked pointer + * (like reference counting, just using a linked list of the references + * instead of their count.) + * + * The implementation stores three pointers for every linked_ptr, but + * does not allocate anything on the free store. + */ + +#ifndef TALK_BASE_LINKED_PTR_H__ +#define TALK_BASE_LINKED_PTR_H__ + +namespace talk_base { + +/* For ANSI-challenged compilers, you may want to #define + * NO_MEMBER_TEMPLATES, explicit or mutable */ +#define NO_MEMBER_TEMPLATES + +template class linked_ptr +{ +public: + +#ifndef NO_MEMBER_TEMPLATES +# define TEMPLATE_FUNCTION template + TEMPLATE_FUNCTION friend class linked_ptr; +#else +# define TEMPLATE_FUNCTION + typedef X Y; +#endif + + typedef X element_type; + + explicit linked_ptr(X* p = 0) throw() + : itsPtr(p) {itsPrev = itsNext = this;} + ~linked_ptr() + {release();} + linked_ptr(const linked_ptr& r) throw() + {acquire(r);} + linked_ptr& operator=(const linked_ptr& r) + { + if (this != &r) { + release(); + acquire(r); + } + return *this; + } + +#ifndef NO_MEMBER_TEMPLATES + template friend class linked_ptr; + template linked_ptr(const linked_ptr& r) throw() + {acquire(r);} + template linked_ptr& operator=(const linked_ptr& r) + { + if (this != &r) { + release(); + acquire(r); + } + return *this; + } +#endif // NO_MEMBER_TEMPLATES + + X& operator*() const throw() {return *itsPtr;} + X* operator->() const throw() {return itsPtr;} + X* get() const throw() {return itsPtr;} + bool unique() const throw() {return itsPrev ? itsPrev==this : true;} + +private: + X* itsPtr; + mutable const linked_ptr* itsPrev; + mutable const linked_ptr* itsNext; + + void acquire(const linked_ptr& r) throw() + { // insert this to the list + itsPtr = r.itsPtr; + itsNext = r.itsNext; + itsNext->itsPrev = this; + itsPrev = &r; +#ifndef mutable + r.itsNext = this; +#else // for ANSI-challenged compilers + (const_cast*>(&r))->itsNext = this; +#endif + } + +#ifndef NO_MEMBER_TEMPLATES + template void acquire(const linked_ptr& r) throw() + { // insert this to the list + itsPtr = r.itsPtr; + itsNext = r.itsNext; + itsNext->itsPrev = this; + itsPrev = &r; +#ifndef mutable + r.itsNext = this; +#else // for ANSI-challenged compilers + (const_cast*>(&r))->itsNext = this; +#endif + } +#endif // NO_MEMBER_TEMPLATES + + void release() + { // erase this from the list, delete if unique + if (unique()) delete itsPtr; + else { + itsPrev->itsNext = itsNext; + itsNext->itsPrev = itsPrev; + itsPrev = itsNext = 0; + } + itsPtr = 0; + } +}; + +} // namespace talk_base + +#endif // TALK_BASE_LINKED_PTR_H__ + diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/linux.h b/thirdparties/common/include/webrtc-sdk/talk/base/linux.h new file mode 100644 index 0000000..a80b29e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/linux.h @@ -0,0 +1,140 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_LINUX_H_ +#define TALK_BASE_LINUX_H_ + +#if defined(LINUX) || defined(ANDROID) +#include +#include +#include + +#include "talk/base/scoped_ptr.h" +#include "talk/base/stream.h" + +namespace talk_base { + +////////////////////////////////////////////////////////////////////////////// +// ConfigParser parses a FileStream of an ".ini."-type format into a map. +////////////////////////////////////////////////////////////////////////////// + +// Sample Usage: +// ConfigParser parser; +// ConfigParser::MapVector key_val_pairs; +// if (parser.Open(inifile) && parser.Parse(&key_val_pairs)) { +// for (int section_num=0; i < key_val_pairs.size(); ++section_num) { +// std::string val1 = key_val_pairs[section_num][key1]; +// std::string val2 = key_val_pairs[section_num][key2]; +// // Do something with valn; +// } +// } + +class ConfigParser { + public: + typedef std::map SimpleMap; + typedef std::vector MapVector; + + ConfigParser(); + virtual ~ConfigParser(); + + virtual bool Open(const std::string& filename); + virtual void Attach(StreamInterface* stream); + virtual bool Parse(MapVector* key_val_pairs); + virtual bool ParseSection(SimpleMap* key_val_pair); + virtual bool ParseLine(std::string* key, std::string* value); + + private: + scoped_ptr instream_; +}; + +////////////////////////////////////////////////////////////////////////////// +// ProcCpuInfo reads CPU info from the /proc subsystem on any *NIX platform. +////////////////////////////////////////////////////////////////////////////// + +// Sample Usage: +// ProcCpuInfo proc_info; +// int no_of_cpu; +// if (proc_info.LoadFromSystem()) { +// std::string out_str; +// proc_info.GetNumCpus(&no_of_cpu); +// proc_info.GetCpuStringValue(0, "vendor_id", &out_str); +// } +// } + +class ProcCpuInfo { + public: + ProcCpuInfo(); + virtual ~ProcCpuInfo(); + + // Reads the proc subsystem's cpu info into memory. If this fails, this + // returns false; if it succeeds, it returns true. + virtual bool LoadFromSystem(); + + // Obtains the number of logical CPU threads and places the value num. + virtual bool GetNumCpus(int* num); + + // Obtains the number of physical CPU cores and places the value num. + virtual bool GetNumPhysicalCpus(int* num); + + // Obtains the CPU family id. + virtual bool GetCpuFamily(int* id); + + // Obtains the number of sections in /proc/cpuinfo, which may be greater + // than the number of CPUs (e.g. on ARM) + virtual bool GetSectionCount(size_t* count); + + // Looks for the CPU proc item with the given name for the given section + // number and places the string value in result. + virtual bool GetSectionStringValue(size_t section_num, const std::string& key, + std::string* result); + + // Looks for the CPU proc item with the given name for the given section + // number and places the int value in result. + virtual bool GetSectionIntValue(size_t section_num, const std::string& key, + int* result); + + private: + 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(); + +// Returns the content (int) of +// /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq +// Returns -1 on error. +int ReadCpuMaxFreq(); + +} // namespace talk_base + +#endif // defined(LINUX) || defined(ANDROID) +#endif // TALK_BASE_LINUX_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/linuxfdwalk.h b/thirdparties/common/include/webrtc-sdk/talk/base/linuxfdwalk.h new file mode 100644 index 0000000..29f04db --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/linuxfdwalk.h @@ -0,0 +1,51 @@ +/* + * libjingle + * Copyright 2004--2009, 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_LINUXFDWALK_H_ +#define TALK_BASE_LINUXFDWALK_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Linux port of SunOS's fdwalk(3) call. It loops over all open file descriptors +// and calls func on each one. Additionally, it is safe to use from the child +// of a fork that hasn't exec'ed yet, so you can use it to close all open file +// descriptors prior to exec'ing a daemon. +// The return value is 0 if successful, or else -1 and errno is set. The +// possible errors include any error that can be returned by opendir(), +// readdir(), or closedir(), plus EBADF if there are problems parsing the +// contents of /proc/self/fd. +// The file descriptors that are enumerated will not include the file descriptor +// used for the enumeration itself. +int fdwalk(void (*func)(void *, int), void *opaque); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TALK_BASE_LINUXFDWALK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/linuxwindowpicker.h b/thirdparties/common/include/webrtc-sdk/talk/base/linuxwindowpicker.h new file mode 100644 index 0000000..f0156ea --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/linuxwindowpicker.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_LINUXWINDOWPICKER_H_ +#define TALK_BASE_LINUXWINDOWPICKER_H_ + +#include "talk/base/basictypes.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/windowpicker.h" + +// Avoid include . +struct _XDisplay; +typedef unsigned long Window; + +namespace talk_base { + +class XWindowEnumerator; + +class LinuxWindowPicker : public WindowPicker { + public: + LinuxWindowPicker(); + ~LinuxWindowPicker(); + + static bool IsDesktopElement(_XDisplay* display, Window window); + + virtual bool Init(); + virtual bool IsVisible(const WindowId& id); + virtual bool MoveToFront(const WindowId& id); + virtual bool GetWindowList(WindowDescriptionList* descriptions); + virtual bool GetDesktopList(DesktopDescriptionList* descriptions); + virtual bool GetDesktopDimensions(const DesktopId& id, int* width, + int* height); + uint8* GetWindowIcon(const WindowId& id, int* width, int* height); + uint8* GetWindowThumbnail(const WindowId& id, int width, int height); + int GetNumDesktops(); + uint8* GetDesktopThumbnail(const DesktopId& id, int width, int height); + + private: + scoped_ptr enumerator_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_LINUXWINDOWPICKER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/logging.h b/thirdparties/common/include/webrtc-sdk/talk/base/logging.h new file mode 100644 index 0000000..2f56982 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/logging.h @@ -0,0 +1,404 @@ +/* + * 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. + */ + +// LOG(...) an ostream target that can be used to send formatted +// output to a variety of logging targets, such as debugger console, stderr, +// file, or any StreamInterface. +// The severity level passed as the first argument to the LOGging +// functions is used as a filter, to limit the verbosity of the logging. +// Static members of LogMessage documented below are used to control the +// verbosity and target of the output. +// There are several variations on the LOG macro which facilitate logging +// of common error conditions, detailed below. + +// LOG(sev) logs the given stream at severity "sev", which must be a +// compile-time constant of the LoggingSeverity type, without the namespace +// prefix. +// LOG_V(sev) Like LOG(), but sev is a run-time variable of the LoggingSeverity +// type (basically, it just doesn't prepend the namespace). +// LOG_F(sev) Like LOG(), but includes the name of the current function. +// LOG_T(sev) Like LOG(), but includes the this pointer. +// LOG_T_F(sev) Like LOG_F(), but includes the this pointer. +// LOG_GLE(M)(sev [, mod]) attempt to add a string description of the +// HRESULT returned by GetLastError. The "M" variant allows searching of a +// DLL's string table for the error description. +// LOG_ERRNO(sev) attempts to add a string description of an errno-derived +// error. errno and associated facilities exist on both Windows and POSIX, +// but on Windows they only apply to the C/C++ runtime. +// LOG_ERR(sev) is an alias for the platform's normal error system, i.e. _GLE on +// Windows and _ERRNO on POSIX. +// (The above three also all have _EX versions that let you specify the error +// code, rather than using the last one.) +// LOG_E(sev, ctx, err, ...) logs a detailed error interpreted using the +// specified context. +// LOG_CHECK_LEVEL(sev) (and LOG_CHECK_LEVEL_V(sev)) can be used as a test +// before performing expensive or sensitive operations whose sole purpose is +// to output logging data at the desired level. +// Lastly, PLOG(sev, err) is an alias for LOG_ERR_EX. + +#ifndef TALK_BASE_LOGGING_H_ +#define TALK_BASE_LOGGING_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" // NOLINT +#endif + +#include +#include +#include +#include +#include "talk/base/basictypes.h" +#include "talk/base/criticalsection.h" + +namespace talk_base { + +class StreamInterface; + +/////////////////////////////////////////////////////////////////////////////// +// ConstantLabel can be used to easily generate string names from constant +// values. This can be useful for logging descriptive names of error messages. +// Usage: +// const ConstantLabel LIBRARY_ERRORS[] = { +// KLABEL(SOME_ERROR), +// KLABEL(SOME_OTHER_ERROR), +// ... +// LASTLABEL +// } +// +// int err = LibraryFunc(); +// LOG(LS_ERROR) << "LibraryFunc returned: " +// << ErrorName(err, LIBRARY_ERRORS); + +struct ConstantLabel { int value; const char * label; }; +#define KLABEL(x) { x, #x } +#define TLABEL(x, y) { x, y } +#define LASTLABEL { 0, 0 } + +const char * FindLabel(int value, const ConstantLabel entries[]); +std::string ErrorName(int err, const ConstantLabel* err_table); + +////////////////////////////////////////////////////////////////////// + +// Note that the non-standard LoggingSeverity aliases exist because they are +// still in broad use. The meanings of the levels are: +// LS_SENSITIVE: Information which should only be logged with the consent +// of the user, due to privacy concerns. +// LS_VERBOSE: This level is for data which we do not want to appear in the +// normal debug log, but should appear in diagnostic logs. +// LS_INFO: Chatty level used in debugging for all sorts of things, the default +// in debug builds. +// LS_WARNING: Something that may warrant investigation. +// LS_ERROR: Something that should not have occurred. +enum LoggingSeverity { LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR, + INFO = LS_INFO, + WARNING = LS_WARNING, + LERROR = LS_ERROR }; + +// LogErrorContext assists in interpreting the meaning of an error value. +enum LogErrorContext { + ERRCTX_NONE, + ERRCTX_ERRNO, // System-local errno + ERRCTX_HRESULT, // Windows HRESULT + ERRCTX_OSSTATUS, // MacOS OSStatus + + // Abbreviations for LOG_E macro + ERRCTX_EN = ERRCTX_ERRNO, // LOG_E(sev, EN, x) + ERRCTX_HR = ERRCTX_HRESULT, // LOG_E(sev, HR, x) + ERRCTX_OS = ERRCTX_OSSTATUS, // LOG_E(sev, OS, x) +}; + +class LogMessage { + public: + static const int NO_LOGGING; + static const uint32 WARN_SLOW_LOGS_DELAY = 50; // ms + + LogMessage(const char* file, int line, LoggingSeverity sev, + LogErrorContext err_ctx = ERRCTX_NONE, int err = 0, + const char* module = NULL); + ~LogMessage(); + + static inline bool Loggable(LoggingSeverity sev) { return (sev >= min_sev_); } + std::ostream& stream() { return print_stream_; } + + // Returns the time at which this function was called for the first time. + // The time will be used as the logging start time. + // If this is not called externally, the LogMessage ctor also calls it, in + // which case the logging start time will be the time of the first LogMessage + // instance is created. + static uint32 LogStartTime(); + + // Returns the wall clock equivalent of |LogStartTime|, in seconds from the + // epoch. + static uint32 WallClockStartTime(); + + // These are attributes which apply to all logging channels + // LogContext: Display the file and line number of the message + static void LogContext(int min_sev); + // LogThreads: Display the thread identifier of the current thread + static void LogThreads(bool on = true); + // LogTimestamps: Display the elapsed time of the program + static void LogTimestamps(bool on = true); + + // These are the available logging channels + // Debug: Debug console on Windows, otherwise stderr + static void LogToDebug(int min_sev); + static int GetLogToDebug() { return dbg_sev_; } + + // Stream: Any non-blocking stream interface. LogMessage takes ownership of + // the stream. Multiple streams may be specified by using AddLogToStream. + // LogToStream is retained for backwards compatibility; when invoked, it + // will discard any previously set streams and install the specified stream. + // GetLogToStream gets the severity for the specified stream, of if none + // is specified, the minimum stream severity. + // RemoveLogToStream removes the specified stream, without destroying it. + static void LogToStream(StreamInterface* stream, int min_sev); + static int GetLogToStream(StreamInterface* stream = NULL); + static void AddLogToStream(StreamInterface* stream, int min_sev); + static void RemoveLogToStream(StreamInterface* stream); + + // Testing against MinLogSeverity allows code to avoid potentially expensive + // logging operations by pre-checking the logging level. + static int GetMinLogSeverity() { return min_sev_; } + + static void SetDiagnosticMode(bool f) { is_diagnostic_mode_ = f; } + static bool IsDiagnosticMode() { return is_diagnostic_mode_; } + + // Parses the provided parameter stream to configure the options above. + // Useful for configuring logging from the command line. If file logging + // is enabled, it is output to the specified filename. + static void ConfigureLogging(const char* params, const char* filename); + + // Convert the string to a LS_ value; also accept numeric values. + static int ParseLogSeverity(const std::string& value); + + private: + typedef std::list > StreamList; + + // Updates min_sev_ appropriately when debug sinks change. + static void UpdateMinLogSeverity(); + + // These assist in formatting some parts of the debug output. + static const char* Describe(LoggingSeverity sev); + static const char* DescribeFile(const char* file); + + // These write out the actual log messages. + static void OutputToDebug(const std::string& msg, LoggingSeverity severity_); + static void OutputToStream(StreamInterface* stream, const std::string& msg); + + // The ostream that buffers the formatted message before output + std::ostringstream print_stream_; + + // The severity level of this message + LoggingSeverity severity_; + + // String data generated in the constructor, that should be appended to + // the message before output. + std::string extra_; + + // If time it takes to write to stream is more than this, log one + // additional warning about it. + uint32 warn_slow_logs_delay_; + + // Global lock for the logging subsystem + static CriticalSection crit_; + + // dbg_sev_ is the thresholds for those output targets + // min_sev_ is the minimum (most verbose) of those levels, and is used + // as a short-circuit in the logging macros to identify messages that won't + // be logged. + // ctx_sev_ is the minimum level at which file context is displayed + static int min_sev_, dbg_sev_, ctx_sev_; + + // The output streams and their associated severities + static StreamList streams_; + + // Flags for formatting options + static bool thread_, timestamp_; + + // are we in diagnostic mode (as defined by the app)? + static bool is_diagnostic_mode_; + + DISALLOW_EVIL_CONSTRUCTORS(LogMessage); +}; + +////////////////////////////////////////////////////////////////////// +// Logging Helpers +////////////////////////////////////////////////////////////////////// + +class LogMultilineState { + public: + size_t unprintable_count_[2]; + LogMultilineState() { + unprintable_count_[0] = unprintable_count_[1] = 0; + } +}; + +// When possible, pass optional state variable to track various data across +// multiple calls to LogMultiline. Otherwise, pass NULL. +void LogMultiline(LoggingSeverity level, const char* label, bool input, + const void* data, size_t len, bool hex_mode, + LogMultilineState* state); + +////////////////////////////////////////////////////////////////////// +// Macros which automatically disable logging when LOGGING == 0 +////////////////////////////////////////////////////////////////////// + +// If LOGGING is not explicitly defined, default to enabled in debug mode +#if !defined(LOGGING) +#if defined(_DEBUG) && !defined(NDEBUG) +#define LOGGING 1 +#else +#define LOGGING 0 +#endif +#endif // !defined(LOGGING) + +#ifndef LOG +#if LOGGING + +// The following non-obvious technique for implementation of a +// conditional log stream was stolen from google3/base/logging.h. + +// This class is used to explicitly ignore values in the conditional +// logging macros. This avoids compiler warnings like "value computed +// is not used" and "statement has no effect". + +class LogMessageVoidify { + public: + LogMessageVoidify() { } + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream&) { } +}; + +#define LOG_SEVERITY_PRECONDITION(sev) \ + !(talk_base::LogMessage::Loggable(sev)) \ + ? (void) 0 \ + : talk_base::LogMessageVoidify() & + +#define LOG(sev) \ + LOG_SEVERITY_PRECONDITION(talk_base::sev) \ + talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev).stream() + +// The _V version is for when a variable is passed in. It doesn't do the +// namespace concatination. +#define LOG_V(sev) \ + LOG_SEVERITY_PRECONDITION(sev) \ + talk_base::LogMessage(__FILE__, __LINE__, sev).stream() + +// The _F version prefixes the message with the current function name. +#if (defined(__GNUC__) && defined(_DEBUG)) || defined(WANT_PRETTY_LOG_F) +#define LOG_F(sev) LOG(sev) << __PRETTY_FUNCTION__ << ": " +#define LOG_T_F(sev) LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": " +#else +#define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": " +#define LOG_T_F(sev) LOG(sev) << this << ": " << __FUNCTION__ << ": " +#endif + +#define LOG_CHECK_LEVEL(sev) \ + talk_base::LogCheckLevel(talk_base::sev) +#define LOG_CHECK_LEVEL_V(sev) \ + talk_base::LogCheckLevel(sev) +inline bool LogCheckLevel(LoggingSeverity sev) { + return (LogMessage::GetMinLogSeverity() <= sev); +} + +#define LOG_E(sev, ctx, err, ...) \ + LOG_SEVERITY_PRECONDITION(talk_base::sev) \ + talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \ + talk_base::ERRCTX_ ## ctx, err , ##__VA_ARGS__) \ + .stream() + +#define LOG_T(sev) LOG(sev) << this << ": " + +#else // !LOGGING + +// Hopefully, the compiler will optimize away some of this code. +// Note: syntax of "1 ? (void)0 : LogMessage" was causing errors in g++, +// converted to "while (false)" +#define LOG(sev) \ + while (false)talk_base:: LogMessage(NULL, 0, talk_base::sev).stream() +#define LOG_V(sev) \ + while (false) talk_base::LogMessage(NULL, 0, sev).stream() +#define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": " +#define LOG_CHECK_LEVEL(sev) \ + false +#define LOG_CHECK_LEVEL_V(sev) \ + false + +#define LOG_E(sev, ctx, err, ...) \ + while (false) talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \ + talk_base::ERRCTX_ ## ctx, err , ##__VA_ARGS__) \ + .stream() + +#define LOG_T(sev) LOG(sev) << this << ": " +#define LOG_T_F(sev) LOG(sev) << this << ": " << __FUNCTION__ << +#endif // !LOGGING + +#define LOG_ERRNO_EX(sev, err) \ + LOG_E(sev, ERRNO, err) +#define LOG_ERRNO(sev) \ + LOG_ERRNO_EX(sev, errno) + +#ifdef WIN32 +#define LOG_GLE_EX(sev, err) \ + LOG_E(sev, HRESULT, err) +#define LOG_GLE(sev) \ + LOG_GLE_EX(sev, GetLastError()) +#define LOG_GLEM(sev, mod) \ + LOG_E(sev, HRESULT, GetLastError(), mod) +#define LOG_ERR_EX(sev, err) \ + LOG_GLE_EX(sev, err) +#define LOG_ERR(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) +#define LOG_ERR(sev) \ + LOG_ERRNO(sev) +#define LAST_SYSTEM_ERROR \ + (errno) +#endif // WIN32 + +#define PLOG(sev, err) \ + LOG_ERR_EX(sev, err) + +// TODO(?): Add an "assert" wrapper that logs in the same manner. + +#endif // LOG + +} // namespace talk_base + +#endif // TALK_BASE_LOGGING_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/macasyncsocket.h b/thirdparties/common/include/webrtc-sdk/talk/base/macasyncsocket.h new file mode 100644 index 0000000..72fddf6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/macasyncsocket.h @@ -0,0 +1,91 @@ +// Copyright 2008 Google Inc. All Rights Reserved. + +// +// MacAsyncSocket is a kind of AsyncSocket. It only creates sockets +// of the TCP type, and does not (yet) support listen and accept. It works +// asynchronously, which means that users of this socket should connect to +// the various events declared in asyncsocket.h to receive notifications about +// this socket. + +#ifndef TALK_BASE_MACASYNCSOCKET_H__ +#define TALK_BASE_MACASYNCSOCKET_H__ + +#include + +#include "talk/base/asyncsocket.h" +#include "talk/base/nethelpers.h" + +namespace talk_base { + +class MacBaseSocketServer; + +class MacAsyncSocket : public AsyncSocket, public sigslot::has_slots<> { + public: + MacAsyncSocket(MacBaseSocketServer* ss, int family); + virtual ~MacAsyncSocket(); + + bool valid() const { return source_ != NULL; } + + // Socket interface + virtual SocketAddress GetLocalAddress() const; + virtual SocketAddress GetRemoteAddress() const; + virtual int Bind(const SocketAddress& addr); + virtual int Connect(const SocketAddress& addr); + virtual int Send(const void* buffer, size_t length); + virtual int SendTo(const void* buffer, size_t length, + const SocketAddress& addr); + virtual int Recv(void* buffer, size_t length); + virtual int RecvFrom(void* buffer, size_t length, SocketAddress* out_addr); + virtual int Listen(int backlog); + virtual MacAsyncSocket* Accept(SocketAddress* out_addr); + virtual int Close(); + virtual int GetError() const; + virtual void SetError(int error); + virtual ConnState GetState() const; + virtual int EstimateMTU(uint16* mtu); + virtual int GetOption(Option opt, int* value); + virtual int SetOption(Option opt, int value); + + // For the MacBaseSocketServer to disable callbacks when process_io is false. + void EnableCallbacks(); + void DisableCallbacks(); + + protected: + void OnResolveResult(SignalThread* thread); + int DoConnect(const SocketAddress& addr); + + private: + // Creates an async socket from an existing bsd socket + MacAsyncSocket(MacBaseSocketServer* ss, int family, int native_socket); + + // Attaches the socket to the CFRunloop and sets the wrapped bsd socket + // to async mode + void Initialize(int family); + + // Translate the SocketAddress into a CFDataRef to pass to CF socket + // functions. Caller must call CFRelease on the result when done. + static CFDataRef CopyCFAddress(const SocketAddress& address); + + // Callback for the underlying CFSocketRef. + static void MacAsyncSocketCallBack(CFSocketRef s, + CFSocketCallBackType callbackType, + CFDataRef address, + const void* data, + void* info); + + MacBaseSocketServer* ss_; + CFSocketRef socket_; + int native_socket_; + CFRunLoopSourceRef source_; + int current_callbacks_; + bool disabled_; + int error_; + ConnState state_; + AsyncResolver* resolver_; + + DISALLOW_EVIL_CONSTRUCTORS(MacAsyncSocket); +}; + +} // namespace talk_base + +#endif // TALK_BASE_MACASYNCSOCKET_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/maccocoasocketserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/maccocoasocketserver.h new file mode 100644 index 0000000..b629e8c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/maccocoasocketserver.h @@ -0,0 +1,65 @@ +/* + * libjingle + * Copyright 2007, 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 libjingle compatible SocketServer for OSX/iOS/Cocoa. + +#ifndef TALK_BASE_MACCOCOASOCKETSERVER_H_ +#define TALK_BASE_MACCOCOASOCKETSERVER_H_ + +#include "talk/base/macsocketserver.h" + +#ifdef __OBJC__ +@class NSTimer, MacCocoaSocketServerHelper; +#else +class NSTimer; +class MacCocoaSocketServerHelper; +#endif + +namespace talk_base { + +// A socketserver implementation that wraps the main cocoa +// application loop accessed through [NSApp run]. +class MacCocoaSocketServer : public MacBaseSocketServer { + public: + explicit MacCocoaSocketServer(); + virtual ~MacCocoaSocketServer(); + + virtual bool Wait(int cms, bool process_io); + virtual void WakeUp(); + + 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); +}; + +} // namespace talk_base + +#endif // TALK_BASE_MACCOCOASOCKETSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/maccocoathreadhelper.h b/thirdparties/common/include/webrtc-sdk/talk/base/maccocoathreadhelper.h new file mode 100644 index 0000000..fed168a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/maccocoathreadhelper.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +// Helper function for using Cocoa with Posix threads. This header should be +// included from C/C++ files that want to use some Cocoa functionality without +// using the .mm extension (mostly for files that are compiled on multiple +// platforms). + +#ifndef TALK_BASE_MACCOCOATHREADHELPER_H__ +#define TALK_BASE_MACCOCOATHREADHELPER_H__ + +namespace talk_base { + +// Cocoa must be "put into multithreading mode" before Cocoa functionality can +// be used on POSIX threads. This function does that. +void InitCocoaMultiThreading(); + +} // namespace talk_base + +#endif // TALK_BASE_MACCOCOATHREADHELPER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/macconversion.h b/thirdparties/common/include/webrtc-sdk/talk/base/macconversion.h new file mode 100644 index 0000000..c63beb6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/macconversion.h @@ -0,0 +1,56 @@ +/* + * libjingle + * Copyright 2004--2009, 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_MACCONVERSION_H_ +#define TALK_BASE_MACCONVERSION_H_ + +#ifdef OSX + +#include + +#include + +// given a CFStringRef, attempt to convert it to a C++ string. +// returns true if it succeeds, false otherwise. +// We can safely assume, given our context, that the string is +// going to be in ASCII, because it will either be an IP address, +// or a domain name, which is guaranteed to be ASCII-representable. +bool p_convertHostCFStringRefToCPPString(const CFStringRef cfstr, + std::string& cppstr); + +// Convert the CFNumber to an integer, putting the integer in the location +// given, and returhing true, if the conversion succeeds. +// If given a NULL or a non-CFNumber, returns false. +// This is pretty aggresive about trying to convert to int. +bool p_convertCFNumberToInt(CFNumberRef cfn, int* i); + +// given a CFNumberRef, determine if it represents a true value. +bool p_isCFNumberTrue(CFNumberRef cfn); + +#endif // OSX + +#endif // TALK_BASE_MACCONVERSION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/macsocketserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/macsocketserver.h new file mode 100644 index 0000000..f24e687 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/macsocketserver.h @@ -0,0 +1,130 @@ +// Copyright 2007, Google Inc. + + +#ifndef TALK_BASE_MACSOCKETSERVER_H__ +#define TALK_BASE_MACSOCKETSERVER_H__ + +#include +#ifdef OSX // Invalid on IOS +#include +#endif +#include "talk/base/physicalsocketserver.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// MacBaseSocketServer +/////////////////////////////////////////////////////////////////////////////// +class MacAsyncSocket; + +class MacBaseSocketServer : public PhysicalSocketServer { + public: + MacBaseSocketServer(); + virtual ~MacBaseSocketServer(); + + // SocketServer Interface + virtual Socket* CreateSocket(int type) { return NULL; } + virtual Socket* CreateSocket(int family, int type) { return NULL; } + + virtual AsyncSocket* CreateAsyncSocket(int type); + virtual AsyncSocket* CreateAsyncSocket(int family, int type); + + virtual bool Wait(int cms, bool process_io) = 0; + virtual void WakeUp() = 0; + + void RegisterSocket(MacAsyncSocket* socket); + void UnregisterSocket(MacAsyncSocket* socket); + + // PhysicalSocketServer Overrides + virtual bool SetPosixSignalHandler(int signum, void (*handler)(int)); + + protected: + void EnableSocketCallbacks(bool enable); + const std::set& sockets() { + return sockets_; + } + + private: + static void FileDescriptorCallback(CFFileDescriptorRef ref, + CFOptionFlags flags, + void* context); + + std::set sockets_; +}; + +// Core Foundation implementation of the socket server. While idle it +// will run the current CF run loop. When the socket server has work +// to do the run loop will be paused. Does not support Carbon or Cocoa +// UI interaction. +class MacCFSocketServer : public MacBaseSocketServer { + public: + MacCFSocketServer(); + virtual ~MacCFSocketServer(); + + // SocketServer Interface + virtual bool Wait(int cms, bool process_io); + virtual void WakeUp(); + void OnWakeUpCallback(); + + private: + CFRunLoopRef run_loop_; + CFRunLoopSourceRef wake_up_; +}; + +#ifndef CARBON_DEPRECATED + +/////////////////////////////////////////////////////////////////////////////// +// MacCarbonSocketServer +/////////////////////////////////////////////////////////////////////////////// + +// Interacts with the Carbon event queue. While idle it will block, +// waiting for events. When the socket server has work to do, it will +// post a 'wake up' event to the queue, causing the thread to exit the +// event loop until the next call to Wait. Other events are dispatched +// to their target. Supports Carbon and Cocoa UI interaction. +class MacCarbonSocketServer : public MacBaseSocketServer { + public: + MacCarbonSocketServer(); + virtual ~MacCarbonSocketServer(); + + // SocketServer Interface + virtual bool Wait(int cms, bool process_io); + virtual void WakeUp(); + + private: + EventQueueRef event_queue_; + EventRef wake_up_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// MacCarbonAppSocketServer +/////////////////////////////////////////////////////////////////////////////// + +// Runs the Carbon application event loop on the current thread while +// idle. When the socket server has work to do, it will post an event +// to the queue, causing the thread to exit the event loop until the +// next call to Wait. Other events are automatically dispatched to +// their target. +class MacCarbonAppSocketServer : public MacBaseSocketServer { + public: + MacCarbonAppSocketServer(); + virtual ~MacCarbonAppSocketServer(); + + // SocketServer Interface + virtual bool Wait(int cms, bool process_io); + virtual void WakeUp(); + + private: + static OSStatus WakeUpEventHandler(EventHandlerCallRef next, EventRef event, + void *data); + static void TimerHandler(EventLoopTimerRef timer, void *data); + + EventQueueRef event_queue_; + EventHandlerRef event_handler_; + EventLoopTimerRef timer_; +}; + +#endif +} // namespace talk_base + +#endif // TALK_BASE_MACSOCKETSERVER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/macutils.h b/thirdparties/common/include/webrtc-sdk/talk/base/macutils.h new file mode 100644 index 0000000..71fc40e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/macutils.h @@ -0,0 +1,76 @@ +/* + * libjingle + * Copyright 2007 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_MACUTILS_H__ +#define TALK_BASE_MACUTILS_H__ + +#include +#ifdef OSX +#include +#endif +#include + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// + +// Note that some of these functions work for both iOS and Mac OS X. The ones +// that are specific to Mac are #ifdef'ed as such. + +bool ToUtf8(const CFStringRef str16, std::string* str8); +bool ToUtf16(const std::string& str8, CFStringRef* str16); + +#ifdef OSX +void DecodeFourChar(UInt32 fc, std::string* out); + +enum MacOSVersionName { + kMacOSUnknown, // ??? + kMacOSOlder, // 10.2- + kMacOSPanther, // 10.3 + kMacOSTiger, // 10.4 + kMacOSLeopard, // 10.5 + kMacOSSnowLeopard, // 10.6 + kMacOSLion, // 10.7 + kMacOSMountainLion, // 10.8 + kMacOSMavericks, // 10.9 + kMacOSNewer, // 10.10+ +}; + +bool GetOSVersion(int* major, int* minor, int* bugfix); +MacOSVersionName GetOSVersionName(); +bool GetQuickTimeVersion(std::string* version); + +// Runs the given apple script. Only supports scripts that does not +// require user interaction. +bool RunAppleScript(const std::string& script); +#endif + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_MACUTILS_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/macwindowpicker.h b/thirdparties/common/include/webrtc-sdk/talk/base/macwindowpicker.h new file mode 100644 index 0000000..475d7d3 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/macwindowpicker.h @@ -0,0 +1,31 @@ +// Copyright 2010 Google Inc. All Rights Reserved + + +#ifndef TALK_BASE_MACWINDOWPICKER_H_ +#define TALK_BASE_MACWINDOWPICKER_H_ + +#include "talk/base/windowpicker.h" + +namespace talk_base { + +class MacWindowPicker : public WindowPicker { + public: + MacWindowPicker(); + ~MacWindowPicker(); + virtual bool Init(); + virtual bool IsVisible(const WindowId& id); + virtual bool MoveToFront(const WindowId& id); + virtual bool GetWindowList(WindowDescriptionList* descriptions); + virtual bool GetDesktopList(DesktopDescriptionList* descriptions); + virtual bool GetDesktopDimensions(const DesktopId& id, int* width, + int* height); + + private: + void* lib_handle_; + void* get_window_list_; + void* get_window_list_desc_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_MACWINDOWPICKER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/mathutils.h b/thirdparties/common/include/webrtc-sdk/talk/base/mathutils.h new file mode 100644 index 0000000..437882a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/mathutils.h @@ -0,0 +1,37 @@ +/* + * libjingle + * Copyright 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 TALK_BASE_MATHUTILS_H_ +#define TALK_BASE_MATHUTILS_H_ + +#include + +#ifndef M_PI +#define M_PI 3.14159265359f +#endif + +#endif // TALK_BASE_MATHUTILS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/md5.h b/thirdparties/common/include/webrtc-sdk/talk/base/md5.h new file mode 100644 index 0000000..ce408ab --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/md5.h @@ -0,0 +1,40 @@ +/* + * This is the header file for the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + */ + +// Changes(fbarchard): Ported to C++ and Google style guide. +// Made context first parameter in MD5Final for consistency with Sha1. + +#ifndef TALK_BASE_MD5_H_ +#define TALK_BASE_MD5_H_ + +#include "talk/base/basictypes.h" + +// Canonical name for a MD5 context structure, used in many crypto libs. +typedef struct MD5Context MD5_CTX; + +struct MD5Context { + uint32 buf[4]; + uint32 bits[2]; + uint32 in[16]; +}; + +void MD5Init(MD5Context* context); +void MD5Update(MD5Context* context, const uint8* data, size_t len); +void MD5Final(MD5Context* context, uint8 digest[16]); +void MD5Transform(uint32 buf[4], const uint32 in[16]); + +#endif // TALK_BASE_MD5_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/md5digest.h b/thirdparties/common/include/webrtc-sdk/talk/base/md5digest.h new file mode 100644 index 0000000..fadb05c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/md5digest.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_MD5DIGEST_H_ +#define TALK_BASE_MD5DIGEST_H_ + +#include "talk/base/md5.h" +#include "talk/base/messagedigest.h" + +namespace talk_base { + +// A simple wrapper for our MD5 implementation. +class Md5Digest : public MessageDigest { + public: + enum { kSize = 16 }; + Md5Digest() { + MD5Init(&ctx_); + } + virtual size_t Size() const { + return kSize; + } + virtual void Update(const void* buf, size_t len) { + MD5Update(&ctx_, static_cast(buf), len); + } + virtual size_t Finish(void* buf, size_t len) { + if (len < kSize) { + return 0; + } + MD5Final(&ctx_, static_cast(buf)); + MD5Init(&ctx_); // Reset for next use. + return kSize; + } + private: + MD5_CTX ctx_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_MD5DIGEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/messagedigest.h b/thirdparties/common/include/webrtc-sdk/talk/base/messagedigest.h new file mode 100644 index 0000000..e8e0f4f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/messagedigest.h @@ -0,0 +1,126 @@ +/* + * 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_BASE_MESSAGEDIGEST_H_ +#define TALK_BASE_MESSAGEDIGEST_H_ + +#include + +namespace talk_base { + +// Definitions for the digest algorithms. +extern const char DIGEST_MD5[]; +extern const char DIGEST_SHA_1[]; +extern const char DIGEST_SHA_224[]; +extern const char DIGEST_SHA_256[]; +extern const char DIGEST_SHA_384[]; +extern const char DIGEST_SHA_512[]; + +// A general class for computing hashes. +class MessageDigest { + public: + enum { kMaxSize = 64 }; // Maximum known size (SHA-512) + virtual ~MessageDigest() {} + // Returns the digest output size (e.g. 16 bytes for MD5). + virtual size_t Size() const = 0; + // Updates the digest with |len| bytes from |buf|. + virtual void Update(const void* buf, size_t len) = 0; + // Outputs the digest value to |buf| with length |len|. + // Returns the number of bytes written, i.e., Size(). + virtual size_t Finish(void* buf, size_t len) = 0; +}; + +// A factory class for creating digest objects. +class MessageDigestFactory { + public: + 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 +// implementation, and outputs the hash to the buffer |output|, which is +// |out_len| bytes long. Returns the number of bytes written to |output| if +// successful, or 0 if |out_len| was too small. +size_t ComputeDigest(MessageDigest* digest, const void* input, size_t in_len, + void* output, size_t out_len); +// Like the previous function, but creates a digest implementation based on +// the desired digest name |alg|, e.g. DIGEST_SHA_1. Returns 0 if there is no +// digest with the given name. +size_t ComputeDigest(const std::string& alg, const void* input, size_t in_len, + void* output, size_t out_len); +// Computes the hash of |input| using the |digest| hash implementation, and +// returns it as a hex-encoded string. +std::string ComputeDigest(MessageDigest* digest, const std::string& input); +// Like the previous function, but creates a digest implementation based on +// the desired digest name |alg|, e.g. DIGEST_SHA_1. Returns empty string if +// there is no digest with the given name. +std::string ComputeDigest(const std::string& alg, const std::string& input); +// Like the previous function, but returns an explicit result code. +bool ComputeDigest(const std::string& alg, const std::string& input, + std::string* output); + +// Shorthand way to compute a hex-encoded hash using MD5. +inline std::string MD5(const std::string& input) { + return ComputeDigest(DIGEST_MD5, input); +} + +// Functions to compute RFC 2104 HMACs. + +// Computes the HMAC of |in_len| bytes of |input|, using the |digest| hash +// implementation and |key_len| bytes of |key| to key the HMAC, and outputs +// the HMAC to the buffer |output|, which is |out_len| bytes long. Returns the +// number of bytes written to |output| if successful, or 0 if |out_len| was too +// small. +size_t ComputeHmac(MessageDigest* digest, const void* key, size_t key_len, + const void* input, size_t in_len, + void* output, size_t out_len); +// Like the previous function, but creates a digest implementation based on +// the desired digest name |alg|, e.g. DIGEST_SHA_1. Returns 0 if there is no +// digest with the given name. +size_t ComputeHmac(const std::string& alg, const void* key, size_t key_len, + const void* input, size_t in_len, + void* output, size_t out_len); +// Computes the HMAC of |input| using the |digest| hash implementation and |key| +// to key the HMAC, and returns it as a hex-encoded string. +std::string ComputeHmac(MessageDigest* digest, const std::string& key, + const std::string& input); +// Like the previous function, but creates a digest implementation based on +// the desired digest name |alg|, e.g. DIGEST_SHA_1. Returns empty string if +// there is no digest with the given name. +std::string ComputeHmac(const std::string& alg, const std::string& key, + const std::string& input); +// Like the previous function, but returns an explicit result code. +bool ComputeHmac(const std::string& alg, const std::string& key, + const std::string& input, std::string* output); + +} // namespace talk_base + +#endif // TALK_BASE_MESSAGEDIGEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/messagehandler.h b/thirdparties/common/include/webrtc-sdk/talk/base/messagehandler.h new file mode 100644 index 0000000..eb29ee8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/messagehandler.h @@ -0,0 +1,85 @@ +/* + * 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 TALK_BASE_MESSAGEHANDLER_H_ +#define TALK_BASE_MESSAGEHANDLER_H_ + +#include "talk/base/constructormagic.h" + +namespace talk_base { + +struct Message; + +// Messages get dispatched to a MessageHandler + +class MessageHandler { + public: + virtual ~MessageHandler(); + virtual void OnMessage(Message* msg) = 0; + + protected: + MessageHandler() {} + + private: + DISALLOW_COPY_AND_ASSIGN(MessageHandler); +}; + +// Helper class to facilitate executing a functor on a thread. +template +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 FunctorMessageHandler : 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/thirdparties/common/include/webrtc-sdk/talk/base/messagequeue.h b/thirdparties/common/include/webrtc-sdk/talk/base/messagequeue.h new file mode 100644 index 0000000..2032593 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/messagequeue.h @@ -0,0 +1,271 @@ +/* + * 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 TALK_BASE_MESSAGEQUEUE_H_ +#define TALK_BASE_MESSAGEQUEUE_H_ + +#include + +#include +#include +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/constructormagic.h" +#include "talk/base/criticalsection.h" +#include "talk/base/messagehandler.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/scoped_ref_ptr.h" +#include "talk/base/sigslot.h" +#include "talk/base/socketserver.h" +#include "talk/base/timeutils.h" + +namespace talk_base { + +struct Message; +class MessageQueue; + +// MessageQueueManager does cleanup of of message queues + +class MessageQueueManager { + public: + static void Add(MessageQueue *message_queue); + static void Remove(MessageQueue *message_queue); + static void Clear(MessageHandler *handler); + + // For testing purposes, we expose whether or not the MessageQueueManager + // instance has been initialized. It has no other use relative to the rest of + // the functions of this class, which auto-initialize the underlying + // MessageQueueManager instance when necessary. + static bool IsInitialized(); + + private: + static MessageQueueManager* Instance(); + + MessageQueueManager(); + ~MessageQueueManager(); + + void AddInternal(MessageQueue *message_queue); + void RemoveInternal(MessageQueue *message_queue); + void ClearInternal(MessageHandler *handler); + + static MessageQueueManager* instance_; + // This list contains all live MessageQueues. + std::vector message_queues_; + CriticalSection crit_; +}; + +// Derive from this for specialized data +// App manages lifetime, except when messages are purged + +class MessageData { + public: + MessageData() {} + virtual ~MessageData() {} +}; + +template +class TypedMessageData : public MessageData { + public: + explicit TypedMessageData(const T& data) : data_(data) { } + const T& data() const { return data_; } + T& data() { return data_; } + private: + T data_; +}; + +// Like TypedMessageData, but for pointers that require a delete. +template +class ScopedMessageData : public MessageData { + public: + explicit ScopedMessageData(T* data) : data_(data) { } + const scoped_ptr& data() const { return data_; } + scoped_ptr& data() { return data_; } + private: + scoped_ptr data_; +}; + +// Like ScopedMessageData, but for reference counted pointers. +template +class ScopedRefMessageData : public MessageData { + public: + explicit ScopedRefMessageData(T* data) : data_(data) { } + const scoped_refptr& data() const { return data_; } + scoped_refptr& data() { return data_; } + private: + scoped_refptr data_; +}; + +template +inline MessageData* WrapMessageData(const T& data) { + return new TypedMessageData(data); +} + +template +inline const T& UseMessageData(MessageData* data) { + return static_cast< TypedMessageData* >(data)->data(); +} + +template +class DisposeData : public MessageData { + public: + explicit DisposeData(T* data) : data_(data) { } + virtual ~DisposeData() { delete data_; } + private: + T* data_; +}; + +const uint32 MQID_ANY = static_cast(-1); +const uint32 MQID_DISPOSE = static_cast(-2); + +// No destructor + +struct Message { + Message() { + memset(this, 0, sizeof(*this)); + } + inline bool Match(MessageHandler* handler, uint32 id) const { + return (handler == NULL || handler == phandler) + && (id == MQID_ANY || id == message_id); + } + MessageHandler *phandler; + uint32 message_id; + MessageData *pdata; + uint32 ts_sensitive; +}; + +typedef std::list MessageList; + +// DelayedMessage goes into a priority queue, sorted by trigger time. Messages +// with the same trigger time are processed in num_ (FIFO) order. + +class DelayedMessage { + public: + DelayedMessage(int delay, uint32 trigger, uint32 num, const Message& msg) + : cmsDelay_(delay), msTrigger_(trigger), num_(num), msg_(msg) { } + + bool operator< (const DelayedMessage& dmsg) const { + return (dmsg.msTrigger_ < msTrigger_) + || ((dmsg.msTrigger_ == msTrigger_) && (dmsg.num_ < num_)); + } + + int cmsDelay_; // for debugging + uint32 msTrigger_; + uint32 num_; + Message msg_; +}; + +class MessageQueue { + public: + explicit MessageQueue(SocketServer* ss = NULL); + virtual ~MessageQueue(); + + SocketServer* socketserver() { return ss_; } + void set_socketserver(SocketServer* ss); + + // Note: The behavior of MessageQueue has changed. When a MQ is stopped, + // futher Posts and Sends will fail. However, any pending Sends and *ready* + // Posts (as opposed to unexpired delayed Posts) will be delivered before + // Get (or Peek) returns false. By guaranteeing delivery of those messages, + // we eliminate the race condition when an MessageHandler and MessageQueue + // may be destroyed independently of each other. + virtual void Quit(); + virtual bool IsQuitting(); + virtual void Restart(); + + // Get() will process I/O until: + // 1) A message is available (returns true) + // 2) cmsWait seconds have elapsed (returns false) + // 3) Stop() is called (returns false) + virtual bool Get(Message *pmsg, int cmsWait = kForever, + bool process_io = true); + virtual bool Peek(Message *pmsg, int cmsWait = 0); + virtual void Post(MessageHandler *phandler, uint32 id = 0, + MessageData *pdata = NULL, bool time_sensitive = false); + virtual void PostDelayed(int cmsDelay, MessageHandler *phandler, + uint32 id = 0, MessageData *pdata = NULL) { + return DoDelayPost(cmsDelay, TimeAfter(cmsDelay), phandler, id, pdata); + } + virtual void PostAt(uint32 tstamp, MessageHandler *phandler, + uint32 id = 0, MessageData *pdata = NULL) { + return DoDelayPost(TimeUntil(tstamp), tstamp, phandler, id, pdata); + } + virtual void Clear(MessageHandler *phandler, uint32 id = MQID_ANY, + MessageList* removed = NULL); + virtual void Dispatch(Message *pmsg); + virtual void ReceiveSends(); + + // Amount of time until the next message can be retrieved + virtual int GetDelay(); + + bool empty() const { return size() == 0u; } + size_t size() const { + CritScope cs(&crit_); // msgq_.size() is not thread safe. + return msgq_.size() + dmsgq_.size() + (fPeekKeep_ ? 1u : 0u); + } + + // Internally posts a message which causes the doomed object to be deleted + template void Dispose(T* doomed) { + if (doomed) { + Post(NULL, MQID_DISPOSE, new DisposeData(doomed)); + } + } + + // When this signal is sent out, any references to this queue should + // no longer be used. + sigslot::signal0<> SignalQueueDestroyed; + + protected: + class PriorityQueue : public std::priority_queue { + public: + container_type& container() { return c; } + void reheap() { make_heap(c.begin(), c.end(), comp); } + }; + + void DoDelayPost(int cmsDelay, uint32 tstamp, MessageHandler *phandler, + uint32 id, MessageData* pdata); + + // The SocketServer is not owned by MessageQueue. + SocketServer* ss_; + // If a server isn't supplied in the constructor, use this one. + scoped_ptr default_ss_; + bool fStop_; + bool fPeekKeep_; + Message msgPeek_; + MessageList msgq_; + PriorityQueue dmsgq_; + uint32 dmsgq_next_num_; + mutable CriticalSection crit_; + + private: + DISALLOW_COPY_AND_ASSIGN(MessageQueue); +}; + +} // namespace talk_base + +#endif // TALK_BASE_MESSAGEQUEUE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/move.h b/thirdparties/common/include/webrtc-sdk/talk/base/move.h new file mode 100644 index 0000000..b6687e0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/move.h @@ -0,0 +1,207 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBRTC_FILES_TALK_BASE_MOVE_H_ +#define THIRD_PARTY_WEBRTC_FILES_TALK_BASE_MOVE_H_ + +// Macro with the boilerplate that makes a type move-only in C++03. +// +// USAGE +// +// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create +// a "move-only" type. Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be +// the first line in a class declaration. +// +// A class using this macro must call .Pass() (or somehow be an r-value already) +// before it can be: +// +// * Passed as a function argument +// * Used as the right-hand side of an assignment +// * Returned from a function +// +// Each class will still need to define their own "move constructor" and "move +// operator=" to make this useful. Here's an example of the macro, the move +// constructor, and the move operator= from the scoped_ptr class: +// +// template +// class scoped_ptr { +// TALK_MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) +// public: +// scoped_ptr(RValue& other) : ptr_(other.release()) { } +// scoped_ptr& operator=(RValue& other) { +// swap(other); +// return *this; +// } +// }; +// +// Note that the constructor must NOT be marked explicit. +// +// For consistency, the second parameter to the macro should always be RValue +// unless you have a strong reason to do otherwise. It is only exposed as a +// macro parameter so that the move constructor and move operator= don't look +// like they're using a phantom type. +// +// +// HOW THIS WORKS +// +// For a thorough explanation of this technique, see: +// +// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor +// +// The summary is that we take advantage of 2 properties: +// +// 1) non-const references will not bind to r-values. +// 2) C++ can apply one user-defined conversion when initializing a +// variable. +// +// The first lets us disable the copy constructor and assignment operator +// by declaring private version of them with a non-const reference parameter. +// +// For l-values, direct initialization still fails like in +// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment +// operators are private. +// +// For r-values, the situation is different. The copy constructor and +// assignment operator are not viable due to (1), so we are trying to call +// a non-existent constructor and non-existing operator= rather than a private +// one. Since we have not committed an error quite yet, we can provide an +// alternate conversion sequence and a constructor. We add +// +// * a private struct named "RValue" +// * a user-defined conversion "operator RValue()" +// * a "move constructor" and "move operator=" that take the RValue& as +// their sole parameter. +// +// Only r-values will trigger this sequence and execute our "move constructor" +// or "move operator=." L-values will match the private copy constructor and +// operator= first giving a "private in this context" error. This combination +// gives us a move-only type. +// +// For signaling a destructive transfer of data from an l-value, we provide a +// method named Pass() which creates an r-value for the current instance +// triggering the move constructor or move operator=. +// +// Other ways to get r-values is to use the result of an expression like a +// function call. +// +// Here's an example with comments explaining what gets triggered where: +// +// class Foo { +// TALK_MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue); +// +// public: +// ... API ... +// Foo(RValue other); // Move constructor. +// Foo& operator=(RValue rhs); // Move operator= +// }; +// +// Foo MakeFoo(); // Function that returns a Foo. +// +// Foo f; +// Foo f_copy(f); // ERROR: Foo(Foo&) is private in this context. +// Foo f_assign; +// f_assign = f; // ERROR: operator=(Foo&) is private in this context. +// +// +// Foo f(MakeFoo()); // R-value so alternate conversion executed. +// Foo f_copy(f.Pass()); // R-value so alternate conversion executed. +// f = f_copy.Pass(); // R-value so alternate conversion executed. +// +// +// IMPLEMENTATION SUBTLETIES WITH RValue +// +// The RValue struct is just a container for a pointer back to the original +// object. It should only ever be created as a temporary, and no external +// class should ever declare it or use it in a parameter. +// +// It is tempting to want to use the RValue type in function parameters, but +// excluding the limited usage here for the move constructor and move +// operator=, doing so would mean that the function could take both r-values +// and l-values equially which is unexpected. See COMPARED To Boost.Move for +// more details. +// +// An alternate, and incorrect, implementation of the RValue class used by +// Boost.Move makes RValue a fieldless child of the move-only type. RValue& +// is then used in place of RValue in the various operators. The RValue& is +// "created" by doing *reinterpret_cast(this). This has the appeal +// of never creating a temporary RValue struct even with optimizations +// disabled. Also, by virtue of inheritance you can treat the RValue +// reference as if it were the move-only type itself. Unfortunately, +// using the result of this reinterpret_cast<> is actually undefined behavior +// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer +// will generate non-working code. +// +// In optimized builds, both implementations generate the same assembly so we +// choose the one that adheres to the standard. +// +// +// COMPARED TO C++11 +// +// In C++11, you would implement this functionality using an r-value reference +// and our .Pass() method would be replaced with a call to std::move(). +// +// This emulation also has a deficiency where it uses up the single +// user-defined conversion allowed by C++ during initialization. This can +// cause problems in some API edge cases. For instance, in scoped_ptr, it is +// impossible to make a function "void Foo(scoped_ptr p)" accept a +// value of type scoped_ptr even if you add a constructor to +// scoped_ptr<> that would make it look like it should work. C++11 does not +// have this deficiency. +// +// +// COMPARED TO Boost.Move +// +// Our implementation similar to Boost.Move, but we keep the RValue struct +// private to the move-only type, and we don't use the reinterpret_cast<> hack. +// +// In Boost.Move, RValue is the boost::rv<> template. This type can be used +// when writing APIs like: +// +// void MyFunc(boost::rv& f) +// +// that can take advantage of rv<> to avoid extra copies of a type. However you +// would still be able to call this version of MyFunc with an l-value: +// +// Foo f; +// MyFunc(f); // Uh oh, we probably just destroyed |f| w/o calling Pass(). +// +// unless someone is very careful to also declare a parallel override like: +// +// void MyFunc(const Foo& f) +// +// that would catch the l-values first. This was declared unsafe in C++11 and +// a C++11 compiler will explicitly fail MyFunc(f). Unfortunately, we cannot +// ensure this in C++03. +// +// Since we have no need for writing such APIs yet, our implementation keeps +// RValue private and uses a .Pass() method to do the conversion instead of +// trying to write a version of "std::move()." Writing an API like std::move() +// would require the RValue struct to be public. +// +// +// CAVEATS +// +// If you include a move-only type as a field inside a class that does not +// explicitly declare a copy constructor, the containing class's implicit +// copy constructor will change from Containing(const Containing&) to +// Containing(Containing&). This can cause some unexpected errors. +// +// http://llvm.org/bugs/show_bug.cgi?id=11528 +// +// The workaround is to explicitly declare your copy constructor. +// +#define TALK_MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \ + private: \ + struct rvalue_type { \ + explicit rvalue_type(type* object) : object(object) {} \ + type* object; \ + }; \ + type(type&); \ + void operator=(type&); \ + public: \ + operator rvalue_type() { return rvalue_type(this); } \ + type Pass() { return type(rvalue_type(this)); } \ + private: + +#endif // THIRD_PARTY_WEBRTC_FILES_TALK_BASE_MOVE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/multipart.h b/thirdparties/common/include/webrtc-sdk/talk/base/multipart.h new file mode 100644 index 0000000..4ff6d89 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/multipart.h @@ -0,0 +1,94 @@ +// libjingle +// Copyright 2004--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. + +#ifndef TALK_BASE_MULTIPART_H__ +#define TALK_BASE_MULTIPART_H__ + +#include +#include + +#include "talk/base/sigslot.h" +#include "talk/base/stream.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// MultipartStream - Implements an RFC2046 multipart stream by concatenating +// the supplied parts together, and adding the correct boundaries. +/////////////////////////////////////////////////////////////////////////////// + +class MultipartStream : public StreamInterface, public sigslot::has_slots<> { + public: + MultipartStream(const std::string& type, const std::string& boundary); + virtual ~MultipartStream(); + + void GetContentType(std::string* content_type); + + // Note: If content_disposition and/or content_type are the empty string, + // they will be omitted. + bool AddPart(StreamInterface* data_stream, + const std::string& content_disposition, + const std::string& content_type); + bool AddPart(const std::string& data, + const std::string& content_disposition, + const std::string& content_type); + void EndParts(); + + // Calculates the size of a part before actually adding the part. + size_t GetPartSize(const std::string& data, + const std::string& content_disposition, + const std::string& content_type) const; + size_t GetEndPartSize() const; + + // StreamInterface + virtual StreamState GetState() const; + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + virtual void Close(); + virtual bool SetPosition(size_t position); + virtual bool GetPosition(size_t* position) const; + virtual bool GetSize(size_t* size) const; + virtual bool GetAvailable(size_t* size) const; + + private: + typedef std::vector PartList; + + // StreamInterface Slots + void OnEvent(StreamInterface* stream, int events, int error); + + std::string type_, boundary_; + PartList parts_; + bool adding_; + size_t current_; // The index into parts_ of the current read position. + size_t position_; // The current read position in bytes. + + DISALLOW_COPY_AND_ASSIGN(MultipartStream); +}; + +} // namespace talk_base + +#endif // TALK_BASE_MULTIPART_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/natserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/natserver.h new file mode 100644 index 0000000..b17e5e7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/natserver.h @@ -0,0 +1,127 @@ +/* + * 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 TALK_BASE_NATSERVER_H_ +#define TALK_BASE_NATSERVER_H_ + +#include +#include + +#include "talk/base/asyncudpsocket.h" +#include "talk/base/socketaddresspair.h" +#include "talk/base/thread.h" +#include "talk/base/socketfactory.h" +#include "talk/base/nattypes.h" + +namespace talk_base { + +// Change how routes (socketaddress pairs) are compared based on the type of +// NAT. The NAT server maintains a hashtable of the routes that it knows +// about. So these affect which routes are treated the same. +struct RouteCmp { + explicit RouteCmp(NAT* nat); + size_t operator()(const SocketAddressPair& r) const; + bool operator()( + const SocketAddressPair& r1, const SocketAddressPair& r2) const; + + bool symmetric; +}; + +// Changes how addresses are compared based on the filtering rules of the NAT. +struct AddrCmp { + explicit AddrCmp(NAT* nat); + size_t operator()(const SocketAddress& r) const; + bool operator()(const SocketAddress& r1, const SocketAddress& r2) const; + + bool use_ip; + bool use_port; +}; + +// Implements the NAT device. It listens for packets on the internal network, +// translates them, and sends them out over the external network. + +const int NAT_SERVER_PORT = 4237; + +class NATServer : public sigslot::has_slots<> { + public: + NATServer( + NATType type, SocketFactory* internal, const SocketAddress& internal_addr, + SocketFactory* external, const SocketAddress& external_ip); + ~NATServer(); + + SocketAddress internal_address() const { + return server_socket_->GetLocalAddress(); + } + + // Packets received on one of the networks. + void OnInternalPacket(AsyncPacketSocket* socket, const char* buf, + size_t size, const SocketAddress& addr, + const PacketTime& packet_time); + void OnExternalPacket(AsyncPacketSocket* socket, const char* buf, + size_t size, const SocketAddress& remote_addr, + const PacketTime& packet_time); + + private: + typedef std::set AddressSet; + + /* Records a translation and the associated external socket. */ + struct TransEntry { + TransEntry(const SocketAddressPair& r, AsyncUDPSocket* s, NAT* nat); + ~TransEntry(); + + void WhitelistInsert(const SocketAddress& addr); + bool WhitelistContains(const SocketAddress& ext_addr); + + SocketAddressPair route; + AsyncUDPSocket* socket; + AddressSet* whitelist; + CriticalSection crit_; + }; + + typedef std::map InternalMap; + typedef std::map ExternalMap; + + /* Creates a new entry that translates the given route. */ + void Translate(const SocketAddressPair& route); + + /* Determines whether the NAT would filter out a packet from this address. */ + bool ShouldFilterOut(TransEntry* entry, const SocketAddress& ext_addr); + + NAT* nat_; + SocketFactory* internal_; + SocketFactory* external_; + SocketAddress external_ip_; + AsyncUDPSocket* server_socket_; + AsyncSocket* tcp_server_socket_; + InternalMap* int_map_; + ExternalMap* ext_map_; + DISALLOW_EVIL_CONSTRUCTORS(NATServer); +}; + +} // namespace talk_base + +#endif // TALK_BASE_NATSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/natsocketfactory.h b/thirdparties/common/include/webrtc-sdk/talk/base/natsocketfactory.h new file mode 100644 index 0000000..c18d745 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/natsocketfactory.h @@ -0,0 +1,183 @@ +/* + * 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 TALK_BASE_NATSOCKETFACTORY_H_ +#define TALK_BASE_NATSOCKETFACTORY_H_ + +#include +#include +#include + +#include "talk/base/natserver.h" +#include "talk/base/socketaddress.h" +#include "talk/base/socketserver.h" + +namespace talk_base { + +const size_t kNATEncodedIPv4AddressSize = 8U; +const size_t kNATEncodedIPv6AddressSize = 20U; + +// Used by the NAT socket implementation. +class NATInternalSocketFactory { + public: + virtual ~NATInternalSocketFactory() {} + virtual AsyncSocket* CreateInternalSocket(int family, int type, + const SocketAddress& local_addr, SocketAddress* nat_addr) = 0; +}; + +// Creates sockets that will send all traffic through a NAT, using an existing +// NATServer instance running at nat_addr. The actual data is sent using sockets +// from a socket factory, given to the constructor. +class NATSocketFactory : public SocketFactory, public NATInternalSocketFactory { + public: + NATSocketFactory(SocketFactory* factory, const SocketAddress& nat_addr); + + // SocketFactory implementation + virtual Socket* CreateSocket(int type); + virtual Socket* CreateSocket(int family, int type); + virtual AsyncSocket* CreateAsyncSocket(int type); + virtual AsyncSocket* CreateAsyncSocket(int family, int type); + + // NATInternalSocketFactory implementation + virtual AsyncSocket* CreateInternalSocket(int family, int type, + const SocketAddress& local_addr, SocketAddress* nat_addr); + + private: + SocketFactory* factory_; + SocketAddress nat_addr_; + DISALLOW_EVIL_CONSTRUCTORS(NATSocketFactory); +}; + +// Creates sockets that will send traffic through a NAT depending on what +// address they bind to. This can be used to simulate a client on a NAT sending +// to a client that is not behind a NAT. +// Note that the internal addresses of clients must be unique. This is because +// there is only one socketserver per thread, and the Bind() address is used to +// figure out which NAT (if any) the socket should talk to. +// +// Example with 3 NATs (2 cascaded), and 3 clients. +// ss->AddTranslator("1.2.3.4", "192.168.0.1", NAT_ADDR_RESTRICTED); +// ss->AddTranslator("99.99.99.99", "10.0.0.1", NAT_SYMMETRIC)-> +// AddTranslator("10.0.0.2", "192.168.1.1", NAT_OPEN_CONE); +// ss->GetTranslator("1.2.3.4")->AddClient("1.2.3.4", "192.168.0.2"); +// ss->GetTranslator("99.99.99.99")->AddClient("10.0.0.3"); +// ss->GetTranslator("99.99.99.99")->GetTranslator("10.0.0.2")-> +// AddClient("192.168.1.2"); +class NATSocketServer : public SocketServer, public NATInternalSocketFactory { + public: + class Translator; + // holds a list of NATs + class TranslatorMap : private std::map { + public: + ~TranslatorMap(); + Translator* Get(const SocketAddress& ext_ip); + Translator* Add(const SocketAddress& ext_ip, Translator*); + void Remove(const SocketAddress& ext_ip); + Translator* FindClient(const SocketAddress& int_ip); + }; + + // a specific NAT + class Translator { + public: + Translator(NATSocketServer* server, NATType type, + const SocketAddress& int_addr, SocketFactory* ext_factory, + const SocketAddress& ext_addr); + + SocketFactory* internal_factory() { return internal_factory_.get(); } + SocketAddress internal_address() const { + return nat_server_->internal_address(); + } + SocketAddress internal_tcp_address() const { + return SocketAddress(); // nat_server_->internal_tcp_address(); + } + + Translator* GetTranslator(const SocketAddress& ext_ip); + Translator* AddTranslator(const SocketAddress& ext_ip, + const SocketAddress& int_ip, NATType type); + void RemoveTranslator(const SocketAddress& ext_ip); + + bool AddClient(const SocketAddress& int_ip); + void RemoveClient(const SocketAddress& int_ip); + + // Looks for the specified client in this or a child NAT. + Translator* FindClient(const SocketAddress& int_ip); + + private: + NATSocketServer* server_; + scoped_ptr internal_factory_; + scoped_ptr nat_server_; + TranslatorMap nats_; + std::set clients_; + }; + + explicit NATSocketServer(SocketServer* ss); + + SocketServer* socketserver() { return server_; } + MessageQueue* queue() { return msg_queue_; } + + Translator* GetTranslator(const SocketAddress& ext_ip); + Translator* AddTranslator(const SocketAddress& ext_ip, + const SocketAddress& int_ip, NATType type); + void RemoveTranslator(const SocketAddress& ext_ip); + + // SocketServer implementation + virtual Socket* CreateSocket(int type); + virtual Socket* CreateSocket(int family, int type); + + virtual AsyncSocket* CreateAsyncSocket(int type); + virtual AsyncSocket* CreateAsyncSocket(int family, int type); + + virtual void SetMessageQueue(MessageQueue* queue) { + msg_queue_ = queue; + server_->SetMessageQueue(queue); + } + virtual bool Wait(int cms, bool process_io) { + return server_->Wait(cms, process_io); + } + virtual void WakeUp() { + server_->WakeUp(); + } + + // NATInternalSocketFactory implementation + virtual AsyncSocket* CreateInternalSocket(int family, int type, + const SocketAddress& local_addr, SocketAddress* nat_addr); + + private: + SocketServer* server_; + MessageQueue* msg_queue_; + TranslatorMap nats_; + DISALLOW_EVIL_CONSTRUCTORS(NATSocketServer); +}; + +// Free-standing NAT helper functions. +size_t PackAddressForNAT(char* buf, size_t buf_size, + const SocketAddress& remote_addr); +size_t UnpackAddressFromNAT(const char* buf, size_t buf_size, + SocketAddress* remote_addr); +} // namespace talk_base + +#endif // TALK_BASE_NATSOCKETFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/nattypes.h b/thirdparties/common/include/webrtc-sdk/talk/base/nattypes.h new file mode 100644 index 0000000..a10f4b9 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/nattypes.h @@ -0,0 +1,64 @@ +/* + * 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 TALK_BASE_NATTYPE_H__ +#define TALK_BASE_NATTYPE_H__ + +namespace talk_base { + +/* Identifies each type of NAT that can be simulated. */ +enum NATType { + NAT_OPEN_CONE, + NAT_ADDR_RESTRICTED, + NAT_PORT_RESTRICTED, + NAT_SYMMETRIC +}; + +// Implements the rules for each specific type of NAT. +class NAT { +public: + virtual ~NAT() { } + + // Determines whether this NAT uses both source and destination address when + // checking whether a mapping already exists. + virtual bool IsSymmetric() = 0; + + // Determines whether this NAT drops packets received from a different IP + // the one last sent to. + virtual bool FiltersIP() = 0; + + // Determines whether this NAT drops packets received from a different port + // the one last sent to. + virtual bool FiltersPort() = 0; + + // Returns an implementation of the given type of NAT. + static NAT* Create(NATType type); +}; + +} // namespace talk_base + +#endif // TALK_BASE_NATTYPE_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/nethelpers.h b/thirdparties/common/include/webrtc-sdk/talk/base/nethelpers.h new file mode 100644 index 0000000..28fc566 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/nethelpers.h @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_NETHELPERS_H_ +#define TALK_BASE_NETHELPERS_H_ + +#ifdef POSIX +#include +#include +#elif WIN32 +#include // NOLINT +#endif + +#include + +#include "talk/base/asyncresolverinterface.h" +#include "talk/base/signalthread.h" +#include "talk/base/sigslot.h" +#include "talk/base/socketaddress.h" + +namespace talk_base { + +class AsyncResolverTest; + +// AsyncResolver will perform async DNS resolution, signaling the result on +// the SignalDone from AsyncResolverInterface when the operation completes. +class AsyncResolver : public SignalThread, public AsyncResolverInterface { + public: + AsyncResolver(); + virtual ~AsyncResolver() {} + + virtual void Start(const SocketAddress& addr); + virtual bool GetResolvedAddress(int family, SocketAddress* addr) const; + virtual int GetError() const { return error_; } + virtual void Destroy(bool wait) { SignalThread::Destroy(wait); } + + const std::vector& addresses() const { return addresses_; } + void set_error(int error) { error_ = error; } + + protected: + virtual void DoWork(); + virtual void OnWorkDone(); + + private: + SocketAddress addr_; + std::vector addresses_; + int error_; +}; + +// talk_base namespaced wrappers for inet_ntop and inet_pton so we can avoid +// the windows-native versions of these. +const char* inet_ntop(int af, const void *src, char* dst, socklen_t size); +int inet_pton(int af, const char* src, void *dst); + +bool HasIPv6Enabled(); +} // namespace talk_base + +#endif // TALK_BASE_NETHELPERS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/network.h b/thirdparties/common/include/webrtc-sdk/talk/base/network.h new file mode 100644 index 0000000..0c5349f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/network.h @@ -0,0 +1,262 @@ +/* + * 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 TALK_BASE_NETWORK_H_ +#define TALK_BASE_NETWORK_H_ + +#include +#include +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/ipaddress.h" +#include "talk/base/messagehandler.h" +#include "talk/base/sigslot.h" + +#if defined(POSIX) +struct ifaddrs; +#endif // defined(POSIX) + +namespace talk_base { + +class Network; +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 { + public: + typedef std::vector NetworkList; + + NetworkManager(); + virtual ~NetworkManager(); + + // Called when network list is updated. + sigslot::signal0<> SignalNetworksChanged; + + // Indicates a failure when getting list of network interfaces. + sigslot::signal0<> SignalError; + + // Start/Stop monitoring of network interfaces + // list. SignalNetworksChanged or SignalError is emitted immidiately + // after StartUpdating() is called. After that SignalNetworksChanged + // is emitted wheneven list of networks changes. + virtual void StartUpdating() = 0; + virtual void StopUpdating() = 0; + + // Returns the current list of networks available on this machine. + // UpdateNetworks() must be called before this method is called. + // It makes sure that repeated calls return the same object for a + // given network, so that quality is tracked appropriately. Does not + // include ignored networks. + virtual void GetNetworks(NetworkList* networks) const = 0; + + // Dumps a list of networks available to LS_INFO. + virtual void DumpNetworks(bool include_ignored) {} +}; + +// Base class for NetworkManager implementations. +class NetworkManagerBase : public NetworkManager { + public: + NetworkManagerBase(); + virtual ~NetworkManagerBase(); + + virtual void GetNetworks(std::vector* networks) const; + bool ipv6_enabled() const { return ipv6_enabled_; } + void set_ipv6_enabled(bool enabled) { ipv6_enabled_ = enabled; } + + protected: + typedef std::map NetworkMap; + // Updates |networks_| with the networks listed in |list|. If + // |network_map_| already has a Network object for a network listed + // in the |list| then it is reused. Accept ownership of the Network + // objects in the |list|. |changed| will be set to true if there is + // any change in the network list. + void MergeNetworkList(const NetworkList& list, bool* changed); + + private: + friend class NetworkTest; + void DoUpdateNetworks(); + + NetworkList networks_; + NetworkMap networks_map_; + bool ipv6_enabled_; +}; + +// Basic implementation of the NetworkManager interface that gets list +// of networks using OS APIs. +class BasicNetworkManager : public NetworkManagerBase, + public MessageHandler { + public: + BasicNetworkManager(); + virtual ~BasicNetworkManager(); + + virtual void StartUpdating(); + virtual void StopUpdating(); + + // Logs the available networks. + virtual void DumpNetworks(bool include_ignored); + + // MessageHandler interface. + virtual void OnMessage(Message* msg); + bool started() { return start_count_ > 0; } + + // Sets the network ignore list, which is empty by default. Any network on + // the ignore list will be filtered from network enumeration results. + void set_network_ignore_list(const std::vector& list) { + network_ignore_list_ = list; + } +#if defined(ANDROID) || defined(LINUX) + // Sets the flag for ignoring non-default routes. + void set_ignore_non_default_routes(bool value) { + ignore_non_default_routes_ = true; + } +#endif + + protected: +#if defined(POSIX) + // Separated from CreateNetworks for tests. + void ConvertIfAddrs(ifaddrs* interfaces, + bool include_ignored, + NetworkList* networks) const; +#endif // defined(POSIX) + + // Creates a network object for each network available on the machine. + bool CreateNetworks(bool include_ignored, NetworkList* networks) const; + + // Determines if a network should be ignored. + bool IsIgnoredNetwork(const Network& network) const; + + private: + friend class NetworkTest; + + void DoUpdateNetworks(); + + Thread* thread_; + bool sent_first_update_; + int start_count_; + std::vector network_ignore_list_; + bool ignore_non_default_routes_; +}; + +// Represents a Unix-type network interface, with a name and single address. +class Network { + public: + 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_; } + + // Returns the OS-assigned name for this network. This is useful for + // debugging but should not be sent over the wire (for privacy reasons). + const std::string& description() const { return description_; } + + // Returns the prefix for this network. + const IPAddress& prefix() const { return prefix_; } + // 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. + // Returns an unset IP if this network has no active addresses. + IPAddress ip() const { + if (ips_.size() == 0) { + return IPAddress(); + } + return ips_.at(0); + } + // Adds an active IP address to this network. Does not check for duplicates. + void AddIP(const IPAddress& ip) { ips_.push_back(ip); } + + // Sets the network's IP address list. Returns true if new IP addresses were + // detected. Passing true to already_changed skips this check. + bool SetIPs(const std::vector& ips, bool already_changed); + // Get the list of IP Addresses associated with this network. + const std::vector& GetIPs() { return ips_;} + // Clear the network's list of addresses. + void ClearIPs() { ips_.clear(); } + + // Returns the scope-id of the network's address. + // Should only be relevant for link-local IPv6 addresses. + int scope_id() const { return scope_id_; } + void set_scope_id(int id) { scope_id_ = id; } + + // Indicates whether this network should be ignored, perhaps because + // the IP is 0, or the interface is one we know is invalid. + 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: + std::string name_; + std::string description_; + IPAddress prefix_; + int prefix_length_; + std::string key_; + std::vector ips_; + int scope_id_; + bool ignored_; + AdapterType type_; + int preference_; + + friend class NetworkManager; +}; + +} // namespace talk_base + +#endif // TALK_BASE_NETWORK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/nssidentity.h b/thirdparties/common/include/webrtc-sdk/talk/base/nssidentity.h new file mode 100644 index 0000000..41a18df --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/nssidentity.h @@ -0,0 +1,147 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_NSSIDENTITY_H_ +#define TALK_BASE_NSSIDENTITY_H_ + +#include + +#include "cert.h" +#include "nspr.h" +#include "hasht.h" +#include "keythi.h" + +#include "talk/base/common.h" +#include "talk/base/logging.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sslidentity.h" + +namespace talk_base { + +class NSSKeyPair { + public: + NSSKeyPair(SECKEYPrivateKey* privkey, SECKEYPublicKey* pubkey) : + privkey_(privkey), pubkey_(pubkey) {} + ~NSSKeyPair(); + + // Generate a 1024-bit RSA key pair. + static NSSKeyPair* Generate(); + NSSKeyPair* GetReference(); + + SECKEYPrivateKey* privkey() const { return privkey_; } + SECKEYPublicKey * pubkey() const { return pubkey_; } + + private: + SECKEYPrivateKey* privkey_; + SECKEYPublicKey* pubkey_; + + DISALLOW_EVIL_CONSTRUCTORS(NSSKeyPair); +}; + + +class NSSCertificate : public SSLCertificate { + public: + static NSSCertificate* FromPEMString(const std::string& pem_string); + // The caller retains ownership of the argument to all the constructors, + // and the constructor makes a copy. + explicit NSSCertificate(CERTCertificate* cert); + explicit NSSCertificate(CERTCertList* cert_list); + virtual ~NSSCertificate() { + if (certificate_) + CERT_DestroyCertificate(certificate_); + } + + virtual NSSCertificate* GetReference() const; + + virtual std::string ToPEMString() const; + + virtual void ToDER(Buffer* der_buffer) const; + + virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const; + + virtual bool ComputeDigest(const std::string& algorithm, + 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, size_t* length); + + // Comparison. Only the certificate itself is considered, not the chain. + bool Equals(const NSSCertificate* tocompare) const; + + private: + NSSCertificate(CERTCertificate* cert, SSLCertChain* chain); + static bool GetDigestObject(const std::string& algorithm, + const SECHashObject** hash_object); + + CERTCertificate* certificate_; + scoped_ptr chain_; + + DISALLOW_EVIL_CONSTRUCTORS(NSSCertificate); +}; + +// Represents a SSL key pair and certificate for NSS. +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() { + LOG(LS_INFO) << "Destroying NSS identity"; + } + + virtual NSSIdentity* GetReference() const; + virtual NSSCertificate& certificate() const; + + NSSKeyPair* keypair() const { return keypair_.get(); } + + private: + NSSIdentity(NSSKeyPair* keypair, NSSCertificate* cert) : + keypair_(keypair), certificate_(cert) {} + + static NSSIdentity* GenerateInternal(const SSLIdentityParams& params); + + talk_base::scoped_ptr keypair_; + talk_base::scoped_ptr certificate_; + + DISALLOW_EVIL_CONSTRUCTORS(NSSIdentity); +}; + +} // namespace talk_base + +#endif // TALK_BASE_NSSIDENTITY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/nssstreamadapter.h b/thirdparties/common/include/webrtc-sdk/talk/base/nssstreamadapter.h new file mode 100644 index 0000000..7c879cb --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/nssstreamadapter.h @@ -0,0 +1,129 @@ +/* + * libjingle + * Copyright 2004--2008, Google Inc. + * Copyright 2011, 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. + */ + +#ifndef TALK_BASE_NSSSTREAMADAPTER_H_ +#define TALK_BASE_NSSSTREAMADAPTER_H_ + +#include +#include + +#include "nspr.h" +#include "nss.h" +#include "secmodt.h" + +#include "talk/base/buffer.h" +#include "talk/base/nssidentity.h" +#include "talk/base/ssladapter.h" +#include "talk/base/sslstreamadapter.h" +#include "talk/base/sslstreamadapterhelper.h" + +namespace talk_base { + +// Singleton +class NSSContext { + public: + NSSContext() {} + ~NSSContext() { + } + + static PK11SlotInfo *GetSlot() { + return Instance() ? Instance()->slot_: NULL; + } + + static NSSContext *Instance(); + static bool InitializeSSL(VerificationCallback callback); + static bool InitializeSSLThread(); + static bool CleanupSSL(); + + private: + PK11SlotInfo *slot_; // The PKCS-11 slot + static bool initialized; // Was this initialized? + static NSSContext *global_nss_context; // The global context +}; + + +class NSSStreamAdapter : public SSLStreamAdapterHelper { + public: + explicit NSSStreamAdapter(StreamInterface* stream); + virtual ~NSSStreamAdapter(); + bool Init(); + + virtual StreamResult Read(void* data, size_t data_len, + size_t* read, int* error); + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + void OnMessage(Message *msg); + + // Key Extractor interface + virtual bool ExportKeyingMaterial(const std::string& label, + const uint8* context, + size_t context_len, + bool use_context, + uint8* result, + size_t result_len); + + // DTLS-SRTP interface + virtual bool SetDtlsSrtpCiphers(const std::vector& ciphers); + virtual bool GetDtlsSrtpCipher(std::string* cipher); + + // Capabilities interfaces + static bool HaveDtls(); + static bool HaveDtlsSrtp(); + static bool HaveExporter(); + + protected: + // Override SSLStreamAdapter + virtual void OnEvent(StreamInterface* stream, int events, int err); + + // Override SSLStreamAdapterHelper + virtual int BeginSSL(); + virtual void Cleanup(); + virtual bool GetDigestLength(const std::string& algorithm, size_t* length) { + return NSSCertificate::GetDigestLength(algorithm, length); + } + + private: + int ContinueSSL(); + static SECStatus AuthCertificateHook(void *arg, PRFileDesc *fd, + PRBool checksig, PRBool isServer); + static SECStatus GetClientAuthDataHook(void *arg, PRFileDesc *fd, + CERTDistNames *caNames, + CERTCertificate **pRetCert, + SECKEYPrivateKey **pRetKey); + + PRFileDesc *ssl_fd_; // NSS's SSL file descriptor + static bool initialized; // Was InitializeSSL() called? + bool cert_ok_; // Did we get and check a cert + std::vector srtp_ciphers_; // SRTP cipher list + + static PRDescIdentity nspr_layer_identity; // The NSPR layer identity +}; + +} // namespace talk_base + +#endif // TALK_BASE_NSSSTREAMADAPTER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/nullsocketserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/nullsocketserver.h new file mode 100644 index 0000000..518ba60 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/nullsocketserver.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_NULLSOCKETSERVER_H_ +#define TALK_BASE_NULLSOCKETSERVER_H_ + +#include "talk/base/event.h" +#include "talk/base/physicalsocketserver.h" + +namespace talk_base { + +// NullSocketServer + +class NullSocketServer : public talk_base::SocketServer { + public: + NullSocketServer() : event_(false, false) {} + + virtual bool Wait(int cms, bool process_io) { + event_.Wait(cms); + return true; + } + + virtual void WakeUp() { + event_.Set(); + } + + virtual talk_base::Socket* CreateSocket(int type) { + ASSERT(false); + return NULL; + } + + virtual talk_base::Socket* CreateSocket(int family, int type) { + ASSERT(false); + return NULL; + } + + virtual talk_base::AsyncSocket* CreateAsyncSocket(int type) { + ASSERT(false); + return NULL; + } + + virtual talk_base::AsyncSocket* CreateAsyncSocket(int family, int type) { + ASSERT(false); + return NULL; + } + + + private: + talk_base::Event event_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_NULLSOCKETSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/openssl.h b/thirdparties/common/include/webrtc-sdk/talk/base/openssl.h new file mode 100644 index 0000000..5c2dcca --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/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 + +#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/thirdparties/common/include/webrtc-sdk/talk/base/openssladapter.h b/thirdparties/common/include/webrtc-sdk/talk/base/openssladapter.h new file mode 100644 index 0000000..456b862 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/openssladapter.h @@ -0,0 +1,105 @@ +/* + * 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 TALK_BASE_OPENSSLADAPTER_H__ +#define TALK_BASE_OPENSSLADAPTER_H__ + +#include +#include "talk/base/ssladapter.h" + +typedef struct ssl_st SSL; +typedef struct ssl_ctx_st SSL_CTX; +typedef struct x509_store_ctx_st X509_STORE_CTX; + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// + +class OpenSSLAdapter : public SSLAdapter { +public: + static bool InitializeSSL(VerificationCallback callback); + static bool InitializeSSLThread(); + static bool CleanupSSL(); + + OpenSSLAdapter(AsyncSocket* socket); + virtual ~OpenSSLAdapter(); + + virtual int StartSSL(const char* hostname, bool restartable); + virtual int Send(const void* pv, size_t cb); + virtual int Recv(void* pv, size_t cb); + virtual int Close(); + + // Note that the socket returns ST_CONNECTING while SSL is being negotiated. + virtual ConnState GetState() const; + +protected: + virtual void OnConnectEvent(AsyncSocket* socket); + virtual void OnReadEvent(AsyncSocket* socket); + virtual void OnWriteEvent(AsyncSocket* socket); + virtual void OnCloseEvent(AsyncSocket* socket, int err); + +private: + enum SSLState { + SSL_NONE, SSL_WAIT, SSL_CONNECTING, SSL_CONNECTED, SSL_ERROR + }; + + int BeginSSL(); + int ContinueSSL(); + void Error(const char* context, int err, bool signal = true); + void Cleanup(); + + static bool VerifyServerName(SSL* ssl, const char* host, + bool ignore_bad_cert); + bool SSLPostConnectionCheck(SSL* ssl, const char* host); +#if _DEBUG + static void SSLInfoCallback(const SSL* s, int where, int ret); +#endif // !_DEBUG + static int SSLVerifyCallback(int ok, X509_STORE_CTX* store); + static VerificationCallback custom_verify_callback_; + friend class OpenSSLStreamAdapter; // for custom_verify_callback_; + + static bool ConfigureTrustedRootCertificates(SSL_CTX* ctx); + static SSL_CTX* SetupSSLContext(); + + SSLState state_; + bool ssl_read_needs_write_; + bool ssl_write_needs_read_; + // If true, socket will retain SSL configuration after Close. + bool restartable_; + + SSL* ssl_; + SSL_CTX* ssl_ctx_; + std::string ssl_host_name_; + + bool custom_verification_succeeded_; +}; + +///////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_OPENSSLADAPTER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/openssldigest.h b/thirdparties/common/include/webrtc-sdk/talk/base/openssldigest.h new file mode 100644 index 0000000..6f98f6a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/openssldigest.h @@ -0,0 +1,67 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_OPENSSLDIGEST_H_ +#define TALK_BASE_OPENSSLDIGEST_H_ + +#include + +#include "talk/base/messagedigest.h" + +namespace talk_base { + +// An implementation of the digest class that uses OpenSSL. +class OpenSSLDigest : public MessageDigest { + public: + // Creates an OpenSSLDigest with |algorithm| as the hash algorithm. + explicit OpenSSLDigest(const std::string& algorithm); + ~OpenSSLDigest(); + // Returns the digest output size (e.g. 16 bytes for MD5). + virtual size_t Size() const; + // Updates the digest with |len| bytes from |buf|. + virtual void Update(const void* buf, size_t len); + // Outputs the digest value to |buf| with length |len|. + virtual size_t Finish(void* buf, size_t len); + + // Helper function to look up a digest's EVP by name. + static bool GetDigestEVP(const std::string &algorithm, + const EVP_MD** md); + // Helper function to look up a digest's name by EVP. + static bool GetDigestName(const EVP_MD* md, + std::string* algorithm); + // Helper function to get the length of a digest. + static bool GetDigestSize(const std::string &algorithm, + size_t* len); + + private: + EVP_MD_CTX ctx_; + const EVP_MD* md_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_OPENSSLDIGEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/opensslidentity.h b/thirdparties/common/include/webrtc-sdk/talk/base/opensslidentity.h new file mode 100644 index 0000000..b48ba8e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/opensslidentity.h @@ -0,0 +1,167 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_OPENSSLIDENTITY_H_ +#define TALK_BASE_OPENSSLIDENTITY_H_ + +#include +#include + +#include + +#include "talk/base/common.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sslidentity.h" + +typedef struct ssl_ctx_st SSL_CTX; + +namespace talk_base { + +// OpenSSLKeyPair encapsulates an OpenSSL EVP_PKEY* keypair object, +// which is reference counted inside the OpenSSL library. +class OpenSSLKeyPair { + public: + explicit OpenSSLKeyPair(EVP_PKEY* pkey) : pkey_(pkey) { + ASSERT(pkey_ != NULL); + } + + static OpenSSLKeyPair* Generate(); + + virtual ~OpenSSLKeyPair(); + + virtual OpenSSLKeyPair* GetReference() { + AddReference(); + return new OpenSSLKeyPair(pkey_); + } + + EVP_PKEY* pkey() const { return pkey_; } + + private: + void AddReference(); + + EVP_PKEY* pkey_; + + DISALLOW_EVIL_CONSTRUCTORS(OpenSSLKeyPair); +}; + +// OpenSSLCertificate encapsulates an OpenSSL X509* certificate object, +// which is also reference counted inside the OpenSSL library. +class OpenSSLCertificate : public SSLCertificate { + public: + // Caller retains ownership of the X509 object. + explicit OpenSSLCertificate(X509* x509) : x509_(x509) { + AddReference(); + } + + static OpenSSLCertificate* Generate(OpenSSLKeyPair* key_pair, + const SSLIdentityParams& params); + static OpenSSLCertificate* FromPEMString(const std::string& pem_string); + + virtual ~OpenSSLCertificate(); + + virtual OpenSSLCertificate* GetReference() const { + return new OpenSSLCertificate(x509_); + } + + X509* x509() const { return x509_; } + + virtual std::string ToPEMString() const; + + 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, + 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, + size_t size, + size_t* length); + + virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const; + + virtual bool GetChain(SSLCertChain** chain) const { + // Chains are not yet supported when using OpenSSL. + // OpenSSLStreamAdapter::SSLVerifyCallback currently requires the remote + // certificate to be self-signed. + return false; + } + + private: + void AddReference() const; + + X509* x509_; + + DISALLOW_EVIL_CONSTRUCTORS(OpenSSLCertificate); +}; + +// Holds a keypair and certificate together, and a method to generate +// them consistently. +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() { } + + virtual const OpenSSLCertificate& certificate() const { + return *certificate_; + } + + virtual OpenSSLIdentity* GetReference() const { + return new OpenSSLIdentity(key_pair_->GetReference(), + certificate_->GetReference()); + } + + // Configure an SSL context object to use our key and certificate. + bool ConfigureIdentity(SSL_CTX* ctx); + + private: + OpenSSLIdentity(OpenSSLKeyPair* key_pair, + OpenSSLCertificate* certificate) + : key_pair_(key_pair), certificate_(certificate) { + ASSERT(key_pair != NULL); + ASSERT(certificate != NULL); + } + + static OpenSSLIdentity* GenerateInternal(const SSLIdentityParams& params); + + scoped_ptr key_pair_; + scoped_ptr certificate_; + + DISALLOW_EVIL_CONSTRUCTORS(OpenSSLIdentity); +}; + + +} // namespace talk_base + +#endif // TALK_BASE_OPENSSLIDENTITY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/opensslstreamadapter.h b/thirdparties/common/include/webrtc-sdk/talk/base/opensslstreamadapter.h new file mode 100644 index 0000000..218345d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/opensslstreamadapter.h @@ -0,0 +1,215 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_OPENSSLSTREAMADAPTER_H__ +#define TALK_BASE_OPENSSLSTREAMADAPTER_H__ + +#include +#include + +#include "talk/base/buffer.h" +#include "talk/base/sslstreamadapter.h" +#include "talk/base/opensslidentity.h" + +typedef struct ssl_st SSL; +typedef struct ssl_ctx_st SSL_CTX; +typedef struct x509_store_ctx_st X509_STORE_CTX; + +namespace talk_base { + +// This class was written with OpenSSLAdapter (a socket adapter) as a +// starting point. It has similar structure and functionality, with +// the peer-to-peer mode added. +// +// Static methods to initialize and deinit the SSL library are in +// OpenSSLAdapter. This class also uses +// OpenSSLAdapter::custom_verify_callback_ (a static field). These +// should probably be moved out to a neutral class. +// +// In a few cases I have factored out some OpenSSLAdapter code into +// static methods so it can be reused from this class. Eventually that +// code should probably be moved to a common support +// class. Unfortunately there remain a few duplicated sections of +// code. I have not done more restructuring because I did not want to +// affect existing code that uses OpenSSLAdapter. +// +// This class does not support the SSL connection restart feature +// present in OpenSSLAdapter. I am not entirely sure how the feature +// is useful and I am not convinced that it works properly. +// +// This implementation is careful to disallow data exchange after an +// SSL error, and it has an explicit SSL_CLOSED state. It should not +// be possible to send any data in clear after one of the StartSSL +// methods has been called. + +// Look in sslstreamadapter.h for documentation of the methods. + +class OpenSSLIdentity; + +/////////////////////////////////////////////////////////////////////////////// + +class OpenSSLStreamAdapter : public SSLStreamAdapter { + public: + explicit OpenSSLStreamAdapter(StreamInterface* stream); + virtual ~OpenSSLStreamAdapter(); + + virtual void SetIdentity(SSLIdentity* identity); + + // Default argument is for compatibility + virtual void SetServerRole(SSLRole role = SSL_SERVER); + virtual bool SetPeerCertificateDigest(const std::string& digest_alg, + const unsigned char* digest_val, + size_t digest_len); + + virtual bool GetPeerCertificate(SSLCertificate** cert) const; + + virtual int StartSSLWithServer(const char* server_name); + virtual int StartSSLWithPeer(); + virtual void SetMode(SSLMode mode); + + virtual StreamResult Read(void* data, size_t data_len, + size_t* read, int* error); + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + virtual void Close(); + virtual StreamState GetState() const; + + // Key Extractor interface + virtual bool ExportKeyingMaterial(const std::string& label, + const uint8* context, + size_t context_len, + bool use_context, + uint8* result, + size_t result_len); + + + // DTLS-SRTP interface + virtual bool SetDtlsSrtpCiphers(const std::vector& ciphers); + virtual bool GetDtlsSrtpCipher(std::string* cipher); + + // Capabilities interfaces + static bool HaveDtls(); + static bool HaveDtlsSrtp(); + static bool HaveExporter(); + + protected: + virtual void OnEvent(StreamInterface* stream, int events, int err); + + private: + enum SSLState { + // Before calling one of the StartSSL methods, data flows + // in clear text. + SSL_NONE, + SSL_WAIT, // waiting for the stream to open to start SSL negotiation + SSL_CONNECTING, // SSL negotiation in progress + SSL_CONNECTED, // SSL stream successfully established + SSL_ERROR, // some SSL error occurred, stream is closed + SSL_CLOSED // Clean close + }; + + enum { MSG_TIMEOUT = MSG_MAX+1}; + + // The following three methods return 0 on success and a negative + // error code on failure. The error code may be from OpenSSL or -1 + // on some other error cases, so it can't really be interpreted + // unfortunately. + + // Go from state SSL_NONE to either SSL_CONNECTING or SSL_WAIT, + // depending on whether the underlying stream is already open or + // not. + int StartSSL(); + // Prepare SSL library, state is SSL_CONNECTING. + int BeginSSL(); + // Perform SSL negotiation steps. + int ContinueSSL(); + + // Error handler helper. signal is given as true for errors in + // asynchronous contexts (when an error method was not returned + // through some other method), and in that case an SE_CLOSE event is + // raised on the stream with the specified error. + // A 0 error means a graceful close, otherwise there is not really enough + // context to interpret the error code. + void Error(const char* context, int err, bool signal); + void Cleanup(); + + // Override MessageHandler + virtual void OnMessage(Message* msg); + + // Flush the input buffers by reading left bytes (for DTLS) + void FlushInput(unsigned int left); + + // SSL library configuration + SSL_CTX* SetupSSLContext(); + // SSL verification check + bool SSLPostConnectionCheck(SSL* ssl, const char* server_name, + const X509* peer_cert, + const std::string& peer_digest); + // SSL certification verification error handler, called back from + // the openssl library. Returns an int interpreted as a boolean in + // the C style: zero means verification failure, non-zero means + // 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 + // Whether the SSL negotiation is blocked on needing to read or + // write to the wrapped stream. + bool ssl_read_needs_write_; + bool ssl_write_needs_read_; + + SSL* ssl_; + SSL_CTX* ssl_ctx_; + + // Our key and certificate, mostly useful in peer-to-peer mode. + scoped_ptr identity_; + // in traditional mode, the server name that the server's certificate + // must specify. Empty in peer-to-peer mode. + std::string ssl_server_name_; + // The certificate that the peer must present or did present. Initially + // null in traditional mode, until the connection is established. + scoped_ptr peer_certificate_; + // In peer-to-peer mode, the digest of the certificate that + // the peer must present. + Buffer peer_certificate_digest_value_; + std::string peer_certificate_digest_algorithm_; + + // OpenSSLAdapter::custom_verify_callback_ result + bool custom_verification_succeeded_; + + // The DtlsSrtp ciphers + std::string srtp_ciphers_; + + // Do DTLS or not + SSLMode ssl_mode_; +}; + +///////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_OPENSSLSTREAMADAPTER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/optionsfile.h b/thirdparties/common/include/webrtc-sdk/talk/base/optionsfile.h new file mode 100644 index 0000000..68b351b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/optionsfile.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_OPTIONSFILE_H_ +#define TALK_BASE_OPTIONSFILE_H_ + +#include +#include + +namespace talk_base { + +// Implements storage of simple options in a text file on disk. This is +// cross-platform, but it is intended mostly for Linux where there is no +// first-class options storage system. +class OptionsFile { + public: + OptionsFile(const std::string &path); + + // Loads the file from disk, overwriting the in-memory values. + bool Load(); + // Saves the contents in memory, overwriting the on-disk values. + bool Save(); + + bool GetStringValue(const std::string& option, std::string* out_val) const; + bool GetIntValue(const std::string& option, int* out_val) const; + bool SetStringValue(const std::string& option, const std::string& val); + bool SetIntValue(const std::string& option, int val); + bool RemoveValue(const std::string& option); + + private: + typedef std::map OptionsMap; + + static bool IsLegalName(const std::string &name); + static bool IsLegalValue(const std::string &value); + + std::string path_; + OptionsMap options_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_OPTIONSFILE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/pathutils.h b/thirdparties/common/include/webrtc-sdk/talk/base/pathutils.h new file mode 100644 index 0000000..ce060e7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/pathutils.h @@ -0,0 +1,180 @@ +/* + * 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 TALK_BASE_PATHUTILS_H__ +#define TALK_BASE_PATHUTILS_H__ + +#include +// Temporary, until deprecated helpers are removed. +#include "talk/base/fileutils.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// Pathname - parsing of pathnames into components, and vice versa. +// +// To establish consistent terminology, a filename never contains a folder +// component. A folder never contains a filename. A pathname may include +// a folder and/or filename component. Here are some examples: +// +// pathname() /home/john/example.txt +// folder() /home/john/ +// filename() example.txt +// parent_folder() /home/ +// folder_name() john/ +// basename() example +// extension() .txt +// +// Basename may begin, end, and/or include periods, but no folder delimiters. +// If extension exists, it consists of a period followed by zero or more +// non-period/non-delimiter characters, and basename is non-empty. +/////////////////////////////////////////////////////////////////////////////// + +class Pathname { +public: + // Folder delimiters are slash and backslash + static bool IsFolderDelimiter(char ch); + static char DefaultFolderDelimiter(); + + Pathname(); + Pathname(const std::string& pathname); + Pathname(const std::string& folder, const std::string& filename); + + // Set's the default folder delimiter for this Pathname + char folder_delimiter() const { return folder_delimiter_; } + void SetFolderDelimiter(char delimiter); + + // Normalize changes all folder delimiters to folder_delimiter() + void Normalize(); + + // Reset to the empty pathname + void clear(); + + // Returns true if the pathname is empty. Note: this->pathname().empty() + // is always false. + bool empty() const; + + std::string url() const; + + // Returns the folder and filename components. If the pathname is empty, + // returns a string representing the current directory (as a relative path, + // i.e., "."). + std::string pathname() const; + void SetPathname(const std::string& pathname); + void SetPathname(const std::string& folder, const std::string& filename); + + // Append pathname to the current folder (if any). Any existing filename + // will be discarded. + void AppendPathname(const std::string& pathname); + + std::string folder() const; + std::string folder_name() const; + std::string parent_folder() const; + // SetFolder and AppendFolder will append a folder delimiter, if needed. + void SetFolder(const std::string& folder); + void AppendFolder(const std::string& folder); + + std::string basename() const; + bool SetBasename(const std::string& basename); + + std::string extension() const; + // SetExtension will prefix a period, if needed. + bool SetExtension(const std::string& extension); + + std::string filename() const; + bool SetFilename(const std::string& filename); + +#ifdef WIN32 + bool GetDrive(char *drive, uint32 bytes) const; + static bool GetDrive(char *drive, uint32 bytes,const std::string& pathname); +#endif + +private: + std::string folder_, basename_, extension_; + char folder_delimiter_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Global Helpers (deprecated) +/////////////////////////////////////////////////////////////////////////////// + +inline void SetOrganizationName(const std::string& organization) { + Filesystem::SetOrganizationName(organization); +} +inline void SetApplicationName(const std::string& application) { + Filesystem::SetApplicationName(application); +} +inline void GetOrganizationName(std::string* organization) { + Filesystem::GetOrganizationName(organization); +} +inline void GetApplicationName(std::string* application) { + Filesystem::GetApplicationName(application); +} +inline bool CreateFolder(const Pathname& path) { + return Filesystem::CreateFolder(path); +} +inline bool FinishPath(Pathname& path, bool create, const std::string& append) { + if (!append.empty()) + path.AppendFolder(append); + return !create || CreateFolder(path); +} +// Note: this method uses the convention of / for the temporary +// folder. Filesystem uses /. We will be migrating exclusively +// to // eventually. Since these are temp folders, +// it's probably ok to orphan them during the transition. +inline bool GetTemporaryFolder(Pathname& path, bool create, + const std::string& append) { + std::string application_name; + Filesystem::GetApplicationName(&application_name); + ASSERT(!application_name.empty()); + return Filesystem::GetTemporaryFolder(path, create, &application_name) + && FinishPath(path, create, append); +} +inline bool GetAppDataFolder(Pathname& path, bool create, + const std::string& append) { + ASSERT(!create); // TODO: Support create flag on Filesystem::GetAppDataFolder. + return Filesystem::GetAppDataFolder(&path, true) + && FinishPath(path, create, append); +} +inline bool CleanupTemporaryFolder() { + Pathname path; + if (!GetTemporaryFolder(path, false, "")) + return false; + if (Filesystem::IsAbsent(path)) + return true; + if (!Filesystem::IsTemporaryPath(path)) { + ASSERT(false); + return false; + } + return Filesystem::DeleteFolderContents(path); +} + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_PATHUTILS_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/physicalsocketserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/physicalsocketserver.h new file mode 100644 index 0000000..715b24e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/physicalsocketserver.h @@ -0,0 +1,137 @@ +/* + * 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 TALK_BASE_PHYSICALSOCKETSERVER_H__ +#define TALK_BASE_PHYSICALSOCKETSERVER_H__ + +#include + +#include "talk/base/asyncfile.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/socketserver.h" +#include "talk/base/criticalsection.h" + +#ifdef POSIX +typedef int SOCKET; +#endif // POSIX + +namespace talk_base { + +// Event constants for the Dispatcher class. +enum DispatcherEvent { + DE_READ = 0x0001, + DE_WRITE = 0x0002, + DE_CONNECT = 0x0004, + DE_CLOSE = 0x0008, + DE_ACCEPT = 0x0010, +}; + +class Signaler; +#ifdef POSIX +class PosixSignalDispatcher; +#endif + +class Dispatcher { + public: + virtual ~Dispatcher() {} + virtual uint32 GetRequestedEvents() = 0; + virtual void OnPreEvent(uint32 ff) = 0; + virtual void OnEvent(uint32 ff, int err) = 0; +#ifdef WIN32 + virtual WSAEVENT GetWSAEvent() = 0; + virtual SOCKET GetSocket() = 0; + virtual bool CheckSignalClose() = 0; +#elif POSIX + virtual int GetDescriptor() = 0; + virtual bool IsDescriptorClosed() = 0; +#endif +}; + +// A socket server that provides the real sockets of the underlying OS. +class PhysicalSocketServer : public SocketServer { + public: + PhysicalSocketServer(); + virtual ~PhysicalSocketServer(); + + // SocketFactory: + virtual Socket* CreateSocket(int type); + virtual Socket* CreateSocket(int family, int type); + + virtual AsyncSocket* CreateAsyncSocket(int type); + virtual AsyncSocket* CreateAsyncSocket(int family, int type); + + // Internal Factory for Accept + AsyncSocket* WrapSocket(SOCKET s); + + // SocketServer: + virtual bool Wait(int cms, bool process_io); + virtual void WakeUp(); + + void Add(Dispatcher* dispatcher); + void Remove(Dispatcher* dispatcher); + +#ifdef POSIX + AsyncFile* CreateFile(int fd); + + // Sets the function to be executed in response to the specified POSIX signal. + // The function is executed from inside Wait() using the "self-pipe trick"-- + // regardless of which thread receives the signal--and hence can safely + // manipulate user-level data structures. + // "handler" may be SIG_IGN, SIG_DFL, or a user-specified function, just like + // with signal(2). + // Only one PhysicalSocketServer should have user-level signal handlers. + // Dispatching signals on multiple PhysicalSocketServers is not reliable. + // The signal mask is not modified. It is the caller's responsibily to + // maintain it as desired. + virtual bool SetPosixSignalHandler(int signum, void (*handler)(int)); + + protected: + Dispatcher* signal_dispatcher(); +#endif + + private: + typedef std::vector DispatcherList; + typedef std::vector IteratorList; + +#ifdef POSIX + static bool InstallSignal(int signum, void (*handler)(int)); + + scoped_ptr signal_dispatcher_; +#endif + DispatcherList dispatchers_; + IteratorList iterators_; + Signaler* signal_wakeup_; + CriticalSection crit_; + bool fWait_; +#ifdef WIN32 + WSAEVENT socket_ev_; +#endif +}; + +} // namespace talk_base + +#endif // TALK_BASE_PHYSICALSOCKETSERVER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/posix.h b/thirdparties/common/include/webrtc-sdk/talk/base/posix.h new file mode 100644 index 0000000..1e650a0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/posix.h @@ -0,0 +1,42 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_POSIX_H_ +#define TALK_BASE_POSIX_H_ + +namespace talk_base { + +// Runs the given executable name as a daemon, so that it executes concurrently +// with this process. Upon completion, the daemon process will automatically be +// reaped by init(8), so an error exit status or a failure to start the +// executable are not reported. Returns true if the daemon process was forked +// successfully, else false. +bool RunAsDaemon(const char *file, const char *const argv[]); + +} // namespace talk_base + +#endif // TALK_BASE_POSIX_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/profiler.h b/thirdparties/common/include/webrtc-sdk/talk/base/profiler.h new file mode 100644 index 0000000..ca13e17 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/profiler.h @@ -0,0 +1,178 @@ +/* + * 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. + */ + +// A simple wall-clock profiler for instrumented code. +// Example: +// void MyLongFunction() { +// PROFILE_F(); // Time the execution of this function. +// // Do something +// { // Time just what is in this scope. +// PROFILE("My event"); +// // Do something else +// } +// } +// Another example: +// void StartAsyncProcess() { +// PROFILE_START("My async event"); +// DoSomethingAsyncAndThenCall(&Callback); +// } +// void Callback() { +// PROFILE_STOP("My async event"); +// // Handle callback. +// } + +#ifndef TALK_BASE_PROFILER_H_ +#define TALK_BASE_PROFILER_H_ + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/common.h" +#include "talk/base/logging.h" +#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 + +#define UV_HELPER2(x) _uv_ ## x +#define UV_HELPER(x) UV_HELPER2(x) +#define UNIQUE_VAR UV_HELPER(__LINE__) + +// Profiles the current scope. +#define PROFILE(msg) talk_base::ProfilerScope UNIQUE_VAR(msg) +// When placed at the start of a function, profiles the current function. +#define PROFILE_F() PROFILE(__FUNCTION__) +// Reports current timings to the log at severity |sev|. +#define PROFILE_DUMP_ALL(sev) \ + talk_base::Profiler::Instance()->ReportAllToLog(__FILE__, __LINE__, sev) +// Reports current timings for all events whose names are prefixed by |prefix| +// to the log at severity |sev|. Using a unique event name as |prefix| will +// report only that event. +#define PROFILE_DUMP(sev, prefix) \ + talk_base::Profiler::Instance()->ReportToLog(__FILE__, __LINE__, sev, prefix) +// Starts and stops a profile event. Useful when an event is not easily +// captured within a scope (eg, an async call with a callback when done). +#define PROFILE_START(msg) talk_base::Profiler::Instance()->StartEvent(msg) +#define PROFILE_STOP(msg) talk_base::Profiler::Instance()->StopEvent(msg) +// TODO(ryanpetrie): Consider adding PROFILE_DUMP_EVERY(sev, iterations) + +#undef UV_HELPER2 +#undef UV_HELPER +#undef UNIQUE_VAR + +#else // ENABLE_PROFILING + +#define PROFILE(msg) (void)0 +#define PROFILE_F() (void)0 +#define PROFILE_DUMP_ALL(sev) (void)0 +#define PROFILE_DUMP(sev, prefix) (void)0 +#define PROFILE_START(msg) (void)0 +#define PROFILE_STOP(msg) (void)0 + +#endif // ENABLE_PROFILING + +namespace talk_base { + +// Tracks information for one profiler event. +class ProfilerEvent { + public: + ProfilerEvent(); + void Start(); + void Stop(); + void Stop(uint64 stop_time); + double standard_deviation() const; + double total_time() const { return total_time_; } + double mean() const { return mean_; } + double minimum() const { return minimum_; } + double maximum() const { return maximum_; } + int event_count() const { return event_count_; } + bool is_started() const { return start_count_ > 0; } + + private: + uint64 current_start_time_; + double total_time_; + double mean_; + double sum_of_squared_differences_; + double minimum_; + double maximum_; + int start_count_; + int event_count_; +}; + +// Singleton that owns ProfilerEvents and reports results. Prefer to use +// macros, defined above, rather than directly calling Profiler methods. +class Profiler { + public: + void StartEvent(const std::string& event_name); + void StopEvent(const std::string& event_name); + void ReportToLog(const char* file, int line, LoggingSeverity severity_to_use, + const std::string& event_prefix); + void ReportAllToLog(const char* file, int line, + LoggingSeverity severity_to_use); + const ProfilerEvent* GetEvent(const std::string& event_name) const; + // Clears all _stopped_ events. Returns true if _all_ events were cleared. + bool Clear(); + + static Profiler* Instance(); + private: + Profiler() {} + + typedef std::map EventMap; + EventMap events_; + mutable SharedExclusiveLock lock_; + + DISALLOW_COPY_AND_ASSIGN(Profiler); +}; + +// Starts an event on construction and stops it on destruction. +// Used by PROFILE macro. +class ProfilerScope { + public: + explicit ProfilerScope(const std::string& event_name) + : event_name_(event_name) { + Profiler::Instance()->StartEvent(event_name_); + } + ~ProfilerScope() { + Profiler::Instance()->StopEvent(event_name_); + } + private: + std::string event_name_; + + DISALLOW_COPY_AND_ASSIGN(ProfilerScope); +}; + +std::ostream& operator<<(std::ostream& stream, + const ProfilerEvent& profiler_event); + +} // namespace talk_base + +#endif // TALK_BASE_PROFILER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/proxydetect.h b/thirdparties/common/include/webrtc-sdk/talk/base/proxydetect.h new file mode 100644 index 0000000..f2a1450 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/proxydetect.h @@ -0,0 +1,48 @@ +/* + * libjingle + * Copyright 2007, 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 _PROXYDETECT_H_ +#define _PROXYDETECT_H_ + +#include "talk/base/proxyinfo.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +namespace talk_base { +// Auto-detect the proxy server. Returns true if a proxy is configured, +// although hostname may be empty if the proxy is not required for +// the given URL. + +bool GetProxySettingsForUrl(const char* agent, const char* url, + talk_base::ProxyInfo* proxy, + bool long_operation = false); + +} // namespace talk_base + +#endif // _PROXYDETECT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/proxyinfo.h b/thirdparties/common/include/webrtc-sdk/talk/base/proxyinfo.h new file mode 100644 index 0000000..e182cd5 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/proxyinfo.h @@ -0,0 +1,59 @@ +/* + * 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 TALK_BASE_PROXYINFO_H__ +#define TALK_BASE_PROXYINFO_H__ + +#include +#include "talk/base/socketaddress.h" +#include "talk/base/cryptstring.h" + +namespace talk_base { + +enum ProxyType { + PROXY_NONE, + PROXY_HTTPS, + PROXY_SOCKS5, + PROXY_UNKNOWN +}; +const char * ProxyToString(ProxyType proxy); + +struct ProxyInfo { + ProxyType type; + SocketAddress address; + std::string autoconfig_url; + bool autodetect; + std::string bypass_list; + std::string username; + CryptString password; + + ProxyInfo() : type(PROXY_NONE), autodetect(false) { } +}; + +} // namespace talk_base + +#endif // TALK_BASE_PROXYINFO_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/proxyserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/proxyserver.h new file mode 100644 index 0000000..1858ee1 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/proxyserver.h @@ -0,0 +1,113 @@ +/* + * 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 TALK_BASE_PROXYSERVER_H_ +#define TALK_BASE_PROXYSERVER_H_ + +#include +#include "talk/base/asyncsocket.h" +#include "talk/base/socketadapters.h" +#include "talk/base/socketaddress.h" +#include "talk/base/stream.h" + +namespace talk_base { + +class SocketFactory; + +// ProxyServer is a base class that allows for easy construction of proxy +// servers. With its helper class ProxyBinding, it contains all the necessary +// logic for receiving and bridging connections. The specific client-server +// proxy protocol is implemented by an instance of the AsyncProxyServerSocket +// class; children of ProxyServer implement WrapSocket appropriately to return +// the correct protocol handler. + +class ProxyBinding : public sigslot::has_slots<> { + public: + ProxyBinding(AsyncProxyServerSocket* in_socket, AsyncSocket* out_socket); + sigslot::signal1 SignalDestroyed; + + private: + void OnConnectRequest(AsyncProxyServerSocket* socket, + const SocketAddress& addr); + void OnInternalRead(AsyncSocket* socket); + void OnInternalWrite(AsyncSocket* socket); + void OnInternalClose(AsyncSocket* socket, int err); + void OnExternalConnect(AsyncSocket* socket); + void OnExternalRead(AsyncSocket* socket); + void OnExternalWrite(AsyncSocket* socket); + void OnExternalClose(AsyncSocket* socket, int err); + + static void Read(AsyncSocket* socket, FifoBuffer* buffer); + static void Write(AsyncSocket* socket, FifoBuffer* buffer); + void Destroy(); + + static const int kBufferSize = 4096; + scoped_ptr int_socket_; + scoped_ptr ext_socket_; + bool connected_; + FifoBuffer out_buffer_; + FifoBuffer in_buffer_; + DISALLOW_EVIL_CONSTRUCTORS(ProxyBinding); +}; + +class ProxyServer : public sigslot::has_slots<> { + public: + ProxyServer(SocketFactory* int_factory, const SocketAddress& int_addr, + SocketFactory* ext_factory, const SocketAddress& ext_ip); + virtual ~ProxyServer(); + + protected: + void OnAcceptEvent(AsyncSocket* socket); + virtual AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) = 0; + void OnBindingDestroyed(ProxyBinding* binding); + + private: + typedef std::list BindingList; + SocketFactory* ext_factory_; + SocketAddress ext_ip_; + scoped_ptr server_socket_; + BindingList bindings_; + DISALLOW_EVIL_CONSTRUCTORS(ProxyServer); +}; + +// SocksProxyServer is a simple extension of ProxyServer to implement SOCKS. +class SocksProxyServer : public ProxyServer { + public: + SocksProxyServer(SocketFactory* int_factory, const SocketAddress& int_addr, + SocketFactory* ext_factory, const SocketAddress& ext_ip) + : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) { + } + protected: + AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) { + return new AsyncSocksProxyServerSocket(socket); + } + DISALLOW_EVIL_CONSTRUCTORS(SocksProxyServer); +}; + +} // namespace talk_base + +#endif // TALK_BASE_PROXYSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/ratelimiter.h b/thirdparties/common/include/webrtc-sdk/talk/base/ratelimiter.h new file mode 100644 index 0000000..6a7ee40 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/ratelimiter.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_RATELIMITER_H_ +#define TALK_BASE_RATELIMITER_H_ + +#include +#include "talk/base/basictypes.h" + +namespace talk_base { + +// Limits the rate of use to a certain maximum quantity per period of +// time. Use, for example, for simple bandwidth throttling. +// +// It's implemented like a diet plan: You have so many calories per +// day. If you hit the limit, you can't eat any more until the next +// day. +class RateLimiter { + public: + // For example, 100kb per second. + RateLimiter(size_t max, double period) + : max_per_period_(max), + period_length_(period), + used_in_period_(0), + period_start_(0.0), + period_end_(period) { + } + virtual ~RateLimiter() {} + + // Returns true if if the desired quantity is available in the + // current period (< (max - used)). Once the given time passes the + // end of the period, used is set to zero and more use is available. + bool CanUse(size_t desired, double time); + // Increment the quantity used this period. If past the end of a + // period, a new period is started. + void Use(size_t used, double time); + + size_t used_in_period() const { + return used_in_period_; + } + + size_t max_per_period() const { + return max_per_period_; + } + + private: + size_t max_per_period_; + double period_length_; + size_t used_in_period_; + double period_start_; + double period_end_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_RATELIMITER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/ratetracker.h b/thirdparties/common/include/webrtc-sdk/talk/base/ratetracker.h new file mode 100644 index 0000000..61fd41a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/ratetracker.h @@ -0,0 +1,59 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_RATETRACKER_H_ +#define TALK_BASE_RATETRACKER_H_ + +#include +#include "talk/base/basictypes.h" + +namespace talk_base { + +// Computes instantaneous units per second. +class RateTracker { + public: + RateTracker(); + virtual ~RateTracker() {} + + size_t total_units() const; + size_t units_second(); + void Update(size_t units); + + protected: + // overrideable for tests + virtual uint32 Time() const; + + private: + size_t total_units_; + size_t units_second_; + uint32 last_units_second_time_; + size_t last_units_second_calc_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_RATETRACKER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/refcount.h b/thirdparties/common/include/webrtc-sdk/talk/base/refcount.h new file mode 100644 index 0000000..7025f6c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/refcount.h @@ -0,0 +1,95 @@ +/* + * 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_APP_BASE_REFCOUNT_H_ +#define TALK_APP_BASE_REFCOUNT_H_ + +#include + +#include "talk/base/criticalsection.h" + +namespace talk_base { + +// Reference count interface. +class RefCountInterface { + public: + virtual int AddRef() = 0; + virtual int Release() = 0; + protected: + virtual ~RefCountInterface() {} +}; + +template +class RefCountedObject : public T { + public: + RefCountedObject() : ref_count_(0) { + } + + template + explicit RefCountedObject(P p) : T(p), ref_count_(0) { + } + + template + RefCountedObject(P1 p1, P2 p2) : T(p1, p2), ref_count_(0) { + } + + template + RefCountedObject(P1 p1, P2 p2, P3 p3) : T(p1, p2, p3), ref_count_(0) { + } + + template + RefCountedObject(P1 p1, P2 p2, P3 p3, P4 p4) + : T(p1, p2, p3, p4), ref_count_(0) { + } + + template + RefCountedObject(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) + : T(p1, p2, p3, p4, p5), ref_count_(0) { + } + + virtual int AddRef() { + return talk_base::AtomicOps::Increment(&ref_count_); + } + + virtual int Release() { + int count = talk_base::AtomicOps::Decrement(&ref_count_); + if (!count) { + delete this; + } + return count; + } + + protected: + virtual ~RefCountedObject() { + } + + int ref_count_; +}; + +} // namespace talk_base + +#endif // TALK_APP_BASE_REFCOUNT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/referencecountedsingletonfactory.h b/thirdparties/common/include/webrtc-sdk/talk/base/referencecountedsingletonfactory.h new file mode 100644 index 0000000..b9eebbd --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/referencecountedsingletonfactory.h @@ -0,0 +1,174 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_ +#define TALK_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_ + +#include "talk/base/common.h" +#include "talk/base/criticalsection.h" +#include "talk/base/logging.h" +#include "talk/base/scoped_ptr.h" + +namespace talk_base { + +template class rcsf_ptr; + +// A ReferenceCountedSingletonFactory is an object which owns another object, +// and doles out the owned object to consumers in a reference-counted manner. +// Thus, the factory owns at most one object of the desired kind, and +// hands consumers a special pointer to it, through which they can access it. +// When the consumers delete the pointer, the reference count goes down, +// and if the reference count hits zero, the factory can throw the object +// away. If a consumer requests the pointer and the factory has none, +// it can create one on the fly and pass it back. +template +class ReferenceCountedSingletonFactory { + friend class rcsf_ptr; + public: + ReferenceCountedSingletonFactory() : ref_count_(0) {} + + virtual ~ReferenceCountedSingletonFactory() { + ASSERT(ref_count_ == 0); + } + + protected: + // Must be implemented in a sub-class. The sub-class may choose whether or not + // to cache the instance across lifetimes by either reset()'ing or not + // reset()'ing the scoped_ptr in CleanupInstance(). + virtual bool SetupInstance() = 0; + virtual void CleanupInstance() = 0; + + scoped_ptr instance_; + + private: + Interface* GetInstance() { + talk_base::CritScope cs(&crit_); + if (ref_count_ == 0) { + if (!SetupInstance()) { + LOG(LS_VERBOSE) << "Failed to setup instance"; + return NULL; + } + ASSERT(instance_.get() != NULL); + } + ++ref_count_; + + LOG(LS_VERBOSE) << "Number of references: " << ref_count_; + return instance_.get(); + } + + void ReleaseInstance() { + talk_base::CritScope cs(&crit_); + ASSERT(ref_count_ > 0); + ASSERT(instance_.get() != NULL); + --ref_count_; + LOG(LS_VERBOSE) << "Number of references: " << ref_count_; + if (ref_count_ == 0) { + CleanupInstance(); + } + } + + CriticalSection crit_; + int ref_count_; + + DISALLOW_COPY_AND_ASSIGN(ReferenceCountedSingletonFactory); +}; + +template +class rcsf_ptr { + public: + // Create a pointer that uses the factory to get the instance. + // This is lazy - it won't generate the instance until it is requested. + explicit rcsf_ptr(ReferenceCountedSingletonFactory* factory) + : instance_(NULL), + factory_(factory) { + } + + ~rcsf_ptr() { + release(); + } + + Interface& operator*() { + EnsureAcquired(); + return *instance_; + } + + Interface* operator->() { + EnsureAcquired(); + return instance_; + } + + // Gets the pointer, creating the singleton if necessary. May return NULL if + // creation failed. + Interface* get() { + Acquire(); + return instance_; + } + + // Set instance to NULL and tell the factory we aren't using the instance + // anymore. + void release() { + if (instance_) { + instance_ = NULL; + factory_->ReleaseInstance(); + } + } + + // Lets us know whether instance is valid or not right now. + // Even though attempts to use the instance will automatically create it, it + // is advisable to check this because creation can fail. + bool valid() const { + return instance_ != NULL; + } + + // Returns the factory that this pointer is using. + ReferenceCountedSingletonFactory* factory() const { + return factory_; + } + + private: + void EnsureAcquired() { + Acquire(); + ASSERT(instance_ != NULL); + } + + void Acquire() { + // Since we're getting a singleton back, acquire is a noop if instance is + // already populated. + if (!instance_) { + instance_ = factory_->GetInstance(); + } + } + + Interface* instance_; + ReferenceCountedSingletonFactory* factory_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(rcsf_ptr); +}; + +}; // namespace talk_base + +#endif // TALK_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/rollingaccumulator.h b/thirdparties/common/include/webrtc-sdk/talk/base/rollingaccumulator.h new file mode 100644 index 0000000..3e45d4b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/rollingaccumulator.h @@ -0,0 +1,189 @@ +/* + * 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_BASE_ROLLINGACCUMULATOR_H_ +#define TALK_BASE_ROLLINGACCUMULATOR_H_ + +#include + +#include "talk/base/common.h" + +namespace talk_base { + +// RollingAccumulator stores and reports statistics +// over N most recent samples. +// +// T is assumed to be an int, long, double or float. +template +class RollingAccumulator { + public: + explicit RollingAccumulator(size_t max_count) + : samples_(max_count) { + Reset(); + } + ~RollingAccumulator() { + } + + size_t max_count() const { + return samples_.size(); + } + + size_t count() const { + 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_; + } + // Add new sample. + 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(); + } + + T ComputeSum() const { + return static_cast(sum_); + } + + double ComputeMean() const { + if (count_ == 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 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. + double ComputeWeightedMean(double learning_rate) const { + if (count_ < 1 || learning_rate <= 0.0 || learning_rate >= 1.0) { + return ComputeMean(); + } + double weighted_mean = 0.0; + double current_weight = 1.0; + double weight_sum = 0.0; + const size_t max_size = max_count(); + for (size_t i = 0; i < count_; ++i) { + current_weight *= learning_rate; + weight_sum += current_weight; + // Add max_size to prevent underflow. + size_t index = (next_index_ + max_size - i - 1) % max_size; + weighted_mean += current_weight * samples_[index]; + } + return weighted_mean / weight_sum; + } + + // Compute estimated variance. Estimation is more accurate + // as the number of samples grows. + double ComputeVariance() const { + if (count_ == 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 mean_2 - (mean * mean); + } + + private: + size_t count_; + size_t next_index_; + 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 samples_; + + DISALLOW_COPY_AND_ASSIGN(RollingAccumulator); +}; + +} // namespace talk_base + +#endif // TALK_BASE_ROLLINGACCUMULATOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/safe_conversions.h b/thirdparties/common/include/webrtc-sdk/talk/base/safe_conversions.h new file mode 100644 index 0000000..d258dfb --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/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 + +#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 +inline bool IsValueInRangeForNumericType(Src value) { + return internal::RangeCheck(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 +inline Dst checked_cast(Src value) { + Check(IsValueInRangeForNumericType(value)); + return static_cast(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 +inline Dst saturated_cast(Src value) { + // Optimization for floating point values, which already saturate. + if (std::numeric_limits::is_iec559) + return static_cast(value); + + switch (internal::RangeCheck(value)) { + case internal::TYPE_VALID: + return static_cast(value); + + case internal::TYPE_UNDERFLOW: + return std::numeric_limits::min(); + + case internal::TYPE_OVERFLOW: + return std::numeric_limits::max(); + + // Should fail only on attempting to assign NaN to a saturated integer. + case internal::TYPE_INVALID: + Check(false); + return std::numeric_limits::max(); + } + + Check(false); // NOTREACHED(); + return static_cast(value); +} + +} // namespace talk_base + +#endif // TALK_BASE_SAFE_CONVERSIONS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/safe_conversions_impl.h b/thirdparties/common/include/webrtc-sdk/talk/base/safe_conversions_impl.h new file mode 100644 index 0000000..82c942a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/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 + +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 ::is_signed ? + DST_SIGNED : DST_UNSIGNED, + SrcSign IsSrcSigned = std::numeric_limits::is_signed ? + SRC_SIGNED : SRC_UNSIGNED> +struct StaticRangeCheck {}; + +template +struct StaticRangeCheck { + typedef std::numeric_limits DstLimits; + typedef std::numeric_limits 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 +struct StaticRangeCheck { + static const DstRange value = sizeof(Dst) >= sizeof(Src) ? + CONTAINS_RANGE : OVERLAPS_RANGE; +}; + +template +struct StaticRangeCheck { + typedef std::numeric_limits DstLimits; + typedef std::numeric_limits 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 +struct StaticRangeCheck { + 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 ::is_signed ? + DST_SIGNED : DST_UNSIGNED, + SrcSign IsSrcSigned = std::numeric_limits::is_signed ? + SRC_SIGNED : SRC_UNSIGNED, + DstRange IsSrcRangeContained = StaticRangeCheck::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 +struct RangeCheckImpl { + static RangeCheckResult Check(Src value) { + return TYPE_VALID; + } +}; + +// Signed to signed narrowing. +template +struct RangeCheckImpl { + static RangeCheckResult Check(Src value) { + typedef std::numeric_limits DstLimits; + return DstLimits::is_iec559 ? + BASE_NUMERIC_RANGE_CHECK_RESULT( + value <= static_cast(DstLimits::max()), + value >= static_cast(DstLimits::max() * -1)) : + BASE_NUMERIC_RANGE_CHECK_RESULT( + value <= static_cast(DstLimits::max()), + value >= static_cast(DstLimits::min())); + } +}; + +// Unsigned to unsigned narrowing. +template +struct RangeCheckImpl { + static RangeCheckResult Check(Src value) { + typedef std::numeric_limits DstLimits; + return BASE_NUMERIC_RANGE_CHECK_RESULT( + value <= static_cast(DstLimits::max()), true); + } +}; + +// Unsigned to signed. +template +struct RangeCheckImpl { + static RangeCheckResult Check(Src value) { + typedef std::numeric_limits DstLimits; + return sizeof(Dst) > sizeof(Src) ? TYPE_VALID : + BASE_NUMERIC_RANGE_CHECK_RESULT( + value <= static_cast(DstLimits::max()), true); + } +}; + +// Signed to unsigned. +template +struct RangeCheckImpl { + static RangeCheckResult Check(Src value) { + typedef std::numeric_limits DstLimits; + typedef std::numeric_limits 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(0)) : + BASE_NUMERIC_RANGE_CHECK_RESULT( + value <= static_cast(DstLimits::max()), + value >= static_cast(0)); + } +}; + +template +inline RangeCheckResult RangeCheck(Src value) { + COMPILE_ASSERT(std::numeric_limits::is_specialized, + argument_must_be_numeric); + COMPILE_ASSERT(std::numeric_limits::is_specialized, + result_must_be_numeric); + return RangeCheckImpl::Check(value); +} + +} // namespace internal +} // namespace talk_base + +#endif // TALK_BASE_SAFE_CONVERSIONS_IMPL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/schanneladapter.h b/thirdparties/common/include/webrtc-sdk/talk/base/schanneladapter.h new file mode 100644 index 0000000..7373bc8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/schanneladapter.h @@ -0,0 +1,94 @@ +/* + * 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 TALK_BASE_SCHANNELADAPTER_H__ +#define TALK_BASE_SCHANNELADAPTER_H__ + +#include +#include "talk/base/ssladapter.h" +#include "talk/base/messagequeue.h" +struct _SecBufferDesc; + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// + +class SChannelAdapter : public SSLAdapter, public MessageHandler { +public: + SChannelAdapter(AsyncSocket* socket); + virtual ~SChannelAdapter(); + + virtual int StartSSL(const char* hostname, bool restartable); + virtual int Send(const void* pv, size_t cb); + virtual int Recv(void* pv, size_t cb); + virtual int Close(); + + // Note that the socket returns ST_CONNECTING while SSL is being negotiated. + virtual ConnState GetState() const; + +protected: + enum SSLState { + SSL_NONE, SSL_WAIT, SSL_CONNECTING, SSL_CONNECTED, SSL_ERROR + }; + struct SSLImpl; + + virtual void OnConnectEvent(AsyncSocket* socket); + virtual void OnReadEvent(AsyncSocket* socket); + virtual void OnWriteEvent(AsyncSocket* socket); + virtual void OnCloseEvent(AsyncSocket* socket, int err); + virtual void OnMessage(Message* pmsg); + + int BeginSSL(); + int ContinueSSL(); + int ProcessContext(long int status, _SecBufferDesc* sbd_in, + _SecBufferDesc* sbd_out); + int DecryptData(); + + int Read(); + int Flush(); + void Error(const char* context, int err, bool signal = true); + void Cleanup(); + + void PostEvent(); + +private: + SSLState state_; + std::string ssl_host_name_; + // If true, socket will retain SSL configuration after Close. + bool restartable_; + // If true, we are delaying signalling close until all data is read. + bool signal_close_; + // If true, we are waiting to be woken up to signal readability or closure. + bool message_pending_; + SSLImpl* impl_; +}; + +///////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_SCHANNELADAPTER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/scoped_autorelease_pool.h b/thirdparties/common/include/webrtc-sdk/talk/base/scoped_autorelease_pool.h new file mode 100644 index 0000000..e128ca4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/scoped_autorelease_pool.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +// Automatically initialize and and free an autoreleasepool. Never allocate +// an instance of this class using "new" - that will result in a compile-time +// error. Only use it as a stack object. +// +// Note: NSAutoreleasePool docs say that you should not normally need to +// declare an NSAutoreleasePool as a member of an object - but there's nothing +// that indicates it will be a problem, as long as the stack lifetime of the +// pool exactly matches the stack lifetime of the object. + +#ifndef TALK_BASE_SCOPED_AUTORELEASE_POOL_H__ +#define TALK_BASE_SCOPED_AUTORELEASE_POOL_H__ + +#if defined(IOS) || defined(OSX) + +#include "talk/base/common.h" + +// This header may be included from Obj-C files or C++ files. +#ifdef __OBJC__ +@class NSAutoreleasePool; +#else +class NSAutoreleasePool; +#endif + +namespace talk_base { + +class ScopedAutoreleasePool { + public: + ScopedAutoreleasePool(); + ~ScopedAutoreleasePool(); + + private: + // Declaring private overrides of new and delete here enforces the "only use + // as a stack object" discipline. + // + // Note: new is declared as "throw()" to get around a gcc warning about new + // returning NULL, but this method will never get called and therefore will + // never actually throw any exception. + void* operator new(size_t size) throw() { return NULL; } + void operator delete (void* ptr) {} + + NSAutoreleasePool* pool_; + + DISALLOW_EVIL_CONSTRUCTORS(ScopedAutoreleasePool); +}; + +} // namespace talk_base + +#endif // IOS || OSX +#endif // TALK_BASE_SCOPED_AUTORELEASE_POOL_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/scoped_ptr.h b/thirdparties/common/include/webrtc-sdk/talk/base/scoped_ptr.h new file mode 100644 index 0000000..964ae6e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/scoped_ptr.h @@ -0,0 +1,590 @@ +// Borrowed from chromium. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Scopers help you manage ownership of a pointer, helping you easily manage the +// a pointer within a scope, and automatically destroying the pointer at the +// end of a scope. There are two main classes you will use, which correspond +// to the operators new/delete and new[]/delete[]. +// +// Example usage (scoped_ptr): +// { +// scoped_ptr foo(new Foo("wee")); +// } // foo goes out of scope, releasing the pointer with it. +// +// { +// scoped_ptr foo; // No pointer managed. +// foo.reset(new Foo("wee")); // Now a pointer is managed. +// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed. +// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed. +// foo->Method(); // Foo::Method() called. +// foo.get()->Method(); // Foo::Method() called. +// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer +// // manages a pointer. +// foo.reset(new Foo("wee4")); // foo manages a pointer again. +// foo.reset(); // Foo("wee4") destroyed, foo no longer +// // manages a pointer. +// } // foo wasn't managing a pointer, so nothing was destroyed. +// +// Example usage (scoped_ptr): +// { +// scoped_ptr foo(new Foo[100]); +// foo.get()->Method(); // Foo::Method on the 0th element. +// foo[10].Method(); // Foo::Method on the 10th element. +// } +// +// These scopers also implement part of the functionality of C++11 unique_ptr +// in that they are "movable but not copyable." You can use the scopers in +// the parameter and return types of functions to signify ownership transfer +// in to and out of a function. When calling a function that has a scoper +// as the argument type, it must be called with the result of an analogous +// scoper's Pass() function or another function that generates a temporary; +// passing by copy will NOT work. Here is an example using scoped_ptr: +// +// void TakesOwnership(scoped_ptr arg) { +// // Do something with arg +// } +// scoped_ptr CreateFoo() { +// // No need for calling Pass() because we are constructing a temporary +// // for the return value. +// return scoped_ptr(new Foo("new")); +// } +// scoped_ptr PassThru(scoped_ptr arg) { +// return arg.Pass(); +// } +// +// { +// scoped_ptr ptr(new Foo("yay")); // ptr manages Foo("yay"). +// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay"). +// scoped_ptr ptr2 = CreateFoo(); // ptr2 owns the return Foo. +// scoped_ptr ptr3 = // ptr3 now owns what was in ptr2. +// PassThru(ptr2.Pass()); // ptr2 is correspondingly NULL. +// } +// +// Notice that if you do not call Pass() when returning from PassThru(), or +// when invoking TakesOwnership(), the code will not compile because scopers +// are not copyable; they only implement move semantics which require calling +// the Pass() function to signify a destructive transfer of state. CreateFoo() +// is different though because we are constructing a temporary on the return +// line and thus can avoid needing to call Pass(). +// +// Pass() properly handles upcast in initialization, i.e. you can use a +// scoped_ptr to initialize a scoped_ptr: +// +// scoped_ptr foo(new Foo()); +// scoped_ptr parent(foo.Pass()); +// +// PassAs<>() should be used to upcast return value in return statement: +// +// scoped_ptr CreateFoo() { +// scoped_ptr result(new FooChild()); +// return result.PassAs(); +// } +// +// Note that PassAs<>() is implemented only for scoped_ptr, but not for +// scoped_ptr. This is because casting array pointers may not be safe. + +#ifndef TALK_BASE_SCOPED_PTR_H__ +#define TALK_BASE_SCOPED_PTR_H__ + +#include // for ptrdiff_t +#include // for free() decl + +#include // For std::swap(). + +#include "talk/base/common.h" // for ASSERT +#include "talk/base/compile_assert.h" // for COMPILE_ASSERT +#include "talk/base/move.h" // for TALK_MOVE_ONLY_TYPE_FOR_CPP_03 +#include "talk/base/template_util.h" // for is_convertible, is_array + +#ifdef _WIN32 +namespace std { using ::ptrdiff_t; }; +#endif // _WIN32 + +namespace talk_base { + +// Function object which deletes its parameter, which must be a pointer. +// If C is an array type, invokes 'delete[]' on the parameter; otherwise, +// invokes 'delete'. The default deleter for scoped_ptr. +template +struct DefaultDeleter { + DefaultDeleter() {} + template DefaultDeleter(const DefaultDeleter& other) { + // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor + // if U* is implicitly convertible to T* and U is not an array type. + // + // Correct implementation should use SFINAE to disable this + // constructor. However, since there are no other 1-argument constructors, + // using a COMPILE_ASSERT() based on is_convertible<> and requiring + // complete types is simpler and will cause compile failures for equivalent + // misuses. + // + // Note, the is_convertible check also ensures that U is not an + // array. T is guaranteed to be a non-array, so any U* where U is an array + // cannot convert to T*. + enum { T_must_be_complete = sizeof(T) }; + enum { U_must_be_complete = sizeof(U) }; + COMPILE_ASSERT((talk_base::is_convertible::value), + U_ptr_must_implicitly_convert_to_T_ptr); + } + inline void operator()(T* ptr) const { + enum { type_must_be_complete = sizeof(T) }; + delete ptr; + } +}; + +// Specialization of DefaultDeleter for array types. +template +struct DefaultDeleter { + inline void operator()(T* ptr) const { + enum { type_must_be_complete = sizeof(T) }; + delete[] ptr; + } + + private: + // Disable this operator for any U != T because it is undefined to execute + // an array delete when the static type of the array mismatches the dynamic + // type. + // + // References: + // C++98 [expr.delete]p3 + // http://cplusplus.github.com/LWG/lwg-defects.html#938 + template void operator()(U* array) const; +}; + +template +struct DefaultDeleter { + // Never allow someone to declare something like scoped_ptr. + COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type); +}; + +// Function object which invokes 'free' on its parameter, which must be +// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr: +// +// scoped_ptr foo_ptr( +// static_cast(malloc(sizeof(int)))); +struct FreeDeleter { + inline void operator()(void* ptr) const { + free(ptr); + } +}; + +namespace internal { + +// Minimal implementation of the core logic of scoped_ptr, suitable for +// reuse in both scoped_ptr and its specializations. +template +class scoped_ptr_impl { + public: + explicit scoped_ptr_impl(T* p) : data_(p) { } + + // Initializer for deleters that have data parameters. + scoped_ptr_impl(T* p, const D& d) : data_(p, d) {} + + // Templated constructor that destructively takes the value from another + // scoped_ptr_impl. + template + scoped_ptr_impl(scoped_ptr_impl* other) + : data_(other->release(), other->get_deleter()) { + // We do not support move-only deleters. We could modify our move + // emulation to have talk_base::subtle::move() and + // talk_base::subtle::forward() + // functions that are imperfect emulations of their C++11 equivalents, + // but until there's a requirement, just assume deleters are copyable. + } + + template + void TakeState(scoped_ptr_impl* other) { + // See comment in templated constructor above regarding lack of support + // for move-only deleters. + reset(other->release()); + get_deleter() = other->get_deleter(); + } + + ~scoped_ptr_impl() { + if (data_.ptr != NULL) { + // Not using get_deleter() saves one function call in non-optimized + // builds. + static_cast(data_)(data_.ptr); + } + } + + void reset(T* p) { + // This is a self-reset, which is no longer allowed: http://crbug.com/162971 + if (p != NULL && p == data_.ptr) + abort(); + + // Note that running data_.ptr = p can lead to undefined behavior if + // get_deleter()(get()) deletes this. In order to pevent this, reset() + // should update the stored pointer before deleting its old value. + // + // However, changing reset() to use that behavior may cause current code to + // break in unexpected ways. If the destruction of the owned object + // dereferences the scoped_ptr when it is destroyed by a call to reset(), + // then it will incorrectly dispatch calls to |p| rather than the original + // value of |data_.ptr|. + // + // During the transition period, set the stored pointer to NULL while + // deleting the object. Eventually, this safety check will be removed to + // prevent the scenario initially described from occuring and + // http://crbug.com/176091 can be closed. + T* old = data_.ptr; + data_.ptr = NULL; + if (old != NULL) + static_cast(data_)(old); + data_.ptr = p; + } + + T* get() const { return data_.ptr; } + + D& get_deleter() { return data_; } + const D& get_deleter() const { return data_; } + + void swap(scoped_ptr_impl& p2) { + // Standard swap idiom: 'using std::swap' ensures that std::swap is + // present in the overload set, but we call swap unqualified so that + // any more-specific overloads can be used, if available. + using std::swap; + swap(static_cast(data_), static_cast(p2.data_)); + swap(data_.ptr, p2.data_.ptr); + } + + T* release() { + T* old_ptr = data_.ptr; + data_.ptr = NULL; + return old_ptr; + } + + T** accept() { + reset(NULL); + return &(data_.ptr); + } + + T** use() { + return &(data_.ptr); + } + + private: + // Needed to allow type-converting constructor. + template friend class scoped_ptr_impl; + + // Use the empty base class optimization to allow us to have a D + // member, while avoiding any space overhead for it when D is an + // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good + // discussion of this technique. + struct Data : public D { + explicit Data(T* ptr_in) : ptr(ptr_in) {} + Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {} + T* ptr; + }; + + Data data_; + + DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl); +}; + +} // namespace internal + +// A scoped_ptr is like a T*, except that the destructor of scoped_ptr +// automatically deletes the pointer it holds (if any). +// That is, scoped_ptr owns the T object that it points to. +// Like a T*, a scoped_ptr may hold either NULL or a pointer to a T object. +// Also like T*, scoped_ptr is thread-compatible, and once you +// dereference it, you get the thread safety guarantees of T. +// +// The size of scoped_ptr is small. On most compilers, when using the +// DefaultDeleter, sizeof(scoped_ptr) == sizeof(T*). Custom deleters will +// increase the size proportional to whatever state they need to have. See +// comments inside scoped_ptr_impl<> for details. +// +// Current implementation targets having a strict subset of C++11's +// unique_ptr<> features. Known deficiencies include not supporting move-only +// deleteres, function pointers as deleters, and deleters with reference +// types. +template > +class scoped_ptr { + TALK_MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) + + public: + // The element and deleter types. + typedef T element_type; + typedef D deleter_type; + + // Constructor. Defaults to initializing with NULL. + scoped_ptr() : impl_(NULL) { } + + // Constructor. Takes ownership of p. + explicit scoped_ptr(element_type* p) : impl_(p) { } + + // Constructor. Allows initialization of a stateful deleter. + scoped_ptr(element_type* p, const D& d) : impl_(p, d) { } + + // Constructor. Allows construction from a scoped_ptr rvalue for a + // convertible type and deleter. + // + // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct + // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor + // has different post-conditions if D is a reference type. Since this + // implementation does not support deleters with reference type, + // we do not need a separate move constructor allowing us to avoid one + // use of SFINAE. You only need to care about this if you modify the + // implementation of scoped_ptr. + template + scoped_ptr(scoped_ptr other) : impl_(&other.impl_) { + COMPILE_ASSERT(!talk_base::is_array::value, U_cannot_be_an_array); + } + + // Constructor. Move constructor for C++03 move emulation of this type. + scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { } + + // operator=. Allows assignment from a scoped_ptr rvalue for a convertible + // type and deleter. + // + // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from + // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated + // form has different requirements on for move-only Deleters. Since this + // implementation does not support move-only Deleters, we do not need a + // separate move assignment operator allowing us to avoid one use of SFINAE. + // You only need to care about this if you modify the implementation of + // scoped_ptr. + template + scoped_ptr& operator=(scoped_ptr rhs) { + COMPILE_ASSERT(!talk_base::is_array::value, U_cannot_be_an_array); + impl_.TakeState(&rhs.impl_); + return *this; + } + + // Reset. Deletes the currently owned object, if any. + // Then takes ownership of a new object, if given. + void reset(element_type* p = NULL) { impl_.reset(p); } + + // Accessors to get the owned object. + // operator* and operator-> will assert() if there is no current object. + element_type& operator*() const { + ASSERT(impl_.get() != NULL); + return *impl_.get(); + } + element_type* operator->() const { + ASSERT(impl_.get() != NULL); + return impl_.get(); + } + element_type* get() const { return impl_.get(); } + + // Access to the deleter. + deleter_type& get_deleter() { return impl_.get_deleter(); } + const deleter_type& get_deleter() const { return impl_.get_deleter(); } + + // Allow scoped_ptr to be used in boolean expressions, but not + // implicitly convertible to a real bool (which is dangerous). + // + // Note that this trick is only safe when the == and != operators + // are declared explicitly, as otherwise "scoped_ptr1 == + // scoped_ptr2" will compile but do the wrong thing (i.e., convert + // to Testable and then do the comparison). + private: + typedef talk_base::internal::scoped_ptr_impl + scoped_ptr::*Testable; + + public: + operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(const element_type* p) const { return impl_.get() == p; } + bool operator!=(const element_type* p) const { return impl_.get() != p; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + impl_.swap(p2.impl_); + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + element_type* release() WARN_UNUSED_RESULT { + return impl_.release(); + } + + // Delete the currently held pointer and return a pointer + // to allow overwriting of the current pointer address. + element_type** accept() WARN_UNUSED_RESULT { + return impl_.accept(); + } + + // Return a pointer to the current pointer address. + element_type** use() WARN_UNUSED_RESULT { + return impl_.use(); + } + + // C++98 doesn't support functions templates with default parameters which + // makes it hard to write a PassAs() that understands converting the deleter + // while preserving simple calling semantics. + // + // Until there is a use case for PassAs() with custom deleters, just ignore + // the custom deleter. + template + scoped_ptr PassAs() { + return scoped_ptr(Pass()); + } + + private: + // Needed to reach into |impl_| in the constructor. + template friend class scoped_ptr; + talk_base::internal::scoped_ptr_impl impl_; + + // Forbidden for API compatibility with std::unique_ptr. + explicit scoped_ptr(int disallow_construction_from_null); + + // Forbid comparison of scoped_ptr types. If U != T, it totally + // doesn't make sense, and if U == T, it still doesn't make sense + // because you should never have the same object owned by two different + // scoped_ptrs. + template bool operator==(scoped_ptr const& p2) const; + template bool operator!=(scoped_ptr const& p2) const; +}; + +template +class scoped_ptr { + TALK_MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) + + public: + // The element and deleter types. + typedef T element_type; + typedef D deleter_type; + + // Constructor. Defaults to initializing with NULL. + scoped_ptr() : impl_(NULL) { } + + // Constructor. Stores the given array. Note that the argument's type + // must exactly match T*. In particular: + // - it cannot be a pointer to a type derived from T, because it is + // inherently unsafe in the general case to access an array through a + // pointer whose dynamic type does not match its static type (eg., if + // T and the derived types had different sizes access would be + // incorrectly calculated). Deletion is also always undefined + // (C++98 [expr.delete]p3). If you're doing this, fix your code. + // - it cannot be NULL, because NULL is an integral expression, not a + // pointer to T. Use the no-argument version instead of explicitly + // passing NULL. + // - it cannot be const-qualified differently from T per unique_ptr spec + // (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting + // to work around this may use implicit_cast(). + // However, because of the first bullet in this comment, users MUST + // NOT use implicit_cast() to upcast the static type of the array. + explicit scoped_ptr(element_type* array) : impl_(array) { } + + // Constructor. Move constructor for C++03 move emulation of this type. + scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { } + + // operator=. Move operator= for C++03 move emulation of this type. + scoped_ptr& operator=(RValue rhs) { + impl_.TakeState(&rhs.object->impl_); + return *this; + } + + // Reset. Deletes the currently owned array, if any. + // Then takes ownership of a new object, if given. + void reset(element_type* array = NULL) { impl_.reset(array); } + + // Accessors to get the owned array. + element_type& operator[](size_t i) const { + ASSERT(impl_.get() != NULL); + return impl_.get()[i]; + } + element_type* get() const { return impl_.get(); } + + // Access to the deleter. + deleter_type& get_deleter() { return impl_.get_deleter(); } + const deleter_type& get_deleter() const { return impl_.get_deleter(); } + + // Allow scoped_ptr to be used in boolean expressions, but not + // implicitly convertible to a real bool (which is dangerous). + private: + typedef talk_base::internal::scoped_ptr_impl + scoped_ptr::*Testable; + + public: + operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(element_type* array) const { return impl_.get() == array; } + bool operator!=(element_type* array) const { return impl_.get() != array; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + impl_.swap(p2.impl_); + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + element_type* release() WARN_UNUSED_RESULT { + return impl_.release(); + } + + // Delete the currently held pointer and return a pointer + // to allow overwriting of the current pointer address. + element_type** accept() WARN_UNUSED_RESULT { + return impl_.accept(); + } + + // Return a pointer to the current pointer address. + element_type** use() WARN_UNUSED_RESULT { + return impl_.use(); + } + + private: + // Force element_type to be a complete type. + enum { type_must_be_complete = sizeof(element_type) }; + + // Actually hold the data. + talk_base::internal::scoped_ptr_impl impl_; + + // Disable initialization from any type other than element_type*, by + // providing a constructor that matches such an initialization, but is + // private and has no definition. This is disabled because it is not safe to + // call delete[] on an array whose static type does not match its dynamic + // type. + template explicit scoped_ptr(U* array); + explicit scoped_ptr(int disallow_construction_from_null); + + // Disable reset() from any type other than element_type*, for the same + // reasons as the constructor above. + template void reset(U* array); + void reset(int disallow_reset_from_null); + + // Forbid comparison of scoped_ptr types. If U != T, it totally + // doesn't make sense, and if U == T, it still doesn't make sense + // because you should never have the same object owned by two different + // scoped_ptrs. + template bool operator==(scoped_ptr const& p2) const; + template bool operator!=(scoped_ptr const& p2) const; +}; + +} // namespace talk_base + +// Free functions +template +void swap(talk_base::scoped_ptr& p1, talk_base::scoped_ptr& p2) { + p1.swap(p2); +} + +template +bool operator==(T* p1, const talk_base::scoped_ptr& p2) { + return p1 == p2.get(); +} + +template +bool operator!=(T* p1, const talk_base::scoped_ptr& p2) { + return p1 != p2.get(); +} + +#endif // #ifndef TALK_BASE_SCOPED_PTR_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/scoped_ref_ptr.h b/thirdparties/common/include/webrtc-sdk/talk/base/scoped_ref_ptr.h new file mode 100644 index 0000000..39b8af6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/scoped_ref_ptr.h @@ -0,0 +1,164 @@ +/* + * 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. + */ + +// Originally these classes are from Chromium. +// http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/ref_counted.h?view=markup + +// +// A smart pointer class for reference counted objects. Use this class instead +// of calling AddRef and Release manually on a reference counted object to +// avoid common memory leaks caused by forgetting to Release an object +// reference. Sample usage: +// +// class MyFoo : public RefCounted { +// ... +// }; +// +// void some_function() { +// scoped_refptr foo = new MyFoo(); +// foo->Method(param); +// // |foo| is released when this function returns +// } +// +// void some_other_function() { +// scoped_refptr foo = new MyFoo(); +// ... +// foo = NULL; // explicitly releases |foo| +// ... +// if (foo) +// foo->Method(param); +// } +// +// The above examples show how scoped_refptr acts like a pointer to T. +// Given two scoped_refptr classes, it is also possible to exchange +// references between the two objects, like so: +// +// { +// scoped_refptr a = new MyFoo(); +// scoped_refptr b; +// +// b.swap(a); +// // now, |b| references the MyFoo object, and |a| references NULL. +// } +// +// To make both |a| and |b| in the above example reference the same MyFoo +// object, simply use the assignment operator: +// +// { +// scoped_refptr a = new MyFoo(); +// scoped_refptr b; +// +// b = a; +// // now, |a| and |b| each own a reference to the same MyFoo object. +// } +// + +#ifndef TALK_BASE_SCOPED_REF_PTR_H_ +#define TALK_BASE_SCOPED_REF_PTR_H_ + +#include + +namespace talk_base { + +template +class scoped_refptr { + public: + scoped_refptr() : ptr_(NULL) { + } + + scoped_refptr(T* p) : ptr_(p) { + if (ptr_) + ptr_->AddRef(); + } + + scoped_refptr(const scoped_refptr& r) : ptr_(r.ptr_) { + if (ptr_) + ptr_->AddRef(); + } + + template + scoped_refptr(const scoped_refptr& r) : ptr_(r.get()) { + if (ptr_) + ptr_->AddRef(); + } + + ~scoped_refptr() { + if (ptr_) + ptr_->Release(); + } + + T* get() const { return ptr_; } + operator T*() const { return ptr_; } + T* operator->() const { return ptr_; } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + T* release() { + T* retVal = ptr_; + ptr_ = NULL; + return retVal; + } + + scoped_refptr& operator=(T* p) { + // AddRef first so that self assignment should work + if (p) + p->AddRef(); + if (ptr_ ) + ptr_ ->Release(); + ptr_ = p; + return *this; + } + + scoped_refptr& operator=(const scoped_refptr& r) { + return *this = r.ptr_; + } + + template + scoped_refptr& operator=(const scoped_refptr& r) { + return *this = r.get(); + } + + void swap(T** pp) { + T* p = ptr_; + ptr_ = *pp; + *pp = p; + } + + void swap(scoped_refptr& r) { + swap(&r.ptr_); + } + + protected: + T* ptr_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_SCOPED_REF_PTR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/scopedptrcollection.h b/thirdparties/common/include/webrtc-sdk/talk/base/scopedptrcollection.h new file mode 100644 index 0000000..2d07989 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/scopedptrcollection.h @@ -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. + */ + +// Stores a collection of pointers that are deleted when the container is +// destructed. + +#ifndef TALK_BASE_SCOPEDPTRCOLLECTION_H_ +#define TALK_BASE_SCOPEDPTRCOLLECTION_H_ + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/constructormagic.h" + +namespace talk_base { + +template +class ScopedPtrCollection { + public: + typedef std::vector 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); + } + + // Remove |t| from the collection without deleting it. + void Remove(T* t) { + collection_.erase(std::remove(collection_.begin(), collection_.end(), t), + collection_.end()); + } + + private: + VectorT collection_; + + DISALLOW_COPY_AND_ASSIGN(ScopedPtrCollection); +}; + +} // namespace talk_base + +#endif // TALK_BASE_SCOPEDPTRCOLLECTION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sec_buffer.h b/thirdparties/common/include/webrtc-sdk/talk/base/sec_buffer.h new file mode 100644 index 0000000..093eb23 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sec_buffer.h @@ -0,0 +1,173 @@ +/* + * 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. + */ + +// @file Contains utility classes that make it easier to use SecBuffers + +#ifndef TALK_BASE_SEC_BUFFER_H__ +#define TALK_BASE_SEC_BUFFER_H__ + +namespace talk_base { + +// A base class for CSecBuffer. Contains +// all implementation that does not require +// template arguments. +class CSecBufferBase : public SecBuffer { + public: + CSecBufferBase() { + Clear(); + } + + // Uses the SSPI to free a pointer, must be + // used for buffers returned from SSPI APIs. + static void FreeSSPI(void *ptr) { + if ( ptr ) { + SECURITY_STATUS status; + status = ::FreeContextBuffer(ptr); + ASSERT(SEC_E_OK == status); // "Freeing context buffer" + } + } + + // Deletes a buffer with operator delete + static void FreeDelete(void *ptr) { + delete [] reinterpret_cast(ptr); + } + + // A noop delete, for buffers over other + // people's memory + static void FreeNone(void *ptr) { + } + + protected: + // Clears the buffer to EMPTY & NULL + void Clear() { + this->BufferType = SECBUFFER_EMPTY; + this->cbBuffer = 0; + this->pvBuffer = NULL; + } +}; + +// Wrapper class for SecBuffer to take care +// of initialization and destruction. +template +class CSecBuffer: public CSecBufferBase { + public: + // Initializes buffer to empty & NULL + CSecBuffer() { + } + + // Frees any allocated memory + ~CSecBuffer() { + Release(); + } + + // Frees the buffer appropriately, and re-nulls + void Release() { + pfnFreeBuffer(this->pvBuffer); + Clear(); + } + + private: + // A placeholder function for compile-time asserts on the class + void CompileAsserts() { + // never invoked... + assert(false); // _T("Notreached") + + // This class must not extend the size of SecBuffer, since + // we use arrays of CSecBuffer in CSecBufferBundle below + cassert(sizeof(CSecBuffer == sizeof(SecBuffer))); + } +}; + +// Contains all generic implementation for the +// SecBufferBundle class +class SecBufferBundleBase { + public: +}; + +// A template class that bundles a SecBufferDesc with +// one or more SecBuffers for convenience. Can take +// care of deallocating buffers appropriately, as indicated +// by pfnFreeBuffer function. +// By default does no deallocation. +template +class CSecBufferBundle : public SecBufferBundleBase { + public: + // Constructs a security buffer bundle with num_buffers + // buffers, all of which are empty and nulled. + CSecBufferBundle() { + desc_.ulVersion = SECBUFFER_VERSION; + desc_.cBuffers = num_buffers; + desc_.pBuffers = buffers_; + } + + // Frees all currently used buffers. + ~CSecBufferBundle() { + Release(); + } + + // Accessor for the descriptor + PSecBufferDesc desc() { + return &desc_; + } + + // Accessor for the descriptor + const PSecBufferDesc desc() const { + return &desc_; + } + + // returns the i-th security buffer + SecBuffer &operator[] (size_t num) { + ASSERT(num < num_buffers); // "Buffer index out of bounds" + return buffers_[num]; + } + + // returns the i-th security buffer + const SecBuffer &operator[] (size_t num) const { + ASSERT(num < num_buffers); // "Buffer index out of bounds" + return buffers_[num]; + } + + // Frees all non-NULL security buffers, + // using the deallocation function + void Release() { + for ( size_t i = 0; i < num_buffers; ++i ) { + buffers_[i].Release(); + } + } + + private: + // Our descriptor + SecBufferDesc desc_; + // Our bundled buffers, each takes care of its own + // initialization and destruction + CSecBuffer buffers_[num_buffers]; +}; + +} // namespace talk_base + +#endif // TALK_BASE_SEC_BUFFER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sha1.h b/thirdparties/common/include/webrtc-sdk/talk/base/sha1.h new file mode 100644 index 0000000..09ab424 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sha1.h @@ -0,0 +1,28 @@ +/* + * SHA-1 in C + * By Steve Reid + * 100% Public Domain + * +*/ + +// Ported to C++, Google style and uses basictypes.h + +#ifndef TALK_BASE_SHA1_H_ +#define TALK_BASE_SHA1_H_ + +#include "talk/base/basictypes.h" + +struct SHA1_CTX { + uint32 state[5]; + // TODO: Change bit count to uint64. + uint32 count[2]; // Bit count of input. + uint8 buffer[64]; +}; + +#define SHA1_DIGEST_SIZE 20 + +void SHA1Init(SHA1_CTX* context); +void SHA1Update(SHA1_CTX* context, const uint8* data, size_t len); +void SHA1Final(SHA1_CTX* context, uint8 digest[SHA1_DIGEST_SIZE]); + +#endif // TALK_BASE_SHA1_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sha1digest.h b/thirdparties/common/include/webrtc-sdk/talk/base/sha1digest.h new file mode 100644 index 0000000..786e46c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sha1digest.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_SHA1DIGEST_H_ +#define TALK_BASE_SHA1DIGEST_H_ + +#include "talk/base/messagedigest.h" +#include "talk/base/sha1.h" + +namespace talk_base { + +// A simple wrapper for our SHA-1 implementation. +class Sha1Digest : public MessageDigest { + public: + enum { kSize = SHA1_DIGEST_SIZE }; + Sha1Digest() { + SHA1Init(&ctx_); + } + virtual size_t Size() const { + return kSize; + } + virtual void Update(const void* buf, size_t len) { + SHA1Update(&ctx_, static_cast(buf), len); + } + virtual size_t Finish(void* buf, size_t len) { + if (len < kSize) { + return 0; + } + SHA1Final(&ctx_, static_cast(buf)); + SHA1Init(&ctx_); // Reset for next use. + return kSize; + } + + private: + SHA1_CTX ctx_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_SHA1DIGEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sharedexclusivelock.h b/thirdparties/common/include/webrtc-sdk/talk/base/sharedexclusivelock.h new file mode 100644 index 0000000..391e83c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sharedexclusivelock.h @@ -0,0 +1,93 @@ +/* + * 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_BASE_SHAREDEXCLUSIVELOCK_H_ +#define TALK_BASE_SHAREDEXCLUSIVELOCK_H_ + +#include "talk/base/constructormagic.h" +#include "talk/base/criticalsection.h" +#include "talk/base/event.h" + +namespace talk_base { + +// This class provides shared-exclusive lock. It can be used in cases like +// multiple-readers/single-writer model. +class SharedExclusiveLock { + public: + SharedExclusiveLock(); + + // Locking/unlocking methods. It is encouraged to use SharedScope or + // ExclusiveScope for protection. + void LockExclusive(); + void UnlockExclusive(); + void LockShared(); + void UnlockShared(); + + private: + talk_base::CriticalSection cs_exclusive_; + talk_base::CriticalSection cs_shared_; + talk_base::Event shared_count_is_zero_; + int shared_count_; + + DISALLOW_COPY_AND_ASSIGN(SharedExclusiveLock); +}; + +class SharedScope { + public: + explicit SharedScope(SharedExclusiveLock* lock) : lock_(lock) { + lock_->LockShared(); + } + + ~SharedScope() { + lock_->UnlockShared(); + } + + private: + SharedExclusiveLock* lock_; + + DISALLOW_COPY_AND_ASSIGN(SharedScope); +}; + +class ExclusiveScope { + public: + explicit ExclusiveScope(SharedExclusiveLock* lock) : lock_(lock) { + lock_->LockExclusive(); + } + + ~ExclusiveScope() { + lock_->UnlockExclusive(); + } + + private: + SharedExclusiveLock* lock_; + + DISALLOW_COPY_AND_ASSIGN(ExclusiveScope); +}; + +} // namespace talk_base + +#endif // TALK_BASE_SHAREDEXCLUSIVELOCK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/signalthread.h b/thirdparties/common/include/webrtc-sdk/talk/base/signalthread.h new file mode 100644 index 0000000..e141e5a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/signalthread.h @@ -0,0 +1,173 @@ +/* + * libjingle + * Copyright 2004--2009, 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_SIGNALTHREAD_H_ +#define TALK_BASE_SIGNALTHREAD_H_ + +#include + +#include "talk/base/constructormagic.h" +#include "talk/base/sigslot.h" +#include "talk/base/thread.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// SignalThread - Base class for worker threads. The main thread should call +// Start() to begin work, and then follow one of these models: +// Normal: Wait for SignalWorkDone, and then call Release to destroy. +// Cancellation: Call Release(true), to abort the worker thread. +// Fire-and-forget: Call Release(false), which allows the thread to run to +// completion, and then self-destruct without further notification. +// Periodic tasks: Wait for SignalWorkDone, then eventually call Start() +// again to repeat the task. When the instance isn't needed anymore, +// call Release. DoWork, OnWorkStart and OnWorkStop are called again, +// on a new thread. +// The subclass should override DoWork() to perform the background task. By +// periodically calling ContinueWork(), it can check for cancellation. +// OnWorkStart and OnWorkDone can be overridden to do pre- or post-work +// tasks in the context of the main thread. +/////////////////////////////////////////////////////////////////////////////// + +class SignalThread + : public sigslot::has_slots<>, + protected MessageHandler { + public: + SignalThread(); + + // Context: Main Thread. Call before Start to change the worker's name. + bool SetName(const std::string& name, const void* obj); + + // Context: Main Thread. Call before Start to change the worker's priority. + bool SetPriority(ThreadPriority priority); + + // Context: Main Thread. Call to begin the worker thread. + void Start(); + + // Context: Main Thread. If the worker thread is not running, deletes the + // object immediately. Otherwise, asks the worker thread to abort processing, + // and schedules the object to be deleted once the worker exits. + // SignalWorkDone will not be signalled. If wait is true, does not return + // until the thread is deleted. + void Destroy(bool wait); + + // Context: Main Thread. If the worker thread is complete, deletes the + // object immediately. Otherwise, schedules the object to be deleted once + // the worker thread completes. SignalWorkDone will be signalled. + void Release(); + + // Context: Main Thread. Signalled when work is complete. + sigslot::signal1 SignalWorkDone; + + enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE }; + + protected: + virtual ~SignalThread(); + + Thread* worker() { return &worker_; } + + // Context: Main Thread. Subclass should override to do pre-work setup. + virtual void OnWorkStart() { } + + // Context: Worker Thread. Subclass should override to do work. + virtual void DoWork() = 0; + + // Context: Worker Thread. Subclass should call periodically to + // dispatch messages and determine if the thread should terminate. + bool ContinueWork(); + + // Context: Worker Thread. Subclass should override when extra work is + // needed to abort the worker thread. + virtual void OnWorkStop() { } + + // Context: Main Thread. Subclass should override to do post-work cleanup. + virtual void OnWorkDone() { } + + // Context: Any Thread. If subclass overrides, be sure to call the base + // implementation. Do not use (message_id < ST_MSG_FIRST_AVAILABLE) + virtual void OnMessage(Message *msg); + + private: + enum State { + kInit, // Initialized, but not started + kRunning, // Started and doing work + kReleasing, // Same as running, but to be deleted when work is done + kComplete, // Work is done + kStopping, // Work is being interrupted + }; + + class Worker : public Thread { + public: + explicit Worker(SignalThread* parent) : parent_(parent) {} + virtual ~Worker() { Stop(); } + virtual void Run() { parent_->Run(); } + + private: + SignalThread* parent_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(Worker); + }; + + class EnterExit { + public: + explicit EnterExit(SignalThread* t) : t_(t) { + t_->cs_.Enter(); + // If refcount_ is zero then the object has already been deleted and we + // will be double-deleting it in ~EnterExit()! (shouldn't happen) + ASSERT(t_->refcount_ != 0); + ++t_->refcount_; + } + ~EnterExit() { + bool d = (0 == --t_->refcount_); + t_->cs_.Leave(); + if (d) + delete t_; + } + + private: + SignalThread* t_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(EnterExit); + }; + + void Run(); + void OnMainThreadDestroyed(); + + Thread* main_; + Worker worker_; + CriticalSection cs_; + State state_; + int refcount_; + + DISALLOW_COPY_AND_ASSIGN(SignalThread); +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_SIGNALTHREAD_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sigslot.h b/thirdparties/common/include/webrtc-sdk/talk/base/sigslot.h new file mode 100644 index 0000000..ce33b8c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sigslot.h @@ -0,0 +1,2850 @@ +// sigslot.h: Signal/Slot classes +// +// Written by Sarah Thompson (sarah@telergy.com) 2002. +// +// License: Public domain. You are free to use this code however you like, with the proviso that +// the author takes on no responsibility or liability for any use. +// +// QUICK DOCUMENTATION +// +// (see also the full documentation at http://sigslot.sourceforge.net/) +// +// #define switches +// SIGSLOT_PURE_ISO - Define this to force ISO C++ compliance. This also disables +// all of the thread safety support on platforms where it is +// available. +// +// SIGSLOT_USE_POSIX_THREADS - Force use of Posix threads when using a C++ compiler other than +// gcc on a platform that supports Posix threads. (When using gcc, +// this is the default - use SIGSLOT_PURE_ISO to disable this if +// necessary) +// +// SIGSLOT_DEFAULT_MT_POLICY - Where thread support is enabled, this defaults to multi_threaded_global. +// Otherwise, the default is single_threaded. #define this yourself to +// override the default. In pure ISO mode, anything other than +// single_threaded will cause a compiler error. +// +// PLATFORM NOTES +// +// Win32 - On Win32, the WIN32 symbol must be #defined. Most mainstream +// compilers do this by default, but you may need to define it +// yourself if your build environment is less standard. This causes +// the Win32 thread support to be compiled in and used automatically. +// +// Unix/Linux/BSD, etc. - If you're using gcc, it is assumed that you have Posix threads +// available, so they are used automatically. You can override this +// (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using +// something other than gcc but still want to use Posix threads, you +// need to #define SIGSLOT_USE_POSIX_THREADS. +// +// ISO C++ - If none of the supported platforms are detected, or if +// SIGSLOT_PURE_ISO is defined, all multithreading support is turned off, +// along with any code that might cause a pure ISO C++ environment to +// complain. Before you ask, gcc -ansi -pedantic won't compile this +// library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of +// errors that aren't really there. If you feel like investigating this, +// please contact the author. +// +// +// THREADING MODES +// +// single_threaded - Your program is assumed to be single threaded from the point of view +// of signal/slot usage (i.e. all objects using signals and slots are +// created and destroyed from a single thread). Behaviour if objects are +// destroyed concurrently is undefined (i.e. you'll get the occasional +// segmentation fault/memory exception). +// +// multi_threaded_global - Your program is assumed to be multi threaded. Objects using signals and +// slots can be safely created and destroyed from any thread, even when +// connections exist. In multi_threaded_global mode, this is achieved by a +// single global mutex (actually a critical section on Windows because they +// are faster). This option uses less OS resources, but results in more +// opportunities for contention, possibly resulting in more context switches +// than are strictly necessary. +// +// multi_threaded_local - Behaviour in this mode is essentially the same as multi_threaded_global, +// except that each signal, and each object that inherits has_slots, all +// have their own mutex/critical section. In practice, this means that +// mutex collisions (and hence context switches) only happen if they are +// absolutely essential. However, on some platforms, creating a lot of +// mutexes can slow down the whole OS, so use this option with care. +// +// USING THE LIBRARY +// +// See the full documentation at http://sigslot.sourceforge.net/ +// +// +// Libjingle specific: +// This file has been modified such that has_slots and signalx do not have to be +// using the same threading requirements. E.g. it is possible to connect a +// has_slots and signal0 or +// has_slots and signal0. +// If has_slots is single threaded the user must ensure that it is not trying +// to connect or disconnect to signalx concurrently or data race may occur. +// If signalx is single threaded the user must ensure that disconnect, connect +// or signal is not happening concurrently or data race may occur. + +#ifndef TALK_BASE_SIGSLOT_H__ +#define TALK_BASE_SIGSLOT_H__ + +#include +#include +#include + +// On our copy of sigslot.h, we set single threading as default. +#define SIGSLOT_DEFAULT_MT_POLICY single_threaded + +#if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS)) +# define _SIGSLOT_SINGLE_THREADED +#elif defined(WIN32) +# define _SIGSLOT_HAS_WIN32_THREADS +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif +# include "talk/base/win32.h" +#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS) +# define _SIGSLOT_HAS_POSIX_THREADS +# include +#else +# define _SIGSLOT_SINGLE_THREADED +#endif + +#ifndef SIGSLOT_DEFAULT_MT_POLICY +# ifdef _SIGSLOT_SINGLE_THREADED +# define SIGSLOT_DEFAULT_MT_POLICY single_threaded +# else +# define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local +# endif +#endif + +// TODO: change this namespace to talk_base? +namespace sigslot { + + class single_threaded + { + public: + single_threaded() + { + ; + } + + virtual ~single_threaded() + { + ; + } + + virtual void lock() + { + ; + } + + virtual void unlock() + { + ; + } + }; + +#ifdef _SIGSLOT_HAS_WIN32_THREADS + // The multi threading policies only get compiled in if they are enabled. + class multi_threaded_global + { + public: + multi_threaded_global() + { + static bool isinitialised = false; + + if(!isinitialised) + { + InitializeCriticalSection(get_critsec()); + isinitialised = true; + } + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + EnterCriticalSection(get_critsec()); + } + + virtual void unlock() + { + LeaveCriticalSection(get_critsec()); + } + + private: + CRITICAL_SECTION* get_critsec() + { + static CRITICAL_SECTION g_critsec; + return &g_critsec; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + InitializeCriticalSection(&m_critsec); + } + + multi_threaded_local(const multi_threaded_local&) + { + InitializeCriticalSection(&m_critsec); + } + + virtual ~multi_threaded_local() + { + DeleteCriticalSection(&m_critsec); + } + + virtual void lock() + { + EnterCriticalSection(&m_critsec); + } + + virtual void unlock() + { + LeaveCriticalSection(&m_critsec); + } + + private: + CRITICAL_SECTION m_critsec; + }; +#endif // _SIGSLOT_HAS_WIN32_THREADS + +#ifdef _SIGSLOT_HAS_POSIX_THREADS + // The multi threading policies only get compiled in if they are enabled. + class multi_threaded_global + { + public: + multi_threaded_global() + { + pthread_mutex_init(get_mutex(), NULL); + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + pthread_mutex_lock(get_mutex()); + } + + virtual void unlock() + { + pthread_mutex_unlock(get_mutex()); + } + + private: + pthread_mutex_t* get_mutex() + { + static pthread_mutex_t g_mutex; + return &g_mutex; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + pthread_mutex_init(&m_mutex, NULL); + } + + multi_threaded_local(const multi_threaded_local&) + { + pthread_mutex_init(&m_mutex, NULL); + } + + virtual ~multi_threaded_local() + { + pthread_mutex_destroy(&m_mutex); + } + + virtual void lock() + { + pthread_mutex_lock(&m_mutex); + } + + virtual void unlock() + { + pthread_mutex_unlock(&m_mutex); + } + + private: + pthread_mutex_t m_mutex; + }; +#endif // _SIGSLOT_HAS_POSIX_THREADS + + template + class lock_block + { + public: + mt_policy *m_mutex; + + lock_block(mt_policy *mtx) + : m_mutex(mtx) + { + m_mutex->lock(); + } + + ~lock_block() + { + m_mutex->unlock(); + } + }; + + class has_slots_interface; + + template + class _connection_base0 + { + public: + virtual ~_connection_base0() {} + virtual has_slots_interface* getdest() const = 0; + virtual void emit() = 0; + virtual _connection_base0* clone() = 0; + virtual _connection_base0* duplicate(has_slots_interface* pnewdest) = 0; + }; + + template + class _connection_base1 + { + public: + virtual ~_connection_base1() {} + virtual has_slots_interface* getdest() const = 0; + virtual void emit(arg1_type) = 0; + virtual _connection_base1* clone() = 0; + virtual _connection_base1* duplicate(has_slots_interface* pnewdest) = 0; + }; + + template + class _connection_base2 + { + public: + virtual ~_connection_base2() {} + virtual has_slots_interface* getdest() const = 0; + virtual void emit(arg1_type, arg2_type) = 0; + virtual _connection_base2* clone() = 0; + virtual _connection_base2* duplicate(has_slots_interface* pnewdest) = 0; + }; + + template + class _connection_base3 + { + public: + virtual ~_connection_base3() {} + virtual has_slots_interface* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type) = 0; + virtual _connection_base3* clone() = 0; + virtual _connection_base3* duplicate(has_slots_interface* pnewdest) = 0; + }; + + template + class _connection_base4 + { + public: + virtual ~_connection_base4() {} + virtual has_slots_interface* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0; + virtual _connection_base4* clone() = 0; + virtual _connection_base4* duplicate(has_slots_interface* pnewdest) = 0; + }; + + template + class _connection_base5 + { + public: + virtual ~_connection_base5() {} + virtual has_slots_interface* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type) = 0; + virtual _connection_base5* clone() = 0; + virtual _connection_base5* duplicate(has_slots_interface* pnewdest) = 0; + }; + + template + class _connection_base6 + { + public: + virtual ~_connection_base6() {} + virtual has_slots_interface* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type) = 0; + virtual _connection_base6* clone() = 0; + virtual _connection_base6* duplicate(has_slots_interface* pnewdest) = 0; + }; + + template + class _connection_base7 + { + public: + virtual ~_connection_base7() {} + virtual has_slots_interface* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type, arg7_type) = 0; + virtual _connection_base7* clone() = 0; + virtual _connection_base7* duplicate(has_slots_interface* pnewdest) = 0; + }; + + template + class _connection_base8 + { + public: + virtual ~_connection_base8() {} + virtual has_slots_interface* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type, arg7_type, arg8_type) = 0; + virtual _connection_base8* clone() = 0; + virtual _connection_base8* duplicate(has_slots_interface* pnewdest) = 0; + }; + + class _signal_base_interface + { + public: + virtual void slot_disconnect(has_slots_interface* pslot) = 0; + virtual void slot_duplicate(const has_slots_interface* poldslot, has_slots_interface* pnewslot) = 0; + }; + + template + class _signal_base : public _signal_base_interface, public mt_policy + { + }; + + class has_slots_interface + { + public: + has_slots_interface() + { + ; + } + + virtual void signal_connect(_signal_base_interface* sender) = 0; + + virtual void signal_disconnect(_signal_base_interface* sender) = 0; + + virtual ~has_slots_interface() + { + } + + virtual void disconnect_all() = 0; + }; + + template + class has_slots : public has_slots_interface, public mt_policy + { + private: + typedef std::set<_signal_base_interface*> sender_set; + typedef sender_set::const_iterator const_iterator; + + public: + has_slots() + { + ; + } + + has_slots(const has_slots& hs) + { + lock_block lock(this); + const_iterator it = hs.m_senders.begin(); + const_iterator itEnd = hs.m_senders.end(); + + while(it != itEnd) + { + (*it)->slot_duplicate(&hs, this); + m_senders.insert(*it); + ++it; + } + } + + void signal_connect(_signal_base_interface* sender) + { + lock_block lock(this); + m_senders.insert(sender); + } + + void signal_disconnect(_signal_base_interface* sender) + { + lock_block lock(this); + m_senders.erase(sender); + } + + virtual ~has_slots() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_senders.begin(); + const_iterator itEnd = m_senders.end(); + + while(it != itEnd) + { + (*it)->slot_disconnect(this); + ++it; + } + + m_senders.erase(m_senders.begin(), m_senders.end()); + } + + private: + sender_set m_senders; + }; + + template + class _signal_base0 : public _signal_base + { + public: + typedef std::list<_connection_base0 *> connections_list; + + _signal_base0() + { + ; + } + + _signal_base0(const _signal_base0& s) + : _signal_base(s) + { + lock_block lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + ~_signal_base0() + { + disconnect_all(); + } + + bool is_empty() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + return it == itEnd; + } + + void disconnect_all() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots_interface* pslot) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + } + + it = itNext; + } + } + + void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base1 : public _signal_base + { + public: + typedef std::list<_connection_base1 *> connections_list; + + _signal_base1() + { + ; + } + + _signal_base1(const _signal_base1& s) + : _signal_base(s) + { + lock_block lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base1() + { + disconnect_all(); + } + + bool is_empty() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + return it == itEnd; + } + + void disconnect_all() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots_interface* pslot) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + } + + it = itNext; + } + } + + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base2 : public _signal_base + { + public: + typedef std::list<_connection_base2 *> + connections_list; + + _signal_base2() + { + ; + } + + _signal_base2(const _signal_base2& s) + : _signal_base(s) + { + lock_block lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base2() + { + disconnect_all(); + } + + bool is_empty() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + return it == itEnd; + } + + void disconnect_all() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots_interface* pslot) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base3 : public _signal_base + { + public: + typedef std::list<_connection_base3 *> + connections_list; + + _signal_base3() + { + ; + } + + _signal_base3(const _signal_base3& s) + : _signal_base(s) + { + lock_block lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base3() + { + disconnect_all(); + } + + bool is_empty() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + return it == itEnd; + } + + void disconnect_all() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots_interface* pslot) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base4 : public _signal_base + { + public: + typedef std::list<_connection_base4 *> connections_list; + + _signal_base4() + { + ; + } + + _signal_base4(const _signal_base4& s) + : _signal_base(s) + { + lock_block lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base4() + { + disconnect_all(); + } + + bool is_empty() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + return it == itEnd; + } + + void disconnect_all() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots_interface* pslot) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base5 : public _signal_base + { + public: + typedef std::list<_connection_base5 *> connections_list; + + _signal_base5() + { + ; + } + + _signal_base5(const _signal_base5& s) + : _signal_base(s) + { + lock_block lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base5() + { + disconnect_all(); + } + + bool is_empty() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + return it == itEnd; + } + + void disconnect_all() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots_interface* pslot) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base6 : public _signal_base + { + public: + typedef std::list<_connection_base6 *> connections_list; + + _signal_base6() + { + ; + } + + _signal_base6(const _signal_base6& s) + : _signal_base(s) + { + lock_block lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base6() + { + disconnect_all(); + } + + bool is_empty() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + return it == itEnd; + } + + void disconnect_all() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots_interface* pslot) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base7 : public _signal_base + { + public: + typedef std::list<_connection_base7 *> connections_list; + + _signal_base7() + { + ; + } + + _signal_base7(const _signal_base7& s) + : _signal_base(s) + { + lock_block lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base7() + { + disconnect_all(); + } + + bool is_empty() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + return it == itEnd; + } + + void disconnect_all() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots_interface* pslot) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base8 : public _signal_base + { + public: + typedef std::list<_connection_base8 *> + connections_list; + + _signal_base8() + { + ; + } + + _signal_base8(const _signal_base8& s) + : _signal_base(s) + { + lock_block lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base8() + { + disconnect_all(); + } + + bool is_empty() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + return it == itEnd; + } + + void disconnect_all() + { + lock_block lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots_interface* pclass) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots_interface* pslot) + { + lock_block lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + delete *it; + m_connected_slots.erase(it); + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + + template + class _connection0 : public _connection_base0 + { + public: + _connection0() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection0(dest_type* pobject, void (dest_type::*pmemfun)()) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection0() + { + } + + virtual _connection_base0* clone() + { + return new _connection0(*this); + } + + virtual _connection_base0* duplicate(has_slots_interface* pnewdest) + { + return new _connection0((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit() + { + (m_pobject->*m_pmemfun)(); + } + + virtual has_slots_interface* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(); + }; + + template + class _connection1 : public _connection_base1 + { + public: + _connection1() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection1() + { + } + + virtual _connection_base1* clone() + { + return new _connection1(*this); + } + + virtual _connection_base1* duplicate(has_slots_interface* pnewdest) + { + return new _connection1((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1) + { + (m_pobject->*m_pmemfun)(a1); + } + + virtual has_slots_interface* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type); + }; + + template + class _connection2 : public _connection_base2 + { + public: + _connection2() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection2() + { + } + + virtual _connection_base2* clone() + { + return new _connection2(*this); + } + + virtual _connection_base2* duplicate(has_slots_interface* pnewdest) + { + return new _connection2((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2) + { + (m_pobject->*m_pmemfun)(a1, a2); + } + + virtual has_slots_interface* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type); + }; + + template + class _connection3 : public _connection_base3 + { + public: + _connection3() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection3() + { + } + + virtual _connection_base3* clone() + { + return new _connection3(*this); + } + + virtual _connection_base3* duplicate(has_slots_interface* pnewdest) + { + return new _connection3((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3) + { + (m_pobject->*m_pmemfun)(a1, a2, a3); + } + + virtual has_slots_interface* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type); + }; + + template + class _connection4 : public _connection_base4 + { + public: + _connection4() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection4() + { + } + + virtual _connection_base4* clone() + { + return new _connection4(*this); + } + + virtual _connection_base4* duplicate(has_slots_interface* pnewdest) + { + return new _connection4((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, + arg4_type a4) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4); + } + + virtual has_slots_interface* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, + arg4_type); + }; + + template + class _connection5 : public _connection_base5 + { + public: + _connection5() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection5() + { + } + + virtual _connection_base5* clone() + { + return new _connection5(*this); + } + + virtual _connection_base5* duplicate(has_slots_interface* pnewdest) + { + return new _connection5((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5); + } + + virtual has_slots_interface* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type); + }; + + template + class _connection6 : public _connection_base6 + { + public: + _connection6() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection6() + { + } + + virtual _connection_base6* clone() + { + return new _connection6(*this); + } + + virtual _connection_base6* duplicate(has_slots_interface* pnewdest) + { + return new _connection6((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6); + } + + virtual has_slots_interface* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type); + }; + + template + class _connection7 : public _connection_base7 + { + public: + _connection7() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection7() + { + } + + virtual _connection_base7* clone() + { + return new _connection7(*this); + } + + virtual _connection_base7* duplicate(has_slots_interface* pnewdest) + { + return new _connection7((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7); + } + + virtual has_slots_interface* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type); + }; + + template + class _connection8 : public _connection_base8 + { + public: + _connection8() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type, arg8_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual ~_connection8() + { + } + + virtual _connection_base8* clone() + { + return new _connection8(*this); + } + + virtual _connection_base8* duplicate(has_slots_interface* pnewdest) + { + return new _connection8((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8); + } + + virtual has_slots_interface* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type); + }; + + template + class signal0 : public _signal_base0 + { + public: + typedef _signal_base0 base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal0() + { + ; + } + + signal0(const signal0& s) + : _signal_base0(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)()) + { + lock_block lock(this); + _connection0* conn = + new _connection0(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit() + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(); + + it = itNext; + } + } + + void operator()() + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(); + + it = itNext; + } + } + }; + + template + class signal1 : public _signal_base1 + { + public: + typedef _signal_base1 base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal1() + { + ; + } + + signal1(const signal1& s) + : _signal_base1(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type)) + { + lock_block lock(this); + _connection1* conn = + new _connection1(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1); + + it = itNext; + } + } + + void operator()(arg1_type a1) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1); + + it = itNext; + } + } + }; + + template + class signal2 : public _signal_base2 + { + public: + typedef _signal_base2 base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal2() + { + ; + } + + signal2(const signal2& s) + : _signal_base2(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type)) + { + lock_block lock(this); + _connection2* conn = new + _connection2(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2); + + it = itNext; + } + } + }; + + template + class signal3 : public _signal_base3 + { + public: + typedef _signal_base3 base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal3() + { + ; + } + + signal3(const signal3& s) + : _signal_base3(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type)) + { + lock_block lock(this); + _connection3* conn = + new _connection3(pclass, + pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3); + + it = itNext; + } + } + }; + + template + class signal4 : public _signal_base4 + { + public: + typedef _signal_base4 base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal4() + { + ; + } + + signal4(const signal4& s) + : _signal_base4(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type)) + { + lock_block lock(this); + _connection4* + conn = new _connection4(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4); + + it = itNext; + } + } + }; + + template + class signal5 : public _signal_base5 + { + public: + typedef _signal_base5 base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal5() + { + ; + } + + signal5(const signal5& s) + : _signal_base5(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type)) + { + lock_block lock(this); + _connection5* conn = new _connection5(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5); + + it = itNext; + } + } + }; + + + template + class signal6 : public _signal_base6 + { + public: + typedef _signal_base6 base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal6() + { + ; + } + + signal6(const signal6& s) + : _signal_base6(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) + { + lock_block lock(this); + _connection6* conn = + new _connection6(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6); + + it = itNext; + } + } + }; + + template + class signal7 : public _signal_base7 + { + public: + typedef _signal_base7 base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal7() + { + ; + } + + signal7(const signal7& s) + : _signal_base7(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type)) + { + lock_block lock(this); + _connection7* conn = + new _connection7(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7); + + it = itNext; + } + } + }; + + template + class signal8 : public _signal_base8 + { + public: + typedef _signal_base8 base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal8() + { + ; + } + + signal8(const signal8& s) + : _signal_base8(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type, arg8_type)) + { + lock_block lock(this); + _connection8* conn = + new _connection8(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + lock_block lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); + + it = itNext; + } + } + }; + +}; // namespace sigslot + +#endif // TALK_BASE_SIGSLOT_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sigslotrepeater.h b/thirdparties/common/include/webrtc-sdk/talk/base/sigslotrepeater.h new file mode 100644 index 0000000..1a86636 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sigslotrepeater.h @@ -0,0 +1,111 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_SIGSLOTREPEATER_H__ +#define TALK_BASE_SIGSLOTREPEATER_H__ + +// repeaters are both signals and slots, which are designed as intermediate +// pass-throughs for signals and slots which don't know about each other (for +// modularity or encapsulation). This eliminates the need to declare a signal +// handler whose sole purpose is to fire another signal. The repeater connects +// to the originating signal using the 'repeat' method. When the repeated +// signal fires, the repeater will also fire. + +#include "talk/base/sigslot.h" + +namespace sigslot { + + template + class repeater0 : public signal0, + public has_slots + { + public: + typedef signal0 base_type; + typedef repeater0 this_type; + + repeater0() { } + repeater0(const this_type& s) : base_type(s) { } + + void reemit() { signal0::emit(); } + void repeat(base_type &s) { s.connect(this, &this_type::reemit); } + void stop(base_type &s) { s.disconnect(this); } + }; + + template + class repeater1 : public signal1, + public has_slots + { + public: + typedef signal1 base_type; + typedef repeater1 this_type; + + repeater1() { } + repeater1(const this_type& s) : base_type(s) { } + + void reemit(arg1_type a1) { signal1::emit(a1); } + void repeat(base_type& s) { s.connect(this, &this_type::reemit); } + void stop(base_type &s) { s.disconnect(this); } + }; + + template + class repeater2 : public signal2, + public has_slots + { + public: + typedef signal2 base_type; + typedef repeater2 this_type; + + repeater2() { } + repeater2(const this_type& s) : base_type(s) { } + + void reemit(arg1_type a1, arg2_type a2) { signal2::emit(a1,a2); } + void repeat(base_type& s) { s.connect(this, &this_type::reemit); } + void stop(base_type &s) { s.disconnect(this); } + }; + + template + class repeater3 : public signal3, + public has_slots + { + public: + typedef signal3 base_type; + typedef repeater3 this_type; + + repeater3() { } + repeater3(const this_type& s) : base_type(s) { } + + void reemit(arg1_type a1, arg2_type a2, arg3_type a3) { + signal3::emit(a1,a2,a3); + } + void repeat(base_type& s) { s.connect(this, &this_type::reemit); } + void stop(base_type &s) { s.disconnect(this); } + }; + +} // namespace sigslot + +#endif // TALK_BASE_SIGSLOTREPEATER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/socket.h b/thirdparties/common/include/webrtc-sdk/talk/base/socket.h new file mode 100644 index 0000000..f83d374 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/socket.h @@ -0,0 +1,205 @@ +/* + * 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 TALK_BASE_SOCKET_H__ +#define TALK_BASE_SOCKET_H__ + +#include + +#ifdef POSIX +#include +#include +#include +#include +#define SOCKET_EACCES EACCES +#endif + +#ifdef WIN32 +#include "talk/base/win32.h" +#endif + +#include "talk/base/basictypes.h" +#include "talk/base/socketaddress.h" + +// Rather than converting errors into a private namespace, +// Reuse the POSIX socket api errors. Note this depends on +// Win32 compatibility. + +#ifdef WIN32 +#undef EWOULDBLOCK // Remove errno.h's definition for each macro below. +#define EWOULDBLOCK WSAEWOULDBLOCK +#undef EINPROGRESS +#define EINPROGRESS WSAEINPROGRESS +#undef EALREADY +#define EALREADY WSAEALREADY +#undef ENOTSOCK +#define ENOTSOCK WSAENOTSOCK +#undef EDESTADDRREQ +#define EDESTADDRREQ WSAEDESTADDRREQ +#undef EMSGSIZE +#define EMSGSIZE WSAEMSGSIZE +#undef EPROTOTYPE +#define EPROTOTYPE WSAEPROTOTYPE +#undef ENOPROTOOPT +#define ENOPROTOOPT WSAENOPROTOOPT +#undef EPROTONOSUPPORT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#undef ESOCKTNOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#undef EOPNOTSUPP +#define EOPNOTSUPP WSAEOPNOTSUPP +#undef EPFNOSUPPORT +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#undef EAFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#undef EADDRINUSE +#define EADDRINUSE WSAEADDRINUSE +#undef EADDRNOTAVAIL +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#undef ENETDOWN +#define ENETDOWN WSAENETDOWN +#undef ENETUNREACH +#define ENETUNREACH WSAENETUNREACH +#undef ENETRESET +#define ENETRESET WSAENETRESET +#undef ECONNABORTED +#define ECONNABORTED WSAECONNABORTED +#undef ECONNRESET +#define ECONNRESET WSAECONNRESET +#undef ENOBUFS +#define ENOBUFS WSAENOBUFS +#undef EISCONN +#define EISCONN WSAEISCONN +#undef ENOTCONN +#define ENOTCONN WSAENOTCONN +#undef ESHUTDOWN +#define ESHUTDOWN WSAESHUTDOWN +#undef ETOOMANYREFS +#define ETOOMANYREFS WSAETOOMANYREFS +#undef ETIMEDOUT +#define ETIMEDOUT WSAETIMEDOUT +#undef ECONNREFUSED +#define ECONNREFUSED WSAECONNREFUSED +#undef ELOOP +#define ELOOP WSAELOOP +#undef ENAMETOOLONG +#define ENAMETOOLONG WSAENAMETOOLONG +#undef EHOSTDOWN +#define EHOSTDOWN WSAEHOSTDOWN +#undef EHOSTUNREACH +#define EHOSTUNREACH WSAEHOSTUNREACH +#undef ENOTEMPTY +#define ENOTEMPTY WSAENOTEMPTY +#undef EPROCLIM +#define EPROCLIM WSAEPROCLIM +#undef EUSERS +#define EUSERS WSAEUSERS +#undef EDQUOT +#define EDQUOT WSAEDQUOT +#undef ESTALE +#define ESTALE WSAESTALE +#undef EREMOTE +#define EREMOTE WSAEREMOTE +#undef EACCES +#define SOCKET_EACCES WSAEACCES +#endif // WIN32 + +#ifdef POSIX +#define INVALID_SOCKET (-1) +#define SOCKET_ERROR (-1) +#define closesocket(s) close(s) +#endif // POSIX + +namespace talk_base { + +inline bool IsBlockingError(int e) { + return (e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS); +} + +// General interface for the socket implementations of various networks. The +// methods match those of normal UNIX sockets very closely. +class Socket { + public: + virtual ~Socket() {} + + // Returns the address to which the socket is bound. If the socket is not + // bound, then the any-address is returned. + virtual SocketAddress GetLocalAddress() const = 0; + + // Returns the address to which the socket is connected. If the socket is + // not connected, then the any-address is returned. + virtual SocketAddress GetRemoteAddress() const = 0; + + virtual int Bind(const SocketAddress& addr) = 0; + virtual int Connect(const SocketAddress& addr) = 0; + virtual int Send(const void *pv, size_t cb) = 0; + virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) = 0; + virtual int Recv(void *pv, size_t cb) = 0; + virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) = 0; + virtual int Listen(int backlog) = 0; + virtual Socket *Accept(SocketAddress *paddr) = 0; + virtual int Close() = 0; + virtual int GetError() const = 0; + virtual void SetError(int error) = 0; + inline bool IsBlocking() const { return IsBlockingError(GetError()); } + + enum ConnState { + CS_CLOSED, + CS_CONNECTING, + CS_CONNECTED + }; + virtual ConnState GetState() const = 0; + + // Fills in the given uint16 with the current estimate of the MTU along the + // path to the address to which this socket is connected. NOTE: This method + // can block for up to 10 seconds on Windows. + virtual int EstimateMTU(uint16* mtu) = 0; + + enum Option { + OPT_DONTFRAGMENT, + OPT_RCVBUF, // receive buffer size + 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_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; + + protected: + Socket() {} + + private: + DISALLOW_EVIL_CONSTRUCTORS(Socket); +}; + +} // namespace talk_base + +#endif // TALK_BASE_SOCKET_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/socket_unittest.h b/thirdparties/common/include/webrtc-sdk/talk/base/socket_unittest.h new file mode 100644 index 0000000..e054fb2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/socket_unittest.h @@ -0,0 +1,105 @@ +/* + * libjingle + * Copyright 2009, 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_SOCKET_UNITTEST_H_ +#define TALK_BASE_SOCKET_UNITTEST_H_ + +#include "talk/base/gunit.h" +#include "talk/base/thread.h" + +namespace talk_base { + +// Generic socket tests, to be used when testing individual socketservers. +// Derive your specific test class from SocketTest, install your +// socketserver, and call the SocketTest test methods. +class SocketTest : public testing::Test { + protected: + SocketTest() : ss_(NULL), kIPv4Loopback(INADDR_LOOPBACK), + kIPv6Loopback(in6addr_loopback) {} + virtual void SetUp() { ss_ = Thread::Current()->socketserver(); } + void TestConnectIPv4(); + void TestConnectIPv6(); + void TestConnectWithDnsLookupIPv4(); + void TestConnectWithDnsLookupIPv6(); + void TestConnectFailIPv4(); + void TestConnectFailIPv6(); + void TestConnectWithDnsLookupFailIPv4(); + void TestConnectWithDnsLookupFailIPv6(); + void TestConnectWithClosedSocketIPv4(); + void TestConnectWithClosedSocketIPv6(); + void TestConnectWhileNotClosedIPv4(); + void TestConnectWhileNotClosedIPv6(); + void TestServerCloseDuringConnectIPv4(); + void TestServerCloseDuringConnectIPv6(); + void TestClientCloseDuringConnectIPv4(); + void TestClientCloseDuringConnectIPv6(); + void TestServerCloseIPv4(); + void TestServerCloseIPv6(); + void TestCloseInClosedCallbackIPv4(); + void TestCloseInClosedCallbackIPv6(); + void TestSocketServerWaitIPv4(); + void TestSocketServerWaitIPv6(); + void TestTcpIPv4(); + void TestTcpIPv6(); + void TestSingleFlowControlCallbackIPv4(); + void TestSingleFlowControlCallbackIPv6(); + void TestUdpIPv4(); + void TestUdpIPv6(); + void TestUdpReadyToSendIPv4(); + void TestUdpReadyToSendIPv6(); + void TestGetSetOptionsIPv4(); + void TestGetSetOptionsIPv6(); + + private: + void ConnectInternal(const IPAddress& loopback); + void ConnectWithDnsLookupInternal(const IPAddress& loopback, + const std::string& host); + void ConnectFailInternal(const IPAddress& loopback); + + void ConnectWithDnsLookupFailInternal(const IPAddress& loopback); + void ConnectWithClosedSocketInternal(const IPAddress& loopback); + void ConnectWhileNotClosedInternal(const IPAddress& loopback); + void ServerCloseDuringConnectInternal(const IPAddress& loopback); + void ClientCloseDuringConnectInternal(const IPAddress& loopback); + void ServerCloseInternal(const IPAddress& loopback); + void CloseInClosedCallbackInternal(const IPAddress& loopback); + void SocketServerWaitInternal(const IPAddress& loopback); + void TcpInternal(const IPAddress& loopback); + void SingleFlowControlCallbackInternal(const IPAddress& loopback); + void UdpInternal(const IPAddress& loopback); + void UdpReadyToSend(const IPAddress& loopback); + void GetSetOptionsInternal(const IPAddress& loopback); + + static const int kTimeout = 5000; // ms + SocketServer* ss_; + const IPAddress kIPv4Loopback; + const IPAddress kIPv6Loopback; +}; + +} // namespace talk_base + +#endif // TALK_BASE_SOCKET_UNITTEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/socketadapters.h b/thirdparties/common/include/webrtc-sdk/talk/base/socketadapters.h new file mode 100644 index 0000000..021c628 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/socketadapters.h @@ -0,0 +1,261 @@ +/* + * 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 TALK_BASE_SOCKETADAPTERS_H_ +#define TALK_BASE_SOCKETADAPTERS_H_ + +#include +#include + +#include "talk/base/asyncsocket.h" +#include "talk/base/cryptstring.h" +#include "talk/base/logging.h" + +namespace talk_base { + +struct HttpAuthContext; +class ByteBuffer; + +/////////////////////////////////////////////////////////////////////////////// + +// Implements a socket adapter that can buffer and process data internally, +// as in the case of connecting to a proxy, where you must speak the proxy +// protocol before commencing normal socket behavior. +class BufferedReadAdapter : public AsyncSocketAdapter { + public: + BufferedReadAdapter(AsyncSocket* socket, size_t buffer_size); + virtual ~BufferedReadAdapter(); + + virtual int Send(const void* pv, size_t cb); + virtual int Recv(void* pv, size_t cb); + + protected: + int DirectSend(const void* pv, size_t cb) { + return AsyncSocketAdapter::Send(pv, cb); + } + + void BufferInput(bool on = true); + virtual void ProcessInput(char* data, size_t* len) = 0; + + virtual void OnReadEvent(AsyncSocket * socket); + + private: + char * buffer_; + size_t buffer_size_, data_len_; + bool buffering_; + DISALLOW_EVIL_CONSTRUCTORS(BufferedReadAdapter); +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Interface for implementing proxy server sockets. +class AsyncProxyServerSocket : public BufferedReadAdapter { + public: + AsyncProxyServerSocket(AsyncSocket* socket, size_t buffer_size) + : BufferedReadAdapter(socket, buffer_size) {} + sigslot::signal2 SignalConnectRequest; + virtual void SendConnectResult(int err, const SocketAddress& addr) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Implements a socket adapter that performs the client side of a +// fake SSL handshake. Used for "ssltcp" P2P functionality. +class AsyncSSLSocket : public BufferedReadAdapter { + public: + explicit AsyncSSLSocket(AsyncSocket* socket); + + virtual int Connect(const SocketAddress& addr); + + protected: + virtual void OnConnectEvent(AsyncSocket* socket); + virtual void ProcessInput(char* data, size_t* len); + DISALLOW_EVIL_CONSTRUCTORS(AsyncSSLSocket); +}; + +// Implements a socket adapter that performs the server side of a +// fake SSL handshake. Used when implementing a relay server that does "ssltcp". +class AsyncSSLServerSocket : public BufferedReadAdapter { + public: + explicit AsyncSSLServerSocket(AsyncSocket* socket); + + protected: + virtual void ProcessInput(char* data, size_t* len); + DISALLOW_EVIL_CONSTRUCTORS(AsyncSSLServerSocket); +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Implements a socket adapter that speaks the HTTP/S proxy protocol. +class AsyncHttpsProxySocket : public BufferedReadAdapter { + public: + AsyncHttpsProxySocket(AsyncSocket* socket, const std::string& user_agent, + const SocketAddress& proxy, + const std::string& username, const CryptString& password); + virtual ~AsyncHttpsProxySocket(); + + // If connect is forced, the adapter will always issue an HTTP CONNECT to the + // target address. Otherwise, it will connect only if the destination port + // is not port 80. + void SetForceConnect(bool force) { force_connect_ = force; } + + virtual int Connect(const SocketAddress& addr); + virtual SocketAddress GetRemoteAddress() const; + virtual int Close(); + virtual ConnState GetState() const; + + protected: + virtual void OnConnectEvent(AsyncSocket* socket); + virtual void OnCloseEvent(AsyncSocket* socket, int err); + virtual void ProcessInput(char* data, size_t* len); + + bool ShouldIssueConnect() const; + void SendRequest(); + void ProcessLine(char* data, size_t len); + void EndResponse(); + void Error(int error); + + private: + SocketAddress proxy_, dest_; + std::string agent_, user_, headers_; + CryptString pass_; + bool force_connect_; + size_t content_length_; + int defer_error_; + bool expect_close_; + enum ProxyState { + PS_INIT, PS_LEADER, PS_AUTHENTICATE, PS_SKIP_HEADERS, PS_ERROR_HEADERS, + PS_TUNNEL_HEADERS, PS_SKIP_BODY, PS_TUNNEL, PS_WAIT_CLOSE, PS_ERROR + } state_; + HttpAuthContext * context_; + std::string unknown_mechanisms_; + DISALLOW_EVIL_CONSTRUCTORS(AsyncHttpsProxySocket); +}; + +/* TODO: Implement this. +class AsyncHttpsProxyServerSocket : public AsyncProxyServerSocket { + public: + explicit AsyncHttpsProxyServerSocket(AsyncSocket* socket); + + private: + virtual void ProcessInput(char * data, size_t& len); + void Error(int error); + DISALLOW_EVIL_CONSTRUCTORS(AsyncHttpsProxyServerSocket); +}; +*/ + +/////////////////////////////////////////////////////////////////////////////// + +// Implements a socket adapter that speaks the SOCKS proxy protocol. +class AsyncSocksProxySocket : public BufferedReadAdapter { + public: + AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy, + const std::string& username, const CryptString& password); + + virtual int Connect(const SocketAddress& addr); + virtual SocketAddress GetRemoteAddress() const; + virtual int Close(); + virtual ConnState GetState() const; + + protected: + virtual void OnConnectEvent(AsyncSocket* socket); + virtual void ProcessInput(char* data, size_t* len); + + void SendHello(); + void SendConnect(); + void SendAuth(); + void Error(int error); + + private: + enum State { + SS_INIT, SS_HELLO, SS_AUTH, SS_CONNECT, SS_TUNNEL, SS_ERROR + }; + State state_; + SocketAddress proxy_, dest_; + std::string user_; + CryptString pass_; + DISALLOW_EVIL_CONSTRUCTORS(AsyncSocksProxySocket); +}; + +// Implements a proxy server socket for the SOCKS protocol. +class AsyncSocksProxyServerSocket : public AsyncProxyServerSocket { + public: + explicit AsyncSocksProxyServerSocket(AsyncSocket* socket); + + private: + virtual void ProcessInput(char* data, size_t* len); + void DirectSend(const ByteBuffer& buf); + + void HandleHello(ByteBuffer* request); + void SendHelloReply(int method); + void HandleAuth(ByteBuffer* request); + void SendAuthReply(int result); + void HandleConnect(ByteBuffer* request); + virtual void SendConnectResult(int result, const SocketAddress& addr); + + void Error(int error); + + static const int kBufferSize = 1024; + enum State { + SS_HELLO, SS_AUTH, SS_CONNECT, SS_CONNECT_PENDING, SS_TUNNEL, SS_ERROR + }; + State state_; + DISALLOW_EVIL_CONSTRUCTORS(AsyncSocksProxyServerSocket); +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Implements a socket adapter that logs everything that it sends and receives. +class LoggingSocketAdapter : public AsyncSocketAdapter { + public: + LoggingSocketAdapter(AsyncSocket* socket, LoggingSeverity level, + const char * label, bool hex_mode = false); + + virtual int Send(const void *pv, size_t cb); + virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr); + virtual int Recv(void *pv, size_t cb); + virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr); + virtual int Close(); + + protected: + virtual void OnConnectEvent(AsyncSocket * socket); + virtual void OnCloseEvent(AsyncSocket * socket, int err); + + private: + LoggingSeverity level_; + std::string label_; + bool hex_mode_; + LogMultilineState lms_; + DISALLOW_EVIL_CONSTRUCTORS(LoggingSocketAdapter); +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_SOCKETADAPTERS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/socketaddress.h b/thirdparties/common/include/webrtc-sdk/talk/base/socketaddress.h new file mode 100644 index 0000000..6f8d21d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/socketaddress.h @@ -0,0 +1,231 @@ +/* + * 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 TALK_BASE_SOCKETADDRESS_H_ +#define TALK_BASE_SOCKETADDRESS_H_ + +#include +#include +#include +#include "talk/base/basictypes.h" +#include "talk/base/ipaddress.h" + +#undef SetPort + +struct sockaddr_in; +struct sockaddr_storage; + +namespace talk_base { + +// Records an IP address and port. +class SocketAddress { + public: + // Creates a nil address. + SocketAddress(); + + // Creates the address with the given host and port. Host may be a + // literal IP string or a hostname to be resolved later. + SocketAddress(const std::string& hostname, int port); + + // Creates the address with the given IP and port. + // IP is given as an integer in host byte order. V4 only, to be deprecated. + SocketAddress(uint32 ip_as_host_order_integer, int port); + + // Creates the address with the given IP and port. + SocketAddress(const IPAddress& ip, int port); + + // Creates a copy of the given address. + SocketAddress(const SocketAddress& addr); + + // Resets to the nil address. + void Clear(); + + // Determines if this is a nil address (empty hostname, any IP, null port) + bool IsNil() const; + + // Returns true if ip and port are set. + bool IsComplete() const; + + // Replaces our address with the given one. + SocketAddress& operator=(const SocketAddress& addr); + + // Changes the IP of this address to the given one, and clears the hostname + // IP is given as an integer in host byte order. V4 only, to be deprecated.. + void SetIP(uint32 ip_as_host_order_integer); + + // Changes the IP of this address to the given one, and clears the hostname. + void SetIP(const IPAddress& ip); + + // Changes the hostname of this address to the given one. + // Does not resolve the address; use Resolve to do so. + void SetIP(const std::string& hostname); + + // Sets the IP address while retaining the hostname. Useful for bypassing + // DNS for a pre-resolved IP. + // IP is given as an integer in host byte order. V4 only, to be deprecated. + void SetResolvedIP(uint32 ip_as_host_order_integer); + + // Sets the IP address while retaining the hostname. Useful for bypassing + // DNS for a pre-resolved IP. + void SetResolvedIP(const IPAddress& ip); + + // Changes the port of this address to the given one. + void SetPort(int port); + + // Returns the hostname. + const std::string& hostname() const { return hostname_; } + + // Returns the IP address as a host byte order integer. + // Returns 0 for non-v4 addresses. + uint32 ip() const; + + const IPAddress& ipaddr() const; + + int family() const {return ip_.family(); } + + // Returns the port part of this address. + uint16 port() const; + + // Returns the scope ID associated with this address. Scope IDs are a + // necessary addition to IPv6 link-local addresses, with different network + // interfaces having different scope-ids for their link-local addresses. + // IPv4 address do not have scope_ids and sockaddr_in structures do not have + // a field for them. + int scope_id() const {return scope_id_; } + void SetScopeID(int id) { scope_id_ = id; } + + // Returns the 'host' portion of the address (hostname or IP) in a form + // suitable for use in a URI. If both IP and hostname are present, hostname + // is preferred. IPv6 addresses are enclosed in square brackets ('[' and ']'). + std::string HostAsURIString() const; + + // Same as HostAsURIString but anonymizes IP addresses by hiding the last + // part. + std::string HostAsSensitiveURIString() const; + + // Returns the port as a string. + std::string PortAsString() const; + + // Returns hostname:port or [hostname]:port. + std::string ToString() const; + + // Same as ToString but anonymizes it by hiding the last part. + std::string ToSensitiveString() const; + + // Parses hostname:port and [hostname]:port. + bool FromString(const std::string& str); + + friend std::ostream& operator<<(std::ostream& os, const SocketAddress& addr); + + // Determines whether this represents a missing / any IP address. + // That is, 0.0.0.0 or ::. + // Hostname and/or port may be set. + bool IsAnyIP() const; + inline bool IsAny() const { return IsAnyIP(); } // deprecated + + // Determines whether the IP address refers to a loopback address. + // For v4 addresses this means the address is in the range 127.0.0.0/8. + // For v6 addresses this means the address is ::1. + bool IsLoopbackIP() const; + + // Determines whether the IP address is in one of the private ranges: + // For v4: 127.0.0.0/8 10.0.0.0/8 192.168.0.0/16 172.16.0.0/12. + // For v6: FE80::/16 and ::1. + bool IsPrivateIP() const; + + // Determines whether the hostname has been resolved to an IP. + bool IsUnresolvedIP() const; + inline bool IsUnresolved() const { return IsUnresolvedIP(); } // deprecated + + // Determines whether this address is identical to the given one. + bool operator ==(const SocketAddress& addr) const; + inline bool operator !=(const SocketAddress& addr) const { + return !this->operator ==(addr); + } + + // Compares based on IP and then port. + bool operator <(const SocketAddress& addr) const; + + // Determines whether this address has the same IP as the one given. + bool EqualIPs(const SocketAddress& addr) const; + + // Determines whether this address has the same port as the one given. + bool EqualPorts(const SocketAddress& addr) const; + + // Hashes this address into a small number. + size_t Hash() const; + + // Write this address to a sockaddr_in. + // If IPv6, will zero out the sockaddr_in and sets family to AF_UNSPEC. + void ToSockAddr(sockaddr_in* saddr) const; + + // Read this address from a sockaddr_in. + bool FromSockAddr(const sockaddr_in& saddr); + + // Read and write the address to/from a sockaddr_storage. + // Dual stack version always sets family to AF_INET6, and maps v4 addresses. + // The other version doesn't map, and outputs an AF_INET address for + // v4 or mapped addresses, and AF_INET6 addresses for others. + // Returns the size of the sockaddr_in or sockaddr_in6 structure that is + // written to the sockaddr_storage, or zero on failure. + size_t ToDualStackSockAddrStorage(sockaddr_storage* saddr) const; + size_t ToSockAddrStorage(sockaddr_storage* saddr) const; + + // Converts the IP address given in 'compact form' into dotted form. + // IP is given as an integer in host byte order. V4 only, to be deprecated. + // TODO: Deprecate this. + static std::string IPToString(uint32 ip_as_host_order_integer); + + // Same as IPToString but anonymizes it by hiding the last part. + // TODO: Deprecate this. + static std::string IPToSensitiveString(uint32 ip_as_host_order_integer); + + // Converts the IP address given in dotted form into compact form. + // Only dotted names (A.B.C.D) are converted. + // Output integer is returned in host byte order. + // TODO: Deprecate, replace wth agnostic versions. + static bool StringToIP(const std::string& str, uint32* ip); + static uint32 StringToIP(const std::string& str); + + // Converts the IP address given in printable form into an IPAddress. + static bool StringToIP(const std::string& str, IPAddress* ip); + + private: + std::string hostname_; + IPAddress ip_; + uint16 port_; + int scope_id_; + bool literal_; // Indicates that 'hostname_' contains a literal IP string. +}; + +bool SocketAddressFromSockAddrStorage(const sockaddr_storage& saddr, + SocketAddress* out); +SocketAddress EmptySocketAddressWithFamily(int family); + +} // namespace talk_base + +#endif // TALK_BASE_SOCKETADDRESS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/socketaddresspair.h b/thirdparties/common/include/webrtc-sdk/talk/base/socketaddresspair.h new file mode 100644 index 0000000..adea0b7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/socketaddresspair.h @@ -0,0 +1,58 @@ +/* + * 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 TALK_BASE_SOCKETADDRESSPAIR_H__ +#define TALK_BASE_SOCKETADDRESSPAIR_H__ + +#include "talk/base/socketaddress.h" + +namespace talk_base { + +// Records a pair (source,destination) of socket addresses. The two addresses +// identify a connection between two machines. (For UDP, this "connection" is +// not maintained explicitly in a socket.) +class SocketAddressPair { +public: + SocketAddressPair() {} + SocketAddressPair(const SocketAddress& srs, const SocketAddress& dest); + + const SocketAddress& source() const { return src_; } + const SocketAddress& destination() const { return dest_; } + + bool operator ==(const SocketAddressPair& r) const; + bool operator <(const SocketAddressPair& r) const; + + size_t Hash() const; + +private: + SocketAddress src_; + SocketAddress dest_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_SOCKETADDRESSPAIR_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/socketfactory.h b/thirdparties/common/include/webrtc-sdk/talk/base/socketfactory.h new file mode 100644 index 0000000..4be2dd9 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/socketfactory.h @@ -0,0 +1,55 @@ +/* + * 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 TALK_BASE_SOCKETFACTORY_H__ +#define TALK_BASE_SOCKETFACTORY_H__ + +#include "talk/base/socket.h" +#include "talk/base/asyncsocket.h" + +namespace talk_base { + +class SocketFactory { +public: + virtual ~SocketFactory() {} + + // Returns a new socket for blocking communication. The type can be + // SOCK_DGRAM and SOCK_STREAM. + // TODO: C++ inheritance rules mean that all users must have both + // CreateSocket(int) and CreateSocket(int,int). Will remove CreateSocket(int) + // (and CreateAsyncSocket(int) when all callers are changed. + virtual Socket* CreateSocket(int type) = 0; + virtual Socket* CreateSocket(int family, int type) = 0; + // Returns a new socket for nonblocking communication. The type can be + // SOCK_DGRAM and SOCK_STREAM. + virtual AsyncSocket* CreateAsyncSocket(int type) = 0; + virtual AsyncSocket* CreateAsyncSocket(int family, int type) = 0; +}; + +} // namespace talk_base + +#endif // TALK_BASE_SOCKETFACTORY_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/socketpool.h b/thirdparties/common/include/webrtc-sdk/talk/base/socketpool.h new file mode 100644 index 0000000..def41e4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/socketpool.h @@ -0,0 +1,160 @@ +/* + * 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 TALK_BASE_SOCKETPOOL_H_ +#define TALK_BASE_SOCKETPOOL_H_ + +#include +#include +#include "talk/base/logging.h" +#include "talk/base/sigslot.h" +#include "talk/base/socketaddress.h" + +namespace talk_base { + +class AsyncSocket; +class LoggingAdapter; +class SocketFactory; +class SocketStream; +class StreamInterface; + +////////////////////////////////////////////////////////////////////// +// StreamPool +////////////////////////////////////////////////////////////////////// + +class StreamPool { +public: + virtual ~StreamPool() { } + + virtual StreamInterface* RequestConnectedStream(const SocketAddress& remote, + int* err) = 0; + virtual void ReturnConnectedStream(StreamInterface* stream) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamCache - Caches a set of open streams, defers creation/destruction to +// the supplied StreamPool. +/////////////////////////////////////////////////////////////////////////////// + +class StreamCache : public StreamPool, public sigslot::has_slots<> { +public: + StreamCache(StreamPool* pool); + virtual ~StreamCache(); + + // StreamPool Interface + virtual StreamInterface* RequestConnectedStream(const SocketAddress& remote, + int* err); + virtual void ReturnConnectedStream(StreamInterface* stream); + +private: + typedef std::pair ConnectedStream; + typedef std::list ConnectedList; + + void OnStreamEvent(StreamInterface* stream, int events, int err); + + // We delegate stream creation and deletion to this pool. + StreamPool* pool_; + // Streams that are in use (returned from RequestConnectedStream). + ConnectedList active_; + // Streams which were returned to us, but are still open. + ConnectedList cached_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// NewSocketPool +// Creates a new stream on every request +/////////////////////////////////////////////////////////////////////////////// + +class NewSocketPool : public StreamPool { +public: + NewSocketPool(SocketFactory* factory); + virtual ~NewSocketPool(); + + // StreamPool Interface + virtual StreamInterface* RequestConnectedStream(const SocketAddress& remote, + int* err); + virtual void ReturnConnectedStream(StreamInterface* stream); + +private: + SocketFactory* factory_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// ReuseSocketPool +// Maintains a single socket at a time, and will reuse it without closing if +// the destination address is the same. +/////////////////////////////////////////////////////////////////////////////// + +class ReuseSocketPool : public StreamPool, public sigslot::has_slots<> { +public: + ReuseSocketPool(SocketFactory* factory); + virtual ~ReuseSocketPool(); + + // StreamPool Interface + virtual StreamInterface* RequestConnectedStream(const SocketAddress& remote, + int* err); + virtual void ReturnConnectedStream(StreamInterface* stream); + +private: + void OnStreamEvent(StreamInterface* stream, int events, int err); + + SocketFactory* factory_; + SocketStream* stream_; + SocketAddress remote_; + bool checked_out_; // Whether the stream is currently checked out +}; + +/////////////////////////////////////////////////////////////////////////////// +// LoggingPoolAdapter - Adapts a StreamPool to supply streams with attached +// LoggingAdapters. +/////////////////////////////////////////////////////////////////////////////// + +class LoggingPoolAdapter : public StreamPool { +public: + LoggingPoolAdapter(StreamPool* pool, LoggingSeverity level, + const std::string& label, bool binary_mode); + virtual ~LoggingPoolAdapter(); + + // StreamPool Interface + virtual StreamInterface* RequestConnectedStream(const SocketAddress& remote, + int* err); + virtual void ReturnConnectedStream(StreamInterface* stream); + +private: + StreamPool* pool_; + LoggingSeverity level_; + std::string label_; + bool binary_mode_; + typedef std::deque StreamList; + StreamList recycle_bin_; +}; + +////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_SOCKETPOOL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/socketserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/socketserver.h new file mode 100644 index 0000000..7fef8cd --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/socketserver.h @@ -0,0 +1,61 @@ +/* + * 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 TALK_BASE_SOCKETSERVER_H_ +#define TALK_BASE_SOCKETSERVER_H_ + +#include "talk/base/socketfactory.h" + +namespace talk_base { + +class MessageQueue; + +// Provides the ability to wait for activity on a set of sockets. The Thread +// class provides a nice wrapper on a socket server. +// +// The server is also a socket factory. The sockets it creates will be +// notified of asynchronous I/O from this server's Wait method. +class SocketServer : public SocketFactory { + public: + // When the socket server is installed into a Thread, this function is + // called to allow the socket server to use the thread's message queue for + // any messaging that it might need to perform. + virtual void SetMessageQueue(MessageQueue* queue) {} + + // Sleeps until: + // 1) cms milliseconds have elapsed (unless cms == kForever) + // 2) WakeUp() is called + // While sleeping, I/O is performed if process_io is true. + virtual bool Wait(int cms, bool process_io) = 0; + + // Causes the current wait (if one is in progress) to wake up. + virtual void WakeUp() = 0; +}; + +} // namespace talk_base + +#endif // TALK_BASE_SOCKETSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/socketstream.h b/thirdparties/common/include/webrtc-sdk/talk/base/socketstream.h new file mode 100644 index 0000000..fd0a005 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/socketstream.h @@ -0,0 +1,74 @@ +/* + * libjingle + * Copyright 2005--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. + */ + +#ifndef TALK_BASE_SOCKETSTREAM_H_ +#define TALK_BASE_SOCKETSTREAM_H_ + +#include "talk/base/asyncsocket.h" +#include "talk/base/common.h" +#include "talk/base/stream.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// + +class SocketStream : public StreamInterface, public sigslot::has_slots<> { + public: + explicit SocketStream(AsyncSocket* socket); + virtual ~SocketStream(); + + void Attach(AsyncSocket* socket); + AsyncSocket* Detach(); + + AsyncSocket* GetSocket() { return socket_; } + + virtual StreamState GetState() const; + + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + + virtual void Close(); + + private: + void OnConnectEvent(AsyncSocket* socket); + void OnReadEvent(AsyncSocket* socket); + void OnWriteEvent(AsyncSocket* socket); + void OnCloseEvent(AsyncSocket* socket, int err); + + AsyncSocket* socket_; + + DISALLOW_EVIL_CONSTRUCTORS(SocketStream); +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_SOCKETSTREAM_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/ssladapter.h b/thirdparties/common/include/webrtc-sdk/talk/base/ssladapter.h new file mode 100644 index 0000000..09813b5 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/ssladapter.h @@ -0,0 +1,78 @@ +/* + * 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 TALK_BASE_SSLADAPTER_H_ +#define TALK_BASE_SSLADAPTER_H_ + +#include "talk/base/asyncsocket.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// + +class SSLAdapter : public AsyncSocketAdapter { + public: + explicit SSLAdapter(AsyncSocket* socket) + : AsyncSocketAdapter(socket), ignore_bad_cert_(false) { } + + bool ignore_bad_cert() const { return ignore_bad_cert_; } + void set_ignore_bad_cert(bool ignore) { ignore_bad_cert_ = ignore; } + + // StartSSL returns 0 if successful. + // If StartSSL is called while the socket is closed or connecting, the SSL + // negotiation will begin as soon as the socket connects. + virtual int StartSSL(const char* hostname, bool restartable) = 0; + + // Create the default SSL adapter for this platform. On failure, returns NULL + // and deletes |socket|. Otherwise, the returned SSLAdapter takes ownership + // of |socket|. + static SSLAdapter* Create(AsyncSocket* socket); + + private: + // If true, the server certificate need not match the configured hostname. + bool ignore_bad_cert_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +typedef bool (*VerificationCallback)(void* cert); + +// Call this on the main thread, before using SSL. +// Call CleanupSSLThread when finished with SSL. +bool InitializeSSL(VerificationCallback callback = NULL); + +// Call to initialize additional threads. +bool InitializeSSLThread(); + +// Call to cleanup additional threads, and also the main thread. +bool CleanupSSL(); + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_SSLADAPTER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sslconfig.h b/thirdparties/common/include/webrtc-sdk/talk/base/sslconfig.h new file mode 100644 index 0000000..f926e8c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sslconfig.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_SSLCONFIG_H_ +#define TALK_BASE_SSLCONFIG_H_ + +// If no preference has been indicated, default to SChannel on Windows and +// OpenSSL everywhere else, if it is available. +#if !defined(SSL_USE_SCHANNEL) && !defined(SSL_USE_OPENSSL) && \ + !defined(SSL_USE_NSS) +#if defined(WIN32) + +#define SSL_USE_SCHANNEL 1 + +#else // defined(WIN32) + +#if defined(HAVE_OPENSSL_SSL_H) +#define SSL_USE_OPENSSL 1 +#elif defined(HAVE_NSS_SSL_H) +#define SSL_USE_NSS 1 +#endif + +#endif // !defined(WIN32) +#endif + +#endif // TALK_BASE_SSLCONFIG_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sslfingerprint.h b/thirdparties/common/include/webrtc-sdk/talk/base/sslfingerprint.h new file mode 100644 index 0000000..f8978c7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sslfingerprint.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_SSLFINGERPRINT_H_ +#define TALK_BASE_SSLFINGERPRINT_H_ + +#include + +#include "talk/base/buffer.h" +#include "talk/base/sslidentity.h" + +namespace talk_base { + +class SSLCertificate; + +struct SSLFingerprint { + static SSLFingerprint* Create(const std::string& algorithm, + const talk_base::SSLIdentity* identity); + + static SSLFingerprint* Create(const std::string& algorithm, + const talk_base::SSLCertificate* cert); + + static SSLFingerprint* CreateFromRfc4572(const std::string& algorithm, + const std::string& fingerprint); + + SSLFingerprint(const std::string& algorithm, const uint8* digest_in, + 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; +}; + +} // namespace talk_base + +#endif // TALK_BASE_SSLFINGERPRINT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sslidentity.h b/thirdparties/common/include/webrtc-sdk/talk/base/sslidentity.h new file mode 100644 index 0000000..4b7d1d7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sslidentity.h @@ -0,0 +1,189 @@ +/* + * 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. + */ + +// Handling of certificates and keypairs for SSLStreamAdapter's peer mode. + +#ifndef TALK_BASE_SSLIDENTITY_H_ +#define TALK_BASE_SSLIDENTITY_H_ + +#include +#include +#include + +#include "talk/base/buffer.h" +#include "talk/base/messagedigest.h" + +namespace talk_base { + +// Forward declaration due to circular dependency with SSLCertificate. +class SSLCertChain; + +// Abstract interface overridden by SSL library specific +// implementations. + +// A somewhat opaque type used to encapsulate a certificate. +// Wraps the SSL library's notion of a certificate, with reference counting. +// The SSLCertificate object is pretty much immutable once created. +// (The OpenSSL implementation only does reference counting and +// possibly caching of intermediate results.) +class SSLCertificate { + public: + // Parses and build a certificate from a PEM encoded string. + // Returns NULL on failure. + // The length of the string representation of the certificate is + // stored in *pem_length if it is non-NULL, and only if + // parsing was successful. + // Caller is responsible for freeing the returned object. + static SSLCertificate* FromPEMString(const std::string& pem_string); + virtual ~SSLCertificate() {} + + // Returns a new SSLCertificate object instance wrapping the same + // underlying certificate, including its chain if present. + // Caller is responsible for freeing the returned object. + virtual SSLCertificate* GetReference() const = 0; + + // Provides the cert chain, or returns false. The caller owns the chain. + // The chain includes a copy of each certificate, excluding the leaf. + virtual bool GetChain(SSLCertChain** chain) const = 0; + + // Returns a PEM encoded string representation of the certificate. + virtual std::string ToPEMString() const = 0; + + // Provides a DER encoded binary representation of the certificate. + virtual void ToDER(Buffer* der_buffer) const = 0; + + // Gets the name of the digest algorithm that was used to compute this + // certificate's signature. + 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, + size_t size, + size_t* length) const = 0; +}; + +// SSLCertChain is a simple wrapper for a vector of SSLCertificates. It serves +// primarily to ensure proper memory management (especially deletion) of the +// SSLCertificate pointers. +class SSLCertChain { + public: + // These constructors copy the provided SSLCertificate(s), so the caller + // retains ownership. + explicit SSLCertChain(const std::vector& certs) { + ASSERT(!certs.empty()); + certs_.resize(certs.size()); + std::transform(certs.begin(), certs.end(), certs_.begin(), DupCert); + } + explicit SSLCertChain(const SSLCertificate* cert) { + certs_.push_back(cert->GetReference()); + } + + ~SSLCertChain() { + std::for_each(certs_.begin(), certs_.end(), DeleteCert); + } + + // Vector access methods. + size_t GetSize() const { return certs_.size(); } + + // Returns a temporary reference, only valid until the chain is destroyed. + const SSLCertificate& Get(size_t pos) const { return *(certs_[pos]); } + + // Returns a new SSLCertChain object instance wrapping the same underlying + // certificate chain. Caller is responsible for freeing the returned object. + SSLCertChain* Copy() const { + return new SSLCertChain(certs_); + } + + private: + // Helper function for duplicating a vector of certificates. + static SSLCertificate* DupCert(const SSLCertificate* cert) { + return cert->GetReference(); + } + + // Helper function for deleting a vector of certificates. + static void DeleteCert(SSLCertificate* cert) { delete cert; } + + std::vector certs_; + + 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. +class SSLIdentity { + public: + // Generates an identity (keypair and self-signed certificate). 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. + // Returns NULL on failure. + // 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); + + virtual ~SSLIdentity() {} + + // Returns a new SSLIdentity object instance wrapping the same + // identity information. + // Caller is responsible for freeing the returned object. + virtual SSLIdentity* GetReference() const = 0; + + // Returns a temporary reference to the certificate. + virtual const SSLCertificate& certificate() const = 0; + + // Helpers for parsing converting between PEM and DER format. + static bool PemToDer(const std::string& pem_type, + const std::string& pem_string, + std::string* der); + static std::string DerToPem(const std::string& pem_type, + const unsigned char* data, + size_t length); +}; + +extern const char kPemTypeCertificate[]; +extern const char kPemTypeRsaPrivateKey[]; + +} // namespace talk_base + +#endif // TALK_BASE_SSLIDENTITY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sslroots.h b/thirdparties/common/include/webrtc-sdk/talk/base/sslroots.h new file mode 100644 index 0000000..56d7c52 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sslroots.h @@ -0,0 +1,4930 @@ +// This file is the root certificates in C form that are needed to connect to +// Google. + +// It was generated with the following command line: +// > python //depot/googleclient/talk/tools/generate_sslroots.py +// //depot/google3/security/cacerts/for_connecting_to_google/roots.pem + +/* subject:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root */ +/* issuer :/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root */ + + +const unsigned char AddTrust_External_Root_certificate[1082]={ +0x30,0x82,0x04,0x36,0x30,0x82,0x03,0x1E,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,0x14, +0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,0x73, +0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41, +0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C, +0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x22,0x30,0x20, +0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20, +0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74, +0x30,0x1E,0x17,0x0D,0x30,0x30,0x30,0x35,0x33,0x30,0x31,0x30,0x34,0x38,0x33,0x38, +0x5A,0x17,0x0D,0x32,0x30,0x30,0x35,0x33,0x30,0x31,0x30,0x34,0x38,0x33,0x38,0x5A, +0x30,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31, +0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75, +0x73,0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D, +0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61, +0x6C,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x22,0x30, +0x20,0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74, +0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F, +0x74,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01, +0x01,0x00,0xB7,0xF7,0x1A,0x33,0xE6,0xF2,0x00,0x04,0x2D,0x39,0xE0,0x4E,0x5B,0xED, +0x1F,0xBC,0x6C,0x0F,0xCD,0xB5,0xFA,0x23,0xB6,0xCE,0xDE,0x9B,0x11,0x33,0x97,0xA4, +0x29,0x4C,0x7D,0x93,0x9F,0xBD,0x4A,0xBC,0x93,0xED,0x03,0x1A,0xE3,0x8F,0xCF,0xE5, +0x6D,0x50,0x5A,0xD6,0x97,0x29,0x94,0x5A,0x80,0xB0,0x49,0x7A,0xDB,0x2E,0x95,0xFD, +0xB8,0xCA,0xBF,0x37,0x38,0x2D,0x1E,0x3E,0x91,0x41,0xAD,0x70,0x56,0xC7,0xF0,0x4F, +0x3F,0xE8,0x32,0x9E,0x74,0xCA,0xC8,0x90,0x54,0xE9,0xC6,0x5F,0x0F,0x78,0x9D,0x9A, +0x40,0x3C,0x0E,0xAC,0x61,0xAA,0x5E,0x14,0x8F,0x9E,0x87,0xA1,0x6A,0x50,0xDC,0xD7, +0x9A,0x4E,0xAF,0x05,0xB3,0xA6,0x71,0x94,0x9C,0x71,0xB3,0x50,0x60,0x0A,0xC7,0x13, +0x9D,0x38,0x07,0x86,0x02,0xA8,0xE9,0xA8,0x69,0x26,0x18,0x90,0xAB,0x4C,0xB0,0x4F, +0x23,0xAB,0x3A,0x4F,0x84,0xD8,0xDF,0xCE,0x9F,0xE1,0x69,0x6F,0xBB,0xD7,0x42,0xD7, +0x6B,0x44,0xE4,0xC7,0xAD,0xEE,0x6D,0x41,0x5F,0x72,0x5A,0x71,0x08,0x37,0xB3,0x79, +0x65,0xA4,0x59,0xA0,0x94,0x37,0xF7,0x00,0x2F,0x0D,0xC2,0x92,0x72,0xDA,0xD0,0x38, +0x72,0xDB,0x14,0xA8,0x45,0xC4,0x5D,0x2A,0x7D,0xB7,0xB4,0xD6,0xC4,0xEE,0xAC,0xCD, +0x13,0x44,0xB7,0xC9,0x2B,0xDD,0x43,0x00,0x25,0xFA,0x61,0xB9,0x69,0x6A,0x58,0x23, +0x11,0xB7,0xA7,0x33,0x8F,0x56,0x75,0x59,0xF5,0xCD,0x29,0xD7,0x46,0xB7,0x0A,0x2B, +0x65,0xB6,0xD3,0x42,0x6F,0x15,0xB2,0xB8,0x7B,0xFB,0xEF,0xE9,0x5D,0x53,0xD5,0x34, +0x5A,0x27,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xDC,0x30,0x81,0xD9,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xAD,0xBD,0x98,0x7A,0x34,0xB4,0x26,0xF7, +0xFA,0xC4,0x26,0x54,0xEF,0x03,0xBD,0xE0,0x24,0xCB,0x54,0x1A,0x30,0x0B,0x06,0x03, +0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13, +0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x99,0x06,0x03,0x55, +0x1D,0x23,0x04,0x81,0x91,0x30,0x81,0x8E,0x80,0x14,0xAD,0xBD,0x98,0x7A,0x34,0xB4, +0x26,0xF7,0xFA,0xC4,0x26,0x54,0xEF,0x03,0xBD,0xE0,0x24,0xCB,0x54,0x1A,0xA1,0x73, +0xA4,0x71,0x30,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53, +0x45,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54, +0x72,0x75,0x73,0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B, +0x13,0x1D,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72, +0x6E,0x61,0x6C,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31, +0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75, +0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52, +0x6F,0x6F,0x74,0x82,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xB0,0x9B,0xE0,0x85,0x25,0xC2, +0xD6,0x23,0xE2,0x0F,0x96,0x06,0x92,0x9D,0x41,0x98,0x9C,0xD9,0x84,0x79,0x81,0xD9, +0x1E,0x5B,0x14,0x07,0x23,0x36,0x65,0x8F,0xB0,0xD8,0x77,0xBB,0xAC,0x41,0x6C,0x47, +0x60,0x83,0x51,0xB0,0xF9,0x32,0x3D,0xE7,0xFC,0xF6,0x26,0x13,0xC7,0x80,0x16,0xA5, +0xBF,0x5A,0xFC,0x87,0xCF,0x78,0x79,0x89,0x21,0x9A,0xE2,0x4C,0x07,0x0A,0x86,0x35, +0xBC,0xF2,0xDE,0x51,0xC4,0xD2,0x96,0xB7,0xDC,0x7E,0x4E,0xEE,0x70,0xFD,0x1C,0x39, +0xEB,0x0C,0x02,0x51,0x14,0x2D,0x8E,0xBD,0x16,0xE0,0xC1,0xDF,0x46,0x75,0xE7,0x24, +0xAD,0xEC,0xF4,0x42,0xB4,0x85,0x93,0x70,0x10,0x67,0xBA,0x9D,0x06,0x35,0x4A,0x18, +0xD3,0x2B,0x7A,0xCC,0x51,0x42,0xA1,0x7A,0x63,0xD1,0xE6,0xBB,0xA1,0xC5,0x2B,0xC2, +0x36,0xBE,0x13,0x0D,0xE6,0xBD,0x63,0x7E,0x79,0x7B,0xA7,0x09,0x0D,0x40,0xAB,0x6A, +0xDD,0x8F,0x8A,0xC3,0xF6,0xF6,0x8C,0x1A,0x42,0x05,0x51,0xD4,0x45,0xF5,0x9F,0xA7, +0x62,0x21,0x68,0x15,0x20,0x43,0x3C,0x99,0xE7,0x7C,0xBD,0x24,0xD8,0xA9,0x91,0x17, +0x73,0x88,0x3F,0x56,0x1B,0x31,0x38,0x18,0xB4,0x71,0x0F,0x9A,0xCD,0xC8,0x0E,0x9E, +0x8E,0x2E,0x1B,0xE1,0x8C,0x98,0x83,0xCB,0x1F,0x31,0xF1,0x44,0x4C,0xC6,0x04,0x73, +0x49,0x76,0x60,0x0F,0xC7,0xF8,0xBD,0x17,0x80,0x6B,0x2E,0xE9,0xCC,0x4C,0x0E,0x5A, +0x9A,0x79,0x0F,0x20,0x0A,0x2E,0xD5,0x9E,0x63,0x26,0x1E,0x55,0x92,0x94,0xD8,0x82, +0x17,0x5A,0x7B,0xD0,0xBC,0xC7,0x8F,0x4E,0x86,0x04, +}; + + +/* subject:/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Class 1 CA Root */ +/* issuer :/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Class 1 CA Root */ + + +const unsigned char AddTrust_Low_Value_Services_Root_certificate[1052]={ +0x30,0x82,0x04,0x18,0x30,0x82,0x03,0x00,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x65,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,0x14, +0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,0x73, +0x74,0x20,0x41,0x42,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x13,0x14,0x41, +0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77, +0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x41,0x64, +0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x31,0x20,0x43, +0x41,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E,0x17,0x0D,0x30,0x30,0x30,0x35,0x33,0x30, +0x31,0x30,0x33,0x38,0x33,0x31,0x5A,0x17,0x0D,0x32,0x30,0x30,0x35,0x33,0x30,0x31, +0x30,0x33,0x38,0x33,0x31,0x5A,0x30,0x65,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x53,0x45,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B, +0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x41,0x42,0x31,0x1D,0x30,0x1B,0x06, +0x03,0x55,0x04,0x0B,0x13,0x14,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x54, +0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03, +0x55,0x04,0x03,0x13,0x18,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x43,0x6C, +0x61,0x73,0x73,0x20,0x31,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74,0x30,0x82,0x01, +0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, +0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0x96,0x96, +0xD4,0x21,0x49,0x60,0xE2,0x6B,0xE8,0x41,0x07,0x0C,0xDE,0xC4,0xE0,0xDC,0x13,0x23, +0xCD,0xC1,0x35,0xC7,0xFB,0xD6,0x4E,0x11,0x0A,0x67,0x5E,0xF5,0x06,0x5B,0x6B,0xA5, +0x08,0x3B,0x5B,0x29,0x16,0x3A,0xE7,0x87,0xB2,0x34,0x06,0xC5,0xBC,0x05,0xA5,0x03, +0x7C,0x82,0xCB,0x29,0x10,0xAE,0xE1,0x88,0x81,0xBD,0xD6,0x9E,0xD3,0xFE,0x2D,0x56, +0xC1,0x15,0xCE,0xE3,0x26,0x9D,0x15,0x2E,0x10,0xFB,0x06,0x8F,0x30,0x04,0xDE,0xA7, +0xB4,0x63,0xB4,0xFF,0xB1,0x9C,0xAE,0x3C,0xAF,0x77,0xB6,0x56,0xC5,0xB5,0xAB,0xA2, +0xE9,0x69,0x3A,0x3D,0x0E,0x33,0x79,0x32,0x3F,0x70,0x82,0x92,0x99,0x61,0x6D,0x8D, +0x30,0x08,0x8F,0x71,0x3F,0xA6,0x48,0x57,0x19,0xF8,0x25,0xDC,0x4B,0x66,0x5C,0xA5, +0x74,0x8F,0x98,0xAE,0xC8,0xF9,0xC0,0x06,0x22,0xE7,0xAC,0x73,0xDF,0xA5,0x2E,0xFB, +0x52,0xDC,0xB1,0x15,0x65,0x20,0xFA,0x35,0x66,0x69,0xDE,0xDF,0x2C,0xF1,0x6E,0xBC, +0x30,0xDB,0x2C,0x24,0x12,0xDB,0xEB,0x35,0x35,0x68,0x90,0xCB,0x00,0xB0,0x97,0x21, +0x3D,0x74,0x21,0x23,0x65,0x34,0x2B,0xBB,0x78,0x59,0xA3,0xD6,0xE1,0x76,0x39,0x9A, +0xA4,0x49,0x8E,0x8C,0x74,0xAF,0x6E,0xA4,0x9A,0xA3,0xD9,0x9B,0xD2,0x38,0x5C,0x9B, +0xA2,0x18,0xCC,0x75,0x23,0x84,0xBE,0xEB,0xE2,0x4D,0x33,0x71,0x8E,0x1A,0xF0,0xC2, +0xF8,0xC7,0x1D,0xA2,0xAD,0x03,0x97,0x2C,0xF8,0xCF,0x25,0xC6,0xF6,0xB8,0x24,0x31, +0xB1,0x63,0x5D,0x92,0x7F,0x63,0xF0,0x25,0xC9,0x53,0x2E,0x1F,0xBF,0x4D,0x02,0x03, +0x01,0x00,0x01,0xA3,0x81,0xD2,0x30,0x81,0xCF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E, +0x04,0x16,0x04,0x14,0x95,0xB1,0xB4,0xF0,0x94,0xB6,0xBD,0xC7,0xDA,0xD1,0x11,0x09, +0x21,0xBE,0xC1,0xAF,0x49,0xFD,0x10,0x7B,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04, +0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x8F,0x06,0x03,0x55,0x1D,0x23,0x04,0x81, +0x87,0x30,0x81,0x84,0x80,0x14,0x95,0xB1,0xB4,0xF0,0x94,0xB6,0xBD,0xC7,0xDA,0xD1, +0x11,0x09,0x21,0xBE,0xC1,0xAF,0x49,0xFD,0x10,0x7B,0xA1,0x69,0xA4,0x67,0x30,0x65, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,0x14,0x30, +0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74, +0x20,0x41,0x42,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x13,0x14,0x41,0x64, +0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F, +0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x41,0x64,0x64, +0x54,0x72,0x75,0x73,0x74,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x31,0x20,0x43,0x41, +0x20,0x52,0x6F,0x6F,0x74,0x82,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x2C,0x6D,0x64,0x1B, +0x1F,0xCD,0x0D,0xDD,0xB9,0x01,0xFA,0x96,0x63,0x34,0x32,0x48,0x47,0x99,0xAE,0x97, +0xED,0xFD,0x72,0x16,0xA6,0x73,0x47,0x5A,0xF4,0xEB,0xDD,0xE9,0xF5,0xD6,0xFB,0x45, +0xCC,0x29,0x89,0x44,0x5D,0xBF,0x46,0x39,0x3D,0xE8,0xEE,0xBC,0x4D,0x54,0x86,0x1E, +0x1D,0x6C,0xE3,0x17,0x27,0x43,0xE1,0x89,0x56,0x2B,0xA9,0x6F,0x72,0x4E,0x49,0x33, +0xE3,0x72,0x7C,0x2A,0x23,0x9A,0xBC,0x3E,0xFF,0x28,0x2A,0xED,0xA3,0xFF,0x1C,0x23, +0xBA,0x43,0x57,0x09,0x67,0x4D,0x4B,0x62,0x06,0x2D,0xF8,0xFF,0x6C,0x9D,0x60,0x1E, +0xD8,0x1C,0x4B,0x7D,0xB5,0x31,0x2F,0xD9,0xD0,0x7C,0x5D,0xF8,0xDE,0x6B,0x83,0x18, +0x78,0x37,0x57,0x2F,0xE8,0x33,0x07,0x67,0xDF,0x1E,0xC7,0x6B,0x2A,0x95,0x76,0xAE, +0x8F,0x57,0xA3,0xF0,0xF4,0x52,0xB4,0xA9,0x53,0x08,0xCF,0xE0,0x4F,0xD3,0x7A,0x53, +0x8B,0xFD,0xBB,0x1C,0x56,0x36,0xF2,0xFE,0xB2,0xB6,0xE5,0x76,0xBB,0xD5,0x22,0x65, +0xA7,0x3F,0xFE,0xD1,0x66,0xAD,0x0B,0xBC,0x6B,0x99,0x86,0xEF,0x3F,0x7D,0xF3,0x18, +0x32,0xCA,0x7B,0xC6,0xE3,0xAB,0x64,0x46,0x95,0xF8,0x26,0x69,0xD9,0x55,0x83,0x7B, +0x2C,0x96,0x07,0xFF,0x59,0x2C,0x44,0xA3,0xC6,0xE5,0xE9,0xA9,0xDC,0xA1,0x63,0x80, +0x5A,0x21,0x5E,0x21,0xCF,0x53,0x54,0xF0,0xBA,0x6F,0x89,0xDB,0xA8,0xAA,0x95,0xCF, +0x8B,0xE3,0x71,0xCC,0x1E,0x1B,0x20,0x44,0x08,0xC0,0x7A,0xB6,0x40,0xFD,0xC4,0xE4, +0x35,0xE1,0x1D,0x16,0x1C,0xD0,0xBC,0x2B,0x8E,0xD6,0x71,0xD9, +}; + + +/* subject:/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Public CA Root */ +/* issuer :/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Public CA Root */ + + +const unsigned char AddTrust_Public_Services_Root_certificate[1049]={ +0x30,0x82,0x04,0x15,0x30,0x82,0x02,0xFD,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x64,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,0x14, +0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,0x73, +0x74,0x20,0x41,0x42,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x13,0x14,0x41, +0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77, +0x6F,0x72,0x6B,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x41,0x64, +0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x43,0x41, +0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E,0x17,0x0D,0x30,0x30,0x30,0x35,0x33,0x30,0x31, +0x30,0x34,0x31,0x35,0x30,0x5A,0x17,0x0D,0x32,0x30,0x30,0x35,0x33,0x30,0x31,0x30, +0x34,0x31,0x35,0x30,0x5A,0x30,0x64,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x53,0x45,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41, +0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x41,0x42,0x31,0x1D,0x30,0x1B,0x06,0x03, +0x55,0x04,0x0B,0x13,0x14,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x54,0x54, +0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x20,0x30,0x1E,0x06,0x03,0x55, +0x04,0x03,0x13,0x17,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x75,0x62, +0x6C,0x69,0x63,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74,0x30,0x82,0x01,0x22,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, +0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xE9,0x1A,0x30,0x8F, +0x83,0x88,0x14,0xC1,0x20,0xD8,0x3C,0x9B,0x8F,0x1B,0x7E,0x03,0x74,0xBB,0xDA,0x69, +0xD3,0x46,0xA5,0xF8,0x8E,0xC2,0x0C,0x11,0x90,0x51,0xA5,0x2F,0x66,0x54,0x40,0x55, +0xEA,0xDB,0x1F,0x4A,0x56,0xEE,0x9F,0x23,0x6E,0xF4,0x39,0xCB,0xA1,0xB9,0x6F,0xF2, +0x7E,0xF9,0x5D,0x87,0x26,0x61,0x9E,0x1C,0xF8,0xE2,0xEC,0xA6,0x81,0xF8,0x21,0xC5, +0x24,0xCC,0x11,0x0C,0x3F,0xDB,0x26,0x72,0x7A,0xC7,0x01,0x97,0x07,0x17,0xF9,0xD7, +0x18,0x2C,0x30,0x7D,0x0E,0x7A,0x1E,0x62,0x1E,0xC6,0x4B,0xC0,0xFD,0x7D,0x62,0x77, +0xD3,0x44,0x1E,0x27,0xF6,0x3F,0x4B,0x44,0xB3,0xB7,0x38,0xD9,0x39,0x1F,0x60,0xD5, +0x51,0x92,0x73,0x03,0xB4,0x00,0x69,0xE3,0xF3,0x14,0x4E,0xEE,0xD1,0xDC,0x09,0xCF, +0x77,0x34,0x46,0x50,0xB0,0xF8,0x11,0xF2,0xFE,0x38,0x79,0xF7,0x07,0x39,0xFE,0x51, +0x92,0x97,0x0B,0x5B,0x08,0x5F,0x34,0x86,0x01,0xAD,0x88,0x97,0xEB,0x66,0xCD,0x5E, +0xD1,0xFF,0xDC,0x7D,0xF2,0x84,0xDA,0xBA,0x77,0xAD,0xDC,0x80,0x08,0xC7,0xA7,0x87, +0xD6,0x55,0x9F,0x97,0x6A,0xE8,0xC8,0x11,0x64,0xBA,0xE7,0x19,0x29,0x3F,0x11,0xB3, +0x78,0x90,0x84,0x20,0x52,0x5B,0x11,0xEF,0x78,0xD0,0x83,0xF6,0xD5,0x48,0x90,0xD0, +0x30,0x1C,0xCF,0x80,0xF9,0x60,0xFE,0x79,0xE4,0x88,0xF2,0xDD,0x00,0xEB,0x94,0x45, +0xEB,0x65,0x94,0x69,0x40,0xBA,0xC0,0xD5,0xB4,0xB8,0xBA,0x7D,0x04,0x11,0xA8,0xEB, +0x31,0x05,0x96,0x94,0x4E,0x58,0x21,0x8E,0x9F,0xD0,0x60,0xFD,0x02,0x03,0x01,0x00, +0x01,0xA3,0x81,0xD1,0x30,0x81,0xCE,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0x81,0x3E,0x37,0xD8,0x92,0xB0,0x1F,0x77,0x9F,0x5C,0xB4,0xAB,0x73,0xAA, +0xE7,0xF6,0x34,0x60,0x2F,0xFA,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03, +0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x81,0x8E,0x06,0x03,0x55,0x1D,0x23,0x04,0x81,0x86,0x30, +0x81,0x83,0x80,0x14,0x81,0x3E,0x37,0xD8,0x92,0xB0,0x1F,0x77,0x9F,0x5C,0xB4,0xAB, +0x73,0xAA,0xE7,0xF6,0x34,0x60,0x2F,0xFA,0xA1,0x68,0xA4,0x66,0x30,0x64,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x41, +0x42,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x13,0x14,0x41,0x64,0x64,0x54, +0x72,0x75,0x73,0x74,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B, +0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x41,0x64,0x64,0x54,0x72, +0x75,0x73,0x74,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x43,0x41,0x20,0x52,0x6F, +0x6F,0x74,0x82,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x03,0xF7,0x15,0x4A,0xF8,0x24,0xDA, +0x23,0x56,0x16,0x93,0x76,0xDD,0x36,0x28,0xB9,0xAE,0x1B,0xB8,0xC3,0xF1,0x64,0xBA, +0x20,0x18,0x78,0x95,0x29,0x27,0x57,0x05,0xBC,0x7C,0x2A,0xF4,0xB9,0x51,0x55,0xDA, +0x87,0x02,0xDE,0x0F,0x16,0x17,0x31,0xF8,0xAA,0x79,0x2E,0x09,0x13,0xBB,0xAF,0xB2, +0x20,0x19,0x12,0xE5,0x93,0xF9,0x4B,0xF9,0x83,0xE8,0x44,0xD5,0xB2,0x41,0x25,0xBF, +0x88,0x75,0x6F,0xFF,0x10,0xFC,0x4A,0x54,0xD0,0x5F,0xF0,0xFA,0xEF,0x36,0x73,0x7D, +0x1B,0x36,0x45,0xC6,0x21,0x6D,0xB4,0x15,0xB8,0x4E,0xCF,0x9C,0x5C,0xA5,0x3D,0x5A, +0x00,0x8E,0x06,0xE3,0x3C,0x6B,0x32,0x7B,0xF2,0x9F,0xF0,0xB6,0xFD,0xDF,0xF0,0x28, +0x18,0x48,0xF0,0xC6,0xBC,0xD0,0xBF,0x34,0x80,0x96,0xC2,0x4A,0xB1,0x6D,0x8E,0xC7, +0x90,0x45,0xDE,0x2F,0x67,0xAC,0x45,0x04,0xA3,0x7A,0xDC,0x55,0x92,0xC9,0x47,0x66, +0xD8,0x1A,0x8C,0xC7,0xED,0x9C,0x4E,0x9A,0xE0,0x12,0xBB,0xB5,0x6A,0x4C,0x84,0xE1, +0xE1,0x22,0x0D,0x87,0x00,0x64,0xFE,0x8C,0x7D,0x62,0x39,0x65,0xA6,0xEF,0x42,0xB6, +0x80,0x25,0x12,0x61,0x01,0xA8,0x24,0x13,0x70,0x00,0x11,0x26,0x5F,0xFA,0x35,0x50, +0xC5,0x48,0xCC,0x06,0x47,0xE8,0x27,0xD8,0x70,0x8D,0x5F,0x64,0xE6,0xA1,0x44,0x26, +0x5E,0x22,0xEC,0x92,0xCD,0xFF,0x42,0x9A,0x44,0x21,0x6D,0x5C,0xC5,0xE3,0x22,0x1D, +0x5F,0x47,0x12,0xE7,0xCE,0x5F,0x5D,0xFA,0xD8,0xAA,0xB1,0x33,0x2D,0xD9,0x76,0xF2, +0x4E,0x3A,0x33,0x0C,0x2B,0xB3,0x2D,0x90,0x06, +}; + + +/* subject:/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Qualified CA Root */ +/* issuer :/C=SE/O=AddTrust AB/OU=AddTrust TTP Network/CN=AddTrust Qualified CA Root */ + + +const unsigned char AddTrust_Qualified_Certificates_Root_certificate[1058]={ +0x30,0x82,0x04,0x1E,0x30,0x82,0x03,0x06,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x67,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,0x14, +0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,0x73, +0x74,0x20,0x41,0x42,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x13,0x14,0x41, +0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77, +0x6F,0x72,0x6B,0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x13,0x1A,0x41,0x64, +0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x51,0x75,0x61,0x6C,0x69,0x66,0x69,0x65,0x64, +0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E,0x17,0x0D,0x30,0x30,0x30,0x35, +0x33,0x30,0x31,0x30,0x34,0x34,0x35,0x30,0x5A,0x17,0x0D,0x32,0x30,0x30,0x35,0x33, +0x30,0x31,0x30,0x34,0x34,0x35,0x30,0x5A,0x30,0x67,0x31,0x0B,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A, +0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x41,0x42,0x31,0x1D,0x30, +0x1B,0x06,0x03,0x55,0x04,0x0B,0x13,0x14,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74, +0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x23,0x30,0x21, +0x06,0x03,0x55,0x04,0x03,0x13,0x1A,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20, +0x51,0x75,0x61,0x6C,0x69,0x66,0x69,0x65,0x64,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F, +0x74,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01, +0x01,0x00,0xE4,0x1E,0x9A,0xFE,0xDC,0x09,0x5A,0x87,0xA4,0x9F,0x47,0xBE,0x11,0x5F, +0xAF,0x84,0x34,0xDB,0x62,0x3C,0x79,0x78,0xB7,0xE9,0x30,0xB5,0xEC,0x0C,0x1C,0x2A, +0xC4,0x16,0xFF,0xE0,0xEC,0x71,0xEB,0x8A,0xF5,0x11,0x6E,0xED,0x4F,0x0D,0x91,0xD2, +0x12,0x18,0x2D,0x49,0x15,0x01,0xC2,0xA4,0x22,0x13,0xC7,0x11,0x64,0xFF,0x22,0x12, +0x9A,0xB9,0x8E,0x5C,0x2F,0x08,0xCF,0x71,0x6A,0xB3,0x67,0x01,0x59,0xF1,0x5D,0x46, +0xF3,0xB0,0x78,0xA5,0xF6,0x0E,0x42,0x7A,0xE3,0x7F,0x1B,0xCC,0xD0,0xF0,0xB7,0x28, +0xFD,0x2A,0xEA,0x9E,0xB3,0xB0,0xB9,0x04,0xAA,0xFD,0xF6,0xC7,0xB4,0xB1,0xB8,0x2A, +0xA0,0xFB,0x58,0xF1,0x19,0xA0,0x6F,0x70,0x25,0x7E,0x3E,0x69,0x4A,0x7F,0x0F,0x22, +0xD8,0xEF,0xAD,0x08,0x11,0x9A,0x29,0x99,0xE1,0xAA,0x44,0x45,0x9A,0x12,0x5E,0x3E, +0x9D,0x6D,0x52,0xFC,0xE7,0xA0,0x3D,0x68,0x2F,0xF0,0x4B,0x70,0x7C,0x13,0x38,0xAD, +0xBC,0x15,0x25,0xF1,0xD6,0xCE,0xAB,0xA2,0xC0,0x31,0xD6,0x2F,0x9F,0xE0,0xFF,0x14, +0x59,0xFC,0x84,0x93,0xD9,0x87,0x7C,0x4C,0x54,0x13,0xEB,0x9F,0xD1,0x2D,0x11,0xF8, +0x18,0x3A,0x3A,0xDE,0x25,0xD9,0xF7,0xD3,0x40,0xED,0xA4,0x06,0x12,0xC4,0x3B,0xE1, +0x91,0xC1,0x56,0x35,0xF0,0x14,0xDC,0x65,0x36,0x09,0x6E,0xAB,0xA4,0x07,0xC7,0x35, +0xD1,0xC2,0x03,0x33,0x36,0x5B,0x75,0x26,0x6D,0x42,0xF1,0x12,0x6B,0x43,0x6F,0x4B, +0x71,0x94,0xFA,0x34,0x1D,0xED,0x13,0x6E,0xCA,0x80,0x7F,0x98,0x2F,0x6C,0xB9,0x65, +0xD8,0xE9,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xD4,0x30,0x81,0xD1,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x39,0x95,0x8B,0x62,0x8B,0x5C,0xC9,0xD4, +0x80,0xBA,0x58,0x0F,0x97,0x3F,0x15,0x08,0x43,0xCC,0x98,0xA7,0x30,0x0B,0x06,0x03, +0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13, +0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x91,0x06,0x03,0x55, +0x1D,0x23,0x04,0x81,0x89,0x30,0x81,0x86,0x80,0x14,0x39,0x95,0x8B,0x62,0x8B,0x5C, +0xC9,0xD4,0x80,0xBA,0x58,0x0F,0x97,0x3F,0x15,0x08,0x43,0xCC,0x98,0xA7,0xA1,0x6B, +0xA4,0x69,0x30,0x67,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53, +0x45,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54, +0x72,0x75,0x73,0x74,0x20,0x41,0x42,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B, +0x13,0x14,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x54,0x54,0x50,0x20,0x4E, +0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x13, +0x1A,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x51,0x75,0x61,0x6C,0x69,0x66, +0x69,0x65,0x64,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74,0x82,0x01,0x01,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01, +0x01,0x00,0x19,0xAB,0x75,0xEA,0xF8,0x8B,0x65,0x61,0x95,0x13,0xBA,0x69,0x04,0xEF, +0x86,0xCA,0x13,0xA0,0xC7,0xAA,0x4F,0x64,0x1B,0x3F,0x18,0xF6,0xA8,0x2D,0x2C,0x55, +0x8F,0x05,0xB7,0x30,0xEA,0x42,0x6A,0x1D,0xC0,0x25,0x51,0x2D,0xA7,0xBF,0x0C,0xB3, +0xED,0xEF,0x08,0x7F,0x6C,0x3C,0x46,0x1A,0xEA,0x18,0x43,0xDF,0x76,0xCC,0xF9,0x66, +0x86,0x9C,0x2C,0x68,0xF5,0xE9,0x17,0xF8,0x31,0xB3,0x18,0xC4,0xD6,0x48,0x7D,0x23, +0x4C,0x68,0xC1,0x7E,0xBB,0x01,0x14,0x6F,0xC5,0xD9,0x6E,0xDE,0xBB,0x04,0x42,0x6A, +0xF8,0xF6,0x5C,0x7D,0xE5,0xDA,0xFA,0x87,0xEB,0x0D,0x35,0x52,0x67,0xD0,0x9E,0x97, +0x76,0x05,0x93,0x3F,0x95,0xC7,0x01,0xE6,0x69,0x55,0x38,0x7F,0x10,0x61,0x99,0xC9, +0xE3,0x5F,0xA6,0xCA,0x3E,0x82,0x63,0x48,0xAA,0xE2,0x08,0x48,0x3E,0xAA,0xF2,0xB2, +0x85,0x62,0xA6,0xB4,0xA7,0xD9,0xBD,0x37,0x9C,0x68,0xB5,0x2D,0x56,0x7D,0xB0,0xB7, +0x3F,0xA0,0xB1,0x07,0xD6,0xE9,0x4F,0xDC,0xDE,0x45,0x71,0x30,0x32,0x7F,0x1B,0x2E, +0x09,0xF9,0xBF,0x52,0xA1,0xEE,0xC2,0x80,0x3E,0x06,0x5C,0x2E,0x55,0x40,0xC1,0x1B, +0xF5,0x70,0x45,0xB0,0xDC,0x5D,0xFA,0xF6,0x72,0x5A,0x77,0xD2,0x63,0xCD,0xCF,0x58, +0x89,0x00,0x42,0x63,0x3F,0x79,0x39,0xD0,0x44,0xB0,0x82,0x6E,0x41,0x19,0xE8,0xDD, +0xE0,0xC1,0x88,0x5A,0xD1,0x1E,0x71,0x93,0x1F,0x24,0x30,0x74,0xE5,0x1E,0xA8,0xDE, +0x3C,0x27,0x37,0x7F,0x83,0xAE,0x9E,0x77,0xCF,0xF0,0x30,0xB1,0xFF,0x4B,0x99,0xE8, +0xC6,0xA1, +}; + + +/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Commercial */ +/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Commercial */ + + +const unsigned char AffirmTrust_Commercial_certificate[848]={ +0x30,0x82,0x03,0x4C,0x30,0x82,0x02,0x34,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x77, +0x77,0x06,0x27,0x26,0xA9,0xB1,0x7C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, +0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1F,0x30,0x1D,0x06, +0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x20,0x43,0x6F,0x6D,0x6D,0x65,0x72,0x63,0x69,0x61,0x6C,0x30,0x1E,0x17,0x0D, +0x31,0x30,0x30,0x31,0x32,0x39,0x31,0x34,0x30,0x36,0x30,0x36,0x5A,0x17,0x0D,0x33, +0x30,0x31,0x32,0x33,0x31,0x31,0x34,0x30,0x36,0x30,0x36,0x5A,0x30,0x44,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69, +0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x43,0x6F,0x6D,0x6D,0x65,0x72,0x63,0x69, +0x61,0x6C,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xF6,0x1B,0x4F,0x67,0x07,0x2B,0xA1,0x15,0xF5,0x06,0x22,0xCB,0x1F, +0x01,0xB2,0xE3,0x73,0x45,0x06,0x44,0x49,0x2C,0xBB,0x49,0x25,0x14,0xD6,0xCE,0xC3, +0xB7,0xAB,0x2C,0x4F,0xC6,0x41,0x32,0x94,0x57,0xFA,0x12,0xA7,0x5B,0x0E,0xE2,0x8F, +0x1F,0x1E,0x86,0x19,0xA7,0xAA,0xB5,0x2D,0xB9,0x5F,0x0D,0x8A,0xC2,0xAF,0x85,0x35, +0x79,0x32,0x2D,0xBB,0x1C,0x62,0x37,0xF2,0xB1,0x5B,0x4A,0x3D,0xCA,0xCD,0x71,0x5F, +0xE9,0x42,0xBE,0x94,0xE8,0xC8,0xDE,0xF9,0x22,0x48,0x64,0xC6,0xE5,0xAB,0xC6,0x2B, +0x6D,0xAD,0x05,0xF0,0xFA,0xD5,0x0B,0xCF,0x9A,0xE5,0xF0,0x50,0xA4,0x8B,0x3B,0x47, +0xA5,0x23,0x5B,0x7A,0x7A,0xF8,0x33,0x3F,0xB8,0xEF,0x99,0x97,0xE3,0x20,0xC1,0xD6, +0x28,0x89,0xCF,0x94,0xFB,0xB9,0x45,0xED,0xE3,0x40,0x17,0x11,0xD4,0x74,0xF0,0x0B, +0x31,0xE2,0x2B,0x26,0x6A,0x9B,0x4C,0x57,0xAE,0xAC,0x20,0x3E,0xBA,0x45,0x7A,0x05, +0xF3,0xBD,0x9B,0x69,0x15,0xAE,0x7D,0x4E,0x20,0x63,0xC4,0x35,0x76,0x3A,0x07,0x02, +0xC9,0x37,0xFD,0xC7,0x47,0xEE,0xE8,0xF1,0x76,0x1D,0x73,0x15,0xF2,0x97,0xA4,0xB5, +0xC8,0x7A,0x79,0xD9,0x42,0xAA,0x2B,0x7F,0x5C,0xFE,0xCE,0x26,0x4F,0xA3,0x66,0x81, +0x35,0xAF,0x44,0xBA,0x54,0x1E,0x1C,0x30,0x32,0x65,0x9D,0xE6,0x3C,0x93,0x5E,0x50, +0x4E,0x7A,0xE3,0x3A,0xD4,0x6E,0xCC,0x1A,0xFB,0xF9,0xD2,0x37,0xAE,0x24,0x2A,0xAB, +0x57,0x03,0x22,0x28,0x0D,0x49,0x75,0x7F,0xB7,0x28,0xDA,0x75,0xBF,0x8E,0xE3,0xDC, +0x0E,0x79,0x31,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9D,0x93,0xC6,0x53,0x8B,0x5E,0xCA,0xAF,0x3F, +0x9F,0x1E,0x0F,0xE5,0x99,0x95,0xBC,0x24,0xF6,0x94,0x8F,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00, +0x58,0xAC,0xF4,0x04,0x0E,0xCD,0xC0,0x0D,0xFF,0x0A,0xFD,0xD4,0xBA,0x16,0x5F,0x29, +0xBD,0x7B,0x68,0x99,0x58,0x49,0xD2,0xB4,0x1D,0x37,0x4D,0x7F,0x27,0x7D,0x46,0x06, +0x5D,0x43,0xC6,0x86,0x2E,0x3E,0x73,0xB2,0x26,0x7D,0x4F,0x93,0xA9,0xB6,0xC4,0x2A, +0x9A,0xAB,0x21,0x97,0x14,0xB1,0xDE,0x8C,0xD3,0xAB,0x89,0x15,0xD8,0x6B,0x24,0xD4, +0xF1,0x16,0xAE,0xD8,0xA4,0x5C,0xD4,0x7F,0x51,0x8E,0xED,0x18,0x01,0xB1,0x93,0x63, +0xBD,0xBC,0xF8,0x61,0x80,0x9A,0x9E,0xB1,0xCE,0x42,0x70,0xE2,0xA9,0x7D,0x06,0x25, +0x7D,0x27,0xA1,0xFE,0x6F,0xEC,0xB3,0x1E,0x24,0xDA,0xE3,0x4B,0x55,0x1A,0x00,0x3B, +0x35,0xB4,0x3B,0xD9,0xD7,0x5D,0x30,0xFD,0x81,0x13,0x89,0xF2,0xC2,0x06,0x2B,0xED, +0x67,0xC4,0x8E,0xC9,0x43,0xB2,0x5C,0x6B,0x15,0x89,0x02,0xBC,0x62,0xFC,0x4E,0xF2, +0xB5,0x33,0xAA,0xB2,0x6F,0xD3,0x0A,0xA2,0x50,0xE3,0xF6,0x3B,0xE8,0x2E,0x44,0xC2, +0xDB,0x66,0x38,0xA9,0x33,0x56,0x48,0xF1,0x6D,0x1B,0x33,0x8D,0x0D,0x8C,0x3F,0x60, +0x37,0x9D,0xD3,0xCA,0x6D,0x7E,0x34,0x7E,0x0D,0x9F,0x72,0x76,0x8B,0x1B,0x9F,0x72, +0xFD,0x52,0x35,0x41,0x45,0x02,0x96,0x2F,0x1C,0xB2,0x9A,0x73,0x49,0x21,0xB1,0x49, +0x47,0x45,0x47,0xB4,0xEF,0x6A,0x34,0x11,0xC9,0x4D,0x9A,0xCC,0x59,0xB7,0xD6,0x02, +0x9E,0x5A,0x4E,0x65,0xB5,0x94,0xAE,0x1B,0xDF,0x29,0xB0,0x16,0xF1,0xBF,0x00,0x9E, +0x07,0x3A,0x17,0x64,0xB5,0x04,0xB5,0x23,0x21,0x99,0x0A,0x95,0x3B,0x97,0x7C,0xEF, +}; + + +/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Networking */ +/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Networking */ + + +const unsigned char AffirmTrust_Networking_certificate[848]={ +0x30,0x82,0x03,0x4C,0x30,0x82,0x02,0x34,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x7C, +0x4F,0x04,0x39,0x1C,0xD4,0x99,0x2D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, +0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1F,0x30,0x1D,0x06, +0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x69,0x6E,0x67,0x30,0x1E,0x17,0x0D, +0x31,0x30,0x30,0x31,0x32,0x39,0x31,0x34,0x30,0x38,0x32,0x34,0x5A,0x17,0x0D,0x33, +0x30,0x31,0x32,0x33,0x31,0x31,0x34,0x30,0x38,0x32,0x34,0x5A,0x30,0x44,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x66,0x66,0x69, +0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x69, +0x6E,0x67,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xB4,0x84,0xCC,0x33,0x17,0x2E,0x6B,0x94,0x6C,0x6B,0x61,0x52,0xA0, +0xEB,0xA3,0xCF,0x79,0x94,0x4C,0xE5,0x94,0x80,0x99,0xCB,0x55,0x64,0x44,0x65,0x8F, +0x67,0x64,0xE2,0x06,0xE3,0x5C,0x37,0x49,0xF6,0x2F,0x9B,0x84,0x84,0x1E,0x2D,0xF2, +0x60,0x9D,0x30,0x4E,0xCC,0x84,0x85,0xE2,0x2C,0xCF,0x1E,0x9E,0xFE,0x36,0xAB,0x33, +0x77,0x35,0x44,0xD8,0x35,0x96,0x1A,0x3D,0x36,0xE8,0x7A,0x0E,0xD8,0xD5,0x47,0xA1, +0x6A,0x69,0x8B,0xD9,0xFC,0xBB,0x3A,0xAE,0x79,0x5A,0xD5,0xF4,0xD6,0x71,0xBB,0x9A, +0x90,0x23,0x6B,0x9A,0xB7,0x88,0x74,0x87,0x0C,0x1E,0x5F,0xB9,0x9E,0x2D,0xFA,0xAB, +0x53,0x2B,0xDC,0xBB,0x76,0x3E,0x93,0x4C,0x08,0x08,0x8C,0x1E,0xA2,0x23,0x1C,0xD4, +0x6A,0xAD,0x22,0xBA,0x99,0x01,0x2E,0x6D,0x65,0xCB,0xBE,0x24,0x66,0x55,0x24,0x4B, +0x40,0x44,0xB1,0x1B,0xD7,0xE1,0xC2,0x85,0xC0,0xDE,0x10,0x3F,0x3D,0xED,0xB8,0xFC, +0xF1,0xF1,0x23,0x53,0xDC,0xBF,0x65,0x97,0x6F,0xD9,0xF9,0x40,0x71,0x8D,0x7D,0xBD, +0x95,0xD4,0xCE,0xBE,0xA0,0x5E,0x27,0x23,0xDE,0xFD,0xA6,0xD0,0x26,0x0E,0x00,0x29, +0xEB,0x3C,0x46,0xF0,0x3D,0x60,0xBF,0x3F,0x50,0xD2,0xDC,0x26,0x41,0x51,0x9E,0x14, +0x37,0x42,0x04,0xA3,0x70,0x57,0xA8,0x1B,0x87,0xED,0x2D,0xFA,0x7B,0xEE,0x8C,0x0A, +0xE3,0xA9,0x66,0x89,0x19,0xCB,0x41,0xF9,0xDD,0x44,0x36,0x61,0xCF,0xE2,0x77,0x46, +0xC8,0x7D,0xF6,0xF4,0x92,0x81,0x36,0xFD,0xDB,0x34,0xF1,0x72,0x7E,0xF3,0x0C,0x16, +0xBD,0xB4,0x15,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x07,0x1F,0xD2,0xE7,0x9C,0xDA,0xC2,0x6E,0xA2, +0x40,0xB4,0xB0,0x7A,0x50,0x10,0x50,0x74,0xC4,0xC8,0xBD,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00, +0x89,0x57,0xB2,0x16,0x7A,0xA8,0xC2,0xFD,0xD6,0xD9,0x9B,0x9B,0x34,0xC2,0x9C,0xB4, +0x32,0x14,0x4D,0xA7,0xA4,0xDF,0xEC,0xBE,0xA7,0xBE,0xF8,0x43,0xDB,0x91,0x37,0xCE, +0xB4,0x32,0x2E,0x50,0x55,0x1A,0x35,0x4E,0x76,0x43,0x71,0x20,0xEF,0x93,0x77,0x4E, +0x15,0x70,0x2E,0x87,0xC3,0xC1,0x1D,0x6D,0xDC,0xCB,0xB5,0x27,0xD4,0x2C,0x56,0xD1, +0x52,0x53,0x3A,0x44,0xD2,0x73,0xC8,0xC4,0x1B,0x05,0x65,0x5A,0x62,0x92,0x9C,0xEE, +0x41,0x8D,0x31,0xDB,0xE7,0x34,0xEA,0x59,0x21,0xD5,0x01,0x7A,0xD7,0x64,0xB8,0x64, +0x39,0xCD,0xC9,0xED,0xAF,0xED,0x4B,0x03,0x48,0xA7,0xA0,0x99,0x01,0x80,0xDC,0x65, +0xA3,0x36,0xAE,0x65,0x59,0x48,0x4F,0x82,0x4B,0xC8,0x65,0xF1,0x57,0x1D,0xE5,0x59, +0x2E,0x0A,0x3F,0x6C,0xD8,0xD1,0xF5,0xE5,0x09,0xB4,0x6C,0x54,0x00,0x0A,0xE0,0x15, +0x4D,0x87,0x75,0x6D,0xB7,0x58,0x96,0x5A,0xDD,0x6D,0xD2,0x00,0xA0,0xF4,0x9B,0x48, +0xBE,0xC3,0x37,0xA4,0xBA,0x36,0xE0,0x7C,0x87,0x85,0x97,0x1A,0x15,0xA2,0xDE,0x2E, +0xA2,0x5B,0xBD,0xAF,0x18,0xF9,0x90,0x50,0xCD,0x70,0x59,0xF8,0x27,0x67,0x47,0xCB, +0xC7,0xA0,0x07,0x3A,0x7D,0xD1,0x2C,0x5D,0x6C,0x19,0x3A,0x66,0xB5,0x7D,0xFD,0x91, +0x6F,0x82,0xB1,0xBE,0x08,0x93,0xDB,0x14,0x47,0xF1,0xA2,0x37,0xC7,0x45,0x9E,0x3C, +0xC7,0x77,0xAF,0x64,0xA8,0x93,0xDF,0xF6,0x69,0x83,0x82,0x60,0xF2,0x49,0x42,0x34, +0xED,0x5A,0x00,0x54,0x85,0x1C,0x16,0x36,0x92,0x0C,0x5C,0xFA,0xA6,0xAD,0xBF,0xDB, +}; + + +/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Premium */ +/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Premium */ + + +const unsigned char AffirmTrust_Premium_certificate[1354]={ +0x30,0x82,0x05,0x46,0x30,0x82,0x03,0x2E,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x6D, +0x8C,0x14,0x46,0xB1,0xA6,0x0A,0xEE,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x41,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B, +0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1C,0x30,0x1A,0x06, +0x03,0x55,0x04,0x03,0x0C,0x13,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73, +0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30, +0x31,0x32,0x39,0x31,0x34,0x31,0x30,0x33,0x36,0x5A,0x17,0x0D,0x34,0x30,0x31,0x32, +0x33,0x31,0x31,0x34,0x31,0x30,0x33,0x36,0x5A,0x30,0x41,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, +0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x1C, +0x30,0x1A,0x06,0x03,0x55,0x04,0x03,0x0C,0x13,0x41,0x66,0x66,0x69,0x72,0x6D,0x54, +0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x30,0x82,0x02,0x22, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xC4,0x12,0xDF, +0xA9,0x5F,0xFE,0x41,0xDD,0xDD,0xF5,0x9F,0x8A,0xE3,0xF6,0xAC,0xE1,0x3C,0x78,0x9A, +0xBC,0xD8,0xF0,0x7F,0x7A,0xA0,0x33,0x2A,0xDC,0x8D,0x20,0x5B,0xAE,0x2D,0x6F,0xE7, +0x93,0xD9,0x36,0x70,0x6A,0x68,0xCF,0x8E,0x51,0xA3,0x85,0x5B,0x67,0x04,0xA0,0x10, +0x24,0x6F,0x5D,0x28,0x82,0xC1,0x97,0x57,0xD8,0x48,0x29,0x13,0xB6,0xE1,0xBE,0x91, +0x4D,0xDF,0x85,0x0C,0x53,0x18,0x9A,0x1E,0x24,0xA2,0x4F,0x8F,0xF0,0xA2,0x85,0x0B, +0xCB,0xF4,0x29,0x7F,0xD2,0xA4,0x58,0xEE,0x26,0x4D,0xC9,0xAA,0xA8,0x7B,0x9A,0xD9, +0xFA,0x38,0xDE,0x44,0x57,0x15,0xE5,0xF8,0x8C,0xC8,0xD9,0x48,0xE2,0x0D,0x16,0x27, +0x1D,0x1E,0xC8,0x83,0x85,0x25,0xB7,0xBA,0xAA,0x55,0x41,0xCC,0x03,0x22,0x4B,0x2D, +0x91,0x8D,0x8B,0xE6,0x89,0xAF,0x66,0xC7,0xE9,0xFF,0x2B,0xE9,0x3C,0xAC,0xDA,0xD2, +0xB3,0xC3,0xE1,0x68,0x9C,0x89,0xF8,0x7A,0x00,0x56,0xDE,0xF4,0x55,0x95,0x6C,0xFB, +0xBA,0x64,0xDD,0x62,0x8B,0xDF,0x0B,0x77,0x32,0xEB,0x62,0xCC,0x26,0x9A,0x9B,0xBB, +0xAA,0x62,0x83,0x4C,0xB4,0x06,0x7A,0x30,0xC8,0x29,0xBF,0xED,0x06,0x4D,0x97,0xB9, +0x1C,0xC4,0x31,0x2B,0xD5,0x5F,0xBC,0x53,0x12,0x17,0x9C,0x99,0x57,0x29,0x66,0x77, +0x61,0x21,0x31,0x07,0x2E,0x25,0x49,0x9D,0x18,0xF2,0xEE,0xF3,0x2B,0x71,0x8C,0xB5, +0xBA,0x39,0x07,0x49,0x77,0xFC,0xEF,0x2E,0x92,0x90,0x05,0x8D,0x2D,0x2F,0x77,0x7B, +0xEF,0x43,0xBF,0x35,0xBB,0x9A,0xD8,0xF9,0x73,0xA7,0x2C,0xF2,0xD0,0x57,0xEE,0x28, +0x4E,0x26,0x5F,0x8F,0x90,0x68,0x09,0x2F,0xB8,0xF8,0xDC,0x06,0xE9,0x2E,0x9A,0x3E, +0x51,0xA7,0xD1,0x22,0xC4,0x0A,0xA7,0x38,0x48,0x6C,0xB3,0xF9,0xFF,0x7D,0xAB,0x86, +0x57,0xE3,0xBA,0xD6,0x85,0x78,0x77,0xBA,0x43,0xEA,0x48,0x7F,0xF6,0xD8,0xBE,0x23, +0x6D,0x1E,0xBF,0xD1,0x36,0x6C,0x58,0x5C,0xF1,0xEE,0xA4,0x19,0x54,0x1A,0xF5,0x03, +0xD2,0x76,0xE6,0xE1,0x8C,0xBD,0x3C,0xB3,0xD3,0x48,0x4B,0xE2,0xC8,0xF8,0x7F,0x92, +0xA8,0x76,0x46,0x9C,0x42,0x65,0x3E,0xA4,0x1E,0xC1,0x07,0x03,0x5A,0x46,0x2D,0xB8, +0x97,0xF3,0xB7,0xD5,0xB2,0x55,0x21,0xEF,0xBA,0xDC,0x4C,0x00,0x97,0xFB,0x14,0x95, +0x27,0x33,0xBF,0xE8,0x43,0x47,0x46,0xD2,0x08,0x99,0x16,0x60,0x3B,0x9A,0x7E,0xD2, +0xE6,0xED,0x38,0xEA,0xEC,0x01,0x1E,0x3C,0x48,0x56,0x49,0x09,0xC7,0x4C,0x37,0x00, +0x9E,0x88,0x0E,0xC0,0x73,0xE1,0x6F,0x66,0xE9,0x72,0x47,0x30,0x3E,0x10,0xE5,0x0B, +0x03,0xC9,0x9A,0x42,0x00,0x6C,0xC5,0x94,0x7E,0x61,0xC4,0x8A,0xDF,0x7F,0x82,0x1A, +0x0B,0x59,0xC4,0x59,0x32,0x77,0xB3,0xBC,0x60,0x69,0x56,0x39,0xFD,0xB4,0x06,0x7B, +0x2C,0xD6,0x64,0x36,0xD9,0xBD,0x48,0xED,0x84,0x1F,0x7E,0xA5,0x22,0x8F,0x2A,0xB8, +0x42,0xF4,0x82,0xB7,0xD4,0x53,0x90,0x78,0x4E,0x2D,0x1A,0xFD,0x81,0x6F,0x44,0xD7, +0x3B,0x01,0x74,0x96,0x42,0xE0,0x00,0xE2,0x2E,0x6B,0xEA,0xC5,0xEE,0x72,0xAC,0xBB, +0xBF,0xFE,0xEA,0xAA,0xA8,0xF8,0xDC,0xF6,0xB2,0x79,0x8A,0xB6,0x67,0x02,0x03,0x01, +0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x9D,0xC0,0x67,0xA6,0x0C,0x22,0xD9,0x26,0xF5,0x45,0xAB,0xA6,0x65,0x52,0x11, +0x27,0xD8,0x45,0xAC,0x63,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0xB3,0x57,0x4D,0x10,0x62,0x4E, +0x3A,0xE4,0xAC,0xEA,0xB8,0x1C,0xAF,0x32,0x23,0xC8,0xB3,0x49,0x5A,0x51,0x9C,0x76, +0x28,0x8D,0x79,0xAA,0x57,0x46,0x17,0xD5,0xF5,0x52,0xF6,0xB7,0x44,0xE8,0x08,0x44, +0xBF,0x18,0x84,0xD2,0x0B,0x80,0xCD,0xC5,0x12,0xFD,0x00,0x55,0x05,0x61,0x87,0x41, +0xDC,0xB5,0x24,0x9E,0x3C,0xC4,0xD8,0xC8,0xFB,0x70,0x9E,0x2F,0x78,0x96,0x83,0x20, +0x36,0xDE,0x7C,0x0F,0x69,0x13,0x88,0xA5,0x75,0x36,0x98,0x08,0xA6,0xC6,0xDF,0xAC, +0xCE,0xE3,0x58,0xD6,0xB7,0x3E,0xDE,0xBA,0xF3,0xEB,0x34,0x40,0xD8,0xA2,0x81,0xF5, +0x78,0x3F,0x2F,0xD5,0xA5,0xFC,0xD9,0xA2,0xD4,0x5E,0x04,0x0E,0x17,0xAD,0xFE,0x41, +0xF0,0xE5,0xB2,0x72,0xFA,0x44,0x82,0x33,0x42,0xE8,0x2D,0x58,0xF7,0x56,0x8C,0x62, +0x3F,0xBA,0x42,0xB0,0x9C,0x0C,0x5C,0x7E,0x2E,0x65,0x26,0x5C,0x53,0x4F,0x00,0xB2, +0x78,0x7E,0xA1,0x0D,0x99,0x2D,0x8D,0xB8,0x1D,0x8E,0xA2,0xC4,0xB0,0xFD,0x60,0xD0, +0x30,0xA4,0x8E,0xC8,0x04,0x62,0xA9,0xC4,0xED,0x35,0xDE,0x7A,0x97,0xED,0x0E,0x38, +0x5E,0x92,0x2F,0x93,0x70,0xA5,0xA9,0x9C,0x6F,0xA7,0x7D,0x13,0x1D,0x7E,0xC6,0x08, +0x48,0xB1,0x5E,0x67,0xEB,0x51,0x08,0x25,0xE9,0xE6,0x25,0x6B,0x52,0x29,0x91,0x9C, +0xD2,0x39,0x73,0x08,0x57,0xDE,0x99,0x06,0xB4,0x5B,0x9D,0x10,0x06,0xE1,0xC2,0x00, +0xA8,0xB8,0x1C,0x4A,0x02,0x0A,0x14,0xD0,0xC1,0x41,0xCA,0xFB,0x8C,0x35,0x21,0x7D, +0x82,0x38,0xF2,0xA9,0x54,0x91,0x19,0x35,0x93,0x94,0x6D,0x6A,0x3A,0xC5,0xB2,0xD0, +0xBB,0x89,0x86,0x93,0xE8,0x9B,0xC9,0x0F,0x3A,0xA7,0x7A,0xB8,0xA1,0xF0,0x78,0x46, +0xFA,0xFC,0x37,0x2F,0xE5,0x8A,0x84,0xF3,0xDF,0xFE,0x04,0xD9,0xA1,0x68,0xA0,0x2F, +0x24,0xE2,0x09,0x95,0x06,0xD5,0x95,0xCA,0xE1,0x24,0x96,0xEB,0x7C,0xF6,0x93,0x05, +0xBB,0xED,0x73,0xE9,0x2D,0xD1,0x75,0x39,0xD7,0xE7,0x24,0xDB,0xD8,0x4E,0x5F,0x43, +0x8F,0x9E,0xD0,0x14,0x39,0xBF,0x55,0x70,0x48,0x99,0x57,0x31,0xB4,0x9C,0xEE,0x4A, +0x98,0x03,0x96,0x30,0x1F,0x60,0x06,0xEE,0x1B,0x23,0xFE,0x81,0x60,0x23,0x1A,0x47, +0x62,0x85,0xA5,0xCC,0x19,0x34,0x80,0x6F,0xB3,0xAC,0x1A,0xE3,0x9F,0xF0,0x7B,0x48, +0xAD,0xD5,0x01,0xD9,0x67,0xB6,0xA9,0x72,0x93,0xEA,0x2D,0x66,0xB5,0xB2,0xB8,0xE4, +0x3D,0x3C,0xB2,0xEF,0x4C,0x8C,0xEA,0xEB,0x07,0xBF,0xAB,0x35,0x9A,0x55,0x86,0xBC, +0x18,0xA6,0xB5,0xA8,0x5E,0xB4,0x83,0x6C,0x6B,0x69,0x40,0xD3,0x9F,0xDC,0xF1,0xC3, +0x69,0x6B,0xB9,0xE1,0x6D,0x09,0xF4,0xF1,0xAA,0x50,0x76,0x0A,0x7A,0x7D,0x7A,0x17, +0xA1,0x55,0x96,0x42,0x99,0x31,0x09,0xDD,0x60,0x11,0x8D,0x05,0x30,0x7E,0xE6,0x8E, +0x46,0xD1,0x9D,0x14,0xDA,0xC7,0x17,0xE4,0x05,0x96,0x8C,0xC4,0x24,0xB5,0x1B,0xCF, +0x14,0x07,0xB2,0x40,0xF8,0xA3,0x9E,0x41,0x86,0xBC,0x04,0xD0,0x6B,0x96,0xC8,0x2A, +0x80,0x34,0xFD,0xBF,0xEF,0x06,0xA3,0xDD,0x58,0xC5,0x85,0x3D,0x3E,0x8F,0xFE,0x9E, +0x29,0xE0,0xB6,0xB8,0x09,0x68,0x19,0x1C,0x18,0x43, +}; + + +/* subject:/C=US/O=AffirmTrust/CN=AffirmTrust Premium ECC */ +/* issuer :/C=US/O=AffirmTrust/CN=AffirmTrust Premium ECC */ + + +const unsigned char AffirmTrust_Premium_ECC_certificate[514]={ +0x30,0x82,0x01,0xFE,0x30,0x82,0x01,0x85,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x74, +0x97,0x25,0x8A,0xC7,0x3F,0x7A,0x54,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D, +0x04,0x03,0x03,0x30,0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66, +0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04, +0x03,0x0C,0x17,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x20,0x50, +0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x45,0x43,0x43,0x30,0x1E,0x17,0x0D,0x31,0x30, +0x30,0x31,0x32,0x39,0x31,0x34,0x32,0x30,0x32,0x34,0x5A,0x17,0x0D,0x34,0x30,0x31, +0x32,0x33,0x31,0x31,0x34,0x32,0x30,0x32,0x34,0x5A,0x30,0x45,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55, +0x04,0x0A,0x0C,0x0B,0x41,0x66,0x66,0x69,0x72,0x6D,0x54,0x72,0x75,0x73,0x74,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x0C,0x17,0x41,0x66,0x66,0x69,0x72,0x6D, +0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x45,0x43, +0x43,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, +0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x0D,0x30,0x5E,0x1B,0x15,0x9D,0x03, +0xD0,0xA1,0x79,0x35,0xB7,0x3A,0x3C,0x92,0x7A,0xCA,0x15,0x1C,0xCD,0x62,0xF3,0x9C, +0x26,0x5C,0x07,0x3D,0xE5,0x54,0xFA,0xA3,0xD6,0xCC,0x12,0xEA,0xF4,0x14,0x5F,0xE8, +0x8E,0x19,0xAB,0x2F,0x2E,0x48,0xE6,0xAC,0x18,0x43,0x78,0xAC,0xD0,0x37,0xC3,0xBD, +0xB2,0xCD,0x2C,0xE6,0x47,0xE2,0x1A,0xE6,0x63,0xB8,0x3D,0x2E,0x2F,0x78,0xC4,0x4F, +0xDB,0xF4,0x0F,0xA4,0x68,0x4C,0x55,0x72,0x6B,0x95,0x1D,0x4E,0x18,0x42,0x95,0x78, +0xCC,0x37,0x3C,0x91,0xE2,0x9B,0x65,0x2B,0x29,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9A,0xAF,0x29,0x7A,0xC0,0x11,0x35,0x35, +0x26,0x51,0x30,0x00,0xC3,0x6A,0xFE,0x40,0xD5,0xAE,0xD6,0x3C,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06, +0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0A,0x06, +0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30, +0x17,0x09,0xF3,0x87,0x88,0x50,0x5A,0xAF,0xC8,0xC0,0x42,0xBF,0x47,0x5F,0xF5,0x6C, +0x6A,0x86,0xE0,0xC4,0x27,0x74,0xE4,0x38,0x53,0xD7,0x05,0x7F,0x1B,0x34,0xE3,0xC6, +0x2F,0xB3,0xCA,0x09,0x3C,0x37,0x9D,0xD7,0xE7,0xB8,0x46,0xF1,0xFD,0xA1,0xE2,0x71, +0x02,0x30,0x42,0x59,0x87,0x43,0xD4,0x51,0xDF,0xBA,0xD3,0x09,0x32,0x5A,0xCE,0x88, +0x7E,0x57,0x3D,0x9C,0x5F,0x42,0x6B,0xF5,0x07,0x2D,0xB5,0xF0,0x82,0x93,0xF9,0x59, +0x6F,0xAE,0x64,0xFA,0x58,0xE5,0x8B,0x1E,0xE3,0x63,0xBE,0xB5,0x81,0xCD,0x6F,0x02, +0x8C,0x79, +}; + + +/* subject:/C=US/O=America Online Inc./CN=America Online Root Certification Authority 1 */ +/* issuer :/C=US/O=America Online Inc./CN=America Online Root Certification Authority 1 */ + + +const unsigned char America_Online_Root_Certification_Authority_1_certificate[936]={ +0x30,0x82,0x03,0xA4,0x30,0x82,0x02,0x8C,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C, +0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x41,0x6D,0x65,0x72,0x69,0x63,0x61, +0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x36,0x30,0x34, +0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x41,0x6D,0x65,0x72,0x69,0x63,0x61,0x20,0x4F, +0x6E,0x6C,0x69,0x6E,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x20,0x31,0x30,0x1E,0x17,0x0D,0x30,0x32,0x30,0x35,0x32,0x38,0x30,0x36, +0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x31,0x31,0x39,0x32,0x30,0x34, +0x33,0x30,0x30,0x5A,0x30,0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x41,0x6D, +0x65,0x72,0x69,0x63,0x61,0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x36,0x30,0x34,0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x41,0x6D,0x65,0x72, +0x69,0x63,0x61,0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75, +0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x31,0x30,0x82,0x01,0x22,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F, +0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xA8,0x2F,0xE8,0xA4,0x69,0x06, +0x03,0x47,0xC3,0xE9,0x2A,0x98,0xFF,0x19,0xA2,0x70,0x9A,0xC6,0x50,0xB2,0x7E,0xA5, +0xDF,0x68,0x4D,0x1B,0x7C,0x0F,0xB6,0x97,0x68,0x7D,0x2D,0xA6,0x8B,0x97,0xE9,0x64, +0x86,0xC9,0xA3,0xEF,0xA0,0x86,0xBF,0x60,0x65,0x9C,0x4B,0x54,0x88,0xC2,0x48,0xC5, +0x4A,0x39,0xBF,0x14,0xE3,0x59,0x55,0xE5,0x19,0xB4,0x74,0xC8,0xB4,0x05,0x39,0x5C, +0x16,0xA5,0xE2,0x95,0x05,0xE0,0x12,0xAE,0x59,0x8B,0xA2,0x33,0x68,0x58,0x1C,0xA6, +0xD4,0x15,0xB7,0xD8,0x9F,0xD7,0xDC,0x71,0xAB,0x7E,0x9A,0xBF,0x9B,0x8E,0x33,0x0F, +0x22,0xFD,0x1F,0x2E,0xE7,0x07,0x36,0xEF,0x62,0x39,0xC5,0xDD,0xCB,0xBA,0x25,0x14, +0x23,0xDE,0x0C,0xC6,0x3D,0x3C,0xCE,0x82,0x08,0xE6,0x66,0x3E,0xDA,0x51,0x3B,0x16, +0x3A,0xA3,0x05,0x7F,0xA0,0xDC,0x87,0xD5,0x9C,0xFC,0x72,0xA9,0xA0,0x7D,0x78,0xE4, +0xB7,0x31,0x55,0x1E,0x65,0xBB,0xD4,0x61,0xB0,0x21,0x60,0xED,0x10,0x32,0x72,0xC5, +0x92,0x25,0x1E,0xF8,0x90,0x4A,0x18,0x78,0x47,0xDF,0x7E,0x30,0x37,0x3E,0x50,0x1B, +0xDB,0x1C,0xD3,0x6B,0x9A,0x86,0x53,0x07,0xB0,0xEF,0xAC,0x06,0x78,0xF8,0x84,0x99, +0xFE,0x21,0x8D,0x4C,0x80,0xB6,0x0C,0x82,0xF6,0x66,0x70,0x79,0x1A,0xD3,0x4F,0xA3, +0xCF,0xF1,0xCF,0x46,0xB0,0x4B,0x0F,0x3E,0xDD,0x88,0x62,0xB8,0x8C,0xA9,0x09,0x28, +0x3B,0x7A,0xC7,0x97,0xE1,0x1E,0xE5,0xF4,0x9F,0xC0,0xC0,0xAE,0x24,0xA0,0xC8,0xA1, +0xD9,0x0F,0xD6,0x7B,0x26,0x82,0x69,0x32,0x3D,0xA7,0x02,0x03,0x01,0x00,0x01,0xA3, +0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x00, +0xAD,0xD9,0xA3,0xF6,0x79,0xF6,0x6E,0x74,0xA9,0x7F,0x33,0x3D,0x81,0x17,0xD7,0x4C, +0xCF,0x33,0xDE,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14, +0x00,0xAD,0xD9,0xA3,0xF6,0x79,0xF6,0x6E,0x74,0xA9,0x7F,0x33,0x3D,0x81,0x17,0xD7, +0x4C,0xCF,0x33,0xDE,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x7C,0x8A,0xD1,0x1F,0x18,0x37,0x82,0xE0, +0xB8,0xB0,0xA3,0xED,0x56,0x95,0xC8,0x62,0x61,0x9C,0x05,0xA2,0xCD,0xC2,0x62,0x26, +0x61,0xCD,0x10,0x16,0xD7,0xCC,0xB4,0x65,0x34,0xD0,0x11,0x8A,0xAD,0xA8,0xA9,0x05, +0x66,0xEF,0x74,0xF3,0x6D,0x5F,0x9D,0x99,0xAF,0xF6,0x8B,0xFB,0xEB,0x52,0xB2,0x05, +0x98,0xA2,0x6F,0x2A,0xC5,0x54,0xBD,0x25,0xBD,0x5F,0xAE,0xC8,0x86,0xEA,0x46,0x2C, +0xC1,0xB3,0xBD,0xC1,0xE9,0x49,0x70,0x18,0x16,0x97,0x08,0x13,0x8C,0x20,0xE0,0x1B, +0x2E,0x3A,0x47,0xCB,0x1E,0xE4,0x00,0x30,0x95,0x5B,0xF4,0x45,0xA3,0xC0,0x1A,0xB0, +0x01,0x4E,0xAB,0xBD,0xC0,0x23,0x6E,0x63,0x3F,0x80,0x4A,0xC5,0x07,0xED,0xDC,0xE2, +0x6F,0xC7,0xC1,0x62,0xF1,0xE3,0x72,0xD6,0x04,0xC8,0x74,0x67,0x0B,0xFA,0x88,0xAB, +0xA1,0x01,0xC8,0x6F,0xF0,0x14,0xAF,0xD2,0x99,0xCD,0x51,0x93,0x7E,0xED,0x2E,0x38, +0xC7,0xBD,0xCE,0x46,0x50,0x3D,0x72,0xE3,0x79,0x25,0x9D,0x9B,0x88,0x2B,0x10,0x20, +0xDD,0xA5,0xB8,0x32,0x9F,0x8D,0xE0,0x29,0xDF,0x21,0x74,0x86,0x82,0xDB,0x2F,0x82, +0x30,0xC6,0xC7,0x35,0x86,0xB3,0xF9,0x96,0x5F,0x46,0xDB,0x0C,0x45,0xFD,0xF3,0x50, +0xC3,0x6F,0xC6,0xC3,0x48,0xAD,0x46,0xA6,0xE1,0x27,0x47,0x0A,0x1D,0x0E,0x9B,0xB6, +0xC2,0x77,0x7F,0x63,0xF2,0xE0,0x7D,0x1A,0xBE,0xFC,0xE0,0xDF,0xD7,0xC7,0xA7,0x6C, +0xB0,0xF9,0xAE,0xBA,0x3C,0xFD,0x74,0xB4,0x11,0xE8,0x58,0x0D,0x80,0xBC,0xD3,0xA8, +0x80,0x3A,0x99,0xED,0x75,0xCC,0x46,0x7B, +}; + + +/* subject:/C=US/O=America Online Inc./CN=America Online Root Certification Authority 2 */ +/* issuer :/C=US/O=America Online Inc./CN=America Online Root Certification Authority 2 */ + + +const unsigned char America_Online_Root_Certification_Authority_2_certificate[1448]={ +0x30,0x82,0x05,0xA4,0x30,0x82,0x03,0x8C,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C, +0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x41,0x6D,0x65,0x72,0x69,0x63,0x61, +0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x36,0x30,0x34, +0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x41,0x6D,0x65,0x72,0x69,0x63,0x61,0x20,0x4F, +0x6E,0x6C,0x69,0x6E,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x20,0x32,0x30,0x1E,0x17,0x0D,0x30,0x32,0x30,0x35,0x32,0x38,0x30,0x36, +0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x30,0x39,0x32,0x39,0x31,0x34,0x30, +0x38,0x30,0x30,0x5A,0x30,0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x41,0x6D, +0x65,0x72,0x69,0x63,0x61,0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x36,0x30,0x34,0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x41,0x6D,0x65,0x72, +0x69,0x63,0x61,0x20,0x4F,0x6E,0x6C,0x69,0x6E,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75, +0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x32,0x30,0x82,0x02,0x22,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0F, +0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xCC,0x41,0x45,0x1D,0xE9,0x3D, +0x4D,0x10,0xF6,0x8C,0xB1,0x41,0xC9,0xE0,0x5E,0xCB,0x0D,0xB7,0xBF,0x47,0x73,0xD3, +0xF0,0x55,0x4D,0xDD,0xC6,0x0C,0xFA,0xB1,0x66,0x05,0x6A,0xCD,0x78,0xB4,0xDC,0x02, +0xDB,0x4E,0x81,0xF3,0xD7,0xA7,0x7C,0x71,0xBC,0x75,0x63,0xA0,0x5D,0xE3,0x07,0x0C, +0x48,0xEC,0x25,0xC4,0x03,0x20,0xF4,0xFF,0x0E,0x3B,0x12,0xFF,0x9B,0x8D,0xE1,0xC6, +0xD5,0x1B,0xB4,0x6D,0x22,0xE3,0xB1,0xDB,0x7F,0x21,0x64,0xAF,0x86,0xBC,0x57,0x22, +0x2A,0xD6,0x47,0x81,0x57,0x44,0x82,0x56,0x53,0xBD,0x86,0x14,0x01,0x0B,0xFC,0x7F, +0x74,0xA4,0x5A,0xAE,0xF1,0xBA,0x11,0xB5,0x9B,0x58,0x5A,0x80,0xB4,0x37,0x78,0x09, +0x33,0x7C,0x32,0x47,0x03,0x5C,0xC4,0xA5,0x83,0x48,0xF4,0x57,0x56,0x6E,0x81,0x36, +0x27,0x18,0x4F,0xEC,0x9B,0x28,0xC2,0xD4,0xB4,0xD7,0x7C,0x0C,0x3E,0x0C,0x2B,0xDF, +0xCA,0x04,0xD7,0xC6,0x8E,0xEA,0x58,0x4E,0xA8,0xA4,0xA5,0x18,0x1C,0x6C,0x45,0x98, +0xA3,0x41,0xD1,0x2D,0xD2,0xC7,0x6D,0x8D,0x19,0xF1,0xAD,0x79,0xB7,0x81,0x3F,0xBD, +0x06,0x82,0x27,0x2D,0x10,0x58,0x05,0xB5,0x78,0x05,0xB9,0x2F,0xDB,0x0C,0x6B,0x90, +0x90,0x7E,0x14,0x59,0x38,0xBB,0x94,0x24,0x13,0xE5,0xD1,0x9D,0x14,0xDF,0xD3,0x82, +0x4D,0x46,0xF0,0x80,0x39,0x52,0x32,0x0F,0xE3,0x84,0xB2,0x7A,0x43,0xF2,0x5E,0xDE, +0x5F,0x3F,0x1D,0xDD,0xE3,0xB2,0x1B,0xA0,0xA1,0x2A,0x23,0x03,0x6E,0x2E,0x01,0x15, +0x87,0x5C,0xA6,0x75,0x75,0xC7,0x97,0x61,0xBE,0xDE,0x86,0xDC,0xD4,0x48,0xDB,0xBD, +0x2A,0xBF,0x4A,0x55,0xDA,0xE8,0x7D,0x50,0xFB,0xB4,0x80,0x17,0xB8,0x94,0xBF,0x01, +0x3D,0xEA,0xDA,0xBA,0x7C,0xE0,0x58,0x67,0x17,0xB9,0x58,0xE0,0x88,0x86,0x46,0x67, +0x6C,0x9D,0x10,0x47,0x58,0x32,0xD0,0x35,0x7C,0x79,0x2A,0x90,0xA2,0x5A,0x10,0x11, +0x23,0x35,0xAD,0x2F,0xCC,0xE4,0x4A,0x5B,0xA7,0xC8,0x27,0xF2,0x83,0xDE,0x5E,0xBB, +0x5E,0x77,0xE7,0xE8,0xA5,0x6E,0x63,0xC2,0x0D,0x5D,0x61,0xD0,0x8C,0xD2,0x6C,0x5A, +0x21,0x0E,0xCA,0x28,0xA3,0xCE,0x2A,0xE9,0x95,0xC7,0x48,0xCF,0x96,0x6F,0x1D,0x92, +0x25,0xC8,0xC6,0xC6,0xC1,0xC1,0x0C,0x05,0xAC,0x26,0xC4,0xD2,0x75,0xD2,0xE1,0x2A, +0x67,0xC0,0x3D,0x5B,0xA5,0x9A,0xEB,0xCF,0x7B,0x1A,0xA8,0x9D,0x14,0x45,0xE5,0x0F, +0xA0,0x9A,0x65,0xDE,0x2F,0x28,0xBD,0xCE,0x6F,0x94,0x66,0x83,0x48,0x29,0xD8,0xEA, +0x65,0x8C,0xAF,0x93,0xD9,0x64,0x9F,0x55,0x57,0x26,0xBF,0x6F,0xCB,0x37,0x31,0x99, +0xA3,0x60,0xBB,0x1C,0xAD,0x89,0x34,0x32,0x62,0xB8,0x43,0x21,0x06,0x72,0x0C,0xA1, +0x5C,0x6D,0x46,0xC5,0xFA,0x29,0xCF,0x30,0xDE,0x89,0xDC,0x71,0x5B,0xDD,0xB6,0x37, +0x3E,0xDF,0x50,0xF5,0xB8,0x07,0x25,0x26,0xE5,0xBC,0xB5,0xFE,0x3C,0x02,0xB3,0xB7, +0xF8,0xBE,0x43,0xC1,0x87,0x11,0x94,0x9E,0x23,0x6C,0x17,0x8A,0xB8,0x8A,0x27,0x0C, +0x54,0x47,0xF0,0xA9,0xB3,0xC0,0x80,0x8C,0xA0,0x27,0xEB,0x1D,0x19,0xE3,0x07,0x8E, +0x77,0x70,0xCA,0x2B,0xF4,0x7D,0x76,0xE0,0x78,0x67,0x02,0x03,0x01,0x00,0x01,0xA3, +0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4D, +0x45,0xC1,0x68,0x38,0xBB,0x73,0xA9,0x69,0xA1,0x20,0xE7,0xED,0xF5,0x22,0xA1,0x23, +0x14,0xD7,0x9E,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14, +0x4D,0x45,0xC1,0x68,0x38,0xBB,0x73,0xA9,0x69,0xA1,0x20,0xE7,0xED,0xF5,0x22,0xA1, +0x23,0x14,0xD7,0x9E,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x05,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x67,0x6B,0x06,0xB9,0x5F,0x45,0x3B,0x2A, +0x4B,0x33,0xB3,0xE6,0x1B,0x6B,0x59,0x4E,0x22,0xCC,0xB9,0xB7,0xA4,0x25,0xC9,0xA7, +0xC4,0xF0,0x54,0x96,0x0B,0x64,0xF3,0xB1,0x58,0x4F,0x5E,0x51,0xFC,0xB2,0x97,0x7B, +0x27,0x65,0xC2,0xE5,0xCA,0xE7,0x0D,0x0C,0x25,0x7B,0x62,0xE3,0xFA,0x9F,0xB4,0x87, +0xB7,0x45,0x46,0xAF,0x83,0xA5,0x97,0x48,0x8C,0xA5,0xBD,0xF1,0x16,0x2B,0x9B,0x76, +0x2C,0x7A,0x35,0x60,0x6C,0x11,0x80,0x97,0xCC,0xA9,0x92,0x52,0xE6,0x2B,0xE6,0x69, +0xED,0xA9,0xF8,0x36,0x2D,0x2C,0x77,0xBF,0x61,0x48,0xD1,0x63,0x0B,0xB9,0x5B,0x52, +0xED,0x18,0xB0,0x43,0x42,0x22,0xA6,0xB1,0x77,0xAE,0xDE,0x69,0xC5,0xCD,0xC7,0x1C, +0xA1,0xB1,0xA5,0x1C,0x10,0xFB,0x18,0xBE,0x1A,0x70,0xDD,0xC1,0x92,0x4B,0xBE,0x29, +0x5A,0x9D,0x3F,0x35,0xBE,0xE5,0x7D,0x51,0xF8,0x55,0xE0,0x25,0x75,0x23,0x87,0x1E, +0x5C,0xDC,0xBA,0x9D,0xB0,0xAC,0xB3,0x69,0xDB,0x17,0x83,0xC9,0xF7,0xDE,0x0C,0xBC, +0x08,0xDC,0x91,0x9E,0xA8,0xD0,0xD7,0x15,0x37,0x73,0xA5,0x35,0xB8,0xFC,0x7E,0xC5, +0x44,0x40,0x06,0xC3,0xEB,0xF8,0x22,0x80,0x5C,0x47,0xCE,0x02,0xE3,0x11,0x9F,0x44, +0xFF,0xFD,0x9A,0x32,0xCC,0x7D,0x64,0x51,0x0E,0xEB,0x57,0x26,0x76,0x3A,0xE3,0x1E, +0x22,0x3C,0xC2,0xA6,0x36,0xDD,0x19,0xEF,0xA7,0xFC,0x12,0xF3,0x26,0xC0,0x59,0x31, +0x85,0x4C,0x9C,0xD8,0xCF,0xDF,0xA4,0xCC,0xCC,0x29,0x93,0xFF,0x94,0x6D,0x76,0x5C, +0x13,0x08,0x97,0xF2,0xED,0xA5,0x0B,0x4D,0xDD,0xE8,0xC9,0x68,0x0E,0x66,0xD3,0x00, +0x0E,0x33,0x12,0x5B,0xBC,0x95,0xE5,0x32,0x90,0xA8,0xB3,0xC6,0x6C,0x83,0xAD,0x77, +0xEE,0x8B,0x7E,0x7E,0xB1,0xA9,0xAB,0xD3,0xE1,0xF1,0xB6,0xC0,0xB1,0xEA,0x88,0xC0, +0xE7,0xD3,0x90,0xE9,0x28,0x92,0x94,0x7B,0x68,0x7B,0x97,0x2A,0x0A,0x67,0x2D,0x85, +0x02,0x38,0x10,0xE4,0x03,0x61,0xD4,0xDA,0x25,0x36,0xC7,0x08,0x58,0x2D,0xA1,0xA7, +0x51,0xAF,0x30,0x0A,0x49,0xF5,0xA6,0x69,0x87,0x07,0x2D,0x44,0x46,0x76,0x8E,0x2A, +0xE5,0x9A,0x3B,0xD7,0x18,0xA2,0xFC,0x9C,0x38,0x10,0xCC,0xC6,0x3B,0xD2,0xB5,0x17, +0x3A,0x6F,0xFD,0xAE,0x25,0xBD,0xF5,0x72,0x59,0x64,0xB1,0x74,0x2A,0x38,0x5F,0x18, +0x4C,0xDF,0xCF,0x71,0x04,0x5A,0x36,0xD4,0xBF,0x2F,0x99,0x9C,0xE8,0xD9,0xBA,0xB1, +0x95,0xE6,0x02,0x4B,0x21,0xA1,0x5B,0xD5,0xC1,0x4F,0x8F,0xAE,0x69,0x6D,0x53,0xDB, +0x01,0x93,0xB5,0x5C,0x1E,0x18,0xDD,0x64,0x5A,0xCA,0x18,0x28,0x3E,0x63,0x04,0x11, +0xFD,0x1C,0x8D,0x00,0x0F,0xB8,0x37,0xDF,0x67,0x8A,0x9D,0x66,0xA9,0x02,0x6A,0x91, +0xFF,0x13,0xCA,0x2F,0x5D,0x83,0xBC,0x87,0x93,0x6C,0xDC,0x24,0x51,0x16,0x04,0x25, +0x66,0xFA,0xB3,0xD9,0xC2,0xBA,0x29,0xBE,0x9A,0x48,0x38,0x82,0x99,0xF4,0xBF,0x3B, +0x4A,0x31,0x19,0xF9,0xBF,0x8E,0x21,0x33,0x14,0xCA,0x4F,0x54,0x5F,0xFB,0xCE,0xFB, +0x8F,0x71,0x7F,0xFD,0x5E,0x19,0xA0,0x0F,0x4B,0x91,0xB8,0xC4,0x54,0xBC,0x06,0xB0, +0x45,0x8F,0x26,0x91,0xA2,0x8E,0xFE,0xA9, +}; + + +/* subject:/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ +/* issuer :/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ + + +const unsigned char Baltimore_CyberTrust_Root_certificate[891]={ +0x30,0x82,0x03,0x77,0x30,0x82,0x02,0x5F,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x02, +0x00,0x00,0xB9,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49, +0x45,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74, +0x69,0x6D,0x6F,0x72,0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A, +0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03, +0x55,0x04,0x03,0x13,0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43, +0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E, +0x17,0x0D,0x30,0x30,0x30,0x35,0x31,0x32,0x31,0x38,0x34,0x36,0x30,0x30,0x5A,0x17, +0x0D,0x32,0x35,0x30,0x35,0x31,0x32,0x32,0x33,0x35,0x39,0x30,0x30,0x5A,0x30,0x5A, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x45,0x31,0x12,0x30, +0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72, +0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A,0x43,0x79,0x62,0x65, +0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x13, +0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43,0x79,0x62,0x65,0x72, +0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x82,0x01,0x22,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, +0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xA3,0x04,0xBB,0x22,0xAB, +0x98,0x3D,0x57,0xE8,0x26,0x72,0x9A,0xB5,0x79,0xD4,0x29,0xE2,0xE1,0xE8,0x95,0x80, +0xB1,0xB0,0xE3,0x5B,0x8E,0x2B,0x29,0x9A,0x64,0xDF,0xA1,0x5D,0xED,0xB0,0x09,0x05, +0x6D,0xDB,0x28,0x2E,0xCE,0x62,0xA2,0x62,0xFE,0xB4,0x88,0xDA,0x12,0xEB,0x38,0xEB, +0x21,0x9D,0xC0,0x41,0x2B,0x01,0x52,0x7B,0x88,0x77,0xD3,0x1C,0x8F,0xC7,0xBA,0xB9, +0x88,0xB5,0x6A,0x09,0xE7,0x73,0xE8,0x11,0x40,0xA7,0xD1,0xCC,0xCA,0x62,0x8D,0x2D, +0xE5,0x8F,0x0B,0xA6,0x50,0xD2,0xA8,0x50,0xC3,0x28,0xEA,0xF5,0xAB,0x25,0x87,0x8A, +0x9A,0x96,0x1C,0xA9,0x67,0xB8,0x3F,0x0C,0xD5,0xF7,0xF9,0x52,0x13,0x2F,0xC2,0x1B, +0xD5,0x70,0x70,0xF0,0x8F,0xC0,0x12,0xCA,0x06,0xCB,0x9A,0xE1,0xD9,0xCA,0x33,0x7A, +0x77,0xD6,0xF8,0xEC,0xB9,0xF1,0x68,0x44,0x42,0x48,0x13,0xD2,0xC0,0xC2,0xA4,0xAE, +0x5E,0x60,0xFE,0xB6,0xA6,0x05,0xFC,0xB4,0xDD,0x07,0x59,0x02,0xD4,0x59,0x18,0x98, +0x63,0xF5,0xA5,0x63,0xE0,0x90,0x0C,0x7D,0x5D,0xB2,0x06,0x7A,0xF3,0x85,0xEA,0xEB, +0xD4,0x03,0xAE,0x5E,0x84,0x3E,0x5F,0xFF,0x15,0xED,0x69,0xBC,0xF9,0x39,0x36,0x72, +0x75,0xCF,0x77,0x52,0x4D,0xF3,0xC9,0x90,0x2C,0xB9,0x3D,0xE5,0xC9,0x23,0x53,0x3F, +0x1F,0x24,0x98,0x21,0x5C,0x07,0x99,0x29,0xBD,0xC6,0x3A,0xEC,0xE7,0x6E,0x86,0x3A, +0x6B,0x97,0x74,0x63,0x33,0xBD,0x68,0x18,0x31,0xF0,0x78,0x8D,0x76,0xBF,0xFC,0x9E, +0x8E,0x5D,0x2A,0x86,0xA7,0x4D,0x90,0xDC,0x27,0x1A,0x39,0x02,0x03,0x01,0x00,0x01, +0xA3,0x45,0x30,0x43,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xE5, +0x9D,0x59,0x30,0x82,0x47,0x58,0xCC,0xAC,0xFA,0x08,0x54,0x36,0x86,0x7B,0x3A,0xB5, +0x04,0x4D,0xF0,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30, +0x06,0x01,0x01,0xFF,0x02,0x01,0x03,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, +0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x85,0x0C,0x5D,0x8E,0xE4, +0x6F,0x51,0x68,0x42,0x05,0xA0,0xDD,0xBB,0x4F,0x27,0x25,0x84,0x03,0xBD,0xF7,0x64, +0xFD,0x2D,0xD7,0x30,0xE3,0xA4,0x10,0x17,0xEB,0xDA,0x29,0x29,0xB6,0x79,0x3F,0x76, +0xF6,0x19,0x13,0x23,0xB8,0x10,0x0A,0xF9,0x58,0xA4,0xD4,0x61,0x70,0xBD,0x04,0x61, +0x6A,0x12,0x8A,0x17,0xD5,0x0A,0xBD,0xC5,0xBC,0x30,0x7C,0xD6,0xE9,0x0C,0x25,0x8D, +0x86,0x40,0x4F,0xEC,0xCC,0xA3,0x7E,0x38,0xC6,0x37,0x11,0x4F,0xED,0xDD,0x68,0x31, +0x8E,0x4C,0xD2,0xB3,0x01,0x74,0xEE,0xBE,0x75,0x5E,0x07,0x48,0x1A,0x7F,0x70,0xFF, +0x16,0x5C,0x84,0xC0,0x79,0x85,0xB8,0x05,0xFD,0x7F,0xBE,0x65,0x11,0xA3,0x0F,0xC0, +0x02,0xB4,0xF8,0x52,0x37,0x39,0x04,0xD5,0xA9,0x31,0x7A,0x18,0xBF,0xA0,0x2A,0xF4, +0x12,0x99,0xF7,0xA3,0x45,0x82,0xE3,0x3C,0x5E,0xF5,0x9D,0x9E,0xB5,0xC8,0x9E,0x7C, +0x2E,0xC8,0xA4,0x9E,0x4E,0x08,0x14,0x4B,0x6D,0xFD,0x70,0x6D,0x6B,0x1A,0x63,0xBD, +0x64,0xE6,0x1F,0xB7,0xCE,0xF0,0xF2,0x9F,0x2E,0xBB,0x1B,0xB7,0xF2,0x50,0x88,0x73, +0x92,0xC2,0xE2,0xE3,0x16,0x8D,0x9A,0x32,0x02,0xAB,0x8E,0x18,0xDD,0xE9,0x10,0x11, +0xEE,0x7E,0x35,0xAB,0x90,0xAF,0x3E,0x30,0x94,0x7A,0xD0,0x33,0x3D,0xA7,0x65,0x0F, +0xF5,0xFC,0x8E,0x9E,0x62,0xCF,0x47,0x44,0x2C,0x01,0x5D,0xBB,0x1D,0xB5,0x32,0xD2, +0x47,0xD2,0x38,0x2E,0xD0,0xFE,0x81,0xDC,0x32,0x6A,0x1E,0xB5,0xEE,0x3C,0xD5,0xFC, +0xE7,0x81,0x1D,0x19,0xC3,0x24,0x42,0xEA,0x63,0x39,0xA9, +}; + + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=AAA Certificate Services */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=AAA Certificate Services */ + + +const unsigned char Comodo_AAA_Services_root_certificate[1078]={ +0x30,0x82,0x04,0x32,0x30,0x82,0x03,0x1A,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x7B,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x21,0x30,0x1F,0x06,0x03,0x55, +0x04,0x03,0x0C,0x18,0x41,0x41,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30,0x1E,0x17,0x0D, +0x30,0x34,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32, +0x38,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x7B,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06, +0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61, +0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04, +0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03, +0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43,0x41,0x20,0x4C, +0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C, +0x18,0x41,0x41,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65, +0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30,0x82,0x01,0x22,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F, +0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xBE,0x40,0x9D,0xF4,0x6E,0xE1, +0xEA,0x76,0x87,0x1C,0x4D,0x45,0x44,0x8E,0xBE,0x46,0xC8,0x83,0x06,0x9D,0xC1,0x2A, +0xFE,0x18,0x1F,0x8E,0xE4,0x02,0xFA,0xF3,0xAB,0x5D,0x50,0x8A,0x16,0x31,0x0B,0x9A, +0x06,0xD0,0xC5,0x70,0x22,0xCD,0x49,0x2D,0x54,0x63,0xCC,0xB6,0x6E,0x68,0x46,0x0B, +0x53,0xEA,0xCB,0x4C,0x24,0xC0,0xBC,0x72,0x4E,0xEA,0xF1,0x15,0xAE,0xF4,0x54,0x9A, +0x12,0x0A,0xC3,0x7A,0xB2,0x33,0x60,0xE2,0xDA,0x89,0x55,0xF3,0x22,0x58,0xF3,0xDE, +0xDC,0xCF,0xEF,0x83,0x86,0xA2,0x8C,0x94,0x4F,0x9F,0x68,0xF2,0x98,0x90,0x46,0x84, +0x27,0xC7,0x76,0xBF,0xE3,0xCC,0x35,0x2C,0x8B,0x5E,0x07,0x64,0x65,0x82,0xC0,0x48, +0xB0,0xA8,0x91,0xF9,0x61,0x9F,0x76,0x20,0x50,0xA8,0x91,0xC7,0x66,0xB5,0xEB,0x78, +0x62,0x03,0x56,0xF0,0x8A,0x1A,0x13,0xEA,0x31,0xA3,0x1E,0xA0,0x99,0xFD,0x38,0xF6, +0xF6,0x27,0x32,0x58,0x6F,0x07,0xF5,0x6B,0xB8,0xFB,0x14,0x2B,0xAF,0xB7,0xAA,0xCC, +0xD6,0x63,0x5F,0x73,0x8C,0xDA,0x05,0x99,0xA8,0x38,0xA8,0xCB,0x17,0x78,0x36,0x51, +0xAC,0xE9,0x9E,0xF4,0x78,0x3A,0x8D,0xCF,0x0F,0xD9,0x42,0xE2,0x98,0x0C,0xAB,0x2F, +0x9F,0x0E,0x01,0xDE,0xEF,0x9F,0x99,0x49,0xF1,0x2D,0xDF,0xAC,0x74,0x4D,0x1B,0x98, +0xB5,0x47,0xC5,0xE5,0x29,0xD1,0xF9,0x90,0x18,0xC7,0x62,0x9C,0xBE,0x83,0xC7,0x26, +0x7B,0x3E,0x8A,0x25,0xC7,0xC0,0xDD,0x9D,0xE6,0x35,0x68,0x10,0x20,0x9D,0x8F,0xD8, +0xDE,0xD2,0xC3,0x84,0x9C,0x0D,0x5E,0xE8,0x2F,0xC9,0x02,0x03,0x01,0x00,0x01,0xA3, +0x81,0xC0,0x30,0x81,0xBD,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, +0xA0,0x11,0x0A,0x23,0x3E,0x96,0xF1,0x07,0xEC,0xE2,0xAF,0x29,0xEF,0x82,0xA5,0x7F, +0xD0,0x30,0xA4,0xB4,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x7B,0x06,0x03,0x55,0x1D,0x1F,0x04,0x74,0x30,0x72, +0x30,0x38,0xA0,0x36,0xA0,0x34,0x86,0x32,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63, +0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F, +0x41,0x41,0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65, +0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63,0x72,0x6C,0x30,0x36,0xA0,0x34,0xA0,0x32, +0x86,0x30,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D, +0x6F,0x64,0x6F,0x2E,0x6E,0x65,0x74,0x2F,0x41,0x41,0x41,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63, +0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05, +0x00,0x03,0x82,0x01,0x01,0x00,0x08,0x56,0xFC,0x02,0xF0,0x9B,0xE8,0xFF,0xA4,0xFA, +0xD6,0x7B,0xC6,0x44,0x80,0xCE,0x4F,0xC4,0xC5,0xF6,0x00,0x58,0xCC,0xA6,0xB6,0xBC, +0x14,0x49,0x68,0x04,0x76,0xE8,0xE6,0xEE,0x5D,0xEC,0x02,0x0F,0x60,0xD6,0x8D,0x50, +0x18,0x4F,0x26,0x4E,0x01,0xE3,0xE6,0xB0,0xA5,0xEE,0xBF,0xBC,0x74,0x54,0x41,0xBF, +0xFD,0xFC,0x12,0xB8,0xC7,0x4F,0x5A,0xF4,0x89,0x60,0x05,0x7F,0x60,0xB7,0x05,0x4A, +0xF3,0xF6,0xF1,0xC2,0xBF,0xC4,0xB9,0x74,0x86,0xB6,0x2D,0x7D,0x6B,0xCC,0xD2,0xF3, +0x46,0xDD,0x2F,0xC6,0xE0,0x6A,0xC3,0xC3,0x34,0x03,0x2C,0x7D,0x96,0xDD,0x5A,0xC2, +0x0E,0xA7,0x0A,0x99,0xC1,0x05,0x8B,0xAB,0x0C,0x2F,0xF3,0x5C,0x3A,0xCF,0x6C,0x37, +0x55,0x09,0x87,0xDE,0x53,0x40,0x6C,0x58,0xEF,0xFC,0xB6,0xAB,0x65,0x6E,0x04,0xF6, +0x1B,0xDC,0x3C,0xE0,0x5A,0x15,0xC6,0x9E,0xD9,0xF1,0x59,0x48,0x30,0x21,0x65,0x03, +0x6C,0xEC,0xE9,0x21,0x73,0xEC,0x9B,0x03,0xA1,0xE0,0x37,0xAD,0xA0,0x15,0x18,0x8F, +0xFA,0xBA,0x02,0xCE,0xA7,0x2C,0xA9,0x10,0x13,0x2C,0xD4,0xE5,0x08,0x26,0xAB,0x22, +0x97,0x60,0xF8,0x90,0x5E,0x74,0xD4,0xA2,0x9A,0x53,0xBD,0xF2,0xA9,0x68,0xE0,0xA2, +0x6E,0xC2,0xD7,0x6C,0xB1,0xA3,0x0F,0x9E,0xBF,0xEB,0x68,0xE7,0x56,0xF2,0xAE,0xF2, +0xE3,0x2B,0x38,0x3A,0x09,0x81,0xB5,0x6B,0x85,0xD7,0xBE,0x2D,0xED,0x3F,0x1A,0xB7, +0xB2,0x63,0xE2,0xF5,0x62,0x2C,0x82,0xD4,0x6A,0x00,0x41,0x50,0xF1,0x39,0x83,0x9F, +0x95,0xE9,0x36,0x96,0x98,0x6E, +}; + + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Certification Authority */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Certification Authority */ + + +const unsigned char COMODO_Certification_Authority_certificate[1057]={ +0x30,0x82,0x04,0x1D,0x30,0x82,0x03,0x05,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4E, +0x81,0x2D,0x8A,0x82,0x65,0xE0,0x0B,0x02,0xEE,0x3E,0x35,0x02,0x46,0xE5,0x3D,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, +0x81,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x27,0x30,0x25,0x06,0x03,0x55, +0x04,0x03,0x13,0x1E,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x32,0x30,0x31,0x30,0x30,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5A,0x30,0x81,0x81,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65, +0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31, +0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72, +0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F, +0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x27,0x30, +0x25,0x06,0x03,0x55,0x04,0x03,0x13,0x1E,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, +0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xD0,0x40,0x8B,0x8B,0x72,0xE3,0x91,0x1B,0xF7, +0x51,0xC1,0x1B,0x54,0x04,0x98,0xD3,0xA9,0xBF,0xC1,0xE6,0x8A,0x5D,0x3B,0x87,0xFB, +0xBB,0x88,0xCE,0x0D,0xE3,0x2F,0x3F,0x06,0x96,0xF0,0xA2,0x29,0x50,0x99,0xAE,0xDB, +0x3B,0xA1,0x57,0xB0,0x74,0x51,0x71,0xCD,0xED,0x42,0x91,0x4D,0x41,0xFE,0xA9,0xC8, +0xD8,0x6A,0x86,0x77,0x44,0xBB,0x59,0x66,0x97,0x50,0x5E,0xB4,0xD4,0x2C,0x70,0x44, +0xCF,0xDA,0x37,0x95,0x42,0x69,0x3C,0x30,0xC4,0x71,0xB3,0x52,0xF0,0x21,0x4D,0xA1, +0xD8,0xBA,0x39,0x7C,0x1C,0x9E,0xA3,0x24,0x9D,0xF2,0x83,0x16,0x98,0xAA,0x16,0x7C, +0x43,0x9B,0x15,0x5B,0xB7,0xAE,0x34,0x91,0xFE,0xD4,0x62,0x26,0x18,0x46,0x9A,0x3F, +0xEB,0xC1,0xF9,0xF1,0x90,0x57,0xEB,0xAC,0x7A,0x0D,0x8B,0xDB,0x72,0x30,0x6A,0x66, +0xD5,0xE0,0x46,0xA3,0x70,0xDC,0x68,0xD9,0xFF,0x04,0x48,0x89,0x77,0xDE,0xB5,0xE9, +0xFB,0x67,0x6D,0x41,0xE9,0xBC,0x39,0xBD,0x32,0xD9,0x62,0x02,0xF1,0xB1,0xA8,0x3D, +0x6E,0x37,0x9C,0xE2,0x2F,0xE2,0xD3,0xA2,0x26,0x8B,0xC6,0xB8,0x55,0x43,0x88,0xE1, +0x23,0x3E,0xA5,0xD2,0x24,0x39,0x6A,0x47,0xAB,0x00,0xD4,0xA1,0xB3,0xA9,0x25,0xFE, +0x0D,0x3F,0xA7,0x1D,0xBA,0xD3,0x51,0xC1,0x0B,0xA4,0xDA,0xAC,0x38,0xEF,0x55,0x50, +0x24,0x05,0x65,0x46,0x93,0x34,0x4F,0x2D,0x8D,0xAD,0xC6,0xD4,0x21,0x19,0xD2,0x8E, +0xCA,0x05,0x61,0x71,0x07,0x73,0x47,0xE5,0x8A,0x19,0x12,0xBD,0x04,0x4D,0xCE,0x4E, +0x9C,0xA5,0x48,0xAC,0xBB,0x26,0xF7,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x8E,0x30, +0x81,0x8B,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x0B,0x58,0xE5, +0x8B,0xC6,0x4C,0x15,0x37,0xA4,0x40,0xA9,0x30,0xA9,0x21,0xBE,0x47,0x36,0x5A,0x56, +0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, +0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01, +0x01,0xFF,0x30,0x49,0x06,0x03,0x55,0x1D,0x1F,0x04,0x42,0x30,0x40,0x30,0x3E,0xA0, +0x3C,0xA0,0x3A,0x86,0x38,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E, +0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4F,0x4D, +0x4F,0x44,0x4F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x2E,0x63,0x72,0x6C,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01, +0x00,0x3E,0x98,0x9E,0x9B,0xF6,0x1B,0xE9,0xD7,0x39,0xB7,0x78,0xAE,0x1D,0x72,0x18, +0x49,0xD3,0x87,0xE4,0x43,0x82,0xEB,0x3F,0xC9,0xAA,0xF5,0xA8,0xB5,0xEF,0x55,0x7C, +0x21,0x52,0x65,0xF9,0xD5,0x0D,0xE1,0x6C,0xF4,0x3E,0x8C,0x93,0x73,0x91,0x2E,0x02, +0xC4,0x4E,0x07,0x71,0x6F,0xC0,0x8F,0x38,0x61,0x08,0xA8,0x1E,0x81,0x0A,0xC0,0x2F, +0x20,0x2F,0x41,0x8B,0x91,0xDC,0x48,0x45,0xBC,0xF1,0xC6,0xDE,0xBA,0x76,0x6B,0x33, +0xC8,0x00,0x2D,0x31,0x46,0x4C,0xED,0xE7,0x9D,0xCF,0x88,0x94,0xFF,0x33,0xC0,0x56, +0xE8,0x24,0x86,0x26,0xB8,0xD8,0x38,0x38,0xDF,0x2A,0x6B,0xDD,0x12,0xCC,0xC7,0x3F, +0x47,0x17,0x4C,0xA2,0xC2,0x06,0x96,0x09,0xD6,0xDB,0xFE,0x3F,0x3C,0x46,0x41,0xDF, +0x58,0xE2,0x56,0x0F,0x3C,0x3B,0xC1,0x1C,0x93,0x35,0xD9,0x38,0x52,0xAC,0xEE,0xC8, +0xEC,0x2E,0x30,0x4E,0x94,0x35,0xB4,0x24,0x1F,0x4B,0x78,0x69,0xDA,0xF2,0x02,0x38, +0xCC,0x95,0x52,0x93,0xF0,0x70,0x25,0x59,0x9C,0x20,0x67,0xC4,0xEE,0xF9,0x8B,0x57, +0x61,0xF4,0x92,0x76,0x7D,0x3F,0x84,0x8D,0x55,0xB7,0xE8,0xE5,0xAC,0xD5,0xF1,0xF5, +0x19,0x56,0xA6,0x5A,0xFB,0x90,0x1C,0xAF,0x93,0xEB,0xE5,0x1C,0xD4,0x67,0x97,0x5D, +0x04,0x0E,0xBE,0x0B,0x83,0xA6,0x17,0x83,0xB9,0x30,0x12,0xA0,0xC5,0x33,0x15,0x05, +0xB9,0x0D,0xFB,0xC7,0x05,0x76,0xE3,0xD8,0x4A,0x8D,0xFC,0x34,0x17,0xA3,0xC6,0x21, +0x28,0xBE,0x30,0x45,0x31,0x1E,0xC7,0x78,0xBE,0x58,0x61,0x38,0xAC,0x3B,0xE2,0x01, +0x65, +}; + + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO ECC Certification Authority */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO ECC Certification Authority */ + + +const unsigned char COMODO_ECC_Certification_Authority_certificate[653]={ +0x30,0x82,0x02,0x89,0x30,0x82,0x02,0x0F,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x1F, +0x47,0xAF,0xAA,0x62,0x00,0x70,0x50,0x54,0x4C,0x01,0x9E,0x9B,0x63,0x99,0x2A,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x85,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06, +0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61, +0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04, +0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03, +0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C, +0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13, +0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x45,0x43,0x43,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x38,0x30,0x33,0x30,0x36,0x30,0x30,0x30, +0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32,0x33,0x35,0x39, +0x35,0x39,0x5A,0x30,0x81,0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72, +0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72, +0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F, +0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D, +0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B, +0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20, +0x45,0x43,0x43,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, +0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x76,0x30,0x10,0x06, +0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03, +0x62,0x00,0x04,0x03,0x47,0x7B,0x2F,0x75,0xC9,0x82,0x15,0x85,0xFB,0x75,0xE4,0x91, +0x16,0xD4,0xAB,0x62,0x99,0xF5,0x3E,0x52,0x0B,0x06,0xCE,0x41,0x00,0x7F,0x97,0xE1, +0x0A,0x24,0x3C,0x1D,0x01,0x04,0xEE,0x3D,0xD2,0x8D,0x09,0x97,0x0C,0xE0,0x75,0xE4, +0xFA,0xFB,0x77,0x8A,0x2A,0xF5,0x03,0x60,0x4B,0x36,0x8B,0x16,0x23,0x16,0xAD,0x09, +0x71,0xF4,0x4A,0xF4,0x28,0x50,0xB4,0xFE,0x88,0x1C,0x6E,0x3F,0x6C,0x2F,0x2F,0x09, +0x59,0x5B,0xA5,0x5B,0x0B,0x33,0x99,0xE2,0xC3,0x3D,0x89,0xF9,0x6A,0x2C,0xEF,0xB2, +0xD3,0x06,0xE9,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0x75,0x71,0xA7,0x19,0x48,0x19,0xBC,0x9D,0x9D,0xEA,0x41,0x47,0xDF,0x94, +0xC4,0x48,0x77,0x99,0xD3,0x79,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D, +0x04,0x03,0x03,0x03,0x68,0x00,0x30,0x65,0x02,0x31,0x00,0xEF,0x03,0x5B,0x7A,0xAC, +0xB7,0x78,0x0A,0x72,0xB7,0x88,0xDF,0xFF,0xB5,0x46,0x14,0x09,0x0A,0xFA,0xA0,0xE6, +0x7D,0x08,0xC6,0x1A,0x87,0xBD,0x18,0xA8,0x73,0xBD,0x26,0xCA,0x60,0x0C,0x9D,0xCE, +0x99,0x9F,0xCF,0x5C,0x0F,0x30,0xE1,0xBE,0x14,0x31,0xEA,0x02,0x30,0x14,0xF4,0x93, +0x3C,0x49,0xA7,0x33,0x7A,0x90,0x46,0x47,0xB3,0x63,0x7D,0x13,0x9B,0x4E,0xB7,0x6F, +0x18,0x37,0x80,0x53,0xFE,0xDD,0x20,0xE0,0x35,0x9A,0x36,0xD1,0xC7,0x01,0xB9,0xE6, +0xDC,0xDD,0xF3,0xFF,0x1D,0x2C,0x3A,0x16,0x57,0xD9,0x92,0x39,0xD6, +}; + + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Secure Certificate Services */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Secure Certificate Services */ + + +const unsigned char Comodo_Secure_Services_root_certificate[1091]={ +0x30,0x82,0x04,0x3F,0x30,0x82,0x03,0x27,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x7E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x24,0x30,0x22,0x06,0x03,0x55, +0x04,0x03,0x0C,0x1B,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30, +0x1E,0x17,0x0D,0x30,0x34,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A, +0x17,0x0D,0x32,0x38,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30, +0x7E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x24,0x30,0x22,0x06,0x03,0x55, +0x04,0x03,0x0C,0x1B,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30, +0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01, +0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00, +0xC0,0x71,0x33,0x82,0x8A,0xD0,0x70,0xEB,0x73,0x87,0x82,0x40,0xD5,0x1D,0xE4,0xCB, +0xC9,0x0E,0x42,0x90,0xF9,0xDE,0x34,0xB9,0xA1,0xBA,0x11,0xF4,0x25,0x85,0xF3,0xCC, +0x72,0x6D,0xF2,0x7B,0x97,0x6B,0xB3,0x07,0xF1,0x77,0x24,0x91,0x5F,0x25,0x8F,0xF6, +0x74,0x3D,0xE4,0x80,0xC2,0xF8,0x3C,0x0D,0xF3,0xBF,0x40,0xEA,0xF7,0xC8,0x52,0xD1, +0x72,0x6F,0xEF,0xC8,0xAB,0x41,0xB8,0x6E,0x2E,0x17,0x2A,0x95,0x69,0x0C,0xCD,0xD2, +0x1E,0x94,0x7B,0x2D,0x94,0x1D,0xAA,0x75,0xD7,0xB3,0x98,0xCB,0xAC,0xBC,0x64,0x53, +0x40,0xBC,0x8F,0xAC,0xAC,0x36,0xCB,0x5C,0xAD,0xBB,0xDD,0xE0,0x94,0x17,0xEC,0xD1, +0x5C,0xD0,0xBF,0xEF,0xA5,0x95,0xC9,0x90,0xC5,0xB0,0xAC,0xFB,0x1B,0x43,0xDF,0x7A, +0x08,0x5D,0xB7,0xB8,0xF2,0x40,0x1B,0x2B,0x27,0x9E,0x50,0xCE,0x5E,0x65,0x82,0x88, +0x8C,0x5E,0xD3,0x4E,0x0C,0x7A,0xEA,0x08,0x91,0xB6,0x36,0xAA,0x2B,0x42,0xFB,0xEA, +0xC2,0xA3,0x39,0xE5,0xDB,0x26,0x38,0xAD,0x8B,0x0A,0xEE,0x19,0x63,0xC7,0x1C,0x24, +0xDF,0x03,0x78,0xDA,0xE6,0xEA,0xC1,0x47,0x1A,0x0B,0x0B,0x46,0x09,0xDD,0x02,0xFC, +0xDE,0xCB,0x87,0x5F,0xD7,0x30,0x63,0x68,0xA1,0xAE,0xDC,0x32,0xA1,0xBA,0xBE,0xFE, +0x44,0xAB,0x68,0xB6,0xA5,0x17,0x15,0xFD,0xBD,0xD5,0xA7,0xA7,0x9A,0xE4,0x44,0x33, +0xE9,0x88,0x8E,0xFC,0xED,0x51,0xEB,0x93,0x71,0x4E,0xAD,0x01,0xE7,0x44,0x8E,0xAB, +0x2D,0xCB,0xA8,0xFE,0x01,0x49,0x48,0xF0,0xC0,0xDD,0xC7,0x68,0xD8,0x92,0xFE,0x3D, +0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xC7,0x30,0x81,0xC4,0x30,0x1D,0x06,0x03,0x55, +0x1D,0x0E,0x04,0x16,0x04,0x14,0x3C,0xD8,0x93,0x88,0xC2,0xC0,0x82,0x09,0xCC,0x01, +0x99,0x06,0x93,0x20,0xE9,0x9E,0x70,0x09,0x63,0x4F,0x30,0x0E,0x06,0x03,0x55,0x1D, +0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D, +0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x81,0x06,0x03, +0x55,0x1D,0x1F,0x04,0x7A,0x30,0x78,0x30,0x3B,0xA0,0x39,0xA0,0x37,0x86,0x35,0x68, +0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F, +0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x53,0x65,0x63,0x75,0x72,0x65,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, +0x2E,0x63,0x72,0x6C,0x30,0x39,0xA0,0x37,0xA0,0x35,0x86,0x33,0x68,0x74,0x74,0x70, +0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x2E,0x6E,0x65, +0x74,0x2F,0x53,0x65,0x63,0x75,0x72,0x65,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2E,0x63,0x72,0x6C,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0x87,0x01,0x6D,0x23,0x1D,0x7E,0x5B,0x17,0x7D,0xC1,0x61,0x32,0xCF, +0x8F,0xE7,0xF3,0x8A,0x94,0x59,0x66,0xE0,0x9E,0x28,0xA8,0x5E,0xD3,0xB7,0xF4,0x34, +0xE6,0xAA,0x39,0xB2,0x97,0x16,0xC5,0x82,0x6F,0x32,0xA4,0xE9,0x8C,0xE7,0xAF,0xFD, +0xEF,0xC2,0xE8,0xB9,0x4B,0xAA,0xA3,0xF4,0xE6,0xDA,0x8D,0x65,0x21,0xFB,0xBA,0x80, +0xEB,0x26,0x28,0x85,0x1A,0xFE,0x39,0x8C,0xDE,0x5B,0x04,0x04,0xB4,0x54,0xF9,0xA3, +0x67,0x9E,0x41,0xFA,0x09,0x52,0xCC,0x05,0x48,0xA8,0xC9,0x3F,0x21,0x04,0x1E,0xCE, +0x48,0x6B,0xFC,0x85,0xE8,0xC2,0x7B,0xAF,0x7F,0xB7,0xCC,0xF8,0x5F,0x3A,0xFD,0x35, +0xC6,0x0D,0xEF,0x97,0xDC,0x4C,0xAB,0x11,0xE1,0x6B,0xCB,0x31,0xD1,0x6C,0xFB,0x48, +0x80,0xAB,0xDC,0x9C,0x37,0xB8,0x21,0x14,0x4B,0x0D,0x71,0x3D,0xEC,0x83,0x33,0x6E, +0xD1,0x6E,0x32,0x16,0xEC,0x98,0xC7,0x16,0x8B,0x59,0xA6,0x34,0xAB,0x05,0x57,0x2D, +0x93,0xF7,0xAA,0x13,0xCB,0xD2,0x13,0xE2,0xB7,0x2E,0x3B,0xCD,0x6B,0x50,0x17,0x09, +0x68,0x3E,0xB5,0x26,0x57,0xEE,0xB6,0xE0,0xB6,0xDD,0xB9,0x29,0x80,0x79,0x7D,0x8F, +0xA3,0xF0,0xA4,0x28,0xA4,0x15,0xC4,0x85,0xF4,0x27,0xD4,0x6B,0xBF,0xE5,0x5C,0xE4, +0x65,0x02,0x76,0x54,0xB4,0xE3,0x37,0x66,0x24,0xD3,0x19,0x61,0xC8,0x52,0x10,0xE5, +0x8B,0x37,0x9A,0xB9,0xA9,0xF9,0x1D,0xBF,0xEA,0x99,0x92,0x61,0x96,0xFF,0x01,0xCD, +0xA1,0x5F,0x0D,0xBC,0x71,0xBC,0x0E,0xAC,0x0B,0x1D,0x47,0x45,0x1D,0xC1,0xEC,0x7C, +0xEC,0xFD,0x29, +}; + + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Trusted Certificate Services */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=Trusted Certificate Services */ + + +const unsigned char Comodo_Trusted_Services_root_certificate[1095]={ +0x30,0x82,0x04,0x43,0x30,0x82,0x03,0x2B,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x7F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72, +0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06, +0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30, +0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20,0x43, +0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x25,0x30,0x23,0x06,0x03,0x55, +0x04,0x03,0x0C,0x1C,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, +0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30, +0x5A,0x17,0x0D,0x32,0x38,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A, +0x30,0x7F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31, +0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x0C,0x12,0x47,0x72,0x65,0x61,0x74,0x65, +0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E, +0x06,0x03,0x55,0x04,0x07,0x0C,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A, +0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x0C,0x11,0x43,0x6F,0x6D,0x6F,0x64,0x6F,0x20, +0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x25,0x30,0x23,0x06,0x03, +0x55,0x04,0x03,0x0C,0x1C,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65, +0x73,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01, +0x01,0x00,0xDF,0x71,0x6F,0x36,0x58,0x53,0x5A,0xF2,0x36,0x54,0x57,0x80,0xC4,0x74, +0x08,0x20,0xED,0x18,0x7F,0x2A,0x1D,0xE6,0x35,0x9A,0x1E,0x25,0xAC,0x9C,0xE5,0x96, +0x7E,0x72,0x52,0xA0,0x15,0x42,0xDB,0x59,0xDD,0x64,0x7A,0x1A,0xD0,0xB8,0x7B,0xDD, +0x39,0x15,0xBC,0x55,0x48,0xC4,0xED,0x3A,0x00,0xEA,0x31,0x11,0xBA,0xF2,0x71,0x74, +0x1A,0x67,0xB8,0xCF,0x33,0xCC,0xA8,0x31,0xAF,0xA3,0xE3,0xD7,0x7F,0xBF,0x33,0x2D, +0x4C,0x6A,0x3C,0xEC,0x8B,0xC3,0x92,0xD2,0x53,0x77,0x24,0x74,0x9C,0x07,0x6E,0x70, +0xFC,0xBD,0x0B,0x5B,0x76,0xBA,0x5F,0xF2,0xFF,0xD7,0x37,0x4B,0x4A,0x60,0x78,0xF7, +0xF0,0xFA,0xCA,0x70,0xB4,0xEA,0x59,0xAA,0xA3,0xCE,0x48,0x2F,0xA9,0xC3,0xB2,0x0B, +0x7E,0x17,0x72,0x16,0x0C,0xA6,0x07,0x0C,0x1B,0x38,0xCF,0xC9,0x62,0xB7,0x3F,0xA0, +0x93,0xA5,0x87,0x41,0xF2,0xB7,0x70,0x40,0x77,0xD8,0xBE,0x14,0x7C,0xE3,0xA8,0xC0, +0x7A,0x8E,0xE9,0x63,0x6A,0xD1,0x0F,0x9A,0xC6,0xD2,0xF4,0x8B,0x3A,0x14,0x04,0x56, +0xD4,0xED,0xB8,0xCC,0x6E,0xF5,0xFB,0xE2,0x2C,0x58,0xBD,0x7F,0x4F,0x6B,0x2B,0xF7, +0x60,0x24,0x58,0x24,0xCE,0x26,0xEF,0x34,0x91,0x3A,0xD5,0xE3,0x81,0xD0,0xB2,0xF0, +0x04,0x02,0xD7,0x5B,0xB7,0x3E,0x92,0xAC,0x6B,0x12,0x8A,0xF9,0xE4,0x05,0xB0,0x3B, +0x91,0x49,0x5C,0xB2,0xEB,0x53,0xEA,0xF8,0x9F,0x47,0x86,0xEE,0xBF,0x95,0xC0,0xC0, +0x06,0x9F,0xD2,0x5B,0x5E,0x11,0x1B,0xF4,0xC7,0x04,0x35,0x29,0xD2,0x55,0x5C,0xE4, +0xED,0xEB,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xC9,0x30,0x81,0xC6,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xC5,0x7B,0x58,0xBD,0xED,0xDA,0x25,0x69, +0xD2,0xF7,0x59,0x16,0xA8,0xB3,0x32,0xC0,0x7B,0x27,0x5B,0xF4,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x83, +0x06,0x03,0x55,0x1D,0x1F,0x04,0x7C,0x30,0x7A,0x30,0x3C,0xA0,0x3A,0xA0,0x38,0x86, +0x36,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F, +0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x54,0x72,0x75,0x73,0x74,0x65,0x64, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69, +0x63,0x65,0x73,0x2E,0x63,0x72,0x6C,0x30,0x3A,0xA0,0x38,0xA0,0x36,0x86,0x34,0x68, +0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F, +0x2E,0x6E,0x65,0x74,0x2F,0x54,0x72,0x75,0x73,0x74,0x65,0x64,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2E, +0x63,0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xC8,0x93,0x81,0x3B,0x89,0xB4,0xAF,0xB8,0x84, +0x12,0x4C,0x8D,0xD2,0xF0,0xDB,0x70,0xBA,0x57,0x86,0x15,0x34,0x10,0xB9,0x2F,0x7F, +0x1E,0xB0,0xA8,0x89,0x60,0xA1,0x8A,0xC2,0x77,0x0C,0x50,0x4A,0x9B,0x00,0x8B,0xD8, +0x8B,0xF4,0x41,0xE2,0xD0,0x83,0x8A,0x4A,0x1C,0x14,0x06,0xB0,0xA3,0x68,0x05,0x70, +0x31,0x30,0xA7,0x53,0x9B,0x0E,0xE9,0x4A,0xA0,0x58,0x69,0x67,0x0E,0xAE,0x9D,0xF6, +0xA5,0x2C,0x41,0xBF,0x3C,0x06,0x6B,0xE4,0x59,0xCC,0x6D,0x10,0xF1,0x96,0x6F,0x1F, +0xDF,0xF4,0x04,0x02,0xA4,0x9F,0x45,0x3E,0xC8,0xD8,0xFA,0x36,0x46,0x44,0x50,0x3F, +0x82,0x97,0x91,0x1F,0x28,0xDB,0x18,0x11,0x8C,0x2A,0xE4,0x65,0x83,0x57,0x12,0x12, +0x8C,0x17,0x3F,0x94,0x36,0xFE,0x5D,0xB0,0xC0,0x04,0x77,0x13,0xB8,0xF4,0x15,0xD5, +0x3F,0x38,0xCC,0x94,0x3A,0x55,0xD0,0xAC,0x98,0xF5,0xBA,0x00,0x5F,0xE0,0x86,0x19, +0x81,0x78,0x2F,0x28,0xC0,0x7E,0xD3,0xCC,0x42,0x0A,0xF5,0xAE,0x50,0xA0,0xD1,0x3E, +0xC6,0xA1,0x71,0xEC,0x3F,0xA0,0x20,0x8C,0x66,0x3A,0x89,0xB4,0x8E,0xD4,0xD8,0xB1, +0x4D,0x25,0x47,0xEE,0x2F,0x88,0xC8,0xB5,0xE1,0x05,0x45,0xC0,0xBE,0x14,0x71,0xDE, +0x7A,0xFD,0x8E,0x7B,0x7D,0x4D,0x08,0x96,0xA5,0x12,0x73,0xF0,0x2D,0xCA,0x37,0x27, +0x74,0x12,0x27,0x4C,0xCB,0xB6,0x97,0xE9,0xD9,0xAE,0x08,0x6D,0x5A,0x39,0x40,0xDD, +0x05,0x47,0x75,0x6A,0x5A,0x21,0xB3,0xA3,0x18,0xCF,0x4E,0xF7,0x2E,0x57,0xB7,0x98, +0x70,0x5E,0xC8,0xC4,0x78,0xB0,0x62, +}; + + +/* subject:/O=Cybertrust, Inc/CN=Cybertrust Global Root */ +/* issuer :/O=Cybertrust, Inc/CN=Cybertrust Global Root */ + + +const unsigned char Cybertrust_Global_Root_certificate[933]={ +0x30,0x82,0x03,0xA1,0x30,0x82,0x02,0x89,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, +0x00,0x00,0x00,0x00,0x01,0x0F,0x85,0xAA,0x2D,0x48,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x3B,0x31,0x18,0x30,0x16,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0F,0x43,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74, +0x2C,0x20,0x49,0x6E,0x63,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16, +0x43,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61, +0x6C,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x32,0x31,0x35, +0x30,0x38,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x31,0x31,0x32,0x31,0x35,0x30, +0x38,0x30,0x30,0x30,0x30,0x5A,0x30,0x3B,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04, +0x0A,0x13,0x0F,0x43,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49, +0x6E,0x63,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x43,0x79,0x62, +0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52, +0x6F,0x6F,0x74,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02, +0x82,0x01,0x01,0x00,0xF8,0xC8,0xBC,0xBD,0x14,0x50,0x66,0x13,0xFF,0xF0,0xD3,0x79, +0xEC,0x23,0xF2,0xB7,0x1A,0xC7,0x8E,0x85,0xF1,0x12,0x73,0xA6,0x19,0xAA,0x10,0xDB, +0x9C,0xA2,0x65,0x74,0x5A,0x77,0x3E,0x51,0x7D,0x56,0xF6,0xDC,0x23,0xB6,0xD4,0xED, +0x5F,0x58,0xB1,0x37,0x4D,0xD5,0x49,0x0E,0x6E,0xF5,0x6A,0x87,0xD6,0xD2,0x8C,0xD2, +0x27,0xC6,0xE2,0xFF,0x36,0x9F,0x98,0x65,0xA0,0x13,0x4E,0xC6,0x2A,0x64,0x9B,0xD5, +0x90,0x12,0xCF,0x14,0x06,0xF4,0x3B,0xE3,0xD4,0x28,0xBE,0xE8,0x0E,0xF8,0xAB,0x4E, +0x48,0x94,0x6D,0x8E,0x95,0x31,0x10,0x5C,0xED,0xA2,0x2D,0xBD,0xD5,0x3A,0x6D,0xB2, +0x1C,0xBB,0x60,0xC0,0x46,0x4B,0x01,0xF5,0x49,0xAE,0x7E,0x46,0x8A,0xD0,0x74,0x8D, +0xA1,0x0C,0x02,0xCE,0xEE,0xFC,0xE7,0x8F,0xB8,0x6B,0x66,0xF3,0x7F,0x44,0x00,0xBF, +0x66,0x25,0x14,0x2B,0xDD,0x10,0x30,0x1D,0x07,0x96,0x3F,0x4D,0xF6,0x6B,0xB8,0x8F, +0xB7,0x7B,0x0C,0xA5,0x38,0xEB,0xDE,0x47,0xDB,0xD5,0x5D,0x39,0xFC,0x88,0xA7,0xF3, +0xD7,0x2A,0x74,0xF1,0xE8,0x5A,0xA2,0x3B,0x9F,0x50,0xBA,0xA6,0x8C,0x45,0x35,0xC2, +0x50,0x65,0x95,0xDC,0x63,0x82,0xEF,0xDD,0xBF,0x77,0x4D,0x9C,0x62,0xC9,0x63,0x73, +0x16,0xD0,0x29,0x0F,0x49,0xA9,0x48,0xF0,0xB3,0xAA,0xB7,0x6C,0xC5,0xA7,0x30,0x39, +0x40,0x5D,0xAE,0xC4,0xE2,0x5D,0x26,0x53,0xF0,0xCE,0x1C,0x23,0x08,0x61,0xA8,0x94, +0x19,0xBA,0x04,0x62,0x40,0xEC,0x1F,0x38,0x70,0x77,0x12,0x06,0x71,0xA7,0x30,0x18, +0x5D,0x25,0x27,0xA5,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xA5,0x30,0x81,0xA2,0x30, +0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30, +0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, +0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xB6,0x08,0x7B,0x0D,0x7A, +0xCC,0xAC,0x20,0x4C,0x86,0x56,0x32,0x5E,0xCF,0xAB,0x6E,0x85,0x2D,0x70,0x57,0x30, +0x3F,0x06,0x03,0x55,0x1D,0x1F,0x04,0x38,0x30,0x36,0x30,0x34,0xA0,0x32,0xA0,0x30, +0x86,0x2E,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x32,0x2E,0x70,0x75, +0x62,0x6C,0x69,0x63,0x2D,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x63, +0x72,0x6C,0x2F,0x63,0x74,0x2F,0x63,0x74,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C, +0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xB6,0x08,0x7B, +0x0D,0x7A,0xCC,0xAC,0x20,0x4C,0x86,0x56,0x32,0x5E,0xCF,0xAB,0x6E,0x85,0x2D,0x70, +0x57,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, +0x03,0x82,0x01,0x01,0x00,0x56,0xEF,0x0A,0x23,0xA0,0x54,0x4E,0x95,0x97,0xC9,0xF8, +0x89,0xDA,0x45,0xC1,0xD4,0xA3,0x00,0x25,0xF4,0x1F,0x13,0xAB,0xB7,0xA3,0x85,0x58, +0x69,0xC2,0x30,0xAD,0xD8,0x15,0x8A,0x2D,0xE3,0xC9,0xCD,0x81,0x5A,0xF8,0x73,0x23, +0x5A,0xA7,0x7C,0x05,0xF3,0xFD,0x22,0x3B,0x0E,0xD1,0x06,0xC4,0xDB,0x36,0x4C,0x73, +0x04,0x8E,0xE5,0xB0,0x22,0xE4,0xC5,0xF3,0x2E,0xA5,0xD9,0x23,0xE3,0xB8,0x4E,0x4A, +0x20,0xA7,0x6E,0x02,0x24,0x9F,0x22,0x60,0x67,0x7B,0x8B,0x1D,0x72,0x09,0xC5,0x31, +0x5C,0xE9,0x79,0x9F,0x80,0x47,0x3D,0xAD,0xA1,0x0B,0x07,0x14,0x3D,0x47,0xFF,0x03, +0x69,0x1A,0x0C,0x0B,0x44,0xE7,0x63,0x25,0xA7,0x7F,0xB2,0xC9,0xB8,0x76,0x84,0xED, +0x23,0xF6,0x7D,0x07,0xAB,0x45,0x7E,0xD3,0xDF,0xB3,0xBF,0xE9,0x8A,0xB6,0xCD,0xA8, +0xA2,0x67,0x2B,0x52,0xD5,0xB7,0x65,0xF0,0x39,0x4C,0x63,0xA0,0x91,0x79,0x93,0x52, +0x0F,0x54,0xDD,0x83,0xBB,0x9F,0xD1,0x8F,0xA7,0x53,0x73,0xC3,0xCB,0xFF,0x30,0xEC, +0x7C,0x04,0xB8,0xD8,0x44,0x1F,0x93,0x5F,0x71,0x09,0x22,0xB7,0x6E,0x3E,0xEA,0x1C, +0x03,0x4E,0x9D,0x1A,0x20,0x61,0xFB,0x81,0x37,0xEC,0x5E,0xFC,0x0A,0x45,0xAB,0xD7, +0xE7,0x17,0x55,0xD0,0xA0,0xEA,0x60,0x9B,0xA6,0xF6,0xE3,0x8C,0x5B,0x29,0xC2,0x06, +0x60,0x14,0x9D,0x2D,0x97,0x4C,0xA9,0x93,0x15,0x9D,0x61,0xC4,0x01,0x5F,0x48,0xD6, +0x58,0xBD,0x56,0x31,0x12,0x4E,0x11,0xC8,0x21,0xE0,0xB3,0x11,0x91,0x65,0xDB,0xB4, +0xA6,0x88,0x38,0xCE,0x55, +}; + + +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA */ + + +const unsigned char DigiCert_Assured_ID_Root_CA_certificate[955]={ +0x30,0x82,0x03,0xB7,0x30,0x82,0x02,0x9F,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x0C, +0xE7,0xE0,0xE5,0x17,0xD8,0x46,0xFE,0x8F,0xE5,0x60,0xFC,0x1B,0xF0,0x30,0x39,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x65, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65,0x64,0x20,0x49,0x44,0x20,0x52,0x6F, +0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x31,0x31,0x31,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x30,0x5A,0x30,0x65,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44, +0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06, +0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65, +0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13, +0x1B,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x41,0x73,0x73,0x75,0x72,0x65, +0x64,0x20,0x49,0x44,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAD,0x0E,0x15, +0xCE,0xE4,0x43,0x80,0x5C,0xB1,0x87,0xF3,0xB7,0x60,0xF9,0x71,0x12,0xA5,0xAE,0xDC, +0x26,0x94,0x88,0xAA,0xF4,0xCE,0xF5,0x20,0x39,0x28,0x58,0x60,0x0C,0xF8,0x80,0xDA, +0xA9,0x15,0x95,0x32,0x61,0x3C,0xB5,0xB1,0x28,0x84,0x8A,0x8A,0xDC,0x9F,0x0A,0x0C, +0x83,0x17,0x7A,0x8F,0x90,0xAC,0x8A,0xE7,0x79,0x53,0x5C,0x31,0x84,0x2A,0xF6,0x0F, +0x98,0x32,0x36,0x76,0xCC,0xDE,0xDD,0x3C,0xA8,0xA2,0xEF,0x6A,0xFB,0x21,0xF2,0x52, +0x61,0xDF,0x9F,0x20,0xD7,0x1F,0xE2,0xB1,0xD9,0xFE,0x18,0x64,0xD2,0x12,0x5B,0x5F, +0xF9,0x58,0x18,0x35,0xBC,0x47,0xCD,0xA1,0x36,0xF9,0x6B,0x7F,0xD4,0xB0,0x38,0x3E, +0xC1,0x1B,0xC3,0x8C,0x33,0xD9,0xD8,0x2F,0x18,0xFE,0x28,0x0F,0xB3,0xA7,0x83,0xD6, +0xC3,0x6E,0x44,0xC0,0x61,0x35,0x96,0x16,0xFE,0x59,0x9C,0x8B,0x76,0x6D,0xD7,0xF1, +0xA2,0x4B,0x0D,0x2B,0xFF,0x0B,0x72,0xDA,0x9E,0x60,0xD0,0x8E,0x90,0x35,0xC6,0x78, +0x55,0x87,0x20,0xA1,0xCF,0xE5,0x6D,0x0A,0xC8,0x49,0x7C,0x31,0x98,0x33,0x6C,0x22, +0xE9,0x87,0xD0,0x32,0x5A,0xA2,0xBA,0x13,0x82,0x11,0xED,0x39,0x17,0x9D,0x99,0x3A, +0x72,0xA1,0xE6,0xFA,0xA4,0xD9,0xD5,0x17,0x31,0x75,0xAE,0x85,0x7D,0x22,0xAE,0x3F, +0x01,0x46,0x86,0xF6,0x28,0x79,0xC8,0xB1,0xDA,0xE4,0x57,0x17,0xC4,0x7E,0x1C,0x0E, +0xB0,0xB4,0x92,0xA6,0x56,0xB3,0xBD,0xB2,0x97,0xED,0xAA,0xA7,0xF0,0xB7,0xC5,0xA8, +0x3F,0x95,0x16,0xD0,0xFF,0xA1,0x96,0xEB,0x08,0x5F,0x18,0x77,0x4F,0x02,0x03,0x01, +0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0x45,0xEB,0xA2,0xAF,0xF4,0x92,0xCB,0x82,0x31,0x2D,0x51,0x8B,0xA7,0xA7, +0x21,0x9D,0xF3,0x6D,0xC8,0x0F,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30, +0x16,0x80,0x14,0x45,0xEB,0xA2,0xAF,0xF4,0x92,0xCB,0x82,0x31,0x2D,0x51,0x8B,0xA7, +0xA7,0x21,0x9D,0xF3,0x6D,0xC8,0x0F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xA2,0x0E,0xBC,0xDF,0xE2, +0xED,0xF0,0xE3,0x72,0x73,0x7A,0x64,0x94,0xBF,0xF7,0x72,0x66,0xD8,0x32,0xE4,0x42, +0x75,0x62,0xAE,0x87,0xEB,0xF2,0xD5,0xD9,0xDE,0x56,0xB3,0x9F,0xCC,0xCE,0x14,0x28, +0xB9,0x0D,0x97,0x60,0x5C,0x12,0x4C,0x58,0xE4,0xD3,0x3D,0x83,0x49,0x45,0x58,0x97, +0x35,0x69,0x1A,0xA8,0x47,0xEA,0x56,0xC6,0x79,0xAB,0x12,0xD8,0x67,0x81,0x84,0xDF, +0x7F,0x09,0x3C,0x94,0xE6,0xB8,0x26,0x2C,0x20,0xBD,0x3D,0xB3,0x28,0x89,0xF7,0x5F, +0xFF,0x22,0xE2,0x97,0x84,0x1F,0xE9,0x65,0xEF,0x87,0xE0,0xDF,0xC1,0x67,0x49,0xB3, +0x5D,0xEB,0xB2,0x09,0x2A,0xEB,0x26,0xED,0x78,0xBE,0x7D,0x3F,0x2B,0xF3,0xB7,0x26, +0x35,0x6D,0x5F,0x89,0x01,0xB6,0x49,0x5B,0x9F,0x01,0x05,0x9B,0xAB,0x3D,0x25,0xC1, +0xCC,0xB6,0x7F,0xC2,0xF1,0x6F,0x86,0xC6,0xFA,0x64,0x68,0xEB,0x81,0x2D,0x94,0xEB, +0x42,0xB7,0xFA,0x8C,0x1E,0xDD,0x62,0xF1,0xBE,0x50,0x67,0xB7,0x6C,0xBD,0xF3,0xF1, +0x1F,0x6B,0x0C,0x36,0x07,0x16,0x7F,0x37,0x7C,0xA9,0x5B,0x6D,0x7A,0xF1,0x12,0x46, +0x60,0x83,0xD7,0x27,0x04,0xBE,0x4B,0xCE,0x97,0xBE,0xC3,0x67,0x2A,0x68,0x11,0xDF, +0x80,0xE7,0x0C,0x33,0x66,0xBF,0x13,0x0D,0x14,0x6E,0xF3,0x7F,0x1F,0x63,0x10,0x1E, +0xFA,0x8D,0x1B,0x25,0x6D,0x6C,0x8F,0xA5,0xB7,0x61,0x01,0xB1,0xD2,0xA3,0x26,0xA1, +0x10,0x71,0x9D,0xAD,0xE2,0xC3,0xF9,0xC3,0x99,0x51,0xB7,0x2B,0x07,0x08,0xCE,0x2E, +0xE6,0x50,0xB2,0xA7,0xFA,0x0A,0x45,0x2F,0xA2,0xF0,0xF2, +}; + + +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA */ + + +const unsigned char DigiCert_Global_Root_CA_certificate[947]={ +0x30,0x82,0x03,0xAF,0x30,0x82,0x02,0x97,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x08, +0x3B,0xE0,0x56,0x90,0x42,0x46,0xB1,0xA1,0x75,0x6A,0xC9,0x59,0x91,0xC7,0x4A,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x61, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43, +0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30, +0x30,0x5A,0x17,0x0D,0x33,0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30, +0x5A,0x30,0x61,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, +0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43, +0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B, +0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63, +0x6F,0x6D,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67, +0x69,0x43,0x65,0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F, +0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xE2,0x3B,0xE1,0x11,0x72,0xDE,0xA8,0xA4,0xD3,0xA3,0x57, +0xAA,0x50,0xA2,0x8F,0x0B,0x77,0x90,0xC9,0xA2,0xA5,0xEE,0x12,0xCE,0x96,0x5B,0x01, +0x09,0x20,0xCC,0x01,0x93,0xA7,0x4E,0x30,0xB7,0x53,0xF7,0x43,0xC4,0x69,0x00,0x57, +0x9D,0xE2,0x8D,0x22,0xDD,0x87,0x06,0x40,0x00,0x81,0x09,0xCE,0xCE,0x1B,0x83,0xBF, +0xDF,0xCD,0x3B,0x71,0x46,0xE2,0xD6,0x66,0xC7,0x05,0xB3,0x76,0x27,0x16,0x8F,0x7B, +0x9E,0x1E,0x95,0x7D,0xEE,0xB7,0x48,0xA3,0x08,0xDA,0xD6,0xAF,0x7A,0x0C,0x39,0x06, +0x65,0x7F,0x4A,0x5D,0x1F,0xBC,0x17,0xF8,0xAB,0xBE,0xEE,0x28,0xD7,0x74,0x7F,0x7A, +0x78,0x99,0x59,0x85,0x68,0x6E,0x5C,0x23,0x32,0x4B,0xBF,0x4E,0xC0,0xE8,0x5A,0x6D, +0xE3,0x70,0xBF,0x77,0x10,0xBF,0xFC,0x01,0xF6,0x85,0xD9,0xA8,0x44,0x10,0x58,0x32, +0xA9,0x75,0x18,0xD5,0xD1,0xA2,0xBE,0x47,0xE2,0x27,0x6A,0xF4,0x9A,0x33,0xF8,0x49, +0x08,0x60,0x8B,0xD4,0x5F,0xB4,0x3A,0x84,0xBF,0xA1,0xAA,0x4A,0x4C,0x7D,0x3E,0xCF, +0x4F,0x5F,0x6C,0x76,0x5E,0xA0,0x4B,0x37,0x91,0x9E,0xDC,0x22,0xE6,0x6D,0xCE,0x14, +0x1A,0x8E,0x6A,0xCB,0xFE,0xCD,0xB3,0x14,0x64,0x17,0xC7,0x5B,0x29,0x9E,0x32,0xBF, +0xF2,0xEE,0xFA,0xD3,0x0B,0x42,0xD4,0xAB,0xB7,0x41,0x32,0xDA,0x0C,0xD4,0xEF,0xF8, +0x81,0xD5,0xBB,0x8D,0x58,0x3F,0xB5,0x1B,0xE8,0x49,0x28,0xA2,0x70,0xDA,0x31,0x04, +0xDD,0xF7,0xB2,0x16,0xF2,0x4C,0x0A,0x4E,0x07,0xA8,0xED,0x4A,0x3D,0x5E,0xB5,0x7F, +0xA3,0x90,0xC3,0xAF,0x27,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F, +0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x03,0xDE,0x50,0x35,0x56,0xD1, +0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,0xB2,0x3D,0xD1,0x55,0x30,0x1F, +0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x03,0xDE,0x50,0x35,0x56, +0xD1,0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,0xB2,0x3D,0xD1,0x55,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0xCB,0x9C,0x37,0xAA,0x48,0x13,0x12,0x0A,0xFA,0xDD,0x44,0x9C,0x4F, +0x52,0xB0,0xF4,0xDF,0xAE,0x04,0xF5,0x79,0x79,0x08,0xA3,0x24,0x18,0xFC,0x4B,0x2B, +0x84,0xC0,0x2D,0xB9,0xD5,0xC7,0xFE,0xF4,0xC1,0x1F,0x58,0xCB,0xB8,0x6D,0x9C,0x7A, +0x74,0xE7,0x98,0x29,0xAB,0x11,0xB5,0xE3,0x70,0xA0,0xA1,0xCD,0x4C,0x88,0x99,0x93, +0x8C,0x91,0x70,0xE2,0xAB,0x0F,0x1C,0xBE,0x93,0xA9,0xFF,0x63,0xD5,0xE4,0x07,0x60, +0xD3,0xA3,0xBF,0x9D,0x5B,0x09,0xF1,0xD5,0x8E,0xE3,0x53,0xF4,0x8E,0x63,0xFA,0x3F, +0xA7,0xDB,0xB4,0x66,0xDF,0x62,0x66,0xD6,0xD1,0x6E,0x41,0x8D,0xF2,0x2D,0xB5,0xEA, +0x77,0x4A,0x9F,0x9D,0x58,0xE2,0x2B,0x59,0xC0,0x40,0x23,0xED,0x2D,0x28,0x82,0x45, +0x3E,0x79,0x54,0x92,0x26,0x98,0xE0,0x80,0x48,0xA8,0x37,0xEF,0xF0,0xD6,0x79,0x60, +0x16,0xDE,0xAC,0xE8,0x0E,0xCD,0x6E,0xAC,0x44,0x17,0x38,0x2F,0x49,0xDA,0xE1,0x45, +0x3E,0x2A,0xB9,0x36,0x53,0xCF,0x3A,0x50,0x06,0xF7,0x2E,0xE8,0xC4,0x57,0x49,0x6C, +0x61,0x21,0x18,0xD5,0x04,0xAD,0x78,0x3C,0x2C,0x3A,0x80,0x6B,0xA7,0xEB,0xAF,0x15, +0x14,0xE9,0xD8,0x89,0xC1,0xB9,0x38,0x6C,0xE2,0x91,0x6C,0x8A,0xFF,0x64,0xB9,0x77, +0x25,0x57,0x30,0xC0,0x1B,0x24,0xA3,0xE1,0xDC,0xE9,0xDF,0x47,0x7C,0xB5,0xB4,0x24, +0x08,0x05,0x30,0xEC,0x2D,0xBD,0x0B,0xBF,0x45,0xBF,0x50,0xB9,0xA9,0xF3,0xEB,0x98, +0x01,0x12,0xAD,0xC8,0x88,0xC6,0x98,0x34,0x5F,0x8D,0x0A,0x3C,0xC6,0xE9,0xD5,0x95, +0x95,0x6D,0xDE, +}; + + +/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA */ +/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA */ + + +const unsigned char DigiCert_High_Assurance_EV_Root_CA_certificate[969]={ +0x30,0x82,0x03,0xC5,0x30,0x82,0x02,0xAD,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x02, +0xAC,0x5C,0x26,0x6A,0x0B,0x40,0x9B,0x8F,0x0B,0x79,0xF2,0xAE,0x46,0x25,0x77,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x6C, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30, +0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77, +0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31, +0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65, +0x72,0x74,0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63, +0x65,0x20,0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D, +0x30,0x36,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33, +0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x6C,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49, +0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77, +0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x2B,0x30, +0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74, +0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63,0x65,0x20, +0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, +0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC6,0xCC,0xE5,0x73,0xE6, +0xFB,0xD4,0xBB,0xE5,0x2D,0x2D,0x32,0xA6,0xDF,0xE5,0x81,0x3F,0xC9,0xCD,0x25,0x49, +0xB6,0x71,0x2A,0xC3,0xD5,0x94,0x34,0x67,0xA2,0x0A,0x1C,0xB0,0x5F,0x69,0xA6,0x40, +0xB1,0xC4,0xB7,0xB2,0x8F,0xD0,0x98,0xA4,0xA9,0x41,0x59,0x3A,0xD3,0xDC,0x94,0xD6, +0x3C,0xDB,0x74,0x38,0xA4,0x4A,0xCC,0x4D,0x25,0x82,0xF7,0x4A,0xA5,0x53,0x12,0x38, +0xEE,0xF3,0x49,0x6D,0x71,0x91,0x7E,0x63,0xB6,0xAB,0xA6,0x5F,0xC3,0xA4,0x84,0xF8, +0x4F,0x62,0x51,0xBE,0xF8,0xC5,0xEC,0xDB,0x38,0x92,0xE3,0x06,0xE5,0x08,0x91,0x0C, +0xC4,0x28,0x41,0x55,0xFB,0xCB,0x5A,0x89,0x15,0x7E,0x71,0xE8,0x35,0xBF,0x4D,0x72, +0x09,0x3D,0xBE,0x3A,0x38,0x50,0x5B,0x77,0x31,0x1B,0x8D,0xB3,0xC7,0x24,0x45,0x9A, +0xA7,0xAC,0x6D,0x00,0x14,0x5A,0x04,0xB7,0xBA,0x13,0xEB,0x51,0x0A,0x98,0x41,0x41, +0x22,0x4E,0x65,0x61,0x87,0x81,0x41,0x50,0xA6,0x79,0x5C,0x89,0xDE,0x19,0x4A,0x57, +0xD5,0x2E,0xE6,0x5D,0x1C,0x53,0x2C,0x7E,0x98,0xCD,0x1A,0x06,0x16,0xA4,0x68,0x73, +0xD0,0x34,0x04,0x13,0x5C,0xA1,0x71,0xD3,0x5A,0x7C,0x55,0xDB,0x5E,0x64,0xE1,0x37, +0x87,0x30,0x56,0x04,0xE5,0x11,0xB4,0x29,0x80,0x12,0xF1,0x79,0x39,0x88,0xA2,0x02, +0x11,0x7C,0x27,0x66,0xB7,0x88,0xB7,0x78,0xF2,0xCA,0x0A,0xA8,0x38,0xAB,0x0A,0x64, +0xC2,0xBF,0x66,0x5D,0x95,0x84,0xC1,0xA1,0x25,0x1E,0x87,0x5D,0x1A,0x50,0x0B,0x20, +0x12,0xCC,0x41,0xBB,0x6E,0x0B,0x51,0x38,0xB8,0x4B,0xCB,0x02,0x03,0x01,0x00,0x01, +0xA3,0x63,0x30,0x61,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, +0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,0x02,0xEF, +0x63,0x64,0x2B,0xC3,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80, +0x14,0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,0x02, +0xEF,0x63,0x64,0x2B,0xC3,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x1C,0x1A,0x06,0x97,0xDC,0xD7,0x9C, +0x9F,0x3C,0x88,0x66,0x06,0x08,0x57,0x21,0xDB,0x21,0x47,0xF8,0x2A,0x67,0xAA,0xBF, +0x18,0x32,0x76,0x40,0x10,0x57,0xC1,0x8A,0xF3,0x7A,0xD9,0x11,0x65,0x8E,0x35,0xFA, +0x9E,0xFC,0x45,0xB5,0x9E,0xD9,0x4C,0x31,0x4B,0xB8,0x91,0xE8,0x43,0x2C,0x8E,0xB3, +0x78,0xCE,0xDB,0xE3,0x53,0x79,0x71,0xD6,0xE5,0x21,0x94,0x01,0xDA,0x55,0x87,0x9A, +0x24,0x64,0xF6,0x8A,0x66,0xCC,0xDE,0x9C,0x37,0xCD,0xA8,0x34,0xB1,0x69,0x9B,0x23, +0xC8,0x9E,0x78,0x22,0x2B,0x70,0x43,0xE3,0x55,0x47,0x31,0x61,0x19,0xEF,0x58,0xC5, +0x85,0x2F,0x4E,0x30,0xF6,0xA0,0x31,0x16,0x23,0xC8,0xE7,0xE2,0x65,0x16,0x33,0xCB, +0xBF,0x1A,0x1B,0xA0,0x3D,0xF8,0xCA,0x5E,0x8B,0x31,0x8B,0x60,0x08,0x89,0x2D,0x0C, +0x06,0x5C,0x52,0xB7,0xC4,0xF9,0x0A,0x98,0xD1,0x15,0x5F,0x9F,0x12,0xBE,0x7C,0x36, +0x63,0x38,0xBD,0x44,0xA4,0x7F,0xE4,0x26,0x2B,0x0A,0xC4,0x97,0x69,0x0D,0xE9,0x8C, +0xE2,0xC0,0x10,0x57,0xB8,0xC8,0x76,0x12,0x91,0x55,0xF2,0x48,0x69,0xD8,0xBC,0x2A, +0x02,0x5B,0x0F,0x44,0xD4,0x20,0x31,0xDB,0xF4,0xBA,0x70,0x26,0x5D,0x90,0x60,0x9E, +0xBC,0x4B,0x17,0x09,0x2F,0xB4,0xCB,0x1E,0x43,0x68,0xC9,0x07,0x27,0xC1,0xD2,0x5C, +0xF7,0xEA,0x21,0xB9,0x68,0x12,0x9C,0x3C,0x9C,0xBF,0x9E,0xFC,0x80,0x5C,0x9B,0x63, +0xCD,0xEC,0x47,0xAA,0x25,0x27,0x67,0xA0,0x37,0xF3,0x00,0x82,0x7D,0x54,0xD7,0xA9, +0xF8,0xE9,0x2E,0x13,0xA3,0x77,0xE8,0x1F,0x4A, +}; + + +/* subject:/O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048) */ +/* issuer :/O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048) */ + + +const unsigned char Entrust_net_Premium_2048_Secure_Server_CA_certificate[1120]={ +0x30,0x82,0x04,0x5C,0x30,0x82,0x03,0x44,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x38, +0x63,0xB9,0x66,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x81,0xB4,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B, +0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x31,0x40,0x30,0x3E,0x06, +0x03,0x55,0x04,0x0B,0x14,0x37,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73, +0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x5F,0x32,0x30,0x34,0x38,0x20,0x69, +0x6E,0x63,0x6F,0x72,0x70,0x2E,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2E,0x20,0x28, +0x6C,0x69,0x6D,0x69,0x74,0x73,0x20,0x6C,0x69,0x61,0x62,0x2E,0x29,0x31,0x25,0x30, +0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C,0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39, +0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D, +0x69,0x74,0x65,0x64,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x03,0x13,0x2A,0x45, +0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x20,0x28,0x32,0x30,0x34,0x38,0x29,0x30,0x1E,0x17,0x0D,0x39,0x39,0x31, +0x32,0x32,0x34,0x31,0x37,0x35,0x30,0x35,0x31,0x5A,0x17,0x0D,0x31,0x39,0x31,0x32, +0x32,0x34,0x31,0x38,0x32,0x30,0x35,0x31,0x5A,0x30,0x81,0xB4,0x31,0x14,0x30,0x12, +0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E, +0x65,0x74,0x31,0x40,0x30,0x3E,0x06,0x03,0x55,0x04,0x0B,0x14,0x37,0x77,0x77,0x77, +0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53, +0x5F,0x32,0x30,0x34,0x38,0x20,0x69,0x6E,0x63,0x6F,0x72,0x70,0x2E,0x20,0x62,0x79, +0x20,0x72,0x65,0x66,0x2E,0x20,0x28,0x6C,0x69,0x6D,0x69,0x74,0x73,0x20,0x6C,0x69, +0x61,0x62,0x2E,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C,0x28, +0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E, +0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x33,0x30,0x31,0x06, +0x03,0x55,0x04,0x03,0x13,0x2A,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65, +0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x28,0x32,0x30,0x34,0x38,0x29, +0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01, +0x00,0xAD,0x4D,0x4B,0xA9,0x12,0x86,0xB2,0xEA,0xA3,0x20,0x07,0x15,0x16,0x64,0x2A, +0x2B,0x4B,0xD1,0xBF,0x0B,0x4A,0x4D,0x8E,0xED,0x80,0x76,0xA5,0x67,0xB7,0x78,0x40, +0xC0,0x73,0x42,0xC8,0x68,0xC0,0xDB,0x53,0x2B,0xDD,0x5E,0xB8,0x76,0x98,0x35,0x93, +0x8B,0x1A,0x9D,0x7C,0x13,0x3A,0x0E,0x1F,0x5B,0xB7,0x1E,0xCF,0xE5,0x24,0x14,0x1E, +0xB1,0x81,0xA9,0x8D,0x7D,0xB8,0xCC,0x6B,0x4B,0x03,0xF1,0x02,0x0C,0xDC,0xAB,0xA5, +0x40,0x24,0x00,0x7F,0x74,0x94,0xA1,0x9D,0x08,0x29,0xB3,0x88,0x0B,0xF5,0x87,0x77, +0x9D,0x55,0xCD,0xE4,0xC3,0x7E,0xD7,0x6A,0x64,0xAB,0x85,0x14,0x86,0x95,0x5B,0x97, +0x32,0x50,0x6F,0x3D,0xC8,0xBA,0x66,0x0C,0xE3,0xFC,0xBD,0xB8,0x49,0xC1,0x76,0x89, +0x49,0x19,0xFD,0xC0,0xA8,0xBD,0x89,0xA3,0x67,0x2F,0xC6,0x9F,0xBC,0x71,0x19,0x60, +0xB8,0x2D,0xE9,0x2C,0xC9,0x90,0x76,0x66,0x7B,0x94,0xE2,0xAF,0x78,0xD6,0x65,0x53, +0x5D,0x3C,0xD6,0x9C,0xB2,0xCF,0x29,0x03,0xF9,0x2F,0xA4,0x50,0xB2,0xD4,0x48,0xCE, +0x05,0x32,0x55,0x8A,0xFD,0xB2,0x64,0x4C,0x0E,0xE4,0x98,0x07,0x75,0xDB,0x7F,0xDF, +0xB9,0x08,0x55,0x60,0x85,0x30,0x29,0xF9,0x7B,0x48,0xA4,0x69,0x86,0xE3,0x35,0x3F, +0x1E,0x86,0x5D,0x7A,0x7A,0x15,0xBD,0xEF,0x00,0x8E,0x15,0x22,0x54,0x17,0x00,0x90, +0x26,0x93,0xBC,0x0E,0x49,0x68,0x91,0xBF,0xF8,0x47,0xD3,0x9D,0x95,0x42,0xC1,0x0E, +0x4D,0xDF,0x6F,0x26,0xCF,0xC3,0x18,0x21,0x62,0x66,0x43,0x70,0xD6,0xD5,0xC0,0x07, +0xE1,0x02,0x03,0x01,0x00,0x01,0xA3,0x74,0x30,0x72,0x30,0x11,0x06,0x09,0x60,0x86, +0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07,0x30,0x1F,0x06, +0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x55,0xE4,0x81,0xD1,0x11,0x80, +0xBE,0xD8,0x89,0xB9,0x08,0xA3,0x31,0xF9,0xA1,0x24,0x09,0x16,0xB9,0x70,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x55,0xE4,0x81,0xD1,0x11,0x80,0xBE, +0xD8,0x89,0xB9,0x08,0xA3,0x31,0xF9,0xA1,0x24,0x09,0x16,0xB9,0x70,0x30,0x1D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x41,0x00,0x04,0x10,0x30,0x0E,0x1B,0x08, +0x56,0x35,0x2E,0x30,0x3A,0x34,0x2E,0x30,0x03,0x02,0x04,0x90,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00, +0x59,0x47,0xAC,0x21,0x84,0x8A,0x17,0xC9,0x9C,0x89,0x53,0x1E,0xBA,0x80,0x85,0x1A, +0xC6,0x3C,0x4E,0x3E,0xB1,0x9C,0xB6,0x7C,0xC6,0x92,0x5D,0x18,0x64,0x02,0xE3,0xD3, +0x06,0x08,0x11,0x61,0x7C,0x63,0xE3,0x2B,0x9D,0x31,0x03,0x70,0x76,0xD2,0xA3,0x28, +0xA0,0xF4,0xBB,0x9A,0x63,0x73,0xED,0x6D,0xE5,0x2A,0xDB,0xED,0x14,0xA9,0x2B,0xC6, +0x36,0x11,0xD0,0x2B,0xEB,0x07,0x8B,0xA5,0xDA,0x9E,0x5C,0x19,0x9D,0x56,0x12,0xF5, +0x54,0x29,0xC8,0x05,0xED,0xB2,0x12,0x2A,0x8D,0xF4,0x03,0x1B,0xFF,0xE7,0x92,0x10, +0x87,0xB0,0x3A,0xB5,0xC3,0x9D,0x05,0x37,0x12,0xA3,0xC7,0xF4,0x15,0xB9,0xD5,0xA4, +0x39,0x16,0x9B,0x53,0x3A,0x23,0x91,0xF1,0xA8,0x82,0xA2,0x6A,0x88,0x68,0xC1,0x79, +0x02,0x22,0xBC,0xAA,0xA6,0xD6,0xAE,0xDF,0xB0,0x14,0x5F,0xB8,0x87,0xD0,0xDD,0x7C, +0x7F,0x7B,0xFF,0xAF,0x1C,0xCF,0xE6,0xDB,0x07,0xAD,0x5E,0xDB,0x85,0x9D,0xD0,0x2B, +0x0D,0x33,0xDB,0x04,0xD1,0xE6,0x49,0x40,0x13,0x2B,0x76,0xFB,0x3E,0xE9,0x9C,0x89, +0x0F,0x15,0xCE,0x18,0xB0,0x85,0x78,0x21,0x4F,0x6B,0x4F,0x0E,0xFA,0x36,0x67,0xCD, +0x07,0xF2,0xFF,0x08,0xD0,0xE2,0xDE,0xD9,0xBF,0x2A,0xAF,0xB8,0x87,0x86,0x21,0x3C, +0x04,0xCA,0xB7,0x94,0x68,0x7F,0xCF,0x3C,0xE9,0x98,0xD7,0x38,0xFF,0xEC,0xC0,0xD9, +0x50,0xF0,0x2E,0x4B,0x58,0xAE,0x46,0x6F,0xD0,0x2E,0xC3,0x60,0xDA,0x72,0x55,0x72, +0xBD,0x4C,0x45,0x9E,0x61,0xBA,0xBF,0x84,0x81,0x92,0x03,0xD1,0xD2,0x69,0x7C,0xC5, +}; + + +/* subject:/C=US/O=Entrust.net/OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Secure Server Certification Authority */ +/* issuer :/C=US/O=Entrust.net/OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Secure Server Certification Authority */ + + +const unsigned char Entrust_net_Secure_Server_CA_certificate[1244]={ +0x30,0x82,0x04,0xD8,0x30,0x82,0x04,0x41,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x37, +0x4A,0xD2,0x43,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x81,0xC3,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x45,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x31,0x3B,0x30,0x39,0x06,0x03,0x55,0x04, +0x0B,0x13,0x32,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E, +0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x6E,0x63,0x6F,0x72,0x70,0x2E,0x20,0x62, +0x79,0x20,0x72,0x65,0x66,0x2E,0x20,0x28,0x6C,0x69,0x6D,0x69,0x74,0x73,0x20,0x6C, +0x69,0x61,0x62,0x2E,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C, +0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74, +0x2E,0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x3A,0x30,0x38, +0x06,0x03,0x55,0x04,0x03,0x13,0x31,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E, +0x65,0x74,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, +0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x35, +0x32,0x35,0x31,0x36,0x30,0x39,0x34,0x30,0x5A,0x17,0x0D,0x31,0x39,0x30,0x35,0x32, +0x35,0x31,0x36,0x33,0x39,0x34,0x30,0x5A,0x30,0x81,0xC3,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, +0x0A,0x13,0x0B,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x31,0x3B, +0x30,0x39,0x06,0x03,0x55,0x04,0x0B,0x13,0x32,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x6E,0x63, +0x6F,0x72,0x70,0x2E,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2E,0x20,0x28,0x6C,0x69, +0x6D,0x69,0x74,0x73,0x20,0x6C,0x69,0x61,0x62,0x2E,0x29,0x31,0x25,0x30,0x23,0x06, +0x03,0x55,0x04,0x0B,0x13,0x1C,0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45, +0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D,0x69,0x74, +0x65,0x64,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x03,0x13,0x31,0x45,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20, +0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x81, +0x9D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, +0x03,0x81,0x8B,0x00,0x30,0x81,0x87,0x02,0x81,0x81,0x00,0xCD,0x28,0x83,0x34,0x54, +0x1B,0x89,0xF3,0x0F,0xAF,0x37,0x91,0x31,0xFF,0xAF,0x31,0x60,0xC9,0xA8,0xE8,0xB2, +0x10,0x68,0xED,0x9F,0xE7,0x93,0x36,0xF1,0x0A,0x64,0xBB,0x47,0xF5,0x04,0x17,0x3F, +0x23,0x47,0x4D,0xC5,0x27,0x19,0x81,0x26,0x0C,0x54,0x72,0x0D,0x88,0x2D,0xD9,0x1F, +0x9A,0x12,0x9F,0xBC,0xB3,0x71,0xD3,0x80,0x19,0x3F,0x47,0x66,0x7B,0x8C,0x35,0x28, +0xD2,0xB9,0x0A,0xDF,0x24,0xDA,0x9C,0xD6,0x50,0x79,0x81,0x7A,0x5A,0xD3,0x37,0xF7, +0xC2,0x4A,0xD8,0x29,0x92,0x26,0x64,0xD1,0xE4,0x98,0x6C,0x3A,0x00,0x8A,0xF5,0x34, +0x9B,0x65,0xF8,0xED,0xE3,0x10,0xFF,0xFD,0xB8,0x49,0x58,0xDC,0xA0,0xDE,0x82,0x39, +0x6B,0x81,0xB1,0x16,0x19,0x61,0xB9,0x54,0xB6,0xE6,0x43,0x02,0x01,0x03,0xA3,0x82, +0x01,0xD7,0x30,0x82,0x01,0xD3,0x30,0x11,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xF8, +0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07,0x30,0x82,0x01,0x19,0x06,0x03,0x55, +0x1D,0x1F,0x04,0x82,0x01,0x10,0x30,0x82,0x01,0x0C,0x30,0x81,0xDE,0xA0,0x81,0xDB, +0xA0,0x81,0xD8,0xA4,0x81,0xD5,0x30,0x81,0xD2,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13, +0x0B,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x31,0x3B,0x30,0x39, +0x06,0x03,0x55,0x04,0x0B,0x13,0x32,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75, +0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x6E,0x63,0x6F,0x72, +0x70,0x2E,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2E,0x20,0x28,0x6C,0x69,0x6D,0x69, +0x74,0x73,0x20,0x6C,0x69,0x61,0x62,0x2E,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55, +0x04,0x0B,0x13,0x1C,0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64, +0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x03,0x13,0x31,0x45,0x6E,0x74,0x72,0x75, +0x73,0x74,0x2E,0x6E,0x65,0x74,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x53,0x65, +0x72,0x76,0x65,0x72,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69, +0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x0D,0x30,0x0B, +0x06,0x03,0x55,0x04,0x03,0x13,0x04,0x43,0x52,0x4C,0x31,0x30,0x29,0xA0,0x27,0xA0, +0x25,0x86,0x23,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x65,0x6E, +0x74,0x72,0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x52,0x4C,0x2F,0x6E,0x65, +0x74,0x31,0x2E,0x63,0x72,0x6C,0x30,0x2B,0x06,0x03,0x55,0x1D,0x10,0x04,0x24,0x30, +0x22,0x80,0x0F,0x31,0x39,0x39,0x39,0x30,0x35,0x32,0x35,0x31,0x36,0x30,0x39,0x34, +0x30,0x5A,0x81,0x0F,0x32,0x30,0x31,0x39,0x30,0x35,0x32,0x35,0x31,0x36,0x30,0x39, +0x34,0x30,0x5A,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0x06, +0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xF0,0x17,0x62, +0x13,0x55,0x3D,0xB3,0xFF,0x0A,0x00,0x6B,0xFB,0x50,0x84,0x97,0xF3,0xED,0x62,0xD0, +0x1A,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xF0,0x17,0x62,0x13, +0x55,0x3D,0xB3,0xFF,0x0A,0x00,0x6B,0xFB,0x50,0x84,0x97,0xF3,0xED,0x62,0xD0,0x1A, +0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x19, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x41,0x00,0x04,0x0C,0x30,0x0A,0x1B, +0x04,0x56,0x34,0x2E,0x30,0x03,0x02,0x04,0x90,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x90,0xDC,0x30,0x02, +0xFA,0x64,0x74,0xC2,0xA7,0x0A,0xA5,0x7C,0x21,0x8D,0x34,0x17,0xA8,0xFB,0x47,0x0E, +0xFF,0x25,0x7C,0x8D,0x13,0x0A,0xFB,0xE4,0x98,0xB5,0xEF,0x8C,0xF8,0xC5,0x10,0x0D, +0xF7,0x92,0xBE,0xF1,0xC3,0xD5,0xD5,0x95,0x6A,0x04,0xBB,0x2C,0xCE,0x26,0x36,0x65, +0xC8,0x31,0xC6,0xE7,0xEE,0x3F,0xE3,0x57,0x75,0x84,0x7A,0x11,0xEF,0x46,0x4F,0x18, +0xF4,0xD3,0x98,0xBB,0xA8,0x87,0x32,0xBA,0x72,0xF6,0x3C,0xE2,0x3D,0x9F,0xD7,0x1D, +0xD9,0xC3,0x60,0x43,0x8C,0x58,0x0E,0x22,0x96,0x2F,0x62,0xA3,0x2C,0x1F,0xBA,0xAD, +0x05,0xEF,0xAB,0x32,0x78,0x87,0xA0,0x54,0x73,0x19,0xB5,0x5C,0x05,0xF9,0x52,0x3E, +0x6D,0x2D,0x45,0x0B,0xF7,0x0A,0x93,0xEA,0xED,0x06,0xF9,0xB2, +}; + + +/* subject:/C=US/O=Entrust, Inc./OU=www.entrust.net/CPS is incorporated by reference/OU=(c) 2006 Entrust, Inc./CN=Entrust Root Certification Authority */ +/* issuer :/C=US/O=Entrust, Inc./OU=www.entrust.net/CPS is incorporated by reference/OU=(c) 2006 Entrust, Inc./CN=Entrust Root Certification Authority */ + + +const unsigned char Entrust_Root_Certification_Authority_certificate[1173]={ +0x30,0x82,0x04,0x91,0x30,0x82,0x03,0x79,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x45, +0x6B,0x50,0x54,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x81,0xB0,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x45,0x6E,0x74, +0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39,0x30,0x37,0x06,0x03, +0x55,0x04,0x0B,0x13,0x30,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72,0x75,0x73,0x74, +0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x73,0x20,0x69,0x6E,0x63,0x6F, +0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x65, +0x72,0x65,0x6E,0x63,0x65,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16, +0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x45,0x6E,0x74,0x72,0x75,0x73,0x74, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x03,0x13, +0x24,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65, +0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68, +0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x32,0x37,0x32, +0x30,0x32,0x33,0x34,0x32,0x5A,0x17,0x0D,0x32,0x36,0x31,0x31,0x32,0x37,0x32,0x30, +0x35,0x33,0x34,0x32,0x5A,0x30,0x81,0xB0,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D, +0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39,0x30, +0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x77,0x77,0x77,0x2E,0x65,0x6E,0x74,0x72, +0x75,0x73,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x43,0x50,0x53,0x20,0x69,0x73,0x20,0x69, +0x6E,0x63,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x72, +0x65,0x66,0x65,0x72,0x65,0x6E,0x63,0x65,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04, +0x0B,0x13,0x16,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x45,0x6E,0x74,0x72, +0x75,0x73,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55, +0x04,0x03,0x13,0x24,0x45,0x6E,0x74,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, +0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00, +0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xB6,0x95,0xB6,0x43,0x42,0xFA,0xC6, +0x6D,0x2A,0x6F,0x48,0xDF,0x94,0x4C,0x39,0x57,0x05,0xEE,0xC3,0x79,0x11,0x41,0x68, +0x36,0xED,0xEC,0xFE,0x9A,0x01,0x8F,0xA1,0x38,0x28,0xFC,0xF7,0x10,0x46,0x66,0x2E, +0x4D,0x1E,0x1A,0xB1,0x1A,0x4E,0xC6,0xD1,0xC0,0x95,0x88,0xB0,0xC9,0xFF,0x31,0x8B, +0x33,0x03,0xDB,0xB7,0x83,0x7B,0x3E,0x20,0x84,0x5E,0xED,0xB2,0x56,0x28,0xA7,0xF8, +0xE0,0xB9,0x40,0x71,0x37,0xC5,0xCB,0x47,0x0E,0x97,0x2A,0x68,0xC0,0x22,0x95,0x62, +0x15,0xDB,0x47,0xD9,0xF5,0xD0,0x2B,0xFF,0x82,0x4B,0xC9,0xAD,0x3E,0xDE,0x4C,0xDB, +0x90,0x80,0x50,0x3F,0x09,0x8A,0x84,0x00,0xEC,0x30,0x0A,0x3D,0x18,0xCD,0xFB,0xFD, +0x2A,0x59,0x9A,0x23,0x95,0x17,0x2C,0x45,0x9E,0x1F,0x6E,0x43,0x79,0x6D,0x0C,0x5C, +0x98,0xFE,0x48,0xA7,0xC5,0x23,0x47,0x5C,0x5E,0xFD,0x6E,0xE7,0x1E,0xB4,0xF6,0x68, +0x45,0xD1,0x86,0x83,0x5B,0xA2,0x8A,0x8D,0xB1,0xE3,0x29,0x80,0xFE,0x25,0x71,0x88, +0xAD,0xBE,0xBC,0x8F,0xAC,0x52,0x96,0x4B,0xAA,0x51,0x8D,0xE4,0x13,0x31,0x19,0xE8, +0x4E,0x4D,0x9F,0xDB,0xAC,0xB3,0x6A,0xD5,0xBC,0x39,0x54,0x71,0xCA,0x7A,0x7A,0x7F, +0x90,0xDD,0x7D,0x1D,0x80,0xD9,0x81,0xBB,0x59,0x26,0xC2,0x11,0xFE,0xE6,0x93,0xE2, +0xF7,0x80,0xE4,0x65,0xFB,0x34,0x37,0x0E,0x29,0x80,0x70,0x4D,0xAF,0x38,0x86,0x2E, +0x9E,0x7F,0x57,0xAF,0x9E,0x17,0xAE,0xEB,0x1C,0xCB,0x28,0x21,0x5F,0xB6,0x1C,0xD8, +0xE7,0xA2,0x04,0x22,0xF9,0xD3,0xDA,0xD8,0xCB,0x02,0x03,0x01,0x00,0x01,0xA3,0x81, +0xB0,0x30,0x81,0xAD,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x2B,0x06,0x03,0x55,0x1D,0x10,0x04,0x24,0x30,0x22, +0x80,0x0F,0x32,0x30,0x30,0x36,0x31,0x31,0x32,0x37,0x32,0x30,0x32,0x33,0x34,0x32, +0x5A,0x81,0x0F,0x32,0x30,0x32,0x36,0x31,0x31,0x32,0x37,0x32,0x30,0x35,0x33,0x34, +0x32,0x5A,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x68, +0x90,0xE4,0x67,0xA4,0xA6,0x53,0x80,0xC7,0x86,0x66,0xA4,0xF1,0xF7,0x4B,0x43,0xFB, +0x84,0xBD,0x6D,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x68,0x90, +0xE4,0x67,0xA4,0xA6,0x53,0x80,0xC7,0x86,0x66,0xA4,0xF1,0xF7,0x4B,0x43,0xFB,0x84, +0xBD,0x6D,0x30,0x1D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x41,0x00,0x04, +0x10,0x30,0x0E,0x1B,0x08,0x56,0x37,0x2E,0x31,0x3A,0x34,0x2E,0x30,0x03,0x02,0x04, +0x90,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, +0x03,0x82,0x01,0x01,0x00,0x93,0xD4,0x30,0xB0,0xD7,0x03,0x20,0x2A,0xD0,0xF9,0x63, +0xE8,0x91,0x0C,0x05,0x20,0xA9,0x5F,0x19,0xCA,0x7B,0x72,0x4E,0xD4,0xB1,0xDB,0xD0, +0x96,0xFB,0x54,0x5A,0x19,0x2C,0x0C,0x08,0xF7,0xB2,0xBC,0x85,0xA8,0x9D,0x7F,0x6D, +0x3B,0x52,0xB3,0x2A,0xDB,0xE7,0xD4,0x84,0x8C,0x63,0xF6,0x0F,0xCB,0x26,0x01,0x91, +0x50,0x6C,0xF4,0x5F,0x14,0xE2,0x93,0x74,0xC0,0x13,0x9E,0x30,0x3A,0x50,0xE3,0xB4, +0x60,0xC5,0x1C,0xF0,0x22,0x44,0x8D,0x71,0x47,0xAC,0xC8,0x1A,0xC9,0xE9,0x9B,0x9A, +0x00,0x60,0x13,0xFF,0x70,0x7E,0x5F,0x11,0x4D,0x49,0x1B,0xB3,0x15,0x52,0x7B,0xC9, +0x54,0xDA,0xBF,0x9D,0x95,0xAF,0x6B,0x9A,0xD8,0x9E,0xE9,0xF1,0xE4,0x43,0x8D,0xE2, +0x11,0x44,0x3A,0xBF,0xAF,0xBD,0x83,0x42,0x73,0x52,0x8B,0xAA,0xBB,0xA7,0x29,0xCF, +0xF5,0x64,0x1C,0x0A,0x4D,0xD1,0xBC,0xAA,0xAC,0x9F,0x2A,0xD0,0xFF,0x7F,0x7F,0xDA, +0x7D,0xEA,0xB1,0xED,0x30,0x25,0xC1,0x84,0xDA,0x34,0xD2,0x5B,0x78,0x83,0x56,0xEC, +0x9C,0x36,0xC3,0x26,0xE2,0x11,0xF6,0x67,0x49,0x1D,0x92,0xAB,0x8C,0xFB,0xEB,0xFF, +0x7A,0xEE,0x85,0x4A,0xA7,0x50,0x80,0xF0,0xA7,0x5C,0x4A,0x94,0x2E,0x5F,0x05,0x99, +0x3C,0x52,0x41,0xE0,0xCD,0xB4,0x63,0xCF,0x01,0x43,0xBA,0x9C,0x83,0xDC,0x8F,0x60, +0x3B,0xF3,0x5A,0xB4,0xB4,0x7B,0xAE,0xDA,0x0B,0x90,0x38,0x75,0xEF,0x81,0x1D,0x66, +0xD2,0xF7,0x57,0x70,0x36,0xB3,0xBF,0xFC,0x28,0xAF,0x71,0x25,0x85,0x5B,0x13,0xFE, +0x1E,0x7F,0x5A,0xB4,0x3C, +}; + + +/* subject:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority */ +/* issuer :/C=US/O=Equifax/OU=Equifax Secure Certificate Authority */ + + +const unsigned char Equifax_Secure_CA_certificate[804]={ +0x30,0x82,0x03,0x20,0x30,0x82,0x02,0x89,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x35, +0xDE,0xF4,0xCF,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x4E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,0x13,0x07,0x45,0x71,0x75,0x69, +0x66,0x61,0x78,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x0B,0x13,0x24,0x45,0x71, +0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x30,0x1E,0x17,0x0D,0x39,0x38,0x30,0x38,0x32,0x32,0x31,0x36,0x34,0x31, +0x35,0x31,0x5A,0x17,0x0D,0x31,0x38,0x30,0x38,0x32,0x32,0x31,0x36,0x34,0x31,0x35, +0x31,0x5A,0x30,0x4E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,0x13,0x07,0x45,0x71,0x75,0x69, +0x66,0x61,0x78,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x0B,0x13,0x24,0x45,0x71, +0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xC1, +0x5D,0xB1,0x58,0x67,0x08,0x62,0xEE,0xA0,0x9A,0x2D,0x1F,0x08,0x6D,0x91,0x14,0x68, +0x98,0x0A,0x1E,0xFE,0xDA,0x04,0x6F,0x13,0x84,0x62,0x21,0xC3,0xD1,0x7C,0xCE,0x9F, +0x05,0xE0,0xB8,0x01,0xF0,0x4E,0x34,0xEC,0xE2,0x8A,0x95,0x04,0x64,0xAC,0xF1,0x6B, +0x53,0x5F,0x05,0xB3,0xCB,0x67,0x80,0xBF,0x42,0x02,0x8E,0xFE,0xDD,0x01,0x09,0xEC, +0xE1,0x00,0x14,0x4F,0xFC,0xFB,0xF0,0x0C,0xDD,0x43,0xBA,0x5B,0x2B,0xE1,0x1F,0x80, +0x70,0x99,0x15,0x57,0x93,0x16,0xF1,0x0F,0x97,0x6A,0xB7,0xC2,0x68,0x23,0x1C,0xCC, +0x4D,0x59,0x30,0xAC,0x51,0x1E,0x3B,0xAF,0x2B,0xD6,0xEE,0x63,0x45,0x7B,0xC5,0xD9, +0x5F,0x50,0xD2,0xE3,0x50,0x0F,0x3A,0x88,0xE7,0xBF,0x14,0xFD,0xE0,0xC7,0xB9,0x02, +0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0x09,0x30,0x82,0x01,0x05,0x30,0x70,0x06,0x03, +0x55,0x1D,0x1F,0x04,0x69,0x30,0x67,0x30,0x65,0xA0,0x63,0xA0,0x61,0xA4,0x5F,0x30, +0x5D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x10, +0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,0x13,0x07,0x45,0x71,0x75,0x69,0x66,0x61,0x78, +0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x0B,0x13,0x24,0x45,0x71,0x75,0x69,0x66, +0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66, +0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31, +0x0D,0x30,0x0B,0x06,0x03,0x55,0x04,0x03,0x13,0x04,0x43,0x52,0x4C,0x31,0x30,0x1A, +0x06,0x03,0x55,0x1D,0x10,0x04,0x13,0x30,0x11,0x81,0x0F,0x32,0x30,0x31,0x38,0x30, +0x38,0x32,0x32,0x31,0x36,0x34,0x31,0x35,0x31,0x5A,0x30,0x0B,0x06,0x03,0x55,0x1D, +0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18, +0x30,0x16,0x80,0x14,0x48,0xE6,0x68,0xF9,0x2B,0xD2,0xB2,0x95,0xD7,0x47,0xD8,0x23, +0x20,0x10,0x4F,0x33,0x98,0x90,0x9F,0xD4,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, +0x16,0x04,0x14,0x48,0xE6,0x68,0xF9,0x2B,0xD2,0xB2,0x95,0xD7,0x47,0xD8,0x23,0x20, +0x10,0x4F,0x33,0x98,0x90,0x9F,0xD4,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x1A,0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07, +0x41,0x00,0x04,0x0D,0x30,0x0B,0x1B,0x05,0x56,0x33,0x2E,0x30,0x63,0x03,0x02,0x06, +0xC0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, +0x03,0x81,0x81,0x00,0x58,0xCE,0x29,0xEA,0xFC,0xF7,0xDE,0xB5,0xCE,0x02,0xB9,0x17, +0xB5,0x85,0xD1,0xB9,0xE3,0xE0,0x95,0xCC,0x25,0x31,0x0D,0x00,0xA6,0x92,0x6E,0x7F, +0xB6,0x92,0x63,0x9E,0x50,0x95,0xD1,0x9A,0x6F,0xE4,0x11,0xDE,0x63,0x85,0x6E,0x98, +0xEE,0xA8,0xFF,0x5A,0xC8,0xD3,0x55,0xB2,0x66,0x71,0x57,0xDE,0xC0,0x21,0xEB,0x3D, +0x2A,0xA7,0x23,0x49,0x01,0x04,0x86,0x42,0x7B,0xFC,0xEE,0x7F,0xA2,0x16,0x52,0xB5, +0x67,0x67,0xD3,0x40,0xDB,0x3B,0x26,0x58,0xB2,0x28,0x77,0x3D,0xAE,0x14,0x77,0x61, +0xD6,0xFA,0x2A,0x66,0x27,0xA0,0x0D,0xFA,0xA7,0x73,0x5C,0xEA,0x70,0xF1,0x94,0x21, +0x65,0x44,0x5F,0xFA,0xFC,0xEF,0x29,0x68,0xA9,0xA2,0x87,0x79,0xEF,0x79,0xEF,0x4F, +0xAC,0x07,0x77,0x38, +}; + + +/* subject:/C=US/O=Equifax Secure Inc./CN=Equifax Secure eBusiness CA-1 */ +/* issuer :/C=US/O=Equifax Secure Inc./CN=Equifax Secure eBusiness CA-1 */ + + +const unsigned char Equifax_Secure_eBusiness_CA_1_certificate[646]={ +0x30,0x82,0x02,0x82,0x30,0x82,0x01,0xEB,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x04, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30, +0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C, +0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x45,0x71,0x75,0x69,0x66,0x61,0x78, +0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x26,0x30,0x24, +0x06,0x03,0x55,0x04,0x03,0x13,0x1D,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53, +0x65,0x63,0x75,0x72,0x65,0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65,0x73,0x73,0x20, +0x43,0x41,0x2D,0x31,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36,0x32,0x31,0x30,0x34, +0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x30,0x30,0x36,0x32,0x31,0x30,0x34,0x30, +0x30,0x30,0x30,0x5A,0x30,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x45,0x71, +0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x03,0x13,0x1D,0x45,0x71,0x75,0x69, +0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x65,0x42,0x75,0x73,0x69, +0x6E,0x65,0x73,0x73,0x20,0x43,0x41,0x2D,0x31,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30, +0x81,0x89,0x02,0x81,0x81,0x00,0xCE,0x2F,0x19,0xBC,0x17,0xB7,0x77,0xDE,0x93,0xA9, +0x5F,0x5A,0x0D,0x17,0x4F,0x34,0x1A,0x0C,0x98,0xF4,0x22,0xD9,0x59,0xD4,0xC4,0x68, +0x46,0xF0,0xB4,0x35,0xC5,0x85,0x03,0x20,0xC6,0xAF,0x45,0xA5,0x21,0x51,0x45,0x41, +0xEB,0x16,0x58,0x36,0x32,0x6F,0xE2,0x50,0x62,0x64,0xF9,0xFD,0x51,0x9C,0xAA,0x24, +0xD9,0xF4,0x9D,0x83,0x2A,0x87,0x0A,0x21,0xD3,0x12,0x38,0x34,0x6C,0x8D,0x00,0x6E, +0x5A,0xA0,0xD9,0x42,0xEE,0x1A,0x21,0x95,0xF9,0x52,0x4C,0x55,0x5A,0xC5,0x0F,0x38, +0x4F,0x46,0xFA,0x6D,0xF8,0x2E,0x35,0xD6,0x1D,0x7C,0xEB,0xE2,0xF0,0xB0,0x75,0x80, +0xC8,0xA9,0x13,0xAC,0xBE,0x88,0xEF,0x3A,0x6E,0xAB,0x5F,0x2A,0x38,0x62,0x02,0xB0, +0x12,0x7B,0xFE,0x8F,0xA6,0x03,0x02,0x03,0x01,0x00,0x01,0xA3,0x66,0x30,0x64,0x30, +0x11,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02, +0x00,0x07,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03, +0x01,0x01,0xFF,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14, +0x4A,0x78,0x32,0x52,0x11,0xDB,0x59,0x16,0x36,0x5E,0xDF,0xC1,0x14,0x36,0x40,0x6A, +0x47,0x7C,0x4C,0xA1,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4A, +0x78,0x32,0x52,0x11,0xDB,0x59,0x16,0x36,0x5E,0xDF,0xC1,0x14,0x36,0x40,0x6A,0x47, +0x7C,0x4C,0xA1,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04, +0x05,0x00,0x03,0x81,0x81,0x00,0x75,0x5B,0xA8,0x9B,0x03,0x11,0xE6,0xE9,0x56,0x4C, +0xCD,0xF9,0xA9,0x4C,0xC0,0x0D,0x9A,0xF3,0xCC,0x65,0x69,0xE6,0x25,0x76,0xCC,0x59, +0xB7,0xD6,0x54,0xC3,0x1D,0xCD,0x99,0xAC,0x19,0xDD,0xB4,0x85,0xD5,0xE0,0x3D,0xFC, +0x62,0x20,0xA7,0x84,0x4B,0x58,0x65,0xF1,0xE2,0xF9,0x95,0x21,0x3F,0xF5,0xD4,0x7E, +0x58,0x1E,0x47,0x87,0x54,0x3E,0x58,0xA1,0xB5,0xB5,0xF8,0x2A,0xEF,0x71,0xE7,0xBC, +0xC3,0xF6,0xB1,0x49,0x46,0xE2,0xD7,0xA0,0x6B,0xE5,0x56,0x7A,0x9A,0x27,0x98,0x7C, +0x46,0x62,0x14,0xE7,0xC9,0xFC,0x6E,0x03,0x12,0x79,0x80,0x38,0x1D,0x48,0x82,0x8D, +0xFC,0x17,0xFE,0x2A,0x96,0x2B,0xB5,0x62,0xA6,0xA6,0x3D,0xBD,0x7F,0x92,0x59,0xCD, +0x5A,0x2A,0x82,0xB2,0x37,0x79, +}; + + +/* subject:/C=US/O=Equifax Secure/OU=Equifax Secure eBusiness CA-2 */ +/* issuer :/C=US/O=Equifax Secure/OU=Equifax Secure eBusiness CA-2 */ + + +const unsigned char Equifax_Secure_eBusiness_CA_2_certificate[804]={ +0x30,0x82,0x03,0x20,0x30,0x82,0x02,0x89,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x37, +0x70,0xCF,0xB5,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x30,0x4E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x45,0x71,0x75,0x69, +0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x31,0x26,0x30,0x24,0x06,0x03, +0x55,0x04,0x0B,0x13,0x1D,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63, +0x75,0x72,0x65,0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65,0x73,0x73,0x20,0x43,0x41, +0x2D,0x32,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36,0x32,0x33,0x31,0x32,0x31,0x34, +0x34,0x35,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32,0x33,0x31,0x32,0x31,0x34,0x34, +0x35,0x5A,0x30,0x4E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x45,0x71,0x75,0x69, +0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x31,0x26,0x30,0x24,0x06,0x03, +0x55,0x04,0x0B,0x13,0x1D,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63, +0x75,0x72,0x65,0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65,0x73,0x73,0x20,0x43,0x41, +0x2D,0x32,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xE4, +0x39,0x39,0x93,0x1E,0x52,0x06,0x1B,0x28,0x36,0xF8,0xB2,0xA3,0x29,0xC5,0xED,0x8E, +0xB2,0x11,0xBD,0xFE,0xEB,0xE7,0xB4,0x74,0xC2,0x8F,0xFF,0x05,0xE7,0xD9,0x9D,0x06, +0xBF,0x12,0xC8,0x3F,0x0E,0xF2,0xD6,0xD1,0x24,0xB2,0x11,0xDE,0xD1,0x73,0x09,0x8A, +0xD4,0xB1,0x2C,0x98,0x09,0x0D,0x1E,0x50,0x46,0xB2,0x83,0xA6,0x45,0x8D,0x62,0x68, +0xBB,0x85,0x1B,0x20,0x70,0x32,0xAA,0x40,0xCD,0xA6,0x96,0x5F,0xC4,0x71,0x37,0x3F, +0x04,0xF3,0xB7,0x41,0x24,0x39,0x07,0x1A,0x1E,0x2E,0x61,0x58,0xA0,0x12,0x0B,0xE5, +0xA5,0xDF,0xC5,0xAB,0xEA,0x37,0x71,0xCC,0x1C,0xC8,0x37,0x3A,0xB9,0x97,0x52,0xA7, +0xAC,0xC5,0x6A,0x24,0x94,0x4E,0x9C,0x7B,0xCF,0xC0,0x6A,0xD6,0xDF,0x21,0xBD,0x02, +0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0x09,0x30,0x82,0x01,0x05,0x30,0x70,0x06,0x03, +0x55,0x1D,0x1F,0x04,0x69,0x30,0x67,0x30,0x65,0xA0,0x63,0xA0,0x61,0xA4,0x5F,0x30, +0x5D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x45,0x71,0x75,0x69,0x66,0x61,0x78, +0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B, +0x13,0x1D,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72,0x65, +0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65,0x73,0x73,0x20,0x43,0x41,0x2D,0x32,0x31, +0x0D,0x30,0x0B,0x06,0x03,0x55,0x04,0x03,0x13,0x04,0x43,0x52,0x4C,0x31,0x30,0x1A, +0x06,0x03,0x55,0x1D,0x10,0x04,0x13,0x30,0x11,0x81,0x0F,0x32,0x30,0x31,0x39,0x30, +0x36,0x32,0x33,0x31,0x32,0x31,0x34,0x34,0x35,0x5A,0x30,0x0B,0x06,0x03,0x55,0x1D, +0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18, +0x30,0x16,0x80,0x14,0x50,0x9E,0x0B,0xEA,0xAF,0x5E,0xB9,0x20,0x48,0xA6,0x50,0x6A, +0xCB,0xFD,0xD8,0x20,0x7A,0xA7,0x82,0x76,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, +0x16,0x04,0x14,0x50,0x9E,0x0B,0xEA,0xAF,0x5E,0xB9,0x20,0x48,0xA6,0x50,0x6A,0xCB, +0xFD,0xD8,0x20,0x7A,0xA7,0x82,0x76,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x1A,0x06,0x09,0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07, +0x41,0x00,0x04,0x0D,0x30,0x0B,0x1B,0x05,0x56,0x33,0x2E,0x30,0x63,0x03,0x02,0x06, +0xC0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, +0x03,0x81,0x81,0x00,0x0C,0x86,0x82,0xAD,0xE8,0x4E,0x1A,0xF5,0x8E,0x89,0x27,0xE2, +0x35,0x58,0x3D,0x29,0xB4,0x07,0x8F,0x36,0x50,0x95,0xBF,0x6E,0xC1,0x9E,0xEB,0xC4, +0x90,0xB2,0x85,0xA8,0xBB,0xB7,0x42,0xE0,0x0F,0x07,0x39,0xDF,0xFB,0x9E,0x90,0xB2, +0xD1,0xC1,0x3E,0x53,0x9F,0x03,0x44,0xB0,0x7E,0x4B,0xF4,0x6F,0xE4,0x7C,0x1F,0xE7, +0xE2,0xB1,0xE4,0xB8,0x9A,0xEF,0xC3,0xBD,0xCE,0xDE,0x0B,0x32,0x34,0xD9,0xDE,0x28, +0xED,0x33,0x6B,0xC4,0xD4,0xD7,0x3D,0x12,0x58,0xAB,0x7D,0x09,0x2D,0xCB,0x70,0xF5, +0x13,0x8A,0x94,0xA1,0x27,0xA4,0xD6,0x70,0xC5,0x6D,0x94,0xB5,0xC9,0x7D,0x9D,0xA0, +0xD2,0xC6,0x08,0x49,0xD9,0x66,0x9B,0xA6,0xD3,0xF4,0x0B,0xDC,0xC5,0x26,0x57,0xE1, +0x91,0x30,0xEA,0xCD, +}; + + +/* subject:/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1 */ +/* issuer :/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1 */ + + +const unsigned char Equifax_Secure_Global_eBusiness_CA_certificate[660]={ +0x30,0x82,0x02,0x90,0x30,0x82,0x01,0xF9,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30, +0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C, +0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x45,0x71,0x75,0x69,0x66,0x61,0x78, +0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B, +0x06,0x03,0x55,0x04,0x03,0x13,0x24,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53, +0x65,0x63,0x75,0x72,0x65,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x65,0x42,0x75, +0x73,0x69,0x6E,0x65,0x73,0x73,0x20,0x43,0x41,0x2D,0x31,0x30,0x1E,0x17,0x0D,0x39, +0x39,0x30,0x36,0x32,0x31,0x30,0x34,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x30, +0x30,0x36,0x32,0x31,0x30,0x34,0x30,0x30,0x30,0x30,0x5A,0x30,0x5A,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03, +0x55,0x04,0x0A,0x13,0x13,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63, +0x75,0x72,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04, +0x03,0x13,0x24,0x45,0x71,0x75,0x69,0x66,0x61,0x78,0x20,0x53,0x65,0x63,0x75,0x72, +0x65,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x65,0x42,0x75,0x73,0x69,0x6E,0x65, +0x73,0x73,0x20,0x43,0x41,0x2D,0x31,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xBA,0xE7,0x17,0x90,0x02,0x65,0xB1,0x34,0x55,0x3C,0x49,0xC2, +0x51,0xD5,0xDF,0xA7,0xD1,0x37,0x8F,0xD1,0xE7,0x81,0x73,0x41,0x52,0x60,0x9B,0x9D, +0xA1,0x17,0x26,0x78,0xAD,0xC7,0xB1,0xE8,0x26,0x94,0x32,0xB5,0xDE,0x33,0x8D,0x3A, +0x2F,0xDB,0xF2,0x9A,0x7A,0x5A,0x73,0x98,0xA3,0x5C,0xE9,0xFB,0x8A,0x73,0x1B,0x5C, +0xE7,0xC3,0xBF,0x80,0x6C,0xCD,0xA9,0xF4,0xD6,0x2B,0xC0,0xF7,0xF9,0x99,0xAA,0x63, +0xA2,0xB1,0x47,0x02,0x0F,0xD4,0xE4,0x51,0x3A,0x12,0x3C,0x6C,0x8A,0x5A,0x54,0x84, +0x70,0xDB,0xC1,0xC5,0x90,0xCF,0x72,0x45,0xCB,0xA8,0x59,0xC0,0xCD,0x33,0x9D,0x3F, +0xA3,0x96,0xEB,0x85,0x33,0x21,0x1C,0x3E,0x1E,0x3E,0x60,0x6E,0x76,0x9C,0x67,0x85, +0xC5,0xC8,0xC3,0x61,0x02,0x03,0x01,0x00,0x01,0xA3,0x66,0x30,0x64,0x30,0x11,0x06, +0x09,0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07, +0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01, +0xFF,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xBE,0xA8, +0xA0,0x74,0x72,0x50,0x6B,0x44,0xB7,0xC9,0x23,0xD8,0xFB,0xA8,0xFF,0xB3,0x57,0x6B, +0x68,0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xBE,0xA8,0xA0, +0x74,0x72,0x50,0x6B,0x44,0xB7,0xC9,0x23,0xD8,0xFB,0xA8,0xFF,0xB3,0x57,0x6B,0x68, +0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00, +0x03,0x81,0x81,0x00,0x30,0xE2,0x01,0x51,0xAA,0xC7,0xEA,0x5F,0xDA,0xB9,0xD0,0x65, +0x0F,0x30,0xD6,0x3E,0xDA,0x0D,0x14,0x49,0x6E,0x91,0x93,0x27,0x14,0x31,0xEF,0xC4, +0xF7,0x2D,0x45,0xF8,0xEC,0xC7,0xBF,0xA2,0x41,0x0D,0x23,0xB4,0x92,0xF9,0x19,0x00, +0x67,0xBD,0x01,0xAF,0xCD,0xE0,0x71,0xFC,0x5A,0xCF,0x64,0xC4,0xE0,0x96,0x98,0xD0, +0xA3,0x40,0xE2,0x01,0x8A,0xEF,0x27,0x07,0xF1,0x65,0x01,0x8A,0x44,0x2D,0x06,0x65, +0x75,0x52,0xC0,0x86,0x10,0x20,0x21,0x5F,0x6C,0x6B,0x0F,0x6C,0xAE,0x09,0x1C,0xAF, +0xF2,0xA2,0x18,0x34,0xC4,0x75,0xA4,0x73,0x1C,0xF1,0x8D,0xDC,0xEF,0xAD,0xF9,0xB3, +0x76,0xB4,0x92,0xBF,0xDC,0x95,0x10,0x1E,0xBE,0xCB,0xC8,0x3B,0x5A,0x84,0x60,0x19, +0x56,0x94,0xA9,0x55, +}; + + +/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */ +/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */ + + +const unsigned char GeoTrust_Global_CA_certificate[856]={ +0x30,0x82,0x03,0x54,0x30,0x82,0x02,0x3C,0xA0,0x03,0x02,0x01,0x02,0x02,0x03,0x02, +0x34,0x56,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05, +0x00,0x30,0x42,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, +0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72, +0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04, +0x03,0x13,0x12,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62, +0x61,0x6C,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x32,0x30,0x35,0x32,0x31,0x30, +0x34,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x32,0x30,0x35,0x32,0x31,0x30,0x34, +0x30,0x30,0x30,0x30,0x5A,0x30,0x42,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47, +0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1B,0x30,0x19, +0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F, +0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xDA,0xCC,0x18,0x63,0x30,0xFD, +0xF4,0x17,0x23,0x1A,0x56,0x7E,0x5B,0xDF,0x3C,0x6C,0x38,0xE4,0x71,0xB7,0x78,0x91, +0xD4,0xBC,0xA1,0xD8,0x4C,0xF8,0xA8,0x43,0xB6,0x03,0xE9,0x4D,0x21,0x07,0x08,0x88, +0xDA,0x58,0x2F,0x66,0x39,0x29,0xBD,0x05,0x78,0x8B,0x9D,0x38,0xE8,0x05,0xB7,0x6A, +0x7E,0x71,0xA4,0xE6,0xC4,0x60,0xA6,0xB0,0xEF,0x80,0xE4,0x89,0x28,0x0F,0x9E,0x25, +0xD6,0xED,0x83,0xF3,0xAD,0xA6,0x91,0xC7,0x98,0xC9,0x42,0x18,0x35,0x14,0x9D,0xAD, +0x98,0x46,0x92,0x2E,0x4F,0xCA,0xF1,0x87,0x43,0xC1,0x16,0x95,0x57,0x2D,0x50,0xEF, +0x89,0x2D,0x80,0x7A,0x57,0xAD,0xF2,0xEE,0x5F,0x6B,0xD2,0x00,0x8D,0xB9,0x14,0xF8, +0x14,0x15,0x35,0xD9,0xC0,0x46,0xA3,0x7B,0x72,0xC8,0x91,0xBF,0xC9,0x55,0x2B,0xCD, +0xD0,0x97,0x3E,0x9C,0x26,0x64,0xCC,0xDF,0xCE,0x83,0x19,0x71,0xCA,0x4E,0xE6,0xD4, +0xD5,0x7B,0xA9,0x19,0xCD,0x55,0xDE,0xC8,0xEC,0xD2,0x5E,0x38,0x53,0xE5,0x5C,0x4F, +0x8C,0x2D,0xFE,0x50,0x23,0x36,0xFC,0x66,0xE6,0xCB,0x8E,0xA4,0x39,0x19,0x00,0xB7, +0x95,0x02,0x39,0x91,0x0B,0x0E,0xFE,0x38,0x2E,0xD1,0x1D,0x05,0x9A,0xF6,0x4D,0x3E, +0x6F,0x0F,0x07,0x1D,0xAF,0x2C,0x1E,0x8F,0x60,0x39,0xE2,0xFA,0x36,0x53,0x13,0x39, +0xD4,0x5E,0x26,0x2B,0xDB,0x3D,0xA8,0x14,0xBD,0x32,0xEB,0x18,0x03,0x28,0x52,0x04, +0x71,0xE5,0xAB,0x33,0x3D,0xE1,0x38,0xBB,0x07,0x36,0x84,0x62,0x9C,0x79,0xEA,0x16, +0x30,0xF4,0x5F,0xC0,0x2B,0xE8,0x71,0x6B,0xE4,0xF9,0x02,0x03,0x01,0x00,0x01,0xA3, +0x53,0x30,0x51,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xC0, +0x7A,0x98,0x68,0x8D,0x89,0xFB,0xAB,0x05,0x64,0x0C,0x11,0x7D,0xAA,0x7D,0x65,0xB8, +0xCA,0xCC,0x4E,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14, +0xC0,0x7A,0x98,0x68,0x8D,0x89,0xFB,0xAB,0x05,0x64,0x0C,0x11,0x7D,0xAA,0x7D,0x65, +0xB8,0xCA,0xCC,0x4E,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x35,0xE3,0x29,0x6A,0xE5,0x2F,0x5D,0x54, +0x8E,0x29,0x50,0x94,0x9F,0x99,0x1A,0x14,0xE4,0x8F,0x78,0x2A,0x62,0x94,0xA2,0x27, +0x67,0x9E,0xD0,0xCF,0x1A,0x5E,0x47,0xE9,0xC1,0xB2,0xA4,0xCF,0xDD,0x41,0x1A,0x05, +0x4E,0x9B,0x4B,0xEE,0x4A,0x6F,0x55,0x52,0xB3,0x24,0xA1,0x37,0x0A,0xEB,0x64,0x76, +0x2A,0x2E,0x2C,0xF3,0xFD,0x3B,0x75,0x90,0xBF,0xFA,0x71,0xD8,0xC7,0x3D,0x37,0xD2, +0xB5,0x05,0x95,0x62,0xB9,0xA6,0xDE,0x89,0x3D,0x36,0x7B,0x38,0x77,0x48,0x97,0xAC, +0xA6,0x20,0x8F,0x2E,0xA6,0xC9,0x0C,0xC2,0xB2,0x99,0x45,0x00,0xC7,0xCE,0x11,0x51, +0x22,0x22,0xE0,0xA5,0xEA,0xB6,0x15,0x48,0x09,0x64,0xEA,0x5E,0x4F,0x74,0xF7,0x05, +0x3E,0xC7,0x8A,0x52,0x0C,0xDB,0x15,0xB4,0xBD,0x6D,0x9B,0xE5,0xC6,0xB1,0x54,0x68, +0xA9,0xE3,0x69,0x90,0xB6,0x9A,0xA5,0x0F,0xB8,0xB9,0x3F,0x20,0x7D,0xAE,0x4A,0xB5, +0xB8,0x9C,0xE4,0x1D,0xB6,0xAB,0xE6,0x94,0xA5,0xC1,0xC7,0x83,0xAD,0xDB,0xF5,0x27, +0x87,0x0E,0x04,0x6C,0xD5,0xFF,0xDD,0xA0,0x5D,0xED,0x87,0x52,0xB7,0x2B,0x15,0x02, +0xAE,0x39,0xA6,0x6A,0x74,0xE9,0xDA,0xC4,0xE7,0xBC,0x4D,0x34,0x1E,0xA9,0x5C,0x4D, +0x33,0x5F,0x92,0x09,0x2F,0x88,0x66,0x5D,0x77,0x97,0xC7,0x1D,0x76,0x13,0xA9,0xD5, +0xE5,0xF1,0x16,0x09,0x11,0x35,0xD5,0xAC,0xDB,0x24,0x71,0x70,0x2C,0x98,0x56,0x0B, +0xD9,0x17,0xB4,0xD1,0xE3,0x51,0x2B,0x5E,0x75,0xE8,0xD5,0xD0,0xDC,0x4F,0x34,0xED, +0xC2,0x05,0x66,0x80,0xA1,0xCB,0xE6,0x33, +}; + + +/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 2 */ +/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 2 */ + + +const unsigned char GeoTrust_Global_CA_2_certificate[874]={ +0x30,0x82,0x03,0x66,0x30,0x82,0x02,0x4E,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16, +0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, +0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x03,0x13, +0x14,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C, +0x20,0x43,0x41,0x20,0x32,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x33,0x30,0x34,0x30, +0x35,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x31,0x39,0x30,0x33,0x30,0x34,0x30,0x35, +0x30,0x30,0x30,0x30,0x5A,0x30,0x44,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47, +0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B, +0x06,0x03,0x55,0x04,0x03,0x13,0x14,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x43,0x41,0x20,0x32,0x30,0x82,0x01,0x22,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, +0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xEF,0x3C,0x4D,0x40, +0x3D,0x10,0xDF,0x3B,0x53,0x00,0xE1,0x67,0xFE,0x94,0x60,0x15,0x3E,0x85,0x88,0xF1, +0x89,0x0D,0x90,0xC8,0x28,0x23,0x99,0x05,0xE8,0x2B,0x20,0x9D,0xC6,0xF3,0x60,0x46, +0xD8,0xC1,0xB2,0xD5,0x8C,0x31,0xD9,0xDC,0x20,0x79,0x24,0x81,0xBF,0x35,0x32,0xFC, +0x63,0x69,0xDB,0xB1,0x2A,0x6B,0xEE,0x21,0x58,0xF2,0x08,0xE9,0x78,0xCB,0x6F,0xCB, +0xFC,0x16,0x52,0xC8,0x91,0xC4,0xFF,0x3D,0x73,0xDE,0xB1,0x3E,0xA7,0xC2,0x7D,0x66, +0xC1,0xF5,0x7E,0x52,0x24,0x1A,0xE2,0xD5,0x67,0x91,0xD0,0x82,0x10,0xD7,0x78,0x4B, +0x4F,0x2B,0x42,0x39,0xBD,0x64,0x2D,0x40,0xA0,0xB0,0x10,0xD3,0x38,0x48,0x46,0x88, +0xA1,0x0C,0xBB,0x3A,0x33,0x2A,0x62,0x98,0xFB,0x00,0x9D,0x13,0x59,0x7F,0x6F,0x3B, +0x72,0xAA,0xEE,0xA6,0x0F,0x86,0xF9,0x05,0x61,0xEA,0x67,0x7F,0x0C,0x37,0x96,0x8B, +0xE6,0x69,0x16,0x47,0x11,0xC2,0x27,0x59,0x03,0xB3,0xA6,0x60,0xC2,0x21,0x40,0x56, +0xFA,0xA0,0xC7,0x7D,0x3A,0x13,0xE3,0xEC,0x57,0xC7,0xB3,0xD6,0xAE,0x9D,0x89,0x80, +0xF7,0x01,0xE7,0x2C,0xF6,0x96,0x2B,0x13,0x0D,0x79,0x2C,0xD9,0xC0,0xE4,0x86,0x7B, +0x4B,0x8C,0x0C,0x72,0x82,0x8A,0xFB,0x17,0xCD,0x00,0x6C,0x3A,0x13,0x3C,0xB0,0x84, +0x87,0x4B,0x16,0x7A,0x29,0xB2,0x4F,0xDB,0x1D,0xD4,0x0B,0xF3,0x66,0x37,0xBD,0xD8, +0xF6,0x57,0xBB,0x5E,0x24,0x7A,0xB8,0x3C,0x8B,0xB9,0xFA,0x92,0x1A,0x1A,0x84,0x9E, +0xD8,0x74,0x8F,0xAA,0x1B,0x7F,0x5E,0xF4,0xFE,0x45,0x22,0x21,0x02,0x03,0x01,0x00, +0x01,0xA3,0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x71,0x38,0x36,0xF2,0x02,0x31,0x53,0x47,0x2B,0x6E,0xBA,0x65,0x46,0xA9,0x10, +0x15,0x58,0x20,0x05,0x09,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16, +0x80,0x14,0x71,0x38,0x36,0xF2,0x02,0x31,0x53,0x47,0x2B,0x6E,0xBA,0x65,0x46,0xA9, +0x10,0x15,0x58,0x20,0x05,0x09,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x03,0xF7,0xB5,0x2B,0xAB,0x5D, +0x10,0xFC,0x7B,0xB2,0xB2,0x5E,0xAC,0x9B,0x0E,0x7E,0x53,0x78,0x59,0x3E,0x42,0x04, +0xFE,0x75,0xA3,0xAD,0xAC,0x81,0x4E,0xD7,0x02,0x8B,0x5E,0xC4,0x2D,0xC8,0x52,0x76, +0xC7,0x2C,0x1F,0xFC,0x81,0x32,0x98,0xD1,0x4B,0xC6,0x92,0x93,0x33,0x35,0x31,0x2F, +0xFC,0xD8,0x1D,0x44,0xDD,0xE0,0x81,0x7F,0x9D,0xE9,0x8B,0xE1,0x64,0x91,0x62,0x0B, +0x39,0x08,0x8C,0xAC,0x74,0x9D,0x59,0xD9,0x7A,0x59,0x52,0x97,0x11,0xB9,0x16,0x7B, +0x6F,0x45,0xD3,0x96,0xD9,0x31,0x7D,0x02,0x36,0x0F,0x9C,0x3B,0x6E,0xCF,0x2C,0x0D, +0x03,0x46,0x45,0xEB,0xA0,0xF4,0x7F,0x48,0x44,0xC6,0x08,0x40,0xCC,0xDE,0x1B,0x70, +0xB5,0x29,0xAD,0xBA,0x8B,0x3B,0x34,0x65,0x75,0x1B,0x71,0x21,0x1D,0x2C,0x14,0x0A, +0xB0,0x96,0x95,0xB8,0xD6,0xEA,0xF2,0x65,0xFB,0x29,0xBA,0x4F,0xEA,0x91,0x93,0x74, +0x69,0xB6,0xF2,0xFF,0xE1,0x1A,0xD0,0x0C,0xD1,0x76,0x85,0xCB,0x8A,0x25,0xBD,0x97, +0x5E,0x2C,0x6F,0x15,0x99,0x26,0xE7,0xB6,0x29,0xFF,0x22,0xEC,0xC9,0x02,0xC7,0x56, +0x00,0xCD,0x49,0xB9,0xB3,0x6C,0x7B,0x53,0x04,0x1A,0xE2,0xA8,0xC9,0xAA,0x12,0x05, +0x23,0xC2,0xCE,0xE7,0xBB,0x04,0x02,0xCC,0xC0,0x47,0xA2,0xE4,0xC4,0x29,0x2F,0x5B, +0x45,0x57,0x89,0x51,0xEE,0x3C,0xEB,0x52,0x08,0xFF,0x07,0x35,0x1E,0x9F,0x35,0x6A, +0x47,0x4A,0x56,0x98,0xD1,0x5A,0x85,0x1F,0x8C,0xF5,0x22,0xBF,0xAB,0xCE,0x83,0xF3, +0xE2,0x22,0x29,0xAE,0x7D,0x83,0x40,0xA8,0xBA,0x6C, +}; + + +/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Primary Certification Authority */ +/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Primary Certification Authority */ + + +const unsigned char GeoTrust_Primary_Certification_Authority_certificate[896]={ +0x30,0x82,0x03,0x7C,0x30,0x82,0x02,0x64,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x18, +0xAC,0xB5,0x6A,0xFD,0x69,0xB6,0x15,0x3A,0x63,0x6C,0xAF,0xDA,0xFA,0xC4,0xA1,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x58, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30, +0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74, +0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x03,0x13,0x28, +0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, +0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31, +0x32,0x37,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x37,0x31, +0x36,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x58,0x31,0x0B,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A, +0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31, +0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x03,0x13,0x28,0x47,0x65,0x6F,0x54,0x72,0x75, +0x73,0x74,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xBE,0xB8,0x15,0x7B,0xFF,0xD4,0x7C,0x7D,0x67,0xAD,0x83,0x64,0x7B, +0xC8,0x42,0x53,0x2D,0xDF,0xF6,0x84,0x08,0x20,0x61,0xD6,0x01,0x59,0x6A,0x9C,0x44, +0x11,0xAF,0xEF,0x76,0xFD,0x95,0x7E,0xCE,0x61,0x30,0xBB,0x7A,0x83,0x5F,0x02,0xBD, +0x01,0x66,0xCA,0xEE,0x15,0x8D,0x6F,0xA1,0x30,0x9C,0xBD,0xA1,0x85,0x9E,0x94,0x3A, +0xF3,0x56,0x88,0x00,0x31,0xCF,0xD8,0xEE,0x6A,0x96,0x02,0xD9,0xED,0x03,0x8C,0xFB, +0x75,0x6D,0xE7,0xEA,0xB8,0x55,0x16,0x05,0x16,0x9A,0xF4,0xE0,0x5E,0xB1,0x88,0xC0, +0x64,0x85,0x5C,0x15,0x4D,0x88,0xC7,0xB7,0xBA,0xE0,0x75,0xE9,0xAD,0x05,0x3D,0x9D, +0xC7,0x89,0x48,0xE0,0xBB,0x28,0xC8,0x03,0xE1,0x30,0x93,0x64,0x5E,0x52,0xC0,0x59, +0x70,0x22,0x35,0x57,0x88,0x8A,0xF1,0x95,0x0A,0x83,0xD7,0xBC,0x31,0x73,0x01,0x34, +0xED,0xEF,0x46,0x71,0xE0,0x6B,0x02,0xA8,0x35,0x72,0x6B,0x97,0x9B,0x66,0xE0,0xCB, +0x1C,0x79,0x5F,0xD8,0x1A,0x04,0x68,0x1E,0x47,0x02,0xE6,0x9D,0x60,0xE2,0x36,0x97, +0x01,0xDF,0xCE,0x35,0x92,0xDF,0xBE,0x67,0xC7,0x6D,0x77,0x59,0x3B,0x8F,0x9D,0xD6, +0x90,0x15,0x94,0xBC,0x42,0x34,0x10,0xC1,0x39,0xF9,0xB1,0x27,0x3E,0x7E,0xD6,0x8A, +0x75,0xC5,0xB2,0xAF,0x96,0xD3,0xA2,0xDE,0x9B,0xE4,0x98,0xBE,0x7D,0xE1,0xE9,0x81, +0xAD,0xB6,0x6F,0xFC,0xD7,0x0E,0xDA,0xE0,0x34,0xB0,0x0D,0x1A,0x77,0xE7,0xE3,0x08, +0x98,0xEF,0x58,0xFA,0x9C,0x84,0xB7,0x36,0xAF,0xC2,0xDF,0xAC,0xD2,0xF4,0x10,0x06, +0x70,0x71,0x35,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03, +0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06, +0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x2C,0xD5,0x50,0x41,0x97,0x15,0x8B,0xF0, +0x8F,0x36,0x61,0x5B,0x4A,0xFB,0x6B,0xD9,0x99,0xC9,0x33,0x92,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00, +0x5A,0x70,0x7F,0x2C,0xDD,0xB7,0x34,0x4F,0xF5,0x86,0x51,0xA9,0x26,0xBE,0x4B,0xB8, +0xAA,0xF1,0x71,0x0D,0xDC,0x61,0xC7,0xA0,0xEA,0x34,0x1E,0x7A,0x77,0x0F,0x04,0x35, +0xE8,0x27,0x8F,0x6C,0x90,0xBF,0x91,0x16,0x24,0x46,0x3E,0x4A,0x4E,0xCE,0x2B,0x16, +0xD5,0x0B,0x52,0x1D,0xFC,0x1F,0x67,0xA2,0x02,0x45,0x31,0x4F,0xCE,0xF3,0xFA,0x03, +0xA7,0x79,0x9D,0x53,0x6A,0xD9,0xDA,0x63,0x3A,0xF8,0x80,0xD7,0xD3,0x99,0xE1,0xA5, +0xE1,0xBE,0xD4,0x55,0x71,0x98,0x35,0x3A,0xBE,0x93,0xEA,0xAE,0xAD,0x42,0xB2,0x90, +0x6F,0xE0,0xFC,0x21,0x4D,0x35,0x63,0x33,0x89,0x49,0xD6,0x9B,0x4E,0xCA,0xC7,0xE7, +0x4E,0x09,0x00,0xF7,0xDA,0xC7,0xEF,0x99,0x62,0x99,0x77,0xB6,0x95,0x22,0x5E,0x8A, +0xA0,0xAB,0xF4,0xB8,0x78,0x98,0xCA,0x38,0x19,0x99,0xC9,0x72,0x9E,0x78,0xCD,0x4B, +0xAC,0xAF,0x19,0xA0,0x73,0x12,0x2D,0xFC,0xC2,0x41,0xBA,0x81,0x91,0xDA,0x16,0x5A, +0x31,0xB7,0xF9,0xB4,0x71,0x80,0x12,0x48,0x99,0x72,0x73,0x5A,0x59,0x53,0xC1,0x63, +0x52,0x33,0xED,0xA7,0xC9,0xD2,0x39,0x02,0x70,0xFA,0xE0,0xB1,0x42,0x66,0x29,0xAA, +0x9B,0x51,0xED,0x30,0x54,0x22,0x14,0x5F,0xD9,0xAB,0x1D,0xC1,0xE4,0x94,0xF0,0xF8, +0xF5,0x2B,0xF7,0xEA,0xCA,0x78,0x46,0xD6,0xB8,0x91,0xFD,0xA6,0x0D,0x2B,0x1A,0x14, +0x01,0x3E,0x80,0xF0,0x42,0xA0,0x95,0x07,0x5E,0x6D,0xCD,0xCC,0x4B,0xA4,0x45,0x8D, +0xAB,0x12,0xE8,0xB3,0xDE,0x5A,0xE5,0xA0,0x7C,0xE8,0x0F,0x22,0x1D,0x5A,0xE9,0x59, +}; + + +/* subject:/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */ +/* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */ + + +const unsigned char GeoTrust_Primary_Certification_Authority___G2_certificate[690]={ +0x30,0x82,0x02,0xAE,0x30,0x82,0x02,0x35,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x3C, +0xB2,0xF4,0x48,0x0A,0x00,0xE2,0xFE,0xEB,0x24,0x3B,0x5E,0x60,0x3E,0xC3,0x6B,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x98,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49, +0x6E,0x63,0x2E,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28,0x63, +0x29,0x20,0x32,0x30,0x30,0x37,0x20,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20, +0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F, +0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x36, +0x30,0x34,0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, +0x74,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66, +0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, +0x79,0x20,0x2D,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x37,0x31,0x31,0x30,0x35, +0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32, +0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x98,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13, +0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39, +0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28,0x63,0x29,0x20,0x32,0x30,0x30, +0x37,0x20,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x20, +0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64, +0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x36,0x30,0x34,0x06,0x03,0x55, +0x04,0x03,0x13,0x2D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x69, +0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69, +0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47, +0x32,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05, +0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x15,0xB1,0xE8,0xFD,0x03,0x15,0x43, +0xE5,0xAC,0xEB,0x87,0x37,0x11,0x62,0xEF,0xD2,0x83,0x36,0x52,0x7D,0x45,0x57,0x0B, +0x4A,0x8D,0x7B,0x54,0x3B,0x3A,0x6E,0x5F,0x15,0x02,0xC0,0x50,0xA6,0xCF,0x25,0x2F, +0x7D,0xCA,0x48,0xB8,0xC7,0x50,0x63,0x1C,0x2A,0x21,0x08,0x7C,0x9A,0x36,0xD8,0x0B, +0xFE,0xD1,0x26,0xC5,0x58,0x31,0x30,0x28,0x25,0xF3,0x5D,0x5D,0xA3,0xB8,0xB6,0xA5, +0xB4,0x92,0xED,0x6C,0x2C,0x9F,0xEB,0xDD,0x43,0x89,0xA2,0x3C,0x4B,0x48,0x91,0x1D, +0x50,0xEC,0x26,0xDF,0xD6,0x60,0x2E,0xBD,0x21,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x15,0x5F,0x35,0x57,0x51,0x55,0xFB, +0x25,0xB2,0xAD,0x03,0x69,0xFC,0x01,0xA3,0xFA,0xBE,0x11,0x55,0xD5,0x30,0x0A,0x06, +0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x67,0x00,0x30,0x64,0x02,0x30, +0x64,0x96,0x59,0xA6,0xE8,0x09,0xDE,0x8B,0xBA,0xFA,0x5A,0x88,0x88,0xF0,0x1F,0x91, +0xD3,0x46,0xA8,0xF2,0x4A,0x4C,0x02,0x63,0xFB,0x6C,0x5F,0x38,0xDB,0x2E,0x41,0x93, +0xA9,0x0E,0xE6,0x9D,0xDC,0x31,0x1C,0xB2,0xA0,0xA7,0x18,0x1C,0x79,0xE1,0xC7,0x36, +0x02,0x30,0x3A,0x56,0xAF,0x9A,0x74,0x6C,0xF6,0xFB,0x83,0xE0,0x33,0xD3,0x08,0x5F, +0xA1,0x9C,0xC2,0x5B,0x9F,0x46,0xD6,0xB6,0xCB,0x91,0x06,0x63,0xA2,0x06,0xE7,0x33, +0xAC,0x3E,0xA8,0x81,0x12,0xD0,0xCB,0xBA,0xD0,0x92,0x0B,0xB6,0x9E,0x96,0xAA,0x04, +0x0F,0x8A, +}; + + +/* subject:/C=US/O=GeoTrust Inc./OU=(c) 2008 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G3 */ +/* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2008 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G3 */ + + +const unsigned char GeoTrust_Primary_Certification_Authority___G3_certificate[1026]={ +0x30,0x82,0x03,0xFE,0x30,0x82,0x02,0xE6,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x15, +0xAC,0x6E,0x94,0x19,0xB2,0x79,0x4B,0x41,0xF6,0x27,0xA9,0xC3,0x18,0x0F,0x1F,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81, +0x98,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16, +0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, +0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13, +0x30,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x38,0x20,0x47,0x65,0x6F,0x54,0x72,0x75, +0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75, +0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C, +0x79,0x31,0x36,0x30,0x34,0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x47,0x65,0x6F,0x54, +0x72,0x75,0x73,0x74,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F, +0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x33,0x30,0x1E,0x17,0x0D,0x30,0x38,0x30, +0x34,0x30,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x32, +0x30,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x98,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55, +0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x0B,0x13,0x30,0x28,0x63,0x29,0x20, +0x32,0x30,0x30,0x38,0x20,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E, +0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69, +0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x36,0x30,0x34, +0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20, +0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, +0x2D,0x20,0x47,0x33,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xDC,0xE2,0x5E,0x62,0x58,0x1D,0x33,0x57,0x39,0x32,0x33, +0xFA,0xEB,0xCB,0x87,0x8C,0xA7,0xD4,0x4A,0xDD,0x06,0x88,0xEA,0x64,0x8E,0x31,0x98, +0xA5,0x38,0x90,0x1E,0x98,0xCF,0x2E,0x63,0x2B,0xF0,0x46,0xBC,0x44,0xB2,0x89,0xA1, +0xC0,0x28,0x0C,0x49,0x70,0x21,0x95,0x9F,0x64,0xC0,0xA6,0x93,0x12,0x02,0x65,0x26, +0x86,0xC6,0xA5,0x89,0xF0,0xFA,0xD7,0x84,0xA0,0x70,0xAF,0x4F,0x1A,0x97,0x3F,0x06, +0x44,0xD5,0xC9,0xEB,0x72,0x10,0x7D,0xE4,0x31,0x28,0xFB,0x1C,0x61,0xE6,0x28,0x07, +0x44,0x73,0x92,0x22,0x69,0xA7,0x03,0x88,0x6C,0x9D,0x63,0xC8,0x52,0xDA,0x98,0x27, +0xE7,0x08,0x4C,0x70,0x3E,0xB4,0xC9,0x12,0xC1,0xC5,0x67,0x83,0x5D,0x33,0xF3,0x03, +0x11,0xEC,0x6A,0xD0,0x53,0xE2,0xD1,0xBA,0x36,0x60,0x94,0x80,0xBB,0x61,0x63,0x6C, +0x5B,0x17,0x7E,0xDF,0x40,0x94,0x1E,0xAB,0x0D,0xC2,0x21,0x28,0x70,0x88,0xFF,0xD6, +0x26,0x6C,0x6C,0x60,0x04,0x25,0x4E,0x55,0x7E,0x7D,0xEF,0xBF,0x94,0x48,0xDE,0xB7, +0x1D,0xDD,0x70,0x8D,0x05,0x5F,0x88,0xA5,0x9B,0xF2,0xC2,0xEE,0xEA,0xD1,0x40,0x41, +0x6D,0x62,0x38,0x1D,0x56,0x06,0xC5,0x03,0x47,0x51,0x20,0x19,0xFC,0x7B,0x10,0x0B, +0x0E,0x62,0xAE,0x76,0x55,0xBF,0x5F,0x77,0xBE,0x3E,0x49,0x01,0x53,0x3D,0x98,0x25, +0x03,0x76,0x24,0x5A,0x1D,0xB4,0xDB,0x89,0xEA,0x79,0xE5,0xB6,0xB3,0x3B,0x3F,0xBA, +0x4C,0x28,0x41,0x7F,0x06,0xAC,0x6A,0x8E,0xC1,0xD0,0xF6,0x05,0x1D,0x7D,0xE6,0x42, +0x86,0xE3,0xA5,0xD5,0x47,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F, +0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30, +0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xC4,0x79,0xCA,0x8E,0xA1,0x4E, +0x03,0x1D,0x1C,0xDC,0x6B,0xDB,0x31,0x5B,0x94,0x3E,0x3F,0x30,0x7F,0x2D,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01, +0x01,0x00,0x2D,0xC5,0x13,0xCF,0x56,0x80,0x7B,0x7A,0x78,0xBD,0x9F,0xAE,0x2C,0x99, +0xE7,0xEF,0xDA,0xDF,0x94,0x5E,0x09,0x69,0xA7,0xE7,0x6E,0x68,0x8C,0xBD,0x72,0xBE, +0x47,0xA9,0x0E,0x97,0x12,0xB8,0x4A,0xF1,0x64,0xD3,0x39,0xDF,0x25,0x34,0xD4,0xC1, +0xCD,0x4E,0x81,0xF0,0x0F,0x04,0xC4,0x24,0xB3,0x34,0x96,0xC6,0xA6,0xAA,0x30,0xDF, +0x68,0x61,0x73,0xD7,0xF9,0x8E,0x85,0x89,0xEF,0x0E,0x5E,0x95,0x28,0x4A,0x2A,0x27, +0x8F,0x10,0x8E,0x2E,0x7C,0x86,0xC4,0x02,0x9E,0xDA,0x0C,0x77,0x65,0x0E,0x44,0x0D, +0x92,0xFD,0xFD,0xB3,0x16,0x36,0xFA,0x11,0x0D,0x1D,0x8C,0x0E,0x07,0x89,0x6A,0x29, +0x56,0xF7,0x72,0xF4,0xDD,0x15,0x9C,0x77,0x35,0x66,0x57,0xAB,0x13,0x53,0xD8,0x8E, +0xC1,0x40,0xC5,0xD7,0x13,0x16,0x5A,0x72,0xC7,0xB7,0x69,0x01,0xC4,0x7A,0xB1,0x83, +0x01,0x68,0x7D,0x8D,0x41,0xA1,0x94,0x18,0xC1,0x25,0x5C,0xFC,0xF0,0xFE,0x83,0x02, +0x87,0x7C,0x0D,0x0D,0xCF,0x2E,0x08,0x5C,0x4A,0x40,0x0D,0x3E,0xEC,0x81,0x61,0xE6, +0x24,0xDB,0xCA,0xE0,0x0E,0x2D,0x07,0xB2,0x3E,0x56,0xDC,0x8D,0xF5,0x41,0x85,0x07, +0x48,0x9B,0x0C,0x0B,0xCB,0x49,0x3F,0x7D,0xEC,0xB7,0xFD,0xCB,0x8D,0x67,0x89,0x1A, +0xAB,0xED,0xBB,0x1E,0xA3,0x00,0x08,0x08,0x17,0x2A,0x82,0x5C,0x31,0x5D,0x46,0x8A, +0x2D,0x0F,0x86,0x9B,0x74,0xD9,0x45,0xFB,0xD4,0x40,0xB1,0x7A,0xAA,0x68,0x2D,0x86, +0xB2,0x99,0x22,0xE1,0xC1,0x2B,0xC7,0x9C,0xF8,0xF3,0x5F,0xA8,0x82,0x12,0xEB,0x19, +0x11,0x2D, +}; + + +/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA */ +/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA */ + + +const unsigned char GeoTrust_Universal_CA_certificate[1388]={ +0x30,0x82,0x05,0x68,0x30,0x82,0x03,0x50,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16, +0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, +0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x03,0x13, +0x15,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x55,0x6E,0x69,0x76,0x65,0x72, +0x73,0x61,0x6C,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x33,0x30,0x34, +0x30,0x35,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x30,0x33,0x30,0x34,0x30, +0x35,0x30,0x30,0x30,0x30,0x5A,0x30,0x45,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D, +0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1E,0x30, +0x1C,0x06,0x03,0x55,0x04,0x03,0x13,0x15,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74, +0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x30,0x82,0x02, +0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, +0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xA6,0x15, +0x55,0xA0,0xA3,0xC6,0xE0,0x1F,0x8C,0x9D,0x21,0x50,0xD7,0xC1,0xBE,0x2B,0x5B,0xB5, +0xA4,0x9E,0xA1,0xD9,0x72,0x58,0xBD,0x00,0x1B,0x4C,0xBF,0x61,0xC9,0x14,0x1D,0x45, +0x82,0xAB,0xC6,0x1D,0x80,0xD6,0x3D,0xEB,0x10,0x9C,0x3A,0xAF,0x6D,0x24,0xF8,0xBC, +0x71,0x01,0x9E,0x06,0xF5,0x7C,0x5F,0x1E,0xC1,0x0E,0x55,0xCA,0x83,0x9A,0x59,0x30, +0xAE,0x19,0xCB,0x30,0x48,0x95,0xED,0x22,0x37,0x8D,0xF4,0x4A,0x9A,0x72,0x66,0x3E, +0xAD,0x95,0xC0,0xE0,0x16,0x00,0xE0,0x10,0x1F,0x2B,0x31,0x0E,0xD7,0x94,0x54,0xD3, +0x42,0x33,0xA0,0x34,0x1D,0x1E,0x45,0x76,0xDD,0x4F,0xCA,0x18,0x37,0xEC,0x85,0x15, +0x7A,0x19,0x08,0xFC,0xD5,0xC7,0x9C,0xF0,0xF2,0xA9,0x2E,0x10,0xA9,0x92,0xE6,0x3D, +0x58,0x3D,0xA9,0x16,0x68,0x3C,0x2F,0x75,0x21,0x18,0x7F,0x28,0x77,0xA5,0xE1,0x61, +0x17,0xB7,0xA6,0xE9,0xF8,0x1E,0x99,0xDB,0x73,0x6E,0xF4,0x0A,0xA2,0x21,0x6C,0xEE, +0xDA,0xAA,0x85,0x92,0x66,0xAF,0xF6,0x7A,0x6B,0x82,0xDA,0xBA,0x22,0x08,0x35,0x0F, +0xCF,0x42,0xF1,0x35,0xFA,0x6A,0xEE,0x7E,0x2B,0x25,0xCC,0x3A,0x11,0xE4,0x6D,0xAF, +0x73,0xB2,0x76,0x1D,0xAD,0xD0,0xB2,0x78,0x67,0x1A,0xA4,0x39,0x1C,0x51,0x0B,0x67, +0x56,0x83,0xFD,0x38,0x5D,0x0D,0xCE,0xDD,0xF0,0xBB,0x2B,0x96,0x1F,0xDE,0x7B,0x32, +0x52,0xFD,0x1D,0xBB,0xB5,0x06,0xA1,0xB2,0x21,0x5E,0xA5,0xD6,0x95,0x68,0x7F,0xF0, +0x99,0x9E,0xDC,0x45,0x08,0x3E,0xE7,0xD2,0x09,0x0D,0x35,0x94,0xDD,0x80,0x4E,0x53, +0x97,0xD7,0xB5,0x09,0x44,0x20,0x64,0x16,0x17,0x03,0x02,0x4C,0x53,0x0D,0x68,0xDE, +0xD5,0xAA,0x72,0x4D,0x93,0x6D,0x82,0x0E,0xDB,0x9C,0xBD,0xCF,0xB4,0xF3,0x5C,0x5D, +0x54,0x7A,0x69,0x09,0x96,0xD6,0xDB,0x11,0xC1,0x8D,0x75,0xA8,0xB4,0xCF,0x39,0xC8, +0xCE,0x3C,0xBC,0x24,0x7C,0xE6,0x62,0xCA,0xE1,0xBD,0x7D,0xA7,0xBD,0x57,0x65,0x0B, +0xE4,0xFE,0x25,0xED,0xB6,0x69,0x10,0xDC,0x28,0x1A,0x46,0xBD,0x01,0x1D,0xD0,0x97, +0xB5,0xE1,0x98,0x3B,0xC0,0x37,0x64,0xD6,0x3D,0x94,0xEE,0x0B,0xE1,0xF5,0x28,0xAE, +0x0B,0x56,0xBF,0x71,0x8B,0x23,0x29,0x41,0x8E,0x86,0xC5,0x4B,0x52,0x7B,0xD8,0x71, +0xAB,0x1F,0x8A,0x15,0xA6,0x3B,0x83,0x5A,0xD7,0x58,0x01,0x51,0xC6,0x4C,0x41,0xD9, +0x7F,0xD8,0x41,0x67,0x72,0xA2,0x28,0xDF,0x60,0x83,0xA9,0x9E,0xC8,0x7B,0xFC,0x53, +0x73,0x72,0x59,0xF5,0x93,0x7A,0x17,0x76,0x0E,0xCE,0xF7,0xE5,0x5C,0xD9,0x0B,0x55, +0x34,0xA2,0xAA,0x5B,0xB5,0x6A,0x54,0xE7,0x13,0xCA,0x57,0xEC,0x97,0x6D,0xF4,0x5E, +0x06,0x2F,0x45,0x8B,0x58,0xD4,0x23,0x16,0x92,0xE4,0x16,0x6E,0x28,0x63,0x59,0x30, +0xDF,0x50,0x01,0x9C,0x63,0x89,0x1A,0x9F,0xDB,0x17,0x94,0x82,0x70,0x37,0xC3,0x24, +0x9E,0x9A,0x47,0xD6,0x5A,0xCA,0x4E,0xA8,0x69,0x89,0x72,0x1F,0x91,0x6C,0xDB,0x7E, +0x9E,0x1B,0xAD,0xC7,0x1F,0x73,0xDD,0x2C,0x4F,0x19,0x65,0xFD,0x7F,0x93,0x40,0x10, +0x2E,0xD2,0xF0,0xED,0x3C,0x9E,0x2E,0x28,0x3E,0x69,0x26,0x33,0xC5,0x7B,0x02,0x03, +0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01, +0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, +0x16,0x04,0x14,0xDA,0xBB,0x2E,0xAA,0xB0,0x0C,0xB8,0x88,0x26,0x51,0x74,0x5C,0x6D, +0x03,0xD3,0xC0,0xD8,0x8F,0x7A,0xD6,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18, +0x30,0x16,0x80,0x14,0xDA,0xBB,0x2E,0xAA,0xB0,0x0C,0xB8,0x88,0x26,0x51,0x74,0x5C, +0x6D,0x03,0xD3,0xC0,0xD8,0x8F,0x7A,0xD6,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01, +0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x31,0x78,0xE6,0xC7, +0xB5,0xDF,0xB8,0x94,0x40,0xC9,0x71,0xC4,0xA8,0x35,0xEC,0x46,0x1D,0xC2,0x85,0xF3, +0x28,0x58,0x86,0xB0,0x0B,0xFC,0x8E,0xB2,0x39,0x8F,0x44,0x55,0xAB,0x64,0x84,0x5C, +0x69,0xA9,0xD0,0x9A,0x38,0x3C,0xFA,0xE5,0x1F,0x35,0xE5,0x44,0xE3,0x80,0x79,0x94, +0x68,0xA4,0xBB,0xC4,0x9F,0x3D,0xE1,0x34,0xCD,0x30,0x46,0x8B,0x54,0x2B,0x95,0xA5, +0xEF,0xF7,0x3F,0x99,0x84,0xFD,0x35,0xE6,0xCF,0x31,0xC6,0xDC,0x6A,0xBF,0xA7,0xD7, +0x23,0x08,0xE1,0x98,0x5E,0xC3,0x5A,0x08,0x76,0xA9,0xA6,0xAF,0x77,0x2F,0xB7,0x60, +0xBD,0x44,0x46,0x6A,0xEF,0x97,0xFF,0x73,0x95,0xC1,0x8E,0xE8,0x93,0xFB,0xFD,0x31, +0xB7,0xEC,0x57,0x11,0x11,0x45,0x9B,0x30,0xF1,0x1A,0x88,0x39,0xC1,0x4F,0x3C,0xA7, +0x00,0xD5,0xC7,0xFC,0xAB,0x6D,0x80,0x22,0x70,0xA5,0x0C,0xE0,0x5D,0x04,0x29,0x02, +0xFB,0xCB,0xA0,0x91,0xD1,0x7C,0xD6,0xC3,0x7E,0x50,0xD5,0x9D,0x58,0xBE,0x41,0x38, +0xEB,0xB9,0x75,0x3C,0x15,0xD9,0x9B,0xC9,0x4A,0x83,0x59,0xC0,0xDA,0x53,0xFD,0x33, +0xBB,0x36,0x18,0x9B,0x85,0x0F,0x15,0xDD,0xEE,0x2D,0xAC,0x76,0x93,0xB9,0xD9,0x01, +0x8D,0x48,0x10,0xA8,0xFB,0xF5,0x38,0x86,0xF1,0xDB,0x0A,0xC6,0xBD,0x84,0xA3,0x23, +0x41,0xDE,0xD6,0x77,0x6F,0x85,0xD4,0x85,0x1C,0x50,0xE0,0xAE,0x51,0x8A,0xBA,0x8D, +0x3E,0x76,0xE2,0xB9,0xCA,0x27,0xF2,0x5F,0x9F,0xEF,0x6E,0x59,0x0D,0x06,0xD8,0x2B, +0x17,0xA4,0xD2,0x7C,0x6B,0xBB,0x5F,0x14,0x1A,0x48,0x8F,0x1A,0x4C,0xE7,0xB3,0x47, +0x1C,0x8E,0x4C,0x45,0x2B,0x20,0xEE,0x48,0xDF,0xE7,0xDD,0x09,0x8E,0x18,0xA8,0xDA, +0x40,0x8D,0x92,0x26,0x11,0x53,0x61,0x73,0x5D,0xEB,0xBD,0xE7,0xC4,0x4D,0x29,0x37, +0x61,0xEB,0xAC,0x39,0x2D,0x67,0x2E,0x16,0xD6,0xF5,0x00,0x83,0x85,0xA1,0xCC,0x7F, +0x76,0xC4,0x7D,0xE4,0xB7,0x4B,0x66,0xEF,0x03,0x45,0x60,0x69,0xB6,0x0C,0x52,0x96, +0x92,0x84,0x5E,0xA6,0xA3,0xB5,0xA4,0x3E,0x2B,0xD9,0xCC,0xD8,0x1B,0x47,0xAA,0xF2, +0x44,0xDA,0x4F,0xF9,0x03,0xE8,0xF0,0x14,0xCB,0x3F,0xF3,0x83,0xDE,0xD0,0xC1,0x54, +0xE3,0xB7,0xE8,0x0A,0x37,0x4D,0x8B,0x20,0x59,0x03,0x30,0x19,0xA1,0x2C,0xC8,0xBD, +0x11,0x1F,0xDF,0xAE,0xC9,0x4A,0xC5,0xF3,0x27,0x66,0x66,0x86,0xAC,0x68,0x91,0xFF, +0xD9,0xE6,0x53,0x1C,0x0F,0x8B,0x5C,0x69,0x65,0x0A,0x26,0xC8,0x1E,0x34,0xC3,0x5D, +0x51,0x7B,0xD7,0xA9,0x9C,0x06,0xA1,0x36,0xDD,0xD5,0x89,0x94,0xBC,0xD9,0xE4,0x2D, +0x0C,0x5E,0x09,0x6C,0x08,0x97,0x7C,0xA3,0x3D,0x7C,0x93,0xFF,0x3F,0xA1,0x14,0xA7, +0xCF,0xB5,0x5D,0xEB,0xDB,0xDB,0x1C,0xC4,0x76,0xDF,0x88,0xB9,0xBD,0x45,0x05,0x95, +0x1B,0xAE,0xFC,0x46,0x6A,0x4C,0xAF,0x48,0xE3,0xCE,0xAE,0x0F,0xD2,0x7E,0xEB,0xE6, +0x6C,0x9C,0x4F,0x81,0x6A,0x7A,0x64,0xAC,0xBB,0x3E,0xD5,0xE7,0xCB,0x76,0x2E,0xC5, +0xA7,0x48,0xC1,0x5C,0x90,0x0F,0xCB,0xC8,0x3F,0xFA,0xE6,0x32,0xE1,0x8D,0x1B,0x6F, +0xA4,0xE6,0x8E,0xD8,0xF9,0x29,0x48,0x8A,0xCE,0x73,0xFE,0x2C, +}; + + +/* subject:/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA 2 */ +/* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Universal CA 2 */ + + +const unsigned char GeoTrust_Universal_CA_2_certificate[1392]={ +0x30,0x82,0x05,0x6C,0x30,0x82,0x03,0x54,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x47,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16, +0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73, +0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13, +0x17,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x55,0x6E,0x69,0x76,0x65,0x72, +0x73,0x61,0x6C,0x20,0x43,0x41,0x20,0x32,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x33, +0x30,0x34,0x30,0x35,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x30,0x33,0x30, +0x34,0x30,0x35,0x30,0x30,0x30,0x30,0x5A,0x30,0x47,0x31,0x0B,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A, +0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31, +0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x47,0x65,0x6F,0x54,0x72,0x75, +0x73,0x74,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x20, +0x32,0x30,0x82,0x02,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02, +0x01,0x00,0xB3,0x54,0x52,0xC1,0xC9,0x3E,0xF2,0xD9,0xDC,0xB1,0x53,0x1A,0x59,0x29, +0xE7,0xB1,0xC3,0x45,0x28,0xE5,0xD7,0xD1,0xED,0xC5,0xC5,0x4B,0xA1,0xAA,0x74,0x7B, +0x57,0xAF,0x4A,0x26,0xFC,0xD8,0xF5,0x5E,0xA7,0x6E,0x19,0xDB,0x74,0x0C,0x4F,0x35, +0x5B,0x32,0x0B,0x01,0xE3,0xDB,0xEB,0x7A,0x77,0x35,0xEA,0xAA,0x5A,0xE0,0xD6,0xE8, +0xA1,0x57,0x94,0xF0,0x90,0xA3,0x74,0x56,0x94,0x44,0x30,0x03,0x1E,0x5C,0x4E,0x2B, +0x85,0x26,0x74,0x82,0x7A,0x0C,0x76,0xA0,0x6F,0x4D,0xCE,0x41,0x2D,0xA0,0x15,0x06, +0x14,0x5F,0xB7,0x42,0xCD,0x7B,0x8F,0x58,0x61,0x34,0xDC,0x2A,0x08,0xF9,0x2E,0xC3, +0x01,0xA6,0x22,0x44,0x1C,0x4C,0x07,0x82,0xE6,0x5B,0xCE,0xD0,0x4A,0x7C,0x04,0xD3, +0x19,0x73,0x27,0xF0,0xAA,0x98,0x7F,0x2E,0xAF,0x4E,0xEB,0x87,0x1E,0x24,0x77,0x6A, +0x5D,0xB6,0xE8,0x5B,0x45,0xBA,0xDC,0xC3,0xA1,0x05,0x6F,0x56,0x8E,0x8F,0x10,0x26, +0xA5,0x49,0xC3,0x2E,0xD7,0x41,0x87,0x22,0xE0,0x4F,0x86,0xCA,0x60,0xB5,0xEA,0xA1, +0x63,0xC0,0x01,0x97,0x10,0x79,0xBD,0x00,0x3C,0x12,0x6D,0x2B,0x15,0xB1,0xAC,0x4B, +0xB1,0xEE,0x18,0xB9,0x4E,0x96,0xDC,0xDC,0x76,0xFF,0x3B,0xBE,0xCF,0x5F,0x03,0xC0, +0xFC,0x3B,0xE8,0xBE,0x46,0x1B,0xFF,0xDA,0x40,0xC2,0x52,0xF7,0xFE,0xE3,0x3A,0xF7, +0x6A,0x77,0x35,0xD0,0xDA,0x8D,0xEB,0x5E,0x18,0x6A,0x31,0xC7,0x1E,0xBA,0x3C,0x1B, +0x28,0xD6,0x6B,0x54,0xC6,0xAA,0x5B,0xD7,0xA2,0x2C,0x1B,0x19,0xCC,0xA2,0x02,0xF6, +0x9B,0x59,0xBD,0x37,0x6B,0x86,0xB5,0x6D,0x82,0xBA,0xD8,0xEA,0xC9,0x56,0xBC,0xA9, +0x36,0x58,0xFD,0x3E,0x19,0xF3,0xED,0x0C,0x26,0xA9,0x93,0x38,0xF8,0x4F,0xC1,0x5D, +0x22,0x06,0xD0,0x97,0xEA,0xE1,0xAD,0xC6,0x55,0xE0,0x81,0x2B,0x28,0x83,0x3A,0xFA, +0xF4,0x7B,0x21,0x51,0x00,0xBE,0x52,0x38,0xCE,0xCD,0x66,0x79,0xA8,0xF4,0x81,0x56, +0xE2,0xD0,0x83,0x09,0x47,0x51,0x5B,0x50,0x6A,0xCF,0xDB,0x48,0x1A,0x5D,0x3E,0xF7, +0xCB,0xF6,0x65,0xF7,0x6C,0xF1,0x95,0xF8,0x02,0x3B,0x32,0x56,0x82,0x39,0x7A,0x5B, +0xBD,0x2F,0x89,0x1B,0xBF,0xA1,0xB4,0xE8,0xFF,0x7F,0x8D,0x8C,0xDF,0x03,0xF1,0x60, +0x4E,0x58,0x11,0x4C,0xEB,0xA3,0x3F,0x10,0x2B,0x83,0x9A,0x01,0x73,0xD9,0x94,0x6D, +0x84,0x00,0x27,0x66,0xAC,0xF0,0x70,0x40,0x09,0x42,0x92,0xAD,0x4F,0x93,0x0D,0x61, +0x09,0x51,0x24,0xD8,0x92,0xD5,0x0B,0x94,0x61,0xB2,0x87,0xB2,0xED,0xFF,0x9A,0x35, +0xFF,0x85,0x54,0xCA,0xED,0x44,0x43,0xAC,0x1B,0x3C,0x16,0x6B,0x48,0x4A,0x0A,0x1C, +0x40,0x88,0x1F,0x92,0xC2,0x0B,0x00,0x05,0xFF,0xF2,0xC8,0x02,0x4A,0xA4,0xAA,0xA9, +0xCC,0x99,0x96,0x9C,0x2F,0x58,0xE0,0x7D,0xE1,0xBE,0xBB,0x07,0xDC,0x5F,0x04,0x72, +0x5C,0x31,0x34,0xC3,0xEC,0x5F,0x2D,0xE0,0x3D,0x64,0x90,0x22,0xE6,0xD1,0xEC,0xB8, +0x2E,0xDD,0x59,0xAE,0xD9,0xA1,0x37,0xBF,0x54,0x35,0xDC,0x73,0x32,0x4F,0x8C,0x04, +0x1E,0x33,0xB2,0xC9,0x46,0xF1,0xD8,0x5C,0xC8,0x55,0x50,0xC9,0x68,0xBD,0xA8,0xBA, +0x36,0x09,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x76,0xF3,0x55,0xE1,0xFA,0xA4,0x36,0xFB,0xF0, +0x9F,0x5C,0x62,0x71,0xED,0x3C,0xF4,0x47,0x38,0x10,0x2B,0x30,0x1F,0x06,0x03,0x55, +0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x76,0xF3,0x55,0xE1,0xFA,0xA4,0x36,0xFB, +0xF0,0x9F,0x5C,0x62,0x71,0xED,0x3C,0xF4,0x47,0x38,0x10,0x2B,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x02,0x01,0x00, +0x66,0xC1,0xC6,0x23,0xF3,0xD9,0xE0,0x2E,0x6E,0x5F,0xE8,0xCF,0xAE,0xB0,0xB0,0x25, +0x4D,0x2B,0xF8,0x3B,0x58,0x9B,0x40,0x24,0x37,0x5A,0xCB,0xAB,0x16,0x49,0xFF,0xB3, +0x75,0x79,0x33,0xA1,0x2F,0x6D,0x70,0x17,0x34,0x91,0xFE,0x67,0x7E,0x8F,0xEC,0x9B, +0xE5,0x5E,0x82,0xA9,0x55,0x1F,0x2F,0xDC,0xD4,0x51,0x07,0x12,0xFE,0xAC,0x16,0x3E, +0x2C,0x35,0xC6,0x63,0xFC,0xDC,0x10,0xEB,0x0D,0xA3,0xAA,0xD0,0x7C,0xCC,0xD1,0xD0, +0x2F,0x51,0x2E,0xC4,0x14,0x5A,0xDE,0xE8,0x19,0xE1,0x3E,0xC6,0xCC,0xA4,0x29,0xE7, +0x2E,0x84,0xAA,0x06,0x30,0x78,0x76,0x54,0x73,0x28,0x98,0x59,0x38,0xE0,0x00,0x0D, +0x62,0xD3,0x42,0x7D,0x21,0x9F,0xAE,0x3D,0x3A,0x8C,0xD5,0xFA,0x77,0x0D,0x18,0x2B, +0x16,0x0E,0x5F,0x36,0xE1,0xFC,0x2A,0xB5,0x30,0x24,0xCF,0xE0,0x63,0x0C,0x7B,0x58, +0x1A,0xFE,0x99,0xBA,0x42,0x12,0xB1,0x91,0xF4,0x7C,0x68,0xE2,0xC8,0xE8,0xAF,0x2C, +0xEA,0xC9,0x7E,0xAE,0xBB,0x2A,0x3D,0x0D,0x15,0xDC,0x34,0x95,0xB6,0x18,0x74,0xA8, +0x6A,0x0F,0xC7,0xB4,0xF4,0x13,0xC4,0xE4,0x5B,0xED,0x0A,0xD2,0xA4,0x97,0x4C,0x2A, +0xED,0x2F,0x6C,0x12,0x89,0x3D,0xF1,0x27,0x70,0xAA,0x6A,0x03,0x52,0x21,0x9F,0x40, +0xA8,0x67,0x50,0xF2,0xF3,0x5A,0x1F,0xDF,0xDF,0x23,0xF6,0xDC,0x78,0x4E,0xE6,0x98, +0x4F,0x55,0x3A,0x53,0xE3,0xEF,0xF2,0xF4,0x9F,0xC7,0x7C,0xD8,0x58,0xAF,0x29,0x22, +0x97,0xB8,0xE0,0xBD,0x91,0x2E,0xB0,0x76,0xEC,0x57,0x11,0xCF,0xEF,0x29,0x44,0xF3, +0xE9,0x85,0x7A,0x60,0x63,0xE4,0x5D,0x33,0x89,0x17,0xD9,0x31,0xAA,0xDA,0xD6,0xF3, +0x18,0x35,0x72,0xCF,0x87,0x2B,0x2F,0x63,0x23,0x84,0x5D,0x84,0x8C,0x3F,0x57,0xA0, +0x88,0xFC,0x99,0x91,0x28,0x26,0x69,0x99,0xD4,0x8F,0x97,0x44,0xBE,0x8E,0xD5,0x48, +0xB1,0xA4,0x28,0x29,0xF1,0x15,0xB4,0xE1,0xE5,0x9E,0xDD,0xF8,0x8F,0xA6,0x6F,0x26, +0xD7,0x09,0x3C,0x3A,0x1C,0x11,0x0E,0xA6,0x6C,0x37,0xF7,0xAD,0x44,0x87,0x2C,0x28, +0xC7,0xD8,0x74,0x82,0xB3,0xD0,0x6F,0x4A,0x57,0xBB,0x35,0x29,0x27,0xA0,0x8B,0xE8, +0x21,0xA7,0x87,0x64,0x36,0x5D,0xCC,0xD8,0x16,0xAC,0xC7,0xB2,0x27,0x40,0x92,0x55, +0x38,0x28,0x8D,0x51,0x6E,0xDD,0x14,0x67,0x53,0x6C,0x71,0x5C,0x26,0x84,0x4D,0x75, +0x5A,0xB6,0x7E,0x60,0x56,0xA9,0x4D,0xAD,0xFB,0x9B,0x1E,0x97,0xF3,0x0D,0xD9,0xD2, +0x97,0x54,0x77,0xDA,0x3D,0x12,0xB7,0xE0,0x1E,0xEF,0x08,0x06,0xAC,0xF9,0x85,0x87, +0xE9,0xA2,0xDC,0xAF,0x7E,0x18,0x12,0x83,0xFD,0x56,0x17,0x41,0x2E,0xD5,0x29,0x82, +0x7D,0x99,0xF4,0x31,0xF6,0x71,0xA9,0xCF,0x2C,0x01,0x27,0xA5,0x05,0xB9,0xAA,0xB2, +0x48,0x4E,0x2A,0xEF,0x9F,0x93,0x52,0x51,0x95,0x3C,0x52,0x73,0x8E,0x56,0x4C,0x17, +0x40,0xC0,0x09,0x28,0xE4,0x8B,0x6A,0x48,0x53,0xDB,0xEC,0xCD,0x55,0x55,0xF1,0xC6, +0xF8,0xE9,0xA2,0x2C,0x4C,0xA6,0xD1,0x26,0x5F,0x7E,0xAF,0x5A,0x4C,0xDA,0x1F,0xA6, +0xF2,0x1C,0x2C,0x7E,0xAE,0x02,0x16,0xD2,0x56,0xD0,0x2F,0x57,0x53,0x47,0xE8,0x92, +}; + + +/* subject:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */ +/* issuer :/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */ + + +const unsigned char GlobalSign_Root_CA_certificate[889]={ +0x30,0x82,0x03,0x75,0x30,0x82,0x02,0x5D,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, +0x00,0x00,0x00,0x00,0x01,0x15,0x4B,0x5A,0xC3,0x94,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x57,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x42,0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, +0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76, +0x2D,0x73,0x61,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F, +0x6F,0x74,0x20,0x43,0x41,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12, +0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20, +0x43,0x41,0x30,0x1E,0x17,0x0D,0x39,0x38,0x30,0x39,0x30,0x31,0x31,0x32,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x32,0x38,0x30,0x31,0x32,0x38,0x31,0x32,0x30,0x30,0x30, +0x30,0x5A,0x30,0x57,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x42, +0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62, +0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76,0x2D,0x73,0x61,0x31,0x10,0x30,0x0E, +0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x1B, +0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53, +0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, +0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xDA,0x0E,0xE6,0x99, +0x8D,0xCE,0xA3,0xE3,0x4F,0x8A,0x7E,0xFB,0xF1,0x8B,0x83,0x25,0x6B,0xEA,0x48,0x1F, +0xF1,0x2A,0xB0,0xB9,0x95,0x11,0x04,0xBD,0xF0,0x63,0xD1,0xE2,0x67,0x66,0xCF,0x1C, +0xDD,0xCF,0x1B,0x48,0x2B,0xEE,0x8D,0x89,0x8E,0x9A,0xAF,0x29,0x80,0x65,0xAB,0xE9, +0xC7,0x2D,0x12,0xCB,0xAB,0x1C,0x4C,0x70,0x07,0xA1,0x3D,0x0A,0x30,0xCD,0x15,0x8D, +0x4F,0xF8,0xDD,0xD4,0x8C,0x50,0x15,0x1C,0xEF,0x50,0xEE,0xC4,0x2E,0xF7,0xFC,0xE9, +0x52,0xF2,0x91,0x7D,0xE0,0x6D,0xD5,0x35,0x30,0x8E,0x5E,0x43,0x73,0xF2,0x41,0xE9, +0xD5,0x6A,0xE3,0xB2,0x89,0x3A,0x56,0x39,0x38,0x6F,0x06,0x3C,0x88,0x69,0x5B,0x2A, +0x4D,0xC5,0xA7,0x54,0xB8,0x6C,0x89,0xCC,0x9B,0xF9,0x3C,0xCA,0xE5,0xFD,0x89,0xF5, +0x12,0x3C,0x92,0x78,0x96,0xD6,0xDC,0x74,0x6E,0x93,0x44,0x61,0xD1,0x8D,0xC7,0x46, +0xB2,0x75,0x0E,0x86,0xE8,0x19,0x8A,0xD5,0x6D,0x6C,0xD5,0x78,0x16,0x95,0xA2,0xE9, +0xC8,0x0A,0x38,0xEB,0xF2,0x24,0x13,0x4F,0x73,0x54,0x93,0x13,0x85,0x3A,0x1B,0xBC, +0x1E,0x34,0xB5,0x8B,0x05,0x8C,0xB9,0x77,0x8B,0xB1,0xDB,0x1F,0x20,0x91,0xAB,0x09, +0x53,0x6E,0x90,0xCE,0x7B,0x37,0x74,0xB9,0x70,0x47,0x91,0x22,0x51,0x63,0x16,0x79, +0xAE,0xB1,0xAE,0x41,0x26,0x08,0xC8,0x19,0x2B,0xD1,0x46,0xAA,0x48,0xD6,0x64,0x2A, +0xD7,0x83,0x34,0xFF,0x2C,0x2A,0xC1,0x6C,0x19,0x43,0x4A,0x07,0x85,0xE7,0xD3,0x7C, +0xF6,0x21,0x68,0xEF,0xEA,0xF2,0x52,0x9F,0x7F,0x93,0x90,0xCF,0x02,0x03,0x01,0x00, +0x01,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04, +0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x60,0x7B,0x66,0x1A,0x45,0x0D,0x97,0xCA,0x89,0x50,0x2F,0x7D,0x04,0xCD,0x34, +0xA8,0xFF,0xFC,0xFD,0x4B,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xD6,0x73,0xE7,0x7C,0x4F,0x76,0xD0, +0x8D,0xBF,0xEC,0xBA,0xA2,0xBE,0x34,0xC5,0x28,0x32,0xB5,0x7C,0xFC,0x6C,0x9C,0x2C, +0x2B,0xBD,0x09,0x9E,0x53,0xBF,0x6B,0x5E,0xAA,0x11,0x48,0xB6,0xE5,0x08,0xA3,0xB3, +0xCA,0x3D,0x61,0x4D,0xD3,0x46,0x09,0xB3,0x3E,0xC3,0xA0,0xE3,0x63,0x55,0x1B,0xF2, +0xBA,0xEF,0xAD,0x39,0xE1,0x43,0xB9,0x38,0xA3,0xE6,0x2F,0x8A,0x26,0x3B,0xEF,0xA0, +0x50,0x56,0xF9,0xC6,0x0A,0xFD,0x38,0xCD,0xC4,0x0B,0x70,0x51,0x94,0x97,0x98,0x04, +0xDF,0xC3,0x5F,0x94,0xD5,0x15,0xC9,0x14,0x41,0x9C,0xC4,0x5D,0x75,0x64,0x15,0x0D, +0xFF,0x55,0x30,0xEC,0x86,0x8F,0xFF,0x0D,0xEF,0x2C,0xB9,0x63,0x46,0xF6,0xAA,0xFC, +0xDF,0xBC,0x69,0xFD,0x2E,0x12,0x48,0x64,0x9A,0xE0,0x95,0xF0,0xA6,0xEF,0x29,0x8F, +0x01,0xB1,0x15,0xB5,0x0C,0x1D,0xA5,0xFE,0x69,0x2C,0x69,0x24,0x78,0x1E,0xB3,0xA7, +0x1C,0x71,0x62,0xEE,0xCA,0xC8,0x97,0xAC,0x17,0x5D,0x8A,0xC2,0xF8,0x47,0x86,0x6E, +0x2A,0xC4,0x56,0x31,0x95,0xD0,0x67,0x89,0x85,0x2B,0xF9,0x6C,0xA6,0x5D,0x46,0x9D, +0x0C,0xAA,0x82,0xE4,0x99,0x51,0xDD,0x70,0xB7,0xDB,0x56,0x3D,0x61,0xE4,0x6A,0xE1, +0x5C,0xD6,0xF6,0xFE,0x3D,0xDE,0x41,0xCC,0x07,0xAE,0x63,0x52,0xBF,0x53,0x53,0xF4, +0x2B,0xE9,0xC7,0xFD,0xB6,0xF7,0x82,0x5F,0x85,0xD2,0x41,0x18,0xDB,0x81,0xB3,0x04, +0x1C,0xC5,0x1F,0xA4,0x80,0x6F,0x15,0x20,0xC9,0xDE,0x0C,0x88,0x0A,0x1D,0xD6,0x66, +0x55,0xE2,0xFC,0x48,0xC9,0x29,0x26,0x69,0xE0, +}; + + +/* subject:/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign */ +/* issuer :/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign */ + + +const unsigned char GlobalSign_Root_CA___R2_certificate[958]={ +0x30,0x82,0x03,0xBA,0x30,0x82,0x02,0xA2,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, +0x00,0x00,0x00,0x00,0x01,0x0F,0x86,0x26,0xE6,0x0D,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x4C,0x31,0x20,0x30,0x1E,0x06, +0x03,0x55,0x04,0x0B,0x13,0x17,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E, +0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x52,0x32,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69, +0x67,0x6E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F, +0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x32,0x31, +0x35,0x30,0x38,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x31,0x31,0x32,0x31,0x35, +0x30,0x38,0x30,0x30,0x30,0x30,0x5A,0x30,0x4C,0x31,0x20,0x30,0x1E,0x06,0x03,0x55, +0x04,0x0B,0x13,0x17,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x52, +0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x52,0x32,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61, +0x6C,0x53,0x69,0x67,0x6E,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01, +0x0A,0x02,0x82,0x01,0x01,0x00,0xA6,0xCF,0x24,0x0E,0xBE,0x2E,0x6F,0x28,0x99,0x45, +0x42,0xC4,0xAB,0x3E,0x21,0x54,0x9B,0x0B,0xD3,0x7F,0x84,0x70,0xFA,0x12,0xB3,0xCB, +0xBF,0x87,0x5F,0xC6,0x7F,0x86,0xD3,0xB2,0x30,0x5C,0xD6,0xFD,0xAD,0xF1,0x7B,0xDC, +0xE5,0xF8,0x60,0x96,0x09,0x92,0x10,0xF5,0xD0,0x53,0xDE,0xFB,0x7B,0x7E,0x73,0x88, +0xAC,0x52,0x88,0x7B,0x4A,0xA6,0xCA,0x49,0xA6,0x5E,0xA8,0xA7,0x8C,0x5A,0x11,0xBC, +0x7A,0x82,0xEB,0xBE,0x8C,0xE9,0xB3,0xAC,0x96,0x25,0x07,0x97,0x4A,0x99,0x2A,0x07, +0x2F,0xB4,0x1E,0x77,0xBF,0x8A,0x0F,0xB5,0x02,0x7C,0x1B,0x96,0xB8,0xC5,0xB9,0x3A, +0x2C,0xBC,0xD6,0x12,0xB9,0xEB,0x59,0x7D,0xE2,0xD0,0x06,0x86,0x5F,0x5E,0x49,0x6A, +0xB5,0x39,0x5E,0x88,0x34,0xEC,0xBC,0x78,0x0C,0x08,0x98,0x84,0x6C,0xA8,0xCD,0x4B, +0xB4,0xA0,0x7D,0x0C,0x79,0x4D,0xF0,0xB8,0x2D,0xCB,0x21,0xCA,0xD5,0x6C,0x5B,0x7D, +0xE1,0xA0,0x29,0x84,0xA1,0xF9,0xD3,0x94,0x49,0xCB,0x24,0x62,0x91,0x20,0xBC,0xDD, +0x0B,0xD5,0xD9,0xCC,0xF9,0xEA,0x27,0x0A,0x2B,0x73,0x91,0xC6,0x9D,0x1B,0xAC,0xC8, +0xCB,0xE8,0xE0,0xA0,0xF4,0x2F,0x90,0x8B,0x4D,0xFB,0xB0,0x36,0x1B,0xF6,0x19,0x7A, +0x85,0xE0,0x6D,0xF2,0x61,0x13,0x88,0x5C,0x9F,0xE0,0x93,0x0A,0x51,0x97,0x8A,0x5A, +0xCE,0xAF,0xAB,0xD5,0xF7,0xAA,0x09,0xAA,0x60,0xBD,0xDC,0xD9,0x5F,0xDF,0x72,0xA9, +0x60,0x13,0x5E,0x00,0x01,0xC9,0x4A,0xFA,0x3F,0xA4,0xEA,0x07,0x03,0x21,0x02,0x8E, +0x82,0xCA,0x03,0xC2,0x9B,0x8F,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x9C,0x30,0x81, +0x99,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, +0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01, +0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9B,0xE2,0x07, +0x57,0x67,0x1C,0x1E,0xC0,0x6A,0x06,0xDE,0x59,0xB4,0x9A,0x2D,0xDF,0xDC,0x19,0x86, +0x2E,0x30,0x36,0x06,0x03,0x55,0x1D,0x1F,0x04,0x2F,0x30,0x2D,0x30,0x2B,0xA0,0x29, +0xA0,0x27,0x86,0x25,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x67, +0x6C,0x6F,0x62,0x61,0x6C,0x73,0x69,0x67,0x6E,0x2E,0x6E,0x65,0x74,0x2F,0x72,0x6F, +0x6F,0x74,0x2D,0x72,0x32,0x2E,0x63,0x72,0x6C,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23, +0x04,0x18,0x30,0x16,0x80,0x14,0x9B,0xE2,0x07,0x57,0x67,0x1C,0x1E,0xC0,0x6A,0x06, +0xDE,0x59,0xB4,0x9A,0x2D,0xDF,0xDC,0x19,0x86,0x2E,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x99,0x81, +0x53,0x87,0x1C,0x68,0x97,0x86,0x91,0xEC,0xE0,0x4A,0xB8,0x44,0x0B,0xAB,0x81,0xAC, +0x27,0x4F,0xD6,0xC1,0xB8,0x1C,0x43,0x78,0xB3,0x0C,0x9A,0xFC,0xEA,0x2C,0x3C,0x6E, +0x61,0x1B,0x4D,0x4B,0x29,0xF5,0x9F,0x05,0x1D,0x26,0xC1,0xB8,0xE9,0x83,0x00,0x62, +0x45,0xB6,0xA9,0x08,0x93,0xB9,0xA9,0x33,0x4B,0x18,0x9A,0xC2,0xF8,0x87,0x88,0x4E, +0xDB,0xDD,0x71,0x34,0x1A,0xC1,0x54,0xDA,0x46,0x3F,0xE0,0xD3,0x2A,0xAB,0x6D,0x54, +0x22,0xF5,0x3A,0x62,0xCD,0x20,0x6F,0xBA,0x29,0x89,0xD7,0xDD,0x91,0xEE,0xD3,0x5C, +0xA2,0x3E,0xA1,0x5B,0x41,0xF5,0xDF,0xE5,0x64,0x43,0x2D,0xE9,0xD5,0x39,0xAB,0xD2, +0xA2,0xDF,0xB7,0x8B,0xD0,0xC0,0x80,0x19,0x1C,0x45,0xC0,0x2D,0x8C,0xE8,0xF8,0x2D, +0xA4,0x74,0x56,0x49,0xC5,0x05,0xB5,0x4F,0x15,0xDE,0x6E,0x44,0x78,0x39,0x87,0xA8, +0x7E,0xBB,0xF3,0x79,0x18,0x91,0xBB,0xF4,0x6F,0x9D,0xC1,0xF0,0x8C,0x35,0x8C,0x5D, +0x01,0xFB,0xC3,0x6D,0xB9,0xEF,0x44,0x6D,0x79,0x46,0x31,0x7E,0x0A,0xFE,0xA9,0x82, +0xC1,0xFF,0xEF,0xAB,0x6E,0x20,0xC4,0x50,0xC9,0x5F,0x9D,0x4D,0x9B,0x17,0x8C,0x0C, +0xE5,0x01,0xC9,0xA0,0x41,0x6A,0x73,0x53,0xFA,0xA5,0x50,0xB4,0x6E,0x25,0x0F,0xFB, +0x4C,0x18,0xF4,0xFD,0x52,0xD9,0x8E,0x69,0xB1,0xE8,0x11,0x0F,0xDE,0x88,0xD8,0xFB, +0x1D,0x49,0xF7,0xAA,0xDE,0x95,0xCF,0x20,0x78,0xC2,0x60,0x12,0xDB,0x25,0x40,0x8C, +0x6A,0xFC,0x7E,0x42,0x38,0x40,0x64,0x12,0xF7,0x9E,0x81,0xE1,0x93,0x2E, +}; + + +/* subject:/OU=GlobalSign Root CA - R3/O=GlobalSign/CN=GlobalSign */ +/* issuer :/OU=GlobalSign Root CA - R3/O=GlobalSign/CN=GlobalSign */ + + +const unsigned char GlobalSign_Root_CA___R3_certificate[867]={ +0x30,0x82,0x03,0x5F,0x30,0x82,0x02,0x47,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, +0x00,0x00,0x00,0x00,0x01,0x21,0x58,0x53,0x08,0xA2,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x4C,0x31,0x20,0x30,0x1E,0x06, +0x03,0x55,0x04,0x0B,0x13,0x17,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E, +0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x52,0x33,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69, +0x67,0x6E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F, +0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x33,0x31, +0x38,0x31,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x30,0x33,0x31,0x38, +0x31,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x4C,0x31,0x20,0x30,0x1E,0x06,0x03,0x55, +0x04,0x0B,0x13,0x17,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x52, +0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x52,0x33,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0A,0x47,0x6C,0x6F,0x62,0x61, +0x6C,0x53,0x69,0x67,0x6E,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01, +0x0A,0x02,0x82,0x01,0x01,0x00,0xCC,0x25,0x76,0x90,0x79,0x06,0x78,0x22,0x16,0xF5, +0xC0,0x83,0xB6,0x84,0xCA,0x28,0x9E,0xFD,0x05,0x76,0x11,0xC5,0xAD,0x88,0x72,0xFC, +0x46,0x02,0x43,0xC7,0xB2,0x8A,0x9D,0x04,0x5F,0x24,0xCB,0x2E,0x4B,0xE1,0x60,0x82, +0x46,0xE1,0x52,0xAB,0x0C,0x81,0x47,0x70,0x6C,0xDD,0x64,0xD1,0xEB,0xF5,0x2C,0xA3, +0x0F,0x82,0x3D,0x0C,0x2B,0xAE,0x97,0xD7,0xB6,0x14,0x86,0x10,0x79,0xBB,0x3B,0x13, +0x80,0x77,0x8C,0x08,0xE1,0x49,0xD2,0x6A,0x62,0x2F,0x1F,0x5E,0xFA,0x96,0x68,0xDF, +0x89,0x27,0x95,0x38,0x9F,0x06,0xD7,0x3E,0xC9,0xCB,0x26,0x59,0x0D,0x73,0xDE,0xB0, +0xC8,0xE9,0x26,0x0E,0x83,0x15,0xC6,0xEF,0x5B,0x8B,0xD2,0x04,0x60,0xCA,0x49,0xA6, +0x28,0xF6,0x69,0x3B,0xF6,0xCB,0xC8,0x28,0x91,0xE5,0x9D,0x8A,0x61,0x57,0x37,0xAC, +0x74,0x14,0xDC,0x74,0xE0,0x3A,0xEE,0x72,0x2F,0x2E,0x9C,0xFB,0xD0,0xBB,0xBF,0xF5, +0x3D,0x00,0xE1,0x06,0x33,0xE8,0x82,0x2B,0xAE,0x53,0xA6,0x3A,0x16,0x73,0x8C,0xDD, +0x41,0x0E,0x20,0x3A,0xC0,0xB4,0xA7,0xA1,0xE9,0xB2,0x4F,0x90,0x2E,0x32,0x60,0xE9, +0x57,0xCB,0xB9,0x04,0x92,0x68,0x68,0xE5,0x38,0x26,0x60,0x75,0xB2,0x9F,0x77,0xFF, +0x91,0x14,0xEF,0xAE,0x20,0x49,0xFC,0xAD,0x40,0x15,0x48,0xD1,0x02,0x31,0x61,0x19, +0x5E,0xB8,0x97,0xEF,0xAD,0x77,0xB7,0x64,0x9A,0x7A,0xBF,0x5F,0xC1,0x13,0xEF,0x9B, +0x62,0xFB,0x0D,0x6C,0xE0,0x54,0x69,0x16,0xA9,0x03,0xDA,0x6E,0xE9,0x83,0x93,0x71, +0x76,0xC6,0x69,0x85,0x82,0x17,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30, +0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30, +0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, +0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x8F,0xF0,0x4B,0x7F,0xA8, +0x2E,0x45,0x24,0xAE,0x4D,0x50,0xFA,0x63,0x9A,0x8B,0xDE,0xE2,0xDD,0x1B,0xBC,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0x4B,0x40,0xDB,0xC0,0x50,0xAA,0xFE,0xC8,0x0C,0xEF,0xF7,0x96,0x54, +0x45,0x49,0xBB,0x96,0x00,0x09,0x41,0xAC,0xB3,0x13,0x86,0x86,0x28,0x07,0x33,0xCA, +0x6B,0xE6,0x74,0xB9,0xBA,0x00,0x2D,0xAE,0xA4,0x0A,0xD3,0xF5,0xF1,0xF1,0x0F,0x8A, +0xBF,0x73,0x67,0x4A,0x83,0xC7,0x44,0x7B,0x78,0xE0,0xAF,0x6E,0x6C,0x6F,0x03,0x29, +0x8E,0x33,0x39,0x45,0xC3,0x8E,0xE4,0xB9,0x57,0x6C,0xAA,0xFC,0x12,0x96,0xEC,0x53, +0xC6,0x2D,0xE4,0x24,0x6C,0xB9,0x94,0x63,0xFB,0xDC,0x53,0x68,0x67,0x56,0x3E,0x83, +0xB8,0xCF,0x35,0x21,0xC3,0xC9,0x68,0xFE,0xCE,0xDA,0xC2,0x53,0xAA,0xCC,0x90,0x8A, +0xE9,0xF0,0x5D,0x46,0x8C,0x95,0xDD,0x7A,0x58,0x28,0x1A,0x2F,0x1D,0xDE,0xCD,0x00, +0x37,0x41,0x8F,0xED,0x44,0x6D,0xD7,0x53,0x28,0x97,0x7E,0xF3,0x67,0x04,0x1E,0x15, +0xD7,0x8A,0x96,0xB4,0xD3,0xDE,0x4C,0x27,0xA4,0x4C,0x1B,0x73,0x73,0x76,0xF4,0x17, +0x99,0xC2,0x1F,0x7A,0x0E,0xE3,0x2D,0x08,0xAD,0x0A,0x1C,0x2C,0xFF,0x3C,0xAB,0x55, +0x0E,0x0F,0x91,0x7E,0x36,0xEB,0xC3,0x57,0x49,0xBE,0xE1,0x2E,0x2D,0x7C,0x60,0x8B, +0xC3,0x41,0x51,0x13,0x23,0x9D,0xCE,0xF7,0x32,0x6B,0x94,0x01,0xA8,0x99,0xE7,0x2C, +0x33,0x1F,0x3A,0x3B,0x25,0xD2,0x86,0x40,0xCE,0x3B,0x2C,0x86,0x78,0xC9,0x61,0x2F, +0x14,0xBA,0xEE,0xDB,0x55,0x6F,0xDF,0x84,0xEE,0x05,0x09,0x4D,0xBD,0x28,0xD8,0x72, +0xCE,0xD3,0x62,0x50,0x65,0x1E,0xEB,0x92,0x97,0x83,0x31,0xD9,0xB3,0xB5,0xCA,0x47, +0x58,0x3F,0x5F, +}; + + +/* subject:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority */ +/* issuer :/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority */ + + +const unsigned char Go_Daddy_Class_2_CA_certificate[1028]={ +0x30,0x82,0x04,0x00,0x30,0x82,0x02,0xE8,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x21, +0x30,0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x54,0x68,0x65,0x20,0x47,0x6F,0x20, +0x44,0x61,0x64,0x64,0x79,0x20,0x47,0x72,0x6F,0x75,0x70,0x2C,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x0B,0x13,0x28,0x47,0x6F,0x20,0x44, +0x61,0x64,0x64,0x79,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F, +0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30,0x36,0x32,0x39,0x31,0x37, +0x30,0x36,0x32,0x30,0x5A,0x17,0x0D,0x33,0x34,0x30,0x36,0x32,0x39,0x31,0x37,0x30, +0x36,0x32,0x30,0x5A,0x30,0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x54,0x68, +0x65,0x20,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x47,0x72,0x6F,0x75,0x70, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x0B,0x13, +0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x43,0x6C,0x61,0x73,0x73,0x20, +0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x20,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0D, +0x00,0x30,0x82,0x01,0x08,0x02,0x82,0x01,0x01,0x00,0xDE,0x9D,0xD7,0xEA,0x57,0x18, +0x49,0xA1,0x5B,0xEB,0xD7,0x5F,0x48,0x86,0xEA,0xBE,0xDD,0xFF,0xE4,0xEF,0x67,0x1C, +0xF4,0x65,0x68,0xB3,0x57,0x71,0xA0,0x5E,0x77,0xBB,0xED,0x9B,0x49,0xE9,0x70,0x80, +0x3D,0x56,0x18,0x63,0x08,0x6F,0xDA,0xF2,0xCC,0xD0,0x3F,0x7F,0x02,0x54,0x22,0x54, +0x10,0xD8,0xB2,0x81,0xD4,0xC0,0x75,0x3D,0x4B,0x7F,0xC7,0x77,0xC3,0x3E,0x78,0xAB, +0x1A,0x03,0xB5,0x20,0x6B,0x2F,0x6A,0x2B,0xB1,0xC5,0x88,0x7E,0xC4,0xBB,0x1E,0xB0, +0xC1,0xD8,0x45,0x27,0x6F,0xAA,0x37,0x58,0xF7,0x87,0x26,0xD7,0xD8,0x2D,0xF6,0xA9, +0x17,0xB7,0x1F,0x72,0x36,0x4E,0xA6,0x17,0x3F,0x65,0x98,0x92,0xDB,0x2A,0x6E,0x5D, +0xA2,0xFE,0x88,0xE0,0x0B,0xDE,0x7F,0xE5,0x8D,0x15,0xE1,0xEB,0xCB,0x3A,0xD5,0xE2, +0x12,0xA2,0x13,0x2D,0xD8,0x8E,0xAF,0x5F,0x12,0x3D,0xA0,0x08,0x05,0x08,0xB6,0x5C, +0xA5,0x65,0x38,0x04,0x45,0x99,0x1E,0xA3,0x60,0x60,0x74,0xC5,0x41,0xA5,0x72,0x62, +0x1B,0x62,0xC5,0x1F,0x6F,0x5F,0x1A,0x42,0xBE,0x02,0x51,0x65,0xA8,0xAE,0x23,0x18, +0x6A,0xFC,0x78,0x03,0xA9,0x4D,0x7F,0x80,0xC3,0xFA,0xAB,0x5A,0xFC,0xA1,0x40,0xA4, +0xCA,0x19,0x16,0xFE,0xB2,0xC8,0xEF,0x5E,0x73,0x0D,0xEE,0x77,0xBD,0x9A,0xF6,0x79, +0x98,0xBC,0xB1,0x07,0x67,0xA2,0x15,0x0D,0xDD,0xA0,0x58,0xC6,0x44,0x7B,0x0A,0x3E, +0x62,0x28,0x5F,0xBA,0x41,0x07,0x53,0x58,0xCF,0x11,0x7E,0x38,0x74,0xC5,0xF8,0xFF, +0xB5,0x69,0x90,0x8F,0x84,0x74,0xEA,0x97,0x1B,0xAF,0x02,0x01,0x03,0xA3,0x81,0xC0, +0x30,0x81,0xBD,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xD2,0xC4, +0xB0,0xD2,0x91,0xD4,0x4C,0x11,0x71,0xB3,0x61,0xCB,0x3D,0xA1,0xFE,0xDD,0xA8,0x6A, +0xD4,0xE3,0x30,0x81,0x8D,0x06,0x03,0x55,0x1D,0x23,0x04,0x81,0x85,0x30,0x81,0x82, +0x80,0x14,0xD2,0xC4,0xB0,0xD2,0x91,0xD4,0x4C,0x11,0x71,0xB3,0x61,0xCB,0x3D,0xA1, +0xFE,0xDD,0xA8,0x6A,0xD4,0xE3,0xA1,0x67,0xA4,0x65,0x30,0x63,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x21,0x30,0x1F,0x06,0x03,0x55, +0x04,0x0A,0x13,0x18,0x54,0x68,0x65,0x20,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79, +0x20,0x47,0x72,0x6F,0x75,0x70,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F, +0x06,0x03,0x55,0x04,0x0B,0x13,0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20, +0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x82, +0x01,0x00,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03, +0x82,0x01,0x01,0x00,0x32,0x4B,0xF3,0xB2,0xCA,0x3E,0x91,0xFC,0x12,0xC6,0xA1,0x07, +0x8C,0x8E,0x77,0xA0,0x33,0x06,0x14,0x5C,0x90,0x1E,0x18,0xF7,0x08,0xA6,0x3D,0x0A, +0x19,0xF9,0x87,0x80,0x11,0x6E,0x69,0xE4,0x96,0x17,0x30,0xFF,0x34,0x91,0x63,0x72, +0x38,0xEE,0xCC,0x1C,0x01,0xA3,0x1D,0x94,0x28,0xA4,0x31,0xF6,0x7A,0xC4,0x54,0xD7, +0xF6,0xE5,0x31,0x58,0x03,0xA2,0xCC,0xCE,0x62,0xDB,0x94,0x45,0x73,0xB5,0xBF,0x45, +0xC9,0x24,0xB5,0xD5,0x82,0x02,0xAD,0x23,0x79,0x69,0x8D,0xB8,0xB6,0x4D,0xCE,0xCF, +0x4C,0xCA,0x33,0x23,0xE8,0x1C,0x88,0xAA,0x9D,0x8B,0x41,0x6E,0x16,0xC9,0x20,0xE5, +0x89,0x9E,0xCD,0x3B,0xDA,0x70,0xF7,0x7E,0x99,0x26,0x20,0x14,0x54,0x25,0xAB,0x6E, +0x73,0x85,0xE6,0x9B,0x21,0x9D,0x0A,0x6C,0x82,0x0E,0xA8,0xF8,0xC2,0x0C,0xFA,0x10, +0x1E,0x6C,0x96,0xEF,0x87,0x0D,0xC4,0x0F,0x61,0x8B,0xAD,0xEE,0x83,0x2B,0x95,0xF8, +0x8E,0x92,0x84,0x72,0x39,0xEB,0x20,0xEA,0x83,0xED,0x83,0xCD,0x97,0x6E,0x08,0xBC, +0xEB,0x4E,0x26,0xB6,0x73,0x2B,0xE4,0xD3,0xF6,0x4C,0xFE,0x26,0x71,0xE2,0x61,0x11, +0x74,0x4A,0xFF,0x57,0x1A,0x87,0x0F,0x75,0x48,0x2E,0xCF,0x51,0x69,0x17,0xA0,0x02, +0x12,0x61,0x95,0xD5,0xD1,0x40,0xB2,0x10,0x4C,0xEE,0xC4,0xAC,0x10,0x43,0xA6,0xA5, +0x9E,0x0A,0xD5,0x95,0x62,0x9A,0x0D,0xCF,0x88,0x82,0xC5,0x32,0x0C,0xE4,0x2B,0x9F, +0x45,0xE6,0x0D,0x9F,0x28,0x9C,0xB1,0xB9,0x2A,0x5A,0x57,0xAD,0x37,0x0F,0xAF,0x1D, +0x7F,0xDB,0xBD,0x9F, +}; + + +/* subject:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./CN=Go Daddy Root Certificate Authority - G2 */ +/* issuer :/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./CN=Go Daddy Root Certificate Authority - G2 */ + + +const unsigned char Go_Daddy_Root_Certificate_Authority___G2_certificate[969]={ +0x30,0x82,0x03,0xC5,0x30,0x82,0x02,0xAD,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, +0x81,0x83,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, +0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E, +0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74, +0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13, +0x11,0x47,0x6F,0x44,0x61,0x64,0x64,0x79,0x2E,0x63,0x6F,0x6D,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04,0x03,0x13,0x28,0x47,0x6F,0x20, +0x44,0x61,0x64,0x64,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79, +0x20,0x2D,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x39,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x32,0x33,0x31,0x32,0x33, +0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x83,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07, +0x41,0x72,0x69,0x7A,0x6F,0x6E,0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07, +0x13,0x0A,0x53,0x63,0x6F,0x74,0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x1A,0x30,0x18, +0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x47,0x6F,0x44,0x61,0x64,0x64,0x79,0x2E,0x63, +0x6F,0x6D,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x31,0x30,0x2F,0x06,0x03,0x55,0x04, +0x03,0x13,0x28,0x47,0x6F,0x20,0x44,0x61,0x64,0x64,0x79,0x20,0x52,0x6F,0x6F,0x74, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82, +0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xBF,0x71,0x62,0x08, +0xF1,0xFA,0x59,0x34,0xF7,0x1B,0xC9,0x18,0xA3,0xF7,0x80,0x49,0x58,0xE9,0x22,0x83, +0x13,0xA6,0xC5,0x20,0x43,0x01,0x3B,0x84,0xF1,0xE6,0x85,0x49,0x9F,0x27,0xEA,0xF6, +0x84,0x1B,0x4E,0xA0,0xB4,0xDB,0x70,0x98,0xC7,0x32,0x01,0xB1,0x05,0x3E,0x07,0x4E, +0xEE,0xF4,0xFA,0x4F,0x2F,0x59,0x30,0x22,0xE7,0xAB,0x19,0x56,0x6B,0xE2,0x80,0x07, +0xFC,0xF3,0x16,0x75,0x80,0x39,0x51,0x7B,0xE5,0xF9,0x35,0xB6,0x74,0x4E,0xA9,0x8D, +0x82,0x13,0xE4,0xB6,0x3F,0xA9,0x03,0x83,0xFA,0xA2,0xBE,0x8A,0x15,0x6A,0x7F,0xDE, +0x0B,0xC3,0xB6,0x19,0x14,0x05,0xCA,0xEA,0xC3,0xA8,0x04,0x94,0x3B,0x46,0x7C,0x32, +0x0D,0xF3,0x00,0x66,0x22,0xC8,0x8D,0x69,0x6D,0x36,0x8C,0x11,0x18,0xB7,0xD3,0xB2, +0x1C,0x60,0xB4,0x38,0xFA,0x02,0x8C,0xCE,0xD3,0xDD,0x46,0x07,0xDE,0x0A,0x3E,0xEB, +0x5D,0x7C,0xC8,0x7C,0xFB,0xB0,0x2B,0x53,0xA4,0x92,0x62,0x69,0x51,0x25,0x05,0x61, +0x1A,0x44,0x81,0x8C,0x2C,0xA9,0x43,0x96,0x23,0xDF,0xAC,0x3A,0x81,0x9A,0x0E,0x29, +0xC5,0x1C,0xA9,0xE9,0x5D,0x1E,0xB6,0x9E,0x9E,0x30,0x0A,0x39,0xCE,0xF1,0x88,0x80, +0xFB,0x4B,0x5D,0xCC,0x32,0xEC,0x85,0x62,0x43,0x25,0x34,0x02,0x56,0x27,0x01,0x91, +0xB4,0x3B,0x70,0x2A,0x3F,0x6E,0xB1,0xE8,0x9C,0x88,0x01,0x7D,0x9F,0xD4,0xF9,0xDB, +0x53,0x6D,0x60,0x9D,0xBF,0x2C,0xE7,0x58,0xAB,0xB8,0x5F,0x46,0xFC,0xCE,0xC4,0x1B, +0x03,0x3C,0x09,0xEB,0x49,0x31,0x5C,0x69,0x46,0xB3,0xE0,0x47,0x02,0x03,0x01,0x00, +0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x3A,0x9A,0x85,0x07,0x10,0x67,0x28,0xB6,0xEF,0xF6,0xBD,0x05,0x41,0x6E,0x20, +0xC1,0x94,0xDA,0x0F,0xDE,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, +0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x99,0xDB,0x5D,0x79,0xD5,0xF9,0x97, +0x59,0x67,0x03,0x61,0xF1,0x7E,0x3B,0x06,0x31,0x75,0x2D,0xA1,0x20,0x8E,0x4F,0x65, +0x87,0xB4,0xF7,0xA6,0x9C,0xBC,0xD8,0xE9,0x2F,0xD0,0xDB,0x5A,0xEE,0xCF,0x74,0x8C, +0x73,0xB4,0x38,0x42,0xDA,0x05,0x7B,0xF8,0x02,0x75,0xB8,0xFD,0xA5,0xB1,0xD7,0xAE, +0xF6,0xD7,0xDE,0x13,0xCB,0x53,0x10,0x7E,0x8A,0x46,0xD1,0x97,0xFA,0xB7,0x2E,0x2B, +0x11,0xAB,0x90,0xB0,0x27,0x80,0xF9,0xE8,0x9F,0x5A,0xE9,0x37,0x9F,0xAB,0xE4,0xDF, +0x6C,0xB3,0x85,0x17,0x9D,0x3D,0xD9,0x24,0x4F,0x79,0x91,0x35,0xD6,0x5F,0x04,0xEB, +0x80,0x83,0xAB,0x9A,0x02,0x2D,0xB5,0x10,0xF4,0xD8,0x90,0xC7,0x04,0x73,0x40,0xED, +0x72,0x25,0xA0,0xA9,0x9F,0xEC,0x9E,0xAB,0x68,0x12,0x99,0x57,0xC6,0x8F,0x12,0x3A, +0x09,0xA4,0xBD,0x44,0xFD,0x06,0x15,0x37,0xC1,0x9B,0xE4,0x32,0xA3,0xED,0x38,0xE8, +0xD8,0x64,0xF3,0x2C,0x7E,0x14,0xFC,0x02,0xEA,0x9F,0xCD,0xFF,0x07,0x68,0x17,0xDB, +0x22,0x90,0x38,0x2D,0x7A,0x8D,0xD1,0x54,0xF1,0x69,0xE3,0x5F,0x33,0xCA,0x7A,0x3D, +0x7B,0x0A,0xE3,0xCA,0x7F,0x5F,0x39,0xE5,0xE2,0x75,0xBA,0xC5,0x76,0x18,0x33,0xCE, +0x2C,0xF0,0x2F,0x4C,0xAD,0xF7,0xB1,0xE7,0xCE,0x4F,0xA8,0xC4,0x9B,0x4A,0x54,0x06, +0xC5,0x7F,0x7D,0xD5,0x08,0x0F,0xE2,0x1C,0xFE,0x7E,0x17,0xB8,0xAC,0x5E,0xF6,0xD4, +0x16,0xB2,0x43,0x09,0x0C,0x4D,0xF6,0xA7,0x6B,0xB4,0x99,0x84,0x65,0xCA,0x7A,0x88, +0xE2,0xE2,0x44,0xBE,0x5C,0xF7,0xEA,0x1C,0xF5, +}; + + +/* subject:/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root */ +/* issuer :/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root */ + + +const unsigned char GTE_CyberTrust_Global_Root_certificate[606]={ +0x30,0x82,0x02,0x5A,0x30,0x82,0x01,0xC3,0x02,0x02,0x01,0xA5,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30,0x75,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x18,0x30,0x16,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0F,0x47,0x54,0x45,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61, +0x74,0x69,0x6F,0x6E,0x31,0x27,0x30,0x25,0x06,0x03,0x55,0x04,0x0B,0x13,0x1E,0x47, +0x54,0x45,0x20,0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x6F, +0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x23,0x30, +0x21,0x06,0x03,0x55,0x04,0x03,0x13,0x1A,0x47,0x54,0x45,0x20,0x43,0x79,0x62,0x65, +0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F, +0x6F,0x74,0x30,0x1E,0x17,0x0D,0x39,0x38,0x30,0x38,0x31,0x33,0x30,0x30,0x32,0x39, +0x30,0x30,0x5A,0x17,0x0D,0x31,0x38,0x30,0x38,0x31,0x33,0x32,0x33,0x35,0x39,0x30, +0x30,0x5A,0x30,0x75,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04,0x0A,0x13,0x0F,0x47,0x54,0x45,0x20, +0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x27,0x30,0x25,0x06, +0x03,0x55,0x04,0x0B,0x13,0x1E,0x47,0x54,0x45,0x20,0x43,0x79,0x62,0x65,0x72,0x54, +0x72,0x75,0x73,0x74,0x20,0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x2C,0x20, +0x49,0x6E,0x63,0x2E,0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x13,0x1A,0x47, +0x54,0x45,0x20,0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C, +0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30, +0x81,0x89,0x02,0x81,0x81,0x00,0x95,0x0F,0xA0,0xB6,0xF0,0x50,0x9C,0xE8,0x7A,0xC7, +0x88,0xCD,0xDD,0x17,0x0E,0x2E,0xB0,0x94,0xD0,0x1B,0x3D,0x0E,0xF6,0x94,0xC0,0x8A, +0x94,0xC7,0x06,0xC8,0x90,0x97,0xC8,0xB8,0x64,0x1A,0x7A,0x7E,0x6C,0x3C,0x53,0xE1, +0x37,0x28,0x73,0x60,0x7F,0xB2,0x97,0x53,0x07,0x9F,0x53,0xF9,0x6D,0x58,0x94,0xD2, +0xAF,0x8D,0x6D,0x88,0x67,0x80,0xE6,0xED,0xB2,0x95,0xCF,0x72,0x31,0xCA,0xA5,0x1C, +0x72,0xBA,0x5C,0x02,0xE7,0x64,0x42,0xE7,0xF9,0xA9,0x2C,0xD6,0x3A,0x0D,0xAC,0x8D, +0x42,0xAA,0x24,0x01,0x39,0xE6,0x9C,0x3F,0x01,0x85,0x57,0x0D,0x58,0x87,0x45,0xF8, +0xD3,0x85,0xAA,0x93,0x69,0x26,0x85,0x70,0x48,0x80,0x3F,0x12,0x15,0xC7,0x79,0xB4, +0x1F,0x05,0x2F,0x3B,0x62,0x99,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A, +0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x03,0x81,0x81,0x00,0x6D,0xEB, +0x1B,0x09,0xE9,0x5E,0xD9,0x51,0xDB,0x67,0x22,0x61,0xA4,0x2A,0x3C,0x48,0x77,0xE3, +0xA0,0x7C,0xA6,0xDE,0x73,0xA2,0x14,0x03,0x85,0x3D,0xFB,0xAB,0x0E,0x30,0xC5,0x83, +0x16,0x33,0x81,0x13,0x08,0x9E,0x7B,0x34,0x4E,0xDF,0x40,0xC8,0x74,0xD7,0xB9,0x7D, +0xDC,0xF4,0x76,0x55,0x7D,0x9B,0x63,0x54,0x18,0xE9,0xF0,0xEA,0xF3,0x5C,0xB1,0xD9, +0x8B,0x42,0x1E,0xB9,0xC0,0x95,0x4E,0xBA,0xFA,0xD5,0xE2,0x7C,0xF5,0x68,0x61,0xBF, +0x8E,0xEC,0x05,0x97,0x5F,0x5B,0xB0,0xD7,0xA3,0x85,0x34,0xC4,0x24,0xA7,0x0D,0x0F, +0x95,0x93,0xEF,0xCB,0x94,0xD8,0x9E,0x1F,0x9D,0x5C,0x85,0x6D,0xC7,0xAA,0xAE,0x4F, +0x1F,0x22,0xB5,0xCD,0x95,0xAD,0xBA,0xA7,0xCC,0xF9,0xAB,0x0B,0x7A,0x7F, +}; + + +/* subject:/C=US/O=Network Solutions L.L.C./CN=Network Solutions Certificate Authority */ +/* issuer :/C=US/O=Network Solutions L.L.C./CN=Network Solutions Certificate Authority */ + + +const unsigned char Network_Solutions_Certificate_Authority_certificate[1002]={ +0x30,0x82,0x03,0xE6,0x30,0x82,0x02,0xCE,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x57, +0xCB,0x33,0x6F,0xC2,0x5C,0x16,0xE6,0x47,0x16,0x17,0xE3,0x90,0x31,0x68,0xE0,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x62, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x21,0x30, +0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x20, +0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x20,0x4C,0x2E,0x4C,0x2E,0x43,0x2E, +0x31,0x30,0x30,0x2E,0x06,0x03,0x55,0x04,0x03,0x13,0x27,0x4E,0x65,0x74,0x77,0x6F, +0x72,0x6B,0x20,0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x20,0x43,0x65,0x72, +0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x32,0x30,0x31,0x30,0x30,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5A,0x30,0x62,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0A,0x13,0x18,0x4E,0x65,0x74,0x77, +0x6F,0x72,0x6B,0x20,0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x20,0x4C,0x2E, +0x4C,0x2E,0x43,0x2E,0x31,0x30,0x30,0x2E,0x06,0x03,0x55,0x04,0x03,0x13,0x27,0x4E, +0x65,0x74,0x77,0x6F,0x72,0x6B,0x20,0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, +0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xE4,0xBC,0x7E,0x92,0x30,0x6D,0xC6,0xD8,0x8E, +0x2B,0x0B,0xBC,0x46,0xCE,0xE0,0x27,0x96,0xDE,0xDE,0xF9,0xFA,0x12,0xD3,0x3C,0x33, +0x73,0xB3,0x04,0x2F,0xBC,0x71,0x8C,0xE5,0x9F,0xB6,0x22,0x60,0x3E,0x5F,0x5D,0xCE, +0x09,0xFF,0x82,0x0C,0x1B,0x9A,0x51,0x50,0x1A,0x26,0x89,0xDD,0xD5,0x61,0x5D,0x19, +0xDC,0x12,0x0F,0x2D,0x0A,0xA2,0x43,0x5D,0x17,0xD0,0x34,0x92,0x20,0xEA,0x73,0xCF, +0x38,0x2C,0x06,0x26,0x09,0x7A,0x72,0xF7,0xFA,0x50,0x32,0xF8,0xC2,0x93,0xD3,0x69, +0xA2,0x23,0xCE,0x41,0xB1,0xCC,0xE4,0xD5,0x1F,0x36,0xD1,0x8A,0x3A,0xF8,0x8C,0x63, +0xE2,0x14,0x59,0x69,0xED,0x0D,0xD3,0x7F,0x6B,0xE8,0xB8,0x03,0xE5,0x4F,0x6A,0xE5, +0x98,0x63,0x69,0x48,0x05,0xBE,0x2E,0xFF,0x33,0xB6,0xE9,0x97,0x59,0x69,0xF8,0x67, +0x19,0xAE,0x93,0x61,0x96,0x44,0x15,0xD3,0x72,0xB0,0x3F,0xBC,0x6A,0x7D,0xEC,0x48, +0x7F,0x8D,0xC3,0xAB,0xAA,0x71,0x2B,0x53,0x69,0x41,0x53,0x34,0xB5,0xB0,0xB9,0xC5, +0x06,0x0A,0xC4,0xB0,0x45,0xF5,0x41,0x5D,0x6E,0x89,0x45,0x7B,0x3D,0x3B,0x26,0x8C, +0x74,0xC2,0xE5,0xD2,0xD1,0x7D,0xB2,0x11,0xD4,0xFB,0x58,0x32,0x22,0x9A,0x80,0xC9, +0xDC,0xFD,0x0C,0xE9,0x7F,0x5E,0x03,0x97,0xCE,0x3B,0x00,0x14,0x87,0x27,0x70,0x38, +0xA9,0x8E,0x6E,0xB3,0x27,0x76,0x98,0x51,0xE0,0x05,0xE3,0x21,0xAB,0x1A,0xD5,0x85, +0x22,0x3C,0x29,0xB5,0x9A,0x16,0xC5,0x80,0xA8,0xF4,0xBB,0x6B,0x30,0x8F,0x2F,0x46, +0x02,0xA2,0xB1,0x0C,0x22,0xE0,0xD3,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x97,0x30, +0x81,0x94,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x21,0x30,0xC9, +0xFB,0x00,0xD7,0x4E,0x98,0xDA,0x87,0xAA,0x2A,0xD0,0xA7,0x2E,0xB1,0x40,0x31,0xA7, +0x4C,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, +0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01, +0x01,0xFF,0x30,0x52,0x06,0x03,0x55,0x1D,0x1F,0x04,0x4B,0x30,0x49,0x30,0x47,0xA0, +0x45,0xA0,0x43,0x86,0x41,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E, +0x6E,0x65,0x74,0x73,0x6F,0x6C,0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x4E,0x65, +0x74,0x77,0x6F,0x72,0x6B,0x53,0x6F,0x6C,0x75,0x74,0x69,0x6F,0x6E,0x73,0x43,0x65, +0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x2E,0x63,0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xBB,0xAE,0x4B,0xE7,0xB7,0x57, +0xEB,0x7F,0xAA,0x2D,0xB7,0x73,0x47,0x85,0x6A,0xC1,0xE4,0xA5,0x1D,0xE4,0xE7,0x3C, +0xE9,0xF4,0x59,0x65,0x77,0xB5,0x7A,0x5B,0x5A,0x8D,0x25,0x36,0xE0,0x7A,0x97,0x2E, +0x38,0xC0,0x57,0x60,0x83,0x98,0x06,0x83,0x9F,0xB9,0x76,0x7A,0x6E,0x50,0xE0,0xBA, +0x88,0x2C,0xFC,0x45,0xCC,0x18,0xB0,0x99,0x95,0x51,0x0E,0xEC,0x1D,0xB8,0x88,0xFF, +0x87,0x50,0x1C,0x82,0xC2,0xE3,0xE0,0x32,0x80,0xBF,0xA0,0x0B,0x47,0xC8,0xC3,0x31, +0xEF,0x99,0x67,0x32,0x80,0x4F,0x17,0x21,0x79,0x0C,0x69,0x5C,0xDE,0x5E,0x34,0xAE, +0x02,0xB5,0x26,0xEA,0x50,0xDF,0x7F,0x18,0x65,0x2C,0xC9,0xF2,0x63,0xE1,0xA9,0x07, +0xFE,0x7C,0x71,0x1F,0x6B,0x33,0x24,0x6A,0x1E,0x05,0xF7,0x05,0x68,0xC0,0x6A,0x12, +0xCB,0x2E,0x5E,0x61,0xCB,0xAE,0x28,0xD3,0x7E,0xC2,0xB4,0x66,0x91,0x26,0x5F,0x3C, +0x2E,0x24,0x5F,0xCB,0x58,0x0F,0xEB,0x28,0xEC,0xAF,0x11,0x96,0xF3,0xDC,0x7B,0x6F, +0xC0,0xA7,0x88,0xF2,0x53,0x77,0xB3,0x60,0x5E,0xAE,0xAE,0x28,0xDA,0x35,0x2C,0x6F, +0x34,0x45,0xD3,0x26,0xE1,0xDE,0xEC,0x5B,0x4F,0x27,0x6B,0x16,0x7C,0xBD,0x44,0x04, +0x18,0x82,0xB3,0x89,0x79,0x17,0x10,0x71,0x3D,0x7A,0xA2,0x16,0x4E,0xF5,0x01,0xCD, +0xA4,0x6C,0x65,0x68,0xA1,0x49,0x76,0x5C,0x43,0xC9,0xD8,0xBC,0x36,0x67,0x6C,0xA5, +0x94,0xB5,0xD4,0xCC,0xB9,0xBD,0x6A,0x35,0x56,0x21,0xDE,0xD8,0xC3,0xEB,0xFB,0xCB, +0xA4,0x60,0x4C,0xB0,0x55,0xA0,0xA0,0x7B,0x57,0xB2, +}; + + +/* subject:/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 3 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ +/* issuer :/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 3 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ + + +const unsigned char RSA_Root_Certificate_1_certificate[747]={ +0x30,0x82,0x02,0xE7,0x30,0x82,0x02,0x50,0x02,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A, +0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xBB,0x31,0x24,0x30, +0x22,0x06,0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74, +0x20,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77, +0x6F,0x72,0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61, +0x6C,0x69,0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33, +0x06,0x03,0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20, +0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56, +0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74, +0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72, +0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69, +0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36, +0x32,0x36,0x30,0x30,0x32,0x32,0x33,0x33,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32, +0x36,0x30,0x30,0x32,0x32,0x33,0x33,0x5A,0x30,0x81,0xBB,0x31,0x24,0x30,0x22,0x06, +0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x56, +0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, +0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61,0x6C,0x69, +0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33,0x06,0x03, +0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x43,0x6C, +0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56,0x61,0x6C, +0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, +0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74,0x74,0x70, +0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72,0x74,0x2E, +0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69,0x63,0x65, +0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02, +0x81,0x81,0x00,0xE3,0x98,0x51,0x96,0x1C,0xE8,0xD5,0xB1,0x06,0x81,0x6A,0x57,0xC3, +0x72,0x75,0x93,0xAB,0xCF,0x9E,0xA6,0xFC,0xF3,0x16,0x52,0xD6,0x2D,0x4D,0x9F,0x35, +0x44,0xA8,0x2E,0x04,0x4D,0x07,0x49,0x8A,0x38,0x29,0xF5,0x77,0x37,0xE7,0xB7,0xAB, +0x5D,0xDF,0x36,0x71,0x14,0x99,0x8F,0xDC,0xC2,0x92,0xF1,0xE7,0x60,0x92,0x97,0xEC, +0xD8,0x48,0xDC,0xBF,0xC1,0x02,0x20,0xC6,0x24,0xA4,0x28,0x4C,0x30,0x5A,0x76,0x6D, +0xB1,0x5C,0xF3,0xDD,0xDE,0x9E,0x10,0x71,0xA1,0x88,0xC7,0x5B,0x9B,0x41,0x6D,0xCA, +0xB0,0xB8,0x8E,0x15,0xEE,0xAD,0x33,0x2B,0xCF,0x47,0x04,0x5C,0x75,0x71,0x0A,0x98, +0x24,0x98,0x29,0xA7,0x49,0x59,0xA5,0xDD,0xF8,0xB7,0x43,0x62,0x61,0xF3,0xD3,0xE2, +0xD0,0x55,0x3F,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x56,0xBB,0x02,0x58,0x84, +0x67,0x08,0x2C,0xDF,0x1F,0xDB,0x7B,0x49,0x33,0xF5,0xD3,0x67,0x9D,0xF4,0xB4,0x0A, +0x10,0xB3,0xC9,0xC5,0x2C,0xE2,0x92,0x6A,0x71,0x78,0x27,0xF2,0x70,0x83,0x42,0xD3, +0x3E,0xCF,0xA9,0x54,0xF4,0xF1,0xD8,0x92,0x16,0x8C,0xD1,0x04,0xCB,0x4B,0xAB,0xC9, +0x9F,0x45,0xAE,0x3C,0x8A,0xA9,0xB0,0x71,0x33,0x5D,0xC8,0xC5,0x57,0xDF,0xAF,0xA8, +0x35,0xB3,0x7F,0x89,0x87,0xE9,0xE8,0x25,0x92,0xB8,0x7F,0x85,0x7A,0xAE,0xD6,0xBC, +0x1E,0x37,0x58,0x2A,0x67,0xC9,0x91,0xCF,0x2A,0x81,0x3E,0xED,0xC6,0x39,0xDF,0xC0, +0x3E,0x19,0x9C,0x19,0xCC,0x13,0x4D,0x82,0x41,0xB5,0x8C,0xDE,0xE0,0x3D,0x60,0x08, +0x20,0x0F,0x45,0x7E,0x6B,0xA2,0x7F,0xA3,0x8C,0x15,0xEE, +}; + + +/* subject:/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority */ +/* issuer :/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority */ + + +const unsigned char Starfield_Class_2_CA_certificate[1043]={ +0x30,0x82,0x04,0x0F,0x30,0x82,0x02,0xF7,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, +0x68,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x25, +0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65, +0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C, +0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x0B,0x13,0x29, +0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x43,0x6C,0x61,0x73,0x73,0x20, +0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, +0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x30, +0x36,0x32,0x39,0x31,0x37,0x33,0x39,0x31,0x36,0x5A,0x17,0x0D,0x33,0x34,0x30,0x36, +0x32,0x39,0x31,0x37,0x33,0x39,0x31,0x36,0x5A,0x30,0x68,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04, +0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63, +0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31, +0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x0B,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69, +0x65,0x6C,0x64,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x30,0x82,0x01,0x20,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0D,0x00,0x30,0x82,0x01,0x08,0x02, +0x82,0x01,0x01,0x00,0xB7,0x32,0xC8,0xFE,0xE9,0x71,0xA6,0x04,0x85,0xAD,0x0C,0x11, +0x64,0xDF,0xCE,0x4D,0xEF,0xC8,0x03,0x18,0x87,0x3F,0xA1,0xAB,0xFB,0x3C,0xA6,0x9F, +0xF0,0xC3,0xA1,0xDA,0xD4,0xD8,0x6E,0x2B,0x53,0x90,0xFB,0x24,0xA4,0x3E,0x84,0xF0, +0x9E,0xE8,0x5F,0xEC,0xE5,0x27,0x44,0xF5,0x28,0xA6,0x3F,0x7B,0xDE,0xE0,0x2A,0xF0, +0xC8,0xAF,0x53,0x2F,0x9E,0xCA,0x05,0x01,0x93,0x1E,0x8F,0x66,0x1C,0x39,0xA7,0x4D, +0xFA,0x5A,0xB6,0x73,0x04,0x25,0x66,0xEB,0x77,0x7F,0xE7,0x59,0xC6,0x4A,0x99,0x25, +0x14,0x54,0xEB,0x26,0xC7,0xF3,0x7F,0x19,0xD5,0x30,0x70,0x8F,0xAF,0xB0,0x46,0x2A, +0xFF,0xAD,0xEB,0x29,0xED,0xD7,0x9F,0xAA,0x04,0x87,0xA3,0xD4,0xF9,0x89,0xA5,0x34, +0x5F,0xDB,0x43,0x91,0x82,0x36,0xD9,0x66,0x3C,0xB1,0xB8,0xB9,0x82,0xFD,0x9C,0x3A, +0x3E,0x10,0xC8,0x3B,0xEF,0x06,0x65,0x66,0x7A,0x9B,0x19,0x18,0x3D,0xFF,0x71,0x51, +0x3C,0x30,0x2E,0x5F,0xBE,0x3D,0x77,0x73,0xB2,0x5D,0x06,0x6C,0xC3,0x23,0x56,0x9A, +0x2B,0x85,0x26,0x92,0x1C,0xA7,0x02,0xB3,0xE4,0x3F,0x0D,0xAF,0x08,0x79,0x82,0xB8, +0x36,0x3D,0xEA,0x9C,0xD3,0x35,0xB3,0xBC,0x69,0xCA,0xF5,0xCC,0x9D,0xE8,0xFD,0x64, +0x8D,0x17,0x80,0x33,0x6E,0x5E,0x4A,0x5D,0x99,0xC9,0x1E,0x87,0xB4,0x9D,0x1A,0xC0, +0xD5,0x6E,0x13,0x35,0x23,0x5E,0xDF,0x9B,0x5F,0x3D,0xEF,0xD6,0xF7,0x76,0xC2,0xEA, +0x3E,0xBB,0x78,0x0D,0x1C,0x42,0x67,0x6B,0x04,0xD8,0xF8,0xD6,0xDA,0x6F,0x8B,0xF2, +0x44,0xA0,0x01,0xAB,0x02,0x01,0x03,0xA3,0x81,0xC5,0x30,0x81,0xC2,0x30,0x1D,0x06, +0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xBF,0x5F,0xB7,0xD1,0xCE,0xDD,0x1F,0x86, +0xF4,0x5B,0x55,0xAC,0xDC,0xD7,0x10,0xC2,0x0E,0xA9,0x88,0xE7,0x30,0x81,0x92,0x06, +0x03,0x55,0x1D,0x23,0x04,0x81,0x8A,0x30,0x81,0x87,0x80,0x14,0xBF,0x5F,0xB7,0xD1, +0xCE,0xDD,0x1F,0x86,0xF4,0x5B,0x55,0xAC,0xDC,0xD7,0x10,0xC2,0x0E,0xA9,0x88,0xE7, +0xA1,0x6C,0xA4,0x6A,0x30,0x68,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x53,0x74, +0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F, +0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30,0x30,0x06,0x03, +0x55,0x04,0x0B,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x43, +0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x82,0x01, +0x00,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0x05,0x9D,0x3F,0x88,0x9D,0xD1,0xC9,0x1A,0x55,0xA1,0xAC,0x69,0xF3, +0xF3,0x59,0xDA,0x9B,0x01,0x87,0x1A,0x4F,0x57,0xA9,0xA1,0x79,0x09,0x2A,0xDB,0xF7, +0x2F,0xB2,0x1E,0xCC,0xC7,0x5E,0x6A,0xD8,0x83,0x87,0xA1,0x97,0xEF,0x49,0x35,0x3E, +0x77,0x06,0x41,0x58,0x62,0xBF,0x8E,0x58,0xB8,0x0A,0x67,0x3F,0xEC,0xB3,0xDD,0x21, +0x66,0x1F,0xC9,0x54,0xFA,0x72,0xCC,0x3D,0x4C,0x40,0xD8,0x81,0xAF,0x77,0x9E,0x83, +0x7A,0xBB,0xA2,0xC7,0xF5,0x34,0x17,0x8E,0xD9,0x11,0x40,0xF4,0xFC,0x2C,0x2A,0x4D, +0x15,0x7F,0xA7,0x62,0x5D,0x2E,0x25,0xD3,0x00,0x0B,0x20,0x1A,0x1D,0x68,0xF9,0x17, +0xB8,0xF4,0xBD,0x8B,0xED,0x28,0x59,0xDD,0x4D,0x16,0x8B,0x17,0x83,0xC8,0xB2,0x65, +0xC7,0x2D,0x7A,0xA5,0xAA,0xBC,0x53,0x86,0x6D,0xDD,0x57,0xA4,0xCA,0xF8,0x20,0x41, +0x0B,0x68,0xF0,0xF4,0xFB,0x74,0xBE,0x56,0x5D,0x7A,0x79,0xF5,0xF9,0x1D,0x85,0xE3, +0x2D,0x95,0xBE,0xF5,0x71,0x90,0x43,0xCC,0x8D,0x1F,0x9A,0x00,0x0A,0x87,0x29,0xE9, +0x55,0x22,0x58,0x00,0x23,0xEA,0xE3,0x12,0x43,0x29,0x5B,0x47,0x08,0xDD,0x8C,0x41, +0x6A,0x65,0x06,0xA8,0xE5,0x21,0xAA,0x41,0xB4,0x95,0x21,0x95,0xB9,0x7D,0xD1,0x34, +0xAB,0x13,0xD6,0xAD,0xBC,0xDC,0xE2,0x3D,0x39,0xCD,0xBD,0x3E,0x75,0x70,0xA1,0x18, +0x59,0x03,0xC9,0x22,0xB4,0x8F,0x9C,0xD5,0x5E,0x2A,0xD7,0xA5,0xB6,0xD4,0x0A,0x6D, +0xF8,0xB7,0x40,0x11,0x46,0x9A,0x1F,0x79,0x0E,0x62,0xBF,0x0F,0x97,0xEC,0xE0,0x2F, +0x1F,0x17,0x94, +}; + + +/* subject:/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Root Certificate Authority - G2 */ +/* issuer :/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Root Certificate Authority - G2 */ + + +const unsigned char Starfield_Root_Certificate_Authority___G2_certificate[993]={ +0x30,0x82,0x03,0xDD,0x30,0x82,0x02,0xC5,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, +0x81,0x8F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, +0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E, +0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74, +0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13, +0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E, +0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x32,0x30, +0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C, +0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47, +0x32,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5A,0x17,0x0D,0x33,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39, +0x5A,0x30,0x81,0x8F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A, +0x6F,0x6E,0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63, +0x6F,0x74,0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04, +0x0A,0x13,0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63, +0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31, +0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x03,0x13,0x29,0x53,0x74,0x61,0x72,0x66,0x69, +0x65,0x6C,0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69, +0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D, +0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02, +0x82,0x01,0x01,0x00,0xBD,0xED,0xC1,0x03,0xFC,0xF6,0x8F,0xFC,0x02,0xB1,0x6F,0x5B, +0x9F,0x48,0xD9,0x9D,0x79,0xE2,0xA2,0xB7,0x03,0x61,0x56,0x18,0xC3,0x47,0xB6,0xD7, +0xCA,0x3D,0x35,0x2E,0x89,0x43,0xF7,0xA1,0x69,0x9B,0xDE,0x8A,0x1A,0xFD,0x13,0x20, +0x9C,0xB4,0x49,0x77,0x32,0x29,0x56,0xFD,0xB9,0xEC,0x8C,0xDD,0x22,0xFA,0x72,0xDC, +0x27,0x61,0x97,0xEE,0xF6,0x5A,0x84,0xEC,0x6E,0x19,0xB9,0x89,0x2C,0xDC,0x84,0x5B, +0xD5,0x74,0xFB,0x6B,0x5F,0xC5,0x89,0xA5,0x10,0x52,0x89,0x46,0x55,0xF4,0xB8,0x75, +0x1C,0xE6,0x7F,0xE4,0x54,0xAE,0x4B,0xF8,0x55,0x72,0x57,0x02,0x19,0xF8,0x17,0x71, +0x59,0xEB,0x1E,0x28,0x07,0x74,0xC5,0x9D,0x48,0xBE,0x6C,0xB4,0xF4,0xA4,0xB0,0xF3, +0x64,0x37,0x79,0x92,0xC0,0xEC,0x46,0x5E,0x7F,0xE1,0x6D,0x53,0x4C,0x62,0xAF,0xCD, +0x1F,0x0B,0x63,0xBB,0x3A,0x9D,0xFB,0xFC,0x79,0x00,0x98,0x61,0x74,0xCF,0x26,0x82, +0x40,0x63,0xF3,0xB2,0x72,0x6A,0x19,0x0D,0x99,0xCA,0xD4,0x0E,0x75,0xCC,0x37,0xFB, +0x8B,0x89,0xC1,0x59,0xF1,0x62,0x7F,0x5F,0xB3,0x5F,0x65,0x30,0xF8,0xA7,0xB7,0x4D, +0x76,0x5A,0x1E,0x76,0x5E,0x34,0xC0,0xE8,0x96,0x56,0x99,0x8A,0xB3,0xF0,0x7F,0xA4, +0xCD,0xBD,0xDC,0x32,0x31,0x7C,0x91,0xCF,0xE0,0x5F,0x11,0xF8,0x6B,0xAA,0x49,0x5C, +0xD1,0x99,0x94,0xD1,0xA2,0xE3,0x63,0x5B,0x09,0x76,0xB5,0x56,0x62,0xE1,0x4B,0x74, +0x1D,0x96,0xD4,0x26,0xD4,0x08,0x04,0x59,0xD0,0x98,0x0E,0x0E,0xE6,0xDE,0xFC,0xC3, +0xEC,0x1F,0x90,0xF1,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x7C,0x0C,0x32,0x1F,0xA7,0xD9,0x30, +0x7F,0xC4,0x7D,0x68,0xA3,0x62,0xA8,0xA1,0xCE,0xAB,0x07,0x5B,0x27,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01, +0x00,0x11,0x59,0xFA,0x25,0x4F,0x03,0x6F,0x94,0x99,0x3B,0x9A,0x1F,0x82,0x85,0x39, +0xD4,0x76,0x05,0x94,0x5E,0xE1,0x28,0x93,0x6D,0x62,0x5D,0x09,0xC2,0xA0,0xA8,0xD4, +0xB0,0x75,0x38,0xF1,0x34,0x6A,0x9D,0xE4,0x9F,0x8A,0x86,0x26,0x51,0xE6,0x2C,0xD1, +0xC6,0x2D,0x6E,0x95,0x20,0x4A,0x92,0x01,0xEC,0xB8,0x8A,0x67,0x7B,0x31,0xE2,0x67, +0x2E,0x8C,0x95,0x03,0x26,0x2E,0x43,0x9D,0x4A,0x31,0xF6,0x0E,0xB5,0x0C,0xBB,0xB7, +0xE2,0x37,0x7F,0x22,0xBA,0x00,0xA3,0x0E,0x7B,0x52,0xFB,0x6B,0xBB,0x3B,0xC4,0xD3, +0x79,0x51,0x4E,0xCD,0x90,0xF4,0x67,0x07,0x19,0xC8,0x3C,0x46,0x7A,0x0D,0x01,0x7D, +0xC5,0x58,0xE7,0x6D,0xE6,0x85,0x30,0x17,0x9A,0x24,0xC4,0x10,0xE0,0x04,0xF7,0xE0, +0xF2,0x7F,0xD4,0xAA,0x0A,0xFF,0x42,0x1D,0x37,0xED,0x94,0xE5,0x64,0x59,0x12,0x20, +0x77,0x38,0xD3,0x32,0x3E,0x38,0x81,0x75,0x96,0x73,0xFA,0x68,0x8F,0xB1,0xCB,0xCE, +0x1F,0xC5,0xEC,0xFA,0x9C,0x7E,0xCF,0x7E,0xB1,0xF1,0x07,0x2D,0xB6,0xFC,0xBF,0xCA, +0xA4,0xBF,0xD0,0x97,0x05,0x4A,0xBC,0xEA,0x18,0x28,0x02,0x90,0xBD,0x54,0x78,0x09, +0x21,0x71,0xD3,0xD1,0x7D,0x1D,0xD9,0x16,0xB0,0xA9,0x61,0x3D,0xD0,0x0A,0x00,0x22, +0xFC,0xC7,0x7B,0xCB,0x09,0x64,0x45,0x0B,0x3B,0x40,0x81,0xF7,0x7D,0x7C,0x32,0xF5, +0x98,0xCA,0x58,0x8E,0x7D,0x2A,0xEE,0x90,0x59,0x73,0x64,0xF9,0x36,0x74,0x5E,0x25, +0xA1,0xF5,0x66,0x05,0x2E,0x7F,0x39,0x15,0xA9,0x2A,0xFB,0x50,0x8B,0x8E,0x85,0x69, +0xF4, +}; + + +/* subject:/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Services Root Certificate Authority - G2 */ +/* issuer :/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./CN=Starfield Services Root Certificate Authority - G2 */ + + +const unsigned char Starfield_Services_Root_Certificate_Authority___G2_certificate[1011]={ +0x30,0x82,0x03,0xEF,0x30,0x82,0x02,0xD7,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x00, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, +0x81,0x98,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, +0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E, +0x61,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74, +0x74,0x73,0x64,0x61,0x6C,0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13, +0x1C,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E, +0x6F,0x6C,0x6F,0x67,0x69,0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x3B,0x30, +0x39,0x06,0x03,0x55,0x04,0x03,0x13,0x32,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C, +0x64,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x52,0x6F,0x6F,0x74,0x20, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68, +0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x39, +0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x37,0x31, +0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x98,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x10,0x30,0x0E,0x06,0x03, +0x55,0x04,0x08,0x13,0x07,0x41,0x72,0x69,0x7A,0x6F,0x6E,0x61,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x07,0x13,0x0A,0x53,0x63,0x6F,0x74,0x74,0x73,0x64,0x61,0x6C, +0x65,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x53,0x74,0x61,0x72, +0x66,0x69,0x65,0x6C,0x64,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x69, +0x65,0x73,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x3B,0x30,0x39,0x06,0x03,0x55,0x04, +0x03,0x13,0x32,0x53,0x74,0x61,0x72,0x66,0x69,0x65,0x6C,0x64,0x20,0x53,0x65,0x72, +0x76,0x69,0x63,0x65,0x73,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79, +0x20,0x2D,0x20,0x47,0x32,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01, +0x0A,0x02,0x82,0x01,0x01,0x00,0xD5,0x0C,0x3A,0xC4,0x2A,0xF9,0x4E,0xE2,0xF5,0xBE, +0x19,0x97,0x5F,0x8E,0x88,0x53,0xB1,0x1F,0x3F,0xCB,0xCF,0x9F,0x20,0x13,0x6D,0x29, +0x3A,0xC8,0x0F,0x7D,0x3C,0xF7,0x6B,0x76,0x38,0x63,0xD9,0x36,0x60,0xA8,0x9B,0x5E, +0x5C,0x00,0x80,0xB2,0x2F,0x59,0x7F,0xF6,0x87,0xF9,0x25,0x43,0x86,0xE7,0x69,0x1B, +0x52,0x9A,0x90,0xE1,0x71,0xE3,0xD8,0x2D,0x0D,0x4E,0x6F,0xF6,0xC8,0x49,0xD9,0xB6, +0xF3,0x1A,0x56,0xAE,0x2B,0xB6,0x74,0x14,0xEB,0xCF,0xFB,0x26,0xE3,0x1A,0xBA,0x1D, +0x96,0x2E,0x6A,0x3B,0x58,0x94,0x89,0x47,0x56,0xFF,0x25,0xA0,0x93,0x70,0x53,0x83, +0xDA,0x84,0x74,0x14,0xC3,0x67,0x9E,0x04,0x68,0x3A,0xDF,0x8E,0x40,0x5A,0x1D,0x4A, +0x4E,0xCF,0x43,0x91,0x3B,0xE7,0x56,0xD6,0x00,0x70,0xCB,0x52,0xEE,0x7B,0x7D,0xAE, +0x3A,0xE7,0xBC,0x31,0xF9,0x45,0xF6,0xC2,0x60,0xCF,0x13,0x59,0x02,0x2B,0x80,0xCC, +0x34,0x47,0xDF,0xB9,0xDE,0x90,0x65,0x6D,0x02,0xCF,0x2C,0x91,0xA6,0xA6,0xE7,0xDE, +0x85,0x18,0x49,0x7C,0x66,0x4E,0xA3,0x3A,0x6D,0xA9,0xB5,0xEE,0x34,0x2E,0xBA,0x0D, +0x03,0xB8,0x33,0xDF,0x47,0xEB,0xB1,0x6B,0x8D,0x25,0xD9,0x9B,0xCE,0x81,0xD1,0x45, +0x46,0x32,0x96,0x70,0x87,0xDE,0x02,0x0E,0x49,0x43,0x85,0xB6,0x6C,0x73,0xBB,0x64, +0xEA,0x61,0x41,0xAC,0xC9,0xD4,0x54,0xDF,0x87,0x2F,0xC7,0x22,0xB2,0x26,0xCC,0x9F, +0x59,0x54,0x68,0x9F,0xFC,0xBE,0x2A,0x2F,0xC4,0x55,0x1C,0x75,0x40,0x60,0x17,0x85, +0x02,0x55,0x39,0x8B,0x7F,0x05,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30, +0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, +0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06, +0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x9C,0x5F,0x00,0xDF,0xAA, +0x01,0xD7,0x30,0x2B,0x38,0x88,0xA2,0xB8,0x6D,0x4A,0x9C,0xF2,0x11,0x91,0x83,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82, +0x01,0x01,0x00,0x4B,0x36,0xA6,0x84,0x77,0x69,0xDD,0x3B,0x19,0x9F,0x67,0x23,0x08, +0x6F,0x0E,0x61,0xC9,0xFD,0x84,0xDC,0x5F,0xD8,0x36,0x81,0xCD,0xD8,0x1B,0x41,0x2D, +0x9F,0x60,0xDD,0xC7,0x1A,0x68,0xD9,0xD1,0x6E,0x86,0xE1,0x88,0x23,0xCF,0x13,0xDE, +0x43,0xCF,0xE2,0x34,0xB3,0x04,0x9D,0x1F,0x29,0xD5,0xBF,0xF8,0x5E,0xC8,0xD5,0xC1, +0xBD,0xEE,0x92,0x6F,0x32,0x74,0xF2,0x91,0x82,0x2F,0xBD,0x82,0x42,0x7A,0xAD,0x2A, +0xB7,0x20,0x7D,0x4D,0xBC,0x7A,0x55,0x12,0xC2,0x15,0xEA,0xBD,0xF7,0x6A,0x95,0x2E, +0x6C,0x74,0x9F,0xCF,0x1C,0xB4,0xF2,0xC5,0x01,0xA3,0x85,0xD0,0x72,0x3E,0xAD,0x73, +0xAB,0x0B,0x9B,0x75,0x0C,0x6D,0x45,0xB7,0x8E,0x94,0xAC,0x96,0x37,0xB5,0xA0,0xD0, +0x8F,0x15,0x47,0x0E,0xE3,0xE8,0x83,0xDD,0x8F,0xFD,0xEF,0x41,0x01,0x77,0xCC,0x27, +0xA9,0x62,0x85,0x33,0xF2,0x37,0x08,0xEF,0x71,0xCF,0x77,0x06,0xDE,0xC8,0x19,0x1D, +0x88,0x40,0xCF,0x7D,0x46,0x1D,0xFF,0x1E,0xC7,0xE1,0xCE,0xFF,0x23,0xDB,0xC6,0xFA, +0x8D,0x55,0x4E,0xA9,0x02,0xE7,0x47,0x11,0x46,0x3E,0xF4,0xFD,0xBD,0x7B,0x29,0x26, +0xBB,0xA9,0x61,0x62,0x37,0x28,0xB6,0x2D,0x2A,0xF6,0x10,0x86,0x64,0xC9,0x70,0xA7, +0xD2,0xAD,0xB7,0x29,0x70,0x79,0xEA,0x3C,0xDA,0x63,0x25,0x9F,0xFD,0x68,0xB7,0x30, +0xEC,0x70,0xFB,0x75,0x8A,0xB7,0x6D,0x60,0x67,0xB2,0x1E,0xC8,0xB9,0xE9,0xD8,0xA8, +0x6F,0x02,0x8B,0x67,0x0D,0x4D,0x26,0x57,0x71,0xDA,0x20,0xFC,0xC1,0x4A,0x50,0x8D, +0xB1,0x28,0xBA, +}; + + +/* subject:/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority */ +/* issuer :/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority */ + + +const unsigned char StartCom_Certification_Authority_certificate[1931]={ +0x30,0x82,0x07,0x87,0x30,0x82,0x05,0x6F,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x2D, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, +0x7D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x4C,0x31,0x16, +0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x53,0x74,0x61,0x72,0x74,0x43,0x6F, +0x6D,0x20,0x4C,0x74,0x64,0x2E,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x0B,0x13, +0x22,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x44,0x69,0x67,0x69,0x74,0x61,0x6C,0x20, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x69,0x67,0x6E, +0x69,0x6E,0x67,0x31,0x29,0x30,0x27,0x06,0x03,0x55,0x04,0x03,0x13,0x20,0x53,0x74, +0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E, +0x17,0x0D,0x30,0x36,0x30,0x39,0x31,0x37,0x31,0x39,0x34,0x36,0x33,0x37,0x5A,0x17, +0x0D,0x33,0x36,0x30,0x39,0x31,0x37,0x31,0x39,0x34,0x36,0x33,0x36,0x5A,0x30,0x7D, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x4C,0x31,0x16,0x30, +0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x53,0x74,0x61,0x72,0x74,0x43,0x6F,0x6D, +0x20,0x4C,0x74,0x64,0x2E,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x0B,0x13,0x22, +0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x44,0x69,0x67,0x69,0x74,0x61,0x6C,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x69,0x67,0x6E,0x69, +0x6E,0x67,0x31,0x29,0x30,0x27,0x06,0x03,0x55,0x04,0x03,0x13,0x20,0x53,0x74,0x61, +0x72,0x74,0x43,0x6F,0x6D,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74, +0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x02, +0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, +0x03,0x82,0x02,0x0F,0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xC1,0x88, +0xDB,0x09,0xBC,0x6C,0x46,0x7C,0x78,0x9F,0x95,0x7B,0xB5,0x33,0x90,0xF2,0x72,0x62, +0xD6,0xC1,0x36,0x20,0x22,0x24,0x5E,0xCE,0xE9,0x77,0xF2,0x43,0x0A,0xA2,0x06,0x64, +0xA4,0xCC,0x8E,0x36,0xF8,0x38,0xE6,0x23,0xF0,0x6E,0x6D,0xB1,0x3C,0xDD,0x72,0xA3, +0x85,0x1C,0xA1,0xD3,0x3D,0xB4,0x33,0x2B,0xD3,0x2F,0xAF,0xFE,0xEA,0xB0,0x41,0x59, +0x67,0xB6,0xC4,0x06,0x7D,0x0A,0x9E,0x74,0x85,0xD6,0x79,0x4C,0x80,0x37,0x7A,0xDF, +0x39,0x05,0x52,0x59,0xF7,0xF4,0x1B,0x46,0x43,0xA4,0xD2,0x85,0x85,0xD2,0xC3,0x71, +0xF3,0x75,0x62,0x34,0xBA,0x2C,0x8A,0x7F,0x1E,0x8F,0xEE,0xED,0x34,0xD0,0x11,0xC7, +0x96,0xCD,0x52,0x3D,0xBA,0x33,0xD6,0xDD,0x4D,0xDE,0x0B,0x3B,0x4A,0x4B,0x9F,0xC2, +0x26,0x2F,0xFA,0xB5,0x16,0x1C,0x72,0x35,0x77,0xCA,0x3C,0x5D,0xE6,0xCA,0xE1,0x26, +0x8B,0x1A,0x36,0x76,0x5C,0x01,0xDB,0x74,0x14,0x25,0xFE,0xED,0xB5,0xA0,0x88,0x0F, +0xDD,0x78,0xCA,0x2D,0x1F,0x07,0x97,0x30,0x01,0x2D,0x72,0x79,0xFA,0x46,0xD6,0x13, +0x2A,0xA8,0xB9,0xA6,0xAB,0x83,0x49,0x1D,0xE5,0xF2,0xEF,0xDD,0xE4,0x01,0x8E,0x18, +0x0A,0x8F,0x63,0x53,0x16,0x85,0x62,0xA9,0x0E,0x19,0x3A,0xCC,0xB5,0x66,0xA6,0xC2, +0x6B,0x74,0x07,0xE4,0x2B,0xE1,0x76,0x3E,0xB4,0x6D,0xD8,0xF6,0x44,0xE1,0x73,0x62, +0x1F,0x3B,0xC4,0xBE,0xA0,0x53,0x56,0x25,0x6C,0x51,0x09,0xF7,0xAA,0xAB,0xCA,0xBF, +0x76,0xFD,0x6D,0x9B,0xF3,0x9D,0xDB,0xBF,0x3D,0x66,0xBC,0x0C,0x56,0xAA,0xAF,0x98, +0x48,0x95,0x3A,0x4B,0xDF,0xA7,0x58,0x50,0xD9,0x38,0x75,0xA9,0x5B,0xEA,0x43,0x0C, +0x02,0xFF,0x99,0xEB,0xE8,0x6C,0x4D,0x70,0x5B,0x29,0x65,0x9C,0xDD,0xAA,0x5D,0xCC, +0xAF,0x01,0x31,0xEC,0x0C,0xEB,0xD2,0x8D,0xE8,0xEA,0x9C,0x7B,0xE6,0x6E,0xF7,0x27, +0x66,0x0C,0x1A,0x48,0xD7,0x6E,0x42,0xE3,0x3F,0xDE,0x21,0x3E,0x7B,0xE1,0x0D,0x70, +0xFB,0x63,0xAA,0xA8,0x6C,0x1A,0x54,0xB4,0x5C,0x25,0x7A,0xC9,0xA2,0xC9,0x8B,0x16, +0xA6,0xBB,0x2C,0x7E,0x17,0x5E,0x05,0x4D,0x58,0x6E,0x12,0x1D,0x01,0xEE,0x12,0x10, +0x0D,0xC6,0x32,0x7F,0x18,0xFF,0xFC,0xF4,0xFA,0xCD,0x6E,0x91,0xE8,0x36,0x49,0xBE, +0x1A,0x48,0x69,0x8B,0xC2,0x96,0x4D,0x1A,0x12,0xB2,0x69,0x17,0xC1,0x0A,0x90,0xD6, +0xFA,0x79,0x22,0x48,0xBF,0xBA,0x7B,0x69,0xF8,0x70,0xC7,0xFA,0x7A,0x37,0xD8,0xD8, +0x0D,0xD2,0x76,0x4F,0x57,0xFF,0x90,0xB7,0xE3,0x91,0xD2,0xDD,0xEF,0xC2,0x60,0xB7, +0x67,0x3A,0xDD,0xFE,0xAA,0x9C,0xF0,0xD4,0x8B,0x7F,0x72,0x22,0xCE,0xC6,0x9F,0x97, +0xB6,0xF8,0xAF,0x8A,0xA0,0x10,0xA8,0xD9,0xFB,0x18,0xC6,0xB6,0xB5,0x5C,0x52,0x3C, +0x89,0xB6,0x19,0x2A,0x73,0x01,0x0A,0x0F,0x03,0xB3,0x12,0x60,0xF2,0x7A,0x2F,0x81, +0xDB,0xA3,0x6E,0xFF,0x26,0x30,0x97,0xF5,0x8B,0xDD,0x89,0x57,0xB6,0xAD,0x3D,0xB3, +0xAF,0x2B,0xC5,0xB7,0x76,0x02,0xF0,0xA5,0xD6,0x2B,0x9A,0x86,0x14,0x2A,0x72,0xF6, +0xE3,0x33,0x8C,0x5D,0x09,0x4B,0x13,0xDF,0xBB,0x8C,0x74,0x13,0x52,0x4B,0x02,0x03, +0x01,0x00,0x01,0xA3,0x82,0x02,0x10,0x30,0x82,0x02,0x0C,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03, +0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4E,0x0B,0xEF,0x1A,0xA4,0x40,0x5B,0xA5,0x17, +0x69,0x87,0x30,0xCA,0x34,0x68,0x43,0xD0,0x41,0xAE,0xF2,0x30,0x1F,0x06,0x03,0x55, +0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x4E,0x0B,0xEF,0x1A,0xA4,0x40,0x5B,0xA5, +0x17,0x69,0x87,0x30,0xCA,0x34,0x68,0x43,0xD0,0x41,0xAE,0xF2,0x30,0x82,0x01,0x5A, +0x06,0x03,0x55,0x1D,0x20,0x04,0x82,0x01,0x51,0x30,0x82,0x01,0x4D,0x30,0x82,0x01, +0x49,0x06,0x0B,0x2B,0x06,0x01,0x04,0x01,0x81,0xB5,0x37,0x01,0x01,0x01,0x30,0x82, +0x01,0x38,0x30,0x2E,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x22, +0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x73,0x74,0x61,0x72,0x74, +0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x70,0x6F,0x6C,0x69,0x63,0x79,0x2E,0x70, +0x64,0x66,0x30,0x34,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x28, +0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x73,0x74,0x61,0x72,0x74, +0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x69,0x6E,0x74,0x65,0x72,0x6D,0x65,0x64, +0x69,0x61,0x74,0x65,0x2E,0x70,0x64,0x66,0x30,0x81,0xCF,0x06,0x08,0x2B,0x06,0x01, +0x05,0x05,0x07,0x02,0x02,0x30,0x81,0xC2,0x30,0x27,0x16,0x20,0x53,0x74,0x61,0x72, +0x74,0x20,0x43,0x6F,0x6D,0x6D,0x65,0x72,0x63,0x69,0x61,0x6C,0x20,0x28,0x53,0x74, +0x61,0x72,0x74,0x43,0x6F,0x6D,0x29,0x20,0x4C,0x74,0x64,0x2E,0x30,0x03,0x02,0x01, +0x01,0x1A,0x81,0x96,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x20,0x4C,0x69,0x61,0x62, +0x69,0x6C,0x69,0x74,0x79,0x2C,0x20,0x72,0x65,0x61,0x64,0x20,0x74,0x68,0x65,0x20, +0x73,0x65,0x63,0x74,0x69,0x6F,0x6E,0x20,0x2A,0x4C,0x65,0x67,0x61,0x6C,0x20,0x4C, +0x69,0x6D,0x69,0x74,0x61,0x74,0x69,0x6F,0x6E,0x73,0x2A,0x20,0x6F,0x66,0x20,0x74, +0x68,0x65,0x20,0x53,0x74,0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x61,0x76,0x61,0x69,0x6C, +0x61,0x62,0x6C,0x65,0x20,0x61,0x74,0x20,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77, +0x77,0x77,0x2E,0x73,0x74,0x61,0x72,0x74,0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x2F, +0x70,0x6F,0x6C,0x69,0x63,0x79,0x2E,0x70,0x64,0x66,0x30,0x11,0x06,0x09,0x60,0x86, +0x48,0x01,0x86,0xF8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07,0x30,0x38,0x06, +0x09,0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x0D,0x04,0x2B,0x16,0x29,0x53,0x74, +0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x46,0x72,0x65,0x65,0x20,0x53,0x53,0x4C,0x20, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75, +0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x8E,0x8F,0xE7,0xDC,0x94, +0x79,0x7C,0xF1,0x85,0x7F,0x9F,0x49,0x6F,0x6B,0xCA,0x5D,0xFB,0x8C,0xFE,0x04,0xC5, +0xC1,0x62,0xD1,0x7D,0x42,0x8A,0xBC,0x53,0xB7,0x94,0x03,0x66,0x30,0x3F,0xB1,0xE7, +0x0A,0xA7,0x50,0x20,0x55,0x25,0x7F,0x76,0x7A,0x14,0x0D,0xEB,0x04,0x0E,0x40,0xE6, +0x3E,0xD8,0x88,0xAB,0x07,0x27,0x83,0xA9,0x75,0xA6,0x37,0x73,0xC7,0xFD,0x4B,0xD2, +0x4D,0xAD,0x17,0x40,0xC8,0x46,0xBE,0x3B,0x7F,0x51,0xFC,0xC3,0xB6,0x05,0x31,0xDC, +0xCD,0x85,0x22,0x4E,0x71,0xB7,0xF2,0x71,0x5E,0xB0,0x1A,0xC6,0xBA,0x93,0x8B,0x78, +0x92,0x4A,0x85,0xF8,0x78,0x0F,0x83,0xFE,0x2F,0xAD,0x2C,0xF7,0xE4,0xA4,0xBB,0x2D, +0xD0,0xE7,0x0D,0x3A,0xB8,0x3E,0xCE,0xF6,0x78,0xF6,0xAE,0x47,0x24,0xCA,0xA3,0x35, +0x36,0xCE,0xC7,0xC6,0x87,0x98,0xDA,0xEC,0xFB,0xE9,0xB2,0xCE,0x27,0x9B,0x88,0xC3, +0x04,0xA1,0xF6,0x0B,0x59,0x68,0xAF,0xC9,0xDB,0x10,0x0F,0x4D,0xF6,0x64,0x63,0x5C, +0xA5,0x12,0x6F,0x92,0xB2,0x93,0x94,0xC7,0x88,0x17,0x0E,0x93,0xB6,0x7E,0x62,0x8B, +0x90,0x7F,0xAB,0x4E,0x9F,0xFC,0xE3,0x75,0x14,0x4F,0x2A,0x32,0xDF,0x5B,0x0D,0xE0, +0xF5,0x7B,0x93,0x0D,0xAB,0xA1,0xCF,0x87,0xE1,0xA5,0x04,0x45,0xE8,0x3C,0x12,0xA5, +0x09,0xC5,0xB0,0xD1,0xB7,0x53,0xF3,0x60,0x14,0xBA,0x85,0x69,0x6A,0x21,0x7C,0x1F, +0x75,0x61,0x17,0x20,0x17,0x7B,0x6C,0x3B,0x41,0x29,0x5C,0xE1,0xAC,0x5A,0xD1,0xCD, +0x8C,0x9B,0xEB,0x60,0x1D,0x19,0xEC,0xF7,0xE5,0xB0,0xDA,0xF9,0x79,0x18,0xA5,0x45, +0x3F,0x49,0x43,0x57,0xD2,0xDD,0x24,0xD5,0x2C,0xA3,0xFD,0x91,0x8D,0x27,0xB5,0xE5, +0xEB,0x14,0x06,0x9A,0x4C,0x7B,0x21,0xBB,0x3A,0xAD,0x30,0x06,0x18,0xC0,0xD8,0xC1, +0x6B,0x2C,0x7F,0x59,0x5C,0x5D,0x91,0xB1,0x70,0x22,0x57,0xEB,0x8A,0x6B,0x48,0x4A, +0xD5,0x0F,0x29,0xEC,0xC6,0x40,0xC0,0x2F,0x88,0x4C,0x68,0x01,0x17,0x77,0xF4,0x24, +0x19,0x4F,0xBD,0xFA,0xE1,0xB2,0x20,0x21,0x4B,0xDD,0x1A,0xD8,0x29,0x7D,0xAA,0xB8, +0xDE,0x54,0xEC,0x21,0x55,0x80,0x6C,0x1E,0xF5,0x30,0xC8,0xA3,0x10,0xE5,0xB2,0xE6, +0x2A,0x14,0x31,0xC3,0x85,0x2D,0x8C,0x98,0xB1,0x86,0x5A,0x4F,0x89,0x59,0x2D,0xB9, +0xC7,0xF7,0x1C,0xC8,0x8A,0x7F,0xC0,0x9D,0x05,0x4A,0xE6,0x42,0x4F,0x62,0xA3,0x6D, +0x29,0xA4,0x1F,0x85,0xAB,0xDB,0xE5,0x81,0xC8,0xAD,0x2A,0x3D,0x4C,0x5D,0x5B,0x84, +0x26,0x71,0xC4,0x85,0x5E,0x71,0x24,0xCA,0xA5,0x1B,0x6C,0xD8,0x61,0xD3,0x1A,0xE0, +0x54,0xDB,0xCE,0xBA,0xA9,0x32,0xB5,0x22,0xF6,0x73,0x41,0x09,0x5D,0xB8,0x17,0x5D, +0x0E,0x0F,0x99,0x90,0xD6,0x47,0xDA,0x6F,0x0A,0x3A,0x62,0x28,0x14,0x67,0x82,0xD9, +0xF1,0xD0,0x80,0x59,0x9B,0xCB,0x31,0xD8,0x9B,0x0F,0x8C,0x77,0x4E,0xB5,0x68,0x8A, +0xF2,0x6C,0xF6,0x24,0x0E,0x2D,0x6C,0x70,0xC5,0x73,0xD1,0xDE,0x14,0xD0,0x71,0x8F, +0xB6,0xD3,0x7B,0x02,0xF6,0xE3,0xB8,0xD4,0x09,0x6E,0x6B,0x9E,0x75,0x84,0x39,0xE6, +0x7F,0x25,0xA5,0xF2,0x48,0x00,0xC0,0xA4,0x01,0xDA,0x3F, +}; + + +/* subject:/C=IL/O=StartCom Ltd./CN=StartCom Certification Authority G2 */ +/* issuer :/C=IL/O=StartCom Ltd./CN=StartCom Certification Authority G2 */ + + +const unsigned char StartCom_Certification_Authority_G2_certificate[1383]={ +0x30,0x82,0x05,0x63,0x30,0x82,0x03,0x4B,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x3B, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, +0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x4C,0x31,0x16, +0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x53,0x74,0x61,0x72,0x74,0x43,0x6F, +0x6D,0x20,0x4C,0x74,0x64,0x2E,0x31,0x2C,0x30,0x2A,0x06,0x03,0x55,0x04,0x03,0x13, +0x23,0x53,0x74,0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x43,0x65,0x72,0x74,0x69,0x66, +0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, +0x79,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x31,0x30,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x31,0x5A,0x17,0x0D,0x33,0x39,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x30,0x31,0x5A,0x30,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x49,0x4C,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x53,0x74, +0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x4C,0x74,0x64,0x2E,0x31,0x2C,0x30,0x2A,0x06, +0x03,0x55,0x04,0x03,0x13,0x23,0x53,0x74,0x61,0x72,0x74,0x43,0x6F,0x6D,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x47,0x32,0x30,0x82,0x02,0x22,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x02,0x0F, +0x00,0x30,0x82,0x02,0x0A,0x02,0x82,0x02,0x01,0x00,0xB6,0x89,0x36,0x5B,0x07,0xB7, +0x20,0x36,0xBD,0x82,0xBB,0xE1,0x16,0x20,0x03,0x95,0x7A,0xAF,0x0E,0xA3,0x55,0xC9, +0x25,0x99,0x4A,0xC5,0xD0,0x56,0x41,0x87,0x90,0x4D,0x21,0x60,0xA4,0x14,0x87,0x3B, +0xCD,0xFD,0xB2,0x3E,0xB4,0x67,0x03,0x6A,0xED,0xE1,0x0F,0x4B,0xC0,0x91,0x85,0x70, +0x45,0xE0,0x42,0x9E,0xDE,0x29,0x23,0xD4,0x01,0x0D,0xA0,0x10,0x79,0xB8,0xDB,0x03, +0xBD,0xF3,0xA9,0x2F,0xD1,0xC6,0xE0,0x0F,0xCB,0x9E,0x8A,0x14,0x0A,0xB8,0xBD,0xF6, +0x56,0x62,0xF1,0xC5,0x72,0xB6,0x32,0x25,0xD9,0xB2,0xF3,0xBD,0x65,0xC5,0x0D,0x2C, +0x6E,0xD5,0x92,0x6F,0x18,0x8B,0x00,0x41,0x14,0x82,0x6F,0x40,0x20,0x26,0x7A,0x28, +0x0F,0xF5,0x1E,0x7F,0x27,0xF7,0x94,0xB1,0x37,0x3D,0xB7,0xC7,0x91,0xF7,0xE2,0x01, +0xEC,0xFD,0x94,0x89,0xE1,0xCC,0x6E,0xD3,0x36,0xD6,0x0A,0x19,0x79,0xAE,0xD7,0x34, +0x82,0x65,0xFF,0x7C,0x42,0xBB,0xB6,0xDD,0x0B,0xA6,0x34,0xAF,0x4B,0x60,0xFE,0x7F, +0x43,0x49,0x06,0x8B,0x8C,0x43,0xB8,0x56,0xF2,0xD9,0x7F,0x21,0x43,0x17,0xEA,0xA7, +0x48,0x95,0x01,0x75,0x75,0xEA,0x2B,0xA5,0x43,0x95,0xEA,0x15,0x84,0x9D,0x08,0x8D, +0x26,0x6E,0x55,0x9B,0xAB,0xDC,0xD2,0x39,0xD2,0x31,0x1D,0x60,0xE2,0xAC,0xCC,0x56, +0x45,0x24,0xF5,0x1C,0x54,0xAB,0xEE,0x86,0xDD,0x96,0x32,0x85,0xF8,0x4C,0x4F,0xE8, +0x95,0x76,0xB6,0x05,0xDD,0x36,0x23,0x67,0xBC,0xFF,0x15,0xE2,0xCA,0x3B,0xE6,0xA6, +0xEC,0x3B,0xEC,0x26,0x11,0x34,0x48,0x8D,0xF6,0x80,0x2B,0x1A,0x23,0x02,0xEB,0x8A, +0x1C,0x3A,0x76,0x2A,0x7B,0x56,0x16,0x1C,0x72,0x2A,0xB3,0xAA,0xE3,0x60,0xA5,0x00, +0x9F,0x04,0x9B,0xE2,0x6F,0x1E,0x14,0x58,0x5B,0xA5,0x6C,0x8B,0x58,0x3C,0xC3,0xBA, +0x4E,0x3A,0x5C,0xF7,0xE1,0x96,0x2B,0x3E,0xEF,0x07,0xBC,0xA4,0xE5,0x5D,0xCC,0x4D, +0x9F,0x0D,0xE1,0xDC,0xAA,0xBB,0xE1,0x6E,0x1A,0xEC,0x8F,0xE1,0xB6,0x4C,0x4D,0x79, +0x72,0x5D,0x17,0x35,0x0B,0x1D,0xD7,0xC1,0x47,0xDA,0x96,0x24,0xE0,0xD0,0x72,0xA8, +0x5A,0x5F,0x66,0x2D,0x10,0xDC,0x2F,0x2A,0x13,0xAE,0x26,0xFE,0x0A,0x1C,0x19,0xCC, +0xD0,0x3E,0x0B,0x9C,0xC8,0x09,0x2E,0xF9,0x5B,0x96,0x7A,0x47,0x9C,0xE9,0x7A,0xF3, +0x05,0x50,0x74,0x95,0x73,0x9E,0x30,0x09,0xF3,0x97,0x82,0x5E,0xE6,0x8F,0x39,0x08, +0x1E,0x59,0xE5,0x35,0x14,0x42,0x13,0xFF,0x00,0x9C,0xF7,0xBE,0xAA,0x50,0xCF,0xE2, +0x51,0x48,0xD7,0xB8,0x6F,0xAF,0xF8,0x4E,0x7E,0x33,0x98,0x92,0x14,0x62,0x3A,0x75, +0x63,0xCF,0x7B,0xFA,0xDE,0x82,0x3B,0xA9,0xBB,0x39,0xE2,0xC4,0xBD,0x2C,0x00,0x0E, +0xC8,0x17,0xAC,0x13,0xEF,0x4D,0x25,0x8E,0xD8,0xB3,0x90,0x2F,0xA9,0xDA,0x29,0x7D, +0x1D,0xAF,0x74,0x3A,0xB2,0x27,0xC0,0xC1,0x1E,0x3E,0x75,0xA3,0x16,0xA9,0xAF,0x7A, +0x22,0x5D,0x9F,0x13,0x1A,0xCF,0xA7,0xA0,0xEB,0xE3,0x86,0x0A,0xD3,0xFD,0xE6,0x96, +0x95,0xD7,0x23,0xC8,0x37,0xDD,0xC4,0x7C,0xAA,0x36,0xAC,0x98,0x1A,0x12,0xB1,0xE0, +0x4E,0xE8,0xB1,0x3B,0xF5,0xD6,0x6F,0xF1,0x30,0xD7,0x02,0x03,0x01,0x00,0x01,0xA3, +0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4B, +0xC5,0xB4,0x40,0x6B,0xAD,0x1C,0xB3,0xA5,0x1C,0x65,0x6E,0x46,0x36,0x89,0x87,0x05, +0x0C,0x0E,0xB6,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B, +0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x73,0x57,0x3F,0x2C,0xD5,0x95,0x32,0x7E,0x37, +0xDB,0x96,0x92,0xEB,0x19,0x5E,0x7E,0x53,0xE7,0x41,0xEC,0x11,0xB6,0x47,0xEF,0xB5, +0xDE,0xED,0x74,0x5C,0xC5,0xF1,0x8E,0x49,0xE0,0xFC,0x6E,0x99,0x13,0xCD,0x9F,0x8A, +0xDA,0xCD,0x3A,0x0A,0xD8,0x3A,0x5A,0x09,0x3F,0x5F,0x34,0xD0,0x2F,0x03,0xD2,0x66, +0x1D,0x1A,0xBD,0x9C,0x90,0x37,0xC8,0x0C,0x8E,0x07,0x5A,0x94,0x45,0x46,0x2A,0xE6, +0xBE,0x7A,0xDA,0xA1,0xA9,0xA4,0x69,0x12,0x92,0xB0,0x7D,0x36,0xD4,0x44,0x87,0xD7, +0x51,0xF1,0x29,0x63,0xD6,0x75,0xCD,0x16,0xE4,0x27,0x89,0x1D,0xF8,0xC2,0x32,0x48, +0xFD,0xDB,0x99,0xD0,0x8F,0x5F,0x54,0x74,0xCC,0xAC,0x67,0x34,0x11,0x62,0xD9,0x0C, +0x0A,0x37,0x87,0xD1,0xA3,0x17,0x48,0x8E,0xD2,0x17,0x1D,0xF6,0xD7,0xFD,0xDB,0x65, +0xEB,0xFD,0xA8,0xD4,0xF5,0xD6,0x4F,0xA4,0x5B,0x75,0xE8,0xC5,0xD2,0x60,0xB2,0xDB, +0x09,0x7E,0x25,0x8B,0x7B,0xBA,0x52,0x92,0x9E,0x3E,0xE8,0xC5,0x77,0xA1,0x3C,0xE0, +0x4A,0x73,0x6B,0x61,0xCF,0x86,0xDC,0x43,0xFF,0xFF,0x21,0xFE,0x23,0x5D,0x24,0x4A, +0xF5,0xD3,0x6D,0x0F,0x62,0x04,0x05,0x57,0x82,0xDA,0x6E,0xA4,0x33,0x25,0x79,0x4B, +0x2E,0x54,0x19,0x8B,0xCC,0x2C,0x3D,0x30,0xE9,0xD1,0x06,0xFF,0xE8,0x32,0x46,0xBE, +0xB5,0x33,0x76,0x77,0xA8,0x01,0x5D,0x96,0xC1,0xC1,0xD5,0xBE,0xAE,0x25,0xC0,0xC9, +0x1E,0x0A,0x09,0x20,0x88,0xA1,0x0E,0xC9,0xF3,0x6F,0x4D,0x82,0x54,0x00,0x20,0xA7, +0xD2,0x8F,0xE4,0x39,0x54,0x17,0x2E,0x8D,0x1E,0xB8,0x1B,0xBB,0x1B,0xBD,0x9A,0x4E, +0x3B,0x10,0x34,0xDC,0x9C,0x88,0x53,0xEF,0xA2,0x31,0x5B,0x58,0x4F,0x91,0x62,0xC8, +0xC2,0x9A,0x9A,0xCD,0x15,0x5D,0x38,0xA9,0xD6,0xBE,0xF8,0x13,0xB5,0x9F,0x12,0x69, +0xF2,0x50,0x62,0xAC,0xFB,0x17,0x37,0xF4,0xEE,0xB8,0x75,0x67,0x60,0x10,0xFB,0x83, +0x50,0xF9,0x44,0xB5,0x75,0x9C,0x40,0x17,0xB2,0xFE,0xFD,0x79,0x5D,0x6E,0x58,0x58, +0x5F,0x30,0xFC,0x00,0xAE,0xAF,0x33,0xC1,0x0E,0x4E,0x6C,0xBA,0xA7,0xA6,0xA1,0x7F, +0x32,0xDB,0x38,0xE0,0xB1,0x72,0x17,0x0A,0x2B,0x91,0xEC,0x6A,0x63,0x26,0xED,0x89, +0xD4,0x78,0xCC,0x74,0x1E,0x05,0xF8,0x6B,0xFE,0x8C,0x6A,0x76,0x39,0x29,0xAE,0x65, +0x23,0x12,0x95,0x08,0x22,0x1C,0x97,0xCE,0x5B,0x06,0xEE,0x0C,0xE2,0xBB,0xBC,0x1F, +0x44,0x93,0xF6,0xD8,0x38,0x45,0x05,0x21,0xED,0xE4,0xAD,0xAB,0x12,0xB6,0x03,0xA4, +0x42,0x2E,0x2D,0xC4,0x09,0x3A,0x03,0x67,0x69,0x84,0x9A,0xE1,0x59,0x90,0x8A,0x28, +0x85,0xD5,0x5D,0x74,0xB1,0xD1,0x0E,0x20,0x58,0x9B,0x13,0xA5,0xB0,0x63,0xA6,0xED, +0x7B,0x47,0xFD,0x45,0x55,0x30,0xA4,0xEE,0x9A,0xD4,0xE6,0xE2,0x87,0xEF,0x98,0xC9, +0x32,0x82,0x11,0x29,0x22,0xBC,0x00,0x0A,0x31,0x5E,0x2D,0x0F,0xC0,0x8E,0xE9,0x6B, +0xB2,0x8F,0x2E,0x06,0xD8,0xD1,0x91,0xC7,0xC6,0x12,0xF4,0x4C,0xFD,0x30,0x17,0xC3, +0xC1,0xDA,0x38,0x5B,0xE3,0xA9,0xEA,0xE6,0xA1,0xBA,0x79,0xEF,0x73,0xD8,0xB6,0x53, +0x57,0x2D,0xF6,0xD0,0xE1,0xD7,0x48, +}; + + +/* subject:/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Class 2 CA/CN=TC TrustCenter Class 2 CA II */ +/* issuer :/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Class 2 CA/CN=TC TrustCenter Class 2 CA II */ + + +const unsigned char TC_TrustCenter_Class_2_CA_II_certificate[1198]={ +0x30,0x82,0x04,0xAA,0x30,0x82,0x03,0x92,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x2E, +0x6A,0x00,0x01,0x00,0x02,0x1F,0xD7,0x52,0x21,0x2C,0x11,0x5C,0x3B,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x76,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06, +0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65, +0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x22,0x30,0x20,0x06,0x03,0x55, +0x04,0x0B,0x13,0x19,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74, +0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x41,0x31,0x25,0x30, +0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74, +0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43, +0x41,0x20,0x49,0x49,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x31,0x31,0x32,0x31,0x34, +0x33,0x38,0x34,0x33,0x5A,0x17,0x0D,0x32,0x35,0x31,0x32,0x33,0x31,0x32,0x32,0x35, +0x39,0x35,0x39,0x5A,0x30,0x76,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43, +0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62, +0x48,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x13,0x19,0x54,0x43,0x20,0x54, +0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73, +0x20,0x32,0x20,0x43,0x41,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C, +0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43, +0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x43,0x41,0x20,0x49,0x49,0x30,0x82,0x01,0x22, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAB,0x80,0x87, +0x9B,0x8E,0xF0,0xC3,0x7C,0x87,0xD7,0xE8,0x24,0x82,0x11,0xB3,0x3C,0xDD,0x43,0x62, +0xEE,0xF8,0xC3,0x45,0xDA,0xE8,0xE1,0xA0,0x5F,0xD1,0x2A,0xB2,0xEA,0x93,0x68,0xDF, +0xB4,0xC8,0xD6,0x43,0xE9,0xC4,0x75,0x59,0x7F,0xFC,0xE1,0x1D,0xF8,0x31,0x70,0x23, +0x1B,0x88,0x9E,0x27,0xB9,0x7B,0xFD,0x3A,0xD2,0xC9,0xA9,0xE9,0x14,0x2F,0x90,0xBE, +0x03,0x52,0xC1,0x49,0xCD,0xF6,0xFD,0xE4,0x08,0x66,0x0B,0x57,0x8A,0xA2,0x42,0xA0, +0xB8,0xD5,0x7F,0x69,0x5C,0x90,0x32,0xB2,0x97,0x0D,0xCA,0x4A,0xDC,0x46,0x3E,0x02, +0x55,0x89,0x53,0xE3,0x1A,0x5A,0xCB,0x36,0xC6,0x07,0x56,0xF7,0x8C,0xCF,0x11,0xF4, +0x4C,0xBB,0x30,0x70,0x04,0x95,0xA5,0xF6,0x39,0x8C,0xFD,0x73,0x81,0x08,0x7D,0x89, +0x5E,0x32,0x1E,0x22,0xA9,0x22,0x45,0x4B,0xB0,0x66,0x2E,0x30,0xCC,0x9F,0x65,0xFD, +0xFC,0xCB,0x81,0xA9,0xF1,0xE0,0x3B,0xAF,0xA3,0x86,0xD1,0x89,0xEA,0xC4,0x45,0x79, +0x50,0x5D,0xAE,0xE9,0x21,0x74,0x92,0x4D,0x8B,0x59,0x82,0x8F,0x94,0xE3,0xE9,0x4A, +0xF1,0xE7,0x49,0xB0,0x14,0xE3,0xF5,0x62,0xCB,0xD5,0x72,0xBD,0x1F,0xB9,0xD2,0x9F, +0xA0,0xCD,0xA8,0xFA,0x01,0xC8,0xD9,0x0D,0xDF,0xDA,0xFC,0x47,0x9D,0xB3,0xC8,0x54, +0xDF,0x49,0x4A,0xF1,0x21,0xA9,0xFE,0x18,0x4E,0xEE,0x48,0xD4,0x19,0xBB,0xEF,0x7D, +0xE4,0xE2,0x9D,0xCB,0x5B,0xB6,0x6E,0xFF,0xE3,0xCD,0x5A,0xE7,0x74,0x82,0x05,0xBA, +0x80,0x25,0x38,0xCB,0xE4,0x69,0x9E,0xAF,0x41,0xAA,0x1A,0x84,0xF5,0x02,0x03,0x01, +0x00,0x01,0xA3,0x82,0x01,0x34,0x30,0x82,0x01,0x30,0x30,0x0F,0x06,0x03,0x55,0x1D, +0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55, +0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55, +0x1D,0x0E,0x04,0x16,0x04,0x14,0xE3,0xAB,0x54,0x4C,0x80,0xA1,0xDB,0x56,0x43,0xB7, +0x91,0x4A,0xCB,0xF3,0x82,0x7A,0x13,0x5C,0x08,0xAB,0x30,0x81,0xED,0x06,0x03,0x55, +0x1D,0x1F,0x04,0x81,0xE5,0x30,0x81,0xE2,0x30,0x81,0xDF,0xA0,0x81,0xDC,0xA0,0x81, +0xD9,0x86,0x35,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72, +0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65,0x72,0x2E,0x64,0x65,0x2F,0x63,0x72,0x6C, +0x2F,0x76,0x32,0x2F,0x74,0x63,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x32,0x5F,0x63, +0x61,0x5F,0x49,0x49,0x2E,0x63,0x72,0x6C,0x86,0x81,0x9F,0x6C,0x64,0x61,0x70,0x3A, +0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65, +0x72,0x2E,0x64,0x65,0x2F,0x43,0x4E,0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75, +0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x25,0x32,0x30,0x43,0x6C,0x61,0x73,0x73, +0x25,0x32,0x30,0x32,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x49,0x49,0x2C,0x4F, +0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65, +0x72,0x25,0x32,0x30,0x47,0x6D,0x62,0x48,0x2C,0x4F,0x55,0x3D,0x72,0x6F,0x6F,0x74, +0x63,0x65,0x72,0x74,0x73,0x2C,0x44,0x43,0x3D,0x74,0x72,0x75,0x73,0x74,0x63,0x65, +0x6E,0x74,0x65,0x72,0x2C,0x44,0x43,0x3D,0x64,0x65,0x3F,0x63,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x52,0x65,0x76,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E, +0x4C,0x69,0x73,0x74,0x3F,0x62,0x61,0x73,0x65,0x3F,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x8C,0xD7, +0xDF,0x7E,0xEE,0x1B,0x80,0x10,0xB3,0x83,0xF5,0xDB,0x11,0xEA,0x6B,0x4B,0xA8,0x92, +0x18,0xD9,0xF7,0x07,0x39,0xF5,0x2C,0xBE,0x06,0x75,0x7A,0x68,0x53,0x15,0x1C,0xEA, +0x4A,0xED,0x5E,0xFC,0x23,0xB2,0x13,0xA0,0xD3,0x09,0xFF,0xF6,0xF6,0x2E,0x6B,0x41, +0x71,0x79,0xCD,0xE2,0x6D,0xFD,0xAE,0x59,0x6B,0x85,0x1D,0xB8,0x4E,0x22,0x9A,0xED, +0x66,0x39,0x6E,0x4B,0x94,0xE6,0x55,0xFC,0x0B,0x1B,0x8B,0x77,0xC1,0x53,0x13,0x66, +0x89,0xD9,0x28,0xD6,0x8B,0xF3,0x45,0x4A,0x63,0xB7,0xFD,0x7B,0x0B,0x61,0x5D,0xB8, +0x6D,0xBE,0xC3,0xDC,0x5B,0x79,0xD2,0xED,0x86,0xE5,0xA2,0x4D,0xBE,0x5E,0x74,0x7C, +0x6A,0xED,0x16,0x38,0x1F,0x7F,0x58,0x81,0x5A,0x1A,0xEB,0x32,0x88,0x2D,0xB2,0xF3, +0x39,0x77,0x80,0xAF,0x5E,0xB6,0x61,0x75,0x29,0xDB,0x23,0x4D,0x88,0xCA,0x50,0x28, +0xCB,0x85,0xD2,0xD3,0x10,0xA2,0x59,0x6E,0xD3,0x93,0x54,0x00,0x7A,0xA2,0x46,0x95, +0x86,0x05,0x9C,0xA9,0x19,0x98,0xE5,0x31,0x72,0x0C,0x00,0xE2,0x67,0xD9,0x40,0xE0, +0x24,0x33,0x7B,0x6F,0x2C,0xB9,0x5C,0xAB,0x65,0x9D,0x2C,0xAC,0x76,0xEA,0x35,0x99, +0xF5,0x97,0xB9,0x0F,0x24,0xEC,0xC7,0x76,0x21,0x28,0x65,0xAE,0x57,0xE8,0x07,0x88, +0x75,0x4A,0x56,0xA0,0xD2,0x05,0x3A,0xA4,0xE6,0x8D,0x92,0x88,0x2C,0xF3,0xF2,0xE1, +0xC1,0xC6,0x61,0xDB,0x41,0xC5,0xC7,0x9B,0xF7,0x0E,0x1A,0x51,0x45,0xC2,0x61,0x6B, +0xDC,0x64,0x27,0x17,0x8C,0x5A,0xB7,0xDA,0x74,0x28,0xCD,0x97,0xE4,0xBD, +}; + + +/* subject:/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Class 3 CA/CN=TC TrustCenter Class 3 CA II */ +/* issuer :/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Class 3 CA/CN=TC TrustCenter Class 3 CA II */ + + +const unsigned char TC_TrustCenter_Class_3_CA_II_certificate[1198]={ +0x30,0x82,0x04,0xAA,0x30,0x82,0x03,0x92,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x4A, +0x47,0x00,0x01,0x00,0x02,0xE5,0xA0,0x5D,0xD6,0x3F,0x00,0x51,0xBF,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x76,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06, +0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65, +0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x22,0x30,0x20,0x06,0x03,0x55, +0x04,0x0B,0x13,0x19,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74, +0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x43,0x41,0x31,0x25,0x30, +0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74, +0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x43, +0x41,0x20,0x49,0x49,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x31,0x31,0x32,0x31,0x34, +0x34,0x31,0x35,0x37,0x5A,0x17,0x0D,0x32,0x35,0x31,0x32,0x33,0x31,0x32,0x32,0x35, +0x39,0x35,0x39,0x5A,0x30,0x76,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43, +0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62, +0x48,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x13,0x19,0x54,0x43,0x20,0x54, +0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73, +0x20,0x33,0x20,0x43,0x41,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C, +0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43, +0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x43,0x41,0x20,0x49,0x49,0x30,0x82,0x01,0x22, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xB4,0xE0,0xBB, +0x51,0xBB,0x39,0x5C,0x8B,0x04,0xC5,0x4C,0x79,0x1C,0x23,0x86,0x31,0x10,0x63,0x43, +0x55,0x27,0x3F,0xC6,0x45,0xC7,0xA4,0x3D,0xEC,0x09,0x0D,0x1A,0x1E,0x20,0xC2,0x56, +0x1E,0xDE,0x1B,0x37,0x07,0x30,0x22,0x2F,0x6F,0xF1,0x06,0xF1,0xAB,0xAD,0xD6,0xC8, +0xAB,0x61,0xA3,0x2F,0x43,0xC4,0xB0,0xB2,0x2D,0xFC,0xC3,0x96,0x69,0x7B,0x7E,0x8A, +0xE4,0xCC,0xC0,0x39,0x12,0x90,0x42,0x60,0xC9,0xCC,0x35,0x68,0xEE,0xDA,0x5F,0x90, +0x56,0x5F,0xCD,0x1C,0x4D,0x5B,0x58,0x49,0xEB,0x0E,0x01,0x4F,0x64,0xFA,0x2C,0x3C, +0x89,0x58,0xD8,0x2F,0x2E,0xE2,0xB0,0x68,0xE9,0x22,0x3B,0x75,0x89,0xD6,0x44,0x1A, +0x65,0xF2,0x1B,0x97,0x26,0x1D,0x28,0x6D,0xAC,0xE8,0xBD,0x59,0x1D,0x2B,0x24,0xF6, +0xD6,0x84,0x03,0x66,0x88,0x24,0x00,0x78,0x60,0xF1,0xF8,0xAB,0xFE,0x02,0xB2,0x6B, +0xFB,0x22,0xFB,0x35,0xE6,0x16,0xD1,0xAD,0xF6,0x2E,0x12,0xE4,0xFA,0x35,0x6A,0xE5, +0x19,0xB9,0x5D,0xDB,0x3B,0x1E,0x1A,0xFB,0xD3,0xFF,0x15,0x14,0x08,0xD8,0x09,0x6A, +0xBA,0x45,0x9D,0x14,0x79,0x60,0x7D,0xAF,0x40,0x8A,0x07,0x73,0xB3,0x93,0x96,0xD3, +0x74,0x34,0x8D,0x3A,0x37,0x29,0xDE,0x5C,0xEC,0xF5,0xEE,0x2E,0x31,0xC2,0x20,0xDC, +0xBE,0xF1,0x4F,0x7F,0x23,0x52,0xD9,0x5B,0xE2,0x64,0xD9,0x9C,0xAA,0x07,0x08,0xB5, +0x45,0xBD,0xD1,0xD0,0x31,0xC1,0xAB,0x54,0x9F,0xA9,0xD2,0xC3,0x62,0x60,0x03,0xF1, +0xBB,0x39,0x4A,0x92,0x4A,0x3D,0x0A,0xB9,0x9D,0xC5,0xA0,0xFE,0x37,0x02,0x03,0x01, +0x00,0x01,0xA3,0x82,0x01,0x34,0x30,0x82,0x01,0x30,0x30,0x0F,0x06,0x03,0x55,0x1D, +0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55, +0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55, +0x1D,0x0E,0x04,0x16,0x04,0x14,0xD4,0xA2,0xFC,0x9F,0xB3,0xC3,0xD8,0x03,0xD3,0x57, +0x5C,0x07,0xA4,0xD0,0x24,0xA7,0xC0,0xF2,0x00,0xD4,0x30,0x81,0xED,0x06,0x03,0x55, +0x1D,0x1F,0x04,0x81,0xE5,0x30,0x81,0xE2,0x30,0x81,0xDF,0xA0,0x81,0xDC,0xA0,0x81, +0xD9,0x86,0x35,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72, +0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65,0x72,0x2E,0x64,0x65,0x2F,0x63,0x72,0x6C, +0x2F,0x76,0x32,0x2F,0x74,0x63,0x5F,0x63,0x6C,0x61,0x73,0x73,0x5F,0x33,0x5F,0x63, +0x61,0x5F,0x49,0x49,0x2E,0x63,0x72,0x6C,0x86,0x81,0x9F,0x6C,0x64,0x61,0x70,0x3A, +0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65, +0x72,0x2E,0x64,0x65,0x2F,0x43,0x4E,0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75, +0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x25,0x32,0x30,0x43,0x6C,0x61,0x73,0x73, +0x25,0x32,0x30,0x33,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x49,0x49,0x2C,0x4F, +0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65, +0x72,0x25,0x32,0x30,0x47,0x6D,0x62,0x48,0x2C,0x4F,0x55,0x3D,0x72,0x6F,0x6F,0x74, +0x63,0x65,0x72,0x74,0x73,0x2C,0x44,0x43,0x3D,0x74,0x72,0x75,0x73,0x74,0x63,0x65, +0x6E,0x74,0x65,0x72,0x2C,0x44,0x43,0x3D,0x64,0x65,0x3F,0x63,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x52,0x65,0x76,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E, +0x4C,0x69,0x73,0x74,0x3F,0x62,0x61,0x73,0x65,0x3F,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x36,0x60, +0xE4,0x70,0xF7,0x06,0x20,0x43,0xD9,0x23,0x1A,0x42,0xF2,0xF8,0xA3,0xB2,0xB9,0x4D, +0x8A,0xB4,0xF3,0xC2,0x9A,0x55,0x31,0x7C,0xC4,0x3B,0x67,0x9A,0xB4,0xDF,0x4D,0x0E, +0x8A,0x93,0x4A,0x17,0x8B,0x1B,0x8D,0xCA,0x89,0xE1,0xCF,0x3A,0x1E,0xAC,0x1D,0xF1, +0x9C,0x32,0xB4,0x8E,0x59,0x76,0xA2,0x41,0x85,0x25,0x37,0xA0,0x13,0xD0,0xF5,0x7C, +0x4E,0xD5,0xEA,0x96,0xE2,0x6E,0x72,0xC1,0xBB,0x2A,0xFE,0x6C,0x6E,0xF8,0x91,0x98, +0x46,0xFC,0xC9,0x1B,0x57,0x5B,0xEA,0xC8,0x1A,0x3B,0x3F,0xB0,0x51,0x98,0x3C,0x07, +0xDA,0x2C,0x59,0x01,0xDA,0x8B,0x44,0xE8,0xE1,0x74,0xFD,0xA7,0x68,0xDD,0x54,0xBA, +0x83,0x46,0xEC,0xC8,0x46,0xB5,0xF8,0xAF,0x97,0xC0,0x3B,0x09,0x1C,0x8F,0xCE,0x72, +0x96,0x3D,0x33,0x56,0x70,0xBC,0x96,0xCB,0xD8,0xD5,0x7D,0x20,0x9A,0x83,0x9F,0x1A, +0xDC,0x39,0xF1,0xC5,0x72,0xA3,0x11,0x03,0xFD,0x3B,0x42,0x52,0x29,0xDB,0xE8,0x01, +0xF7,0x9B,0x5E,0x8C,0xD6,0x8D,0x86,0x4E,0x19,0xFA,0xBC,0x1C,0xBE,0xC5,0x21,0xA5, +0x87,0x9E,0x78,0x2E,0x36,0xDB,0x09,0x71,0xA3,0x72,0x34,0xF8,0x6C,0xE3,0x06,0x09, +0xF2,0x5E,0x56,0xA5,0xD3,0xDD,0x98,0xFA,0xD4,0xE6,0x06,0xF4,0xF0,0xB6,0x20,0x63, +0x4B,0xEA,0x29,0xBD,0xAA,0x82,0x66,0x1E,0xFB,0x81,0xAA,0xA7,0x37,0xAD,0x13,0x18, +0xE6,0x92,0xC3,0x81,0xC1,0x33,0xBB,0x88,0x1E,0xA1,0xE7,0xE2,0xB4,0xBD,0x31,0x6C, +0x0E,0x51,0x3D,0x6F,0xFB,0x96,0x56,0x80,0xE2,0x36,0x17,0xD1,0xDC,0xE4, +}; + + +/* subject:/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Universal CA/CN=TC TrustCenter Universal CA I */ +/* issuer :/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Universal CA/CN=TC TrustCenter Universal CA I */ + + +const unsigned char TC_TrustCenter_Universal_CA_I_certificate[993]={ +0x30,0x82,0x03,0xDD,0x30,0x82,0x02,0xC5,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x1D, +0xA2,0x00,0x01,0x00,0x02,0xEC,0xB7,0x60,0x80,0x78,0x8D,0xB6,0x06,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x79,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06, +0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65, +0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55, +0x04,0x0B,0x13,0x1B,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74, +0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31, +0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x03,0x13,0x1D,0x54,0x43,0x20,0x54,0x72,0x75, +0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73, +0x61,0x6C,0x20,0x43,0x41,0x20,0x49,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x33,0x32, +0x32,0x31,0x35,0x35,0x34,0x32,0x38,0x5A,0x17,0x0D,0x32,0x35,0x31,0x32,0x33,0x31, +0x32,0x32,0x35,0x39,0x35,0x39,0x5A,0x30,0x79,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13, +0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20, +0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x54, +0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E, +0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31,0x26,0x30,0x24,0x06,0x03, +0x55,0x04,0x03,0x13,0x1D,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E, +0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41, +0x20,0x49,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xA4,0x77,0x23,0x96,0x44,0xAF,0x90,0xF4,0x31,0xA7,0x10,0xF4,0x26, +0x87,0x9C,0xF3,0x38,0xD9,0x0F,0x5E,0xDE,0xCF,0x41,0xE8,0x31,0xAD,0xC6,0x74,0x91, +0x24,0x96,0x78,0x1E,0x09,0xA0,0x9B,0x9A,0x95,0x4A,0x4A,0xF5,0x62,0x7C,0x02,0xA8, +0xCA,0xAC,0xFB,0x5A,0x04,0x76,0x39,0xDE,0x5F,0xF1,0xF9,0xB3,0xBF,0xF3,0x03,0x58, +0x55,0xD2,0xAA,0xB7,0xE3,0x04,0x22,0xD1,0xF8,0x94,0xDA,0x22,0x08,0x00,0x8D,0xD3, +0x7C,0x26,0x5D,0xCC,0x77,0x79,0xE7,0x2C,0x78,0x39,0xA8,0x26,0x73,0x0E,0xA2,0x5D, +0x25,0x69,0x85,0x4F,0x55,0x0E,0x9A,0xEF,0xC6,0xB9,0x44,0xE1,0x57,0x3D,0xDF,0x1F, +0x54,0x22,0xE5,0x6F,0x65,0xAA,0x33,0x84,0x3A,0xF3,0xCE,0x7A,0xBE,0x55,0x97,0xAE, +0x8D,0x12,0x0F,0x14,0x33,0xE2,0x50,0x70,0xC3,0x49,0x87,0x13,0xBC,0x51,0xDE,0xD7, +0x98,0x12,0x5A,0xEF,0x3A,0x83,0x33,0x92,0x06,0x75,0x8B,0x92,0x7C,0x12,0x68,0x7B, +0x70,0x6A,0x0F,0xB5,0x9B,0xB6,0x77,0x5B,0x48,0x59,0x9D,0xE4,0xEF,0x5A,0xAD,0xF3, +0xC1,0x9E,0xD4,0xD7,0x45,0x4E,0xCA,0x56,0x34,0x21,0xBC,0x3E,0x17,0x5B,0x6F,0x77, +0x0C,0x48,0x01,0x43,0x29,0xB0,0xDD,0x3F,0x96,0x6E,0xE6,0x95,0xAA,0x0C,0xC0,0x20, +0xB6,0xFD,0x3E,0x36,0x27,0x9C,0xE3,0x5C,0xCF,0x4E,0x81,0xDC,0x19,0xBB,0x91,0x90, +0x7D,0xEC,0xE6,0x97,0x04,0x1E,0x93,0xCC,0x22,0x49,0xD7,0x97,0x86,0xB6,0x13,0x0A, +0x3C,0x43,0x23,0x77,0x7E,0xF0,0xDC,0xE6,0xCD,0x24,0x1F,0x3B,0x83,0x9B,0x34,0x3A, +0x83,0x34,0xE3,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x1F,0x06,0x03, +0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x92,0xA4,0x75,0x2C,0xA4,0x9E,0xBE, +0x81,0x44,0xEB,0x79,0xFC,0x8A,0xC5,0x95,0xA5,0xEB,0x10,0x75,0x73,0x30,0x0F,0x06, +0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E, +0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x1D, +0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x92,0xA4,0x75,0x2C,0xA4,0x9E,0xBE, +0x81,0x44,0xEB,0x79,0xFC,0x8A,0xC5,0x95,0xA5,0xEB,0x10,0x75,0x73,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01, +0x00,0x28,0xD2,0xE0,0x86,0xD5,0xE6,0xF8,0x7B,0xF0,0x97,0xDC,0x22,0x6B,0x3B,0x95, +0x14,0x56,0x0F,0x11,0x30,0xA5,0x9A,0x4F,0x3A,0xB0,0x3A,0xE0,0x06,0xCB,0x65,0xF5, +0xED,0xC6,0x97,0x27,0xFE,0x25,0xF2,0x57,0xE6,0x5E,0x95,0x8C,0x3E,0x64,0x60,0x15, +0x5A,0x7F,0x2F,0x0D,0x01,0xC5,0xB1,0x60,0xFD,0x45,0x35,0xCF,0xF0,0xB2,0xBF,0x06, +0xD9,0xEF,0x5A,0xBE,0xB3,0x62,0x21,0xB4,0xD7,0xAB,0x35,0x7C,0x53,0x3E,0xA6,0x27, +0xF1,0xA1,0x2D,0xDA,0x1A,0x23,0x9D,0xCC,0xDD,0xEC,0x3C,0x2D,0x9E,0x27,0x34,0x5D, +0x0F,0xC2,0x36,0x79,0xBC,0xC9,0x4A,0x62,0x2D,0xED,0x6B,0xD9,0x7D,0x41,0x43,0x7C, +0xB6,0xAA,0xCA,0xED,0x61,0xB1,0x37,0x82,0x15,0x09,0x1A,0x8A,0x16,0x30,0xD8,0xEC, +0xC9,0xD6,0x47,0x72,0x78,0x4B,0x10,0x46,0x14,0x8E,0x5F,0x0E,0xAF,0xEC,0xC7,0x2F, +0xAB,0x10,0xD7,0xB6,0xF1,0x6E,0xEC,0x86,0xB2,0xC2,0xE8,0x0D,0x92,0x73,0xDC,0xA2, +0xF4,0x0F,0x3A,0xBF,0x61,0x23,0x10,0x89,0x9C,0x48,0x40,0x6E,0x70,0x00,0xB3,0xD3, +0xBA,0x37,0x44,0x58,0x11,0x7A,0x02,0x6A,0x88,0xF0,0x37,0x34,0xF0,0x19,0xE9,0xAC, +0xD4,0x65,0x73,0xF6,0x69,0x8C,0x64,0x94,0x3A,0x79,0x85,0x29,0xB0,0x16,0x2B,0x0C, +0x82,0x3F,0x06,0x9C,0xC7,0xFD,0x10,0x2B,0x9E,0x0F,0x2C,0xB6,0x9E,0xE3,0x15,0xBF, +0xD9,0x36,0x1C,0xBA,0x25,0x1A,0x52,0x3D,0x1A,0xEC,0x22,0x0C,0x1C,0xE0,0xA4,0xA2, +0x3D,0xF0,0xE8,0x39,0xCF,0x81,0xC0,0x7B,0xED,0x5D,0x1F,0x6F,0xC5,0xD0,0x0B,0xD7, +0x98, +}; + + +/* subject:/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Universal CA/CN=TC TrustCenter Universal CA III */ +/* issuer :/C=DE/O=TC TrustCenter GmbH/OU=TC TrustCenter Universal CA/CN=TC TrustCenter Universal CA III */ + + +const unsigned char TC_TrustCenter_Universal_CA_III_certificate[997]={ +0x30,0x82,0x03,0xE1,0x30,0x82,0x02,0xC9,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x63, +0x25,0x00,0x01,0x00,0x02,0x14,0x8D,0x33,0x15,0x02,0xE4,0x6C,0xF4,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x7B,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06, +0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65, +0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55, +0x04,0x0B,0x13,0x1B,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74, +0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31, +0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x03,0x13,0x1F,0x54,0x43,0x20,0x54,0x72,0x75, +0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73, +0x61,0x6C,0x20,0x43,0x41,0x20,0x49,0x49,0x49,0x30,0x1E,0x17,0x0D,0x30,0x39,0x30, +0x39,0x30,0x39,0x30,0x38,0x31,0x35,0x32,0x37,0x5A,0x17,0x0D,0x32,0x39,0x31,0x32, +0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x7B,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04, +0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65, +0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13, +0x1B,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20, +0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31,0x28,0x30,0x26, +0x06,0x03,0x55,0x04,0x03,0x13,0x1F,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43, +0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20, +0x43,0x41,0x20,0x49,0x49,0x49,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, +0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC2,0xDA,0x9C,0x62,0xB0,0xB9,0x71,0x12,0xB0, +0x0B,0xC8,0x1A,0x57,0xB2,0xAE,0x83,0x14,0x99,0xB3,0x34,0x4B,0x9B,0x90,0xA2,0xC5, +0xE7,0xE7,0x2F,0x02,0xA0,0x4D,0x2D,0xA4,0xFA,0x85,0xDA,0x9B,0x25,0x85,0x2D,0x40, +0x28,0x20,0x6D,0xEA,0xE0,0xBD,0xB1,0x48,0x83,0x22,0x29,0x44,0x9F,0x4E,0x83,0xEE, +0x35,0x51,0x13,0x73,0x74,0xD5,0xBC,0xF2,0x30,0x66,0x94,0x53,0xC0,0x40,0x36,0x2F, +0x0C,0x84,0x65,0xCE,0x0F,0x6E,0xC2,0x58,0x93,0xE8,0x2C,0x0B,0x3A,0xE9,0xC1,0x8E, +0xFB,0xF2,0x6B,0xCA,0x3C,0xE2,0x9C,0x4E,0x8E,0xE4,0xF9,0x7D,0xD3,0x27,0x9F,0x1B, +0xD5,0x67,0x78,0x87,0x2D,0x7F,0x0B,0x47,0xB3,0xC7,0xE8,0xC9,0x48,0x7C,0xAF,0x2F, +0xCC,0x0A,0xD9,0x41,0xEF,0x9F,0xFE,0x9A,0xE1,0xB2,0xAE,0xF9,0x53,0xB5,0xE5,0xE9, +0x46,0x9F,0x60,0xE3,0xDF,0x8D,0xD3,0x7F,0xFB,0x96,0x7E,0xB3,0xB5,0x72,0xF8,0x4B, +0xAD,0x08,0x79,0xCD,0x69,0x89,0x40,0x27,0xF5,0x2A,0xC1,0xAD,0x43,0xEC,0xA4,0x53, +0xC8,0x61,0xB6,0xF7,0xD2,0x79,0x2A,0x67,0x18,0x76,0x48,0x6D,0x5B,0x25,0x01,0xD1, +0x26,0xC5,0xB7,0x57,0x69,0x23,0x15,0x5B,0x61,0x8A,0xAD,0xF0,0x1B,0x2D,0xD9,0xAF, +0x5C,0xF1,0x26,0x90,0x69,0xA9,0xD5,0x0C,0x40,0xF5,0x33,0x80,0x43,0x8F,0x9C,0xA3, +0x76,0x2A,0x45,0xB4,0xAF,0xBF,0x7F,0x3E,0x87,0x3F,0x76,0xC5,0xCD,0x2A,0xDE,0x20, +0xC5,0x16,0x58,0xCB,0xF9,0x1B,0xF5,0x0F,0xCB,0x0D,0x11,0x52,0x64,0xB8,0xD2,0x76, +0x62,0x77,0x83,0xF1,0x58,0x9F,0xFF,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61, +0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x56,0xE7,0xE1, +0x5B,0x25,0x43,0x80,0xE0,0xF6,0x8C,0xE1,0x71,0xBC,0x8E,0xE5,0x80,0x2F,0xC4,0x48, +0xE2,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01, +0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02, +0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x56,0xE7,0xE1, +0x5B,0x25,0x43,0x80,0xE0,0xF6,0x8C,0xE1,0x71,0xBC,0x8E,0xE5,0x80,0x2F,0xC4,0x48, +0xE2,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00, +0x03,0x82,0x01,0x01,0x00,0x83,0xC7,0xAF,0xEA,0x7F,0x4D,0x0A,0x3C,0x39,0xB1,0x68, +0xBE,0x7B,0x6D,0x89,0x2E,0xE9,0xB3,0x09,0xE7,0x18,0x57,0x8D,0x85,0x9A,0x17,0xF3, +0x76,0x42,0x50,0x13,0x0F,0xC7,0x90,0x6F,0x33,0xAD,0xC5,0x49,0x60,0x2B,0x6C,0x49, +0x58,0x19,0xD4,0xE2,0xBE,0xB7,0xBF,0xAB,0x49,0xBC,0x94,0xC8,0xAB,0xBE,0x28,0x6C, +0x16,0x68,0xE0,0xC8,0x97,0x46,0x20,0xA0,0x68,0x67,0x60,0x88,0x39,0x20,0x51,0xD8, +0x68,0x01,0x11,0xCE,0xA7,0xF6,0x11,0x07,0xF6,0xEC,0xEC,0xAC,0x1A,0x1F,0xB2,0x66, +0x6E,0x56,0x67,0x60,0x7A,0x74,0x5E,0xC0,0x6D,0x97,0x36,0xAE,0xB5,0x0D,0x5D,0x66, +0x73,0xC0,0x25,0x32,0x45,0xD8,0x4A,0x06,0x07,0x8F,0xC4,0xB7,0x07,0xB1,0x4D,0x06, +0x0D,0xE1,0xA5,0xEB,0xF4,0x75,0xCA,0xBA,0x9C,0xD0,0xBD,0xB3,0xD3,0x32,0x24,0x4C, +0xEE,0x7E,0xE2,0x76,0x04,0x4B,0x49,0x53,0xD8,0xF2,0xE9,0x54,0x33,0xFC,0xE5,0x71, +0x1F,0x3D,0x14,0x5C,0x96,0x4B,0xF1,0x3A,0xF2,0x00,0xBB,0x6C,0xB4,0xFA,0x96,0x55, +0x08,0x88,0x09,0xC1,0xCC,0x91,0x19,0x29,0xB0,0x20,0x2D,0xFF,0xCB,0x38,0xA4,0x40, +0xE1,0x17,0xBE,0x79,0x61,0x80,0xFF,0x07,0x03,0x86,0x4C,0x4E,0x7B,0x06,0x9F,0x11, +0x86,0x8D,0x89,0xEE,0x27,0xC4,0xDB,0xE2,0xBC,0x19,0x8E,0x0B,0xC3,0xC3,0x13,0xC7, +0x2D,0x03,0x63,0x3B,0xD3,0xE8,0xE4,0xA2,0x2A,0xC2,0x82,0x08,0x94,0x16,0x54,0xF0, +0xEF,0x1F,0x27,0x90,0x25,0xB8,0x0D,0x0E,0x28,0x1B,0x47,0x77,0x47,0xBD,0x1C,0xA8, +0x25,0xF1,0x94,0xB4,0x66, +}; + + +/* subject:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com */ +/* issuer :/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com */ + + +const unsigned char Thawte_Premium_Server_CA_certificate[811]={ +0x30,0x82,0x03,0x27,0x30,0x82,0x02,0x90,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30, +0x81,0xCE,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x5A,0x41,0x31, +0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x08,0x13,0x0C,0x57,0x65,0x73,0x74,0x65,0x72, +0x6E,0x20,0x43,0x61,0x70,0x65,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x13, +0x09,0x43,0x61,0x70,0x65,0x20,0x54,0x6F,0x77,0x6E,0x31,0x1D,0x30,0x1B,0x06,0x03, +0x55,0x04,0x0A,0x13,0x14,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x43,0x6F,0x6E,0x73, +0x75,0x6C,0x74,0x69,0x6E,0x67,0x20,0x63,0x63,0x31,0x28,0x30,0x26,0x06,0x03,0x55, +0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, +0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73, +0x69,0x6F,0x6E,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x54,0x68, +0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x53,0x65,0x72, +0x76,0x65,0x72,0x20,0x43,0x41,0x31,0x28,0x30,0x26,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x09,0x01,0x16,0x19,0x70,0x72,0x65,0x6D,0x69,0x75,0x6D,0x2D,0x73, +0x65,0x72,0x76,0x65,0x72,0x40,0x74,0x68,0x61,0x77,0x74,0x65,0x2E,0x63,0x6F,0x6D, +0x30,0x1E,0x17,0x0D,0x39,0x36,0x30,0x38,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30, +0x5A,0x17,0x0D,0x32,0x30,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A, +0x30,0x81,0xCE,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x5A,0x41, +0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x08,0x13,0x0C,0x57,0x65,0x73,0x74,0x65, +0x72,0x6E,0x20,0x43,0x61,0x70,0x65,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07, +0x13,0x09,0x43,0x61,0x70,0x65,0x20,0x54,0x6F,0x77,0x6E,0x31,0x1D,0x30,0x1B,0x06, +0x03,0x55,0x04,0x0A,0x13,0x14,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x43,0x6F,0x6E, +0x73,0x75,0x6C,0x74,0x69,0x6E,0x67,0x20,0x63,0x63,0x31,0x28,0x30,0x26,0x06,0x03, +0x55,0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69, +0x6F,0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69, +0x73,0x69,0x6F,0x6E,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x54, +0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x65,0x6D,0x69,0x75,0x6D,0x20,0x53,0x65, +0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x31,0x28,0x30,0x26,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x09,0x01,0x16,0x19,0x70,0x72,0x65,0x6D,0x69,0x75,0x6D,0x2D, +0x73,0x65,0x72,0x76,0x65,0x72,0x40,0x74,0x68,0x61,0x77,0x74,0x65,0x2E,0x63,0x6F, +0x6D,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xD2,0x36, +0x36,0x6A,0x8B,0xD7,0xC2,0x5B,0x9E,0xDA,0x81,0x41,0x62,0x8F,0x38,0xEE,0x49,0x04, +0x55,0xD6,0xD0,0xEF,0x1C,0x1B,0x95,0x16,0x47,0xEF,0x18,0x48,0x35,0x3A,0x52,0xF4, +0x2B,0x6A,0x06,0x8F,0x3B,0x2F,0xEA,0x56,0xE3,0xAF,0x86,0x8D,0x9E,0x17,0xF7,0x9E, +0xB4,0x65,0x75,0x02,0x4D,0xEF,0xCB,0x09,0xA2,0x21,0x51,0xD8,0x9B,0xD0,0x67,0xD0, +0xBA,0x0D,0x92,0x06,0x14,0x73,0xD4,0x93,0xCB,0x97,0x2A,0x00,0x9C,0x5C,0x4E,0x0C, +0xBC,0xFA,0x15,0x52,0xFC,0xF2,0x44,0x6E,0xDA,0x11,0x4A,0x6E,0x08,0x9F,0x2F,0x2D, +0xE3,0xF9,0xAA,0x3A,0x86,0x73,0xB6,0x46,0x53,0x58,0xC8,0x89,0x05,0xBD,0x83,0x11, +0xB8,0x73,0x3F,0xAA,0x07,0x8D,0xF4,0x42,0x4D,0xE7,0x40,0x9D,0x1C,0x37,0x02,0x03, +0x01,0x00,0x01,0xA3,0x13,0x30,0x11,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01, +0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x03,0x81,0x81,0x00,0x26,0x48,0x2C,0x16,0xC2, +0x58,0xFA,0xE8,0x16,0x74,0x0C,0xAA,0xAA,0x5F,0x54,0x3F,0xF2,0xD7,0xC9,0x78,0x60, +0x5E,0x5E,0x6E,0x37,0x63,0x22,0x77,0x36,0x7E,0xB2,0x17,0xC4,0x34,0xB9,0xF5,0x08, +0x85,0xFC,0xC9,0x01,0x38,0xFF,0x4D,0xBE,0xF2,0x16,0x42,0x43,0xE7,0xBB,0x5A,0x46, +0xFB,0xC1,0xC6,0x11,0x1F,0xF1,0x4A,0xB0,0x28,0x46,0xC9,0xC3,0xC4,0x42,0x7D,0xBC, +0xFA,0xAB,0x59,0x6E,0xD5,0xB7,0x51,0x88,0x11,0xE3,0xA4,0x85,0x19,0x6B,0x82,0x4C, +0xA4,0x0C,0x12,0xAD,0xE9,0xA4,0xAE,0x3F,0xF1,0xC3,0x49,0x65,0x9A,0x8C,0xC5,0xC8, +0x3E,0x25,0xB7,0x94,0x99,0xBB,0x92,0x32,0x71,0x07,0xF0,0x86,0x5E,0xED,0x50,0x27, +0xA6,0x0D,0xA6,0x23,0xF9,0xBB,0xCB,0xA6,0x07,0x14,0x42, +}; + + +/* subject:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA */ +/* issuer :/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA */ + + +const unsigned char thawte_Primary_Root_CA_certificate[1060]={ +0x30,0x82,0x04,0x20,0x30,0x82,0x03,0x08,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x34, +0x4E,0xD5,0x57,0x20,0xD5,0xED,0xEC,0x49,0xF4,0x2F,0xCE,0x37,0xDB,0x2B,0x6D,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, +0xA9,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15, +0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65,0x2C, +0x20,0x49,0x6E,0x63,0x2E,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65, +0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73,0x69,0x6F,0x6E,0x31, +0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32,0x30, +0x30,0x36,0x20,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20, +0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64, +0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55, +0x04,0x03,0x13,0x16,0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D,0x61, +0x72,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x36, +0x31,0x31,0x31,0x37,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30, +0x37,0x31,0x36,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xA9,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63, +0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73,0x69,0x6F,0x6E,0x31,0x38,0x30,0x36,0x06, +0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x74, +0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F, +0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65, +0x20,0x6F,0x6E,0x6C,0x79,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16, +0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x52, +0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82, +0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAC,0xA0,0xF0,0xFB,0x80,0x59,0xD4,0x9C,0xC7, +0xA4,0xCF,0x9D,0xA1,0x59,0x73,0x09,0x10,0x45,0x0C,0x0D,0x2C,0x6E,0x68,0xF1,0x6C, +0x5B,0x48,0x68,0x49,0x59,0x37,0xFC,0x0B,0x33,0x19,0xC2,0x77,0x7F,0xCC,0x10,0x2D, +0x95,0x34,0x1C,0xE6,0xEB,0x4D,0x09,0xA7,0x1C,0xD2,0xB8,0xC9,0x97,0x36,0x02,0xB7, +0x89,0xD4,0x24,0x5F,0x06,0xC0,0xCC,0x44,0x94,0x94,0x8D,0x02,0x62,0x6F,0xEB,0x5A, +0xDD,0x11,0x8D,0x28,0x9A,0x5C,0x84,0x90,0x10,0x7A,0x0D,0xBD,0x74,0x66,0x2F,0x6A, +0x38,0xA0,0xE2,0xD5,0x54,0x44,0xEB,0x1D,0x07,0x9F,0x07,0xBA,0x6F,0xEE,0xE9,0xFD, +0x4E,0x0B,0x29,0xF5,0x3E,0x84,0xA0,0x01,0xF1,0x9C,0xAB,0xF8,0x1C,0x7E,0x89,0xA4, +0xE8,0xA1,0xD8,0x71,0x65,0x0D,0xA3,0x51,0x7B,0xEE,0xBC,0xD2,0x22,0x60,0x0D,0xB9, +0x5B,0x9D,0xDF,0xBA,0xFC,0x51,0x5B,0x0B,0xAF,0x98,0xB2,0xE9,0x2E,0xE9,0x04,0xE8, +0x62,0x87,0xDE,0x2B,0xC8,0xD7,0x4E,0xC1,0x4C,0x64,0x1E,0xDD,0xCF,0x87,0x58,0xBA, +0x4A,0x4F,0xCA,0x68,0x07,0x1D,0x1C,0x9D,0x4A,0xC6,0xD5,0x2F,0x91,0xCC,0x7C,0x71, +0x72,0x1C,0xC5,0xC0,0x67,0xEB,0x32,0xFD,0xC9,0x92,0x5C,0x94,0xDA,0x85,0xC0,0x9B, +0xBF,0x53,0x7D,0x2B,0x09,0xF4,0x8C,0x9D,0x91,0x1F,0x97,0x6A,0x52,0xCB,0xDE,0x09, +0x36,0xA4,0x77,0xD8,0x7B,0x87,0x50,0x44,0xD5,0x3E,0x6E,0x29,0x69,0xFB,0x39,0x49, +0x26,0x1E,0x09,0xA5,0x80,0x7B,0x40,0x2D,0xEB,0xE8,0x27,0x85,0xC9,0xFE,0x61,0xFD, +0x7E,0xE6,0x7C,0x97,0x1D,0xD5,0x9D,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40, +0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01, +0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, +0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x7B,0x5B,0x45,0xCF, +0xAF,0xCE,0xCB,0x7A,0xFD,0x31,0x92,0x1A,0x6A,0xB6,0xF3,0x46,0xEB,0x57,0x48,0x50, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03, +0x82,0x01,0x01,0x00,0x79,0x11,0xC0,0x4B,0xB3,0x91,0xB6,0xFC,0xF0,0xE9,0x67,0xD4, +0x0D,0x6E,0x45,0xBE,0x55,0xE8,0x93,0xD2,0xCE,0x03,0x3F,0xED,0xDA,0x25,0xB0,0x1D, +0x57,0xCB,0x1E,0x3A,0x76,0xA0,0x4C,0xEC,0x50,0x76,0xE8,0x64,0x72,0x0C,0xA4,0xA9, +0xF1,0xB8,0x8B,0xD6,0xD6,0x87,0x84,0xBB,0x32,0xE5,0x41,0x11,0xC0,0x77,0xD9,0xB3, +0x60,0x9D,0xEB,0x1B,0xD5,0xD1,0x6E,0x44,0x44,0xA9,0xA6,0x01,0xEC,0x55,0x62,0x1D, +0x77,0xB8,0x5C,0x8E,0x48,0x49,0x7C,0x9C,0x3B,0x57,0x11,0xAC,0xAD,0x73,0x37,0x8E, +0x2F,0x78,0x5C,0x90,0x68,0x47,0xD9,0x60,0x60,0xE6,0xFC,0x07,0x3D,0x22,0x20,0x17, +0xC4,0xF7,0x16,0xE9,0xC4,0xD8,0x72,0xF9,0xC8,0x73,0x7C,0xDF,0x16,0x2F,0x15,0xA9, +0x3E,0xFD,0x6A,0x27,0xB6,0xA1,0xEB,0x5A,0xBA,0x98,0x1F,0xD5,0xE3,0x4D,0x64,0x0A, +0x9D,0x13,0xC8,0x61,0xBA,0xF5,0x39,0x1C,0x87,0xBA,0xB8,0xBD,0x7B,0x22,0x7F,0xF6, +0xFE,0xAC,0x40,0x79,0xE5,0xAC,0x10,0x6F,0x3D,0x8F,0x1B,0x79,0x76,0x8B,0xC4,0x37, +0xB3,0x21,0x18,0x84,0xE5,0x36,0x00,0xEB,0x63,0x20,0x99,0xB9,0xE9,0xFE,0x33,0x04, +0xBB,0x41,0xC8,0xC1,0x02,0xF9,0x44,0x63,0x20,0x9E,0x81,0xCE,0x42,0xD3,0xD6,0x3F, +0x2C,0x76,0xD3,0x63,0x9C,0x59,0xDD,0x8F,0xA6,0xE1,0x0E,0xA0,0x2E,0x41,0xF7,0x2E, +0x95,0x47,0xCF,0xBC,0xFD,0x33,0xF3,0xF6,0x0B,0x61,0x7E,0x7E,0x91,0x2B,0x81,0x47, +0xC2,0x27,0x30,0xEE,0xA7,0x10,0x5D,0x37,0x8F,0x5C,0x39,0x2B,0xE4,0x04,0xF0,0x7B, +0x8D,0x56,0x8C,0x68, +}; + + +/* subject:/C=US/O=thawte, Inc./OU=(c) 2007 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA - G2 */ +/* issuer :/C=US/O=thawte, Inc./OU=(c) 2007 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA - G2 */ + + +const unsigned char thawte_Primary_Root_CA___G2_certificate[652]={ +0x30,0x82,0x02,0x88,0x30,0x82,0x02,0x0D,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x35, +0xFC,0x26,0x5C,0xD9,0x84,0x4F,0xC9,0x3D,0x26,0x3D,0x57,0x9B,0xAE,0xD7,0x56,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0x84,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29, +0x20,0x32,0x30,0x30,0x37,0x20,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69, +0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x24,0x30,0x22, +0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72, +0x69,0x6D,0x61,0x72,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20, +0x47,0x32,0x30,0x1E,0x17,0x0D,0x30,0x37,0x31,0x31,0x30,0x35,0x30,0x30,0x30,0x30, +0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32,0x33,0x35,0x39,0x35, +0x39,0x5A,0x30,0x81,0x84,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61, +0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x38,0x30,0x36,0x06,0x03,0x55, +0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x37,0x20,0x74,0x68,0x61, +0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20, +0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F, +0x6E,0x6C,0x79,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x13,0x1B,0x74,0x68, +0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x52,0x6F,0x6F, +0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x47,0x32,0x30,0x76,0x30,0x10,0x06,0x07,0x2A, +0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00, +0x04,0xA2,0xD5,0x9C,0x82,0x7B,0x95,0x9D,0xF1,0x52,0x78,0x87,0xFE,0x8A,0x16,0xBF, +0x05,0xE6,0xDF,0xA3,0x02,0x4F,0x0D,0x07,0xC6,0x00,0x51,0xBA,0x0C,0x02,0x52,0x2D, +0x22,0xA4,0x42,0x39,0xC4,0xFE,0x8F,0xEA,0xC9,0xC1,0xBE,0xD4,0x4D,0xFF,0x9F,0x7A, +0x9E,0xE2,0xB1,0x7C,0x9A,0xAD,0xA7,0x86,0x09,0x73,0x87,0xD1,0xE7,0x9A,0xE3,0x7A, +0xA5,0xAA,0x6E,0xFB,0xBA,0xB3,0x70,0xC0,0x67,0x88,0xA2,0x35,0xD4,0xA3,0x9A,0xB1, +0xFD,0xAD,0xC2,0xEF,0x31,0xFA,0xA8,0xB9,0xF3,0xFB,0x08,0xC6,0x91,0xD1,0xFB,0x29, +0x95,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04, +0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF, +0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, +0x14,0x9A,0xD8,0x00,0x30,0x00,0xE7,0x6B,0x7F,0x85,0x18,0xEE,0x8B,0xB6,0xCE,0x8A, +0x0C,0xF8,0x11,0xE1,0xBB,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03, +0x03,0x03,0x69,0x00,0x30,0x66,0x02,0x31,0x00,0xDD,0xF8,0xE0,0x57,0x47,0x5B,0xA7, +0xE6,0x0A,0xC3,0xBD,0xF5,0x80,0x8A,0x97,0x35,0x0D,0x1B,0x89,0x3C,0x54,0x86,0x77, +0x28,0xCA,0xA1,0xF4,0x79,0xDE,0xB5,0xE6,0x38,0xB0,0xF0,0x65,0x70,0x8C,0x7F,0x02, +0x54,0xC2,0xBF,0xFF,0xD8,0xA1,0x3E,0xD9,0xCF,0x02,0x31,0x00,0xC4,0x8D,0x94,0xFC, +0xDC,0x53,0xD2,0xDC,0x9D,0x78,0x16,0x1F,0x15,0x33,0x23,0x53,0x52,0xE3,0x5A,0x31, +0x5D,0x9D,0xCA,0xAE,0xBD,0x13,0x29,0x44,0x0D,0x27,0x5B,0xA8,0xE7,0x68,0x9C,0x12, +0xF7,0x58,0x3F,0x2E,0x72,0x02,0x57,0xA3,0x8F,0xA1,0x14,0x2E, +}; + + +/* subject:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2008 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA - G3 */ +/* issuer :/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2008 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA - G3 */ + + +const unsigned char thawte_Primary_Root_CA___G3_certificate[1070]={ +0x30,0x82,0x04,0x2A,0x30,0x82,0x03,0x12,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x60, +0x01,0x97,0xB7,0x46,0xA7,0xEA,0xB4,0xB4,0x9A,0xD6,0x4B,0x2F,0xF7,0x90,0xFB,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81, +0xAE,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15, +0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65,0x2C, +0x20,0x49,0x6E,0x63,0x2E,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65, +0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73,0x69,0x6F,0x6E,0x31, +0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32,0x30, +0x30,0x38,0x20,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20, +0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64, +0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x24,0x30,0x22,0x06,0x03,0x55, +0x04,0x03,0x13,0x1B,0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D,0x61, +0x72,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x47,0x33,0x30, +0x1E,0x17,0x0D,0x30,0x38,0x30,0x34,0x30,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x5A, +0x17,0x0D,0x33,0x37,0x31,0x32,0x30,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30, +0x81,0xAE,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, +0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x74,0x68,0x61,0x77,0x74,0x65, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13, +0x1F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53, +0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73,0x69,0x6F,0x6E, +0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x0B,0x13,0x2F,0x28,0x63,0x29,0x20,0x32, +0x30,0x30,0x38,0x20,0x74,0x68,0x61,0x77,0x74,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E, +0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65, +0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x24,0x30,0x22,0x06,0x03, +0x55,0x04,0x03,0x13,0x1B,0x74,0x68,0x61,0x77,0x74,0x65,0x20,0x50,0x72,0x69,0x6D, +0x61,0x72,0x79,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x2D,0x20,0x47,0x33, +0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01, +0x00,0xB2,0xBF,0x27,0x2C,0xFB,0xDB,0xD8,0x5B,0xDD,0x78,0x7B,0x1B,0x9E,0x77,0x66, +0x81,0xCB,0x3E,0xBC,0x7C,0xAE,0xF3,0xA6,0x27,0x9A,0x34,0xA3,0x68,0x31,0x71,0x38, +0x33,0x62,0xE4,0xF3,0x71,0x66,0x79,0xB1,0xA9,0x65,0xA3,0xA5,0x8B,0xD5,0x8F,0x60, +0x2D,0x3F,0x42,0xCC,0xAA,0x6B,0x32,0xC0,0x23,0xCB,0x2C,0x41,0xDD,0xE4,0xDF,0xFC, +0x61,0x9C,0xE2,0x73,0xB2,0x22,0x95,0x11,0x43,0x18,0x5F,0xC4,0xB6,0x1F,0x57,0x6C, +0x0A,0x05,0x58,0x22,0xC8,0x36,0x4C,0x3A,0x7C,0xA5,0xD1,0xCF,0x86,0xAF,0x88,0xA7, +0x44,0x02,0x13,0x74,0x71,0x73,0x0A,0x42,0x59,0x02,0xF8,0x1B,0x14,0x6B,0x42,0xDF, +0x6F,0x5F,0xBA,0x6B,0x82,0xA2,0x9D,0x5B,0xE7,0x4A,0xBD,0x1E,0x01,0x72,0xDB,0x4B, +0x74,0xE8,0x3B,0x7F,0x7F,0x7D,0x1F,0x04,0xB4,0x26,0x9B,0xE0,0xB4,0x5A,0xAC,0x47, +0x3D,0x55,0xB8,0xD7,0xB0,0x26,0x52,0x28,0x01,0x31,0x40,0x66,0xD8,0xD9,0x24,0xBD, +0xF6,0x2A,0xD8,0xEC,0x21,0x49,0x5C,0x9B,0xF6,0x7A,0xE9,0x7F,0x55,0x35,0x7E,0x96, +0x6B,0x8D,0x93,0x93,0x27,0xCB,0x92,0xBB,0xEA,0xAC,0x40,0xC0,0x9F,0xC2,0xF8,0x80, +0xCF,0x5D,0xF4,0x5A,0xDC,0xCE,0x74,0x86,0xA6,0x3E,0x6C,0x0B,0x53,0xCA,0xBD,0x92, +0xCE,0x19,0x06,0x72,0xE6,0x0C,0x5C,0x38,0x69,0xC7,0x04,0xD6,0xBC,0x6C,0xCE,0x5B, +0xF6,0xF7,0x68,0x9C,0xDC,0x25,0x15,0x48,0x88,0xA1,0xE9,0xA9,0xF8,0x98,0x9C,0xE0, +0xF3,0xD5,0x31,0x28,0x61,0x11,0x6C,0x67,0x96,0x8D,0x39,0x99,0xCB,0xC2,0x45,0x24, +0x39,0x02,0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,0x1D, +0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55, +0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55, +0x1D,0x0E,0x04,0x16,0x04,0x14,0xAD,0x6C,0xAA,0x94,0x60,0x9C,0xED,0xE4,0xFF,0xFA, +0x3E,0x0A,0x74,0x2B,0x63,0x03,0xF7,0xB6,0x59,0xBF,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x1A,0x40, +0xD8,0x95,0x65,0xAC,0x09,0x92,0x89,0xC6,0x39,0xF4,0x10,0xE5,0xA9,0x0E,0x66,0x53, +0x5D,0x78,0xDE,0xFA,0x24,0x91,0xBB,0xE7,0x44,0x51,0xDF,0xC6,0x16,0x34,0x0A,0xEF, +0x6A,0x44,0x51,0xEA,0x2B,0x07,0x8A,0x03,0x7A,0xC3,0xEB,0x3F,0x0A,0x2C,0x52,0x16, +0xA0,0x2B,0x43,0xB9,0x25,0x90,0x3F,0x70,0xA9,0x33,0x25,0x6D,0x45,0x1A,0x28,0x3B, +0x27,0xCF,0xAA,0xC3,0x29,0x42,0x1B,0xDF,0x3B,0x4C,0xC0,0x33,0x34,0x5B,0x41,0x88, +0xBF,0x6B,0x2B,0x65,0xAF,0x28,0xEF,0xB2,0xF5,0xC3,0xAA,0x66,0xCE,0x7B,0x56,0xEE, +0xB7,0xC8,0xCB,0x67,0xC1,0xC9,0x9C,0x1A,0x18,0xB8,0xC4,0xC3,0x49,0x03,0xF1,0x60, +0x0E,0x50,0xCD,0x46,0xC5,0xF3,0x77,0x79,0xF7,0xB6,0x15,0xE0,0x38,0xDB,0xC7,0x2F, +0x28,0xA0,0x0C,0x3F,0x77,0x26,0x74,0xD9,0x25,0x12,0xDA,0x31,0xDA,0x1A,0x1E,0xDC, +0x29,0x41,0x91,0x22,0x3C,0x69,0xA7,0xBB,0x02,0xF2,0xB6,0x5C,0x27,0x03,0x89,0xF4, +0x06,0xEA,0x9B,0xE4,0x72,0x82,0xE3,0xA1,0x09,0xC1,0xE9,0x00,0x19,0xD3,0x3E,0xD4, +0x70,0x6B,0xBA,0x71,0xA6,0xAA,0x58,0xAE,0xF4,0xBB,0xE9,0x6C,0xB6,0xEF,0x87,0xCC, +0x9B,0xBB,0xFF,0x39,0xE6,0x56,0x61,0xD3,0x0A,0xA7,0xC4,0x5C,0x4C,0x60,0x7B,0x05, +0x77,0x26,0x7A,0xBF,0xD8,0x07,0x52,0x2C,0x62,0xF7,0x70,0x63,0xD9,0x39,0xBC,0x6F, +0x1C,0xC2,0x79,0xDC,0x76,0x29,0xAF,0xCE,0xC5,0x2C,0x64,0x04,0x5E,0x88,0x36,0x6E, +0x31,0xD4,0x40,0x1A,0x62,0x34,0x36,0x3F,0x35,0x01,0xAE,0xAC,0x63,0xA0, +}; + + +/* subject:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Server CA/emailAddress=server-certs@thawte.com */ +/* issuer :/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Server CA/emailAddress=server-certs@thawte.com */ + + +const unsigned char Thawte_Server_CA_certificate[791]={ +0x30,0x82,0x03,0x13,0x30,0x82,0x02,0x7C,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,0x05,0x00,0x30, +0x81,0xC4,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x5A,0x41,0x31, +0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x08,0x13,0x0C,0x57,0x65,0x73,0x74,0x65,0x72, +0x6E,0x20,0x43,0x61,0x70,0x65,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x13, +0x09,0x43,0x61,0x70,0x65,0x20,0x54,0x6F,0x77,0x6E,0x31,0x1D,0x30,0x1B,0x06,0x03, +0x55,0x04,0x0A,0x13,0x14,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x43,0x6F,0x6E,0x73, +0x75,0x6C,0x74,0x69,0x6E,0x67,0x20,0x63,0x63,0x31,0x28,0x30,0x26,0x06,0x03,0x55, +0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, +0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x44,0x69,0x76,0x69,0x73, +0x69,0x6F,0x6E,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x03,0x13,0x10,0x54,0x68, +0x61,0x77,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x31,0x26, +0x30,0x24,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x01,0x16,0x17,0x73, +0x65,0x72,0x76,0x65,0x72,0x2D,0x63,0x65,0x72,0x74,0x73,0x40,0x74,0x68,0x61,0x77, +0x74,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x17,0x0D,0x39,0x36,0x30,0x38,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x30,0x31,0x32,0x33,0x31,0x32, +0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xC4,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x5A,0x41,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x08,0x13, +0x0C,0x57,0x65,0x73,0x74,0x65,0x72,0x6E,0x20,0x43,0x61,0x70,0x65,0x31,0x12,0x30, +0x10,0x06,0x03,0x55,0x04,0x07,0x13,0x09,0x43,0x61,0x70,0x65,0x20,0x54,0x6F,0x77, +0x6E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0A,0x13,0x14,0x54,0x68,0x61,0x77, +0x74,0x65,0x20,0x43,0x6F,0x6E,0x73,0x75,0x6C,0x74,0x69,0x6E,0x67,0x20,0x63,0x63, +0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0B,0x13,0x1F,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65, +0x73,0x20,0x44,0x69,0x76,0x69,0x73,0x69,0x6F,0x6E,0x31,0x19,0x30,0x17,0x06,0x03, +0x55,0x04,0x03,0x13,0x10,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x53,0x65,0x72,0x76, +0x65,0x72,0x20,0x43,0x41,0x31,0x26,0x30,0x24,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, +0x0D,0x01,0x09,0x01,0x16,0x17,0x73,0x65,0x72,0x76,0x65,0x72,0x2D,0x63,0x65,0x72, +0x74,0x73,0x40,0x74,0x68,0x61,0x77,0x74,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x81,0x9F, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03, +0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xD3,0xA4,0x50,0x6E,0xC8,0xFF, +0x56,0x6B,0xE6,0xCF,0x5D,0xB6,0xEA,0x0C,0x68,0x75,0x47,0xA2,0xAA,0xC2,0xDA,0x84, +0x25,0xFC,0xA8,0xF4,0x47,0x51,0xDA,0x85,0xB5,0x20,0x74,0x94,0x86,0x1E,0x0F,0x75, +0xC9,0xE9,0x08,0x61,0xF5,0x06,0x6D,0x30,0x6E,0x15,0x19,0x02,0xE9,0x52,0xC0,0x62, +0xDB,0x4D,0x99,0x9E,0xE2,0x6A,0x0C,0x44,0x38,0xCD,0xFE,0xBE,0xE3,0x64,0x09,0x70, +0xC5,0xFE,0xB1,0x6B,0x29,0xB6,0x2F,0x49,0xC8,0x3B,0xD4,0x27,0x04,0x25,0x10,0x97, +0x2F,0xE7,0x90,0x6D,0xC0,0x28,0x42,0x99,0xD7,0x4C,0x43,0xDE,0xC3,0xF5,0x21,0x6D, +0x54,0x9F,0x5D,0xC3,0x58,0xE1,0xC0,0xE4,0xD9,0x5B,0xB0,0xB8,0xDC,0xB4,0x7B,0xDF, +0x36,0x3A,0xC2,0xB5,0x66,0x22,0x12,0xD6,0x87,0x0D,0x02,0x03,0x01,0x00,0x01,0xA3, +0x13,0x30,0x11,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x04,0x05,0x00,0x03,0x81,0x81,0x00,0x07,0xFA,0x4C,0x69,0x5C,0xFB,0x95,0xCC,0x46, +0xEE,0x85,0x83,0x4D,0x21,0x30,0x8E,0xCA,0xD9,0xA8,0x6F,0x49,0x1A,0xE6,0xDA,0x51, +0xE3,0x60,0x70,0x6C,0x84,0x61,0x11,0xA1,0x1A,0xC8,0x48,0x3E,0x59,0x43,0x7D,0x4F, +0x95,0x3D,0xA1,0x8B,0xB7,0x0B,0x62,0x98,0x7A,0x75,0x8A,0xDD,0x88,0x4E,0x4E,0x9E, +0x40,0xDB,0xA8,0xCC,0x32,0x74,0xB9,0x6F,0x0D,0xC6,0xE3,0xB3,0x44,0x0B,0xD9,0x8A, +0x6F,0x9A,0x29,0x9B,0x99,0x18,0x28,0x3B,0xD1,0xE3,0x40,0x28,0x9A,0x5A,0x3C,0xD5, +0xB5,0xE7,0x20,0x1B,0x8B,0xCA,0xA4,0xAB,0x8D,0xE9,0x51,0xD9,0xE2,0x4C,0x2C,0x59, +0xA9,0xDA,0xB9,0xB2,0x75,0x1B,0xF6,0x42,0xF2,0xEF,0xC7,0xF2,0x18,0xF9,0x89,0xBC, +0xA3,0xFF,0x8A,0x23,0x2E,0x70,0x47, +}; + + +/* subject:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC */ +/* issuer :/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC */ + + +const unsigned char UTN_DATACorp_SGC_Root_CA_certificate[1122]={ +0x30,0x82,0x04,0x5E,0x30,0x82,0x03,0x46,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x44, +0xBE,0x0C,0x8B,0x50,0x00,0x21,0xB4,0x11,0xD3,0x2A,0x68,0x06,0xA9,0xAD,0x69,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, +0x93,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06, +0x03,0x55,0x04,0x07,0x13,0x0E,0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20, +0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54, +0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74, +0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68, +0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72, +0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03, +0x13,0x12,0x55,0x54,0x4E,0x20,0x2D,0x20,0x44,0x41,0x54,0x41,0x43,0x6F,0x72,0x70, +0x20,0x53,0x47,0x43,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36,0x32,0x34,0x31,0x38, +0x35,0x37,0x32,0x31,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32,0x34,0x31,0x39,0x30, +0x36,0x33,0x30,0x5A,0x30,0x81,0x93,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55, +0x54,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x07,0x13,0x0E,0x53,0x61,0x6C,0x74, +0x20,0x4C,0x61,0x6B,0x65,0x20,0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03, +0x55,0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55, +0x53,0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03, +0x55,0x04,0x0B,0x13,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E, +0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x1B,0x30, +0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x55,0x54,0x4E,0x20,0x2D,0x20,0x44,0x41, +0x54,0x41,0x43,0x6F,0x72,0x70,0x20,0x53,0x47,0x43,0x30,0x82,0x01,0x22,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01, +0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xDF,0xEE,0x58,0x10,0xA2, +0x2B,0x6E,0x55,0xC4,0x8E,0xBF,0x2E,0x46,0x09,0xE7,0xE0,0x08,0x0F,0x2E,0x2B,0x7A, +0x13,0x94,0x1B,0xBD,0xF6,0xB6,0x80,0x8E,0x65,0x05,0x93,0x00,0x1E,0xBC,0xAF,0xE2, +0x0F,0x8E,0x19,0x0D,0x12,0x47,0xEC,0xAC,0xAD,0xA3,0xFA,0x2E,0x70,0xF8,0xDE,0x6E, +0xFB,0x56,0x42,0x15,0x9E,0x2E,0x5C,0xEF,0x23,0xDE,0x21,0xB9,0x05,0x76,0x27,0x19, +0x0F,0x4F,0xD6,0xC3,0x9C,0xB4,0xBE,0x94,0x19,0x63,0xF2,0xA6,0x11,0x0A,0xEB,0x53, +0x48,0x9C,0xBE,0xF2,0x29,0x3B,0x16,0xE8,0x1A,0xA0,0x4C,0xA6,0xC9,0xF4,0x18,0x59, +0x68,0xC0,0x70,0xF2,0x53,0x00,0xC0,0x5E,0x50,0x82,0xA5,0x56,0x6F,0x36,0xF9,0x4A, +0xE0,0x44,0x86,0xA0,0x4D,0x4E,0xD6,0x47,0x6E,0x49,0x4A,0xCB,0x67,0xD7,0xA6,0xC4, +0x05,0xB9,0x8E,0x1E,0xF4,0xFC,0xFF,0xCD,0xE7,0x36,0xE0,0x9C,0x05,0x6C,0xB2,0x33, +0x22,0x15,0xD0,0xB4,0xE0,0xCC,0x17,0xC0,0xB2,0xC0,0xF4,0xFE,0x32,0x3F,0x29,0x2A, +0x95,0x7B,0xD8,0xF2,0xA7,0x4E,0x0F,0x54,0x7C,0xA1,0x0D,0x80,0xB3,0x09,0x03,0xC1, +0xFF,0x5C,0xDD,0x5E,0x9A,0x3E,0xBC,0xAE,0xBC,0x47,0x8A,0x6A,0xAE,0x71,0xCA,0x1F, +0xB1,0x2A,0xB8,0x5F,0x42,0x05,0x0B,0xEC,0x46,0x30,0xD1,0x72,0x0B,0xCA,0xE9,0x56, +0x6D,0xF5,0xEF,0xDF,0x78,0xBE,0x61,0xBA,0xB2,0xA5,0xAE,0x04,0x4C,0xBC,0xA8,0xAC, +0x69,0x15,0x97,0xBD,0xEF,0xEB,0xB4,0x8C,0xBF,0x35,0xF8,0xD4,0xC3,0xD1,0x28,0x0E, +0x5C,0x3A,0x9F,0x70,0x18,0x33,0x20,0x77,0xC4,0xA2,0xAF,0x02,0x03,0x01,0x00,0x01, +0xA3,0x81,0xAB,0x30,0x81,0xA8,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03, +0x02,0x01,0xC6,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x53, +0x32,0xD1,0xB3,0xCF,0x7F,0xFA,0xE0,0xF1,0xA0,0x5D,0x85,0x4E,0x92,0xD2,0x9E,0x45, +0x1D,0xB4,0x4F,0x30,0x3D,0x06,0x03,0x55,0x1D,0x1F,0x04,0x36,0x30,0x34,0x30,0x32, +0xA0,0x30,0xA0,0x2E,0x86,0x2C,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C, +0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x55, +0x54,0x4E,0x2D,0x44,0x41,0x54,0x41,0x43,0x6F,0x72,0x70,0x53,0x47,0x43,0x2E,0x63, +0x72,0x6C,0x30,0x2A,0x06,0x03,0x55,0x1D,0x25,0x04,0x23,0x30,0x21,0x06,0x08,0x2B, +0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0x82,0x37, +0x0A,0x03,0x03,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x04,0x01,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01, +0x01,0x00,0x27,0x35,0x97,0x00,0x8A,0x8B,0x28,0xBD,0xC6,0x33,0x30,0x1E,0x29,0xFC, +0xE2,0xF7,0xD5,0x98,0xD4,0x40,0xBB,0x60,0xCA,0xBF,0xAB,0x17,0x2C,0x09,0x36,0x7F, +0x50,0xFA,0x41,0xDC,0xAE,0x96,0x3A,0x0A,0x23,0x3E,0x89,0x59,0xC9,0xA3,0x07,0xED, +0x1B,0x37,0xAD,0xFC,0x7C,0xBE,0x51,0x49,0x5A,0xDE,0x3A,0x0A,0x54,0x08,0x16,0x45, +0xC2,0x99,0xB1,0x87,0xCD,0x8C,0x68,0xE0,0x69,0x03,0xE9,0xC4,0x4E,0x98,0xB2,0x3B, +0x8C,0x16,0xB3,0x0E,0xA0,0x0C,0x98,0x50,0x9B,0x93,0xA9,0x70,0x09,0xC8,0x2C,0xA3, +0x8F,0xDF,0x02,0xE4,0xE0,0x71,0x3A,0xF1,0xB4,0x23,0x72,0xA0,0xAA,0x01,0xDF,0xDF, +0x98,0x3E,0x14,0x50,0xA0,0x31,0x26,0xBD,0x28,0xE9,0x5A,0x30,0x26,0x75,0xF9,0x7B, +0x60,0x1C,0x8D,0xF3,0xCD,0x50,0x26,0x6D,0x04,0x27,0x9A,0xDF,0xD5,0x0D,0x45,0x47, +0x29,0x6B,0x2C,0xE6,0x76,0xD9,0xA9,0x29,0x7D,0x32,0xDD,0xC9,0x36,0x3C,0xBD,0xAE, +0x35,0xF1,0x11,0x9E,0x1D,0xBB,0x90,0x3F,0x12,0x47,0x4E,0x8E,0xD7,0x7E,0x0F,0x62, +0x73,0x1D,0x52,0x26,0x38,0x1C,0x18,0x49,0xFD,0x30,0x74,0x9A,0xC4,0xE5,0x22,0x2F, +0xD8,0xC0,0x8D,0xED,0x91,0x7A,0x4C,0x00,0x8F,0x72,0x7F,0x5D,0xDA,0xDD,0x1B,0x8B, +0x45,0x6B,0xE7,0xDD,0x69,0x97,0xA8,0xC5,0x56,0x4C,0x0F,0x0C,0xF6,0x9F,0x7A,0x91, +0x37,0xF6,0x97,0x82,0xE0,0xDD,0x71,0x69,0xFF,0x76,0x3F,0x60,0x4D,0x3C,0xCF,0xF7, +0x99,0xF9,0xC6,0x57,0xF4,0xC9,0x55,0x39,0x78,0xBA,0x2C,0x79,0xC9,0xA6,0x88,0x2B, +0xF4,0x08, +}; + + +/* subject:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware */ +/* issuer :/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware */ + + +const unsigned char UTN_USERFirst_Hardware_Root_CA_certificate[1144]={ +0x30,0x82,0x04,0x74,0x30,0x82,0x03,0x5C,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x44, +0xBE,0x0C,0x8B,0x50,0x00,0x24,0xB4,0x11,0xD3,0x36,0x2A,0xFE,0x65,0x0A,0xFD,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, +0x97,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06, +0x03,0x55,0x04,0x07,0x13,0x0E,0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20, +0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54, +0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74, +0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68, +0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72, +0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03, +0x13,0x16,0x55,0x54,0x4E,0x2D,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2D, +0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x37, +0x30,0x39,0x31,0x38,0x31,0x30,0x34,0x32,0x5A,0x17,0x0D,0x31,0x39,0x30,0x37,0x30, +0x39,0x31,0x38,0x31,0x39,0x32,0x32,0x5A,0x30,0x81,0x97,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, +0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x07,0x13,0x0E, +0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20,0x43,0x69,0x74,0x79,0x31,0x1E, +0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45, +0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x21, +0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F, +0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F, +0x6D,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,0x54,0x4E,0x2D, +0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2D,0x48,0x61,0x72,0x64,0x77,0x61, +0x72,0x65,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82, +0x01,0x01,0x00,0xB1,0xF7,0xC3,0x38,0x3F,0xB4,0xA8,0x7F,0xCF,0x39,0x82,0x51,0x67, +0xD0,0x6D,0x9F,0xD2,0xFF,0x58,0xF3,0xE7,0x9F,0x2B,0xEC,0x0D,0x89,0x54,0x99,0xB9, +0x38,0x99,0x16,0xF7,0xE0,0x21,0x79,0x48,0xC2,0xBB,0x61,0x74,0x12,0x96,0x1D,0x3C, +0x6A,0x72,0xD5,0x3C,0x10,0x67,0x3A,0x39,0xED,0x2B,0x13,0xCD,0x66,0xEB,0x95,0x09, +0x33,0xA4,0x6C,0x97,0xB1,0xE8,0xC6,0xEC,0xC1,0x75,0x79,0x9C,0x46,0x5E,0x8D,0xAB, +0xD0,0x6A,0xFD,0xB9,0x2A,0x55,0x17,0x10,0x54,0xB3,0x19,0xF0,0x9A,0xF6,0xF1,0xB1, +0x5D,0xB6,0xA7,0x6D,0xFB,0xE0,0x71,0x17,0x6B,0xA2,0x88,0xFB,0x00,0xDF,0xFE,0x1A, +0x31,0x77,0x0C,0x9A,0x01,0x7A,0xB1,0x32,0xE3,0x2B,0x01,0x07,0x38,0x6E,0xC3,0xA5, +0x5E,0x23,0xBC,0x45,0x9B,0x7B,0x50,0xC1,0xC9,0x30,0x8F,0xDB,0xE5,0x2B,0x7A,0xD3, +0x5B,0xFB,0x33,0x40,0x1E,0xA0,0xD5,0x98,0x17,0xBC,0x8B,0x87,0xC3,0x89,0xD3,0x5D, +0xA0,0x8E,0xB2,0xAA,0xAA,0xF6,0x8E,0x69,0x88,0x06,0xC5,0xFA,0x89,0x21,0xF3,0x08, +0x9D,0x69,0x2E,0x09,0x33,0x9B,0x29,0x0D,0x46,0x0F,0x8C,0xCC,0x49,0x34,0xB0,0x69, +0x51,0xBD,0xF9,0x06,0xCD,0x68,0xAD,0x66,0x4C,0xBC,0x3E,0xAC,0x61,0xBD,0x0A,0x88, +0x0E,0xC8,0xDF,0x3D,0xEE,0x7C,0x04,0x4C,0x9D,0x0A,0x5E,0x6B,0x91,0xD6,0xEE,0xC7, +0xED,0x28,0x8D,0xAB,0x4D,0x87,0x89,0x73,0xD0,0x6E,0xA4,0xD0,0x1E,0x16,0x8B,0x14, +0xE1,0x76,0x44,0x03,0x7F,0x63,0xAC,0xE4,0xCD,0x49,0x9C,0xC5,0x92,0xF4,0xAB,0x32, +0xA1,0x48,0x5B,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xB9,0x30,0x81,0xB6,0x30,0x0B, +0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0xC6,0x30,0x0F,0x06,0x03,0x55, +0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03, +0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xA1,0x72,0x5F,0x26,0x1B,0x28,0x98,0x43,0x95, +0x5D,0x07,0x37,0xD5,0x85,0x96,0x9D,0x4B,0xD2,0xC3,0x45,0x30,0x44,0x06,0x03,0x55, +0x1D,0x1F,0x04,0x3D,0x30,0x3B,0x30,0x39,0xA0,0x37,0xA0,0x35,0x86,0x33,0x68,0x74, +0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75, +0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x55,0x54,0x4E,0x2D,0x55,0x53,0x45,0x52,0x46, +0x69,0x72,0x73,0x74,0x2D,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2E,0x63,0x72, +0x6C,0x30,0x31,0x06,0x03,0x55,0x1D,0x25,0x04,0x2A,0x30,0x28,0x06,0x08,0x2B,0x06, +0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x05, +0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x06,0x06,0x08,0x2B,0x06,0x01,0x05, +0x05,0x07,0x03,0x07,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x47,0x19,0x0F,0xDE,0x74,0xC6,0x99,0x97, +0xAF,0xFC,0xAD,0x28,0x5E,0x75,0x8E,0xEB,0x2D,0x67,0xEE,0x4E,0x7B,0x2B,0xD7,0x0C, +0xFF,0xF6,0xDE,0xCB,0x55,0xA2,0x0A,0xE1,0x4C,0x54,0x65,0x93,0x60,0x6B,0x9F,0x12, +0x9C,0xAD,0x5E,0x83,0x2C,0xEB,0x5A,0xAE,0xC0,0xE4,0x2D,0xF4,0x00,0x63,0x1D,0xB8, +0xC0,0x6C,0xF2,0xCF,0x49,0xBB,0x4D,0x93,0x6F,0x06,0xA6,0x0A,0x22,0xB2,0x49,0x62, +0x08,0x4E,0xFF,0xC8,0xC8,0x14,0xB2,0x88,0x16,0x5D,0xE7,0x01,0xE4,0x12,0x95,0xE5, +0x45,0x34,0xB3,0x8B,0x69,0xBD,0xCF,0xB4,0x85,0x8F,0x75,0x51,0x9E,0x7D,0x3A,0x38, +0x3A,0x14,0x48,0x12,0xC6,0xFB,0xA7,0x3B,0x1A,0x8D,0x0D,0x82,0x40,0x07,0xE8,0x04, +0x08,0x90,0xA1,0x89,0xCB,0x19,0x50,0xDF,0xCA,0x1C,0x01,0xBC,0x1D,0x04,0x19,0x7B, +0x10,0x76,0x97,0x3B,0xEE,0x90,0x90,0xCA,0xC4,0x0E,0x1F,0x16,0x6E,0x75,0xEF,0x33, +0xF8,0xD3,0x6F,0x5B,0x1E,0x96,0xE3,0xE0,0x74,0x77,0x74,0x7B,0x8A,0xA2,0x6E,0x2D, +0xDD,0x76,0xD6,0x39,0x30,0x82,0xF0,0xAB,0x9C,0x52,0xF2,0x2A,0xC7,0xAF,0x49,0x5E, +0x7E,0xC7,0x68,0xE5,0x82,0x81,0xC8,0x6A,0x27,0xF9,0x27,0x88,0x2A,0xD5,0x58,0x50, +0x95,0x1F,0xF0,0x3B,0x1C,0x57,0xBB,0x7D,0x14,0x39,0x62,0x2B,0x9A,0xC9,0x94,0x92, +0x2A,0xA3,0x22,0x0C,0xFF,0x89,0x26,0x7D,0x5F,0x23,0x2B,0x47,0xD7,0x15,0x1D,0xA9, +0x6A,0x9E,0x51,0x0D,0x2A,0x51,0x9E,0x81,0xF9,0xD4,0x3B,0x5E,0x70,0x12,0x7F,0x10, +0x32,0x9C,0x1E,0xBB,0x9D,0xF8,0x66,0xA8, +}; + + +/* subject:/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 1 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ +/* issuer :/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 1 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ + + +const unsigned char ValiCert_Class_1_VA_certificate[747]={ +0x30,0x82,0x02,0xE7,0x30,0x82,0x02,0x50,0x02,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A, +0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xBB,0x31,0x24,0x30, +0x22,0x06,0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74, +0x20,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77, +0x6F,0x72,0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61, +0x6C,0x69,0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33, +0x06,0x03,0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20, +0x43,0x6C,0x61,0x73,0x73,0x20,0x31,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56, +0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74, +0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72, +0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69, +0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36, +0x32,0x35,0x32,0x32,0x32,0x33,0x34,0x38,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32, +0x35,0x32,0x32,0x32,0x33,0x34,0x38,0x5A,0x30,0x81,0xBB,0x31,0x24,0x30,0x22,0x06, +0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x56, +0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, +0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61,0x6C,0x69, +0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33,0x06,0x03, +0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x43,0x6C, +0x61,0x73,0x73,0x20,0x31,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56,0x61,0x6C, +0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, +0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74,0x74,0x70, +0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72,0x74,0x2E, +0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69,0x63,0x65, +0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02, +0x81,0x81,0x00,0xD8,0x59,0x82,0x7A,0x89,0xB8,0x96,0xBA,0xA6,0x2F,0x68,0x6F,0x58, +0x2E,0xA7,0x54,0x1C,0x06,0x6E,0xF4,0xEA,0x8D,0x48,0xBC,0x31,0x94,0x17,0xF0,0xF3, +0x4E,0xBC,0xB2,0xB8,0x35,0x92,0x76,0xB0,0xD0,0xA5,0xA5,0x01,0xD7,0x00,0x03,0x12, +0x22,0x19,0x08,0xF8,0xFF,0x11,0x23,0x9B,0xCE,0x07,0xF5,0xBF,0x69,0x1A,0x26,0xFE, +0x4E,0xE9,0xD1,0x7F,0x9D,0x2C,0x40,0x1D,0x59,0x68,0x6E,0xA6,0xF8,0x58,0xB0,0x9D, +0x1A,0x8F,0xD3,0x3F,0xF1,0xDC,0x19,0x06,0x81,0xA8,0x0E,0xE0,0x3A,0xDD,0xC8,0x53, +0x45,0x09,0x06,0xE6,0x0F,0x70,0xC3,0xFA,0x40,0xA6,0x0E,0xE2,0x56,0x05,0x0F,0x18, +0x4D,0xFC,0x20,0x82,0xD1,0x73,0x55,0x74,0x8D,0x76,0x72,0xA0,0x1D,0x9D,0x1D,0xC0, +0xDD,0x3F,0x71,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x50,0x68,0x3D,0x49,0xF4, +0x2C,0x1C,0x06,0x94,0xDF,0x95,0x60,0x7F,0x96,0x7B,0x17,0xFE,0x4F,0x71,0xAD,0x64, +0xC8,0xDD,0x77,0xD2,0xEF,0x59,0x55,0xE8,0x3F,0xE8,0x8E,0x05,0x2A,0x21,0xF2,0x07, +0xD2,0xB5,0xA7,0x52,0xFE,0x9C,0xB1,0xB6,0xE2,0x5B,0x77,0x17,0x40,0xEA,0x72,0xD6, +0x23,0xCB,0x28,0x81,0x32,0xC3,0x00,0x79,0x18,0xEC,0x59,0x17,0x89,0xC9,0xC6,0x6A, +0x1E,0x71,0xC9,0xFD,0xB7,0x74,0xA5,0x25,0x45,0x69,0xC5,0x48,0xAB,0x19,0xE1,0x45, +0x8A,0x25,0x6B,0x19,0xEE,0xE5,0xBB,0x12,0xF5,0x7F,0xF7,0xA6,0x8D,0x51,0xC3,0xF0, +0x9D,0x74,0xB7,0xA9,0x3E,0xA0,0xA5,0xFF,0xB6,0x49,0x03,0x13,0xDA,0x22,0xCC,0xED, +0x71,0x82,0x2B,0x99,0xCF,0x3A,0xB7,0xF5,0x2D,0x72,0xC8, +}; + + +/* subject:/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 2 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ +/* issuer :/L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 2 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com */ + + +const unsigned char ValiCert_Class_2_VA_certificate[747]={ +0x30,0x82,0x02,0xE7,0x30,0x82,0x02,0x50,0x02,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A, +0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xBB,0x31,0x24,0x30, +0x22,0x06,0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74, +0x20,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77, +0x6F,0x72,0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61, +0x6C,0x69,0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33, +0x06,0x03,0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20, +0x43,0x6C,0x61,0x73,0x73,0x20,0x32,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56, +0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74, +0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72, +0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69, +0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x36, +0x32,0x36,0x30,0x30,0x31,0x39,0x35,0x34,0x5A,0x17,0x0D,0x31,0x39,0x30,0x36,0x32, +0x36,0x30,0x30,0x31,0x39,0x35,0x34,0x5A,0x30,0x81,0xBB,0x31,0x24,0x30,0x22,0x06, +0x03,0x55,0x04,0x07,0x13,0x1B,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x56, +0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, +0x6B,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x61,0x6C,0x69, +0x43,0x65,0x72,0x74,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x35,0x30,0x33,0x06,0x03, +0x55,0x04,0x0B,0x13,0x2C,0x56,0x61,0x6C,0x69,0x43,0x65,0x72,0x74,0x20,0x43,0x6C, +0x61,0x73,0x73,0x20,0x32,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x56,0x61,0x6C, +0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74, +0x79,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x68,0x74,0x74,0x70, +0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x76,0x61,0x6C,0x69,0x63,0x65,0x72,0x74,0x2E, +0x63,0x6F,0x6D,0x2F,0x31,0x20,0x30,0x1E,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, +0x01,0x09,0x01,0x16,0x11,0x69,0x6E,0x66,0x6F,0x40,0x76,0x61,0x6C,0x69,0x63,0x65, +0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02, +0x81,0x81,0x00,0xCE,0x3A,0x71,0xCA,0xE5,0xAB,0xC8,0x59,0x92,0x55,0xD7,0xAB,0xD8, +0x74,0x0E,0xF9,0xEE,0xD9,0xF6,0x55,0x47,0x59,0x65,0x47,0x0E,0x05,0x55,0xDC,0xEB, +0x98,0x36,0x3C,0x5C,0x53,0x5D,0xD3,0x30,0xCF,0x38,0xEC,0xBD,0x41,0x89,0xED,0x25, +0x42,0x09,0x24,0x6B,0x0A,0x5E,0xB3,0x7C,0xDD,0x52,0x2D,0x4C,0xE6,0xD4,0xD6,0x7D, +0x5A,0x59,0xA9,0x65,0xD4,0x49,0x13,0x2D,0x24,0x4D,0x1C,0x50,0x6F,0xB5,0xC1,0x85, +0x54,0x3B,0xFE,0x71,0xE4,0xD3,0x5C,0x42,0xF9,0x80,0xE0,0x91,0x1A,0x0A,0x5B,0x39, +0x36,0x67,0xF3,0x3F,0x55,0x7C,0x1B,0x3F,0xB4,0x5F,0x64,0x73,0x34,0xE3,0xB4,0x12, +0xBF,0x87,0x64,0xF8,0xDA,0x12,0xFF,0x37,0x27,0xC1,0xB3,0x43,0xBB,0xEF,0x7B,0x6E, +0x2E,0x69,0xF7,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x3B,0x7F,0x50,0x6F,0x6F, +0x50,0x94,0x99,0x49,0x62,0x38,0x38,0x1F,0x4B,0xF8,0xA5,0xC8,0x3E,0xA7,0x82,0x81, +0xF6,0x2B,0xC7,0xE8,0xC5,0xCE,0xE8,0x3A,0x10,0x82,0xCB,0x18,0x00,0x8E,0x4D,0xBD, +0xA8,0x58,0x7F,0xA1,0x79,0x00,0xB5,0xBB,0xE9,0x8D,0xAF,0x41,0xD9,0x0F,0x34,0xEE, +0x21,0x81,0x19,0xA0,0x32,0x49,0x28,0xF4,0xC4,0x8E,0x56,0xD5,0x52,0x33,0xFD,0x50, +0xD5,0x7E,0x99,0x6C,0x03,0xE4,0xC9,0x4C,0xFC,0xCB,0x6C,0xAB,0x66,0xB3,0x4A,0x21, +0x8C,0xE5,0xB5,0x0C,0x32,0x3E,0x10,0xB2,0xCC,0x6C,0xA1,0xDC,0x9A,0x98,0x4C,0x02, +0x5B,0xF3,0xCE,0xB9,0x9E,0xA5,0x72,0x0E,0x4A,0xB7,0x3F,0x3C,0xE6,0x16,0x68,0xF8, +0xBE,0xED,0x74,0x4C,0xBC,0x5B,0xD5,0x62,0x1F,0x43,0xDD, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority */ +/* issuer :/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority */ + + +const unsigned char Verisign_Class_3_Public_Primary_Certification_Authority_certificate[576]={ +0x30,0x82,0x02,0x3C,0x30,0x82,0x01,0xA5,0x02,0x10,0x3C,0x91,0x31,0xCB,0x1F,0xF6, +0xD0,0x1B,0x0E,0x9A,0xB8,0xD0,0x44,0xBF,0x12,0xBE,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x5F,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04, +0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x37,0x30,0x35,0x06,0x03,0x55,0x04,0x0B,0x13,0x2E,0x43,0x6C,0x61,0x73, +0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61, +0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E, +0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x39,0x36, +0x30,0x31,0x32,0x39,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x38,0x30, +0x38,0x30,0x32,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x5F,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55, +0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x31,0x37,0x30,0x35,0x06,0x03,0x55,0x04,0x0B,0x13,0x2E,0x43,0x6C,0x61, +0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D, +0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, +0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x81,0x9F,0x30,0x0D, +0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xC9,0x5C,0x59,0x9E,0xF2,0x1B,0x8A,0x01, +0x14,0xB4,0x10,0xDF,0x04,0x40,0xDB,0xE3,0x57,0xAF,0x6A,0x45,0x40,0x8F,0x84,0x0C, +0x0B,0xD1,0x33,0xD9,0xD9,0x11,0xCF,0xEE,0x02,0x58,0x1F,0x25,0xF7,0x2A,0xA8,0x44, +0x05,0xAA,0xEC,0x03,0x1F,0x78,0x7F,0x9E,0x93,0xB9,0x9A,0x00,0xAA,0x23,0x7D,0xD6, +0xAC,0x85,0xA2,0x63,0x45,0xC7,0x72,0x27,0xCC,0xF4,0x4C,0xC6,0x75,0x71,0xD2,0x39, +0xEF,0x4F,0x42,0xF0,0x75,0xDF,0x0A,0x90,0xC6,0x8E,0x20,0x6F,0x98,0x0F,0xF8,0xAC, +0x23,0x5F,0x70,0x29,0x36,0xA4,0xC9,0x86,0xE7,0xB1,0x9A,0x20,0xCB,0x53,0xA5,0x85, +0xE7,0x3D,0xBE,0x7D,0x9A,0xFE,0x24,0x45,0x33,0xDC,0x76,0x15,0xED,0x0F,0xA2,0x71, +0x64,0x4C,0x65,0x2E,0x81,0x68,0x45,0xA7,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06, +0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00, +0x10,0x72,0x52,0xA9,0x05,0x14,0x19,0x32,0x08,0x41,0xF0,0xC5,0x6B,0x0A,0xCC,0x7E, +0x0F,0x21,0x19,0xCD,0xE4,0x67,0xDC,0x5F,0xA9,0x1B,0xE6,0xCA,0xE8,0x73,0x9D,0x22, +0xD8,0x98,0x6E,0x73,0x03,0x61,0x91,0xC5,0x7C,0xB0,0x45,0x40,0x6E,0x44,0x9D,0x8D, +0xB0,0xB1,0x96,0x74,0x61,0x2D,0x0D,0xA9,0x45,0xD2,0xA4,0x92,0x2A,0xD6,0x9A,0x75, +0x97,0x6E,0x3F,0x53,0xFD,0x45,0x99,0x60,0x1D,0xA8,0x2B,0x4C,0xF9,0x5E,0xA7,0x09, +0xD8,0x75,0x30,0xD7,0xD2,0x65,0x60,0x3D,0x67,0xD6,0x48,0x55,0x75,0x69,0x3F,0x91, +0xF5,0x48,0x0B,0x47,0x69,0x22,0x69,0x82,0x96,0xBE,0xC9,0xC8,0x38,0x86,0x4A,0x7A, +0x2C,0x73,0x19,0x48,0x69,0x4E,0x6B,0x7C,0x65,0xBF,0x0F,0xFC,0x70,0xCE,0x88,0x90, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign, Inc. - For authorized use only/OU=VeriSign Trust Network */ +/* issuer :/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign, Inc. - For authorized use only/OU=VeriSign Trust Network */ + + +const unsigned char Verisign_Class_3_Public_Primary_Certification_Authority___G2_certificate[774]={ +0x30,0x82,0x03,0x02,0x30,0x82,0x02,0x6B,0x02,0x10,0x7D,0xD9,0xFE,0x07,0xCF,0xA8, +0x1E,0xB7,0x10,0x79,0x67,0xFB,0xA7,0x89,0x34,0xC6,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xC1,0x31,0x0B,0x30,0x09, +0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55, +0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x31,0x3C,0x30,0x3A,0x06,0x03,0x55,0x04,0x0B,0x13,0x33,0x43,0x6C,0x61, +0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D, +0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, +0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x32, +0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29,0x20,0x31, +0x39,0x39,0x38,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E, +0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69, +0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x1F,0x30,0x1D, +0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20, +0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x30,0x1E,0x17, +0x0D,0x39,0x38,0x30,0x35,0x31,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D, +0x32,0x38,0x30,0x38,0x30,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xC1, +0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30, +0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x3C,0x30,0x3A,0x06,0x03,0x55,0x04,0x0B,0x13, +0x33,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20, +0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, +0x2D,0x20,0x47,0x32,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28, +0x63,0x29,0x20,0x31,0x39,0x39,0x38,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74, +0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79, +0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69,0x53, +0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, +0x6B,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, +0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xCC,0x5E, +0xD1,0x11,0x5D,0x5C,0x69,0xD0,0xAB,0xD3,0xB9,0x6A,0x4C,0x99,0x1F,0x59,0x98,0x30, +0x8E,0x16,0x85,0x20,0x46,0x6D,0x47,0x3F,0xD4,0x85,0x20,0x84,0xE1,0x6D,0xB3,0xF8, +0xA4,0xED,0x0C,0xF1,0x17,0x0F,0x3B,0xF9,0xA7,0xF9,0x25,0xD7,0xC1,0xCF,0x84,0x63, +0xF2,0x7C,0x63,0xCF,0xA2,0x47,0xF2,0xC6,0x5B,0x33,0x8E,0x64,0x40,0x04,0x68,0xC1, +0x80,0xB9,0x64,0x1C,0x45,0x77,0xC7,0xD8,0x6E,0xF5,0x95,0x29,0x3C,0x50,0xE8,0x34, +0xD7,0x78,0x1F,0xA8,0xBA,0x6D,0x43,0x91,0x95,0x8F,0x45,0x57,0x5E,0x7E,0xC5,0xFB, +0xCA,0xA4,0x04,0xEB,0xEA,0x97,0x37,0x54,0x30,0x6F,0xBB,0x01,0x47,0x32,0x33,0xCD, +0xDC,0x57,0x9B,0x64,0x69,0x61,0xF8,0x9B,0x1D,0x1C,0x89,0x4F,0x5C,0x67,0x02,0x03, +0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x03,0x81,0x81,0x00,0x51,0x4D,0xCD,0xBE,0x5C,0xCB,0x98,0x19,0x9C,0x15, +0xB2,0x01,0x39,0x78,0x2E,0x4D,0x0F,0x67,0x70,0x70,0x99,0xC6,0x10,0x5A,0x94,0xA4, +0x53,0x4D,0x54,0x6D,0x2B,0xAF,0x0D,0x5D,0x40,0x8B,0x64,0xD3,0xD7,0xEE,0xDE,0x56, +0x61,0x92,0x5F,0xA6,0xC4,0x1D,0x10,0x61,0x36,0xD3,0x2C,0x27,0x3C,0xE8,0x29,0x09, +0xB9,0x11,0x64,0x74,0xCC,0xB5,0x73,0x9F,0x1C,0x48,0xA9,0xBC,0x61,0x01,0xEE,0xE2, +0x17,0xA6,0x0C,0xE3,0x40,0x08,0x3B,0x0E,0xE7,0xEB,0x44,0x73,0x2A,0x9A,0xF1,0x69, +0x92,0xEF,0x71,0x14,0xC3,0x39,0xAC,0x71,0xA7,0x91,0x09,0x6F,0xE4,0x71,0x06,0xB3, +0xBA,0x59,0x57,0x26,0x79,0x00,0xF6,0xF8,0x0D,0xA2,0x33,0x30,0x28,0xD4,0xAA,0x58, +0xA0,0x9D,0x9D,0x69,0x91,0xFD, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G3 */ +/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G3 */ + + +const unsigned char Verisign_Class_3_Public_Primary_Certification_Authority___G3_certificate[1054]={ +0x30,0x82,0x04,0x1A,0x30,0x82,0x03,0x02,0x02,0x11,0x00,0x9B,0x7E,0x06,0x49,0xA3, +0x3E,0x62,0xB9,0xD5,0xEE,0x90,0x48,0x71,0x29,0xEF,0x57,0x30,0x0D,0x06,0x09,0x2A, +0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xCA,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, +0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65, +0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74, +0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28, +0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74, +0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79, +0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53, +0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C, +0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x20,0x2D,0x20,0x47,0x33,0x30,0x1E,0x17,0x0D,0x39,0x39,0x31,0x30,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x37,0x31,0x36, +0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xCA,0x31,0x0B,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A, +0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E, +0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69,0x53, +0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, +0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29,0x20, +0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, +0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72, +0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x45,0x30, +0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, +0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20, +0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, +0x2D,0x20,0x47,0x33,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xCB,0xBA,0x9C,0x52,0xFC,0x78,0x1F,0x1A,0x1E,0x6F,0x1B, +0x37,0x73,0xBD,0xF8,0xC9,0x6B,0x94,0x12,0x30,0x4F,0xF0,0x36,0x47,0xF5,0xD0,0x91, +0x0A,0xF5,0x17,0xC8,0xA5,0x61,0xC1,0x16,0x40,0x4D,0xFB,0x8A,0x61,0x90,0xE5,0x76, +0x20,0xC1,0x11,0x06,0x7D,0xAB,0x2C,0x6E,0xA6,0xF5,0x11,0x41,0x8E,0xFA,0x2D,0xAD, +0x2A,0x61,0x59,0xA4,0x67,0x26,0x4C,0xD0,0xE8,0xBC,0x52,0x5B,0x70,0x20,0x04,0x58, +0xD1,0x7A,0xC9,0xA4,0x69,0xBC,0x83,0x17,0x64,0xAD,0x05,0x8B,0xBC,0xD0,0x58,0xCE, +0x8D,0x8C,0xF5,0xEB,0xF0,0x42,0x49,0x0B,0x9D,0x97,0x27,0x67,0x32,0x6E,0xE1,0xAE, +0x93,0x15,0x1C,0x70,0xBC,0x20,0x4D,0x2F,0x18,0xDE,0x92,0x88,0xE8,0x6C,0x85,0x57, +0x11,0x1A,0xE9,0x7E,0xE3,0x26,0x11,0x54,0xA2,0x45,0x96,0x55,0x83,0xCA,0x30,0x89, +0xE8,0xDC,0xD8,0xA3,0xED,0x2A,0x80,0x3F,0x7F,0x79,0x65,0x57,0x3E,0x15,0x20,0x66, +0x08,0x2F,0x95,0x93,0xBF,0xAA,0x47,0x2F,0xA8,0x46,0x97,0xF0,0x12,0xE2,0xFE,0xC2, +0x0A,0x2B,0x51,0xE6,0x76,0xE6,0xB7,0x46,0xB7,0xE2,0x0D,0xA6,0xCC,0xA8,0xC3,0x4C, +0x59,0x55,0x89,0xE6,0xE8,0x53,0x5C,0x1C,0xEA,0x9D,0xF0,0x62,0x16,0x0B,0xA7,0xC9, +0x5F,0x0C,0xF0,0xDE,0xC2,0x76,0xCE,0xAF,0xF7,0x6A,0xF2,0xFA,0x41,0xA6,0xA2,0x33, +0x14,0xC9,0xE5,0x7A,0x63,0xD3,0x9E,0x62,0x37,0xD5,0x85,0x65,0x9E,0x0E,0xE6,0x53, +0x24,0x74,0x1B,0x5E,0x1D,0x12,0x53,0x5B,0xC7,0x2C,0xE7,0x83,0x49,0x3B,0x15,0xAE, +0x8A,0x68,0xB9,0x57,0x97,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x11,0x14, +0x96,0xC1,0xAB,0x92,0x08,0xF7,0x3F,0x2F,0xC9,0xB2,0xFE,0xE4,0x5A,0x9F,0x64,0xDE, +0xDB,0x21,0x4F,0x86,0x99,0x34,0x76,0x36,0x57,0xDD,0xD0,0x15,0x2F,0xC5,0xAD,0x7F, +0x15,0x1F,0x37,0x62,0x73,0x3E,0xD4,0xE7,0x5F,0xCE,0x17,0x03,0xDB,0x35,0xFA,0x2B, +0xDB,0xAE,0x60,0x09,0x5F,0x1E,0x5F,0x8F,0x6E,0xBB,0x0B,0x3D,0xEA,0x5A,0x13,0x1E, +0x0C,0x60,0x6F,0xB5,0xC0,0xB5,0x23,0x22,0x2E,0x07,0x0B,0xCB,0xA9,0x74,0xCB,0x47, +0xBB,0x1D,0xC1,0xD7,0xA5,0x6B,0xCC,0x2F,0xD2,0x42,0xFD,0x49,0xDD,0xA7,0x89,0xCF, +0x53,0xBA,0xDA,0x00,0x5A,0x28,0xBF,0x82,0xDF,0xF8,0xBA,0x13,0x1D,0x50,0x86,0x82, +0xFD,0x8E,0x30,0x8F,0x29,0x46,0xB0,0x1E,0x3D,0x35,0xDA,0x38,0x62,0x16,0x18,0x4A, +0xAD,0xE6,0xB6,0x51,0x6C,0xDE,0xAF,0x62,0xEB,0x01,0xD0,0x1E,0x24,0xFE,0x7A,0x8F, +0x12,0x1A,0x12,0x68,0xB8,0xFB,0x66,0x99,0x14,0x14,0x45,0x5C,0xAE,0xE7,0xAE,0x69, +0x17,0x81,0x2B,0x5A,0x37,0xC9,0x5E,0x2A,0xF4,0xC6,0xE2,0xA1,0x5C,0x54,0x9B,0xA6, +0x54,0x00,0xCF,0xF0,0xF1,0xC1,0xC7,0x98,0x30,0x1A,0x3B,0x36,0x16,0xDB,0xA3,0x6E, +0xEA,0xFD,0xAD,0xB2,0xC2,0xDA,0xEF,0x02,0x47,0x13,0x8A,0xC0,0xF1,0xB3,0x31,0xAD, +0x4F,0x1C,0xE1,0x4F,0x9C,0xAF,0x0F,0x0C,0x9D,0xF7,0x78,0x0D,0xD8,0xF4,0x35,0x56, +0x80,0xDA,0xB7,0x6D,0x17,0x8F,0x9D,0x1E,0x81,0x64,0xE1,0xFE,0xC5,0x45,0xBA,0xAD, +0x6B,0xB9,0x0A,0x7A,0x4E,0x4F,0x4B,0x84,0xEE,0x4B,0xF1,0x7D,0xDD,0x11, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2007 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G4 */ +/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2007 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G4 */ + + +const unsigned char VeriSign_Class_3_Public_Primary_Certification_Authority___G4_certificate[904]={ +0x30,0x82,0x03,0x84,0x30,0x82,0x03,0x0A,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x2F, +0x80,0xFE,0x23,0x8C,0x0E,0x22,0x0F,0x48,0x67,0x12,0x28,0x91,0x87,0xAC,0xB3,0x30, +0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x81,0xCA,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20, +0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56, +0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65, +0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31, +0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x37,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75, +0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C, +0x79,0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62, +0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x34,0x30,0x1E,0x17,0x0D,0x30,0x37,0x31,0x31, +0x30,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31, +0x38,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xCA,0x31,0x0B,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04, +0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63, +0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F, +0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29, +0x20,0x32,0x30,0x30,0x37,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20, +0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F, +0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x45, +0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6C,0x69,0x63, +0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69, +0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79, +0x20,0x2D,0x20,0x47,0x34,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D, +0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0xA7,0x56,0x7A, +0x7C,0x52,0xDA,0x64,0x9B,0x0E,0x2D,0x5C,0xD8,0x5E,0xAC,0x92,0x3D,0xFE,0x01,0xE6, +0x19,0x4A,0x3D,0x14,0x03,0x4B,0xFA,0x60,0x27,0x20,0xD9,0x83,0x89,0x69,0xFA,0x54, +0xC6,0x9A,0x18,0x5E,0x55,0x2A,0x64,0xDE,0x06,0xF6,0x8D,0x4A,0x3B,0xAD,0x10,0x3C, +0x65,0x3D,0x90,0x88,0x04,0x89,0xE0,0x30,0x61,0xB3,0xAE,0x5D,0x01,0xA7,0x7B,0xDE, +0x7C,0xB2,0xBE,0xCA,0x65,0x61,0x00,0x86,0xAE,0xDA,0x8F,0x7B,0xD0,0x89,0xAD,0x4D, +0x1D,0x59,0x9A,0x41,0xB1,0xBC,0x47,0x80,0xDC,0x9E,0x62,0xC3,0xF9,0xA3,0x81,0xB2, +0x30,0x81,0xAF,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30, +0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04, +0x03,0x02,0x01,0x06,0x30,0x6D,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0C, +0x04,0x61,0x30,0x5F,0xA1,0x5D,0xA0,0x5B,0x30,0x59,0x30,0x57,0x30,0x55,0x16,0x09, +0x69,0x6D,0x61,0x67,0x65,0x2F,0x67,0x69,0x66,0x30,0x21,0x30,0x1F,0x30,0x07,0x06, +0x05,0x2B,0x0E,0x03,0x02,0x1A,0x04,0x14,0x8F,0xE5,0xD3,0x1A,0x86,0xAC,0x8D,0x8E, +0x6B,0xC3,0xCF,0x80,0x6A,0xD4,0x48,0x18,0x2C,0x7B,0x19,0x2E,0x30,0x25,0x16,0x23, +0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6C,0x6F,0x67,0x6F,0x2E,0x76,0x65,0x72,0x69, +0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F,0x76,0x73,0x6C,0x6F,0x67,0x6F,0x2E, +0x67,0x69,0x66,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xB3,0x16, +0x91,0xFD,0xEE,0xA6,0x6E,0xE4,0xB5,0x2E,0x49,0x8F,0x87,0x78,0x81,0x80,0xEC,0xE5, +0xB1,0xB5,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x68, +0x00,0x30,0x65,0x02,0x30,0x66,0x21,0x0C,0x18,0x26,0x60,0x5A,0x38,0x7B,0x56,0x42, +0xE0,0xA7,0xFC,0x36,0x84,0x51,0x91,0x20,0x2C,0x76,0x4D,0x43,0x3D,0xC4,0x1D,0x84, +0x23,0xD0,0xAC,0xD6,0x7C,0x35,0x06,0xCE,0xCD,0x69,0xBD,0x90,0x0D,0xDB,0x6C,0x48, +0x42,0x1D,0x0E,0xAA,0x42,0x02,0x31,0x00,0x9C,0x3D,0x48,0x39,0x23,0x39,0x58,0x1A, +0x15,0x12,0x59,0x6A,0x9E,0xEF,0xD5,0x59,0xB2,0x1D,0x52,0x2C,0x99,0x71,0xCD,0xC7, +0x29,0xDF,0x1B,0x2A,0x61,0x7B,0x71,0xD1,0xDE,0xF3,0xC0,0xE5,0x0D,0x3A,0x4A,0xAA, +0x2D,0xA7,0xD8,0x86,0x2A,0xDD,0x2E,0x10, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5 */ +/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5 */ + + +const unsigned char VeriSign_Class_3_Public_Primary_Certification_Authority___G5_certificate[1239]={ +0x30,0x82,0x04,0xD3,0x30,0x82,0x03,0xBB,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x18, +0xDA,0xD1,0x9E,0x26,0x7D,0xE8,0xBB,0x4A,0x21,0x58,0xCD,0xCC,0x6B,0x3B,0x4A,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, +0xCA,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B, +0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74, +0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04, +0x0B,0x13,0x31,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72, +0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20, +0x6F,0x6E,0x6C,0x79,0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56, +0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20, +0x50,0x75,0x62,0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43, +0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74, +0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x35,0x30,0x1E,0x17,0x0D,0x30, +0x36,0x31,0x31,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36, +0x30,0x37,0x31,0x36,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xCA,0x31,0x0B, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06, +0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20, +0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56, +0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65, +0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31, +0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x36,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75, +0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C, +0x79,0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62, +0x6C,0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x20,0x2D,0x20,0x47,0x35,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00, +0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAF,0x24,0x08,0x08,0x29,0x7A,0x35, +0x9E,0x60,0x0C,0xAA,0xE7,0x4B,0x3B,0x4E,0xDC,0x7C,0xBC,0x3C,0x45,0x1C,0xBB,0x2B, +0xE0,0xFE,0x29,0x02,0xF9,0x57,0x08,0xA3,0x64,0x85,0x15,0x27,0xF5,0xF1,0xAD,0xC8, +0x31,0x89,0x5D,0x22,0xE8,0x2A,0xAA,0xA6,0x42,0xB3,0x8F,0xF8,0xB9,0x55,0xB7,0xB1, +0xB7,0x4B,0xB3,0xFE,0x8F,0x7E,0x07,0x57,0xEC,0xEF,0x43,0xDB,0x66,0x62,0x15,0x61, +0xCF,0x60,0x0D,0xA4,0xD8,0xDE,0xF8,0xE0,0xC3,0x62,0x08,0x3D,0x54,0x13,0xEB,0x49, +0xCA,0x59,0x54,0x85,0x26,0xE5,0x2B,0x8F,0x1B,0x9F,0xEB,0xF5,0xA1,0x91,0xC2,0x33, +0x49,0xD8,0x43,0x63,0x6A,0x52,0x4B,0xD2,0x8F,0xE8,0x70,0x51,0x4D,0xD1,0x89,0x69, +0x7B,0xC7,0x70,0xF6,0xB3,0xDC,0x12,0x74,0xDB,0x7B,0x5D,0x4B,0x56,0xD3,0x96,0xBF, +0x15,0x77,0xA1,0xB0,0xF4,0xA2,0x25,0xF2,0xAF,0x1C,0x92,0x67,0x18,0xE5,0xF4,0x06, +0x04,0xEF,0x90,0xB9,0xE4,0x00,0xE4,0xDD,0x3A,0xB5,0x19,0xFF,0x02,0xBA,0xF4,0x3C, +0xEE,0xE0,0x8B,0xEB,0x37,0x8B,0xEC,0xF4,0xD7,0xAC,0xF2,0xF6,0xF0,0x3D,0xAF,0xDD, +0x75,0x91,0x33,0x19,0x1D,0x1C,0x40,0xCB,0x74,0x24,0x19,0x21,0x93,0xD9,0x14,0xFE, +0xAC,0x2A,0x52,0xC7,0x8F,0xD5,0x04,0x49,0xE4,0x8D,0x63,0x47,0x88,0x3C,0x69,0x83, +0xCB,0xFE,0x47,0xBD,0x2B,0x7E,0x4F,0xC5,0x95,0xAE,0x0E,0x9D,0xD4,0xD1,0x43,0xC0, +0x67,0x73,0xE3,0x14,0x08,0x7E,0xE5,0x3F,0x9F,0x73,0xB8,0x33,0x0A,0xCF,0x5D,0x3F, +0x34,0x87,0x96,0x8A,0xEE,0x53,0xE8,0x25,0x15,0x02,0x03,0x01,0x00,0x01,0xA3,0x81, +0xB2,0x30,0x81,0xAF,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05, +0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04, +0x04,0x03,0x02,0x01,0x06,0x30,0x6D,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01, +0x0C,0x04,0x61,0x30,0x5F,0xA1,0x5D,0xA0,0x5B,0x30,0x59,0x30,0x57,0x30,0x55,0x16, +0x09,0x69,0x6D,0x61,0x67,0x65,0x2F,0x67,0x69,0x66,0x30,0x21,0x30,0x1F,0x30,0x07, +0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x04,0x14,0x8F,0xE5,0xD3,0x1A,0x86,0xAC,0x8D, +0x8E,0x6B,0xC3,0xCF,0x80,0x6A,0xD4,0x48,0x18,0x2C,0x7B,0x19,0x2E,0x30,0x25,0x16, +0x23,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6C,0x6F,0x67,0x6F,0x2E,0x76,0x65,0x72, +0x69,0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F,0x76,0x73,0x6C,0x6F,0x67,0x6F, +0x2E,0x67,0x69,0x66,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x7F, +0xD3,0x65,0xA7,0xC2,0xDD,0xEC,0xBB,0xF0,0x30,0x09,0xF3,0x43,0x39,0xFA,0x02,0xAF, +0x33,0x31,0x33,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, +0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x93,0x24,0x4A,0x30,0x5F,0x62,0xCF,0xD8,0x1A, +0x98,0x2F,0x3D,0xEA,0xDC,0x99,0x2D,0xBD,0x77,0xF6,0xA5,0x79,0x22,0x38,0xEC,0xC4, +0xA7,0xA0,0x78,0x12,0xAD,0x62,0x0E,0x45,0x70,0x64,0xC5,0xE7,0x97,0x66,0x2D,0x98, +0x09,0x7E,0x5F,0xAF,0xD6,0xCC,0x28,0x65,0xF2,0x01,0xAA,0x08,0x1A,0x47,0xDE,0xF9, +0xF9,0x7C,0x92,0x5A,0x08,0x69,0x20,0x0D,0xD9,0x3E,0x6D,0x6E,0x3C,0x0D,0x6E,0xD8, +0xE6,0x06,0x91,0x40,0x18,0xB9,0xF8,0xC1,0xED,0xDF,0xDB,0x41,0xAA,0xE0,0x96,0x20, +0xC9,0xCD,0x64,0x15,0x38,0x81,0xC9,0x94,0xEE,0xA2,0x84,0x29,0x0B,0x13,0x6F,0x8E, +0xDB,0x0C,0xDD,0x25,0x02,0xDB,0xA4,0x8B,0x19,0x44,0xD2,0x41,0x7A,0x05,0x69,0x4A, +0x58,0x4F,0x60,0xCA,0x7E,0x82,0x6A,0x0B,0x02,0xAA,0x25,0x17,0x39,0xB5,0xDB,0x7F, +0xE7,0x84,0x65,0x2A,0x95,0x8A,0xBD,0x86,0xDE,0x5E,0x81,0x16,0x83,0x2D,0x10,0xCC, +0xDE,0xFD,0xA8,0x82,0x2A,0x6D,0x28,0x1F,0x0D,0x0B,0xC4,0xE5,0xE7,0x1A,0x26,0x19, +0xE1,0xF4,0x11,0x6F,0x10,0xB5,0x95,0xFC,0xE7,0x42,0x05,0x32,0xDB,0xCE,0x9D,0x51, +0x5E,0x28,0xB6,0x9E,0x85,0xD3,0x5B,0xEF,0xA5,0x7D,0x45,0x40,0x72,0x8E,0xB7,0x0E, +0x6B,0x0E,0x06,0xFB,0x33,0x35,0x48,0x71,0xB8,0x9D,0x27,0x8B,0xC4,0x65,0x5F,0x0D, +0x86,0x76,0x9C,0x44,0x7A,0xF6,0x95,0x5C,0xF6,0x5D,0x32,0x08,0x33,0xA4,0x54,0xB6, +0x18,0x3F,0x68,0x5C,0xF2,0x42,0x4A,0x85,0x38,0x54,0x83,0x5F,0xD1,0xE8,0x2C,0xF2, +0xAC,0x11,0xD6,0xA8,0xED,0x63,0x6A, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 4 Public Primary Certification Authority - G3 */ +/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 1999 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 4 Public Primary Certification Authority - G3 */ + + +const unsigned char Verisign_Class_4_Public_Primary_Certification_Authority___G3_certificate[1054]={ +0x30,0x82,0x04,0x1A,0x30,0x82,0x03,0x02,0x02,0x11,0x00,0xEC,0xA0,0xA7,0x8B,0x6E, +0x75,0x6A,0x01,0xCF,0xC4,0x7C,0xCC,0x2F,0x94,0x5E,0xD7,0x30,0x0D,0x06,0x09,0x2A, +0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0xCA,0x31,0x0B,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03, +0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, +0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65, +0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74, +0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28, +0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, +0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74, +0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79, +0x31,0x45,0x30,0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53, +0x69,0x67,0x6E,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x34,0x20,0x50,0x75,0x62,0x6C, +0x69,0x63,0x20,0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, +0x74,0x79,0x20,0x2D,0x20,0x47,0x33,0x30,0x1E,0x17,0x0D,0x39,0x39,0x31,0x30,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x36,0x30,0x37,0x31,0x36, +0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0xCA,0x31,0x0B,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0A, +0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E, +0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B,0x13,0x16,0x56,0x65,0x72,0x69,0x53, +0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72, +0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04,0x0B,0x13,0x31,0x28,0x63,0x29,0x20, +0x31,0x39,0x39,0x39,0x20,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x2C,0x20,0x49, +0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72,0x20,0x61,0x75,0x74,0x68,0x6F,0x72, +0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20,0x6F,0x6E,0x6C,0x79,0x31,0x45,0x30, +0x43,0x06,0x03,0x55,0x04,0x03,0x13,0x3C,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E, +0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x34,0x20,0x50,0x75,0x62,0x6C,0x69,0x63,0x20, +0x50,0x72,0x69,0x6D,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20, +0x2D,0x20,0x47,0x33,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, +0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A, +0x02,0x82,0x01,0x01,0x00,0xAD,0xCB,0xA5,0x11,0x69,0xC6,0x59,0xAB,0xF1,0x8F,0xB5, +0x19,0x0F,0x56,0xCE,0xCC,0xB5,0x1F,0x20,0xE4,0x9E,0x26,0x25,0x4B,0xE0,0x73,0x65, +0x89,0x59,0xDE,0xD0,0x83,0xE4,0xF5,0x0F,0xB5,0xBB,0xAD,0xF1,0x7C,0xE8,0x21,0xFC, +0xE4,0xE8,0x0C,0xEE,0x7C,0x45,0x22,0x19,0x76,0x92,0xB4,0x13,0xB7,0x20,0x5B,0x09, +0xFA,0x61,0xAE,0xA8,0xF2,0xA5,0x8D,0x85,0xC2,0x2A,0xD6,0xDE,0x66,0x36,0xD2,0x9B, +0x02,0xF4,0xA8,0x92,0x60,0x7C,0x9C,0x69,0xB4,0x8F,0x24,0x1E,0xD0,0x86,0x52,0xF6, +0x32,0x9C,0x41,0x58,0x1E,0x22,0xBD,0xCD,0x45,0x62,0x95,0x08,0x6E,0xD0,0x66,0xDD, +0x53,0xA2,0xCC,0xF0,0x10,0xDC,0x54,0x73,0x8B,0x04,0xA1,0x46,0x33,0x33,0x5C,0x17, +0x40,0xB9,0x9E,0x4D,0xD3,0xF3,0xBE,0x55,0x83,0xE8,0xB1,0x89,0x8E,0x5A,0x7C,0x9A, +0x96,0x22,0x90,0x3B,0x88,0x25,0xF2,0xD2,0x53,0x88,0x02,0x0C,0x0B,0x78,0xF2,0xE6, +0x37,0x17,0x4B,0x30,0x46,0x07,0xE4,0x80,0x6D,0xA6,0xD8,0x96,0x2E,0xE8,0x2C,0xF8, +0x11,0xB3,0x38,0x0D,0x66,0xA6,0x9B,0xEA,0xC9,0x23,0x5B,0xDB,0x8E,0xE2,0xF3,0x13, +0x8E,0x1A,0x59,0x2D,0xAA,0x02,0xF0,0xEC,0xA4,0x87,0x66,0xDC,0xC1,0x3F,0xF5,0xD8, +0xB9,0xF4,0xEC,0x82,0xC6,0xD2,0x3D,0x95,0x1D,0xE5,0xC0,0x4F,0x84,0xC9,0xD9,0xA3, +0x44,0x28,0x06,0x6A,0xD7,0x45,0xAC,0xF0,0x6B,0x6A,0xEF,0x4E,0x5F,0xF8,0x11,0x82, +0x1E,0x38,0x63,0x34,0x66,0x50,0xD4,0x3E,0x93,0x73,0xFA,0x30,0xC3,0x66,0xAD,0xFF, +0x93,0x2D,0x97,0xEF,0x03,0x02,0x03,0x01,0x00,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86, +0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x8F,0xFA, +0x25,0x6B,0x4F,0x5B,0xE4,0xA4,0x4E,0x27,0x55,0xAB,0x22,0x15,0x59,0x3C,0xCA,0xB5, +0x0A,0xD4,0x4A,0xDB,0xAB,0xDD,0xA1,0x5F,0x53,0xC5,0xA0,0x57,0x39,0xC2,0xCE,0x47, +0x2B,0xBE,0x3A,0xC8,0x56,0xBF,0xC2,0xD9,0x27,0x10,0x3A,0xB1,0x05,0x3C,0xC0,0x77, +0x31,0xBB,0x3A,0xD3,0x05,0x7B,0x6D,0x9A,0x1C,0x30,0x8C,0x80,0xCB,0x93,0x93,0x2A, +0x83,0xAB,0x05,0x51,0x82,0x02,0x00,0x11,0x67,0x6B,0xF3,0x88,0x61,0x47,0x5F,0x03, +0x93,0xD5,0x5B,0x0D,0xE0,0xF1,0xD4,0xA1,0x32,0x35,0x85,0xB2,0x3A,0xDB,0xB0,0x82, +0xAB,0xD1,0xCB,0x0A,0xBC,0x4F,0x8C,0x5B,0xC5,0x4B,0x00,0x3B,0x1F,0x2A,0x82,0xA6, +0x7E,0x36,0x85,0xDC,0x7E,0x3C,0x67,0x00,0xB5,0xE4,0x3B,0x52,0xE0,0xA8,0xEB,0x5D, +0x15,0xF9,0xC6,0x6D,0xF0,0xAD,0x1D,0x0E,0x85,0xB7,0xA9,0x9A,0x73,0x14,0x5A,0x5B, +0x8F,0x41,0x28,0xC0,0xD5,0xE8,0x2D,0x4D,0xA4,0x5E,0xCD,0xAA,0xD9,0xED,0xCE,0xDC, +0xD8,0xD5,0x3C,0x42,0x1D,0x17,0xC1,0x12,0x5D,0x45,0x38,0xC3,0x38,0xF3,0xFC,0x85, +0x2E,0x83,0x46,0x48,0xB2,0xD7,0x20,0x5F,0x92,0x36,0x8F,0xE7,0x79,0x0F,0x98,0x5E, +0x99,0xE8,0xF0,0xD0,0xA4,0xBB,0xF5,0x53,0xBD,0x2A,0xCE,0x59,0xB0,0xAF,0x6E,0x7F, +0x6C,0xBB,0xD2,0x1E,0x00,0xB0,0x21,0xED,0xF8,0x41,0x62,0x82,0xB9,0xD8,0xB2,0xC4, +0xBB,0x46,0x50,0xF3,0x31,0xC5,0x8F,0x01,0xA8,0x74,0xEB,0xF5,0x78,0x27,0xDA,0xE7, +0xF7,0x66,0x43,0xF3,0x9E,0x83,0x3E,0x20,0xAA,0xC3,0x35,0x60,0x91,0xCE, +}; + + +/* subject:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2008 VeriSign, Inc. - For authorized use only/CN=VeriSign Universal Root Certification Authority */ +/* issuer :/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2008 VeriSign, Inc. - For authorized use only/CN=VeriSign Universal Root Certification Authority */ + + +const unsigned char VeriSign_Universal_Root_Certification_Authority_certificate[1213]={ +0x30,0x82,0x04,0xB9,0x30,0x82,0x03,0xA1,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x40, +0x1A,0xC4,0x64,0x21,0xB3,0x13,0x21,0x03,0x0E,0xBB,0xE4,0x12,0x1A,0xC5,0x1D,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81, +0xBD,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B, +0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74, +0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04, +0x0B,0x13,0x31,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x38,0x20,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72, +0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20, +0x6F,0x6E,0x6C,0x79,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x03,0x13,0x2F,0x56, +0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61, +0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E, +0x17,0x0D,0x30,0x38,0x30,0x34,0x30,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17, +0x0D,0x33,0x37,0x31,0x32,0x30,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81, +0xBD,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0A,0x13,0x0E,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x0B, +0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75,0x73,0x74, +0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x3A,0x30,0x38,0x06,0x03,0x55,0x04, +0x0B,0x13,0x31,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x38,0x20,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6E,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x20,0x2D,0x20,0x46,0x6F,0x72, +0x20,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x7A,0x65,0x64,0x20,0x75,0x73,0x65,0x20, +0x6F,0x6E,0x6C,0x79,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x03,0x13,0x2F,0x56, +0x65,0x72,0x69,0x53,0x69,0x67,0x6E,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61, +0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82, +0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05, +0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC7, +0x61,0x37,0x5E,0xB1,0x01,0x34,0xDB,0x62,0xD7,0x15,0x9B,0xFF,0x58,0x5A,0x8C,0x23, +0x23,0xD6,0x60,0x8E,0x91,0xD7,0x90,0x98,0x83,0x7A,0xE6,0x58,0x19,0x38,0x8C,0xC5, +0xF6,0xE5,0x64,0x85,0xB4,0xA2,0x71,0xFB,0xED,0xBD,0xB9,0xDA,0xCD,0x4D,0x00,0xB4, +0xC8,0x2D,0x73,0xA5,0xC7,0x69,0x71,0x95,0x1F,0x39,0x3C,0xB2,0x44,0x07,0x9C,0xE8, +0x0E,0xFA,0x4D,0x4A,0xC4,0x21,0xDF,0x29,0x61,0x8F,0x32,0x22,0x61,0x82,0xC5,0x87, +0x1F,0x6E,0x8C,0x7C,0x5F,0x16,0x20,0x51,0x44,0xD1,0x70,0x4F,0x57,0xEA,0xE3,0x1C, +0xE3,0xCC,0x79,0xEE,0x58,0xD8,0x0E,0xC2,0xB3,0x45,0x93,0xC0,0x2C,0xE7,0x9A,0x17, +0x2B,0x7B,0x00,0x37,0x7A,0x41,0x33,0x78,0xE1,0x33,0xE2,0xF3,0x10,0x1A,0x7F,0x87, +0x2C,0xBE,0xF6,0xF5,0xF7,0x42,0xE2,0xE5,0xBF,0x87,0x62,0x89,0x5F,0x00,0x4B,0xDF, +0xC5,0xDD,0xE4,0x75,0x44,0x32,0x41,0x3A,0x1E,0x71,0x6E,0x69,0xCB,0x0B,0x75,0x46, +0x08,0xD1,0xCA,0xD2,0x2B,0x95,0xD0,0xCF,0xFB,0xB9,0x40,0x6B,0x64,0x8C,0x57,0x4D, +0xFC,0x13,0x11,0x79,0x84,0xED,0x5E,0x54,0xF6,0x34,0x9F,0x08,0x01,0xF3,0x10,0x25, +0x06,0x17,0x4A,0xDA,0xF1,0x1D,0x7A,0x66,0x6B,0x98,0x60,0x66,0xA4,0xD9,0xEF,0xD2, +0x2E,0x82,0xF1,0xF0,0xEF,0x09,0xEA,0x44,0xC9,0x15,0x6A,0xE2,0x03,0x6E,0x33,0xD3, +0xAC,0x9F,0x55,0x00,0xC7,0xF6,0x08,0x6A,0x94,0xB9,0x5F,0xDC,0xE0,0x33,0xF1,0x84, +0x60,0xF9,0x5B,0x27,0x11,0xB4,0xFC,0x16,0xF2,0xBB,0x56,0x6A,0x80,0x25,0x8D,0x02, +0x03,0x01,0x00,0x01,0xA3,0x81,0xB2,0x30,0x81,0xAF,0x30,0x0F,0x06,0x03,0x55,0x1D, +0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55, +0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x6D,0x06,0x08,0x2B, +0x06,0x01,0x05,0x05,0x07,0x01,0x0C,0x04,0x61,0x30,0x5F,0xA1,0x5D,0xA0,0x5B,0x30, +0x59,0x30,0x57,0x30,0x55,0x16,0x09,0x69,0x6D,0x61,0x67,0x65,0x2F,0x67,0x69,0x66, +0x30,0x21,0x30,0x1F,0x30,0x07,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x04,0x14,0x8F, +0xE5,0xD3,0x1A,0x86,0xAC,0x8D,0x8E,0x6B,0xC3,0xCF,0x80,0x6A,0xD4,0x48,0x18,0x2C, +0x7B,0x19,0x2E,0x30,0x25,0x16,0x23,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6C,0x6F, +0x67,0x6F,0x2E,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F, +0x76,0x73,0x6C,0x6F,0x67,0x6F,0x2E,0x67,0x69,0x66,0x30,0x1D,0x06,0x03,0x55,0x1D, +0x0E,0x04,0x16,0x04,0x14,0xB6,0x77,0xFA,0x69,0x48,0x47,0x9F,0x53,0x12,0xD5,0xC2, +0xEA,0x07,0x32,0x76,0x07,0xD1,0x97,0x07,0x19,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, +0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x4A,0xF8,0xF8, +0xB0,0x03,0xE6,0x2C,0x67,0x7B,0xE4,0x94,0x77,0x63,0xCC,0x6E,0x4C,0xF9,0x7D,0x0E, +0x0D,0xDC,0xC8,0xB9,0x35,0xB9,0x70,0x4F,0x63,0xFA,0x24,0xFA,0x6C,0x83,0x8C,0x47, +0x9D,0x3B,0x63,0xF3,0x9A,0xF9,0x76,0x32,0x95,0x91,0xB1,0x77,0xBC,0xAC,0x9A,0xBE, +0xB1,0xE4,0x31,0x21,0xC6,0x81,0x95,0x56,0x5A,0x0E,0xB1,0xC2,0xD4,0xB1,0xA6,0x59, +0xAC,0xF1,0x63,0xCB,0xB8,0x4C,0x1D,0x59,0x90,0x4A,0xEF,0x90,0x16,0x28,0x1F,0x5A, +0xAE,0x10,0xFB,0x81,0x50,0x38,0x0C,0x6C,0xCC,0xF1,0x3D,0xC3,0xF5,0x63,0xE3,0xB3, +0xE3,0x21,0xC9,0x24,0x39,0xE9,0xFD,0x15,0x66,0x46,0xF4,0x1B,0x11,0xD0,0x4D,0x73, +0xA3,0x7D,0x46,0xF9,0x3D,0xED,0xA8,0x5F,0x62,0xD4,0xF1,0x3F,0xF8,0xE0,0x74,0x57, +0x2B,0x18,0x9D,0x81,0xB4,0xC4,0x28,0xDA,0x94,0x97,0xA5,0x70,0xEB,0xAC,0x1D,0xBE, +0x07,0x11,0xF0,0xD5,0xDB,0xDD,0xE5,0x8C,0xF0,0xD5,0x32,0xB0,0x83,0xE6,0x57,0xE2, +0x8F,0xBF,0xBE,0xA1,0xAA,0xBF,0x3D,0x1D,0xB5,0xD4,0x38,0xEA,0xD7,0xB0,0x5C,0x3A, +0x4F,0x6A,0x3F,0x8F,0xC0,0x66,0x6C,0x63,0xAA,0xE9,0xD9,0xA4,0x16,0xF4,0x81,0xD1, +0x95,0x14,0x0E,0x7D,0xCD,0x95,0x34,0xD9,0xD2,0x8F,0x70,0x73,0x81,0x7B,0x9C,0x7E, +0xBD,0x98,0x61,0xD8,0x45,0x87,0x98,0x90,0xC5,0xEB,0x86,0x30,0xC6,0x35,0xBF,0xF0, +0xFF,0xC3,0x55,0x88,0x83,0x4B,0xEF,0x05,0x92,0x06,0x71,0xF2,0xB8,0x98,0x93,0xB7, +0xEC,0xCD,0x82,0x61,0xF1,0x38,0xE6,0x4F,0x97,0x98,0x2A,0x5A,0x8D, +}; + + +/* subject:/C=US/OU=www.xrampsecurity.com/O=XRamp Security Services Inc/CN=XRamp Global Certification Authority */ +/* issuer :/C=US/OU=www.xrampsecurity.com/O=XRamp Security Services Inc/CN=XRamp Global Certification Authority */ + + +const unsigned char XRamp_Global_CA_Root_certificate[1076]={ +0x30,0x82,0x04,0x30,0x30,0x82,0x03,0x18,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x50, +0x94,0x6C,0xEC,0x18,0xEA,0xD5,0x9C,0x4D,0xD5,0x97,0xEF,0x75,0x8F,0xA0,0xAD,0x30, +0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81, +0x82,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1E, +0x30,0x1C,0x06,0x03,0x55,0x04,0x0B,0x13,0x15,0x77,0x77,0x77,0x2E,0x78,0x72,0x61, +0x6D,0x70,0x73,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x2E,0x63,0x6F,0x6D,0x31,0x24, +0x30,0x22,0x06,0x03,0x55,0x04,0x0A,0x13,0x1B,0x58,0x52,0x61,0x6D,0x70,0x20,0x53, +0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, +0x20,0x49,0x6E,0x63,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x03,0x13,0x24,0x58, +0x52,0x61,0x6D,0x70,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, +0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x30,0x34,0x31,0x31,0x30,0x31,0x31,0x37,0x31, +0x34,0x30,0x34,0x5A,0x17,0x0D,0x33,0x35,0x30,0x31,0x30,0x31,0x30,0x35,0x33,0x37, +0x31,0x39,0x5A,0x30,0x81,0x82,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, +0x02,0x55,0x53,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0B,0x13,0x15,0x77,0x77, +0x77,0x2E,0x78,0x72,0x61,0x6D,0x70,0x73,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x2E, +0x63,0x6F,0x6D,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0A,0x13,0x1B,0x58,0x52, +0x61,0x6D,0x70,0x20,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x53,0x65,0x72, +0x76,0x69,0x63,0x65,0x73,0x20,0x49,0x6E,0x63,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55, +0x04,0x03,0x13,0x24,0x58,0x52,0x61,0x6D,0x70,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, +0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09, +0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00, +0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0x98,0x24,0x1E,0xBD,0x15,0xB4,0xBA, +0xDF,0xC7,0x8C,0xA5,0x27,0xB6,0x38,0x0B,0x69,0xF3,0xB6,0x4E,0xA8,0x2C,0x2E,0x21, +0x1D,0x5C,0x44,0xDF,0x21,0x5D,0x7E,0x23,0x74,0xFE,0x5E,0x7E,0xB4,0x4A,0xB7,0xA6, +0xAD,0x1F,0xAE,0xE0,0x06,0x16,0xE2,0x9B,0x5B,0xD9,0x67,0x74,0x6B,0x5D,0x80,0x8F, +0x29,0x9D,0x86,0x1B,0xD9,0x9C,0x0D,0x98,0x6D,0x76,0x10,0x28,0x58,0xE4,0x65,0xB0, +0x7F,0x4A,0x98,0x79,0x9F,0xE0,0xC3,0x31,0x7E,0x80,0x2B,0xB5,0x8C,0xC0,0x40,0x3B, +0x11,0x86,0xD0,0xCB,0xA2,0x86,0x36,0x60,0xA4,0xD5,0x30,0x82,0x6D,0xD9,0x6E,0xD0, +0x0F,0x12,0x04,0x33,0x97,0x5F,0x4F,0x61,0x5A,0xF0,0xE4,0xF9,0x91,0xAB,0xE7,0x1D, +0x3B,0xBC,0xE8,0xCF,0xF4,0x6B,0x2D,0x34,0x7C,0xE2,0x48,0x61,0x1C,0x8E,0xF3,0x61, +0x44,0xCC,0x6F,0xA0,0x4A,0xA9,0x94,0xB0,0x4D,0xDA,0xE7,0xA9,0x34,0x7A,0x72,0x38, +0xA8,0x41,0xCC,0x3C,0x94,0x11,0x7D,0xEB,0xC8,0xA6,0x8C,0xB7,0x86,0xCB,0xCA,0x33, +0x3B,0xD9,0x3D,0x37,0x8B,0xFB,0x7A,0x3E,0x86,0x2C,0xE7,0x73,0xD7,0x0A,0x57,0xAC, +0x64,0x9B,0x19,0xEB,0xF4,0x0F,0x04,0x08,0x8A,0xAC,0x03,0x17,0x19,0x64,0xF4,0x5A, +0x25,0x22,0x8D,0x34,0x2C,0xB2,0xF6,0x68,0x1D,0x12,0x6D,0xD3,0x8A,0x1E,0x14,0xDA, +0xC4,0x8F,0xA6,0xE2,0x23,0x85,0xD5,0x7A,0x0D,0xBD,0x6A,0xE0,0xE9,0xEC,0xEC,0x17, +0xBB,0x42,0x1B,0x67,0xAA,0x25,0xED,0x45,0x83,0x21,0xFC,0xC1,0xC9,0x7C,0xD5,0x62, +0x3E,0xFA,0xF2,0xC5,0x2D,0xD3,0xFD,0xD4,0x65,0x02,0x03,0x01,0x00,0x01,0xA3,0x81, +0x9F,0x30,0x81,0x9C,0x30,0x13,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x14, +0x02,0x04,0x06,0x1E,0x04,0x00,0x43,0x00,0x41,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F, +0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, +0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, +0x04,0x14,0xC6,0x4F,0xA2,0x3D,0x06,0x63,0x84,0x09,0x9C,0xCE,0x62,0xE4,0x04,0xAC, +0x8D,0x5C,0xB5,0xE9,0xB6,0x1B,0x30,0x36,0x06,0x03,0x55,0x1D,0x1F,0x04,0x2F,0x30, +0x2D,0x30,0x2B,0xA0,0x29,0xA0,0x27,0x86,0x25,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F, +0x63,0x72,0x6C,0x2E,0x78,0x72,0x61,0x6D,0x70,0x73,0x65,0x63,0x75,0x72,0x69,0x74, +0x79,0x2E,0x63,0x6F,0x6D,0x2F,0x58,0x47,0x43,0x41,0x2E,0x63,0x72,0x6C,0x30,0x10, +0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x01,0x04,0x03,0x02,0x01,0x01, +0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03, +0x82,0x01,0x01,0x00,0x91,0x15,0x39,0x03,0x01,0x1B,0x67,0xFB,0x4A,0x1C,0xF9,0x0A, +0x60,0x5B,0xA1,0xDA,0x4D,0x97,0x62,0xF9,0x24,0x53,0x27,0xD7,0x82,0x64,0x4E,0x90, +0x2E,0xC3,0x49,0x1B,0x2B,0x9A,0xDC,0xFC,0xA8,0x78,0x67,0x35,0xF1,0x1D,0xF0,0x11, +0xBD,0xB7,0x48,0xE3,0x10,0xF6,0x0D,0xDF,0x3F,0xD2,0xC9,0xB6,0xAA,0x55,0xA4,0x48, +0xBA,0x02,0xDB,0xDE,0x59,0x2E,0x15,0x5B,0x3B,0x9D,0x16,0x7D,0x47,0xD7,0x37,0xEA, +0x5F,0x4D,0x76,0x12,0x36,0xBB,0x1F,0xD7,0xA1,0x81,0x04,0x46,0x20,0xA3,0x2C,0x6D, +0xA9,0x9E,0x01,0x7E,0x3F,0x29,0xCE,0x00,0x93,0xDF,0xFD,0xC9,0x92,0x73,0x89,0x89, +0x64,0x9E,0xE7,0x2B,0xE4,0x1C,0x91,0x2C,0xD2,0xB9,0xCE,0x7D,0xCE,0x6F,0x31,0x99, +0xD3,0xE6,0xBE,0xD2,0x1E,0x90,0xF0,0x09,0x14,0x79,0x5C,0x23,0xAB,0x4D,0xD2,0xDA, +0x21,0x1F,0x4D,0x99,0x79,0x9D,0xE1,0xCF,0x27,0x9F,0x10,0x9B,0x1C,0x88,0x0D,0xB0, +0x8A,0x64,0x41,0x31,0xB8,0x0E,0x6C,0x90,0x24,0xA4,0x9B,0x5C,0x71,0x8F,0xBA,0xBB, +0x7E,0x1C,0x1B,0xDB,0x6A,0x80,0x0F,0x21,0xBC,0xE9,0xDB,0xA6,0xB7,0x40,0xF4,0xB2, +0x8B,0xA9,0xB1,0xE4,0xEF,0x9A,0x1A,0xD0,0x3D,0x69,0x99,0xEE,0xA8,0x28,0xA3,0xE1, +0x3C,0xB3,0xF0,0xB2,0x11,0x9C,0xCF,0x7C,0x40,0xE6,0xDD,0xE7,0x43,0x7D,0xA2,0xD8, +0x3A,0xB5,0xA9,0x8D,0xF2,0x34,0x99,0xC4,0xD4,0x10,0xE1,0x06,0xFD,0x09,0x84,0x10, +0x3B,0xEE,0xC4,0x4C,0xF4,0xEC,0x27,0x7C,0x42,0xC2,0x74,0x7C,0x82,0x8A,0x09,0xC9, +0xB4,0x03,0x25,0xBC, +}; + + +const unsigned char* kSSLCertCertificateList[] = { + AddTrust_External_Root_certificate, + AddTrust_Low_Value_Services_Root_certificate, + AddTrust_Public_Services_Root_certificate, + AddTrust_Qualified_Certificates_Root_certificate, + AffirmTrust_Commercial_certificate, + AffirmTrust_Networking_certificate, + AffirmTrust_Premium_certificate, + AffirmTrust_Premium_ECC_certificate, + America_Online_Root_Certification_Authority_1_certificate, + America_Online_Root_Certification_Authority_2_certificate, + Baltimore_CyberTrust_Root_certificate, + Comodo_AAA_Services_root_certificate, + COMODO_Certification_Authority_certificate, + COMODO_ECC_Certification_Authority_certificate, + Comodo_Secure_Services_root_certificate, + Comodo_Trusted_Services_root_certificate, + Cybertrust_Global_Root_certificate, + DigiCert_Assured_ID_Root_CA_certificate, + DigiCert_Global_Root_CA_certificate, + DigiCert_High_Assurance_EV_Root_CA_certificate, + Entrust_net_Premium_2048_Secure_Server_CA_certificate, + Entrust_net_Secure_Server_CA_certificate, + Entrust_Root_Certification_Authority_certificate, + Equifax_Secure_CA_certificate, + Equifax_Secure_eBusiness_CA_1_certificate, + Equifax_Secure_eBusiness_CA_2_certificate, + Equifax_Secure_Global_eBusiness_CA_certificate, + GeoTrust_Global_CA_certificate, + GeoTrust_Global_CA_2_certificate, + GeoTrust_Primary_Certification_Authority_certificate, + GeoTrust_Primary_Certification_Authority___G2_certificate, + GeoTrust_Primary_Certification_Authority___G3_certificate, + GeoTrust_Universal_CA_certificate, + GeoTrust_Universal_CA_2_certificate, + GlobalSign_Root_CA_certificate, + GlobalSign_Root_CA___R2_certificate, + GlobalSign_Root_CA___R3_certificate, + Go_Daddy_Class_2_CA_certificate, + Go_Daddy_Root_Certificate_Authority___G2_certificate, + GTE_CyberTrust_Global_Root_certificate, + Network_Solutions_Certificate_Authority_certificate, + RSA_Root_Certificate_1_certificate, + Starfield_Class_2_CA_certificate, + Starfield_Root_Certificate_Authority___G2_certificate, + Starfield_Services_Root_Certificate_Authority___G2_certificate, + StartCom_Certification_Authority_certificate, + StartCom_Certification_Authority_G2_certificate, + TC_TrustCenter_Class_2_CA_II_certificate, + TC_TrustCenter_Class_3_CA_II_certificate, + TC_TrustCenter_Universal_CA_I_certificate, + TC_TrustCenter_Universal_CA_III_certificate, + Thawte_Premium_Server_CA_certificate, + thawte_Primary_Root_CA_certificate, + thawte_Primary_Root_CA___G2_certificate, + thawte_Primary_Root_CA___G3_certificate, + Thawte_Server_CA_certificate, + UTN_DATACorp_SGC_Root_CA_certificate, + UTN_USERFirst_Hardware_Root_CA_certificate, + ValiCert_Class_1_VA_certificate, + ValiCert_Class_2_VA_certificate, + Verisign_Class_3_Public_Primary_Certification_Authority_certificate, + Verisign_Class_3_Public_Primary_Certification_Authority___G2_certificate, + Verisign_Class_3_Public_Primary_Certification_Authority___G3_certificate, + VeriSign_Class_3_Public_Primary_Certification_Authority___G4_certificate, + VeriSign_Class_3_Public_Primary_Certification_Authority___G5_certificate, + Verisign_Class_4_Public_Primary_Certification_Authority___G3_certificate, + VeriSign_Universal_Root_Certification_Authority_certificate, + XRamp_Global_CA_Root_certificate, +}; + +const size_t kSSLCertCertificateSizeList[] = { + 1082, + 1052, + 1049, + 1058, + 848, + 848, + 1354, + 514, + 936, + 1448, + 891, + 1078, + 1057, + 653, + 1091, + 1095, + 933, + 955, + 947, + 969, + 1120, + 1244, + 1173, + 804, + 646, + 804, + 660, + 856, + 874, + 896, + 690, + 1026, + 1388, + 1392, + 889, + 958, + 867, + 1028, + 969, + 606, + 1002, + 747, + 1043, + 993, + 1011, + 1931, + 1383, + 1198, + 1198, + 993, + 997, + 811, + 1060, + 652, + 1070, + 791, + 1122, + 1144, + 747, + 747, + 576, + 774, + 1054, + 904, + 1239, + 1054, + 1213, + 1076, +}; + diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sslsocketfactory.h b/thirdparties/common/include/webrtc-sdk/talk/base/sslsocketfactory.h new file mode 100644 index 0000000..e6ec318 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sslsocketfactory.h @@ -0,0 +1,98 @@ +/* + * libjingle + * Copyright 2007, 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_SSLSOCKETFACTORY_H__ +#define TALK_BASE_SSLSOCKETFACTORY_H__ + +#include "talk/base/proxyinfo.h" +#include "talk/base/socketserver.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// SslSocketFactory +/////////////////////////////////////////////////////////////////////////////// + +class SslSocketFactory : public SocketFactory { + public: + SslSocketFactory(SocketFactory* factory, const std::string& user_agent) + : factory_(factory), agent_(user_agent), autodetect_proxy_(true), + force_connect_(false), logging_level_(LS_VERBOSE), binary_mode_(false), + ignore_bad_cert_(false) { + } + + void SetAutoDetectProxy() { + autodetect_proxy_ = true; + } + void SetForceConnect(bool force) { + force_connect_ = force; + } + void SetProxy(const ProxyInfo& proxy) { + autodetect_proxy_ = false; + proxy_ = proxy; + } + bool autodetect_proxy() const { return autodetect_proxy_; } + const ProxyInfo& proxy() const { return proxy_; } + + void UseSSL(const char* hostname) { hostname_ = hostname; } + void DisableSSL() { hostname_.clear(); } + void SetIgnoreBadCert(bool ignore) { ignore_bad_cert_ = ignore; } + bool ignore_bad_cert() const { return ignore_bad_cert_; } + + void SetLogging(LoggingSeverity level, const std::string& label, + bool binary_mode = false) { + logging_level_ = level; + logging_label_ = label; + binary_mode_ = binary_mode; + } + + // SocketFactory Interface + virtual Socket* CreateSocket(int type); + virtual Socket* CreateSocket(int family, int type); + + virtual AsyncSocket* CreateAsyncSocket(int type); + virtual AsyncSocket* CreateAsyncSocket(int family, int type); + + private: + friend class ProxySocketAdapter; + AsyncSocket* CreateProxySocket(const ProxyInfo& proxy, int family, int type); + + SocketFactory* factory_; + std::string agent_; + bool autodetect_proxy_, force_connect_; + ProxyInfo proxy_; + std::string hostname_, logging_label_; + LoggingSeverity logging_level_; + bool binary_mode_; + bool ignore_bad_cert_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_SSLSOCKETFACTORY_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sslstreamadapter.h b/thirdparties/common/include/webrtc-sdk/talk/base/sslstreamadapter.h new file mode 100644 index 0000000..856eeb0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sslstreamadapter.h @@ -0,0 +1,179 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_SSLSTREAMADAPTER_H_ +#define TALK_BASE_SSLSTREAMADAPTER_H_ + +#include +#include + +#include "talk/base/stream.h" +#include "talk/base/sslidentity.h" + +namespace talk_base { + +// SSLStreamAdapter : A StreamInterfaceAdapter that does SSL/TLS. +// After SSL has been started, the stream will only open on successful +// SSL verification of certificates, and the communication is +// encrypted of course. +// +// This class was written with SSLAdapter as a starting point. It +// offers a similar interface, with two differences: there is no +// support for a restartable SSL connection, and this class has a +// peer-to-peer mode. +// +// The SSL library requires initialization and cleanup. Static method +// for doing this are in SSLAdapter. They should possibly be moved out +// to a neutral class. + + +enum SSLRole { SSL_CLIENT, SSL_SERVER }; +enum SSLMode { SSL_MODE_TLS, SSL_MODE_DTLS }; + +// Errors for Read -- in the high range so no conflict with OpenSSL. +enum { SSE_MSG_TRUNC = 0xff0001 }; + +class SSLStreamAdapter : public StreamAdapterInterface { + public: + // Instantiate an SSLStreamAdapter wrapping the given stream, + // (using the selected implementation for the platform). + // Caller is responsible for freeing the returned object. + static SSLStreamAdapter* Create(StreamInterface* stream); + + explicit SSLStreamAdapter(StreamInterface* stream) + : StreamAdapterInterface(stream), ignore_bad_cert_(false) { } + + void set_ignore_bad_cert(bool ignore) { ignore_bad_cert_ = ignore; } + bool ignore_bad_cert() const { return ignore_bad_cert_; } + + // Specify our SSL identity: key and certificate. Mostly this is + // only used in the peer-to-peer mode (unless we actually want to + // provide a client certificate to a server). + // SSLStream takes ownership of the SSLIdentity object and will + // free it when appropriate. Should be called no more than once on a + // given SSLStream instance. + virtual void SetIdentity(SSLIdentity* identity) = 0; + + // Call this to indicate that we are to play the server's role in + // the peer-to-peer mode. + // The default argument is for backward compatibility + // TODO(ekr@rtfm.com): rename this SetRole to reflect its new function + virtual void SetServerRole(SSLRole role = SSL_SERVER) = 0; + + // Do DTLS or TLS + virtual void SetMode(SSLMode mode) = 0; + + // The mode of operation is selected by calling either + // StartSSLWithServer or StartSSLWithPeer. + // Use of the stream prior to calling either of these functions will + // pass data in clear text. + // Calling one of these functions causes SSL negotiation to begin as + // soon as possible: right away if the underlying wrapped stream is + // already opened, or else as soon as it opens. + // + // These functions return a negative error code on failure. + // Returning 0 means success so far, but negotiation is probably not + // complete and will continue asynchronously. In that case, the + // exposed stream will open after successful negotiation and + // verification, or an SE_CLOSE event will be raised if negotiation + // fails. + + // StartSSLWithServer starts SSL negotiation with a server in + // traditional mode. server_name specifies the expected server name + // which the server's certificate needs to specify. + virtual int StartSSLWithServer(const char* server_name) = 0; + + // StartSSLWithPeer starts negotiation in the special peer-to-peer + // mode. + // Generally, SetIdentity() and possibly SetServerRole() should have + // been called before this. + // SetPeerCertificate() or SetPeerCertificateDigest() must also be called. + // It may be called after StartSSLWithPeer() but must be called before the + // underlying stream opens. + virtual int StartSSLWithPeer() = 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 + // obtained through some other secure channel (such as the XMPP + // channel). Unlike SetPeerCertificate(), this must specify the + // terminal certificate, not just a CA. + // SSLStream makes a copy of the digest value. + virtual bool SetPeerCertificateDigest(const std::string& digest_alg, + const unsigned char* digest_val, + size_t digest_len) = 0; + + // 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 + // Arguments are: + // label -- the exporter label. + // part of the RFC defining each exporter + // usage (IN) + // context/context_len -- a context to bind to for this connection; + // optional, can be NULL, 0 (IN) + // use_context -- whether to use the context value + // (needed to distinguish no context from + // zero-length ones). + // result -- where to put the computed value + // result_len -- the length of the computed value + virtual bool ExportKeyingMaterial(const std::string& label, + const uint8* context, + size_t context_len, + bool use_context, + uint8* result, + size_t result_len) { + return false; // Default is unsupported + } + + + // DTLS-SRTP interface + virtual bool SetDtlsSrtpCiphers(const std::vector& ciphers) { + return false; + } + + virtual bool GetDtlsSrtpCipher(std::string* cipher) { + return false; + } + + // Capabilities testing + static bool HaveDtls(); + static bool HaveDtlsSrtp(); + static bool HaveExporter(); + + // If true, the server certificate need not match the configured + // server_name, and in fact missing certificate authority and other + // verification errors are ignored. + bool ignore_bad_cert_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_SSLSTREAMADAPTER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/sslstreamadapterhelper.h b/thirdparties/common/include/webrtc-sdk/talk/base/sslstreamadapterhelper.h new file mode 100644 index 0000000..ad4e870 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/sslstreamadapterhelper.h @@ -0,0 +1,135 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_SSLSTREAMADAPTERHELPER_H_ +#define TALK_BASE_SSLSTREAMADAPTERHELPER_H_ + +#include +#include + +#include "talk/base/buffer.h" +#include "talk/base/stream.h" +#include "talk/base/sslidentity.h" +#include "talk/base/sslstreamadapter.h" + +namespace talk_base { + +// SSLStreamAdapterHelper : A stream adapter which implements much +// of the logic that is common between the known implementations +// (NSS and OpenSSL) +class SSLStreamAdapterHelper : public SSLStreamAdapter { + public: + explicit SSLStreamAdapterHelper(StreamInterface* stream) + : SSLStreamAdapter(stream), + state_(SSL_NONE), + role_(SSL_CLIENT), + ssl_error_code_(0), // Not meaningful yet + ssl_mode_(SSL_MODE_TLS) {} + + + // Overrides of SSLStreamAdapter + virtual void SetIdentity(SSLIdentity* identity); + virtual void SetServerRole(SSLRole role = SSL_SERVER); + virtual void SetMode(SSLMode mode); + + virtual int StartSSLWithServer(const char* server_name); + virtual int StartSSLWithPeer(); + + virtual bool SetPeerCertificateDigest(const std::string& digest_alg, + const unsigned char* digest_val, + size_t digest_len); + virtual bool GetPeerCertificate(SSLCertificate** cert) const; + virtual StreamState GetState() const; + virtual void Close(); + + protected: + // Internal helper methods + // The following method returns 0 on success and a negative + // error code on failure. The error code may be either -1 or + // from the impl on some other error cases, so it can't really be + // interpreted unfortunately. + + // Perform SSL negotiation steps. + int ContinueSSL(); + + // Error handler helper. signal is given as true for errors in + // asynchronous contexts (when an error code was not returned + // through some other method), and in that case an SE_CLOSE event is + // raised on the stream with the specified error. + // A 0 error means a graceful close, otherwise there is not really enough + // context to interpret the error code. + virtual void Error(const char* context, int err, bool signal); + + // Must be implemented by descendents + virtual int BeginSSL() = 0; + virtual void Cleanup() = 0; + virtual bool GetDigestLength(const std::string& algorithm, + size_t* length) = 0; + + enum SSLState { + // Before calling one of the StartSSL methods, data flows + // in clear text. + SSL_NONE, + SSL_WAIT, // waiting for the stream to open to start SSL negotiation + SSL_CONNECTING, // SSL negotiation in progress + SSL_CONNECTED, // SSL stream successfully established + SSL_ERROR, // some SSL error occurred, stream is closed + SSL_CLOSED // Clean close + }; + + // MSG_MAX is the maximum generic stream message number. + enum { MSG_DTLS_TIMEOUT = MSG_MAX + 1 }; + + SSLState state_; + SSLRole role_; + int ssl_error_code_; // valid when state_ == SSL_ERROR + + // Our key and certificate, mostly useful in peer-to-peer mode. + scoped_ptr identity_; + // in traditional mode, the server name that the server's certificate + // must specify. Empty in peer-to-peer mode. + std::string ssl_server_name_; + // The peer's certificate. Only used for GetPeerCertificate. + scoped_ptr peer_certificate_; + + // The digest of the certificate that the peer must present. + Buffer peer_certificate_digest_value_; + std::string peer_certificate_digest_algorithm_; + + // Do DTLS or not + SSLMode ssl_mode_; + + private: + // Go from state SSL_NONE to either SSL_CONNECTING or SSL_WAIT, + // depending on whether the underlying stream is already open or + // not. Returns 0 on success and a negative value on error. + int StartSSL(); +}; + +} // namespace talk_base + +#endif // TALK_BASE_SSLSTREAMADAPTERHELPER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/stream.h b/thirdparties/common/include/webrtc-sdk/talk/base/stream.h new file mode 100644 index 0000000..35935b8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/stream.h @@ -0,0 +1,837 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_STREAM_H_ +#define TALK_BASE_STREAM_H_ + +#include + +#include "talk/base/basictypes.h" +#include "talk/base/buffer.h" +#include "talk/base/criticalsection.h" +#include "talk/base/logging.h" +#include "talk/base/messagehandler.h" +#include "talk/base/messagequeue.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sigslot.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// StreamInterface is a generic asynchronous stream interface, supporting read, +// write, and close operations, and asynchronous signalling of state changes. +// The interface is designed with file, memory, and socket implementations in +// mind. Some implementations offer extended operations, such as seeking. +/////////////////////////////////////////////////////////////////////////////// + +// The following enumerations are declared outside of the StreamInterface +// class for brevity in use. + +// The SS_OPENING state indicates that the stream will signal open or closed +// in the future. +enum StreamState { SS_CLOSED, SS_OPENING, SS_OPEN }; + +// Stream read/write methods return this value to indicate various success +// and failure conditions described below. +enum StreamResult { SR_ERROR, SR_SUCCESS, SR_BLOCK, SR_EOS }; + +// StreamEvents are used to asynchronously signal state transitionss. The flags +// may be combined. +// SE_OPEN: The stream has transitioned to the SS_OPEN state +// SE_CLOSE: The stream has transitioned to the SS_CLOSED state +// SE_READ: Data is available, so Read is likely to not return SR_BLOCK +// SE_WRITE: Data can be written, so Write is likely to not return SR_BLOCK +enum StreamEvent { SE_OPEN = 1, SE_READ = 2, SE_WRITE = 4, SE_CLOSE = 8 }; + +class Thread; + +struct StreamEventData : public MessageData { + int events, error; + StreamEventData(int ev, int er) : events(ev), error(er) { } +}; + +class StreamInterface : public MessageHandler { + public: + enum { + MSG_POST_EVENT = 0xF1F1, MSG_MAX = MSG_POST_EVENT + }; + + virtual ~StreamInterface(); + + virtual StreamState GetState() const = 0; + + // Read attempts to fill buffer of size buffer_len. Write attempts to send + // data_len bytes stored in data. The variables read and write are set only + // on SR_SUCCESS (see below). Likewise, error is only set on SR_ERROR. + // Read and Write return a value indicating: + // SR_ERROR: an error occurred, which is returned in a non-null error + // argument. Interpretation of the error requires knowledge of the + // stream's concrete type, which limits its usefulness. + // SR_SUCCESS: some number of bytes were successfully written, which is + // returned in a non-null read/write argument. + // SR_BLOCK: the stream is in non-blocking mode, and the operation would + // block, or the stream is in SS_OPENING state. + // SR_EOS: the end-of-stream has been reached, or the stream is in the + // SS_CLOSED state. + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error) = 0; + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error) = 0; + // Attempt to transition to the SS_CLOSED state. SE_CLOSE will not be + // signalled as a result of this call. + virtual void Close() = 0; + + // Streams may signal one or more StreamEvents to indicate state changes. + // The first argument identifies the stream on which the state change occured. + // The second argument is a bit-wise combination of StreamEvents. + // If SE_CLOSE is signalled, then the third argument is the associated error + // code. Otherwise, the value is undefined. + // Note: Not all streams will support asynchronous event signalling. However, + // SS_OPENING and SR_BLOCK returned from stream member functions imply that + // certain events will be raised in the future. + sigslot::signal3 SignalEvent; + + // Like calling SignalEvent, but posts a message to the specified thread, + // which will call SignalEvent. This helps unroll the stack and prevent + // re-entrancy. + void PostEvent(Thread* t, int events, int err); + // Like the aforementioned method, but posts to the current thread. + void PostEvent(int events, int err); + + // + // OPTIONAL OPERATIONS + // + // Not all implementations will support the following operations. In general, + // a stream will only support an operation if it reasonably efficient to do + // so. For example, while a socket could buffer incoming data to support + // seeking, it will not do so. Instead, a buffering stream adapter should + // be used. + // + // Even though several of these operations are related, you should + // always use whichever operation is most relevant. For example, you may + // be tempted to use GetSize() and GetPosition() to deduce the result of + // GetAvailable(). However, a stream which is read-once may support the + // latter operation but not the former. + // + + // The following four methods are used to avoid copying data multiple times. + + // GetReadData returns a pointer to a buffer which is owned by the stream. + // The buffer contains data_len bytes. NULL is returned if no data is + // available, or if the method fails. If the caller processes the data, it + // must call ConsumeReadData with the number of processed bytes. GetReadData + // does not require a matching call to ConsumeReadData if the data is not + // processed. Read and ConsumeReadData invalidate the buffer returned by + // GetReadData. + virtual const void* GetReadData(size_t* data_len) { return NULL; } + virtual void ConsumeReadData(size_t used) {} + + // GetWriteBuffer returns a pointer to a buffer which is owned by the stream. + // The buffer has a capacity of buf_len bytes. NULL is returned if there is + // no buffer available, or if the method fails. The call may write data to + // the buffer, and then call ConsumeWriteBuffer with the number of bytes + // written. GetWriteBuffer does not require a matching call to + // ConsumeWriteData if no data is written. Write, ForceWrite, and + // ConsumeWriteData invalidate the buffer returned by GetWriteBuffer. + // TODO: Allow the caller to specify a minimum buffer size. If the specified + // amount of buffer is not yet available, return NULL and Signal SE_WRITE + // when it is available. If the requested amount is too large, return an + // error. + virtual void* GetWriteBuffer(size_t* buf_len) { return NULL; } + virtual void ConsumeWriteBuffer(size_t used) {} + + // Write data_len bytes found in data, circumventing any throttling which + // would could cause SR_BLOCK to be returned. Returns true if all the data + // was written. Otherwise, the method is unsupported, or an unrecoverable + // error occurred, and the error value is set. This method should be used + // sparingly to write critical data which should not be throttled. A stream + // which cannot circumvent its blocking constraints should not implement this + // method. + // NOTE: This interface is being considered experimentally at the moment. It + // would be used by JUDP and BandwidthStream as a way to circumvent certain + // soft limits in writing. + //virtual bool ForceWrite(const void* data, size_t data_len, int* error) { + // if (error) *error = -1; + // return false; + //} + + // Seek to a byte offset from the beginning of the stream. Returns false if + // the stream does not support seeking, or cannot seek to the specified + // position. + virtual bool SetPosition(size_t position) { return false; } + + // Get the byte offset of the current position from the start of the stream. + // Returns false if the position is not known. + virtual bool GetPosition(size_t* position) const { return false; } + + // Get the byte length of the entire stream. Returns false if the length + // is not known. + virtual bool GetSize(size_t* size) const { return false; } + + // Return the number of Read()-able bytes remaining before end-of-stream. + // Returns false if not known. + virtual bool GetAvailable(size_t* size) const { return false; } + + // Return the number of Write()-able bytes remaining before end-of-stream. + // Returns false if not known. + virtual bool GetWriteRemaining(size_t* size) const { return false; } + + // Return true if flush is successful. + virtual bool Flush() { return false; } + + // Communicates the amount of data which will be written to the stream. The + // stream may choose to preallocate memory to accomodate this data. The + // stream may return false to indicate that there is not enough room (ie, + // Write will return SR_EOS/SR_ERROR at some point). Note that calling this + // function should not affect the existing state of data in the stream. + virtual bool ReserveSize(size_t size) { return true; } + + // + // CONVENIENCE METHODS + // + // These methods are implemented in terms of other methods, for convenience. + // + + // Seek to the start of the stream. + inline bool Rewind() { return SetPosition(0); } + + // WriteAll is a helper function which repeatedly calls Write until all the + // data is written, or something other than SR_SUCCESS is returned. Note that + // unlike Write, the argument 'written' is always set, and may be non-zero + // on results other than SR_SUCCESS. The remaining arguments have the + // same semantics as Write. + StreamResult WriteAll(const void* data, size_t data_len, + size_t* written, int* error); + + // Similar to ReadAll. Calls Read until buffer_len bytes have been read, or + // until a non-SR_SUCCESS result is returned. 'read' is always set. + StreamResult ReadAll(void* buffer, size_t buffer_len, + size_t* read, int* error); + + // ReadLine is a helper function which repeatedly calls Read until it hits + // the end-of-line character, or something other than SR_SUCCESS. + // TODO: this is too inefficient to keep here. Break this out into a buffered + // readline object or adapter + StreamResult ReadLine(std::string* line); + + protected: + StreamInterface(); + + // MessageHandler Interface + virtual void OnMessage(Message* msg); + + private: + DISALLOW_EVIL_CONSTRUCTORS(StreamInterface); +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamAdapterInterface is a convenient base-class for adapting a stream. +// By default, all operations are pass-through. Override the methods that you +// require adaptation. Streams should really be upgraded to reference-counted. +// In the meantime, use the owned flag to indicate whether the adapter should +// own the adapted stream. +/////////////////////////////////////////////////////////////////////////////// + +class StreamAdapterInterface : public StreamInterface, + public sigslot::has_slots<> { + public: + explicit StreamAdapterInterface(StreamInterface* stream, bool owned = true); + + // Core Stream Interface + virtual StreamState GetState() const { + return stream_->GetState(); + } + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error) { + return stream_->Read(buffer, buffer_len, read, error); + } + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error) { + return stream_->Write(data, data_len, written, error); + } + virtual void Close() { + stream_->Close(); + } + + // Optional Stream Interface + /* Note: Many stream adapters were implemented prior to this Read/Write + interface. Therefore, a simple pass through of data in those cases may + be broken. At a later time, we should do a once-over pass of all + adapters, and make them compliant with these interfaces, after which this + code can be uncommented. + virtual const void* GetReadData(size_t* data_len) { + return stream_->GetReadData(data_len); + } + virtual void ConsumeReadData(size_t used) { + stream_->ConsumeReadData(used); + } + + virtual void* GetWriteBuffer(size_t* buf_len) { + return stream_->GetWriteBuffer(buf_len); + } + virtual void ConsumeWriteBuffer(size_t used) { + stream_->ConsumeWriteBuffer(used); + } + */ + + /* Note: This interface is currently undergoing evaluation. + virtual bool ForceWrite(const void* data, size_t data_len, int* error) { + return stream_->ForceWrite(data, data_len, error); + } + */ + + virtual bool SetPosition(size_t position) { + return stream_->SetPosition(position); + } + virtual bool GetPosition(size_t* position) const { + return stream_->GetPosition(position); + } + virtual bool GetSize(size_t* size) const { + return stream_->GetSize(size); + } + virtual bool GetAvailable(size_t* size) const { + return stream_->GetAvailable(size); + } + virtual bool GetWriteRemaining(size_t* size) const { + return stream_->GetWriteRemaining(size); + } + virtual bool ReserveSize(size_t size) { + return stream_->ReserveSize(size); + } + virtual bool Flush() { + return stream_->Flush(); + } + + void Attach(StreamInterface* stream, bool owned = true); + StreamInterface* Detach(); + + protected: + virtual ~StreamAdapterInterface(); + + // Note that the adapter presents itself as the origin of the stream events, + // since users of the adapter may not recognize the adapted object. + virtual void OnEvent(StreamInterface* stream, int events, int err) { + SignalEvent(this, events, err); + } + StreamInterface* stream() { return stream_; } + + private: + StreamInterface* stream_; + bool owned_; + DISALLOW_EVIL_CONSTRUCTORS(StreamAdapterInterface); +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamTap is a non-modifying, pass-through adapter, which copies all data +// in either direction to the tap. Note that errors or blocking on writing to +// the tap will prevent further tap writes from occurring. +/////////////////////////////////////////////////////////////////////////////// + +class StreamTap : public StreamAdapterInterface { + public: + explicit StreamTap(StreamInterface* stream, StreamInterface* tap); + + void AttachTap(StreamInterface* tap); + StreamInterface* DetachTap(); + StreamResult GetTapResult(int* error); + + // StreamAdapterInterface Interface + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + + private: + scoped_ptr tap_; + StreamResult tap_result_; + int tap_error_; + DISALLOW_EVIL_CONSTRUCTORS(StreamTap); +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamSegment adapts a read stream, to expose a subset of the adapted +// stream's data. This is useful for cases where a stream contains multiple +// documents concatenated together. StreamSegment can expose a subset of +// the data as an independent stream, including support for rewinding and +// seeking. +/////////////////////////////////////////////////////////////////////////////// + +class StreamSegment : public StreamAdapterInterface { + public: + // The current position of the adapted stream becomes the beginning of the + // segment. If a length is specified, it bounds the length of the segment. + explicit StreamSegment(StreamInterface* stream); + explicit StreamSegment(StreamInterface* stream, size_t length); + + // StreamAdapterInterface Interface + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + virtual bool SetPosition(size_t position); + virtual bool GetPosition(size_t* position) const; + virtual bool GetSize(size_t* size) const; + virtual bool GetAvailable(size_t* size) const; + + private: + size_t start_, pos_, length_; + DISALLOW_EVIL_CONSTRUCTORS(StreamSegment); +}; + +/////////////////////////////////////////////////////////////////////////////// +// NullStream gives errors on read, and silently discards all written data. +/////////////////////////////////////////////////////////////////////////////// + +class NullStream : public StreamInterface { + public: + NullStream(); + virtual ~NullStream(); + + // StreamInterface Interface + virtual StreamState GetState() const; + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + virtual void Close(); +}; + +/////////////////////////////////////////////////////////////////////////////// +// FileStream is a simple implementation of a StreamInterface, which does not +// support asynchronous notification. +/////////////////////////////////////////////////////////////////////////////// + +class FileStream : public StreamInterface { + public: + FileStream(); + virtual ~FileStream(); + + // The semantics of filename and mode are the same as stdio's fopen + virtual bool Open(const std::string& filename, const char* mode, int* error); + virtual bool OpenShare(const std::string& filename, const char* mode, + int shflag, int* error); + + // By default, reads and writes are buffered for efficiency. Disabling + // buffering causes writes to block until the bytes on disk are updated. + virtual bool DisableBuffering(); + + virtual StreamState GetState() const; + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + virtual void Close(); + virtual bool SetPosition(size_t position); + virtual bool GetPosition(size_t* position) const; + virtual bool GetSize(size_t* size) const; + virtual bool GetAvailable(size_t* size) const; + virtual bool ReserveSize(size_t size); + + virtual bool Flush(); + +#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(); + bool Unlock(); +#endif + + // Note: Deprecated in favor of Filesystem::GetFileSize(). + static bool GetSize(const std::string& filename, size_t* size); + + protected: + virtual void DoClose(); + + FILE* file_; + + private: + DISALLOW_EVIL_CONSTRUCTORS(FileStream); +}; + +// A stream that caps the output at a certain size, dropping content from the +// middle of the logical stream and maintaining equal parts of the start/end of +// the logical stream. +class CircularFileStream : public FileStream { + public: + explicit CircularFileStream(size_t max_size); + + virtual bool Open(const std::string& filename, const char* mode, int* error); + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + + private: + enum ReadSegment { + READ_MARKED, // Read 0 .. marked_position_ + READ_MIDDLE, // Read position_ .. file_size + READ_LATEST, // Read marked_position_ .. position_ if the buffer was + // overwritten or 0 .. position_ otherwise. + }; + + size_t max_write_size_; + size_t position_; + size_t marked_position_; + size_t last_write_position_; + ReadSegment read_segment_; + 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 { + public: + // Takes ownership of the stream, but not the thread. + AsyncWriteStream(StreamInterface* stream, talk_base::Thread* write_thread) + : stream_(stream), + write_thread_(write_thread), + state_(stream ? stream->GetState() : SS_CLOSED) { + } + + virtual ~AsyncWriteStream(); + + // StreamInterface Interface + virtual StreamState GetState() const { return state_; } + // This is needed by some stream writers, such as RtpDumpWriter. + virtual bool GetPosition(size_t* position) const; + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + virtual void Close(); + virtual bool Flush(); + + protected: + // From MessageHandler + virtual void OnMessage(talk_base::Message* pmsg); + virtual void ClearBufferAndWrite(); + + private: + talk_base::scoped_ptr stream_; + Thread* write_thread_; + StreamState state_; + Buffer buffer_; + mutable CriticalSection crit_stream_; + CriticalSection crit_buffer_; + + DISALLOW_EVIL_CONSTRUCTORS(AsyncWriteStream); +}; + + +#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. +class POpenStream : public FileStream { + public: + POpenStream() : wait_status_(-1) {} + virtual ~POpenStream(); + + virtual bool Open(const std::string& subcommand, const char* mode, + int* error); + // Same as Open(). shflag is ignored. + virtual bool OpenShare(const std::string& subcommand, const char* mode, + int shflag, int* error); + + // Returns the wait status from the last Close() of an Open()'ed stream, or + // -1 if no Open()+Close() has been done on this object. Meaning of the number + // is documented in "man 2 wait". + int GetWaitStatus() const { return wait_status_; } + + protected: + virtual void DoClose(); + + private: + int wait_status_; +}; +#endif // POSIX + +/////////////////////////////////////////////////////////////////////////////// +// MemoryStream is a simple implementation of a StreamInterface over in-memory +// data. Data is read and written at the current seek position. Reads return +// end-of-stream when they reach the end of data. Writes actually extend the +// end of data mark. +/////////////////////////////////////////////////////////////////////////////// + +class MemoryStreamBase : public StreamInterface { + public: + virtual StreamState GetState() const; + virtual StreamResult Read(void* buffer, size_t bytes, size_t* bytes_read, + int* error); + virtual StreamResult Write(const void* buffer, size_t bytes, + size_t* bytes_written, int* error); + virtual void Close(); + virtual bool SetPosition(size_t position); + virtual bool GetPosition(size_t* position) const; + virtual bool GetSize(size_t* size) const; + virtual bool GetAvailable(size_t* size) const; + virtual bool ReserveSize(size_t size); + + char* GetBuffer() { return buffer_; } + const char* GetBuffer() const { return buffer_; } + + protected: + MemoryStreamBase(); + + virtual StreamResult DoReserve(size_t size, int* error); + + // Invariant: 0 <= seek_position <= data_length_ <= buffer_length_ + char* buffer_; + size_t buffer_length_; + size_t data_length_; + size_t seek_position_; + + private: + DISALLOW_EVIL_CONSTRUCTORS(MemoryStreamBase); +}; + +// MemoryStream dynamically resizes to accomodate written data. + +class MemoryStream : public MemoryStreamBase { + public: + MemoryStream(); + explicit MemoryStream(const char* data); // Calls SetData(data, strlen(data)) + MemoryStream(const void* data, size_t length); // Calls SetData(data, length) + virtual ~MemoryStream(); + + void SetData(const void* data, size_t length); + + protected: + virtual StreamResult DoReserve(size_t size, int* error); + // Memory Streams are aligned for efficiency. + static const int kAlignment = 16; + char* buffer_alloc_; +}; + +// ExternalMemoryStream adapts an external memory buffer, so writes which would +// extend past the end of the buffer will return end-of-stream. + +class ExternalMemoryStream : public MemoryStreamBase { + public: + ExternalMemoryStream(); + ExternalMemoryStream(void* data, size_t length); + virtual ~ExternalMemoryStream(); + + void SetData(void* data, size_t length); +}; + +// FifoBuffer allows for efficient, thread-safe buffering of data between +// writer and reader. As the data can wrap around the end of the buffer, +// MemoryStreamBase can't help us here. + +class FifoBuffer : public StreamInterface { + public: + // Creates a FIFO buffer with the specified capacity. + explicit FifoBuffer(size_t length); + // Creates a FIFO buffer with the specified capacity and owner + FifoBuffer(size_t length, Thread* owner); + virtual ~FifoBuffer(); + // Gets the amount of data currently readable from the buffer. + bool GetBuffered(size_t* data_len) const; + // Resizes the buffer to the specified capacity. Fails if data_length_ > size + bool SetCapacity(size_t length); + + // Read into |buffer| with an offset from the current read position, offset + // is specified in number of bytes. + // This method doesn't adjust read position nor the number of available + // bytes, user has to call ConsumeReadData() to do this. + StreamResult ReadOffset(void* buffer, size_t bytes, size_t offset, + size_t* bytes_read); + + // Write |buffer| with an offset from the current write position, offset is + // specified in number of bytes. + // This method doesn't adjust the number of buffered bytes, user has to call + // ConsumeWriteBuffer() to do this. + StreamResult WriteOffset(const void* buffer, size_t bytes, size_t offset, + size_t* bytes_written); + + // StreamInterface methods + virtual StreamState GetState() const; + virtual StreamResult Read(void* buffer, size_t bytes, + size_t* bytes_read, int* error); + virtual StreamResult Write(const void* buffer, size_t bytes, + size_t* bytes_written, int* error); + virtual void Close(); + virtual const void* GetReadData(size_t* data_len); + virtual void ConsumeReadData(size_t used); + virtual void* GetWriteBuffer(size_t* buf_len); + virtual void ConsumeWriteBuffer(size_t used); + virtual bool GetWriteRemaining(size_t* size) const; + + private: + // Helper method that implements ReadOffset. Caller must acquire a lock + // when calling this method. + StreamResult ReadOffsetLocked(void* buffer, size_t bytes, size_t offset, + size_t* bytes_read); + + // Helper method that implements WriteOffset. Caller must acquire a lock + // when calling this method. + StreamResult WriteOffsetLocked(const void* buffer, size_t bytes, + size_t offset, size_t* bytes_written); + + StreamState state_; // keeps the opened/closed state of the stream + scoped_ptr buffer_; // the allocated buffer + size_t buffer_length_; // size of the allocated buffer + size_t data_length_; // amount of readable data in the buffer + size_t read_position_; // offset to the readable data + Thread* owner_; // stream callbacks are dispatched on this thread + mutable CriticalSection crit_; // object lock + DISALLOW_EVIL_CONSTRUCTORS(FifoBuffer); +}; + +/////////////////////////////////////////////////////////////////////////////// + +class LoggingAdapter : public StreamAdapterInterface { + public: + LoggingAdapter(StreamInterface* stream, LoggingSeverity level, + const std::string& label, bool hex_mode = false); + + void set_label(const std::string& label); + + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + virtual void Close(); + + protected: + virtual void OnEvent(StreamInterface* stream, int events, int err); + + private: + LoggingSeverity level_; + std::string label_; + bool hex_mode_; + LogMultilineState lms_; + + DISALLOW_EVIL_CONSTRUCTORS(LoggingAdapter); +}; + +/////////////////////////////////////////////////////////////////////////////// +// StringStream - Reads/Writes to an external std::string +/////////////////////////////////////////////////////////////////////////////// + +class StringStream : public StreamInterface { + public: + explicit StringStream(std::string& str); + explicit StringStream(const std::string& str); + + virtual StreamState GetState() const; + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + virtual void Close(); + virtual bool SetPosition(size_t position); + virtual bool GetPosition(size_t* position) const; + virtual bool GetSize(size_t* size) const; + virtual bool GetAvailable(size_t* size) const; + virtual bool ReserveSize(size_t size); + + private: + std::string& str_; + size_t read_pos_; + bool read_only_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamReference - A reference counting stream adapter +/////////////////////////////////////////////////////////////////////////////// + +// Keep in mind that the streams and adapters defined in this file are +// not thread-safe, so this has limited uses. + +// A StreamRefCount holds the reference count and a pointer to the +// wrapped stream. It deletes the wrapped stream when there are no +// more references. We can then have multiple StreamReference +// instances pointing to one StreamRefCount, all wrapping the same +// stream. + +class StreamReference : public StreamAdapterInterface { + class StreamRefCount; + public: + // Constructor for the first reference to a stream + // Note: get more references through NewReference(). Use this + // constructor only once on a given stream. + explicit StreamReference(StreamInterface* stream); + StreamInterface* GetStream() { return stream(); } + StreamInterface* NewReference(); + virtual ~StreamReference(); + + private: + class StreamRefCount { + public: + explicit StreamRefCount(StreamInterface* stream) + : stream_(stream), ref_count_(1) { + } + void AddReference() { + CritScope lock(&cs_); + ++ref_count_; + } + void Release() { + int ref_count; + { // Atomic ops would have been a better fit here. + CritScope lock(&cs_); + ref_count = --ref_count_; + } + if (ref_count == 0) { + delete stream_; + delete this; + } + } + private: + StreamInterface* stream_; + int ref_count_; + CriticalSection cs_; + DISALLOW_EVIL_CONSTRUCTORS(StreamRefCount); + }; + + // Constructor for adding references + explicit StreamReference(StreamRefCount* stream_ref_count, + StreamInterface* stream); + + StreamRefCount* stream_ref_count_; + DISALLOW_EVIL_CONSTRUCTORS(StreamReference); +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Flow attempts to move bytes from source to sink via buffer of size +// buffer_len. The function returns SR_SUCCESS when source reaches +// end-of-stream (returns SR_EOS), and all the data has been written successful +// to sink. Alternately, if source returns SR_BLOCK or SR_ERROR, or if sink +// returns SR_BLOCK, SR_ERROR, or SR_EOS, then the function immediately returns +// with the unexpected StreamResult value. +// data_len is the length of the valid data in buffer. in case of error +// this is the data that read from source but can't move to destination. +// as a pass in parameter, it indicates data in buffer that should move to sink +StreamResult Flow(StreamInterface* source, + char* buffer, size_t buffer_len, + StreamInterface* sink, size_t* data_len = NULL); + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_STREAM_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/stringdigest.h b/thirdparties/common/include/webrtc-sdk/talk/base/stringdigest.h new file mode 100644 index 0000000..e065048 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/stringdigest.h @@ -0,0 +1,34 @@ +/* + * 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_BASE_STRINGDIGEST_H_ +#define TALK_BASE_STRINGDIGEST_H_ + +// TODO: Update remaining callers to use messagedigest.h instead +#include "talk/base/messagedigest.h" + +#endif // TALK_BASE_STRINGDIGEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/stringencode.h b/thirdparties/common/include/webrtc-sdk/talk/base/stringencode.h new file mode 100644 index 0000000..5a42554 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/stringencode.h @@ -0,0 +1,227 @@ +/* + * 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_BASE_STRINGENCODE_H_ +#define TALK_BASE_STRINGENCODE_H_ + +#include +#include +#include + +#include "talk/base/common.h" + +namespace talk_base { + +////////////////////////////////////////////////////////////////////// +// String Encoding Utilities +////////////////////////////////////////////////////////////////////// + +// Convert an unsigned value to it's utf8 representation. Returns the length +// of the encoded string, or 0 if the encoding is longer than buflen - 1. +size_t utf8_encode(char* buffer, size_t buflen, unsigned long value); +// Decode the utf8 encoded value pointed to by source. Returns the number of +// bytes used by the encoding, or 0 if the encoding is invalid. +size_t utf8_decode(const char* source, size_t srclen, unsigned long* value); + +// Escaping prefixes illegal characters with the escape character. Compact, but +// illegal characters still appear in the string. +size_t escape(char * buffer, size_t buflen, + const char * source, size_t srclen, + const char * illegal, char escape); +// Note: in-place unescaping (buffer == source) is allowed. +size_t unescape(char * buffer, size_t buflen, + const char * source, size_t srclen, + char escape); + +// Encoding replaces illegal characters with the escape character and 2 hex +// chars, so it's a little less compact than escape, but completely removes +// illegal characters. note that hex digits should not be used as illegal +// characters. +size_t encode(char * buffer, size_t buflen, + const char * source, size_t srclen, + const char * illegal, char escape); +// Note: in-place decoding (buffer == source) is allowed. +size_t decode(char * buffer, size_t buflen, + const char * source, size_t srclen, + char escape); + +// Returns a list of characters that may be unsafe for use in the name of a +// file, suitable for passing to the 'illegal' member of escape or encode. +const char* unsafe_filename_characters(); + +// url_encode is an encode operation with a predefined set of illegal characters +// and escape character (for use in URLs, obviously). +size_t url_encode(char * buffer, size_t buflen, + const char * source, size_t srclen); +// Note: in-place decoding (buffer == source) is allowed. +size_t url_decode(char * buffer, size_t buflen, + const char * source, size_t srclen); + +// html_encode prevents data embedded in html from containing markup. +size_t html_encode(char * buffer, size_t buflen, + const char * source, size_t srclen); +// Note: in-place decoding (buffer == source) is allowed. +size_t html_decode(char * buffer, size_t buflen, + const char * source, size_t srclen); + +// xml_encode makes data suitable for inside xml attributes and values. +size_t xml_encode(char * buffer, size_t buflen, + const char * source, size_t srclen); +// Note: in-place decoding (buffer == source) is allowed. +size_t xml_decode(char * buffer, size_t buflen, + const char * source, size_t srclen); + +// Convert an unsigned value from 0 to 15 to the hex character equivalent... +char hex_encode(unsigned char val); +// ...and vice-versa. +bool hex_decode(char ch, unsigned char* val); + +// hex_encode shows the hex representation of binary data in ascii. +size_t hex_encode(char* buffer, size_t buflen, + const char* source, size_t srclen); + +// hex_encode, but separate each byte representation with a delimiter. +// |delimiter| == 0 means no delimiter +// If the buffer is too short, we return 0 +size_t hex_encode_with_delimiter(char* buffer, size_t buflen, + const char* source, size_t srclen, + char delimiter); + +// Helper functions for hex_encode. +std::string hex_encode(const char* source, size_t srclen); +std::string hex_encode_with_delimiter(const char* source, size_t srclen, + char delimiter); + +// hex_decode converts ascii hex to binary. +size_t hex_decode(char* buffer, size_t buflen, + const char* source, size_t srclen); + +// hex_decode, assuming that there is a delimiter between every byte +// pair. +// |delimiter| == 0 means no delimiter +// If the buffer is too short or the data is invalid, we return 0. +size_t hex_decode_with_delimiter(char* buffer, size_t buflen, + const char* source, size_t srclen, + char delimiter); + +// Helper functions for hex_decode. +size_t hex_decode(char* buffer, size_t buflen, const std::string& source); +size_t hex_decode_with_delimiter(char* buffer, size_t buflen, + const std::string& source, char delimiter); + +// Apply any suitable string transform (including the ones above) to an STL +// string. Stack-allocated temporary space is used for the transformation, +// so value and source may refer to the same string. +typedef size_t (*Transform)(char * buffer, size_t buflen, + const char * source, size_t srclen); +size_t transform(std::string& value, size_t maxlen, const std::string& source, + Transform t); + +// Return the result of applying transform t to source. +std::string s_transform(const std::string& source, Transform t); + +// Convenience wrappers. +inline std::string s_url_encode(const std::string& source) { + return s_transform(source, url_encode); +} +inline std::string s_url_decode(const std::string& source) { + return s_transform(source, url_decode); +} + +// Splits the source string into multiple fields separated by delimiter, +// with duplicates of delimiter creating empty fields. +size_t split(const std::string& source, char delimiter, + std::vector* fields); + +// Splits the source string into multiple fields separated by delimiter, +// with duplicates of delimiter ignored. Trailing delimiter ignored. +size_t tokenize(const std::string& source, char delimiter, + std::vector* fields); + +// Tokenize and append the tokens to fields. Return the new size of fields. +size_t tokenize_append(const std::string& source, char delimiter, + std::vector* fields); + +// Splits the source string into multiple fields separated by delimiter, with +// duplicates of delimiter ignored. Trailing delimiter ignored. A substring in +// between the start_mark and the end_mark is treated as a single field. Return +// the size of fields. For example, if source is "filename +// \"/Library/Application Support/media content.txt\"", delimiter is ' ', and +// the start_mark and end_mark are '"', this method returns two fields: +// "filename" and "/Library/Application Support/media content.txt". +size_t tokenize(const std::string& source, char delimiter, char start_mark, + char end_mark, std::vector* fields); + +// Safe sprintf to std::string +//void sprintf(std::string& value, size_t maxlen, const char * format, ...) +// PRINTF_FORMAT(3); + +// Convert arbitrary values to/from a string. + +template +static bool ToString(const T &t, std::string* s) { + ASSERT(NULL != s); + std::ostringstream oss; + oss << std::boolalpha << t; + *s = oss.str(); + return !oss.fail(); +} + +template +static bool FromString(const std::string& s, T* t) { + ASSERT(NULL != t); + std::istringstream iss(s); + iss >> std::boolalpha >> *t; + return !iss.fail(); +} + +// Inline versions of the string conversion routines. + +template +static inline std::string ToString(const T& val) { + std::string str; ToString(val, &str); return str; +} + +template +static inline T FromString(const std::string& str) { + T val; FromString(str, &val); return val; +} + +template +static inline T FromString(const T& defaultValue, const std::string& str) { + T val(defaultValue); FromString(str, &val); return val; +} + +// simple function to strip out characters which shouldn't be +// used in filenames +char make_char_safe_for_filename(char c); + +////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_STRINGENCODE_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/stringutils.h b/thirdparties/common/include/webrtc-sdk/talk/base/stringutils.h new file mode 100644 index 0000000..7c9275b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/stringutils.h @@ -0,0 +1,335 @@ +/* + * 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 TALK_BASE_STRINGUTILS_H__ +#define TALK_BASE_STRINGUTILS_H__ + +#include +#include +#include +#include + +#ifdef WIN32 +#include +#include +#define alloca _alloca +#endif // WIN32 + +#ifdef POSIX +#ifdef BSD +#include +#else // BSD +#include +#endif // !BSD +#endif // POSIX + +#include + +#include "talk/base/basictypes.h" + +/////////////////////////////////////////////////////////////////////////////// +// Generic string/memory utilities +/////////////////////////////////////////////////////////////////////////////// + +#define STACK_ARRAY(TYPE, LEN) static_cast(::alloca((LEN)*sizeof(TYPE))) + +namespace talk_base { + +// Complement to memset. Verifies memory consists of count bytes of value c. +bool memory_check(const void* memory, int c, size_t count); + +// Determines whether the simple wildcard pattern matches target. +// Alpha characters in pattern match case-insensitively. +// Asterisks in pattern match 0 or more characters. +// Ex: string_match("www.TEST.GOOGLE.COM", "www.*.com") -> true +bool string_match(const char* target, const char* pattern); + +} // namespace talk_base + +/////////////////////////////////////////////////////////////////////////////// +// Rename a bunch of common string functions so they are consistent across +// platforms and between char and wchar_t variants. +// Here is the full list of functions that are unified: +// strlen, strcmp, stricmp, strncmp, strnicmp +// strchr, vsnprintf, strtoul, tolowercase +// tolowercase is like tolower, but not compatible with end-of-file value +// +// It's not clear if we will ever use wchar_t strings on unix. In theory, +// all strings should be Utf8 all the time, except when interfacing with Win32 +// APIs that require Utf16. +/////////////////////////////////////////////////////////////////////////////// + +inline char tolowercase(char c) { + return static_cast(tolower(c)); +} + +#ifdef WIN32 + +inline size_t strlen(const wchar_t* s) { + return wcslen(s); +} +inline int strcmp(const wchar_t* s1, const wchar_t* s2) { + return wcscmp(s1, s2); +} +inline int stricmp(const wchar_t* s1, const wchar_t* s2) { + return _wcsicmp(s1, s2); +} +inline int strncmp(const wchar_t* s1, const wchar_t* s2, size_t n) { + return wcsncmp(s1, s2, n); +} +inline int strnicmp(const wchar_t* s1, const wchar_t* s2, size_t n) { + return _wcsnicmp(s1, s2, n); +} +inline const wchar_t* strchr(const wchar_t* s, wchar_t c) { + return wcschr(s, c); +} +inline const wchar_t* strstr(const wchar_t* haystack, const wchar_t* needle) { + return wcsstr(haystack, needle); +} +#ifndef vsnprintf +inline int vsnprintf(wchar_t* buf, size_t n, const wchar_t* fmt, va_list args) { + return _vsnwprintf(buf, n, fmt, args); +} +#endif // !vsnprintf +inline unsigned long strtoul(const wchar_t* snum, wchar_t** end, int base) { + return wcstoul(snum, end, base); +} +inline wchar_t tolowercase(wchar_t c) { + return static_cast(towlower(c)); +} + +#endif // WIN32 + +#ifdef POSIX + +inline int _stricmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline int _strnicmp(const char* s1, const char* s2, size_t n) { + return strncasecmp(s1, s2, n); +} + +#endif // POSIX + +/////////////////////////////////////////////////////////////////////////////// +// Traits simplifies porting string functions to be CTYPE-agnostic +/////////////////////////////////////////////////////////////////////////////// + +namespace talk_base { + +const size_t SIZE_UNKNOWN = static_cast(-1); + +template +struct Traits { + // STL string type + //typedef XXX string; + // Null-terminated string + //inline static const CTYPE* empty_str(); +}; + +/////////////////////////////////////////////////////////////////////////////// +// String utilities which work with char or wchar_t +/////////////////////////////////////////////////////////////////////////////// + +template +inline const CTYPE* nonnull(const CTYPE* str, const CTYPE* def_str = NULL) { + return str ? str : (def_str ? def_str : Traits::empty_str()); +} + +template +const CTYPE* strchr(const CTYPE* str, const CTYPE* chs) { + for (size_t i=0; str[i]; ++i) { + for (size_t j=0; chs[j]; ++j) { + if (str[i] == chs[j]) { + return str + i; + } + } + } + return 0; +} + +template +const CTYPE* strchrn(const CTYPE* str, size_t slen, CTYPE ch) { + for (size_t i=0; i +size_t strlenn(const CTYPE* buffer, size_t buflen) { + size_t bufpos = 0; + while (buffer[bufpos] && (bufpos < buflen)) { + ++bufpos; + } + return bufpos; +} + +// Safe versions of strncpy, strncat, snprintf and vsnprintf that always +// null-terminate. + +template +size_t strcpyn(CTYPE* buffer, size_t buflen, + const CTYPE* source, size_t srclen = SIZE_UNKNOWN) { + if (buflen <= 0) + return 0; + + if (srclen == SIZE_UNKNOWN) { + srclen = strlenn(source, buflen - 1); + } else if (srclen >= buflen) { + srclen = buflen - 1; + } + memcpy(buffer, source, srclen * sizeof(CTYPE)); + buffer[srclen] = 0; + return srclen; +} + +template +size_t strcatn(CTYPE* buffer, size_t buflen, + const CTYPE* source, size_t srclen = SIZE_UNKNOWN) { + if (buflen <= 0) + return 0; + + size_t bufpos = strlenn(buffer, buflen - 1); + return bufpos + strcpyn(buffer + bufpos, buflen - bufpos, source, srclen); +} + +// Some compilers (clang specifically) require vsprintfn be defined before +// sprintfn. +template +size_t vsprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, + va_list args) { + int len = vsnprintf(buffer, buflen, format, args); + if ((len < 0) || (static_cast(len) >= buflen)) { + len = static_cast(buflen - 1); + buffer[len] = 0; + } + return len; +} + +template +size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...); +template +size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...) { + va_list args; + va_start(args, format); + size_t len = vsprintfn(buffer, buflen, format, args); + va_end(args); + return len; +} + +/////////////////////////////////////////////////////////////////////////////// +// Allow safe comparing and copying ascii (not UTF-8) with both wide and +// non-wide character strings. +/////////////////////////////////////////////////////////////////////////////// + +inline int asccmp(const char* s1, const char* s2) { + return strcmp(s1, s2); +} +inline int ascicmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +inline int ascncmp(const char* s1, const char* s2, size_t n) { + return strncmp(s1, s2, n); +} +inline int ascnicmp(const char* s1, const char* s2, size_t n) { + return _strnicmp(s1, s2, n); +} +inline size_t asccpyn(char* buffer, size_t buflen, + const char* source, size_t srclen = SIZE_UNKNOWN) { + return strcpyn(buffer, buflen, source, srclen); +} + +#ifdef WIN32 + +typedef wchar_t(*CharacterTransformation)(wchar_t); +inline wchar_t identity(wchar_t c) { return c; } +int ascii_string_compare(const wchar_t* s1, const char* s2, size_t n, + CharacterTransformation transformation); + +inline int asccmp(const wchar_t* s1, const char* s2) { + return ascii_string_compare(s1, s2, static_cast(-1), identity); +} +inline int ascicmp(const wchar_t* s1, const char* s2) { + return ascii_string_compare(s1, s2, static_cast(-1), tolowercase); +} +inline int ascncmp(const wchar_t* s1, const char* s2, size_t n) { + return ascii_string_compare(s1, s2, n, identity); +} +inline int ascnicmp(const wchar_t* s1, const char* s2, size_t n) { + return ascii_string_compare(s1, s2, n, tolowercase); +} +size_t asccpyn(wchar_t* buffer, size_t buflen, + const char* source, size_t srclen = SIZE_UNKNOWN); + +#endif // WIN32 + +/////////////////////////////////////////////////////////////////////////////// +// Traits specializations +/////////////////////////////////////////////////////////////////////////////// + +template<> +struct Traits { + typedef std::string string; + inline static const char* empty_str() { return ""; } +}; + +/////////////////////////////////////////////////////////////////////////////// +// Traits specializations (Windows only, currently) +/////////////////////////////////////////////////////////////////////////////// + +#ifdef WIN32 + +template<> +struct Traits { + typedef std::wstring string; + inline static const wchar_t* Traits::empty_str() { return L""; } +}; + +#endif // WIN32 + +// Replaces all occurrences of "search" with "replace". +void replace_substrs(const char *search, + size_t search_len, + const char *replace, + size_t replace_len, + std::string *s); + +// True iff s1 starts with s2. +bool starts_with(const char *s1, const char *s2); + +// True iff s1 ends with s2. +bool ends_with(const char *s1, const char *s2); + +// Remove leading and trailing whitespaces. +std::string string_trim(const std::string& s); + +} // namespace talk_base + +#endif // TALK_BASE_STRINGUTILS_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/systeminfo.h b/thirdparties/common/include/webrtc-sdk/talk/base/systeminfo.h new file mode 100644 index 0000000..5c0e8ea --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/systeminfo.h @@ -0,0 +1,98 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_SYSTEMINFO_H__ +#define TALK_BASE_SYSTEMINFO_H__ + +#include + +#include "talk/base/basictypes.h" + +namespace talk_base { + +class SystemInfo { + public: + enum Architecture { + SI_ARCH_UNKNOWN = -1, + SI_ARCH_X86 = 0, + SI_ARCH_X64 = 1, + SI_ARCH_ARM = 2 + }; + + SystemInfo(); + + // The number of CPU Cores in the system. + int GetMaxPhysicalCpus(); + // The number of CPU Threads in the system. + int GetMaxCpus(); + // The number of CPU Threads currently available to this process. + int GetCurCpus(); + // Identity of the CPUs. + Architecture GetCpuArchitecture(); + std::string GetCpuVendor(); + int GetCpuFamily(); + int GetCpuModel(); + int GetCpuStepping(); + // Return size of CPU cache in bytes. Uses largest available cache (L3). + int GetCpuCacheSize(); + // Estimated speed of the CPUs, in MHz. e.g. 2400 for 2.4 GHz + int GetMaxCpuSpeed(); + int GetCurCpuSpeed(); + // Total amount of physical memory, in bytes. + int64 GetMemorySize(); + // The model name of the machine, e.g. "MacBookAir1,1" + std::string GetMachineModel(); + + // The gpu identifier + struct GpuInfo { + GpuInfo() : vendor_id(0), device_id(0) {} + std::string device_name; + std::string description; + int vendor_id; + int device_id; + std::string driver; + std::string driver_version; + }; + bool GetGpuInfo(GpuInfo *info); + + private: + int physical_cpus_; + int logical_cpus_; + int cache_size_; + Architecture cpu_arch_; + std::string cpu_vendor_; + int cpu_family_; + int cpu_model_; + int cpu_stepping_; + int cpu_speed_; + int64 memory_; + std::string machine_model_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_SYSTEMINFO_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/task.h b/thirdparties/common/include/webrtc-sdk/talk/base/task.h new file mode 100644 index 0000000..775fa49 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/task.h @@ -0,0 +1,194 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_TASK_H__ +#define TALK_BASE_TASK_H__ + +#include +#include "talk/base/basictypes.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sigslot.h" +#include "talk/base/taskparent.h" + +///////////////////////////////////////////////////////////////////// +// +// TASK +// +///////////////////////////////////////////////////////////////////// +// +// Task is a state machine infrastructure. States are pushed forward by +// pushing forwards a TaskRunner that holds on to all Tasks. The purpose +// of Task is threefold: +// +// (1) It manages ongoing work on the UI thread. Multitasking without +// threads, keeping it easy, keeping it real. :-) It does this by +// organizing a set of states for each task. When you return from your +// Process*() function, you return an integer for the next state. You do +// not go onto the next state yourself. Every time you enter a state, +// you check to see if you can do anything yet. If not, you return +// STATE_BLOCKED. If you _could_ do anything, do not return +// STATE_BLOCKED - even if you end up in the same state, return +// STATE_mysamestate. When you are done, return STATE_DONE and then the +// task will self-delete sometime afterwards. +// +// (2) It helps you avoid all those reentrancy problems when you chain +// too many triggers on one thread. Basically if you want to tell a task +// to process something for you, you feed your task some information and +// then you Wake() it. Don't tell it to process it right away. If it +// might be working on something as you send it information, you may want +// to have a queue in the task. +// +// (3) Finally it helps manage parent tasks and children. If a parent +// task gets aborted, all the children tasks are too. The nice thing +// about this, for example, is if you have one parent task that +// represents, say, and Xmpp connection, then you can spawn a whole bunch +// of infinite lifetime child tasks and now worry about cleaning them up. +// When the parent task goes to STATE_DONE, the task engine will make +// sure all those children are aborted and get deleted. +// +// Notice that Task has a few built-in states, e.g., +// +// STATE_INIT - the task isn't running yet +// STATE_START - the task is in its first state +// STATE_RESPONSE - the task is in its second state +// STATE_DONE - the task is done +// +// STATE_ERROR - indicates an error - we should audit the error code in +// light of any usage of it to see if it should be improved. When I +// first put down the task stuff I didn't have a good sense of what was +// needed for Abort and Error, and now the subclasses of Task will ground +// the design in a stronger way. +// +// STATE_NEXT - the first undefined state number. (like WM_USER) - you +// can start defining more task states there. +// +// When you define more task states, just override Process(int state) and +// add your own switch statement. If you want to delegate to +// Task::Process, you can effectively delegate to its switch statement. +// No fancy method pointers or such - this is all just pretty low tech, +// easy to debug, and fast. +// +// Also notice that Task has some primitive built-in timeout functionality. +// +// A timeout is defined as "the task stays in STATE_BLOCKED longer than +// timeout_seconds_." +// +// Descendant classes can override this behavior by calling the +// various protected methods to change the timeout behavior. For +// instance, a descendand might call SuspendTimeout() when it knows +// that it isn't waiting for anything that might timeout, but isn't +// yet in the STATE_DONE state. +// + +namespace talk_base { + +// Executes a sequence of steps +class Task : public TaskParent { + public: + Task(TaskParent *parent); + virtual ~Task(); + + int32 unique_id() { return unique_id_; } + + void Start(); + void Step(); + int GetState() const { return state_; } + bool HasError() const { return (GetState() == STATE_ERROR); } + bool Blocked() const { return blocked_; } + bool IsDone() const { return done_; } + int64 ElapsedTime(); + + // Called from outside to stop task without any more callbacks + void Abort(bool nowake = false); + + bool TimedOut(); + + int64 timeout_time() const { return timeout_time_; } + int timeout_seconds() const { return timeout_seconds_; } + void set_timeout_seconds(int timeout_seconds); + + sigslot::signal0<> SignalTimeout; + + // Called inside the task to signal that the task may be unblocked + void Wake(); + + protected: + + enum { + STATE_BLOCKED = -1, + STATE_INIT = 0, + STATE_START = 1, + STATE_DONE = 2, + STATE_ERROR = 3, + STATE_RESPONSE = 4, + STATE_NEXT = 5, // Subclasses which need more states start here and higher + }; + + // Called inside to advise that the task should wake and signal an error + void Error(); + + int64 CurrentTime(); + + virtual std::string GetStateName(int state) const; + virtual int Process(int state); + virtual void Stop(); + virtual int ProcessStart() = 0; + virtual int ProcessResponse() { return STATE_DONE; } + + void ResetTimeout(); + void ClearTimeout(); + + void SuspendTimeout(); + void ResumeTimeout(); + + protected: + virtual int OnTimeout() { + // by default, we are finished after timing out + return STATE_DONE; + } + + private: + void Done(); + + int state_; + bool blocked_; + bool done_; + bool aborted_; + bool busy_; + bool error_; + int64 start_time_; + int64 timeout_time_; + int timeout_seconds_; + bool timeout_suspended_; + int32 unique_id_; + + static int32 unique_id_seed_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_TASK_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/taskparent.h b/thirdparties/common/include/webrtc-sdk/talk/base/taskparent.h new file mode 100644 index 0000000..005f7c2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/taskparent.h @@ -0,0 +1,79 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_TASKPARENT_H__ +#define TALK_BASE_TASKPARENT_H__ + +#include + +#include "talk/base/basictypes.h" +#include "talk/base/scoped_ptr.h" + +namespace talk_base { + +class Task; +class TaskRunner; + +class TaskParent { + public: + TaskParent(Task *derived_instance, TaskParent *parent); + explicit TaskParent(TaskRunner *derived_instance); + virtual ~TaskParent() { } + + TaskParent *GetParent() { return parent_; } + TaskRunner *GetRunner() { return runner_; } + + bool AllChildrenDone(); + bool AnyChildError(); +#ifdef _DEBUG + bool IsChildTask(Task *task); +#endif + + protected: + void OnStopped(Task *task); + void AbortAllChildren(); + TaskParent *parent() { + return parent_; + } + + private: + void Initialize(); + void OnChildStopped(Task *child); + void AddChild(Task *child); + + TaskParent *parent_; + TaskRunner *runner_; + bool child_error_; + typedef std::set ChildSet; + scoped_ptr children_; + DISALLOW_EVIL_CONSTRUCTORS(TaskParent); +}; + + +} // namespace talk_base + +#endif // TALK_BASE_TASKPARENT_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/taskrunner.h b/thirdparties/common/include/webrtc-sdk/talk/base/taskrunner.h new file mode 100644 index 0000000..acefda5 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/taskrunner.h @@ -0,0 +1,117 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_TASKRUNNER_H__ +#define TALK_BASE_TASKRUNNER_H__ + +#include + +#include "talk/base/basictypes.h" +#include "talk/base/sigslot.h" +#include "talk/base/taskparent.h" + +namespace talk_base { +class Task; + +const int64 kSecToMsec = 1000; +const int64 kMsecTo100ns = 10000; +const int64 kSecTo100ns = kSecToMsec * kMsecTo100ns; + +class TaskRunner : public TaskParent, public sigslot::has_slots<> { + public: + TaskRunner(); + virtual ~TaskRunner(); + + virtual void WakeTasks() = 0; + + // Returns the current time in 100ns units. It is used for + // determining timeouts. The origin is not important, only + // the units and that rollover while the computer is running. + // + // On Windows, GetSystemTimeAsFileTime is the typical implementation. + virtual int64 CurrentTime() = 0 ; + + void StartTask(Task *task); + void RunTasks(); + void PollTasks(); + + void UpdateTaskTimeout(Task *task, int64 previous_task_timeout_time); + +#ifdef _DEBUG + bool is_ok_to_delete(Task* task) { + return task == deleting_task_; + } + + void IncrementAbortCount() { + ++abort_count_; + } + + void DecrementAbortCount() { + --abort_count_; + } +#endif + + // Returns the next absolute time when a task times out + // OR "0" if there is no next timeout. + int64 next_task_timeout() const; + + protected: + // The primary usage of this method is to know if + // a callback timer needs to be set-up or adjusted. + // This method will be called + // * when the next_task_timeout() becomes a smaller value OR + // * when next_task_timeout() has changed values and the previous + // value is in the past. + // + // If the next_task_timeout moves to the future, this method will *not* + // get called (because it subclass should check next_task_timeout() + // when its timer goes off up to see if it needs to set-up a new timer). + // + // Note that this maybe called conservatively. In that it may be + // called when no time change has happened. + virtual void OnTimeoutChange() { + // by default, do nothing. + } + + private: + void InternalRunTasks(bool in_destructor); + void CheckForTimeoutChange(int64 previous_timeout_time); + + std::vector tasks_; + Task *next_timeout_task_; + bool tasks_running_; +#ifdef _DEBUG + int abort_count_; + Task* deleting_task_; +#endif + + void RecalcNextTimeout(Task *exclude_task); +}; + +} // namespace talk_base + +#endif // TASK_BASE_TASKRUNNER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/template_util.h b/thirdparties/common/include/webrtc-sdk/talk/base/template_util.h new file mode 100644 index 0000000..82857c6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/template_util.h @@ -0,0 +1,106 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TALK_BASE_TEMPLATE_UTIL_H_ +#define TALK_BASE_TEMPLATE_UTIL_H_ + +#include // For size_t. + +namespace talk_base { + +// template definitions from tr1 + +template +struct integral_constant { + static const T value = v; + typedef T value_type; + typedef integral_constant type; +}; + +template const T integral_constant::value; + +typedef integral_constant true_type; +typedef integral_constant false_type; + +template struct is_pointer : false_type {}; +template struct is_pointer : true_type {}; + +template struct is_same : public false_type {}; +template struct is_same : true_type {}; + +template struct is_array : public false_type {}; +template struct is_array : public true_type {}; +template struct is_array : public true_type {}; + +template struct is_non_const_reference : false_type {}; +template struct is_non_const_reference : true_type {}; +template struct is_non_const_reference : false_type {}; + +template struct is_void : false_type {}; +template <> struct is_void : true_type {}; + +namespace internal { + +// Types YesType and NoType are guaranteed such that sizeof(YesType) < +// sizeof(NoType). +typedef char YesType; + +struct NoType { + YesType dummy[2]; +}; + +// This class is an implementation detail for is_convertible, and you +// don't need to know how it works to use is_convertible. For those +// who care: we declare two different functions, one whose argument is +// of type To and one with a variadic argument list. We give them +// return types of different size, so we can use sizeof to trick the +// compiler into telling us which function it would have chosen if we +// had called it with an argument of type From. See Alexandrescu's +// _Modern C++ Design_ for more details on this sort of trick. + +struct ConvertHelper { + template + static YesType Test(To); + + template + static NoType Test(...); + + template + static From& Create(); +}; + +// Used to determine if a type is a struct/union/class. Inspired by Boost's +// is_class type_trait implementation. +struct IsClassHelper { + template + static YesType Test(void(C::*)(void)); + + template + static NoType Test(...); +}; + +} // namespace internal + +// Inherits from true_type if From is convertible to To, false_type otherwise. +// +// Note that if the type is convertible, this will be a true_type REGARDLESS +// of whether or not the conversion would emit a warning. +template +struct is_convertible + : integral_constant( + internal::ConvertHelper::Create())) == + sizeof(internal::YesType)> { +}; + +template +struct is_class + : integral_constant(0)) == + sizeof(internal::YesType)> { +}; + +} // namespace talk_base + +#endif // TALK_BASE_TEMPLATE_UTIL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/testbase64.h b/thirdparties/common/include/webrtc-sdk/talk/base/testbase64.h new file mode 100644 index 0000000..ec05f72 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/testbase64.h @@ -0,0 +1,5 @@ +/* This file was generated by googleclient/talk/binary2header.sh */ + +static unsigned char testbase64[] = { +0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xe1, 0x0d, 0x07, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x9e, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xbe, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xc3, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xcc, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd4, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xdc, 0x01, 0x32, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x3c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x04, 0x02, 0x13, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x02, 0xc4, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x53, 0x4f, 0x4e, 0x59, 0x00, 0x44, 0x53, 0x43, 0x2d, 0x50, 0x32, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x20, 0x37, 0x2e, 0x30, 0x00, 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, 0x31, 0x3a, 0x33, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x31, 0x30, 0x3a, 0x30, 0x34, 0x00, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58, 0x20, 0x31, 0x30, 0x2e, 0x34, 0x2e, 0x38, 0x00, 0x00, 0x1c, 0x82, 0x9a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x6a, 0x82, 0x9d, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x72, 0x88, 0x22, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x88, 0x27, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x64, 0x00, 0x00, 0x90, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x7a, 0x90, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x8e, 0x91, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x00, 0x91, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xa2, 0x92, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xaa, 0x92, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xb2, 0x92, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x92, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x92, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xba, 0xa0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0xa0, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0xa3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0a, 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, 0x31, 0x3a, 0x32, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x30, 0x35, 0x3a, 0x35, 0x32, 0x00, 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, 0x31, 0x3a, 0x32, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x30, 0x35, 0x3a, 0x35, 0x32, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x12, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x1a, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x22, 0x02, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xed, 0x00, 0x0c, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x5f, 0x43, 0x4d, 0x00, 0x02, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x00, 0x64, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0c, 0x09, 0x09, 0x0c, 0x11, 0x0b, 0x0a, 0x0b, 0x11, 0x15, 0x0f, 0x0c, 0x0c, 0x0f, 0x15, 0x18, 0x13, 0x13, 0x15, 0x13, 0x13, 0x18, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x0d, 0x0b, 0x0b, 0x0d, 0x0e, 0x0d, 0x10, 0x0e, 0x0e, 0x10, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x07, 0xff, 0xc4, 0x01, 0x3f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x01, 0x04, 0x01, 0x03, 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08, 0x05, 0x03, 0x0c, 0x33, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31, 0x05, 0x41, 0x51, 0x61, 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14, 0x91, 0xa1, 0xb1, 0x42, 0x23, 0x24, 0x15, 0x52, 0xc1, 0x62, 0x33, 0x34, 0x72, 0x82, 0xd1, 0x43, 0x07, 0x25, 0x92, 0x53, 0xf0, 0xe1, 0xf1, 0x63, 0x73, 0x35, 0x16, 0xa2, 0xb2, 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45, 0xc2, 0xa3, 0x74, 0x36, 0x17, 0xd2, 0x55, 0xe2, 0x65, 0xf2, 0xb3, 0x84, 0xc3, 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x27, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x11, 0x00, 0x02, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x35, 0x01, 0x00, 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04, 0x41, 0x51, 0x61, 0x71, 0x22, 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xa1, 0xb1, 0x42, 0x23, 0xc1, 0x52, 0xd1, 0xf0, 0x33, 0x24, 0x62, 0xe1, 0x72, 0x82, 0x92, 0x43, 0x53, 0x15, 0x63, 0x73, 0x34, 0xf1, 0x25, 0x06, 0x16, 0xa2, 0xb2, 0x83, 0x07, 0x26, 0x35, 0xc2, 0xd2, 0x44, 0x93, 0x54, 0xa3, 0x17, 0x64, 0x45, 0x55, 0x36, 0x74, 0x65, 0xe2, 0xf2, 0xb3, 0x84, 0xc3, 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf2, 0xed, 0xb2, 0x8d, 0x4d, 0x45, 0xcd, 0x2f, 0x3f, 0x44, 0x68, 0x93, 0xc3, 0x58, 0xc8, 0xf1, 0x1f, 0x8a, 0x33, 0x86, 0xda, 0x58, 0xc1, 0xa0, 0x02, 0x4f, 0xc4, 0xa1, 0x69, 0xa5, 0x9b, 0x5b, 0x4b, 0x84, 0x73, 0xdf, 0xc9, 0x15, 0xf8, 0xe3, 0xd1, 0x0e, 0x07, 0x93, 0xf3, 0xd1, 0x0f, 0x1c, 0x17, 0xef, 0x2e, 0x3b, 0x5b, 0xdc, 0xff, 0x00, 0xdf, 0x42, 0xbf, 0x8f, 0x8e, 0xdc, 0x82, 0xca, 0xd8, 0x37, 0x11, 0xa9, 0x3d, 0x82, 0x69, 0x2b, 0xc4, 0x6d, 0xc9, 0x75, 0x25, 0xbc, 0xf7, 0xec, 0xa1, 0xb5, 0x74, 0x19, 0x5d, 0x2e, 0x8a, 0x9a, 0x4b, 0x89, 0x7d, 0xc4, 0x68, 0xc6, 0xf6, 0xfe, 0xb2, 0xa0, 0x30, 0x1d, 0x60, 0x86, 0x88, 0x8d, 0x49, 0x3e, 0x01, 0x11, 0x20, 0xa3, 0x8c, 0xb9, 0xb1, 0xaa, 0x62, 0xad, 0xbf, 0x18, 0x97, 0x43, 0x47, 0x1d, 0xd2, 0xaf, 0x04, 0xd9, 0xb8, 0xc8, 0x0d, 0x68, 0xe4, 0xf7, 0x3e, 0x48, 0xf1, 0x05, 0xbc, 0x25, 0xaa, 0x07, 0x71, 0xd9, 0x14, 0x78, 0xf6, 0x49, 0xb5, 0x90, 0xfd, 0xa7, 0xc6, 0x14, 0xfd, 0x1b, 0x1c, 0xff, 0x00, 0x4d, 0x8d, 0x2e, 0x73, 0x8c, 0x35, 0xa3, 0x52, 0x4f, 0x92, 0x48, 0xa6, 0x1a, 0x24, 0xb6, 0x2a, 0xfa, 0xa5, 0x9e, 0x60, 0x64, 0x39, 0x94, 0x13, 0xcb, 0x27, 0x73, 0x80, 0xf3, 0x0c, 0xf6, 0xff, 0x00, 0xd2, 0x5a, 0x78, 0xbf, 0x53, 0x71, 0xf6, 0x01, 0x75, 0xb6, 0x97, 0x6a, 0x25, 0xa1, 0xad, 0x1f, 0xf4, 0xb7, 0x23, 0x48, 0xb7, 0x94, 0x84, 0x97, 0x5b, 0xff, 0x00, 0x32, 0xa9, 0xdd, 0xfc, 0xed, 0x9b, 0x7e, 0x0d, 0x9e, 0x52, 0x4a, 0x95, 0x61, 0xff, 0xd0, 0xf3, 0x3b, 0xa7, 0x70, 0xee, 0x01, 0x8f, 0xb9, 0x59, 0xfa, 0x7e, 0xdf, 0xe4, 0xc8, 0xf9, 0x2a, 0xc2, 0x5c, 0x63, 0xc3, 0x54, 0x67, 0x87, 0x6e, 0x10, 0x35, 0x68, 0xd4, 0x79, 0x1e, 0x53, 0x4a, 0xe0, 0xdc, 0xe9, 0xb8, 0x1f, 0x6a, 0xda, 0x6c, 0x25, 0x94, 0x37, 0xb0, 0xd0, 0xb8, 0xad, 0x67, 0xe4, 0x55, 0x8a, 0x5b, 0x8b, 0x82, 0xc0, 0x6f, 0x76, 0x80, 0x34, 0x49, 0x05, 0x2e, 0x9e, 0xc6, 0x1c, 0x66, 0x31, 0xba, 0x10, 0x23, 0xe0, 0xaf, 0xe1, 0x61, 0x53, 0x43, 0x8d, 0x81, 0xb3, 0x67, 0xef, 0x9e, 0x49, 0x2a, 0x12, 0x6c, 0xb6, 0x63, 0x1a, 0x0c, 0x31, 0xba, 0x55, 0xcd, 0xac, 0xfa, 0x8e, 0xdf, 0x91, 0x6e, 0x91, 0xd9, 0xb3, 0xc9, 0x73, 0x90, 0x7a, 0xab, 0x6a, 0xc2, 0xa4, 0x60, 0xe2, 0x8f, 0xd2, 0x38, 0x03, 0x7d, 0x9e, 0x0d, 0xff, 0x00, 0xcc, 0xd6, 0xd3, 0x6b, 0x71, 0x67, 0xd2, 0x3e, 0x64, 0x72, 0xab, 0xdb, 0x8d, 0x54, 0x39, 0xc5, 0x83, 0x6b, 0x3d, 0xee, 0x2e, 0xd4, 0x92, 0x3c, 0x4a, 0x56, 0xba, 0xb4, 0x79, 0x5c, 0xf7, 0xb2, 0x96, 0x6c, 0x8d, 0xaf, 0x80, 0x48, 0x3c, 0xf0, 0xb2, 0x1f, 0x63, 0x9c, 0xe9, 0x3f, 0x24, 0x5c, 0xdb, 0xdd, 0x76, 0x43, 0xde, 0xfd, 0x5c, 0xe3, 0x24, 0xfc, 0x50, 0x00, 0x93, 0x0a, 0x78, 0x8a, 0x0d, 0x49, 0xca, 0xcf, 0x93, 0x63, 0x1b, 0x7d, 0xd7, 0x57, 0x50, 0xd5, 0xef, 0x70, 0x6b, 0x4f, 0xc7, 0x45, 0xdb, 0x74, 0x9e, 0x8d, 0x5e, 0x33, 0x83, 0xd8, 0x37, 0xdd, 0xc3, 0xac, 0x3d, 0xbf, 0x92, 0xc5, 0x5b, 0xea, 0xbf, 0xd5, 0x62, 0xc0, 0xdc, 0xbc, 0xbd, 0x2d, 0x22, 0x5a, 0xcf, 0xdd, 0x69, 0xff, 0x00, 0xd1, 0x8e, 0x5d, 0xa5, 0x38, 0xb5, 0xb0, 0x00, 0xc6, 0xc4, 0x24, 0x4a, 0xd6, 0x8d, 0x18, 0x04, 0x49, 0x88, 0x9e, 0x55, 0xd6, 0x61, 0xb0, 0xc1, 0x70, 0x32, 0xdd, 0x3c, 0x95, 0xda, 0xf1, 0xfe, 0xf5, 0x62, 0xbc, 0x76, 0x8e, 0x75, 0x28, 0x02, 0xa2, 0xe7, 0x7d, 0x92, 0xb9, 0x84, 0x96, 0x96, 0xda, 0xf7, 0x70, 0x12, 0x4e, 0x5a, 0xff, 0x00, 0xff, 0xd1, 0xf3, 0x7a, 0x21, 0xaf, 0xde, 0xef, 0xa2, 0x22, 0x55, 0xfc, 0x5a, 0xbd, 0x42, 0xfb, 0x08, 0xfa, 0x67, 0x4f, 0x82, 0xcd, 0x6d, 0x85, 0xc0, 0x56, 0x3b, 0x90, 0xb7, 0xf0, 0x2a, 0x0e, 0x63, 0x58, 0x3b, 0xf2, 0xa3, 0x9e, 0x8c, 0xb8, 0x86, 0xbe, 0x49, 0xf1, 0x2c, 0x0c, 0x86, 0xb4, 0x4c, 0x69, 0xe4, 0xaf, 0x6e, 0xcc, 0x6b, 0x7d, 0x46, 0xb3, 0x70, 0xec, 0x38, 0x51, 0x7d, 0x02, 0x8a, 0xc7, 0xa6, 0xd9, 0x20, 0x68, 0x0f, 0x8f, 0x8a, 0xcf, 0xc9, 0xc2, 0xea, 0x59, 0x5b, 0x48, 0xb0, 0x91, 0xae, 0xe6, 0xc9, 0x03, 0xc9, 0x30, 0x51, 0x66, 0xd4, 0x0d, 0xad, 0xbd, 0x5f, 0x53, 0xcc, 0x6b, 0xb6, 0x90, 0x5a, 0x3b, 0x83, 0x0b, 0x43, 0x17, 0x31, 0xd6, 0xc3, 0x6e, 0x12, 0x3b, 0x79, 0xac, 0xc1, 0x89, 0x47, 0xd9, 0xe8, 0x63, 0x98, 0x45, 0xed, 0x6c, 0x5a, 0xf1, 0xa0, 0x27, 0xc5, 0x5b, 0xc3, 0x6f, 0xa6, 0xe0, 0x1c, 0x7d, 0xb3, 0xa2, 0x69, 0x34, 0x7b, 0xae, 0x1a, 0x8d, 0x45, 0x17, 0x9d, 0xeb, 0xfd, 0x21, 0xd8, 0xb9, 0xae, 0xb5, 0x80, 0xbb, 0x1e, 0xd2, 0x5c, 0xd7, 0x78, 0x13, 0xf9, 0xae, 0x4b, 0xea, 0xc7, 0x4a, 0x39, 0xbd, 0x55, 0xb3, 0xed, 0x66, 0x38, 0xf5, 0x09, 0x22, 0x41, 0x23, 0xe8, 0x37, 0xfb, 0x4b, 0xa1, 0xeb, 0xd6, 0xfe, 0x88, 0x31, 0xbf, 0x41, 0xc0, 0xee, 0xd2, 0x74, 0x02, 0x78, 0x53, 0xfa, 0x97, 0x43, 0x19, 0x85, 0x65, 0xff, 0x00, 0x9d, 0x71, 0x33, 0xe4, 0x1a, 0x7d, 0x8d, 0x53, 0x42, 0x56, 0x35, 0x6b, 0xe5, 0x80, 0x06, 0xc7, 0x57, 0xa7, 0xc4, 0xa9, 0xdb, 0xb6, 0x81, 0x1f, 0xeb, 0xd9, 0x69, 0x56, 0xc2, 0xd0, 0x00, 0xe5, 0x55, 0xc0, 0x12, 0xc2, 0xd7, 0x4e, 0xa2, 0x5a, 0x7c, 0x0a, 0xd0, 0x63, 0x9a, 0xd1, 0xaf, 0xd2, 0xe2, 0x3c, 0x12, 0x62, 0x66, 0xc6, 0x42, 0x23, 0x5a, 0x49, 0x8f, 0x10, 0xa2, 0xd2, 0x3e, 0x28, 0x9d, 0xc4, 0x88, 0x09, 0x29, 0x16, 0xc3, 0x3c, 0x24, 0x8d, 0xe6, 0x92, 0x72, 0x1f, 0xff, 0xd2, 0xf3, 0xbb, 0xb0, 0xfe, 0xcb, 0x99, 0xe9, 0xce, 0xf6, 0x88, 0x2d, 0x77, 0x91, 0x5b, 0x3d, 0x3d, 0xd0, 0xe6, 0x90, 0xa9, 0x65, 0x57, 0x38, 0x95, 0xdd, 0xcb, 0x9a, 0x7d, 0xce, 0xf2, 0x3f, 0x44, 0x23, 0x60, 0x58, 0x76, 0xe9, 0xca, 0x8c, 0xea, 0x1b, 0x31, 0x02, 0x32, 0x23, 0xea, 0xee, 0xb1, 0xcd, 0xb0, 0xc7, 0x87, 0x74, 0x7a, 0xeb, 0x70, 0x1a, 0x71, 0xe1, 0xfe, 0xe4, 0x1c, 0x1d, 0xae, 0xe5, 0x69, 0xd8, 0xfa, 0x99, 0x50, 0x0d, 0x1a, 0xf7, 0x2a, 0x3a, 0x0c, 0xf4, 0x1a, 0x8e, 0xc7, 0x27, 0x5d, 0xbf, 0x18, 0x41, 0xdc, 0xc2, 0xf0, 0x7f, 0x74, 0xf6, 0x3a, 0x22, 0x66, 0xdb, 0x68, 0xc6, 0x80, 0x48, 0x6b, 0x88, 0x06, 0x39, 0x0d, 0xee, 0xaa, 0x1f, 0xb3, 0xd5, 0x1b, 0x83, 0xd8, 0x3b, 0x38, 0x8f, 0x69, 0xfe, 0xdf, 0xd1, 0x4d, 0x29, 0xa1, 0x4c, 0x7a, 0xf4, 0xbf, 0xa7, 0x92, 0xcf, 0xa5, 0x20, 0x08, 0xf3, 0xf6, 0xff, 0x00, 0x15, 0xbb, 0xd1, 0x31, 0xd9, 0x5e, 0x3d, 0x75, 0x56, 0x36, 0x88, 0x00, 0x81, 0xe0, 0x16, 0x5e, 0x55, 0x74, 0x3f, 0x00, 0x9d, 0xe0, 0xcc, 0x69, 0xe7, 0x3a, 0x2d, 0xbe, 0x90, 0x00, 0xa9, 0xae, 0xef, 0x1f, 0x95, 0x4b, 0x0d, 0x9a, 0xdc, 0xc7, 0x45, 0xfe, 0xb1, 0x7d, 0x60, 0xa7, 0xa1, 0xe0, 0x1f, 0x4e, 0x1d, 0x99, 0x69, 0x02, 0x9a, 0xcf, 0x1f, 0xca, 0x7b, 0xbf, 0x90, 0xc5, 0xc2, 0xb3, 0xeb, 0x57, 0xd6, 0x03, 0x6b, 0xae, 0x39, 0xb6, 0x82, 0xe3, 0x31, 0xa1, 0x68, 0xf2, 0x6b, 0x5c, 0x12, 0xfa, 0xe1, 0x91, 0x66, 0x47, 0x5d, 0xb8, 0x3b, 0x4f, 0x44, 0x36, 0xb6, 0x8f, 0x28, 0xdd, 0xff, 0x00, 0x7e, 0x46, 0xab, 0x12, 0x2b, 0x65, 0x55, 0x32, 0xa7, 0x62, 0xb6, 0xbd, 0xf7, 0x64, 0x10, 0xdb, 0x03, 0x9f, 0x1b, 0x9e, 0xc7, 0xd9, 0xb8, 0x3b, 0x1f, 0x67, 0xf3, 0x6c, 0x52, 0x80, 0xd7, 0x7d, 0x0f, 0xea, 0x7f, 0x5d, 0x1d, 0x67, 0xa6, 0x0b, 0x1e, 0x47, 0xda, 0x69, 0x3b, 0x2e, 0x03, 0xc7, 0xf3, 0x5f, 0x1f, 0xf0, 0x8b, 0xa1, 0x02, 0x46, 0xba, 0x79, 0xaf, 0x32, 0xff, 0x00, 0x16, 0xad, 0xca, 0x1d, 0x57, 0x2a, 0xdc, 0x79, 0x18, 0x41, 0xb0, 0xf6, 0x9e, 0xe4, 0x9f, 0xd0, 0x8f, 0xeb, 0x31, 0xab, 0xd2, 0x83, 0xa4, 0xcb, 0x8c, 0xb8, 0xa0, 0x42, 0x12, 0x7b, 0x67, 0x9f, 0x2f, 0xf5, 0x09, 0x26, 0x96, 0xc4, 0xce, 0xa9, 0x20, 0xa7, 0xff, 0xd3, 0xf3, 0x2f, 0xb4, 0x5d, 0xe9, 0x0a, 0xb7, 0x9f, 0x4c, 0x19, 0xdb, 0x3a, 0x2d, 0x5e, 0x94, 0xfd, 0xc4, 0xb7, 0xc5, 0x62, 0xf9, 0x2b, 0xfd, 0x2e, 0xe3, 0x5d, 0xe0, 0x7c, 0x13, 0x48, 0xd1, 0x92, 0x12, 0xa9, 0x0b, 0x7a, 0xbc, 0x2d, 0xc2, 0x7f, 0x92, 0x60, 0xab, 0x4e, 0x79, 0x2e, 0x00, 0xf0, 0xaa, 0xe1, 0xda, 0x3d, 0x43, 0xfc, 0xad, 0x55, 0xbb, 0x80, 0x79, 0x81, 0xa0, 0xe6, 0x54, 0x32, 0x6d, 0x02, 0xbe, 0xf3, 0x61, 0x81, 0xa8, 0x44, 0x14, 0x03, 0x59, 0x0e, 0x1c, 0xf6, 0x1f, 0xdc, 0xb2, 0xec, 0xa3, 0x23, 0x77, 0xe8, 0x6e, 0x70, 0xf2, 0x25, 0x1f, 0x1f, 0x17, 0xa9, 0x6d, 0x71, 0x36, 0x97, 0x47, 0x00, 0xa4, 0x02, 0xe0, 0x2c, 0x7c, 0xc1, 0xab, 0xd5, 0x31, 0x85, 0x35, 0xd4, 0xe6, 0x13, 0x02, 0xd6, 0x4b, 0x67, 0x48, 0x2b, 0xa9, 0xe9, 0x2e, 0x02, 0xb6, 0x4f, 0x82, 0xe5, 0x7a, 0x95, 0x19, 0xc6, 0x87, 0x3d, 0xfb, 0xa2, 0xb8, 0x79, 0x1e, 0x4d, 0x3b, 0x96, 0xcf, 0x4f, 0xbd, 0xcd, 0xa2, 0xa2, 0x1f, 0xa0, 0x82, 0xd3, 0xfc, 0x97, 0x05, 0x24, 0x36, 0x6b, 0xf3, 0x31, 0xa2, 0x35, 0x79, 0xef, 0xad, 0xf8, 0xae, 0xaf, 0xaf, 0xd8, 0xf2, 0xd8, 0x6d, 0xed, 0x6b, 0xda, 0x7b, 0x18, 0x1b, 0x5d, 0xff, 0x00, 0x52, 0xb1, 0x6d, 0xf0, 0x81, 0x31, 0xca, 0xf4, 0x6e, 0xb1, 0x80, 0xce, 0xb1, 0x84, 0xc0, 0x21, 0xb7, 0xd6, 0x77, 0x31, 0xd1, 0x27, 0xc1, 0xcd, 0xfe, 0xd2, 0xe3, 0xec, 0xe8, 0x1d, 0x45, 0x96, 0xb0, 0x9a, 0xb7, 0x87, 0x3f, 0x68, 0x2d, 0xf7, 0x01, 0x1f, 0xbe, 0xd1, 0xf4, 0x7f, 0xb4, 0xa4, 0x0d, 0x77, 0xbb, 0xfa, 0x8f, 0x80, 0x3a, 0x7f, 0x43, 0xaa, 0xe2, 0xdf, 0xd2, 0x65, 0x7e, 0x95, 0xe4, 0x0f, 0x1f, 0xa1, 0xfe, 0x6b, 0x16, 0x9f, 0x52, 0xfa, 0xc1, 0xd3, 0xba, 0x6d, 0x26, 0xdc, 0xac, 0x86, 0xd4, 0xd9, 0x0d, 0x31, 0x2e, 0x74, 0x9e, 0xdb, 0x59, 0x2e, 0x55, 0xe8, 0xc9, 0xb2, 0x96, 0xd5, 0x4b, 0x9f, 0xb8, 0x6d, 0xda, 0x1c, 0x04, 0x09, 0x03, 0xfe, 0x8a, 0xc6, 0xfa, 0xd3, 0xf5, 0x6a, 0xbe, 0xbb, 0x5b, 0x2e, 0xc6, 0xb5, 0x94, 0xe6, 0xd5, 0x20, 0x97, 0x7d, 0x1b, 0x1b, 0xf9, 0xad, 0x7c, 0x7d, 0x17, 0xb7, 0xf3, 0x1e, 0x92, 0x1b, 0x7f, 0xf8, 0xe0, 0x7d, 0x59, 0xdd, 0xfd, 0x32, 0xd8, 0x8f, 0xa5, 0xe8, 0x3a, 0x12, 0x5c, 0x3f, 0xfc, 0xc4, 0xfa, 0xc3, 0xb3, 0x77, 0xa7, 0x56, 0xed, 0xdb, 0x76, 0x7a, 0x8d, 0xdd, 0x1f, 0xbf, 0xfd, 0x44, 0x92, 0x56, 0x8f, 0xff, 0xd4, 0xf2, 0xe8, 0x86, 0x17, 0x1e, 0xfa, 0x04, 0x56, 0x4b, 0x43, 0x6c, 0x6f, 0x2d, 0xe5, 0x46, 0x01, 0x64, 0x2b, 0x14, 0x32, 0x5b, 0xb4, 0xa0, 0x52, 0x1d, 0xde, 0x9b, 0x94, 0xdb, 0xab, 0x6b, 0x81, 0xf7, 0x05, 0xb0, 0xd7, 0x07, 0xb2, 0x27, 0x55, 0xc6, 0x57, 0x65, 0xd8, 0x76, 0x6e, 0x64, 0xed, 0xee, 0x16, 0xce, 0x27, 0x57, 0x63, 0xda, 0x0c, 0xc2, 0x8e, 0x51, 0x67, 0x84, 0xfa, 0x1d, 0xdd, 0x62, 0xc7, 0x07, 0xe9, 0xf7, 0xa3, 0xd6, 0x6c, 0x02, 0x41, 0x55, 0x31, 0xf3, 0x2b, 0xb3, 0xba, 0x2b, 0x2e, 0x68, 0x24, 0x1d, 0x47, 0x64, 0xca, 0xa6, 0x50, 0x41, 0x65, 0x90, 0x6c, 0xb1, 0xa5, 0xae, 0x33, 0x23, 0x51, 0xe4, 0xab, 0x7d, 0x5d, 0xcb, 0xb6, 0xcc, 0x37, 0xd0, 0x40, 0x73, 0x71, 0xde, 0x58, 0x09, 0xe7, 0x6f, 0x2c, 0x44, 0xc9, 0xc9, 0xae, 0xba, 0x9d, 0x63, 0x88, 0x01, 0xa0, 0x95, 0x9d, 0xf5, 0x3f, 0x2a, 0xe6, 0x67, 0xdb, 0x50, 0x83, 0x55, 0xad, 0x36, 0x3e, 0x78, 0x10, 0x74, 0x77, 0xfd, 0x2d, 0xaa, 0x4c, 0x7d, 0x58, 0x73, 0x91, 0xa0, 0x0f, 0x51, 0x45, 0xb7, 0x33, 0xdd, 0x58, 0x69, 0x1d, 0xd8, 0x0c, 0x9f, 0x96, 0x88, 0x19, 0x99, 0x19, 0xac, 0xcf, 0xa3, 0xd2, 0xad, 0xb5, 0xdb, 0x76, 0x8f, 0xad, 0xc4, 0xea, 0xcf, 0xdf, 0x7e, 0xdf, 0xdd, 0xfc, 0xd5, 0xa3, 0x5e, 0x43, 0x2b, 0x6b, 0xb2, 0xad, 0x3b, 0x6a, 0xa4, 0x13, 0xa7, 0x04, 0xac, 0x7a, 0x6f, 0xb3, 0x23, 0x26, 0xcc, 0xfb, 0xb4, 0x75, 0x8e, 0x01, 0x83, 0xf7, 0x58, 0x3e, 0x8b, 0x53, 0xa7, 0x2a, 0x1a, 0x31, 0x42, 0x36, 0x5d, 0x4c, 0x9a, 0xf2, 0xdc, 0xc6, 0xfe, 0x98, 0xb4, 0x34, 0xcb, 0x48, 0x0a, 0x8f, 0xdb, 0xb2, 0xeb, 0x76, 0xd6, 0x07, 0x5c, 0x59, 0xc9, 0x64, 0x8f, 0x93, 0xa7, 0x73, 0x16, 0x83, 0xaf, 0x0e, 0xa4, 0x33, 0xef, 0x50, 0xc5, 0x0c, 0xda, 0x59, 0x10, 0x06, 0x8a, 0x2e, 0x29, 0x0e, 0xac, 0xc2, 0x31, 0x3d, 0x36, 0x69, 0x7e, 0xd6, 0xcc, 0xf5, 0x3d, 0x6f, 0xb3, 0xeb, 0x1b, 0x76, 0xef, 0x3b, 0xa3, 0xfa, 0xc9, 0x2b, 0x5f, 0x66, 0x6f, 0xa9, 0x1e, 0x73, 0xf2, 0x49, 0x2e, 0x39, 0xf7, 0x4f, 0xb7, 0x8d, 0xff, 0xd5, 0xf3, 0x26, 0xfe, 0x0a, 0xc5, 0x1b, 0xa7, 0xcb, 0xb2, 0xcf, 0x49, 0x03, 0xb2, 0x46, 0xee, 0xd9, 0xd9, 0xb3, 0xf4, 0x9f, 0x25, 0x4a, 0xdf, 0x4b, 0x77, 0xe8, 0x27, 0xd4, 0xef, 0x1c, 0x2a, 0x29, 0x26, 0xc5, 0x7c, 0x9d, 0x6c, 0x7f, 0xb7, 0x6e, 0x1b, 0x26, 0x7f, 0x05, 0xa3, 0xfe, 0x53, 0x8d, 0x62, 0x57, 0x30, 0x92, 0x12, 0xfa, 0x2f, 0x86, 0xdf, 0xa4, 0xec, 0x67, 0xfe, 0xd0, 0xf4, 0xff, 0x00, 0x4d, 0xfc, 0xdf, 0x78, 0xe1, 0x68, 0x7d, 0x54, 0x99, 0xbf, 0x6f, 0xf3, 0xbe, 0xdf, 0x8e, 0xdd, 0x7f, 0xef, 0xeb, 0x97, 0x49, 0x3e, 0x3b, 0x7f, 0x06, 0x2c, 0x9f, 0x37, 0x5f, 0xf0, 0x9f, 0x4c, 0xeb, 0x7b, 0xbf, 0x67, 0x55, 0xe8, 0xff, 0x00, 0x31, 0xbc, 0x7a, 0x9e, 0x31, 0xdb, 0xfe, 0x92, 0xae, 0x37, 0x7a, 0x4d, 0xdb, 0xe2, 0x17, 0x9d, 0xa4, 0xa3, 0xc9, 0xba, 0xfc, 0x7b, 0x7d, 0x5f, 0x52, 0xa7, 0x7e, 0xd1, 0x28, 0xf8, 0xf3, 0xb0, 0xc7, 0x32, 0xbc, 0x99, 0x24, 0xc5, 0xe3, 0xab, 0xeb, 0x1f, 0xa4, 0xf5, 0xfc, 0xe1, 0x25, 0xe4, 0xe9, 0x24, 0x97, 0xff, 0xd9, 0xff, 0xed, 0x2e, 0x1c, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x20, 0x33, 0x2e, 0x30, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x1c, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x1c, 0x02, 0x78, 0x00, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xfb, 0x09, 0xa6, 0xbd, 0x07, 0x4c, 0x2a, 0x36, 0x9d, 0x8f, 0xe2, 0xcc, 0x57, 0xa9, 0xac, 0x85, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xea, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xb0, 0x3c, 0x3f, 0x78, 0x6d, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x22, 0x3f, 0x3e, 0x0a, 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x2f, 0x44, 0x54, 0x44, 0x20, 0x50, 0x4c, 0x49, 0x53, 0x54, 0x20, 0x31, 0x2e, 0x30, 0x2f, 0x2f, 0x45, 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x54, 0x44, 0x73, 0x2f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x2d, 0x31, 0x2e, 0x30, 0x2e, 0x64, 0x74, 0x64, 0x22, 0x3e, 0x0a, 0x3c, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x3e, 0x0a, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x48, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x48, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x32, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x31, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x31, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x32, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x31, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x73, 0x75, 0x62, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x61, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x33, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x37, 0x36, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x37, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x39, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x6e, 0x61, 0x2d, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x54, 0x31, 0x37, 0x3a, 0x34, 0x39, 0x3a, 0x33, 0x36, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x31, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x33, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x37, 0x36, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x37, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x39, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x70, 0x64, 0x2e, 0x50, 0x4d, 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x70, 0x64, 0x2e, 0x50, 0x4d, 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x55, 0x53, 0x20, 0x4c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x54, 0x31, 0x37, 0x3a, 0x34, 0x39, 0x3a, 0x33, 0x36, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x31, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x41, 0x50, 0x49, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x30, 0x30, 0x2e, 0x32, 0x30, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2f, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x41, 0x50, 0x49, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x30, 0x30, 0x2e, 0x32, 0x30, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2f, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x3c, 0x2f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3e, 0x0a, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0xde, 0x02, 0x40, 0xff, 0xee, 0xff, 0xee, 0x03, 0x06, 0x02, 0x52, 0x03, 0x67, 0x05, 0x28, 0x03, 0xfc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd8, 0x02, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x01, 0x7f, 0xff, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x08, 0x00, 0x19, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x2f, 0x66, 0x66, 0x00, 0x01, 0x00, 0x6c, 0x66, 0x66, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2f, 0x66, 0x66, 0x00, 0x01, 0x00, 0xa1, 0x99, 0x9a, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x03, 0x45, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x08, 0x00, 0x44, 0x00, 0x53, 0x00, 0x43, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x32, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x75, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x4f, 0x62, 0x6a, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x63, 0x74, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x70, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x74, 0x6f, 0x6d, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x52, 0x67, 0x68, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x06, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x56, 0x6c, 0x4c, 0x73, 0x00, 0x00, 0x00, 0x01, 0x4f, 0x62, 0x6a, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x07, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x49, 0x44, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0c, 0x45, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x6f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x54, 0x79, 0x70, 0x65, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0a, 0x45, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6d, 0x67, 0x20, 0x00, 0x00, 0x00, 0x06, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x4f, 0x62, 0x6a, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x63, 0x74, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x70, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x74, 0x6f, 0x6d, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x52, 0x67, 0x68, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, 0x6c, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x75, 0x6c, 0x6c, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x73, 0x67, 0x65, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x61, 0x6c, 0x74, 0x54, 0x61, 0x67, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x63, 0x65, 0x6c, 0x6c, 0x54, 0x65, 0x78, 0x74, 0x49, 0x73, 0x48, 0x54, 0x4d, 0x4c, 0x62, 0x6f, 0x6f, 0x6c, 0x01, 0x00, 0x00, 0x00, 0x08, 0x63, 0x65, 0x6c, 0x6c, 0x54, 0x65, 0x78, 0x74, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x68, 0x6f, 0x72, 0x7a, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0f, 0x45, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x48, 0x6f, 0x72, 0x7a, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x00, 0x00, 0x00, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x00, 0x00, 0x09, 0x76, 0x65, 0x72, 0x74, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0f, 0x45, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x74, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x00, 0x00, 0x00, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x00, 0x00, 0x0b, 0x62, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x11, 0x45, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x42, 0x47, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x09, 0x74, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6c, 0x65, 0x66, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x72, 0x69, 0x67, 0x68, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf9, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0x09, 0xdd, 0x00, 0x18, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xed, 0x00, 0x0c, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x5f, 0x43, 0x4d, 0x00, 0x02, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x00, 0x64, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0c, 0x09, 0x09, 0x0c, 0x11, 0x0b, 0x0a, 0x0b, 0x11, 0x15, 0x0f, 0x0c, 0x0c, 0x0f, 0x15, 0x18, 0x13, 0x13, 0x15, 0x13, 0x13, 0x18, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x0d, 0x0b, 0x0b, 0x0d, 0x0e, 0x0d, 0x10, 0x0e, 0x0e, 0x10, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x07, 0xff, 0xc4, 0x01, 0x3f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x01, 0x04, 0x01, 0x03, 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08, 0x05, 0x03, 0x0c, 0x33, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31, 0x05, 0x41, 0x51, 0x61, 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14, 0x91, 0xa1, 0xb1, 0x42, 0x23, 0x24, 0x15, 0x52, 0xc1, 0x62, 0x33, 0x34, 0x72, 0x82, 0xd1, 0x43, 0x07, 0x25, 0x92, 0x53, 0xf0, 0xe1, 0xf1, 0x63, 0x73, 0x35, 0x16, 0xa2, 0xb2, 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45, 0xc2, 0xa3, 0x74, 0x36, 0x17, 0xd2, 0x55, 0xe2, 0x65, 0xf2, 0xb3, 0x84, 0xc3, 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x27, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x11, 0x00, 0x02, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x35, 0x01, 0x00, 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04, 0x41, 0x51, 0x61, 0x71, 0x22, 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xa1, 0xb1, 0x42, 0x23, 0xc1, 0x52, 0xd1, 0xf0, 0x33, 0x24, 0x62, 0xe1, 0x72, 0x82, 0x92, 0x43, 0x53, 0x15, 0x63, 0x73, 0x34, 0xf1, 0x25, 0x06, 0x16, 0xa2, 0xb2, 0x83, 0x07, 0x26, 0x35, 0xc2, 0xd2, 0x44, 0x93, 0x54, 0xa3, 0x17, 0x64, 0x45, 0x55, 0x36, 0x74, 0x65, 0xe2, 0xf2, 0xb3, 0x84, 0xc3, 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf2, 0xed, 0xb2, 0x8d, 0x4d, 0x45, 0xcd, 0x2f, 0x3f, 0x44, 0x68, 0x93, 0xc3, 0x58, 0xc8, 0xf1, 0x1f, 0x8a, 0x33, 0x86, 0xda, 0x58, 0xc1, 0xa0, 0x02, 0x4f, 0xc4, 0xa1, 0x69, 0xa5, 0x9b, 0x5b, 0x4b, 0x84, 0x73, 0xdf, 0xc9, 0x15, 0xf8, 0xe3, 0xd1, 0x0e, 0x07, 0x93, 0xf3, 0xd1, 0x0f, 0x1c, 0x17, 0xef, 0x2e, 0x3b, 0x5b, 0xdc, 0xff, 0x00, 0xdf, 0x42, 0xbf, 0x8f, 0x8e, 0xdc, 0x82, 0xca, 0xd8, 0x37, 0x11, 0xa9, 0x3d, 0x82, 0x69, 0x2b, 0xc4, 0x6d, 0xc9, 0x75, 0x25, 0xbc, 0xf7, 0xec, 0xa1, 0xb5, 0x74, 0x19, 0x5d, 0x2e, 0x8a, 0x9a, 0x4b, 0x89, 0x7d, 0xc4, 0x68, 0xc6, 0xf6, 0xfe, 0xb2, 0xa0, 0x30, 0x1d, 0x60, 0x86, 0x88, 0x8d, 0x49, 0x3e, 0x01, 0x11, 0x20, 0xa3, 0x8c, 0xb9, 0xb1, 0xaa, 0x62, 0xad, 0xbf, 0x18, 0x97, 0x43, 0x47, 0x1d, 0xd2, 0xaf, 0x04, 0xd9, 0xb8, 0xc8, 0x0d, 0x68, 0xe4, 0xf7, 0x3e, 0x48, 0xf1, 0x05, 0xbc, 0x25, 0xaa, 0x07, 0x71, 0xd9, 0x14, 0x78, 0xf6, 0x49, 0xb5, 0x90, 0xfd, 0xa7, 0xc6, 0x14, 0xfd, 0x1b, 0x1c, 0xff, 0x00, 0x4d, 0x8d, 0x2e, 0x73, 0x8c, 0x35, 0xa3, 0x52, 0x4f, 0x92, 0x48, 0xa6, 0x1a, 0x24, 0xb6, 0x2a, 0xfa, 0xa5, 0x9e, 0x60, 0x64, 0x39, 0x94, 0x13, 0xcb, 0x27, 0x73, 0x80, 0xf3, 0x0c, 0xf6, 0xff, 0x00, 0xd2, 0x5a, 0x78, 0xbf, 0x53, 0x71, 0xf6, 0x01, 0x75, 0xb6, 0x97, 0x6a, 0x25, 0xa1, 0xad, 0x1f, 0xf4, 0xb7, 0x23, 0x48, 0xb7, 0x94, 0x84, 0x97, 0x5b, 0xff, 0x00, 0x32, 0xa9, 0xdd, 0xfc, 0xed, 0x9b, 0x7e, 0x0d, 0x9e, 0x52, 0x4a, 0x95, 0x61, 0xff, 0xd0, 0xf3, 0x3b, 0xa7, 0x70, 0xee, 0x01, 0x8f, 0xb9, 0x59, 0xfa, 0x7e, 0xdf, 0xe4, 0xc8, 0xf9, 0x2a, 0xc2, 0x5c, 0x63, 0xc3, 0x54, 0x67, 0x87, 0x6e, 0x10, 0x35, 0x68, 0xd4, 0x79, 0x1e, 0x53, 0x4a, 0xe0, 0xdc, 0xe9, 0xb8, 0x1f, 0x6a, 0xda, 0x6c, 0x25, 0x94, 0x37, 0xb0, 0xd0, 0xb8, 0xad, 0x67, 0xe4, 0x55, 0x8a, 0x5b, 0x8b, 0x82, 0xc0, 0x6f, 0x76, 0x80, 0x34, 0x49, 0x05, 0x2e, 0x9e, 0xc6, 0x1c, 0x66, 0x31, 0xba, 0x10, 0x23, 0xe0, 0xaf, 0xe1, 0x61, 0x53, 0x43, 0x8d, 0x81, 0xb3, 0x67, 0xef, 0x9e, 0x49, 0x2a, 0x12, 0x6c, 0xb6, 0x63, 0x1a, 0x0c, 0x31, 0xba, 0x55, 0xcd, 0xac, 0xfa, 0x8e, 0xdf, 0x91, 0x6e, 0x91, 0xd9, 0xb3, 0xc9, 0x73, 0x90, 0x7a, 0xab, 0x6a, 0xc2, 0xa4, 0x60, 0xe2, 0x8f, 0xd2, 0x38, 0x03, 0x7d, 0x9e, 0x0d, 0xff, 0x00, 0xcc, 0xd6, 0xd3, 0x6b, 0x71, 0x67, 0xd2, 0x3e, 0x64, 0x72, 0xab, 0xdb, 0x8d, 0x54, 0x39, 0xc5, 0x83, 0x6b, 0x3d, 0xee, 0x2e, 0xd4, 0x92, 0x3c, 0x4a, 0x56, 0xba, 0xb4, 0x79, 0x5c, 0xf7, 0xb2, 0x96, 0x6c, 0x8d, 0xaf, 0x80, 0x48, 0x3c, 0xf0, 0xb2, 0x1f, 0x63, 0x9c, 0xe9, 0x3f, 0x24, 0x5c, 0xdb, 0xdd, 0x76, 0x43, 0xde, 0xfd, 0x5c, 0xe3, 0x24, 0xfc, 0x50, 0x00, 0x93, 0x0a, 0x78, 0x8a, 0x0d, 0x49, 0xca, 0xcf, 0x93, 0x63, 0x1b, 0x7d, 0xd7, 0x57, 0x50, 0xd5, 0xef, 0x70, 0x6b, 0x4f, 0xc7, 0x45, 0xdb, 0x74, 0x9e, 0x8d, 0x5e, 0x33, 0x83, 0xd8, 0x37, 0xdd, 0xc3, 0xac, 0x3d, 0xbf, 0x92, 0xc5, 0x5b, 0xea, 0xbf, 0xd5, 0x62, 0xc0, 0xdc, 0xbc, 0xbd, 0x2d, 0x22, 0x5a, 0xcf, 0xdd, 0x69, 0xff, 0x00, 0xd1, 0x8e, 0x5d, 0xa5, 0x38, 0xb5, 0xb0, 0x00, 0xc6, 0xc4, 0x24, 0x4a, 0xd6, 0x8d, 0x18, 0x04, 0x49, 0x88, 0x9e, 0x55, 0xd6, 0x61, 0xb0, 0xc1, 0x70, 0x32, 0xdd, 0x3c, 0x95, 0xda, 0xf1, 0xfe, 0xf5, 0x62, 0xbc, 0x76, 0x8e, 0x75, 0x28, 0x02, 0xa2, 0xe7, 0x7d, 0x92, 0xb9, 0x84, 0x96, 0x96, 0xda, 0xf7, 0x70, 0x12, 0x4e, 0x5a, 0xff, 0x00, 0xff, 0xd1, 0xf3, 0x7a, 0x21, 0xaf, 0xde, 0xef, 0xa2, 0x22, 0x55, 0xfc, 0x5a, 0xbd, 0x42, 0xfb, 0x08, 0xfa, 0x67, 0x4f, 0x82, 0xcd, 0x6d, 0x85, 0xc0, 0x56, 0x3b, 0x90, 0xb7, 0xf0, 0x2a, 0x0e, 0x63, 0x58, 0x3b, 0xf2, 0xa3, 0x9e, 0x8c, 0xb8, 0x86, 0xbe, 0x49, 0xf1, 0x2c, 0x0c, 0x86, 0xb4, 0x4c, 0x69, 0xe4, 0xaf, 0x6e, 0xcc, 0x6b, 0x7d, 0x46, 0xb3, 0x70, 0xec, 0x38, 0x51, 0x7d, 0x02, 0x8a, 0xc7, 0xa6, 0xd9, 0x20, 0x68, 0x0f, 0x8f, 0x8a, 0xcf, 0xc9, 0xc2, 0xea, 0x59, 0x5b, 0x48, 0xb0, 0x91, 0xae, 0xe6, 0xc9, 0x03, 0xc9, 0x30, 0x51, 0x66, 0xd4, 0x0d, 0xad, 0xbd, 0x5f, 0x53, 0xcc, 0x6b, 0xb6, 0x90, 0x5a, 0x3b, 0x83, 0x0b, 0x43, 0x17, 0x31, 0xd6, 0xc3, 0x6e, 0x12, 0x3b, 0x79, 0xac, 0xc1, 0x89, 0x47, 0xd9, 0xe8, 0x63, 0x98, 0x45, 0xed, 0x6c, 0x5a, 0xf1, 0xa0, 0x27, 0xc5, 0x5b, 0xc3, 0x6f, 0xa6, 0xe0, 0x1c, 0x7d, 0xb3, 0xa2, 0x69, 0x34, 0x7b, 0xae, 0x1a, 0x8d, 0x45, 0x17, 0x9d, 0xeb, 0xfd, 0x21, 0xd8, 0xb9, 0xae, 0xb5, 0x80, 0xbb, 0x1e, 0xd2, 0x5c, 0xd7, 0x78, 0x13, 0xf9, 0xae, 0x4b, 0xea, 0xc7, 0x4a, 0x39, 0xbd, 0x55, 0xb3, 0xed, 0x66, 0x38, 0xf5, 0x09, 0x22, 0x41, 0x23, 0xe8, 0x37, 0xfb, 0x4b, 0xa1, 0xeb, 0xd6, 0xfe, 0x88, 0x31, 0xbf, 0x41, 0xc0, 0xee, 0xd2, 0x74, 0x02, 0x78, 0x53, 0xfa, 0x97, 0x43, 0x19, 0x85, 0x65, 0xff, 0x00, 0x9d, 0x71, 0x33, 0xe4, 0x1a, 0x7d, 0x8d, 0x53, 0x42, 0x56, 0x35, 0x6b, 0xe5, 0x80, 0x06, 0xc7, 0x57, 0xa7, 0xc4, 0xa9, 0xdb, 0xb6, 0x81, 0x1f, 0xeb, 0xd9, 0x69, 0x56, 0xc2, 0xd0, 0x00, 0xe5, 0x55, 0xc0, 0x12, 0xc2, 0xd7, 0x4e, 0xa2, 0x5a, 0x7c, 0x0a, 0xd0, 0x63, 0x9a, 0xd1, 0xaf, 0xd2, 0xe2, 0x3c, 0x12, 0x62, 0x66, 0xc6, 0x42, 0x23, 0x5a, 0x49, 0x8f, 0x10, 0xa2, 0xd2, 0x3e, 0x28, 0x9d, 0xc4, 0x88, 0x09, 0x29, 0x16, 0xc3, 0x3c, 0x24, 0x8d, 0xe6, 0x92, 0x72, 0x1f, 0xff, 0xd2, 0xf3, 0xbb, 0xb0, 0xfe, 0xcb, 0x99, 0xe9, 0xce, 0xf6, 0x88, 0x2d, 0x77, 0x91, 0x5b, 0x3d, 0x3d, 0xd0, 0xe6, 0x90, 0xa9, 0x65, 0x57, 0x38, 0x95, 0xdd, 0xcb, 0x9a, 0x7d, 0xce, 0xf2, 0x3f, 0x44, 0x23, 0x60, 0x58, 0x76, 0xe9, 0xca, 0x8c, 0xea, 0x1b, 0x31, 0x02, 0x32, 0x23, 0xea, 0xee, 0xb1, 0xcd, 0xb0, 0xc7, 0x87, 0x74, 0x7a, 0xeb, 0x70, 0x1a, 0x71, 0xe1, 0xfe, 0xe4, 0x1c, 0x1d, 0xae, 0xe5, 0x69, 0xd8, 0xfa, 0x99, 0x50, 0x0d, 0x1a, 0xf7, 0x2a, 0x3a, 0x0c, 0xf4, 0x1a, 0x8e, 0xc7, 0x27, 0x5d, 0xbf, 0x18, 0x41, 0xdc, 0xc2, 0xf0, 0x7f, 0x74, 0xf6, 0x3a, 0x22, 0x66, 0xdb, 0x68, 0xc6, 0x80, 0x48, 0x6b, 0x88, 0x06, 0x39, 0x0d, 0xee, 0xaa, 0x1f, 0xb3, 0xd5, 0x1b, 0x83, 0xd8, 0x3b, 0x38, 0x8f, 0x69, 0xfe, 0xdf, 0xd1, 0x4d, 0x29, 0xa1, 0x4c, 0x7a, 0xf4, 0xbf, 0xa7, 0x92, 0xcf, 0xa5, 0x20, 0x08, 0xf3, 0xf6, 0xff, 0x00, 0x15, 0xbb, 0xd1, 0x31, 0xd9, 0x5e, 0x3d, 0x75, 0x56, 0x36, 0x88, 0x00, 0x81, 0xe0, 0x16, 0x5e, 0x55, 0x74, 0x3f, 0x00, 0x9d, 0xe0, 0xcc, 0x69, 0xe7, 0x3a, 0x2d, 0xbe, 0x90, 0x00, 0xa9, 0xae, 0xef, 0x1f, 0x95, 0x4b, 0x0d, 0x9a, 0xdc, 0xc7, 0x45, 0xfe, 0xb1, 0x7d, 0x60, 0xa7, 0xa1, 0xe0, 0x1f, 0x4e, 0x1d, 0x99, 0x69, 0x02, 0x9a, 0xcf, 0x1f, 0xca, 0x7b, 0xbf, 0x90, 0xc5, 0xc2, 0xb3, 0xeb, 0x57, 0xd6, 0x03, 0x6b, 0xae, 0x39, 0xb6, 0x82, 0xe3, 0x31, 0xa1, 0x68, 0xf2, 0x6b, 0x5c, 0x12, 0xfa, 0xe1, 0x91, 0x66, 0x47, 0x5d, 0xb8, 0x3b, 0x4f, 0x44, 0x36, 0xb6, 0x8f, 0x28, 0xdd, 0xff, 0x00, 0x7e, 0x46, 0xab, 0x12, 0x2b, 0x65, 0x55, 0x32, 0xa7, 0x62, 0xb6, 0xbd, 0xf7, 0x64, 0x10, 0xdb, 0x03, 0x9f, 0x1b, 0x9e, 0xc7, 0xd9, 0xb8, 0x3b, 0x1f, 0x67, 0xf3, 0x6c, 0x52, 0x80, 0xd7, 0x7d, 0x0f, 0xea, 0x7f, 0x5d, 0x1d, 0x67, 0xa6, 0x0b, 0x1e, 0x47, 0xda, 0x69, 0x3b, 0x2e, 0x03, 0xc7, 0xf3, 0x5f, 0x1f, 0xf0, 0x8b, 0xa1, 0x02, 0x46, 0xba, 0x79, 0xaf, 0x32, 0xff, 0x00, 0x16, 0xad, 0xca, 0x1d, 0x57, 0x2a, 0xdc, 0x79, 0x18, 0x41, 0xb0, 0xf6, 0x9e, 0xe4, 0x9f, 0xd0, 0x8f, 0xeb, 0x31, 0xab, 0xd2, 0x83, 0xa4, 0xcb, 0x8c, 0xb8, 0xa0, 0x42, 0x12, 0x7b, 0x67, 0x9f, 0x2f, 0xf5, 0x09, 0x26, 0x96, 0xc4, 0xce, 0xa9, 0x20, 0xa7, 0xff, 0xd3, 0xf3, 0x2f, 0xb4, 0x5d, 0xe9, 0x0a, 0xb7, 0x9f, 0x4c, 0x19, 0xdb, 0x3a, 0x2d, 0x5e, 0x94, 0xfd, 0xc4, 0xb7, 0xc5, 0x62, 0xf9, 0x2b, 0xfd, 0x2e, 0xe3, 0x5d, 0xe0, 0x7c, 0x13, 0x48, 0xd1, 0x92, 0x12, 0xa9, 0x0b, 0x7a, 0xbc, 0x2d, 0xc2, 0x7f, 0x92, 0x60, 0xab, 0x4e, 0x79, 0x2e, 0x00, 0xf0, 0xaa, 0xe1, 0xda, 0x3d, 0x43, 0xfc, 0xad, 0x55, 0xbb, 0x80, 0x79, 0x81, 0xa0, 0xe6, 0x54, 0x32, 0x6d, 0x02, 0xbe, 0xf3, 0x61, 0x81, 0xa8, 0x44, 0x14, 0x03, 0x59, 0x0e, 0x1c, 0xf6, 0x1f, 0xdc, 0xb2, 0xec, 0xa3, 0x23, 0x77, 0xe8, 0x6e, 0x70, 0xf2, 0x25, 0x1f, 0x1f, 0x17, 0xa9, 0x6d, 0x71, 0x36, 0x97, 0x47, 0x00, 0xa4, 0x02, 0xe0, 0x2c, 0x7c, 0xc1, 0xab, 0xd5, 0x31, 0x85, 0x35, 0xd4, 0xe6, 0x13, 0x02, 0xd6, 0x4b, 0x67, 0x48, 0x2b, 0xa9, 0xe9, 0x2e, 0x02, 0xb6, 0x4f, 0x82, 0xe5, 0x7a, 0x95, 0x19, 0xc6, 0x87, 0x3d, 0xfb, 0xa2, 0xb8, 0x79, 0x1e, 0x4d, 0x3b, 0x96, 0xcf, 0x4f, 0xbd, 0xcd, 0xa2, 0xa2, 0x1f, 0xa0, 0x82, 0xd3, 0xfc, 0x97, 0x05, 0x24, 0x36, 0x6b, 0xf3, 0x31, 0xa2, 0x35, 0x79, 0xef, 0xad, 0xf8, 0xae, 0xaf, 0xaf, 0xd8, 0xf2, 0xd8, 0x6d, 0xed, 0x6b, 0xda, 0x7b, 0x18, 0x1b, 0x5d, 0xff, 0x00, 0x52, 0xb1, 0x6d, 0xf0, 0x81, 0x31, 0xca, 0xf4, 0x6e, 0xb1, 0x80, 0xce, 0xb1, 0x84, 0xc0, 0x21, 0xb7, 0xd6, 0x77, 0x31, 0xd1, 0x27, 0xc1, 0xcd, 0xfe, 0xd2, 0xe3, 0xec, 0xe8, 0x1d, 0x45, 0x96, 0xb0, 0x9a, 0xb7, 0x87, 0x3f, 0x68, 0x2d, 0xf7, 0x01, 0x1f, 0xbe, 0xd1, 0xf4, 0x7f, 0xb4, 0xa4, 0x0d, 0x77, 0xbb, 0xfa, 0x8f, 0x80, 0x3a, 0x7f, 0x43, 0xaa, 0xe2, 0xdf, 0xd2, 0x65, 0x7e, 0x95, 0xe4, 0x0f, 0x1f, 0xa1, 0xfe, 0x6b, 0x16, 0x9f, 0x52, 0xfa, 0xc1, 0xd3, 0xba, 0x6d, 0x26, 0xdc, 0xac, 0x86, 0xd4, 0xd9, 0x0d, 0x31, 0x2e, 0x74, 0x9e, 0xdb, 0x59, 0x2e, 0x55, 0xe8, 0xc9, 0xb2, 0x96, 0xd5, 0x4b, 0x9f, 0xb8, 0x6d, 0xda, 0x1c, 0x04, 0x09, 0x03, 0xfe, 0x8a, 0xc6, 0xfa, 0xd3, 0xf5, 0x6a, 0xbe, 0xbb, 0x5b, 0x2e, 0xc6, 0xb5, 0x94, 0xe6, 0xd5, 0x20, 0x97, 0x7d, 0x1b, 0x1b, 0xf9, 0xad, 0x7c, 0x7d, 0x17, 0xb7, 0xf3, 0x1e, 0x92, 0x1b, 0x7f, 0xf8, 0xe0, 0x7d, 0x59, 0xdd, 0xfd, 0x32, 0xd8, 0x8f, 0xa5, 0xe8, 0x3a, 0x12, 0x5c, 0x3f, 0xfc, 0xc4, 0xfa, 0xc3, 0xb3, 0x77, 0xa7, 0x56, 0xed, 0xdb, 0x76, 0x7a, 0x8d, 0xdd, 0x1f, 0xbf, 0xfd, 0x44, 0x92, 0x56, 0x8f, 0xff, 0xd4, 0xf2, 0xe8, 0x86, 0x17, 0x1e, 0xfa, 0x04, 0x56, 0x4b, 0x43, 0x6c, 0x6f, 0x2d, 0xe5, 0x46, 0x01, 0x64, 0x2b, 0x14, 0x32, 0x5b, 0xb4, 0xa0, 0x52, 0x1d, 0xde, 0x9b, 0x94, 0xdb, 0xab, 0x6b, 0x81, 0xf7, 0x05, 0xb0, 0xd7, 0x07, 0xb2, 0x27, 0x55, 0xc6, 0x57, 0x65, 0xd8, 0x76, 0x6e, 0x64, 0xed, 0xee, 0x16, 0xce, 0x27, 0x57, 0x63, 0xda, 0x0c, 0xc2, 0x8e, 0x51, 0x67, 0x84, 0xfa, 0x1d, 0xdd, 0x62, 0xc7, 0x07, 0xe9, 0xf7, 0xa3, 0xd6, 0x6c, 0x02, 0x41, 0x55, 0x31, 0xf3, 0x2b, 0xb3, 0xba, 0x2b, 0x2e, 0x68, 0x24, 0x1d, 0x47, 0x64, 0xca, 0xa6, 0x50, 0x41, 0x65, 0x90, 0x6c, 0xb1, 0xa5, 0xae, 0x33, 0x23, 0x51, 0xe4, 0xab, 0x7d, 0x5d, 0xcb, 0xb6, 0xcc, 0x37, 0xd0, 0x40, 0x73, 0x71, 0xde, 0x58, 0x09, 0xe7, 0x6f, 0x2c, 0x44, 0xc9, 0xc9, 0xae, 0xba, 0x9d, 0x63, 0x88, 0x01, 0xa0, 0x95, 0x9d, 0xf5, 0x3f, 0x2a, 0xe6, 0x67, 0xdb, 0x50, 0x83, 0x55, 0xad, 0x36, 0x3e, 0x78, 0x10, 0x74, 0x77, 0xfd, 0x2d, 0xaa, 0x4c, 0x7d, 0x58, 0x73, 0x91, 0xa0, 0x0f, 0x51, 0x45, 0xb7, 0x33, 0xdd, 0x58, 0x69, 0x1d, 0xd8, 0x0c, 0x9f, 0x96, 0x88, 0x19, 0x99, 0x19, 0xac, 0xcf, 0xa3, 0xd2, 0xad, 0xb5, 0xdb, 0x76, 0x8f, 0xad, 0xc4, 0xea, 0xcf, 0xdf, 0x7e, 0xdf, 0xdd, 0xfc, 0xd5, 0xa3, 0x5e, 0x43, 0x2b, 0x6b, 0xb2, 0xad, 0x3b, 0x6a, 0xa4, 0x13, 0xa7, 0x04, 0xac, 0x7a, 0x6f, 0xb3, 0x23, 0x26, 0xcc, 0xfb, 0xb4, 0x75, 0x8e, 0x01, 0x83, 0xf7, 0x58, 0x3e, 0x8b, 0x53, 0xa7, 0x2a, 0x1a, 0x31, 0x42, 0x36, 0x5d, 0x4c, 0x9a, 0xf2, 0xdc, 0xc6, 0xfe, 0x98, 0xb4, 0x34, 0xcb, 0x48, 0x0a, 0x8f, 0xdb, 0xb2, 0xeb, 0x76, 0xd6, 0x07, 0x5c, 0x59, 0xc9, 0x64, 0x8f, 0x93, 0xa7, 0x73, 0x16, 0x83, 0xaf, 0x0e, 0xa4, 0x33, 0xef, 0x50, 0xc5, 0x0c, 0xda, 0x59, 0x10, 0x06, 0x8a, 0x2e, 0x29, 0x0e, 0xac, 0xc2, 0x31, 0x3d, 0x36, 0x69, 0x7e, 0xd6, 0xcc, 0xf5, 0x3d, 0x6f, 0xb3, 0xeb, 0x1b, 0x76, 0xef, 0x3b, 0xa3, 0xfa, 0xc9, 0x2b, 0x5f, 0x66, 0x6f, 0xa9, 0x1e, 0x73, 0xf2, 0x49, 0x2e, 0x39, 0xf7, 0x4f, 0xb7, 0x8d, 0xff, 0xd5, 0xf3, 0x26, 0xfe, 0x0a, 0xc5, 0x1b, 0xa7, 0xcb, 0xb2, 0xcf, 0x49, 0x03, 0xb2, 0x46, 0xee, 0xd9, 0xd9, 0xb3, 0xf4, 0x9f, 0x25, 0x4a, 0xdf, 0x4b, 0x77, 0xe8, 0x27, 0xd4, 0xef, 0x1c, 0x2a, 0x29, 0x26, 0xc5, 0x7c, 0x9d, 0x6c, 0x7f, 0xb7, 0x6e, 0x1b, 0x26, 0x7f, 0x05, 0xa3, 0xfe, 0x53, 0x8d, 0x62, 0x57, 0x30, 0x92, 0x12, 0xfa, 0x2f, 0x86, 0xdf, 0xa4, 0xec, 0x67, 0xfe, 0xd0, 0xf4, 0xff, 0x00, 0x4d, 0xfc, 0xdf, 0x78, 0xe1, 0x68, 0x7d, 0x54, 0x99, 0xbf, 0x6f, 0xf3, 0xbe, 0xdf, 0x8e, 0xdd, 0x7f, 0xef, 0xeb, 0x97, 0x49, 0x3e, 0x3b, 0x7f, 0x06, 0x2c, 0x9f, 0x37, 0x5f, 0xf0, 0x9f, 0x4c, 0xeb, 0x7b, 0xbf, 0x67, 0x55, 0xe8, 0xff, 0x00, 0x31, 0xbc, 0x7a, 0x9e, 0x31, 0xdb, 0xfe, 0x92, 0xae, 0x37, 0x7a, 0x4d, 0xdb, 0xe2, 0x17, 0x9d, 0xa4, 0xa3, 0xc9, 0xba, 0xfc, 0x7b, 0x7d, 0x5f, 0x52, 0xa7, 0x7e, 0xd1, 0x28, 0xf8, 0xf3, 0xb0, 0xc7, 0x32, 0xbc, 0x99, 0x24, 0xc5, 0xe3, 0xab, 0xeb, 0x1f, 0xa4, 0xf5, 0xfc, 0xe1, 0x25, 0xe4, 0xe9, 0x24, 0x97, 0xff, 0xd9, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x20, 0x00, 0x37, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xff, 0xe1, 0x15, 0x67, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x00, 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x3d, 0x27, 0xef, 0xbb, 0xbf, 0x27, 0x20, 0x69, 0x64, 0x3d, 0x27, 0x57, 0x35, 0x4d, 0x30, 0x4d, 0x70, 0x43, 0x65, 0x68, 0x69, 0x48, 0x7a, 0x72, 0x65, 0x53, 0x7a, 0x4e, 0x54, 0x63, 0x7a, 0x6b, 0x63, 0x39, 0x64, 0x27, 0x3f, 0x3e, 0x0a, 0x3c, 0x3f, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2d, 0x78, 0x61, 0x70, 0x2d, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x20, 0x65, 0x73, 0x63, 0x3d, 0x22, 0x43, 0x52, 0x22, 0x3f, 0x3e, 0x0a, 0x3c, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x27, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x6e, 0x73, 0x3a, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x27, 0x20, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x74, 0x6b, 0x3d, 0x27, 0x58, 0x4d, 0x50, 0x20, 0x74, 0x6f, 0x6f, 0x6c, 0x6b, 0x69, 0x74, 0x20, 0x32, 0x2e, 0x38, 0x2e, 0x32, 0x2d, 0x33, 0x33, 0x2c, 0x20, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x31, 0x2e, 0x35, 0x27, 0x3e, 0x0a, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x31, 0x39, 0x39, 0x39, 0x2f, 0x30, 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, 0x27, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x69, 0x58, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x58, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x27, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x70, 0x64, 0x66, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x64, 0x66, 0x2f, 0x31, 0x2e, 0x33, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x20, 0x70, 0x64, 0x66, 0x3a, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x20, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3a, 0x43, 0x61, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x61, 0x70, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x20, 0x78, 0x61, 0x70, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x61, 0x70, 0x4d, 0x4d, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x6d, 0x6d, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x78, 0x61, 0x70, 0x4d, 0x4d, 0x3a, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x3e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x64, 0x6f, 0x63, 0x69, 0x64, 0x3a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x36, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x3c, 0x2f, 0x78, 0x61, 0x70, 0x4d, 0x4d, 0x3a, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x64, 0x63, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x75, 0x72, 0x6c, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x64, 0x63, 0x2f, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x31, 0x2e, 0x31, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x63, 0x3a, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x41, 0x6c, 0x74, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0x20, 0x78, 0x6d, 0x6c, 0x3a, 0x6c, 0x61, 0x6e, 0x67, 0x3d, 0x27, 0x78, 0x2d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x27, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x41, 0x6c, 0x74, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x63, 0x3a, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x3e, 0x0a, 0x3c, 0x2f, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x3d, 0x27, 0x77, 0x27, 0x3f, 0x3e, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x00, 0x64, 0x40, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x06, 0x04, 0x03, 0x04, 0x06, 0x07, 0x05, 0x04, 0x04, 0x05, 0x07, 0x08, 0x06, 0x06, 0x07, 0x06, 0x06, 0x08, 0x0a, 0x08, 0x09, 0x09, 0x09, 0x09, 0x08, 0x0a, 0x0a, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0a, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x04, 0x05, 0x05, 0x08, 0x07, 0x08, 0x0f, 0x0a, 0x0a, 0x0f, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x11, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x0d, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x00, 0x07, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x03, 0x02, 0x06, 0x01, 0x00, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x02, 0x06, 0x07, 0x03, 0x04, 0x02, 0x06, 0x02, 0x73, 0x01, 0x02, 0x03, 0x11, 0x04, 0x00, 0x05, 0x21, 0x12, 0x31, 0x41, 0x51, 0x06, 0x13, 0x61, 0x22, 0x71, 0x81, 0x14, 0x32, 0x91, 0xa1, 0x07, 0x15, 0xb1, 0x42, 0x23, 0xc1, 0x52, 0xd1, 0xe1, 0x33, 0x16, 0x62, 0xf0, 0x24, 0x72, 0x82, 0xf1, 0x25, 0x43, 0x34, 0x53, 0x92, 0xa2, 0xb2, 0x63, 0x73, 0xc2, 0x35, 0x44, 0x27, 0x93, 0xa3, 0xb3, 0x36, 0x17, 0x54, 0x64, 0x74, 0xc3, 0xd2, 0xe2, 0x08, 0x26, 0x83, 0x09, 0x0a, 0x18, 0x19, 0x84, 0x94, 0x45, 0x46, 0xa4, 0xb4, 0x56, 0xd3, 0x55, 0x28, 0x1a, 0xf2, 0xe3, 0xf3, 0xc4, 0xd4, 0xe4, 0xf4, 0x65, 0x75, 0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, 0x11, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x05, 0x05, 0x04, 0x05, 0x06, 0x04, 0x08, 0x03, 0x03, 0x6d, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31, 0x41, 0x05, 0x51, 0x13, 0x61, 0x22, 0x06, 0x71, 0x81, 0x91, 0x32, 0xa1, 0xb1, 0xf0, 0x14, 0xc1, 0xd1, 0xe1, 0x23, 0x42, 0x15, 0x52, 0x62, 0x72, 0xf1, 0x33, 0x24, 0x34, 0x43, 0x82, 0x16, 0x92, 0x53, 0x25, 0xa2, 0x63, 0xb2, 0xc2, 0x07, 0x73, 0xd2, 0x35, 0xe2, 0x44, 0x83, 0x17, 0x54, 0x93, 0x08, 0x09, 0x0a, 0x18, 0x19, 0x26, 0x36, 0x45, 0x1a, 0x27, 0x64, 0x74, 0x55, 0x37, 0xf2, 0xa3, 0xb3, 0xc3, 0x28, 0x29, 0xd3, 0xe3, 0xf3, 0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4, 0x65, 0x75, 0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x46, 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8, 0x39, 0x49, 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf0, 0x67, 0xa6, 0x5c, 0x0f, 0x01, 0xd4, 0x7e, 0x18, 0x12, 0x98, 0xe9, 0xd6, 0x2d, 0x34, 0x6d, 0x70, 0xdf, 0xdc, 0xa1, 0xe3, 0xec, 0x5b, 0xfb, 0x32, 0x24, 0xb2, 0x01, 0x1f, 0x15, 0xa4, 0x52, 0x4a, 0x82, 0x31, 0xf1, 0xfe, 0xd1, 0x3d, 0x14, 0x64, 0x49, 0x64, 0x22, 0x98, 0xcf, 0xa5, 0x46, 0x6c, 0x16, 0x55, 0x71, 0x56, 0x62, 0x28, 0x07, 0xc5, 0x45, 0x15, 0xa0, 0xc8, 0x89, 0x33, 0xe1, 0x63, 0xd2, 0xd8, 0x34, 0x44, 0x17, 0xa0, 0x2c, 0x4d, 0x16, 0xbb, 0xed, 0xdc, 0xf8, 0x64, 0xc1, 0x6b, 0x31, 0x42, 0x18, 0x8e, 0xc7, 0xb5, 0x2a, 0x7d, 0xb2, 0x56, 0xc5, 0x61, 0x8c, 0xf2, 0xa0, 0x1b, 0x1e, 0x83, 0x0d, 0xa1, 0x63, 0x50, 0x1f, 0x97, 0x7c, 0x2a, 0xa9, 0x1a, 0x9a, 0x86, 0x4f, 0xb4, 0xb4, 0x38, 0x0a, 0xa6, 0x0b, 0xb8, 0x0c, 0x05, 0x14, 0xf8, 0x76, 0x3e, 0x19, 0x14, 0xb6, 0x78, 0xf8, 0x8c, 0x2a, 0xd5, 0x01, 0xdc, 0x6f, 0x8a, 0x1a, 0xe3, 0x8d, 0xab, 0xff, 0xd0, 0xf0, 0xec, 0xe9, 0x15, 0xb5, 0xb9, 0x5a, 0x7c, 0x4c, 0xa2, 0x9e, 0x24, 0xf5, 0xca, 0xc6, 0xe5, 0x99, 0xd9, 0x34, 0x99, 0x04, 0x3a, 0x7d, 0xb5, 0xba, 0xd5, 0x51, 0x63, 0x0e, 0xc7, 0xc5, 0x9b, 0x73, 0xf8, 0xe4, 0x6f, 0x76, 0xca, 0xd9, 0xda, 0x54, 0x6d, 0x72, 0x2e, 0x1a, 0x57, 0x11, 0x44, 0x40, 0x0d, 0x27, 0x7a, 0x0f, 0xd9, 0x5f, 0x12, 0x69, 0x4c, 0x84, 0xcd, 0x36, 0xe3, 0x85, 0xb2, 0xcd, 0x2f, 0x4a, 0x8b, 0x58, 0x36, 0xf6, 0x76, 0xa8, 0x64, 0x64, 0x3c, 0xa4, 0x93, 0xaa, 0x25, 0x3c, 0x49, 0xda, 0xa4, 0xe5, 0x26, 0x54, 0xe4, 0x8c, 0x7c, 0x5c, 0x93, 0x4d, 0x67, 0xc9, 0x3a, 0x6e, 0x9f, 0x13, 0xb4, 0xce, 0xf7, 0x3a, 0x9b, 0xad, 0x52, 0xd6, 0x2a, 0xd1, 0x49, 0xee, 0xc7, 0xf8, 0x64, 0x46, 0x42, 0x4e, 0xcd, 0x92, 0xc2, 0x00, 0xdd, 0x8a, 0x47, 0xe5, 0x69, 0x6e, 0xd4, 0xa4, 0x08, 0x16, 0x83, 0x9c, 0x8c, 0xdd, 0x95, 0x6b, 0xb9, 0xf6, 0xef, 0x97, 0x78, 0x94, 0xe3, 0x78, 0x04, 0xa4, 0xf3, 0xe8, 0xee, 0x64, 0xe1, 0x12, 0x10, 0x05, 0x6a, 0xc7, 0xc0, 0x6f, 0x53, 0xf3, 0xc9, 0x89, 0xb4, 0x9c, 0x4e, 0xb4, 0xf2, 0xd3, 0xde, 0x7a, 0xd2, 0x19, 0x16, 0x38, 0x61, 0x5d, 0xd9, 0x88, 0x05, 0x9c, 0xf4, 0x0a, 0x0f, 0x5f, 0x73, 0x84, 0xe4, 0xa4, 0xc7, 0x0d, 0xa5, 0xf1, 0x59, 0xba, 0x5c, 0x08, 0x98, 0x6f, 0xc8, 0x20, 0xfa, 0x4e, 0x4e, 0xf6, 0x69, 0xe1, 0xa2, 0x89, 0xfd, 0x1f, 0x77, 0x2c, 0xe6, 0xce, 0xd6, 0x17, 0x9a, 0x69, 0xdb, 0xd3, 0x86, 0x18, 0xc1, 0x67, 0x77, 0x26, 0x80, 0x28, 0x1b, 0x93, 0x88, 0x41, 0x0f, 0x40, 0xb0, 0xfc, 0x87, 0xf3, 0x43, 0x98, 0xd7, 0x58, 0x96, 0xdb, 0x4d, 0x91, 0x88, 0xe5, 0x6c, 0x58, 0xdc, 0x5c, 0x2a, 0xf7, 0x2c, 0xb1, 0xfc, 0x20, 0x8f, 0x02, 0xd9, 0x65, 0x06, 0xbe, 0x26, 0x6f, 0xa2, 0x7f, 0xce, 0x3d, 0x69, 0x26, 0xdd, 0x13, 0x52, 0xbf, 0xbd, 0x92, 0x62, 0x59, 0x4c, 0x90, 0xac, 0x50, 0x45, 0x5e, 0xbb, 0x09, 0x03, 0x12, 0x29, 0x84, 0x00, 0xc4, 0xc9, 0x11, 0xff, 0x00, 0x42, 0xe7, 0xa7, 0x7a, 0xd4, 0xfd, 0x21, 0x79, 0xe9, 0x78, 0x71, 0x8b, 0x95, 0x39, 0x75, 0xaf, 0x4e, 0x98, 0x78, 0x42, 0x38, 0xdf, 0xff, 0xd1, 0xf0, 0xe6, 0xa0, 0x58, 0xc8, 0x84, 0x9a, 0xaa, 0x30, 0x55, 0xf9, 0x0a, 0x6f, 0x90, 0x0c, 0xca, 0x72, 0x48, 0xb8, 0x1e, 0x89, 0xa7, 0x23, 0x17, 0x24, 0xff, 0x00, 0x61, 0xb6, 0x54, 0x76, 0x6e, 0x1b, 0xa7, 0xbe, 0x50, 0xf2, 0xc1, 0xd7, 0x4c, 0x52, 0x5e, 0x33, 0x5b, 0xe9, 0x10, 0xf4, 0x54, 0x3c, 0x5e, 0x77, 0xee, 0x49, 0xec, 0x2b, 0xb6, 0x63, 0xe4, 0xc9, 0xc3, 0xef, 0x73, 0xf0, 0xe1, 0x32, 0x1b, 0xf2, 0x7a, 0x05, 0xce, 0xad, 0x65, 0xa1, 0x98, 0xb4, 0x0f, 0x2a, 0x5b, 0x23, 0xeb, 0x12, 0x00, 0x88, 0xb0, 0xa8, 0x66, 0x46, 0x3d, 0xea, 0x7b, 0xfb, 0x9e, 0x99, 0x89, 0xbc, 0x8d, 0x97, 0x3a, 0x34, 0x05, 0x32, 0x5d, 0x1f, 0xc9, 0x1a, 0x8c, 0x36, 0x8c, 0x6f, 0x66, 0xfa, 0xc6, 0xb7, 0x7d, 0xf0, 0x94, 0x04, 0xf0, 0x88, 0xc9, 0xd5, 0x9d, 0x8d, 0x4b, 0x11, 0xd4, 0x9f, 0xbb, 0x25, 0xc5, 0xdc, 0xa2, 0x03, 0x99, 0x4b, 0xbc, 0xf3, 0x0d, 0x97, 0x96, 0x74, 0xe5, 0xf2, 0xb6, 0x80, 0x95, 0xbd, 0x99, 0x15, 0xf5, 0x4b, 0xd2, 0x37, 0x58, 0x46, 0xd4, 0x27, 0xc5, 0xce, 0xc1, 0x7c, 0x30, 0x8e, 0x68, 0x94, 0x7b, 0x9e, 0x6d, 0xe6, 0x7b, 0x9b, 0x5d, 0x3a, 0xd8, 0xdb, 0x32, 0xfa, 0x77, 0x65, 0x15, 0xe4, 0x57, 0xa7, 0x21, 0x55, 0x04, 0x57, 0xef, 0xd8, 0x66, 0x56, 0x38, 0x19, 0x1b, 0xe8, 0xe0, 0x67, 0x98, 0xc7, 0x1a, 0x1c, 0xde, 0x71, 0x71, 0x79, 0x2c, 0xf2, 0xfa, 0x8c, 0x48, 0xec, 0xb5, 0x24, 0x9a, 0x0c, 0xce, 0x75, 0x29, 0xae, 0x8c, 0x67, 0xd4, 0xb5, 0x0b, 0x4b, 0x04, 0x05, 0xef, 0x2e, 0x66, 0x8e, 0x18, 0x08, 0x15, 0xdd, 0x8f, 0x11, 0xb0, 0xeb, 0x4c, 0x04, 0x5b, 0x21, 0x2a, 0x7d, 0x41, 0xe4, 0x4f, 0xcb, 0xcb, 0x5d, 0x12, 0x45, 0xb8, 0xb7, 0x53, 0x71, 0xaa, 0x9f, 0x86, 0x5b, 0xd6, 0x50, 0x4a, 0xed, 0xba, 0x46, 0x77, 0x00, 0x13, 0xd4, 0x8c, 0x85, 0xd3, 0x12, 0x6d, 0xeb, 0x1a, 0x67, 0x95, 0xd9, 0x39, 0x39, 0x50, 0xac, 0xff, 0x00, 0x6f, 0xc4, 0xff, 0x00, 0x1c, 0x81, 0x92, 0xb2, 0x6b, 0x6d, 0x02, 0xdd, 0xbd, 0x36, 0x92, 0x36, 0x2d, 0x1f, 0xc0, 0x2a, 0x0b, 0x28, 0x1b, 0x91, 0x41, 0xf4, 0x9c, 0xb6, 0x25, 0x81, 0x46, 0xfe, 0x81, 0xb5, 0xad, 0x3d, 0xba, 0x57, 0xb7, 0xf9, 0xf6, 0xc9, 0xb0, 0x7f, 0xff, 0xd2, 0xf0, 0xe2, 0x86, 0x95, 0xc4, 0x67, 0x7e, 0x3f, 0x11, 0xf7, 0xa8, 0x19, 0x06, 0x69, 0x8d, 0xca, 0xca, 0x24, 0x8f, 0xd3, 0x52, 0x24, 0x89, 0x47, 0x25, 0x1f, 0xcb, 0x20, 0xf8, 0xb2, 0xb2, 0x76, 0x6e, 0x88, 0x36, 0xf6, 0x6f, 0x2a, 0xc1, 0x6e, 0xfa, 0x45, 0xad, 0xbc, 0x3f, 0x0b, 0x46, 0x81, 0x4d, 0x46, 0xea, 0x7a, 0x9a, 0x83, 0x9a, 0xa9, 0xdd, 0xbb, 0xec, 0x7b, 0x06, 0x5b, 0xe5, 0xcf, 0x2e, 0x69, 0xfa, 0x5c, 0xcd, 0x7b, 0x14, 0x5e, 0xa5, 0xee, 0xf5, 0xb8, 0x7d, 0xdd, 0x99, 0xba, 0xef, 0x91, 0x16, 0x5b, 0x36, 0xb6, 0x65, 0x0d, 0xac, 0xb2, 0x5b, 0xed, 0x34, 0x81, 0x7a, 0xbb, 0x46, 0x40, 0x6a, 0x9e, 0xb4, 0x39, 0x31, 0x13, 0x49, 0xda, 0xd2, 0x9b, 0xed, 0x1e, 0xc4, 0x24, 0xb3, 0x35, 0xb2, 0x88, 0x60, 0x06, 0xe6, 0x56, 0x98, 0x96, 0x79, 0x1e, 0x31, 0x51, 0xc9, 0x8f, 0xcb, 0x00, 0xe6, 0xb3, 0xe4, 0xf9, 0x2b, 0xcc, 0x7a, 0x94, 0xda, 0x96, 0xa9, 0x71, 0x77, 0x70, 0x79, 0xcd, 0x33, 0x97, 0x76, 0x3f, 0xcc, 0xc6, 0xa6, 0x9f, 0x2e, 0x99, 0xb9, 0xc6, 0x2a, 0x21, 0xe6, 0x73, 0xca, 0xe6, 0x4a, 0x51, 0x1a, 0x99, 0x1c, 0x28, 0x04, 0x93, 0xd0, 0x0e, 0xa4, 0xe4, 0xda, 0x5f, 0x50, 0xfe, 0x4a, 0xfe, 0x48, 0xb5, 0xb2, 0xc1, 0xe6, 0x1f, 0x31, 0x7e, 0xef, 0x52, 0x91, 0x43, 0xc3, 0x6e, 0x77, 0xf4, 0x22, 0x6d, 0xbf, 0xe4, 0x63, 0x0e, 0xbf, 0xca, 0x36, 0xeb, 0x5c, 0x84, 0xa5, 0x48, 0x7d, 0x3b, 0x61, 0xa1, 0xdb, 0x5b, 0x2c, 0x71, 0xda, 0x45, 0xc4, 0x28, 0x00, 0x81, 0xdb, 0x31, 0xc9, 0xb4, 0xb2, 0x3b, 0x5d, 0x27, 0xa5, 0x05, 0x1b, 0xc7, 0xdb, 0x10, 0xa9, 0xbd, 0xa6, 0x93, 0x0c, 0x75, 0xe4, 0x39, 0x35, 0x41, 0x3d, 0xc5, 0x06, 0xdb, 0x8e, 0xfd, 0x46, 0x5b, 0x1d, 0x98, 0x95, 0x4f, 0x46, 0xdb, 0xd5, 0xfb, 0x29, 0x5e, 0x9d, 0x0d, 0x32, 0xeb, 0x61, 0x4f, 0xff, 0xd3, 0xf1, 0x46, 0x9a, 0x16, 0x1b, 0x91, 0x71, 0x28, 0xac, 0x4a, 0x14, 0x30, 0x3e, 0x19, 0x54, 0xb9, 0x36, 0xc7, 0x9b, 0x2d, 0xd1, 0x6c, 0x45, 0xe3, 0xdc, 0xde, 0xc8, 0x95, 0x5b, 0x87, 0xf8, 0x41, 0x1d, 0x10, 0x54, 0x01, 0x98, 0x79, 0x25, 0xd1, 0xda, 0xe9, 0xe1, 0xb5, 0x9e, 0xac, 0xeb, 0x42, 0xba, 0x8e, 0xdf, 0x8c, 0x31, 0x21, 0x70, 0xb4, 0x5d, 0xbe, 0xc5, 0x7c, 0x2b, 0xed, 0xe1, 0x94, 0x18, 0xb9, 0x51, 0x3d, 0x03, 0x2c, 0x13, 0x6b, 0xf1, 0x42, 0x6e, 0xe2, 0xb7, 0x12, 0xa0, 0xdd, 0x50, 0x9f, 0x4f, 0x6f, 0xa7, 0x6f, 0xc7, 0x03, 0x61, 0xa0, 0x83, 0xb5, 0xf3, 0x97, 0x98, 0x20, 0x9c, 0x44, 0xea, 0xd0, 0xad, 0x48, 0x64, 0x90, 0x21, 0xd8, 0x9f, 0xa7, 0xa6, 0x44, 0xca, 0x99, 0xc6, 0x36, 0xcb, 0x74, 0x5d, 0x7e, 0x5b, 0xfe, 0x31, 0x6a, 0x31, 0xf3, 0x8c, 0xd0, 0xad, 0x40, 0xa3, 0x1f, 0x7c, 0x44, 0xd6, 0x51, 0xd9, 0xe0, 0x5f, 0x9a, 0x7e, 0x41, 0x9f, 0x40, 0xf3, 0x14, 0xba, 0x85, 0xba, 0x34, 0xba, 0x2d, 0xfb, 0x34, 0xd0, 0xcf, 0x4f, 0xb0, 0xce, 0x6a, 0x51, 0xe9, 0xb0, 0x20, 0xf4, 0xf1, 0x19, 0xb2, 0xc3, 0x90, 0x11, 0x4e, 0x97, 0x55, 0x80, 0x83, 0xc4, 0x17, 0x7e, 0x4c, 0x79, 0x19, 0xfc, 0xd1, 0xe7, 0x78, 0x4b, 0x91, 0x1d, 0xae, 0x92, 0xa6, 0xf6, 0x46, 0x75, 0xe4, 0xad, 0x22, 0x1f, 0xdd, 0xa1, 0x07, 0xb3, 0x1e, 0xfe, 0xd9, 0x92, 0xeb, 0x4b, 0xed, 0xfd, 0x0a, 0xc2, 0x63, 0x27, 0xa4, 0x88, 0x17, 0x60, 0x49, 0x35, 0xdc, 0x8e, 0xa5, 0x7d, 0xab, 0xd3, 0x28, 0x90, 0x50, 0xcd, 0xed, 0x2d, 0xda, 0x15, 0x55, 0x51, 0xf1, 0x1a, 0x0a, 0xf7, 0x39, 0x5d, 0xaa, 0x77, 0x6f, 0x01, 0x8e, 0xa7, 0x7d, 0xfa, 0xff, 0x00, 0x66, 0x10, 0xa8, 0xb8, 0x63, 0x76, 0x90, 0xa8, 0x20, 0x06, 0x56, 0xdb, 0x61, 0xda, 0xbd, 0x4f, 0xcb, 0x24, 0x15, 0x0f, 0xf5, 0x66, 0xe5, 0x5f, 0x4c, 0x53, 0xc3, 0xb7, 0xce, 0x99, 0x6b, 0x17, 0xff, 0xd4, 0xf0, 0xec, 0x57, 0x6f, 0x32, 0xa5, 0xa4, 0x43, 0x76, 0x75, 0xa9, 0xf1, 0x03, 0xfa, 0x64, 0x08, 0x6c, 0x8e, 0xfb, 0x3d, 0x7f, 0xcb, 0x16, 0x2b, 0x3d, 0xbc, 0x16, 0xa3, 0x66, 0x6d, 0x98, 0xfb, 0x1e, 0xb9, 0xac, 0xc8, 0x77, 0xb7, 0x7d, 0x01, 0xb3, 0x37, 0xb8, 0xd3, 0x46, 0x95, 0x68, 0x86, 0xd2, 0x2e, 0x4e, 0xab, 0xf0, 0x23, 0x11, 0x4e, 0x5f, 0xcd, 0x98, 0xe7, 0x25, 0x96, 0x71, 0x83, 0x0f, 0xd6, 0x3c, 0xb9, 0xe7, 0x0d, 0x7c, 0x41, 0x22, 0x5e, 0xb3, 0x20, 0x0c, 0x65, 0x80, 0xc8, 0x63, 0x8e, 0xbb, 0x95, 0xa5, 0x07, 0xeb, 0xcc, 0xac, 0x73, 0x83, 0x4e, 0x5c, 0x59, 0x09, 0xd8, 0xec, 0xc8, 0x57, 0x41, 0xd3, 0x4e, 0x95, 0xa5, 0x5b, 0x4b, 0x6a, 0xcb, 0xab, 0x43, 0x10, 0x4b, 0xeb, 0x85, 0xa2, 0x2c, 0x8e, 0x3f, 0x68, 0x54, 0xf5, 0x00, 0xd3, 0x97, 0x7a, 0x65, 0x79, 0xa6, 0x24, 0x76, 0x6f, 0xd3, 0x62, 0x96, 0x30, 0x78, 0xcb, 0x21, 0xf2, 0xf4, 0x22, 0xce, 0x54, 0x8e, 0x46, 0x26, 0x10, 0x7e, 0x0a, 0xf5, 0xd8, 0xf5, 0x1f, 0x31, 0x98, 0x83, 0x73, 0xb3, 0x91, 0xcd, 0x67, 0xe6, 0x7d, 0xe8, 0x16, 0x69, 0x6f, 0x10, 0x1f, 0x54, 0x9a, 0x37, 0xf5, 0x41, 0x5e, 0x7f, 0x0a, 0x29, 0x62, 0x02, 0xf8, 0x9c, 0xc8, 0x8c, 0x77, 0x6a, 0x99, 0xa0, 0x89, 0xff, 0x00, 0x9c, 0x74, 0xd2, 0xed, 0xed, 0xfc, 0xbb, 0x7b, 0xaa, 0x9a, 0x7d, 0x62, 0xfe, 0x46, 0x2d, 0xfe, 0x4c, 0x51, 0x31, 0x11, 0xa9, 0xf6, 0xef, 0x9b, 0x30, 0x5e, 0x7b, 0x38, 0xdd, 0xf4, 0x7f, 0x95, 0x94, 0xbc, 0x12, 0x43, 0x30, 0x6a, 0xb2, 0xf3, 0x86, 0x40, 0x3e, 0xcb, 0xd7, 0x6a, 0xd7, 0xb1, 0xe9, 0x8f, 0x37, 0x19, 0x97, 0x41, 0x2c, 0x71, 0x20, 0xf5, 0x36, 0x9c, 0x55, 0x78, 0x1d, 0x8a, 0x91, 0xd7, 0x11, 0x14, 0x5a, 0x3e, 0x19, 0x03, 0x10, 0x6b, 0xca, 0xbd, 0x86, 0xf8, 0x9d, 0x95, 0x18, 0x36, 0x65, 0x2e, 0xbc, 0x54, 0x1f, 0xa2, 0x99, 0x00, 0x59, 0x2a, 0x6f, 0x5e, 0x55, 0x15, 0xe9, 0x5f, 0xc3, 0x2f, 0xb6, 0x14, 0xff, 0x00, 0xff, 0xd5, 0xf1, 0x95, 0xfe, 0x80, 0x74, 0x0d, 0x7c, 0xd9, 0x89, 0x3d, 0x78, 0x57, 0x8b, 0xc5, 0x28, 0xe8, 0x55, 0xf7, 0x1f, 0x48, 0xca, 0x38, 0xb8, 0x83, 0x9f, 0x93, 0x07, 0x85, 0x3a, 0x7a, 0x6f, 0x95, 0x66, 0x2b, 0x2c, 0x4c, 0x0d, 0x14, 0x00, 0x3e, 0x9c, 0xc3, 0x98, 0x76, 0xb8, 0x45, 0xbd, 0x02, 0xde, 0x48, 0xee, 0xdc, 0xa0, 0x15, 0xe2, 0x2b, 0xc8, 0x8a, 0x8a, 0xfd, 0x3b, 0x66, 0x3f, 0x00, 0x73, 0x84, 0x2d, 0x36, 0xb5, 0xb5, 0x9e, 0x35, 0x1c, 0x29, 0xc4, 0xfe, 0xc8, 0x04, 0x7f, 0xc4, 0x69, 0x91, 0xe1, 0x67, 0x2c, 0x4a, 0xd2, 0xe9, 0x4e, 0xe3, 0xd4, 0xf4, 0x81, 0x5a, 0x12, 0xc5, 0x41, 0x3f, 0x79, 0x38, 0x9b, 0x60, 0x20, 0x07, 0x34, 0xb0, 0xc9, 0x03, 0x5c, 0x23, 0x03, 0x53, 0x13, 0x56, 0x88, 0xdf, 0x09, 0xda, 0x9b, 0xd3, 0xb6, 0x52, 0x0e, 0xec, 0xe4, 0x29, 0x24, 0xfc, 0xd0, 0xe7, 0x75, 0xe5, 0x57, 0x6b, 0x61, 0xfb, 0xf0, 0xca, 0xaa, 0x57, 0xa8, 0xe6, 0x78, 0x1a, 0x7d, 0xf9, 0x95, 0x8a, 0x5e, 0xa0, 0xe3, 0x67, 0x8f, 0xa0, 0xbd, 0x5b, 0xf2, 0xdf, 0x4a, 0x82, 0xcb, 0x4a, 0xb3, 0xb0, 0xb4, 0x41, 0x0a, 0x70, 0x48, 0xd9, 0x57, 0x60, 0x51, 0x3a, 0x8f, 0xbc, 0xe6, 0x7b, 0xcb, 0xe4, 0x3b, 0xa7, 0x3f, 0x9b, 0x9f, 0x9a, 0xba, 0x77, 0xe5, 0x5f, 0x95, 0x9c, 0x59, 0x94, 0x9f, 0xcd, 0x37, 0x8c, 0xa9, 0xa6, 0xd9, 0x39, 0xaa, 0xd0, 0x7d, 0xa9, 0x1c, 0x03, 0x5e, 0x09, 0xff, 0x00, 0x0c, 0x76, 0xcb, 0x62, 0x2d, 0xa5, 0xf2, 0x85, 0xbf, 0xe7, 0x87, 0xe6, 0xa3, 0x5e, 0x4d, 0xa8, 0xc9, 0xe6, 0x8b, 0xd5, 0x69, 0x5c, 0xb0, 0x4a, 0xab, 0xc4, 0xb5, 0x35, 0x0a, 0xaa, 0xea, 0x40, 0x03, 0xa0, 0xf6, 0xcb, 0x40, 0x4d, 0x3e, 0xdb, 0xff, 0x00, 0x9c, 0x7f, 0xfc, 0xce, 0x4f, 0xcc, 0xbf, 0x26, 0x25, 0xe5, 0xd3, 0x2f, 0xe9, 0xdd, 0x3d, 0xfe, 0xab, 0xa9, 0xaa, 0xd2, 0xa6, 0x40, 0x2a, 0xb2, 0x71, 0x00, 0x01, 0xea, 0x0d, 0xe8, 0x3a, 0x64, 0x25, 0x16, 0x1c, 0x8b, 0xd9, 0x51, 0x39, 0x28, 0x12, 0x51, 0x41, 0xfd, 0xa3, 0xd2, 0xb9, 0x4f, 0x0d, 0x33, 0xb5, 0xf4, 0x87, 0x9d, 0x79, 0x0e, 0xb4, 0xaf, 0x6a, 0xf8, 0xf1, 0xf0, 0xc9, 0xda, 0xbf, 0xff, 0xd6, 0xf2, 0xc6, 0xb5, 0x68, 0x64, 0xd0, 0x6d, 0x35, 0x20, 0x39, 0xcd, 0x13, 0x0f, 0x5e, 0x61, 0xfc, 0x8f, 0x40, 0x8b, 0x5e, 0xe0, 0x66, 0x1c, 0x4f, 0xaa, 0x9d, 0xe6, 0xa6, 0x1e, 0x91, 0x2e, 0xa9, 0x87, 0x95, 0xee, 0x9c, 0xc5, 0x55, 0x34, 0x60, 0x40, 0xae, 0x57, 0x30, 0xd9, 0xa7, 0x95, 0xbd, 0x6f, 0xcb, 0x26, 0x39, 0x40, 0x0d, 0x4e, 0xc0, 0x9f, 0x9e, 0x50, 0x5d, 0xac, 0x79, 0x33, 0x8b, 0xbb, 0x9b, 0x3b, 0x6b, 0x35, 0x48, 0x54, 0x09, 0x29, 0x56, 0x7f, 0xe1, 0x86, 0x72, 0x00, 0x2c, 0x6e, 0xf7, 0x63, 0x3e, 0x63, 0xbd, 0xbd, 0x5d, 0x20, 0x2a, 0xb3, 0xa4, 0x33, 0x48, 0xab, 0x21, 0x43, 0xf1, 0x2c, 0x47, 0xed, 0x1d, 0xbc, 0x73, 0x18, 0x9b, 0x64, 0x28, 0x96, 0x3a, 0xc7, 0x49, 0xb0, 0xf4, 0xcc, 0xe9, 0x73, 0x6c, 0xb4, 0xf8, 0x67, 0x92, 0x32, 0x21, 0x70, 0x7b, 0x89, 0x05, 0x57, 0xef, 0x38, 0x28, 0x94, 0x4a, 0x7d, 0x13, 0x7d, 0x6a, 0xd3, 0x4c, 0xb8, 0xf2, 0xc3, 0xc8, 0x2e, 0x03, 0xf3, 0xe2, 0x7d, 0x33, 0xb7, 0xc5, 0xcc, 0x71, 0x03, 0xc6, 0xb9, 0x64, 0x06, 0xe2, 0x9a, 0xf2, 0x4f, 0xd2, 0x6d, 0xe9, 0xfe, 0x41, 0x45, 0x5b, 0x18, 0x66, 0xa5, 0x64, 0x09, 0xf4, 0xd5, 0xb7, 0xcd, 0x93, 0xc7, 0xcf, 0x9b, 0xe5, 0x6f, 0xf9, 0xc8, 0x0d, 0x56, 0xeb, 0x59, 0xfc, 0xce, 0xd5, 0x12, 0x61, 0xc4, 0x69, 0xe9, 0x0d, 0xa4, 0x4b, 0xfe, 0x48, 0x40, 0xd5, 0x3e, 0xe4, 0xb6, 0x64, 0x8e, 0x4c, 0x02, 0x61, 0x65, 0xa0, 0x14, 0xb4, 0xb6, 0xb0, 0xb1, 0xb6, 0xb2, 0x97, 0xcb, 0xf1, 0x5a, 0x2d, 0xc6, 0xa5, 0xac, 0xb4, 0x70, 0x5d, 0xc7, 0x3d, 0xc1, 0x51, 0x24, 0x91, 0xc9, 0x31, 0x75, 0x6b, 0x70, 0x9f, 0x14, 0x68, 0x01, 0x46, 0xe4, 0xb5, 0xa3, 0x17, 0xcb, 0x40, 0x61, 0x6f, 0x47, 0xff, 0x00, 0x9c, 0x3a, 0x8f, 0x5b, 0x4f, 0x3c, 0x6b, 0xb7, 0xfa, 0x30, 0x91, 0x3c, 0xa4, 0xb1, 0x95, 0xb9, 0x82, 0x42, 0x0a, 0xbc, 0x8e, 0xe4, 0xdb, 0xa9, 0xef, 0xc9, 0x17, 0x91, 0x24, 0x7c, 0xb2, 0x05, 0x64, 0xfb, 0x75, 0x64, 0x32, 0x39, 0x69, 0x5b, 0x9c, 0xad, 0xb9, 0xdb, 0xa7, 0xb5, 0x3b, 0x53, 0x2a, 0x21, 0x41, 0x44, 0xf3, 0x8b, 0x8f, 0x2e, 0x43, 0x9d, 0x2b, 0xd4, 0x57, 0x23, 0x41, 0x36, 0xff, 0x00, 0xff, 0xd7, 0xf0, 0xc0, 0xd5, 0xb5, 0x11, 0x64, 0xb6, 0x3f, 0x59, 0x90, 0xd9, 0xab, 0x06, 0xf4, 0x79, 0x7c, 0x3b, 0x74, 0xc8, 0x08, 0x8b, 0xb6, 0xe3, 0x96, 0x55, 0x57, 0xb3, 0x3e, 0xf2, 0x35, 0xc7, 0xd6, 0x0b, 0x45, 0x5d, 0xdc, 0x8a, 0x7d, 0xd9, 0x8d, 0x94, 0x3b, 0x3d, 0x1c, 0x9e, 0xc3, 0xe5, 0xc3, 0x2c, 0x7c, 0xc5, 0x0f, 0xee, 0xdb, 0x8b, 0x0c, 0xc4, 0x26, 0x9d, 0xa0, 0x9a, 0x7d, 0x2c, 0xe5, 0xe4, 0x55, 0x7f, 0xee, 0xc1, 0x15, 0x04, 0xd0, 0x12, 0x3c, 0x72, 0x89, 0x1b, 0x2c, 0xcc, 0xa8, 0x2a, 0x8b, 0x87, 0xbb, 0x63, 0x1a, 0x28, 0x65, 0xf0, 0xed, 0xf2, 0xc3, 0xc2, 0x0a, 0x06, 0x4a, 0x46, 0xc7, 0xa5, 0xa3, 0x59, 0xc8, 0xb2, 0xc7, 0x45, 0x22, 0x9c, 0x14, 0x54, 0x10, 0x46, 0xf5, 0x1d, 0x32, 0x5c, 0x14, 0x14, 0xe4, 0x32, 0x2f, 0x3a, 0xf3, 0xb6, 0x90, 0x9a, 0x6d, 0xae, 0x9f, 0x3d, 0xab, 0xb8, 0x8a, 0x3b, 0xf8, 0x39, 0x44, 0x58, 0xf0, 0x08, 0xd5, 0x14, 0xa5, 0x7b, 0x65, 0x98, 0x8e, 0xfb, 0xb5, 0x67, 0x87, 0xa5, 0xef, 0x5e, 0x44, 0x96, 0x35, 0xb5, 0xb6, 0x59, 0x36, 0xfd, 0xd8, 0xa0, 0xf1, 0x20, 0x53, 0x33, 0xc0, 0x79, 0x59, 0x73, 0x7c, 0xd7, 0xf9, 0xfb, 0xa2, 0xcd, 0x67, 0xf9, 0xa7, 0x7b, 0x72, 0xf1, 0x71, 0x83, 0x53, 0x86, 0x0b, 0x98, 0x24, 0x22, 0x8a, 0xcc, 0x88, 0x23, 0x7f, 0xb8, 0xae, 0xf9, 0x7c, 0x50, 0x1e, 0x5f, 0x7c, 0x48, 0x21, 0x44, 0x6b, 0xce, 0x9b, 0xb0, 0x1b, 0x9e, 0xf5, 0xaf, 0x8e, 0x4d, 0x5f, 0x7a, 0x7f, 0xce, 0x34, 0xf9, 0x5d, 0x3c, 0xa3, 0xf9, 0x69, 0x63, 0xa9, 0x3c, 0x27, 0xeb, 0xda, 0xe1, 0x37, 0xd7, 0x2e, 0xaa, 0xdb, 0x06, 0xda, 0x30, 0x49, 0xfe, 0x54, 0x03, 0x03, 0x49, 0xdc, 0xb3, 0xaf, 0x38, 0xfe, 0x6a, 0xf9, 0x47, 0xc9, 0x3a, 0x74, 0x97, 0xfa, 0xf6, 0xaf, 0x15, 0x85, 0xb8, 0x75, 0x89, 0xb8, 0x87, 0x9a, 0x72, 0xee, 0x2a, 0x14, 0x24, 0x60, 0xb1, 0xa8, 0xdf, 0x07, 0x0b, 0x2d, 0xcb, 0xcf, 0x7f, 0xe8, 0x6a, 0xff, 0x00, 0x26, 0xbd, 0x6a, 0x7f, 0x89, 0x2f, 0xf8, 0x52, 0x9e, 0xb7, 0xe8, 0xb9, 0xb8, 0x57, 0xc2, 0x95, 0xe9, 0x8f, 0x08, 0x5a, 0x2f, 0xff, 0xd0, 0xf0, 0x4d, 0x40, 0xaa, 0xd7, 0x00, 0x64, 0xcb, 0x3c, 0x97, 0xa8, 0xb5, 0x9e, 0xa3, 0x1a, 0xd6, 0x84, 0x95, 0x3f, 0x45, 0x72, 0x9c, 0xa2, 0xc3, 0x99, 0xa5, 0x9d, 0x49, 0xf4, 0x17, 0x97, 0xaf, 0x63, 0x17, 0x52, 0x6f, 0xf0, 0xc8, 0x43, 0x6f, 0x9a, 0xe9, 0x07, 0x70, 0x0e, 0xec, 0x83, 0x51, 0x44, 0xb8, 0x61, 0x1a, 0x9e, 0x11, 0xd3, 0x91, 0x60, 0x68, 0x6b, 0xd3, 0x31, 0x4f, 0x36, 0xd3, 0x4c, 0x52, 0xef, 0x4c, 0xd5, 0x0c, 0xc4, 0x69, 0xda, 0x94, 0xc8, 0x3a, 0xf0, 0x66, 0x07, 0x73, 0xe0, 0x40, 0xfd, 0x79, 0x93, 0x12, 0x1c, 0x9c, 0x32, 0xc7, 0xfc, 0x41, 0x33, 0xd2, 0xb4, 0x6f, 0x38, 0x98, 0x65, 0x76, 0xbf, 0x69, 0x42, 0xd0, 0xaa, 0xc9, 0xde, 0x95, 0xad, 0x28, 0x46, 0x4e, 0xac, 0x39, 0x77, 0x80, 0x11, 0xbf, 0xd8, 0xc7, 0x7c, 0xe1, 0xa5, 0xf9, 0x92, 0x4d, 0x32, 0x5b, 0x8b, 0x93, 0x27, 0xa7, 0x68, 0x56, 0xe2, 0x45, 0xda, 0x85, 0x61, 0x6e, 0x67, 0xad, 0x6b, 0xb0, 0x38, 0xc2, 0x81, 0xe4, 0xc7, 0x52, 0x31, 0x1c, 0x67, 0x86, 0x5b, 0xbd, 0x37, 0xca, 0x7a, 0x94, 0xb1, 0x69, 0xb6, 0x2e, 0xb7, 0x15, 0x48, 0xc2, 0xb4, 0x52, 0x53, 0xac, 0x32, 0xaf, 0xb1, 0xed, 0x9b, 0x10, 0x36, 0x78, 0x5c, 0x9f, 0x51, 0x64, 0x1f, 0x98, 0x3e, 0x58, 0xb6, 0xfc, 0xc8, 0xf2, 0xe5, 0xbc, 0x68, 0x52, 0x2d, 0x5a, 0xd1, 0x84, 0xb6, 0xf3, 0x95, 0x0e, 0xc0, 0x85, 0xe2, 0xcb, 0xd8, 0xd1, 0xbb, 0xe4, 0xc1, 0xa6, 0x97, 0xce, 0x17, 0x5f, 0x95, 0xde, 0x6d, 0xb6, 0xbe, 0xb7, 0x69, 0x34, 0xf3, 0x3c, 0x72, 0xcf, 0xe8, 0xa3, 0x45, 0x49, 0x95, 0x4a, 0x90, 0x3e, 0x35, 0x5a, 0x95, 0x1d, 0xfe, 0x21, 0x93, 0x4d, 0xbe, 0xd2, 0xd2, 0xf5, 0x8b, 0xbd, 0x32, 0x2d, 0x3f, 0x4c, 0x9a, 0xe4, 0xca, 0x9e, 0x90, 0x85, 0x65, 0x55, 0x08, 0x85, 0x91, 0x01, 0x3b, 0x0a, 0x05, 0xe9, 0xb0, 0xc0, 0x5a, 0xc3, 0xcd, 0x3f, 0x3b, 0x7f, 0x26, 0xec, 0xff, 0x00, 0x35, 0x6d, 0x6d, 0xb5, 0x3d, 0x16, 0xfe, 0x0d, 0x3b, 0xcd, 0x96, 0x01, 0x92, 0x46, 0x9e, 0xa2, 0x0b, 0xc8, 0xb7, 0x28, 0x92, 0x71, 0xfb, 0x2e, 0xa7, 0xec, 0x3d, 0x0f, 0xc2, 0x68, 0x71, 0x05, 0x95, 0xd3, 0xe7, 0x9f, 0xfa, 0x16, 0x2f, 0xcd, 0x7f, 0x43, 0xd6, 0xfa, 0xa5, 0x97, 0xab, 0xeb, 0x7a, 0x5f, 0x55, 0xfa, 0xec, 0x5e, 0xaf, 0x0f, 0xf7, 0xed, 0x2b, 0x4e, 0x15, 0xff, 0x00, 0x65, 0xdf, 0x8e, 0x14, 0xf1, 0xbf, 0xff, 0xd1, 0xf0, 0x5a, 0xa7, 0x18, 0x5e, 0x56, 0x1f, 0x68, 0x71, 0x5f, 0xa7, 0xbe, 0x2a, 0x98, 0xdb, 0xfa, 0x90, 0x24, 0x37, 0xb0, 0xfd, 0xb8, 0xa8, 0x58, 0x78, 0xae, 0x43, 0xc9, 0xb4, 0x6d, 0xbb, 0xda, 0x3c, 0xa1, 0xad, 0x43, 0xa8, 0xda, 0xc5, 0x2a, 0x3d, 0x26, 0x5a, 0x02, 0x2b, 0xbe, 0x60, 0x64, 0x8d, 0x17, 0x6f, 0x8b, 0x20, 0x90, 0x7a, 0x3c, 0x32, 0x8b, 0xa8, 0x02, 0xf3, 0xfd, 0xe0, 0x1b, 0x11, 0x98, 0x66, 0x3b, 0xb9, 0x62, 0x54, 0x83, 0x36, 0xf2, 0xa4, 0xe4, 0x29, 0x34, 0xeb, 0xc8, 0x74, 0xae, 0x0d, 0xc3, 0x65, 0x82, 0x13, 0x6b, 0x57, 0xba, 0x54, 0xe4, 0x8c, 0x41, 0x1b, 0x75, 0xa7, 0xe0, 0x72, 0x5c, 0x4c, 0x84, 0x50, 0x5a, 0xb3, 0xdd, 0xdd, 0xc3, 0x24, 0x33, 0xb1, 0x60, 0xe0, 0x86, 0x52, 0x45, 0x38, 0xd2, 0x87, 0x24, 0x26, 0x6d, 0x8c, 0xe1, 0x41, 0x25, 0xfc, 0xa3, 0xd7, 0x2f, 0x6f, 0x3c, 0xbf, 0x73, 0xa5, 0xb2, 0x2c, 0xd1, 0x69, 0x17, 0x2f, 0x6b, 0x14, 0x8c, 0x0f, 0x21, 0x0d, 0x79, 0x46, 0x09, 0x15, 0xed, 0xb7, 0x4e, 0xd9, 0xb9, 0x8b, 0xcb, 0xe4, 0xa2, 0x5e, 0xa3, 0xa6, 0xdf, 0x6a, 0x36, 0xe4, 0xcd, 0x69, 0x1c, 0x4e, 0x84, 0x7c, 0x76, 0xab, 0x21, 0x67, 0xa8, 0xa7, 0xd9, 0xf8, 0x4d, 0x2b, 0xf3, 0xc3, 0x4d, 0x49, 0x57, 0x98, 0x75, 0x6f, 0x31, 0xda, 0xf9, 0xa3, 0x4b, 0xfd, 0x1f, 0x69, 0x1d, 0xae, 0xa1, 0xa9, 0x7e, 0xee, 0xe6, 0xd2, 0x79, 0x18, 0xf3, 0xb5, 0x1f, 0xee, 0xd9, 0x0a, 0x01, 0x4e, 0x3f, 0xb3, 0x4d, 0xf2, 0x9c, 0xb9, 0x04, 0x05, 0xb7, 0xe2, 0x87, 0x1e, 0xdd, 0x19, 0x3e, 0xaf, 0x6b, 0xae, 0xcb, 0x6d, 0x13, 0x0d, 0x45, 0xa2, 0x8e, 0x06, 0xe5, 0x13, 0x2a, 0x02, 0x01, 0x5e, 0x82, 0xb5, 0x04, 0xe6, 0x11, 0xd4, 0xcd, 0xda, 0x43, 0x49, 0x8e, 0xb7, 0xdc, 0xb1, 0x51, 0xe6, 0x4d, 0x76, 0xd2, 0x61, 0x15, 0xaa, 0x4b, 0xa8, 0xc9, 0x6e, 0x49, 0x79, 0x20, 0xe6, 0x8c, 0x49, 0xad, 0x43, 0x16, 0xe4, 0xa7, 0xaf, 0x43, 0xd3, 0x26, 0x35, 0x75, 0xcd, 0xa8, 0xe8, 0x87, 0x46, 0xbf, 0xc7, 0x9a, 0xff, 0x00, 0xd6, 0xbf, 0x48, 0xfe, 0x88, 0xfd, 0xe7, 0x0f, 0xab, 0xfa, 0x3f, 0x58, 0x7f, 0x5f, 0x8d, 0x3f, 0x9f, 0xa7, 0x5e, 0xd4, 0xc3, 0xf9, 0xd1, 0x7c, 0xb6, 0x47, 0xe4, 0x3a, 0x5b, 0xff, 0xd2, 0xf0, 0xb7, 0xa6, 0x1e, 0xdf, 0xd3, 0xf6, 0xa5, 0x71, 0x54, 0xdb, 0x4b, 0x80, 0x3c, 0x42, 0x26, 0xee, 0x29, 0xbe, 0x51, 0x23, 0x4e, 0x44, 0x05, 0x84, 0x45, 0xa5, 0xd5, 0xf7, 0x97, 0x2e, 0xfd, 0x6b, 0x6a, 0x98, 0x09, 0xab, 0xc7, 0xfc, 0x46, 0x3b, 0x4c, 0x26, 0x32, 0x30, 0x3e, 0x4f, 0x49, 0xd0, 0xfc, 0xfb, 0x05, 0xd4, 0x4a, 0x7d, 0x40, 0xac, 0x3a, 0x8e, 0x84, 0x1c, 0xc5, 0x96, 0x2a, 0x73, 0xe1, 0x9c, 0x16, 0x6d, 0xa5, 0x79, 0x86, 0xd6, 0xec, 0x80, 0x5a, 0xa0, 0xf5, 0xca, 0xcc, 0x5c, 0xa1, 0x2b, 0x1b, 0x26, 0x30, 0x6a, 0x31, 0x46, 0xcf, 0x1c, 0x87, 0x94, 0x64, 0x9e, 0x3d, 0xb6, 0xf0, 0xca, 0xa8, 0x39, 0x51, 0x99, 0x42, 0x6b, 0x1a, 0xc5, 0xa5, 0xa5, 0x94, 0xf7, 0x92, 0xc8, 0xaa, 0xb1, 0x23, 0x30, 0x04, 0xf8, 0x0e, 0x9f, 0x4e, 0x4a, 0x11, 0xb2, 0xd5, 0x9b, 0x25, 0x06, 0x1b, 0xff, 0x00, 0x38, 0xfd, 0xad, 0xdf, 0xda, 0xf9, 0xa2, 0xfe, 0xc5, 0x42, 0xbe, 0x9b, 0x7f, 0x0b, 0xdd, 0xdd, 0x07, 0xaf, 0x14, 0x68, 0xd8, 0x71, 0x6d, 0xbb, 0x90, 0xfc, 0x73, 0x6e, 0xf2, 0xf2, 0xdd, 0xf4, 0xad, 0xa6, 0xab, 0x6d, 0x69, 0x14, 0xfa, 0xee, 0xa0, 0xe2, 0x0b, 0x0d, 0x39, 0x19, 0xfe, 0x11, 0xc5, 0x1a, 0x4a, 0x1d, 0x8f, 0x73, 0x4f, 0xf8, 0x96, 0x0b, 0x40, 0x8d, 0xec, 0xf3, 0x6d, 0x3f, 0x52, 0xba, 0xd6, 0x35, 0x8b, 0xbf, 0x36, 0x6a, 0x5f, 0x0d, 0xc5, 0xdc, 0xa8, 0xb6, 0xa8, 0x7a, 0xc5, 0x6c, 0x9b, 0x22, 0x0f, 0xa3, 0x73, 0x9a, 0xbc, 0xb3, 0xe2, 0x36, 0xed, 0xb1, 0x43, 0x80, 0x53, 0xd0, 0xa7, 0xd4, 0x44, 0xfa, 0x7a, 0xda, 0x83, 0xbd, 0x3e, 0x2f, 0xa7, 0x2b, 0xad, 0x9b, 0xb8, 0x8d, 0xa8, 0xe8, 0x91, 0xdb, 0xfa, 0x2d, 0x6f, 0xc3, 0x8a, 0x2d, 0x56, 0xa3, 0xad, 0x4f, 0x5c, 0xa4, 0x0d, 0xdc, 0xa3, 0xca, 0xd0, 0xbf, 0xa1, 0xe3, 0xfa, 0xe7, 0x0f, 0xf2, 0xb9, 0x57, 0xbf, 0x1a, 0xe4, 0xb8, 0x57, 0xc5, 0xdd, 0xff, 0xd3, 0xf0, 0xcc, 0x5d, 0x7b, 0x70, 0xc5, 0x53, 0x6d, 0x2f, 0xd5, 0xe4, 0x69, 0xfd, 0xdf, 0xec, 0xd7, 0xad, 0x7d, 0xb2, 0x8c, 0x8d, 0xd8, 0xed, 0x91, 0x9f, 0x43, 0xea, 0xe7, 0xeb, 0x94, 0xad, 0x3e, 0x1e, 0x95, 0xfc, 0x72, 0x81, 0x7d, 0x1c, 0x9d, 0xba, 0xb1, 0x7b, 0xdf, 0xa9, 0x7a, 0xdf, 0xee, 0x2f, 0xd4, 0xfa, 0xe7, 0xed, 0x7a, 0x7f, 0xdd, 0xff, 0x00, 0xb2, 0xae, 0x64, 0x0b, 0xea, 0xe3, 0x9a, 0xbf, 0x4a, 0x6f, 0xa4, 0xff, 0x00, 0x89, 0xbd, 0x45, 0xfa, 0xb5, 0x79, 0xf7, 0xeb, 0xc7, 0xe9, 0xae, 0x57, 0x2e, 0x17, 0x23, 0x1f, 0x89, 0xd1, 0x99, 0x8f, 0xf1, 0xa7, 0x11, 0xcf, 0xd3, 0xf5, 0x29, 0xb5, 0x6b, 0xd3, 0xe8, 0xcc, 0x7f, 0x45, 0xb9, 0xa3, 0xc5, 0x62, 0xbe, 0x68, 0xff, 0x00, 0x15, 0xfd, 0x4c, 0xfe, 0x90, 0xaf, 0xd4, 0xab, 0xf1, 0x7a, 0x7f, 0x62, 0x9d, 0xab, 0xdf, 0x32, 0xb1, 0x70, 0x5e, 0xdc, 0xdc, 0x2d, 0x47, 0x8b, 0x5e, 0xae, 0x4c, 0xbf, 0xf2, 0x37, 0x9f, 0x3d, 0x5b, 0xd2, 0xff, 0x00, 0x8e, 0x87, 0xee, 0x29, 0x5a, 0xf2, 0xf4, 0xaa, 0xd4, 0xa5, 0x36, 0xa7, 0x3a, 0x57, 0xfd, 0x8e, 0x64, 0x3a, 0xf2, 0xf6, 0xbf, 0xcc, 0x7f, 0x5b, 0xfc, 0x23, 0xa7, 0xfe, 0x8e, 0xff, 0x00, 0x8e, 0x37, 0xd6, 0x63, 0xfa, 0xe5, 0x2b, 0xcb, 0x87, 0xec, 0xd6, 0xbd, 0xb9, 0x7d, 0xac, 0xc7, 0xcd, 0x7c, 0x2d, 0xf8, 0x2b, 0x89, 0x26, 0x8f, 0xd4, 0xfa, 0x94, 0x3e, 0x85, 0x29, 0xc9, 0x69, 0xfc, 0x33, 0x58, 0x5d, 0x9c, 0x79, 0xb2, 0xbb, 0x0f, 0xac, 0x7a, 0x2b, 0xea, 0x75, 0xef, 0x92, 0x0c, 0x53, 0x3d, 0x2f, 0xd4, 0xfa, 0xbb, 0xfa, 0x74, 0xf5, 0x39, 0x9a, 0xd7, 0xe7, 0x80, 0x53, 0x79, 0xba, 0x5b, 0xfe, 0x97, 0xfa, 0x4b, 0xfc, 0xba, 0x7f, 0xb1, 0xc7, 0xab, 0x1e, 0x8f, 0xff, 0xd9 +}; diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/testclient.h b/thirdparties/common/include/webrtc-sdk/talk/base/testclient.h new file mode 100644 index 0000000..2cce91e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/testclient.h @@ -0,0 +1,110 @@ +/* + * 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 TALK_BASE_TESTCLIENT_H_ +#define TALK_BASE_TESTCLIENT_H_ + +#include +#include "talk/base/asyncudpsocket.h" +#include "talk/base/criticalsection.h" + +namespace talk_base { + +// A simple client that can send TCP or UDP data and check that it receives +// what it expects to receive. Useful for testing server functionality. +class TestClient : public sigslot::has_slots<> { + public: + // Records the contents of a packet that was received. + struct Packet { + Packet(const SocketAddress& a, const char* b, size_t s); + Packet(const Packet& p); + virtual ~Packet(); + + SocketAddress addr; + char* buf; + size_t size; + }; + + // Creates a client that will send and receive with the given socket and + // will post itself messages with the given thread. + explicit TestClient(AsyncPacketSocket* socket); + ~TestClient(); + + SocketAddress address() const { return socket_->GetLocalAddress(); } + SocketAddress remote_address() const { return socket_->GetRemoteAddress(); } + + // Checks that the socket moves to the specified connect state. + bool CheckConnState(AsyncPacketSocket::State state); + + // Checks that the socket is connected to the remote side. + bool CheckConnected() { + return CheckConnState(AsyncPacketSocket::STATE_CONNECTED); + } + + // Sends using the clients socket. + int Send(const char* buf, size_t size); + + // Sends using the clients socket to the given destination. + int SendTo(const char* buf, size_t size, const SocketAddress& dest); + + // Returns the next packet received by the client or 0 if none is received + // within a reasonable amount of time. The caller must delete the packet + // when done with it. + Packet* NextPacket(); + + // Checks that the next packet has the given contents. Returns the remote + // address that the packet was sent from. + bool CheckNextPacket(const char* buf, size_t len, SocketAddress* addr); + + // Checks that no packets have arrived or will arrive in the next second. + bool CheckNoPacket(); + + int GetError(); + int SetOption(Socket::Option opt, int value); + + bool ready_to_send() const; + + private: + static const int kTimeout = 1000; + // Workaround for the fact that AsyncPacketSocket::GetConnState doesn't exist. + Socket::ConnState GetState(); + // Slot for packets read on the socket. + void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t len, + const SocketAddress& remote_addr, + const PacketTime& packet_time); + void OnReadyToSend(AsyncPacketSocket* socket); + + CriticalSection crit_; + AsyncPacketSocket* socket_; + std::vector* packets_; + bool ready_to_send_; + DISALLOW_EVIL_CONSTRUCTORS(TestClient); +}; + +} // namespace talk_base + +#endif // TALK_BASE_TESTCLIENT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/testechoserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/testechoserver.h new file mode 100644 index 0000000..62b42c4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/testechoserver.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_TESTECHOSERVER_H_ +#define TALK_BASE_TESTECHOSERVER_H_ + +#include +#include "talk/base/asynctcpsocket.h" +#include "talk/base/socketaddress.h" +#include "talk/base/sigslot.h" +#include "talk/base/thread.h" + +namespace talk_base { + +// A test echo server, echoes back any packets sent to it. +// Useful for unit tests. +class TestEchoServer : public sigslot::has_slots<> { + public: + TestEchoServer(Thread* thread, const SocketAddress& addr) + : server_socket_(thread->socketserver()->CreateAsyncSocket(addr.family(), + SOCK_STREAM)) { + server_socket_->Bind(addr); + server_socket_->Listen(5); + server_socket_->SignalReadEvent.connect(this, &TestEchoServer::OnAccept); + } + ~TestEchoServer() { + for (ClientList::iterator it = client_sockets_.begin(); + it != client_sockets_.end(); ++it) { + delete *it; + } + } + + SocketAddress address() const { return server_socket_->GetLocalAddress(); } + + private: + void OnAccept(AsyncSocket* socket) { + AsyncSocket* raw_socket = socket->Accept(NULL); + if (raw_socket) { + AsyncTCPSocket* packet_socket = new AsyncTCPSocket(raw_socket, false); + packet_socket->SignalReadPacket.connect(this, &TestEchoServer::OnPacket); + packet_socket->SignalClose.connect(this, &TestEchoServer::OnClose); + client_sockets_.push_back(packet_socket); + } + } + void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t size, + const SocketAddress& remote_addr, + const PacketTime& packet_time) { + talk_base::PacketOptions options; + socket->Send(buf, size, options); + } + void OnClose(AsyncPacketSocket* socket, int err) { + ClientList::iterator it = + std::find(client_sockets_.begin(), client_sockets_.end(), socket); + client_sockets_.erase(it); + Thread::Current()->Dispose(socket); + } + + typedef std::list ClientList; + scoped_ptr server_socket_; + ClientList client_sockets_; + DISALLOW_EVIL_CONSTRUCTORS(TestEchoServer); +}; + +} // namespace talk_base + +#endif // TALK_BASE_TESTECHOSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/testutils.h b/thirdparties/common/include/webrtc-sdk/talk/base/testutils.h new file mode 100644 index 0000000..c137cd3 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/testutils.h @@ -0,0 +1,646 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_TESTUTILS_H__ +#define TALK_BASE_TESTUTILS_H__ + +// Utilities for testing talk_base infrastructure in unittests + +#ifdef LINUX +#include +#include + +// X defines a few macros that stomp on types that gunit.h uses. +#undef None +#undef Bool +#endif + +#include +#include +#include "talk/base/asyncsocket.h" +#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" +#include "talk/base/thread.h" + +namespace testing { + +using namespace talk_base; + +/////////////////////////////////////////////////////////////////////////////// +// StreamSink - Monitor asynchronously signalled events from StreamInterface +// or AsyncSocket (which should probably be a StreamInterface. +/////////////////////////////////////////////////////////////////////////////// + +// Note: Any event that is an error is treaded as SSE_ERROR instead of that +// event. + +enum StreamSinkEvent { + SSE_OPEN = SE_OPEN, + SSE_READ = SE_READ, + SSE_WRITE = SE_WRITE, + SSE_CLOSE = SE_CLOSE, + SSE_ERROR = 16 +}; + +class StreamSink : public sigslot::has_slots<> { + public: + void Monitor(StreamInterface* stream) { + stream->SignalEvent.connect(this, &StreamSink::OnEvent); + events_.erase(stream); + } + void Unmonitor(StreamInterface* stream) { + stream->SignalEvent.disconnect(this); + // In case you forgot to unmonitor a previous object with this address + events_.erase(stream); + } + bool Check(StreamInterface* stream, StreamSinkEvent event, bool reset = true) { + return DoCheck(stream, event, reset); + } + int Events(StreamInterface* stream, bool reset = true) { + return DoEvents(stream, reset); + } + + void Monitor(AsyncSocket* socket) { + socket->SignalConnectEvent.connect(this, &StreamSink::OnConnectEvent); + socket->SignalReadEvent.connect(this, &StreamSink::OnReadEvent); + socket->SignalWriteEvent.connect(this, &StreamSink::OnWriteEvent); + socket->SignalCloseEvent.connect(this, &StreamSink::OnCloseEvent); + // In case you forgot to unmonitor a previous object with this address + events_.erase(socket); + } + void Unmonitor(AsyncSocket* socket) { + socket->SignalConnectEvent.disconnect(this); + socket->SignalReadEvent.disconnect(this); + socket->SignalWriteEvent.disconnect(this); + socket->SignalCloseEvent.disconnect(this); + events_.erase(socket); + } + bool Check(AsyncSocket* socket, StreamSinkEvent event, bool reset = true) { + return DoCheck(socket, event, reset); + } + int Events(AsyncSocket* socket, bool reset = true) { + return DoEvents(socket, reset); + } + + private: + typedef std::map EventMap; + + void OnEvent(StreamInterface* stream, int events, int error) { + if (error) { + events = SSE_ERROR; + } + AddEvents(stream, events); + } + void OnConnectEvent(AsyncSocket* socket) { + AddEvents(socket, SSE_OPEN); + } + void OnReadEvent(AsyncSocket* socket) { + AddEvents(socket, SSE_READ); + } + void OnWriteEvent(AsyncSocket* socket) { + AddEvents(socket, SSE_WRITE); + } + void OnCloseEvent(AsyncSocket* socket, int error) { + AddEvents(socket, (0 == error) ? SSE_CLOSE : SSE_ERROR); + } + + void AddEvents(void* obj, int events) { + EventMap::iterator it = events_.find(obj); + if (events_.end() == it) { + events_.insert(EventMap::value_type(obj, events)); + } else { + it->second |= events; + } + } + bool DoCheck(void* obj, StreamSinkEvent event, bool reset) { + EventMap::iterator it = events_.find(obj); + if ((events_.end() == it) || (0 == (it->second & event))) { + return false; + } + if (reset) { + it->second &= ~event; + } + return true; + } + int DoEvents(void* obj, bool reset) { + EventMap::iterator it = events_.find(obj); + if (events_.end() == it) + return 0; + int events = it->second; + if (reset) { + it->second = 0; + } + return events; + } + + EventMap events_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamSource - Implements stream interface and simulates asynchronous +// events on the stream, without a network. Also buffers written data. +/////////////////////////////////////////////////////////////////////////////// + +class StreamSource : public StreamInterface { +public: + StreamSource() { + Clear(); + } + + void Clear() { + readable_data_.clear(); + written_data_.clear(); + state_ = SS_CLOSED; + read_block_ = 0; + write_block_ = SIZE_UNKNOWN; + } + void QueueString(const char* data) { + QueueData(data, strlen(data)); + } + void QueueStringF(const char* format, ...) { + va_list args; + va_start(args, format); + char buffer[1024]; + size_t len = vsprintfn(buffer, sizeof(buffer), format, args); + ASSERT(len < sizeof(buffer) - 1); + va_end(args); + QueueData(buffer, len); + } + void QueueData(const char* data, size_t len) { + readable_data_.insert(readable_data_.end(), data, data + len); + if ((SS_OPEN == state_) && (readable_data_.size() == len)) { + SignalEvent(this, SE_READ, 0); + } + } + std::string ReadData() { + std::string data; + // avoid accessing written_data_[0] if it is undefined + if (written_data_.size() > 0) { + data.insert(0, &written_data_[0], written_data_.size()); + } + written_data_.clear(); + return data; + } + void SetState(StreamState state) { + int events = 0; + if ((SS_OPENING == state_) && (SS_OPEN == state)) { + events |= SE_OPEN; + if (!readable_data_.empty()) { + events |= SE_READ; + } + } else if ((SS_CLOSED != state_) && (SS_CLOSED == state)) { + events |= SE_CLOSE; + } + state_ = state; + if (events) { + SignalEvent(this, events, 0); + } + } + // Will cause Read to block when there are pos bytes in the read queue. + void SetReadBlock(size_t pos) { read_block_ = pos; } + // Will cause Write to block when there are pos bytes in the write queue. + void SetWriteBlock(size_t pos) { write_block_ = pos; } + + virtual StreamState GetState() const { return state_; } + virtual StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error) { + if (SS_CLOSED == state_) { + if (error) *error = -1; + return SR_ERROR; + } + if ((SS_OPENING == state_) || (readable_data_.size() <= read_block_)) { + return SR_BLOCK; + } + size_t count = _min(buffer_len, readable_data_.size() - read_block_); + memcpy(buffer, &readable_data_[0], count); + size_t new_size = readable_data_.size() - count; + // Avoid undefined access beyond the last element of the vector. + // This only happens when new_size is 0. + if (count < readable_data_.size()) { + memmove(&readable_data_[0], &readable_data_[count], new_size); + } + readable_data_.resize(new_size); + if (read) *read = count; + return SR_SUCCESS; + } + virtual StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error) { + if (SS_CLOSED == state_) { + if (error) *error = -1; + return SR_ERROR; + } + if (SS_OPENING == state_) { + return SR_BLOCK; + } + if (SIZE_UNKNOWN != write_block_) { + if (written_data_.size() >= write_block_) { + return SR_BLOCK; + } + if (data_len > (write_block_ - written_data_.size())) { + data_len = write_block_ - written_data_.size(); + } + } + if (written) *written = data_len; + const char* cdata = static_cast(data); + written_data_.insert(written_data_.end(), cdata, cdata + data_len); + return SR_SUCCESS; + } + virtual void Close() { state_ = SS_CLOSED; } + +private: + typedef std::vector Buffer; + Buffer readable_data_, written_data_; + StreamState state_; + size_t read_block_, write_block_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// SocketTestClient +// Creates a simulated client for testing. Works on real and virtual networks. +/////////////////////////////////////////////////////////////////////////////// + +class SocketTestClient : public sigslot::has_slots<> { +public: + SocketTestClient() { + Init(NULL, AF_INET); + } + SocketTestClient(AsyncSocket* socket) { + Init(socket, socket->GetLocalAddress().family()); + } + SocketTestClient(const SocketAddress& address) { + Init(NULL, address.family()); + socket_->Connect(address); + } + + AsyncSocket* socket() { return socket_.get(); } + + void QueueString(const char* data) { + QueueData(data, strlen(data)); + } + void QueueStringF(const char* format, ...) { + va_list args; + va_start(args, format); + char buffer[1024]; + size_t len = vsprintfn(buffer, sizeof(buffer), format, args); + ASSERT(len < sizeof(buffer) - 1); + va_end(args); + QueueData(buffer, len); + } + void QueueData(const char* data, size_t len) { + send_buffer_.insert(send_buffer_.end(), data, data + len); + if (Socket::CS_CONNECTED == socket_->GetState()) { + Flush(); + } + } + std::string ReadData() { + std::string data(&recv_buffer_[0], recv_buffer_.size()); + recv_buffer_.clear(); + return data; + } + + bool IsConnected() const { + return (Socket::CS_CONNECTED == socket_->GetState()); + } + bool IsClosed() const { + return (Socket::CS_CLOSED == socket_->GetState()); + } + +private: + typedef std::vector Buffer; + + void Init(AsyncSocket* socket, int family) { + if (!socket) { + socket = Thread::Current()->socketserver() + ->CreateAsyncSocket(family, SOCK_STREAM); + } + socket_.reset(socket); + socket_->SignalConnectEvent.connect(this, + &SocketTestClient::OnConnectEvent); + socket_->SignalReadEvent.connect(this, &SocketTestClient::OnReadEvent); + socket_->SignalWriteEvent.connect(this, &SocketTestClient::OnWriteEvent); + socket_->SignalCloseEvent.connect(this, &SocketTestClient::OnCloseEvent); + } + + void Flush() { + size_t sent = 0; + while (sent < send_buffer_.size()) { + int result = socket_->Send(&send_buffer_[sent], + send_buffer_.size() - sent); + if (result > 0) { + sent += result; + } else { + break; + } + } + size_t new_size = send_buffer_.size() - sent; + memmove(&send_buffer_[0], &send_buffer_[sent], new_size); + send_buffer_.resize(new_size); + } + + void OnConnectEvent(AsyncSocket* socket) { + if (!send_buffer_.empty()) { + Flush(); + } + } + void OnReadEvent(AsyncSocket* socket) { + char data[64 * 1024]; + int result = socket_->Recv(data, ARRAY_SIZE(data)); + if (result > 0) { + recv_buffer_.insert(recv_buffer_.end(), data, data + result); + } + } + void OnWriteEvent(AsyncSocket* socket) { + if (!send_buffer_.empty()) { + Flush(); + } + } + void OnCloseEvent(AsyncSocket* socket, int error) { + } + + scoped_ptr socket_; + Buffer send_buffer_, recv_buffer_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// SocketTestServer +// Creates a simulated server for testing. Works on real and virtual networks. +/////////////////////////////////////////////////////////////////////////////// + +class SocketTestServer : public sigslot::has_slots<> { + public: + SocketTestServer(const SocketAddress& address) + : socket_(Thread::Current()->socketserver() + ->CreateAsyncSocket(address.family(), SOCK_STREAM)) + { + socket_->SignalReadEvent.connect(this, &SocketTestServer::OnReadEvent); + socket_->Bind(address); + socket_->Listen(5); + } + virtual ~SocketTestServer() { + clear(); + } + + size_t size() const { return clients_.size(); } + SocketTestClient* client(size_t index) const { return clients_[index]; } + SocketTestClient* operator[](size_t index) const { return client(index); } + + void clear() { + for (size_t i=0; i(socket_->Accept(NULL)); + if (!accepted) + return; + clients_.push_back(new SocketTestClient(accepted)); + } + + scoped_ptr socket_; + std::vector clients_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Generic Utilities +/////////////////////////////////////////////////////////////////////////////// + +inline bool ReadFile(const char* filename, std::string* contents) { + FILE* fp = fopen(filename, "rb"); + if (!fp) + return false; + char buffer[1024*64]; + size_t read; + contents->clear(); + while ((read = fread(buffer, 1, sizeof(buffer), fp))) { + contents->append(buffer, read); + } + bool success = (0 != feof(fp)); + fclose(fp); + 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 +/////////////////////////////////////////////////////////////////////////////// + +inline AssertionResult CmpHelperMemEq(const char* expected_expression, + const char* expected_length_expression, + const char* actual_expression, + const char* actual_length_expression, + const void* expected, + size_t expected_length, + const void* actual, + size_t actual_length) +{ + if ((expected_length == actual_length) + && (0 == memcmp(expected, actual, expected_length))) { + return AssertionSuccess(); + } + + Message msg; + msg << "Value of: " << actual_expression + << " [" << actual_length_expression << "]"; + if (true) { //!actual_value.Equals(actual_expression)) { + size_t buffer_size = actual_length * 2 + 1; + char* buffer = STACK_ARRAY(char, buffer_size); + hex_encode(buffer, buffer_size, + reinterpret_cast(actual), actual_length); + msg << "\n Actual: " << buffer << " [" << actual_length << "]"; + } + + msg << "\nExpected: " << expected_expression + << " [" << expected_length_expression << "]"; + if (true) { //!expected_value.Equals(expected_expression)) { + size_t buffer_size = expected_length * 2 + 1; + char* buffer = STACK_ARRAY(char, buffer_size); + hex_encode(buffer, buffer_size, + reinterpret_cast(expected), expected_length); + msg << "\nWhich is: " << buffer << " [" << expected_length << "]"; + } + + return AssertionFailure(msg); +} + +inline AssertionResult CmpHelperFileEq(const char* expected_expression, + const char* expected_length_expression, + const char* actual_filename, + const void* expected, + size_t expected_length, + const char* filename) +{ + std::string contents; + if (!ReadFile(filename, &contents)) { + Message msg; + msg << "File '" << filename << "' could not be read."; + return AssertionFailure(msg); + } + return CmpHelperMemEq(expected_expression, expected_length_expression, + actual_filename, "", + expected, expected_length, + contents.c_str(), contents.size()); +} + +#define EXPECT_MEMEQ(expected, expected_length, actual, actual_length) \ + EXPECT_PRED_FORMAT4(::testing::CmpHelperMemEq, expected, expected_length, \ + actual, actual_length) + +#define ASSERT_MEMEQ(expected, expected_length, actual, actual_length) \ + ASSERT_PRED_FORMAT4(::testing::CmpHelperMemEq, expected, expected_length, \ + actual, actual_length) + +#define EXPECT_FILEEQ(expected, expected_length, filename) \ + EXPECT_PRED_FORMAT3(::testing::CmpHelperFileEq, expected, expected_length, \ + filename) + +#define ASSERT_FILEEQ(expected, expected_length, filename) \ + ASSERT_PRED_FORMAT3(::testing::CmpHelperFileEq, expected, expected_length, \ + filename) + +/////////////////////////////////////////////////////////////////////////////// +// Helpers for initializing constant memory with integers in a particular byte +// order +/////////////////////////////////////////////////////////////////////////////// + +#define BYTE_CAST(x) static_cast((x) & 0xFF) + +// Declare a N-bit integer as a little-endian sequence of bytes +#define LE16(x) BYTE_CAST(((uint16)x) >> 0), BYTE_CAST(((uint16)x) >> 8) + +#define LE32(x) BYTE_CAST(((uint32)x) >> 0), BYTE_CAST(((uint32)x) >> 8), \ + BYTE_CAST(((uint32)x) >> 16), BYTE_CAST(((uint32)x) >> 24) + +#define LE64(x) BYTE_CAST(((uint64)x) >> 0), BYTE_CAST(((uint64)x) >> 8), \ + BYTE_CAST(((uint64)x) >> 16), BYTE_CAST(((uint64)x) >> 24), \ + BYTE_CAST(((uint64)x) >> 32), BYTE_CAST(((uint64)x) >> 40), \ + BYTE_CAST(((uint64)x) >> 48), BYTE_CAST(((uint64)x) >> 56) + +// Declare a N-bit integer as a big-endian (Internet) sequence of bytes +#define BE16(x) BYTE_CAST(((uint16)x) >> 8), BYTE_CAST(((uint16)x) >> 0) + +#define BE32(x) BYTE_CAST(((uint32)x) >> 24), BYTE_CAST(((uint32)x) >> 16), \ + BYTE_CAST(((uint32)x) >> 8), BYTE_CAST(((uint32)x) >> 0) + +#define BE64(x) BYTE_CAST(((uint64)x) >> 56), BYTE_CAST(((uint64)x) >> 48), \ + BYTE_CAST(((uint64)x) >> 40), BYTE_CAST(((uint64)x) >> 32), \ + BYTE_CAST(((uint64)x) >> 24), BYTE_CAST(((uint64)x) >> 16), \ + BYTE_CAST(((uint64)x) >> 8), BYTE_CAST(((uint64)x) >> 0) + +// Declare a N-bit integer as a this-endian (local machine) sequence of bytes +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 1 +#endif // BIG_ENDIAN + +#if BIG_ENDIAN +#define TE16 BE16 +#define TE32 BE32 +#define TE64 BE64 +#else // !BIG_ENDIAN +#define TE16 LE16 +#define TE32 LE32 +#define TE64 LE64 +#endif // !BIG_ENDIAN + +/////////////////////////////////////////////////////////////////////////////// + +// Helpers for determining if X/screencasting is available (on linux). + +#define MAYBE_SKIP_SCREENCAST_TEST() \ + if (!testing::IsScreencastingAvailable()) { \ + LOG(LS_WARNING) << "Skipping test, since it doesn't have the requisite " \ + << "X environment for screen capture."; \ + return; \ + } \ + +#ifdef LINUX +struct XDisplay { + XDisplay() : display_(XOpenDisplay(NULL)) { } + ~XDisplay() { if (display_) XCloseDisplay(display_); } + bool IsValid() const { return display_ != NULL; } + operator Display*() { return display_; } + private: + Display* display_; +}; +#endif + +// Returns true if screencasting is available. When false, anything that uses +// screencasting features may fail. +inline bool IsScreencastingAvailable() { +#ifdef LINUX + XDisplay display; + if (!display.IsValid()) { + 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; +} +} // namespace testing + +#endif // TALK_BASE_TESTUTILS_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/thread.h b/thirdparties/common/include/webrtc-sdk/talk/base/thread.h new file mode 100644 index 0000000..18bf31c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/thread.h @@ -0,0 +1,311 @@ +/* + * 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_BASE_THREAD_H_ +#define TALK_BASE_THREAD_H_ + +#include +#include +#include +#include + +#ifdef POSIX +#include +#endif +#include "talk/base/constructormagic.h" +#include "talk/base/event.h" +#include "talk/base/messagequeue.h" + +#ifdef WIN32 +#include "talk/base/win32.h" +#endif + +namespace talk_base { + +class Thread; + +class ThreadManager { + public: + ThreadManager(); + ~ThreadManager(); + + static ThreadManager* Instance(); + + Thread* CurrentThread(); + void SetCurrentThread(Thread* thread); + + // Returns a thread object with its thread_ ivar set + // to whatever the OS uses to represent the thread. + // If there already *is* a Thread object corresponding to this thread, + // this method will return that. Otherwise it creates a new Thread + // object whose wrapped() method will return true, and whose + // handle will, on Win32, be opened with only synchronization privileges - + // if you need more privilegs, rather than changing this method, please + // write additional code to adjust the privileges, or call a different + // factory method of your own devising, because this one gets used in + // unexpected contexts (like inside browser plugins) and it would be a + // shame to break it. It is also conceivable on Win32 that we won't even + // be able to get synchronization privileges, in which case the result + // will have a NULL handle. + Thread *WrapCurrentThread(); + void UnwrapCurrentThread(); + + private: +#ifdef POSIX + pthread_key_t key_; +#endif + +#ifdef WIN32 + DWORD key_; +#endif + + DISALLOW_COPY_AND_ASSIGN(ThreadManager); +}; + +struct _SendMessage { + _SendMessage() {} + Thread *thread; + Message msg; + bool *ready; +}; + +enum ThreadPriority { + PRIORITY_IDLE = -1, + PRIORITY_NORMAL = 0, + PRIORITY_ABOVE_NORMAL = 1, + PRIORITY_HIGH = 2, +}; + +class Runnable { + public: + virtual ~Runnable() {} + virtual void Run(Thread* thread) = 0; + + protected: + Runnable() {} + + private: + DISALLOW_COPY_AND_ASSIGN(Runnable); +}; + +// WARNING! SUBCLASSES MUST CALL Stop() IN THEIR DESTRUCTORS! See ~Thread(). + +class Thread : public MessageQueue { + public: + explicit Thread(SocketServer* ss = NULL); + // NOTE: ALL SUBCLASSES OF Thread MUST CALL Stop() IN THEIR DESTRUCTORS (or + // guarantee Stop() is explicitly called before the subclass is destroyed). + // This is required to avoid a data race between the destructor modifying the + // vtable, and the Thread::PreRun calling the virtual method Run(). + virtual ~Thread(); + + static Thread* Current(); + + bool IsCurrent() const { + return Current() == this; + } + + // Sleeps the calling thread for the specified number of milliseconds, during + // which time no processing is performed. Returns false if sleeping was + // interrupted by a signal (POSIX only). + static bool SleepMs(int millis); + + // Sets the thread's name, for debugging. Must be called before Start(). + // If |obj| is non-NULL, its value is appended to |name|. + const std::string& name() const { return name_; } + bool SetName(const std::string& name, const void* obj); + + // Sets the thread's priority. Must be called before Start(). + ThreadPriority priority() const { return priority_; } + bool SetPriority(ThreadPriority priority); + + // Starts the execution of the thread. + bool Start(Runnable* runnable = NULL); + + // 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 + // underlying OS thread. + virtual void Stop(); + + // By default, Thread::Run() calls ProcessMessages(kForever). To do other + // work, override Run(). To receive and dispatch messages, call + // ProcessMessages occasionally. + virtual void Run(); + + virtual void Send(MessageHandler *phandler, uint32 id = 0, + MessageData *pdata = NULL); + + // Convenience method to invoke a functor on another thread. Caller must + // provide the |ReturnT| template argument, which cannot (easily) be deduced. + // Uses Send() internally, which blocks the current thread until execution + // is complete. + // Ex: bool result = thread.Invoke(&MyFunctionReturningBool); + template + ReturnT Invoke(const FunctorT& functor) { + FunctorMessageHandler handler(functor); + Send(&handler); + return handler.result(); + } + + // From MessageQueue + virtual void Clear(MessageHandler *phandler, uint32 id = MQID_ANY, + MessageList* removed = NULL); + virtual void ReceiveSends(); + + // ProcessMessages will process I/O and dispatch messages until: + // 1) cms milliseconds have elapsed (returns true) + // 2) Stop() is called (returns false) + bool ProcessMessages(int cms); + + // Returns true if this is a thread that we created using the standard + // constructor, false if it was created by a call to + // ThreadManager::WrapCurrentThread(). The main thread of an application + // is generally not owned, since the OS representation of the thread + // obviously exists before we can get to it. + // You cannot call Start on non-owned threads. + bool IsOwned(); + +#ifdef WIN32 + HANDLE GetHandle() const { + return thread_; + } + DWORD GetId() const { + return thread_id_; + } +#elif POSIX + pthread_t GetPThread() { + return thread_; + } +#endif + + // This method should be called when thread is created using non standard + // method, like derived implementation of talk_base::Thread and it can not be + // started by calling Start(). This will set started flag to true and + // owned to false. This must be called from the current thread. + // NOTE: These methods should be used by the derived classes only, added here + // only for testing. + 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: + static void *PreRun(void *pv); + + // ThreadManager calls this instead WrapCurrent() because + // ThreadManager::Instance() cannot be used while ThreadManager is + // 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_; + Event running_; // Signalled means running. + +#ifdef POSIX + pthread_t thread_; +#endif + +#ifdef WIN32 + HANDLE thread_; + DWORD thread_id_; +#endif + + bool owned_; + + friend class ThreadManager; + + DISALLOW_COPY_AND_ASSIGN(Thread); +}; + +// AutoThread automatically installs itself at construction +// uninstalls at destruction, if a Thread object is +// _not already_ associated with the current OS thread. + +class AutoThread : public Thread { + public: + explicit AutoThread(SocketServer* ss = 0); + virtual ~AutoThread(); + + private: + DISALLOW_COPY_AND_ASSIGN(AutoThread); +}; + +// Win32 extension for threads that need to use COM +#ifdef WIN32 +class ComThread : public Thread { + public: + ComThread() {} + virtual ~ComThread() { Stop(); } + + protected: + virtual void Run(); + + private: + DISALLOW_COPY_AND_ASSIGN(ComThread); +}; +#endif + +// Provides an easy way to install/uninstall a socketserver on a thread. +class SocketServerScope { + public: + explicit SocketServerScope(SocketServer* ss) { + old_ss_ = Thread::Current()->socketserver(); + Thread::Current()->set_socketserver(ss); + } + ~SocketServerScope() { + Thread::Current()->set_socketserver(old_ss_); + } + + private: + SocketServer* old_ss_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(SocketServerScope); +}; + +} // namespace talk_base + +#endif // TALK_BASE_THREAD_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/timeutils.h b/thirdparties/common/include/webrtc-sdk/talk/base/timeutils.h new file mode 100644 index 0000000..d04435c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/timeutils.h @@ -0,0 +1,113 @@ +/* + * libjingle + * Copyright 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 TALK_BASE_TIMEUTILS_H_ +#define TALK_BASE_TIMEUTILS_H_ + +#include + +#include "talk/base/basictypes.h" + +namespace talk_base { + +static const int64 kNumMillisecsPerSec = INT64_C(1000); +static const int64 kNumMicrosecsPerSec = INT64_C(1000000); +static const int64 kNumNanosecsPerSec = INT64_C(1000000000); + +static const int64 kNumMicrosecsPerMillisec = kNumMicrosecsPerSec / + kNumMillisecsPerSec; +static const int64 kNumNanosecsPerMillisec = kNumNanosecsPerSec / + kNumMillisecsPerSec; +static const int64 kNumNanosecsPerMicrosec = kNumNanosecsPerSec / + kNumMicrosecsPerSec; + +// January 1970, in NTP milliseconds. +static const int64 kJan1970AsNtpMillisecs = INT64_C(2208988800000); + +typedef uint32 TimeStamp; + +// Returns the current time in milliseconds. +uint32 Time(); +// Returns the current time in microseconds. +uint64 TimeMicros(); +// Returns the current time in nanoseconds. +uint64 TimeNanos(); + +// Stores current time in *tm and microseconds in *microseconds. +void CurrentTmTime(struct tm *tm, int *microseconds); + +// Returns a future timestamp, 'elapsed' milliseconds from now. +uint32 TimeAfter(int32 elapsed); + +// Comparisons between time values, which can wrap around. +bool TimeIsBetween(uint32 earlier, uint32 middle, uint32 later); // Inclusive +bool TimeIsLaterOrEqual(uint32 earlier, uint32 later); // Inclusive +bool TimeIsLater(uint32 earlier, uint32 later); // Exclusive + +// Returns the later of two timestamps. +inline uint32 TimeMax(uint32 ts1, uint32 ts2) { + return TimeIsLaterOrEqual(ts1, ts2) ? ts2 : ts1; +} + +// Returns the earlier of two timestamps. +inline uint32 TimeMin(uint32 ts1, uint32 ts2) { + return TimeIsLaterOrEqual(ts1, ts2) ? ts1 : ts2; +} + +// Number of milliseconds that would elapse between 'earlier' and 'later' +// timestamps. The value is negative if 'later' occurs before 'earlier'. +int32 TimeDiff(uint32 later, uint32 earlier); + +// The number of milliseconds that have elapsed since 'earlier'. +inline int32 TimeSince(uint32 earlier) { + return TimeDiff(Time(), earlier); +} + +// The number of milliseconds that will elapse between now and 'later'. +inline int32 TimeUntil(uint32 later) { + return TimeDiff(later, Time()); +} + +// Converts a unix timestamp in nanoseconds to an NTP timestamp in ms. +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/thirdparties/common/include/webrtc-sdk/talk/base/timing.h b/thirdparties/common/include/webrtc-sdk/talk/base/timing.h new file mode 100644 index 0000000..b2b9278 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/timing.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_TIMING_H_ +#define TALK_BASE_TIMING_H_ + +#if defined(WIN32) +#include "talk/base/win32.h" +#endif + +namespace talk_base { + +class Timing { + public: + Timing(); + virtual ~Timing(); + + // WallTimeNow() returns the current wall-clock time in seconds, + // within 10 milliseconds resolution. + virtual double WallTimeNow(); + + // TimerNow() is like WallTimeNow(), but is monotonically + // increasing. It returns seconds in resolution of 10 microseconds + // or better. Although timer and wall-clock time have the same + // timing unit, they do not necessarily correlate because wall-clock + // time may be adjusted backwards, hence not monotonic. + // Made virtual so we can make a fake one. + virtual double TimerNow(); + + // BusyWait() exhausts CPU as long as the time elapsed is less than + // the specified interval in seconds. Returns the actual waiting + // time based on TimerNow() measurement. + double BusyWait(double period); + + // IdleWait() relinquishes control of CPU for specified period in + // seconds. It uses highest resolution sleep mechanism as possible, + // but does not otherwise guarantee the accuracy. Returns the + // actual waiting time based on TimerNow() measurement. + // + // This function is not re-entrant for an object. Create a fresh + // Timing object for each thread. + double IdleWait(double period); + + private: +#if defined(WIN32) + HANDLE timer_handle_; +#endif +}; + +} // namespace talk_base + +#endif // TALK_BASE_TIMING_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/transformadapter.h b/thirdparties/common/include/webrtc-sdk/talk/base/transformadapter.h new file mode 100644 index 0000000..1b22135 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/transformadapter.h @@ -0,0 +1,97 @@ +/* + * 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 TALK_BASE_TRANSFORMADAPTER_H__ +#define TALK_BASE_TRANSFORMADAPTER_H__ + +#include "talk/base/stream.h" + +namespace talk_base { +/////////////////////////////////////////////////////////////////////////////// + +class TransformInterface { +public: + virtual ~TransformInterface() { } + + // Transform should convert the in_len bytes of input into the out_len-sized + // output buffer. If flush is true, there will be no more data following + // input. + // After the transformation, in_len contains the number of bytes consumed, and + // out_len contains the number of bytes ready in output. + // Note: Transform should not return SR_BLOCK, as there is no asynchronous + // notification available. + virtual StreamResult Transform(const void * input, size_t * in_len, + void * output, size_t * out_len, + bool flush) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// + +// TransformAdapter causes all data passed through to be transformed by the +// supplied TransformInterface object, which may apply compression, encryption, +// etc. + +class TransformAdapter : public StreamAdapterInterface { +public: + // Note that the transformation is unidirectional, in the direction specified + // by the constructor. Operations in the opposite direction result in SR_EOS. + TransformAdapter(StreamInterface * stream, + TransformInterface * transform, + bool direction_read); + virtual ~TransformAdapter(); + + virtual StreamResult Read(void * buffer, size_t buffer_len, + size_t * read, int * error); + virtual StreamResult Write(const void * data, size_t data_len, + size_t * written, int * error); + virtual void Close(); + + // Apriori, we can't tell what the transformation does to the stream length. + virtual bool GetAvailable(size_t* size) const { return false; } + virtual bool ReserveSize(size_t size) { return true; } + + // Transformations might not be restartable + virtual bool Rewind() { return false; } + +private: + enum State { ST_PROCESSING, ST_FLUSHING, ST_COMPLETE, ST_ERROR }; + enum { BUFFER_SIZE = 1024 }; + + TransformInterface * transform_; + bool direction_read_; + State state_; + int error_; + + char buffer_[BUFFER_SIZE]; + size_t len_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_TRANSFORMADAPTER_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/unixfilesystem.h b/thirdparties/common/include/webrtc-sdk/talk/base/unixfilesystem.h new file mode 100644 index 0000000..c5c530e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/unixfilesystem.h @@ -0,0 +1,143 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_UNIXFILESYSTEM_H_ +#define TALK_BASE_UNIXFILESYSTEM_H_ + +#include + +#include "talk/base/fileutils.h" + +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. 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 + + // Opens a file. Returns an open StreamInterface if function succeeds. + // Otherwise, returns NULL. + virtual FileStream *OpenFile(const Pathname &filename, + const std::string &mode); + + // Atomically creates an empty file accessible only to the current user if one + // does not already exist at the given path, otherwise fails. + virtual bool CreatePrivateFile(const Pathname &filename); + + // This will attempt to delete the file located at filename. + // It will fail with VERIY if you pass it a non-existant file, or a directory. + virtual bool DeleteFile(const Pathname &filename); + + // This will attempt to delete the folder located at 'folder' + // It ASSERTs and returns false if you pass it a non-existant folder or a + // plain file. + virtual bool DeleteEmptyFolder(const Pathname &folder); + + // Creates a directory. This will call itself recursively to create /foo/bar + // even if /foo does not exist. All created directories are created with the + // given mode. + // Returns TRUE if function succeeds + virtual bool CreateFolder(const Pathname &pathname, mode_t mode); + + // As above, with mode = 0755. + virtual bool CreateFolder(const Pathname &pathname); + + // This moves a file from old_path to new_path, where "file" can be a plain + // file or directory, which will be moved recursively. + // Returns true if function succeeds. + virtual bool MoveFile(const Pathname &old_path, const Pathname &new_path); + virtual bool MoveFolder(const Pathname &old_path, const Pathname &new_path); + + // This copies a file from old_path to _new_path where "file" can be a plain + // file or directory, which will be copied recursively. + // Returns true if function succeeds + virtual bool CopyFile(const Pathname &old_path, const Pathname &new_path); + + // Returns true if a pathname is a directory + virtual bool IsFolder(const Pathname& pathname); + + // Returns true if pathname represents a temporary location on the system. + virtual bool IsTemporaryPath(const Pathname& pathname); + + // Returns true of pathname represents an existing file + virtual bool IsFile(const Pathname& pathname); + + // Returns true if pathname refers to no filesystem object, every parent + // directory either exists, or is also absent. + virtual bool IsAbsent(const Pathname& pathname); + + virtual std::string TempFilename(const Pathname &dir, + const std::string &prefix); + + // A folder appropriate for storing temporary files (Contents are + // automatically deleted when the program exists) + virtual bool GetTemporaryFolder(Pathname &path, bool create, + const std::string *append); + + virtual bool GetFileSize(const Pathname& path, size_t* size); + virtual bool GetFileTime(const Pathname& path, FileTimeType which, + time_t* time); + + // Returns the path to the running application. + virtual bool GetAppPathname(Pathname* path); + + virtual bool GetAppDataFolder(Pathname* path, bool per_user); + + // Get a temporary folder that is unique to the current user and application. + virtual bool GetAppTempFolder(Pathname* path); + + virtual bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes); + + // Returns the absolute path of the current directory. + virtual Pathname GetCurrentDirectory(); + + private: +#if defined(ANDROID) || defined(IOS) + static char* provided_app_data_folder_; + static char* provided_app_temp_folder_; +#else + static char* app_temp_path_; +#endif + + static char* CopyString(const std::string& str); +}; + +} // namespace talk_base + +#endif // TALK_BASE_UNIXFILESYSTEM_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/urlencode.h b/thirdparties/common/include/webrtc-sdk/talk/base/urlencode.h new file mode 100644 index 0000000..d26e3e5 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/urlencode.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef _URLENCODE_H_ +#define _URLENCODE_H_ + +#include + +// Decode all encoded characters. Also decode + as space. +int UrlDecode(const char *source, char *dest); + +// Decode all encoded characters. +int UrlDecodeWithoutEncodingSpaceAsPlus(const char *source, char *dest); + +// Encode all characters except alphas, numbers, and -_.!~*'() +// Also encode space as +. +int UrlEncode(const char *source, char *dest, unsigned max); + +// Encode all characters except alphas, numbers, and -_.!~*'() +int UrlEncodeWithoutEncodingSpaceAsPlus(const char *source, char *dest, + unsigned max); + +// Encode only unsafe chars, including \ "^&`<>[]{} +// Also encode space as %20, instead of + +int UrlEncodeOnlyUnsafeChars(const char *source, char *dest, unsigned max); + +std::string UrlDecodeString(const std::string & encoded); +std::string UrlDecodeStringWithoutEncodingSpaceAsPlus( + const std::string & encoded); +std::string UrlEncodeString(const std::string & decoded); +std::string UrlEncodeStringWithoutEncodingSpaceAsPlus( + const std::string & decoded); +std::string UrlEncodeStringForOnlyUnsafeChars(const std::string & decoded); + +#endif + diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/versionparsing.h b/thirdparties/common/include/webrtc-sdk/talk/base/versionparsing.h new file mode 100644 index 0000000..6eb4494 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/versionparsing.h @@ -0,0 +1,52 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_VERSIONPARSING_H_ +#define TALK_BASE_VERSIONPARSING_H_ + +#include + +namespace talk_base { + +// Parses a version string into an array. "num_expected_segments" must be the +// number of numerical segments that the version is expected to have (e.g., +// "1.1.2.0" has 4). "version" must be an array of that length to hold the +// parsed numbers. +// Returns "true" iff successful. +bool ParseVersionString(const std::string& version_str, + int num_expected_segments, + int version[]); + +// Computes the lexicographical order of two versions. The return value +// indicates the order in the standard way (e.g., see strcmp()). +int CompareVersions(const int version1[], + const int version2[], + int num_segments); + +} // namespace talk_base + +#endif // TALK_BASE_VERSIONPARSING_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/virtualsocketserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/virtualsocketserver.h new file mode 100644 index 0000000..d01347b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/virtualsocketserver.h @@ -0,0 +1,251 @@ +/* + * 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 TALK_BASE_VIRTUALSOCKETSERVER_H_ +#define TALK_BASE_VIRTUALSOCKETSERVER_H_ + +#include + +#include +#include + +#include "talk/base/messagequeue.h" +#include "talk/base/socketserver.h" + +namespace talk_base { + +class VirtualSocket; +class SocketAddressPair; + +// Simulates a network in the same manner as a loopback interface. The +// interface can create as many addresses as you want. All of the sockets +// created by this network will be able to communicate with one another, unless +// they are bound to addresses from incompatible families. +class VirtualSocketServer : public SocketServer, public sigslot::has_slots<> { + public: + // TODO: Add "owned" parameter. + // If "owned" is set, the supplied socketserver will be deleted later. + explicit VirtualSocketServer(SocketServer* ss); + virtual ~VirtualSocketServer(); + + SocketServer* socketserver() { return server_; } + + // Limits the network bandwidth (maximum bytes per second). Zero means that + // all sends occur instantly. Defaults to 0. + uint32 bandwidth() const { return bandwidth_; } + void set_bandwidth(uint32 bandwidth) { bandwidth_ = bandwidth; } + + // Limits the amount of data which can be in flight on the network without + // packet loss (on a per sender basis). Defaults to 64 KB. + uint32 network_capacity() const { return network_capacity_; } + void set_network_capacity(uint32 capacity) { + network_capacity_ = capacity; + } + + // The amount of data which can be buffered by tcp on the sender's side + uint32 send_buffer_capacity() const { return send_buffer_capacity_; } + void set_send_buffer_capacity(uint32 capacity) { + send_buffer_capacity_ = capacity; + } + + // The amount of data which can be buffered by tcp on the receiver's side + uint32 recv_buffer_capacity() const { return recv_buffer_capacity_; } + void set_recv_buffer_capacity(uint32 capacity) { + recv_buffer_capacity_ = capacity; + } + + // Controls the (transit) delay for packets sent in the network. This does + // not inclue the time required to sit in the send queue. Both of these + // values are measured in milliseconds. Defaults to no delay. + uint32 delay_mean() const { return delay_mean_; } + uint32 delay_stddev() const { return delay_stddev_; } + uint32 delay_samples() const { return delay_samples_; } + void set_delay_mean(uint32 delay_mean) { delay_mean_ = delay_mean; } + void set_delay_stddev(uint32 delay_stddev) { + delay_stddev_ = delay_stddev; + } + void set_delay_samples(uint32 delay_samples) { + delay_samples_ = delay_samples; + } + + // If the (transit) delay parameters are modified, this method should be + // called to recompute the new distribution. + void UpdateDelayDistribution(); + + // Controls the (uniform) probability that any sent packet is dropped. This + // is separate from calculations to drop based on queue size. + double drop_probability() { return drop_prob_; } + void set_drop_probability(double drop_prob) { + assert((0 <= drop_prob) && (drop_prob <= 1)); + drop_prob_ = drop_prob; + } + + // SocketFactory: + virtual Socket* CreateSocket(int type); + virtual Socket* CreateSocket(int family, int type); + + virtual AsyncSocket* CreateAsyncSocket(int type); + virtual AsyncSocket* CreateAsyncSocket(int family, int type); + + // SocketServer: + virtual void SetMessageQueue(MessageQueue* queue); + virtual bool Wait(int cms, bool process_io); + virtual void WakeUp(); + + typedef std::pair Point; + typedef std::vector Function; + + static Function* CreateDistribution(uint32 mean, uint32 stddev, + uint32 samples); + + // Similar to Thread::ProcessMessages, but it only processes messages until + // there are no immediate messages or pending network traffic. Returns false + // if Thread::Stop() was called. + bool ProcessMessagesUntilIdle(); + + protected: + // Returns a new IP not used before in this network. + IPAddress GetNextIP(int family); + uint16 GetNextPort(); + + VirtualSocket* CreateSocketInternal(int family, int type); + + // Binds the given socket to addr, assigning and IP and Port if necessary + int Bind(VirtualSocket* socket, SocketAddress* addr); + + // Binds the given socket to the given (fully-defined) address. + int Bind(VirtualSocket* socket, const SocketAddress& addr); + + // Find the socket bound to the given address + VirtualSocket* LookupBinding(const SocketAddress& addr); + + int Unbind(const SocketAddress& addr, VirtualSocket* socket); + + // Adds a mapping between this socket pair and the socket. + void AddConnection(const SocketAddress& client, + const SocketAddress& server, + VirtualSocket* socket); + + // Find the socket pair corresponding to this server address. + VirtualSocket* LookupConnection(const SocketAddress& client, + const SocketAddress& server); + + void RemoveConnection(const SocketAddress& client, + const SocketAddress& server); + + // Connects the given socket to the socket at the given address + int Connect(VirtualSocket* socket, const SocketAddress& remote_addr, + bool use_delay); + + // Sends a disconnect message to the socket at the given address + bool Disconnect(VirtualSocket* socket); + + // Sends the given packet to the socket at the given address (if one exists). + int SendUdp(VirtualSocket* socket, const char* data, size_t data_size, + const SocketAddress& remote_addr); + + // Moves as much data as possible from the sender's buffer to the network + void SendTcp(VirtualSocket* socket); + + // Places a packet on the network. + void AddPacketToNetwork(VirtualSocket* socket, VirtualSocket* recipient, + uint32 cur_time, const char* data, size_t data_size, + size_t header_size, bool ordered); + + // Removes stale packets from the network + void PurgeNetworkPackets(VirtualSocket* socket, uint32 cur_time); + + // Computes the number of milliseconds required to send a packet of this size. + uint32 SendDelay(uint32 size); + + // Returns a random transit delay chosen from the appropriate distribution. + uint32 GetRandomTransitDelay(); + + // Basic operations on functions. Those that return a function also take + // ownership of the function given (and hence, may modify or delete it). + static Function* Accumulate(Function* f); + static Function* Invert(Function* f); + static Function* Resample(Function* f, double x1, double x2, uint32 samples); + static double Evaluate(Function* f, double x); + + // NULL out our message queue if it goes away. Necessary in the case where + // our lifetime is greater than that of the thread we are using, since we + // try to send Close messages for all connected sockets when we shutdown. + void OnMessageQueueDestroyed() { msg_queue_ = NULL; } + + // Determine if two sockets should be able to communicate. + // We don't (currently) specify an address family for sockets; instead, + // the currently bound address is used to infer the address family. + // Any socket that is not explicitly bound to an IPv4 address is assumed to be + // dual-stack capable. + // This function tests if two addresses can communicate, as well as the + // sockets to which they may be bound (the addresses may or may not yet be + // bound to the sockets). + // First the addresses are tested (after normalization): + // If both have the same family, then communication is OK. + // If only one is IPv4 then false, unless the other is bound to ::. + // This applies even if the IPv4 address is 0.0.0.0. + // The socket arguments are optional; the sockets are checked to see if they + // were explicitly bound to IPv6-any ('::'), and if so communication is + // permitted. + // NB: This scheme doesn't permit non-dualstack IPv6 sockets. + static bool CanInteractWith(VirtualSocket* local, VirtualSocket* remote); + + private: + friend class VirtualSocket; + + typedef std::map AddressMap; + typedef std::map ConnectionMap; + + SocketServer* server_; + bool server_owned_; + MessageQueue* msg_queue_; + bool stop_on_idle_; + uint32 network_delay_; + in_addr next_ipv4_; + in6_addr next_ipv6_; + uint16 next_port_; + AddressMap* bindings_; + ConnectionMap* connections_; + + uint32 bandwidth_; + uint32 network_capacity_; + uint32 send_buffer_capacity_; + uint32 recv_buffer_capacity_; + uint32 delay_mean_; + uint32 delay_stddev_; + uint32 delay_samples_; + Function* delay_dist_; + CriticalSection delay_crit_; + + double drop_prob_; + DISALLOW_EVIL_CONSTRUCTORS(VirtualSocketServer); +}; + +} // namespace talk_base + +#endif // TALK_BASE_VIRTUALSOCKETSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/win32.h b/thirdparties/common/include/webrtc-sdk/talk/base/win32.h new file mode 100644 index 0000000..515ad46 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/win32.h @@ -0,0 +1,146 @@ +/* + * 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 TALK_BASE_WIN32_H_ +#define TALK_BASE_WIN32_H_ + +#ifdef WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +// Make sure we don't get min/max macros +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#include + +#ifndef SECURITY_MANDATORY_LABEL_AUTHORITY +// Add defines that we use if we are compiling against older sdks +#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L) +#define TokenIntegrityLevel static_cast(0x19) +typedef struct _TOKEN_MANDATORY_LABEL { + SID_AND_ATTRIBUTES Label; +} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL; +#endif // SECURITY_MANDATORY_LABEL_AUTHORITY + +#undef SetPort + +#include + +#include "talk/base/stringutils.h" +#include "talk/base/basictypes.h" + +namespace talk_base { + +const char* win32_inet_ntop(int af, const void *src, char* dst, socklen_t size); +int win32_inet_pton(int af, const char* src, void *dst); + +/////////////////////////////////////////////////////////////////////////////// + +inline std::wstring ToUtf16(const char* utf8, size_t len) { + int len16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast(len), + NULL, 0); + wchar_t* ws = STACK_ARRAY(wchar_t, len16); + ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast(len), ws, len16); + return std::wstring(ws, len16); +} + +inline std::wstring ToUtf16(const std::string& str) { + return ToUtf16(str.data(), str.length()); +} + +inline std::string ToUtf8(const wchar_t* wide, size_t len) { + int len8 = ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast(len), + NULL, 0, NULL, NULL); + char* ns = STACK_ARRAY(char, len8); + ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast(len), ns, len8, + NULL, NULL); + return std::string(ns, len8); +} + +inline std::string ToUtf8(const wchar_t* wide) { + return ToUtf8(wide, wcslen(wide)); +} + +inline std::string ToUtf8(const std::wstring& wstr) { + return ToUtf8(wstr.data(), wstr.length()); +} + +// Convert FILETIME to time_t +void FileTimeToUnixTime(const FILETIME& ft, time_t* ut); + +// Convert time_t to FILETIME +void UnixTimeToFileTime(const time_t& ut, FILETIME * ft); + +// Convert a Utf8 path representation to a non-length-limited Unicode pathname. +bool Utf8ToWindowsFilename(const std::string& utf8, std::wstring* filename); + +// Convert a FILETIME to a UInt64 +inline uint64 ToUInt64(const FILETIME& ft) { + ULARGE_INTEGER r = {ft.dwLowDateTime, ft.dwHighDateTime}; + return r.QuadPart; +} + +enum WindowsMajorVersions { + kWindows2000 = 5, + kWindowsVista = 6, +}; +bool GetOsVersion(int* major, int* minor, int* build); + +inline bool IsWindowsVistaOrLater() { + int major; + return (GetOsVersion(&major, NULL, NULL) && major >= kWindowsVista); +} + +inline bool IsWindowsXpOrLater() { + int major, minor; + return (GetOsVersion(&major, &minor, NULL) && + (major >= kWindowsVista || + (major == kWindows2000 && minor >= 1))); +} + +// Determine the current integrity level of the process. +bool GetCurrentProcessIntegrityLevel(int* level); + +inline bool IsCurrentProcessLowIntegrity() { + int level; + return (GetCurrentProcessIntegrityLevel(&level) && + level < SECURITY_MANDATORY_MEDIUM_RID); +} + +bool AdjustCurrentProcessPrivilege(const TCHAR* privilege, bool to_enable); + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // WIN32 +#endif // TALK_BASE_WIN32_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/win32filesystem.h b/thirdparties/common/include/webrtc-sdk/talk/base/win32filesystem.h new file mode 100644 index 0000000..24ea081 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/win32filesystem.h @@ -0,0 +1,118 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef _TALK_BASE_WIN32FILESYSTEM_H__ +#define _TALK_BASE_WIN32FILESYSTEM_H__ + +#include "fileutils.h" + +namespace talk_base { + +class Win32Filesystem : public FilesystemInterface { + public: + // Opens a file. Returns an open StreamInterface if function succeeds. Otherwise, + // returns NULL. + virtual FileStream *OpenFile(const Pathname &filename, + const std::string &mode); + + // Atomically creates an empty file accessible only to the current user if one + // does not already exist at the given path, otherwise fails. + virtual bool CreatePrivateFile(const Pathname &filename); + + // This will attempt to delete the path located at filename. + // If the path points to a folder, it will fail with VERIFY + virtual bool DeleteFile(const Pathname &filename); + + // This will attempt to delete an empty folder. If the path does not point to + // a folder, it fails with VERIFY. If the folder is not empty, it fails normally + virtual bool DeleteEmptyFolder(const Pathname &folder); + + // Creates a directory. This will call itself recursively to create /foo/bar even if + // /foo does not exist. + // Returns TRUE if function succeeds + virtual bool CreateFolder(const Pathname &pathname); + + // This moves a file from old_path to new_path. If the new path is on a + // different volume than the old, it will attempt to copy and then delete + // the folder + // Returns true if the file is successfully moved + virtual bool MoveFile(const Pathname &old_path, const Pathname &new_path); + + // Moves a folder from old_path to new_path. If the new path is on a different + // volume from the old, it will attempt to Copy and then Delete the folder + // Returns true if the folder is successfully moved + virtual bool MoveFolder(const Pathname &old_path, const Pathname &new_path); + + // This copies a file from old_path to _new_path + // Returns true if function succeeds + virtual bool CopyFile(const Pathname &old_path, const Pathname &new_path); + + // Returns true if a pathname is a directory + virtual bool IsFolder(const Pathname& pathname); + + // Returns true if a file exists at path + virtual bool IsFile(const Pathname &path); + + // Returns true if pathname refers to no filesystem object, every parent + // directory either exists, or is also absent. + virtual bool IsAbsent(const Pathname& pathname); + + // Returns true if pathname represents a temporary location on the system. + virtual bool IsTemporaryPath(const Pathname& pathname); + + // All of the following functions set pathname and return true if successful. + // Returned paths always include a trailing backslash. + // If create is true, the path will be recursively created. + // If append is non-NULL, it will be appended (and possibly created). + + virtual std::string TempFilename(const Pathname &dir, const std::string &prefix); + + virtual bool GetFileSize(const Pathname& path, size_t* size); + virtual bool GetFileTime(const Pathname& path, FileTimeType which, + time_t* time); + + // A folder appropriate for storing temporary files (Contents are + // automatically deleted when the program exists) + virtual bool GetTemporaryFolder(Pathname &path, bool create, + const std::string *append); + + // Returns the path to the running application. + virtual bool GetAppPathname(Pathname* path); + + virtual bool GetAppDataFolder(Pathname* path, bool per_user); + + // Get a temporary folder that is unique to the current user and application. + virtual bool GetAppTempFolder(Pathname* path); + + virtual bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes); + + virtual Pathname GetCurrentDirectory(); +}; + +} // namespace talk_base + +#endif // _WIN32FILESYSTEM_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/win32regkey.h b/thirdparties/common/include/webrtc-sdk/talk/base/win32regkey.h new file mode 100644 index 0000000..f780b50 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/win32regkey.h @@ -0,0 +1,354 @@ +/* + * libjingle + * Copyright 2003-2007, 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. + */ + +// Registry configuration wrappers class +// +// Offers static functions for convenient +// fast access for individual values +// +// Also provides a wrapper class for efficient +// batch operations on values of a given registry key. +// + +#ifndef TALK_BASE_WIN32REGKEY_H_ +#define TALK_BASE_WIN32REGKEY_H_ + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/win32.h" + +namespace talk_base { + +// maximum sizes registry key and value names +const int kMaxKeyNameChars = 255 + 1; +const int kMaxValueNameChars = 16383 + 1; + +class RegKey { + public: + // constructor + RegKey(); + + // destructor + ~RegKey(); + + // create a reg key + HRESULT Create(HKEY parent_key, const wchar_t* key_name); + + HRESULT Create(HKEY parent_key, + const wchar_t* key_name, + wchar_t* reg_class, + DWORD options, + REGSAM sam_desired, + LPSECURITY_ATTRIBUTES lp_sec_attr, + LPDWORD lp_disposition); + + // open an existing reg key + HRESULT Open(HKEY parent_key, const wchar_t* key_name); + + HRESULT Open(HKEY parent_key, const wchar_t* key_name, REGSAM sam_desired); + + // close this reg key + HRESULT Close(); + + // check if the key has a specified value + bool HasValue(const wchar_t* value_name) const; + + // get the number of values for this key + uint32 GetValueCount(); + + // Called to get the value name for the given value name index + // Use GetValueCount() to get the total value_name count for this key + // Returns failure if no key at the specified index + // If you modify the key while enumerating, the indexes will be out of order. + // Since the index order is not guaranteed, you need to reset your counting + // loop. + // 'type' refers to REG_DWORD, REG_QWORD, etc.. + // 'type' can be NULL if not interested in the value type + HRESULT GetValueNameAt(int index, std::wstring* value_name, DWORD* type); + + // check if the current key has the specified subkey + bool HasSubkey(const wchar_t* key_name) const; + + // get the number of subkeys for this key + uint32 GetSubkeyCount(); + + // Called to get the key name for the given key index + // Use GetSubkeyCount() to get the total count for this key + // Returns failure if no key at the specified index + // If you modify the key while enumerating, the indexes will be out of order. + // Since the index order is not guaranteed, you need to reset your counting + // loop. + HRESULT GetSubkeyNameAt(int index, std::wstring* key_name); + + // SETTERS + + // set an int32 value - use when reading multiple values from a key + HRESULT SetValue(const wchar_t* value_name, DWORD value) const; + + // set an int64 value + HRESULT SetValue(const wchar_t* value_name, DWORD64 value) const; + + // set a string value + HRESULT SetValue(const wchar_t* value_name, const wchar_t* value) const; + + // set binary data + HRESULT SetValue(const wchar_t* value_name, + const uint8* value, + DWORD byte_count) const; + + // set raw data, including type + HRESULT SetValue(const wchar_t* value_name, + const uint8* value, + DWORD byte_count, + DWORD type) const; + + // GETTERS + + // get an int32 value + HRESULT GetValue(const wchar_t* value_name, DWORD* value) const; + + // get an int64 value + HRESULT GetValue(const wchar_t* value_name, DWORD64* value) const; + + // get a string value - the caller must free the return buffer + HRESULT GetValue(const wchar_t* value_name, wchar_t** value) const; + + // get a string value + HRESULT GetValue(const wchar_t* value_name, std::wstring* value) const; + + // get a std::vector value from REG_MULTI_SZ type + HRESULT GetValue(const wchar_t* value_name, + std::vector* value) const; + + // get binary data - the caller must free the return buffer + HRESULT GetValue(const wchar_t* value_name, + uint8** value, + DWORD* byte_count) const; + + // get raw data, including type - the caller must free the return buffer + HRESULT GetValue(const wchar_t* value_name, + uint8** value, + DWORD* byte_count, + DWORD* type) const; + + // STATIC VERSIONS + + // flush + static HRESULT FlushKey(const wchar_t* full_key_name); + + // check if a key exists + static bool HasKey(const wchar_t* full_key_name); + + // check if the key has a specified value + static bool HasValue(const wchar_t* full_key_name, const wchar_t* value_name); + + // SETTERS + + // STATIC int32 set + static HRESULT SetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + DWORD value); + + // STATIC int64 set + static HRESULT SetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + DWORD64 value); + + // STATIC float set + static HRESULT SetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + float value); + + // STATIC double set + static HRESULT SetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + double value); + + // STATIC string set + static HRESULT SetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + const wchar_t* value); + + // STATIC binary data set + static HRESULT SetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + const uint8* value, + DWORD byte_count); + + // STATIC multi-string set + static HRESULT SetValueMultiSZ(const wchar_t* full_key_name, + const TCHAR* value_name, + const uint8* value, + DWORD byte_count); + + // GETTERS + + // STATIC int32 get + static HRESULT GetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + DWORD* value); + + // STATIC int64 get + // + // Note: if you are using time64 you should + // likely use GetLimitedTimeValue (util.h) instead of this method. + static HRESULT GetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + DWORD64* value); + + // STATIC float get + static HRESULT GetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + float* value); + + // STATIC double get + static HRESULT GetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + double* value); + + // STATIC string get + // Note: the caller must free the return buffer for wchar_t* version + static HRESULT GetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + wchar_t** value); + static HRESULT GetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + std::wstring* value); + + // STATIC REG_MULTI_SZ get + static HRESULT GetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + std::vector* value); + + // STATIC get binary data - the caller must free the return buffer + static HRESULT GetValue(const wchar_t* full_key_name, + const wchar_t* value_name, + uint8** value, + DWORD* byte_count); + + // Get type of a registry value + static HRESULT GetValueType(const wchar_t* full_key_name, + const wchar_t* value_name, + DWORD* value_type); + + // delete a subkey of the current key (with no subkeys) + HRESULT DeleteSubKey(const wchar_t* key_name); + + // recursively delete a sub key of the current key (and all its subkeys) + HRESULT RecurseDeleteSubKey(const wchar_t* key_name); + + // STATIC version of delete key - handles nested keys also + // delete a key and all its sub-keys recursively + // Returns S_FALSE if key didn't exist, S_OK if deletion was successful, + // and failure otherwise. + static HRESULT DeleteKey(const wchar_t* full_key_name); + + // STATIC version of delete key + // delete a key recursively or non-recursively + // Returns S_FALSE if key didn't exist, S_OK if deletion was successful, + // and failure otherwise. + static HRESULT DeleteKey(const wchar_t* full_key_name, bool recursive); + + // delete the specified value + HRESULT DeleteValue(const wchar_t* value_name); + + // STATIC version of delete value + // Returns S_FALSE if key didn't exist, S_OK if deletion was successful, + // and failure otherwise. + static HRESULT DeleteValue(const wchar_t* full_key_name, + const wchar_t* value_name); + + // Peek inside (use a RegKey as a smart wrapper around a registry handle) + HKEY key() { return h_key_; } + + // helper function to get the HKEY and the root key from a string + // modifies the argument in place and returns the key name + // e.g. HKLM\\Software\\Google\... returns HKLM, "Software\\Google\..." + // Necessary for the static versions that use the full name of the reg key + static HKEY GetRootKeyInfo(std::wstring* full_key_name); + + // Returns true if this key name is 'safe' for deletion (doesn't specify a key + // root) + static bool SafeKeyNameForDeletion(const wchar_t* key_name); + + // save the key and all of its subkeys and values to a file + static HRESULT Save(const wchar_t* full_key_name, const wchar_t* file_name); + + // restore the key and all of its subkeys and values which are saved into a + // file + static HRESULT Restore(const wchar_t* full_key_name, + const wchar_t* file_name); + + // Is the key empty: having no sub-keys and values + static bool IsKeyEmpty(const wchar_t* full_key_name); + + private: + + // helper function to get any value from the registry + // used when the size of the data is unknown + HRESULT GetValueHelper(const wchar_t* value_name, + DWORD* type, uint8** value, + DWORD* byte_count) const; + + // helper function to get the parent key name and the subkey from a string + // modifies the argument in place and returns the key name + // Necessary for the static versions that use the full name of the reg key + static std::wstring GetParentKeyInfo(std::wstring* key_name); + + // common SET Helper for the static case + static HRESULT SetValueStaticHelper(const wchar_t* full_key_name, + const wchar_t* value_name, + DWORD type, + LPVOID value, + DWORD byte_count = 0); + + // common GET Helper for the static case + static HRESULT GetValueStaticHelper(const wchar_t* full_key_name, + const wchar_t* value_name, + DWORD type, + LPVOID value, + DWORD* byte_count = NULL); + + // convert REG_MULTI_SZ bytes to string array + static HRESULT MultiSZBytesToStringArray(const uint8* buffer, + DWORD byte_count, + std::vector* value); + + // the HKEY for the current key + HKEY h_key_; + + // for unittest + friend void RegKeyHelperFunctionsTest(); + + DISALLOW_EVIL_CONSTRUCTORS(RegKey); +}; + +} // namespace talk_base + +#endif // TALK_BASE_WIN32REGKEY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/win32socketinit.h b/thirdparties/common/include/webrtc-sdk/talk/base/win32socketinit.h new file mode 100644 index 0000000..53edb1b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/win32socketinit.h @@ -0,0 +1,37 @@ +/* + * libjingle + * Copyright 2009, 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_WIN32SOCKETINIT_H_ +#define TALK_BASE_WIN32SOCKETINIT_H_ + +namespace talk_base { + +void EnsureWinsockInit(); + +} // namespace talk_base + +#endif // TALK_BASE_WIN32SOCKETINIT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/win32socketserver.h b/thirdparties/common/include/webrtc-sdk/talk/base/win32socketserver.h new file mode 100644 index 0000000..910f959 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/win32socketserver.h @@ -0,0 +1,181 @@ +/* + * 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 TALK_BASE_WIN32SOCKETSERVER_H_ +#define TALK_BASE_WIN32SOCKETSERVER_H_ + +#ifdef WIN32 +#include "talk/base/asyncsocket.h" +#include "talk/base/criticalsection.h" +#include "talk/base/messagequeue.h" +#include "talk/base/socketserver.h" +#include "talk/base/socketfactory.h" +#include "talk/base/socket.h" +#include "talk/base/thread.h" +#include "talk/base/win32window.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// Win32Socket +/////////////////////////////////////////////////////////////////////////////// + +class Win32Socket : public AsyncSocket { + public: + Win32Socket(); + virtual ~Win32Socket(); + + bool CreateT(int family, int type); + + int Attach(SOCKET s); + void SetTimeout(int ms); + + // AsyncSocket Interface + virtual SocketAddress GetLocalAddress() const; + virtual SocketAddress GetRemoteAddress() const; + virtual int Bind(const SocketAddress& addr); + virtual int Connect(const SocketAddress& addr); + virtual int Send(const void *buffer, size_t length); + virtual int SendTo(const void *buffer, size_t length, const SocketAddress& addr); + virtual int Recv(void *buffer, size_t length); + virtual int RecvFrom(void *buffer, size_t length, SocketAddress *out_addr); + virtual int Listen(int backlog); + virtual Win32Socket *Accept(SocketAddress *out_addr); + virtual int Close(); + virtual int GetError() const; + virtual void SetError(int error); + virtual ConnState GetState() const; + virtual int EstimateMTU(uint16* mtu); + virtual int GetOption(Option opt, int* value); + virtual int SetOption(Option opt, int value); + + private: + void CreateSink(); + bool SetAsync(int events); + int DoConnect(const SocketAddress& addr); + bool HandleClosed(int close_error); + void PostClosed(); + void UpdateLastError(); + static int TranslateOption(Option opt, int* slevel, int* sopt); + + void OnSocketNotify(SOCKET socket, int event, int error); + void OnDnsNotify(HANDLE task, int error); + + SOCKET socket_; + int error_; + ConnState state_; + SocketAddress addr_; // address that we connected to (see DoConnect) + uint32 connect_time_; + bool closing_; + int close_error_; + + class EventSink; + friend class EventSink; + EventSink * sink_; + + struct DnsLookup; + DnsLookup * dns_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Win32SocketServer +/////////////////////////////////////////////////////////////////////////////// + +class Win32SocketServer : public SocketServer { + public: + explicit Win32SocketServer(MessageQueue* message_queue); + virtual ~Win32SocketServer(); + + void set_modeless_dialog(HWND hdlg) { + hdlg_ = hdlg; + } + + // SocketServer Interface + virtual Socket* CreateSocket(int type); + virtual Socket* CreateSocket(int family, int type); + + virtual AsyncSocket* CreateAsyncSocket(int type); + virtual AsyncSocket* CreateAsyncSocket(int family, int type); + + virtual void SetMessageQueue(MessageQueue* queue); + virtual bool Wait(int cms, bool process_io); + virtual void WakeUp(); + + void Pump(); + + HWND handle() { return wnd_.handle(); } + + private: + class MessageWindow : public Win32Window { + public: + explicit MessageWindow(Win32SocketServer* ss) : ss_(ss) {} + private: + virtual bool OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT& result); + Win32SocketServer* ss_; + }; + + static const TCHAR kWindowName[]; + MessageQueue *message_queue_; + MessageWindow wnd_; + CriticalSection cs_; + bool posted_; + HWND hdlg_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Win32Thread. Automatically pumps Windows messages. +/////////////////////////////////////////////////////////////////////////////// + +class Win32Thread : public Thread { + public: + Win32Thread() : ss_(this), id_(0) { + set_socketserver(&ss_); + } + virtual ~Win32Thread() { + Stop(); + set_socketserver(NULL); + } + virtual void Run() { + id_ = GetCurrentThreadId(); + Thread::Run(); + id_ = 0; + } + virtual void Quit() { + PostThreadMessage(id_, WM_QUIT, 0, 0); + } + private: + Win32SocketServer ss_; + DWORD id_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // WIN32 + +#endif // TALK_BASE_WIN32SOCKETSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/win32toolhelp.h b/thirdparties/common/include/webrtc-sdk/talk/base/win32toolhelp.h new file mode 100644 index 0000000..b532fd7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/win32toolhelp.h @@ -0,0 +1,166 @@ +// Copyright 2010 Google Inc. All Rights Reserved. + + +#ifndef TALK_BASE_WIN32TOOLHELP_H_ +#define TALK_BASE_WIN32TOOLHELP_H_ + +#ifndef WIN32 +#error WIN32 Only +#endif + +#include "talk/base/win32.h" + +// Should be included first, but that causes redefinitions. +#include + +#include "talk/base/constructormagic.h" + +namespace talk_base { + +// The toolhelp api used to enumerate processes and their modules +// on Windows is very repetetive and clunky to use. This little +// template wraps it to make it a little more programmer friendly. +// +// Traits: Traits type that adapts the enumerator to the corresponding +// win32 toolhelp api. Each traits class need to: +// - define the type of the enumerated data as a public symbol Type +// +// - implement bool First(HANDLE, T*) normally calls a +// Xxxx32First method in the toolhelp API. Ex Process32First(...) +// +// - implement bool Next(HANDLE, T*) normally calls a +// Xxxx32Next method in the toolhelp API. Ex Process32Next(...) +// +// - implement bool CloseHandle(HANDLE) +// +template +class ToolhelpEnumeratorBase { + public: + ToolhelpEnumeratorBase(HANDLE snapshot) + : snapshot_(snapshot), broken_(false), first_(true) { + + // Clear out the Traits::Type structure instance. + Zero(¤t_); + } + + virtual ~ToolhelpEnumeratorBase() { + Close(); + } + + // Moves forward to the next object using the First and Next + // pointers. If either First or Next ever indicates an failure + // all subsequent calls to this method will fail; the enumerator + // object is considered broken. + bool Next() { + if (!Valid()) { + return false; + } + + // Move the iteration forward. + current_.dwSize = sizeof(typename Traits::Type); + bool incr_ok = false; + if (first_) { + incr_ok = Traits::First(snapshot_, ¤t_); + first_ = false; + } else { + incr_ok = Traits::Next(snapshot_, ¤t_); + } + + if (!incr_ok) { + Zero(¤t_); + broken_ = true; + } + + return incr_ok; + } + + const typename Traits::Type& current() const { + return current_; + } + + void Close() { + if (snapshot_ != INVALID_HANDLE_VALUE) { + Traits::CloseHandle(snapshot_); + snapshot_ = INVALID_HANDLE_VALUE; + } + } + + private: + // Checks the state of the snapshot handle. + bool Valid() { + return snapshot_ != INVALID_HANDLE_VALUE && !broken_; + } + + static void Zero(typename Traits::Type* buff) { + ZeroMemory(buff, sizeof(typename Traits::Type)); + } + + HANDLE snapshot_; + typename Traits::Type current_; + bool broken_; + bool first_; +}; + +class ToolhelpTraits { + public: + static HANDLE CreateSnapshot(uint32 flags, uint32 process_id) { + return CreateToolhelp32Snapshot(flags, process_id); + } + + static bool CloseHandle(HANDLE handle) { + return ::CloseHandle(handle) == TRUE; + } +}; + +class ToolhelpProcessTraits : public ToolhelpTraits { + public: + typedef PROCESSENTRY32 Type; + + static bool First(HANDLE handle, Type* t) { + return ::Process32First(handle, t) == TRUE; + } + + static bool Next(HANDLE handle, Type* t) { + return ::Process32Next(handle, t) == TRUE; + } +}; + +class ProcessEnumerator : public ToolhelpEnumeratorBase { + public: + ProcessEnumerator() + : ToolhelpEnumeratorBase( + ToolhelpProcessTraits::CreateSnapshot(TH32CS_SNAPPROCESS, 0)) { + } + + private: + DISALLOW_EVIL_CONSTRUCTORS(ProcessEnumerator); +}; + +class ToolhelpModuleTraits : public ToolhelpTraits { + public: + typedef MODULEENTRY32 Type; + + static bool First(HANDLE handle, Type* t) { + return ::Module32First(handle, t) == TRUE; + } + + static bool Next(HANDLE handle, Type* t) { + return ::Module32Next(handle, t) == TRUE; + } +}; + +class ModuleEnumerator : public ToolhelpEnumeratorBase { + public: + explicit ModuleEnumerator(uint32 process_id) + : ToolhelpEnumeratorBase( + ToolhelpModuleTraits::CreateSnapshot(TH32CS_SNAPMODULE, + process_id)) { + } + + private: + DISALLOW_EVIL_CONSTRUCTORS(ModuleEnumerator); +}; + +} // namespace talk_base + +#endif // TALK_BASE_WIN32TOOLHELP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/win32window.h b/thirdparties/common/include/webrtc-sdk/talk/base/win32window.h new file mode 100644 index 0000000..d1bcc81 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/win32window.h @@ -0,0 +1,77 @@ +/* + * 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 TALK_BASE_WIN32WINDOW_H_ +#define TALK_BASE_WIN32WINDOW_H_ + +#ifdef WIN32 + +#include "talk/base/win32.h" + +namespace talk_base { + +/////////////////////////////////////////////////////////////////////////////// +// Win32Window +/////////////////////////////////////////////////////////////////////////////// + +class Win32Window { + public: + Win32Window(); + virtual ~Win32Window(); + + HWND handle() const { return wnd_; } + + bool Create(HWND parent, const wchar_t* title, DWORD style, DWORD exstyle, + int x, int y, int cx, int cy); + void Destroy(); + + // Call this when your DLL unloads. + static void Shutdown(); + + protected: + virtual bool OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, + LRESULT& result); + + virtual bool OnClose() { return true; } + virtual void OnNcDestroy() { } + + private: + static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam); + + HWND wnd_; + static HINSTANCE instance_; + static ATOM window_class_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // WIN32 + +#endif // TALK_BASE_WIN32WINDOW_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/win32windowpicker.h b/thirdparties/common/include/webrtc-sdk/talk/base/win32windowpicker.h new file mode 100644 index 0000000..db0f488 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/win32windowpicker.h @@ -0,0 +1,33 @@ +// Copyright 2010 Google Inc. All Rights Reserved + + +#ifndef TALK_BASE_WIN32WINDOWPICKER_H_ +#define TALK_BASE_WIN32WINDOWPICKER_H_ + +#include "talk/base/win32.h" +#include "talk/base/windowpicker.h" + +namespace talk_base { + +class Win32WindowPicker : public WindowPicker { + public: + Win32WindowPicker(); + virtual bool Init(); + virtual bool IsVisible(const WindowId& id); + virtual bool MoveToFront(const WindowId& id); + virtual bool GetWindowList(WindowDescriptionList* descriptions); + virtual bool GetDesktopList(DesktopDescriptionList* descriptions); + virtual bool GetDesktopDimensions(const DesktopId& id, int* width, + int* height); + + protected: + static BOOL CALLBACK EnumProc(HWND hwnd, LPARAM l_param); + static BOOL CALLBACK MonitorEnumProc(HMONITOR h_monitor, + HDC hdc_monitor, + LPRECT lprc_monitor, + LPARAM l_param); +}; + +} // namespace talk_base + +#endif // TALK_BASE_WIN32WINDOWPICKER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/window.h b/thirdparties/common/include/webrtc-sdk/talk/base/window.h new file mode 100644 index 0000000..af7039c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/window.h @@ -0,0 +1,141 @@ +/* + * 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 TALK_BASE_WINDOW_H_ +#define TALK_BASE_WINDOW_H_ + +#include "talk/base/stringencode.h" + +// Define platform specific window types. +#if defined(LINUX) +typedef unsigned long Window; // Avoid include . +#elif defined(WIN32) +// We commonly include win32.h in talk/base so just include it here. +#include "talk/base/win32.h" // Include HWND, HMONITOR. +#elif defined(OSX) +typedef unsigned int CGWindowID; +typedef unsigned int CGDirectDisplayID; +#endif + +namespace talk_base { + +class WindowId { + public: + // Define WindowT for each platform. +#if defined(LINUX) + typedef Window WindowT; +#elif defined(WIN32) + typedef HWND WindowT; +#elif defined(OSX) + typedef CGWindowID WindowT; +#else + typedef unsigned int WindowT; +#endif + + static WindowId Cast(uint64 id) { +#if defined(WIN32) + return WindowId(reinterpret_cast(id)); +#else + return WindowId(static_cast(id)); +#endif + } + + static uint64 Format(const WindowT& id) { +#if defined(WIN32) + return static_cast(reinterpret_cast(id)); +#else + return static_cast(id); +#endif + } + + WindowId() : id_(0) {} + WindowId(const WindowT& id) : id_(id) {} // NOLINT + const WindowT& id() const { return id_; } + bool IsValid() const { return id_ != 0; } + bool Equals(const WindowId& other) const { + return id_ == other.id(); + } + + private: + WindowT id_; +}; + +class DesktopId { + public: + // Define DesktopT for each platform. +#if defined(LINUX) + typedef Window DesktopT; +#elif defined(WIN32) + typedef HMONITOR DesktopT; +#elif defined(OSX) + typedef CGDirectDisplayID DesktopT; +#else + typedef unsigned int DesktopT; +#endif + + static DesktopId Cast(int id, int index) { +#if defined(WIN32) + return DesktopId(reinterpret_cast(id), index); +#else + return DesktopId(static_cast(id), index); +#endif + } + + DesktopId() : id_(0), index_(-1) {} + DesktopId(const DesktopT& id, int index) // NOLINT + : id_(id), index_(index) { + } + const DesktopT& id() const { return id_; } + int index() const { return index_; } + bool IsValid() const { return index_ != -1; } + bool Equals(const DesktopId& other) const { + return id_ == other.id() && index_ == other.index(); + } + + private: + // Id is the platform specific desktop identifier. + DesktopT id_; + // Index is the desktop index as enumerated by each platform. + // Desktop capturer typically takes the index instead of id. + int index_; +}; + +// Window event types. +enum WindowEvent { + WE_RESIZE = 0, + WE_CLOSE = 1, + WE_MINIMIZE = 2, + WE_RESTORE = 3, +}; + +inline std::string ToString(const WindowId& window) { + return ToString(window.id()); +} + +} // namespace talk_base + +#endif // TALK_BASE_WINDOW_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/windowpicker.h b/thirdparties/common/include/webrtc-sdk/talk/base/windowpicker.h new file mode 100644 index 0000000..2ff4769 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/windowpicker.h @@ -0,0 +1,78 @@ +// Copyright 2010 Google Inc. All Rights Reserved + +// thorcarpenter@google.com (Thor Carpenter) + +#ifndef TALK_BASE_WINDOWPICKER_H_ +#define TALK_BASE_WINDOWPICKER_H_ + +#include +#include + +#include "talk/base/window.h" + +namespace talk_base { + +class WindowDescription { + public: + WindowDescription() : id_() {} + WindowDescription(const WindowId& id, const std::string& title) + : id_(id), title_(title) { + } + const WindowId& id() const { return id_; } + void set_id(const WindowId& id) { id_ = id; } + const std::string& title() const { return title_; } + void set_title(const std::string& title) { title_ = title; } + + private: + WindowId id_; + std::string title_; +}; + +class DesktopDescription { + public: + DesktopDescription() : id_() {} + DesktopDescription(const DesktopId& id, const std::string& title) + : id_(id), title_(title), primary_(false) { + } + const DesktopId& id() const { return id_; } + void set_id(const DesktopId& id) { id_ = id; } + const std::string& title() const { return title_; } + void set_title(const std::string& title) { title_ = title; } + // Indicates whether it is the primary desktop in the system. + bool primary() const { return primary_; } + void set_primary(bool primary) { primary_ = primary; } + + private: + DesktopId id_; + std::string title_; + bool primary_; +}; + +typedef std::vector WindowDescriptionList; +typedef std::vector DesktopDescriptionList; + +class WindowPicker { + public: + virtual ~WindowPicker() {} + virtual bool Init() = 0; + + // TODO: Move this two methods to window.h when we no longer need to load + // CoreGraphics dynamically. + virtual bool IsVisible(const WindowId& id) = 0; + virtual bool MoveToFront(const WindowId& id) = 0; + + // Gets a list of window description and appends to descriptions. + // Returns true if successful. + virtual bool GetWindowList(WindowDescriptionList* descriptions) = 0; + // Gets a list of desktop descriptions and appends to descriptions. + // Returns true if successful. + virtual bool GetDesktopList(DesktopDescriptionList* descriptions) = 0; + // Gets the width and height of a desktop. + // Returns true if successful. + virtual bool GetDesktopDimensions(const DesktopId& id, int* width, + int* height) = 0; +}; + +} // namespace talk_base + +#endif // TALK_BASE_WINDOWPICKER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/windowpickerfactory.h b/thirdparties/common/include/webrtc-sdk/talk/base/windowpickerfactory.h new file mode 100644 index 0000000..ade5a53 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/windowpickerfactory.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#ifndef TALK_BASE_WINDOWPICKERFACTORY_H_ +#define TALK_BASE_WINDOWPICKERFACTORY_H_ + +#if defined(WIN32) +#include "talk/base/win32windowpicker.h" +#elif defined(OSX) +#include "talk/base/macutils.h" +#include "talk/base/macwindowpicker.h" +#elif defined(LINUX) +#include "talk/base/linuxwindowpicker.h" +#endif + +#include "talk/base/windowpicker.h" + +namespace talk_base { + +class WindowPickerFactory { + public: + virtual ~WindowPickerFactory() {} + + // Instance method for dependency injection. + virtual WindowPicker* Create() { + return CreateWindowPicker(); + } + + static WindowPicker* CreateWindowPicker() { +#if defined(WIN32) + return new Win32WindowPicker(); +#elif defined(OSX) + return new MacWindowPicker(); +#elif defined(LINUX) && defined(HAVE_X11) + return new LinuxWindowPicker(); +#else + return NULL; +#endif + } + + static bool IsSupported() { +#ifdef OSX + return GetOSVersionName() >= kMacOSLeopard; +#else + return true; +#endif + } +}; + +} // namespace talk_base + +#endif // TALK_BASE_WINDOWPICKERFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/winfirewall.h b/thirdparties/common/include/webrtc-sdk/talk/base/winfirewall.h new file mode 100644 index 0000000..c564c81 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/winfirewall.h @@ -0,0 +1,73 @@ +/* + * 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 TALK_BASE_WINFIREWALL_H_ +#define TALK_BASE_WINFIREWALL_H_ + +#ifndef _HRESULT_DEFINED +#define _HRESULT_DEFINED +typedef long HRESULT; // Can't forward declare typedef, but don't need all win +#endif // !_HRESULT_DEFINED + +struct INetFwMgr; +struct INetFwPolicy; +struct INetFwProfile; + +namespace talk_base { + +////////////////////////////////////////////////////////////////////// +// WinFirewall +////////////////////////////////////////////////////////////////////// + +class WinFirewall { + public: + WinFirewall(); + ~WinFirewall(); + + bool Initialize(HRESULT* result); + void Shutdown(); + + bool Enabled() const; + bool QueryAuthorized(const char* filename, bool* authorized) const; + bool QueryAuthorizedW(const wchar_t* filename, bool* authorized) const; + + bool AddApplication(const char* filename, const char* friendly_name, + bool authorized, HRESULT* result); + bool AddApplicationW(const wchar_t* filename, const wchar_t* friendly_name, + bool authorized, HRESULT* result); + + private: + INetFwMgr* mgr_; + INetFwPolicy* policy_; + INetFwProfile* profile_; +}; + +////////////////////////////////////////////////////////////////////// + +} // namespace talk_base + +#endif // TALK_BASE_WINFIREWALL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/winping.h b/thirdparties/common/include/webrtc-sdk/talk/base/winping.h new file mode 100644 index 0000000..5d1d18d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/winping.h @@ -0,0 +1,120 @@ +/* + * 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 TALK_BASE_WINPING_H__ +#define TALK_BASE_WINPING_H__ + +#ifdef WIN32 + +#include "talk/base/win32.h" +#include "talk/base/basictypes.h" +#include "talk/base/IPAddress.h" + +namespace talk_base { + +// This class wraps a Win32 API for doing ICMP pinging. This API, unlike the +// the normal socket APIs (as implemented on Win9x), will return an error if +// an ICMP packet with the dont-fragment bit set is too large. This means this +// class can be used to detect the MTU to a given address. + +typedef struct ip_option_information { + UCHAR Ttl; // Time To Live + UCHAR Tos; // Type Of Service + UCHAR Flags; // IP header flags + UCHAR OptionsSize; // Size in bytes of options data + PUCHAR OptionsData; // Pointer to options data +} IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION; + +typedef HANDLE (WINAPI *PIcmpCreateFile)(); + +typedef BOOL (WINAPI *PIcmpCloseHandle)(HANDLE icmp_handle); + +typedef HANDLE (WINAPI *PIcmp6CreateFile)(); + +typedef BOOL (WINAPI *PIcmp6CloseHandle)(HANDLE icmp_handle); + +typedef DWORD (WINAPI *PIcmpSendEcho)( + HANDLE IcmpHandle, + ULONG DestinationAddress, + LPVOID RequestData, + WORD RequestSize, + PIP_OPTION_INFORMATION RequestOptions, + LPVOID ReplyBuffer, + DWORD ReplySize, + DWORD Timeout); + +typedef DWORD (WINAPI *PIcmp6SendEcho2)( + HANDLE IcmpHandle, + HANDLE Event, + FARPROC ApcRoutine, + PVOID ApcContext, + struct sockaddr_in6 *SourceAddress, + struct sockaddr_in6 *DestinationAddress, + LPVOID RequestData, + WORD RequestSize, + PIP_OPTION_INFORMATION RequestOptions, + LPVOID ReplyBuffer, + DWORD ReplySize, + DWORD Timeout +); + +class WinPing { +public: + WinPing(); + ~WinPing(); + + // Determines whether the class was initialized correctly. + bool IsValid() { return valid_; } + + // Attempts to send a ping with the given parameters. + enum PingResult { PING_FAIL, PING_INVALID_PARAMS, + PING_TOO_LARGE, PING_TIMEOUT, PING_SUCCESS }; + PingResult Ping( + IPAddress ip, uint32 data_size, uint32 timeout_millis, uint8 ttl, + bool allow_fragments); + +private: + HMODULE dll_; + HANDLE hping_; + HANDLE hping6_; + PIcmpCreateFile create_; + PIcmpCloseHandle close_; + PIcmpSendEcho send_; + PIcmp6CreateFile create6_; + PIcmp6SendEcho2 send6_; + char* data_; + uint32 dlen_; + char* reply_; + uint32 rlen_; + bool valid_; +}; + +} // namespace talk_base + +#endif // WIN32 + +#endif // TALK_BASE_WINPING_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/base/worker.h b/thirdparties/common/include/webrtc-sdk/talk/base/worker.h new file mode 100644 index 0000000..b75e970 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/base/worker.h @@ -0,0 +1,89 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_BASE_WORKER_H_ +#define TALK_BASE_WORKER_H_ + +#include "talk/base/constructormagic.h" +#include "talk/base/messagehandler.h" + +namespace talk_base { + +class Thread; + +// A worker is an object that performs some specific long-lived task in an +// event-driven manner. +// The only method that should be considered thread-safe is HaveWork(), which +// allows you to signal the availability of work from any thread. All other +// methods are thread-hostile. Specifically: +// StartWork()/StopWork() should not be called concurrently with themselves or +// each other, and it is an error to call them while the worker is running on +// a different thread. +// The destructor may not be called if the worker is currently running +// (regardless of the thread), but you can call StopWork() in a subclass's +// destructor. +class Worker : private MessageHandler { + public: + Worker(); + + // Destroys this Worker, but it must have already been stopped via StopWork(). + virtual ~Worker(); + + // Attaches the worker to the current thread and begins processing work if not + // already doing so. + bool StartWork(); + // Stops processing work if currently doing so and detaches from the current + // thread. + bool StopWork(); + + protected: + // Signal that work is available to be done. May only be called within the + // lifetime of a OnStart()/OnStop() pair. + void HaveWork(); + + // These must be implemented by a subclass. + // Called on the worker thread to start working. + virtual void OnStart() = 0; + // Called on the worker thread when work has been signalled via HaveWork(). + virtual void OnHaveWork() = 0; + // Called on the worker thread to stop working. Upon return, any pending + // OnHaveWork() calls are cancelled. + virtual void OnStop() = 0; + + private: + // Inherited from MessageHandler. + virtual void OnMessage(Message *msg); + + // The thread that is currently doing the work. + Thread *worker_thread_; + + DISALLOW_COPY_AND_ASSIGN(Worker); +}; + +} // namespace talk_base + +#endif // TALK_BASE_WORKER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/audioframe.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/audioframe.h new file mode 100644 index 0000000..929bc6b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/audioframe.h @@ -0,0 +1,63 @@ +/* + * 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_BASE_AUDIOFRAME_H_ +#define TALK_MEDIA_BASE_AUDIOFRAME_H_ + +namespace cricket { + +class AudioFrame { + public: + AudioFrame() + : audio10ms_(NULL), + length_(0), + sampling_frequency_(8000), + stereo_(false) { + } + AudioFrame(int16* audio, size_t audio_length, int sample_freq, bool stereo) + : audio10ms_(audio), + length_(audio_length), + sampling_frequency_(sample_freq), + stereo_(stereo) { + } + + int16* GetData() { return audio10ms_; } + size_t GetSize() const { return length_; } + int GetSamplingFrequency() const { return sampling_frequency_; } + bool GetStereo() const { return stereo_; } + + private: + // TODO(janahan): currently the data is not owned by this class. + // add ownership when we come up with the first use case that requires it. + int16* audio10ms_; + size_t length_; + int sampling_frequency_; + bool stereo_; +}; + +} // namespace cricket +#endif // TALK_MEDIA_BASE_AUDIOFRAME_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/audiorenderer.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/audiorenderer.h new file mode 100644 index 0000000..6bd6251 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/audiorenderer.h @@ -0,0 +1,76 @@ +/* + * 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_MEDIA_BASE_AUDIORENDERER_H_ +#define TALK_MEDIA_BASE_AUDIORENDERER_H_ + +namespace cricket { + +// 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. + // 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. + // TODO(xians): Remove this interface after Chrome switches to the + // AudioRenderer::Sink interface. + virtual void RemoveChannel(int channel_id) {} + + protected: + virtual ~AudioRenderer() {} +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_AUDIORENDERER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/capturemanager.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/capturemanager.h new file mode 100644 index 0000000..d3a818e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/capturemanager.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +// The CaptureManager class manages VideoCapturers to make it possible to share +// the same VideoCapturers across multiple instances. E.g. if two instances of +// some class want to listen to same VideoCapturer they can't individually stop +// and start capturing as doing so will affect the other instance. +// The class employs reference counting on starting and stopping of capturing of +// frames such that if anyone is still listening it will not be stopped. The +// class also provides APIs for attaching VideoRenderers to a specific capturer +// such that the VideoRenderers are fed frames directly from the capturer. In +// addition, these frames can be altered before being sent to the capturers by +// way of VideoProcessors. +// CaptureManager is Thread-unsafe. This means that none of its APIs may be +// called concurrently. Note that callbacks are called by the VideoCapturer's +// thread which is normally a separate unmarshalled thread and thus normally +// require lock protection. + +#ifndef TALK_MEDIA_BASE_CAPTUREMANAGER_H_ +#define TALK_MEDIA_BASE_CAPTUREMANAGER_H_ + +#include +#include + +#include "talk/base/sigslotrepeater.h" +#include "talk/media/base/capturerenderadapter.h" +#include "talk/media/base/videocommon.h" + +namespace cricket { + +class VideoCapturer; +class VideoProcessor; +class VideoRenderer; +class VideoCapturerState; + +class CaptureManager : public sigslot::has_slots<> { + public: + enum RestartOptions { + kRequestRestart, + kForceRestart + }; + + CaptureManager() {} + virtual ~CaptureManager(); + + virtual bool StartVideoCapture(VideoCapturer* video_capturer, + const VideoFormat& desired_format); + virtual bool StopVideoCapture(VideoCapturer* video_capturer, + const VideoFormat& format); + + // Possibly restarts the capturer. If |options| is set to kRequestRestart, + // the CaptureManager chooses whether this request can be handled with the + // current state or if a restart is actually needed. If |options| is set to + // kForceRestart, the capturer is restarted. + virtual bool RestartVideoCapture(VideoCapturer* video_capturer, + const VideoFormat& previous_format, + const VideoFormat& desired_format, + RestartOptions options); + + virtual bool AddVideoRenderer(VideoCapturer* video_capturer, + VideoRenderer* video_renderer); + virtual bool RemoveVideoRenderer(VideoCapturer* video_capturer, + VideoRenderer* video_renderer); + + virtual bool AddVideoProcessor(VideoCapturer* video_capturer, + VideoProcessor* video_processor); + virtual bool RemoveVideoProcessor(VideoCapturer* video_capturer, + VideoProcessor* video_processor); + + sigslot::repeater2 SignalCapturerStateChange; + + private: + typedef std::map CaptureStates; + + bool IsCapturerRegistered(VideoCapturer* video_capturer) const; + bool RegisterVideoCapturer(VideoCapturer* video_capturer); + void UnregisterVideoCapturer(VideoCapturerState* capture_state); + + bool StartWithBestCaptureFormat(VideoCapturerState* capture_info, + VideoCapturer* video_capturer); + + VideoCapturerState* GetCaptureState(VideoCapturer* video_capturer) const; + CaptureRenderAdapter* GetAdapter(VideoCapturer* video_capturer) const; + + CaptureStates capture_states_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_CAPTUREMANAGER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/capturerenderadapter.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/capturerenderadapter.h new file mode 100644 index 0000000..2b4168a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/capturerenderadapter.h @@ -0,0 +1,91 @@ +/* + * 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. + */ + +// This file contains the class CaptureRenderAdapter. The class connects a +// VideoCapturer to any number of VideoRenders such that the former feeds the +// latter. +// CaptureRenderAdapter is Thread-unsafe. This means that none of its APIs may +// be called concurrently. + +#ifndef TALK_MEDIA_BASE_CAPTURERENDERADAPTER_H_ +#define TALK_MEDIA_BASE_CAPTURERENDERADAPTER_H_ + +#include + +#include "talk/base/criticalsection.h" +#include "talk/base/sigslot.h" +#include "talk/media/base/videocapturer.h" + +namespace cricket { + +class VideoCapturer; +class VideoProcessor; +class VideoRenderer; + +class CaptureRenderAdapter : public sigslot::has_slots<> { + public: + static CaptureRenderAdapter* Create(VideoCapturer* video_capturer); + ~CaptureRenderAdapter(); + + bool AddRenderer(VideoRenderer* video_renderer); + bool RemoveRenderer(VideoRenderer* video_renderer); + + VideoCapturer* video_capturer() { return video_capturer_; } + private: + struct VideoRendererInfo { + explicit VideoRendererInfo(VideoRenderer* r) + : renderer(r), + render_width(0), + render_height(0) { + } + VideoRenderer* renderer; + size_t render_width; + size_t render_height; + }; + + // Just pointers since ownership is not handed over to this class. + typedef std::vector VideoRenderers; + + explicit CaptureRenderAdapter(VideoCapturer* video_capturer); + void Init(); + + // Callback for frames received from the capturer. + void OnVideoFrame(VideoCapturer* capturer, const VideoFrame* video_frame); + + void MaybeSetRenderingSize(const VideoFrame* frame); + + bool IsRendererRegistered(const VideoRenderer& video_renderer) const; + + VideoRenderers video_renderers_; + VideoCapturer* video_capturer_; + // Critical section synchronizing the capture thread. + mutable talk_base::CriticalSection capture_crit_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_CAPTURERENDERADAPTER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/codec.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/codec.h new file mode 100644 index 0000000..c243efe --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/codec.h @@ -0,0 +1,325 @@ +/* + * 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_BASE_CODEC_H_ +#define TALK_MEDIA_BASE_CODEC_H_ + +#include +#include +#include +#include + +#include "talk/media/base/constants.h" + +namespace cricket { + +typedef std::map CodecParameterMap; + +class FeedbackParam { + public: + FeedbackParam(const std::string& id, const std::string& param) + : id_(id), + param_(param) { + } + explicit FeedbackParam(const std::string& id) + : id_(id), + param_(kParamValueEmpty) { + } + bool operator==(const FeedbackParam& other) const; + + const std::string& id() const { return id_; } + const std::string& param() const { return param_; } + + private: + std::string id_; // e.g. "nack", "ccm" + std::string param_; // e.g. "", "rpsi", "fir" +}; + +class FeedbackParams { + public: + bool operator==(const FeedbackParams& other) const; + + bool Has(const FeedbackParam& param) const; + void Add(const FeedbackParam& param); + + void Intersect(const FeedbackParams& from); + + const std::vector& params() const { return params_; } + private: + bool HasDuplicateEntries() const; + + std::vector params_; +}; + +struct Codec { + int id; + std::string name; + int clockrate; + int preference; + CodecParameterMap params; + FeedbackParams feedback_params; + + // Creates a codec with the given parameters. + Codec(int id, const std::string& name, int clockrate, int preference) + : id(id), + name(name), + clockrate(clockrate), + preference(preference) { + } + + // Creates an empty codec. + Codec() : id(0), clockrate(0), preference(0) {} + + // Indicates if this codec is compatible with the specified codec. + bool Matches(const Codec& codec) const; + + // Find the parameter for |name| and write the value to |out|. + bool GetParam(const std::string& name, std::string* out) const; + bool GetParam(const std::string& name, int* out) const; + + void SetParam(const std::string& name, const std::string& value); + void SetParam(const std::string& name, int value); + + bool HasFeedbackParam(const FeedbackParam& param) const; + void AddFeedbackParam(const FeedbackParam& param); + + static bool Preferable(const Codec& first, const Codec& other) { + return first.preference > other.preference; + } + + // Filter |this| feedbacks params such that only those shared by both |this| + // and |other| are kept. + void IntersectFeedbackParams(const Codec& other); + + Codec& operator=(const Codec& c) { + this->id = c.id; // id is reserved in objective-c + name = c.name; + clockrate = c.clockrate; + preference = c.preference; + params = c.params; + feedback_params = c.feedback_params; + return *this; + } + + bool operator==(const Codec& c) const { + return this->id == c.id && // id is reserved in objective-c + name == c.name && + clockrate == c.clockrate && + preference == c.preference && + params == c.params && + feedback_params == c.feedback_params; + } + + bool operator!=(const Codec& c) const { + return !(*this == c); + } +}; + +struct AudioCodec : public Codec { + int bitrate; + int channels; + + // Creates a codec with the given parameters. + AudioCodec(int pt, const std::string& nm, int cr, int br, int cs, int pr) + : Codec(pt, nm, cr, pr), + bitrate(br), + channels(cs) { + } + + // Creates an empty codec. + AudioCodec() : Codec(), bitrate(0), channels(0) {} + + // Indicates if this codec is compatible with the specified codec. + bool Matches(const AudioCodec& codec) const; + + static bool Preferable(const AudioCodec& first, const AudioCodec& other) { + return first.preference > other.preference; + } + + std::string ToString() const; + + AudioCodec& operator=(const AudioCodec& c) { + this->id = c.id; // id is reserved in objective-c + name = c.name; + clockrate = c.clockrate; + bitrate = c.bitrate; + channels = c.channels; + preference = c.preference; + params = c.params; + feedback_params = c.feedback_params; + return *this; + } + + bool operator==(const AudioCodec& c) const { + return this->id == c.id && // id is reserved in objective-c + name == c.name && + clockrate == c.clockrate && + bitrate == c.bitrate && + channels == c.channels && + preference == c.preference && + params == c.params && + feedback_params == c.feedback_params; + } + + bool operator!=(const AudioCodec& c) const { + return !(*this == c); + } +}; + +struct VideoCodec : public Codec { + int width; + int height; + int framerate; + + // Creates a codec with the given parameters. + VideoCodec(int pt, const std::string& nm, int w, int h, int fr, int pr) + : Codec(pt, nm, kVideoCodecClockrate, pr), + width(w), + height(h), + framerate(fr) { + } + + // Creates an empty codec. + VideoCodec() + : Codec(), + width(0), + height(0), + framerate(0) { + clockrate = kVideoCodecClockrate; + } + + static bool Preferable(const VideoCodec& first, const VideoCodec& other) { + return first.preference > other.preference; + } + + std::string ToString() const; + + VideoCodec& operator=(const VideoCodec& c) { + this->id = c.id; // id is reserved in objective-c + name = c.name; + clockrate = c.clockrate; + width = c.width; + height = c.height; + framerate = c.framerate; + preference = c.preference; + params = c.params; + feedback_params = c.feedback_params; + return *this; + } + + bool operator==(const VideoCodec& c) const { + return this->id == c.id && // id is reserved in objective-c + name == c.name && + clockrate == c.clockrate && + width == c.width && + height == c.height && + framerate == c.framerate && + preference == c.preference && + params == c.params && + feedback_params == c.feedback_params; + } + + 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 { + DataCodec(int id, const std::string& name, int preference) + : Codec(id, name, kDataCodecClockrate, preference) { + } + + DataCodec() : Codec() { + clockrate = kDataCodecClockrate; + } + + std::string ToString() const; +}; + +struct VideoEncoderConfig { + static const int kDefaultMaxThreads = -1; + static const int kDefaultCpuProfile = -1; + + VideoEncoderConfig() + : max_codec(), + num_threads(kDefaultMaxThreads), + cpu_profile(kDefaultCpuProfile) { + } + + VideoEncoderConfig(const VideoCodec& c) + : max_codec(c), + num_threads(kDefaultMaxThreads), + cpu_profile(kDefaultCpuProfile) { + } + + VideoEncoderConfig(const VideoCodec& c, int t, int p) + : max_codec(c), + num_threads(t), + cpu_profile(p) { + } + + VideoEncoderConfig& operator=(const VideoEncoderConfig& config) { + max_codec = config.max_codec; + num_threads = config.num_threads; + cpu_profile = config.cpu_profile; + return *this; + } + + bool operator==(const VideoEncoderConfig& config) const { + return max_codec == config.max_codec && + num_threads == config.num_threads && + cpu_profile == config.cpu_profile; + } + + bool operator!=(const VideoEncoderConfig& config) const { + return !(*this == config); + } + + VideoCodec max_codec; + int num_threads; + int cpu_profile; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_CODEC_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/constants.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/constants.h new file mode 100644 index 0000000..f337c3c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/constants.h @@ -0,0 +1,142 @@ +/* + * 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. + */ + +#ifndef TALK_MEDIA_BASE_CONSTANTS_H_ +#define TALK_MEDIA_BASE_CONSTANTS_H_ + +#include + +// This file contains constants related to media. + +namespace cricket { + +extern const int kVideoCodecClockrate; +extern const int kDataCodecClockrate; +extern const int kDataMaxBandwidth; // bps + +// Default CPU thresholds. +extern const float kHighSystemCpuThreshold; +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; +extern const char kCodecParamAssociatedPayloadType[]; + +extern const char kOpusCodecName[]; + +// Attribute parameters +extern const char kCodecParamPTime[]; +extern const char kCodecParamMaxPTime[]; +// fmtp parameters +extern const char kCodecParamMinPTime[]; +extern const char kCodecParamSPropStereo[]; +extern const char kCodecParamStereo[]; +extern const char kCodecParamUseInbandFec[]; +extern const char kCodecParamMaxAverageBitrate[]; +extern const char kCodecParamSctpProtocol[]; +extern const char kCodecParamSctpStreams[]; + +extern const char kParamValueTrue[]; +// Parameters are stored as parameter/value pairs. For parameters who do not +// have a value, |kParamValueEmpty| should be used as value. +extern const char kParamValueEmpty[]; + +// opus parameters. +// Default value for maxptime according to +// http://tools.ietf.org/html/draft-spittka-payload-rtp-opus-03 +extern const int kOpusDefaultMaxPTime; +extern const int kOpusDefaultPTime; +extern const int kOpusDefaultMinPTime; +extern const int kOpusDefaultSPropStereo; +extern const int kOpusDefaultStereo; +extern const int kOpusDefaultUseInbandFec; +// Prefered values in this code base. Note that they may differ from the default +// values in http://tools.ietf.org/html/draft-spittka-payload-rtp-opus-03 +// Only frames larger or equal to 10 ms are currently supported in this code +// base. +extern const int kPreferredMaxPTime; +extern const int kPreferredMinPTime; +extern const int kPreferredSPropStereo; +extern const int kPreferredStereo; +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[]; +// ccm submessages according to RFC 5104 +extern const char kRtcpFbParamCcm[]; +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[]; + +// We put the data codec names here so callers of +// DataEngine::CreateChannel don't have to import rtpdataengine.h or +// sctpdataengine.h to get the codec names they want to pass in. +extern const int kGoogleRtpDataCodecId; +extern const char kGoogleRtpDataCodecName[]; + +// TODO(pthatcher): Find an id that won't conflict with anything. On +// the other hand, it really shouldn't matter since the id won't be +// used on the wire. +extern const int kGoogleSctpDataCodecId; +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/thirdparties/common/include/webrtc-sdk/talk/media/base/cpuid.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/cpuid.h new file mode 100644 index 0000000..ad072af --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/cpuid.h @@ -0,0 +1,76 @@ +/* + * 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_MEDIA_BASE_CPUID_H_ +#define TALK_MEDIA_BASE_CPUID_H_ + +#include "talk/base/basictypes.h" // For DISALLOW_IMPLICIT_CONSTRUCTORS + +namespace cricket { + +class CpuInfo { + public: + // The following flags must match libyuv/cpu_id.h values. + // Internal flag to indicate cpuid requires initialization. + static const int kCpuInit = 0x1; + + // These flags are only valid on ARM processors. + static const int kCpuHasARM = 0x2; + static const int kCpuHasNEON = 0x4; + // 0x8 reserved for future ARM flag. + + // These flags are only valid on x86 processors. + static const int kCpuHasX86 = 0x10; + static const int kCpuHasSSE2 = 0x20; + static const int kCpuHasSSSE3 = 0x40; + static const int kCpuHasSSE41 = 0x80; + static const int kCpuHasSSE42 = 0x100; + static const int kCpuHasAVX = 0x200; + static const int kCpuHasAVX2 = 0x400; + static const int kCpuHasERMS = 0x800; + + // These flags are only valid on MIPS processors. + static const int kCpuHasMIPS = 0x1000; + static const int kCpuHasMIPS_DSP = 0x2000; + static const int kCpuHasMIPS_DSPR2 = 0x4000; + + // Detect CPU has SSE2 etc. + static bool TestCpuFlag(int flag); + + // For testing, allow CPU flags to be disabled. + static void MaskCpuFlagsForTest(int enable_flags); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(CpuInfo); +}; + +// Detect an Intel Core I5 or better such as 4th generation Macbook Air. +bool IsCoreIOrBetter(); + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_CPUID_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/cryptoparams.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/cryptoparams.h new file mode 100644 index 0000000..535891f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/cryptoparams.h @@ -0,0 +1,54 @@ +/* + * 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_BASE_CRYPTOPARAMS_H_ +#define TALK_MEDIA_BASE_CRYPTOPARAMS_H_ + +#include + +namespace cricket { + +// Parameters for SRTP negotiation, as described in RFC 4568. +struct CryptoParams { + CryptoParams() : tag(0) {} + CryptoParams(int t, const std::string& cs, + const std::string& kp, const std::string& sp) + : tag(t), cipher_suite(cs), key_params(kp), session_params(sp) {} + + bool Matches(const CryptoParams& params) const { + return (tag == params.tag && cipher_suite == params.cipher_suite); + } + + int tag; + std::string cipher_suite; + std::string key_params; + std::string session_params; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_CRYPTOPARAMS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/fakecapturemanager.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakecapturemanager.h new file mode 100644 index 0000000..b7aa173 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakecapturemanager.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef TALK_MEDIA_BASE_FAKECAPTUREMANAGER_H_ +#define TALK_MEDIA_BASE_FAKECAPTUREMANAGER_H_ + +#include "talk/media/base/capturemanager.h" + +namespace cricket { + +class FakeCaptureManager : public CaptureManager { + public: + FakeCaptureManager() {} + ~FakeCaptureManager() {} + + virtual bool AddVideoRenderer(VideoCapturer* video_capturer, + VideoRenderer* video_renderer) { + return true; + } + virtual bool RemoveVideoRenderer(VideoCapturer* video_capturer, + VideoRenderer* video_renderer) { + return true; + } +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_FAKECAPTUREMANAGER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/fakemediaengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakemediaengine.h new file mode 100644 index 0000000..54fdae7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakemediaengine.h @@ -0,0 +1,1086 @@ +/* + * 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_BASE_FAKEMEDIAENGINE_H_ +#define TALK_MEDIA_BASE_FAKEMEDIAENGINE_H_ + +#include +#include +#include +#include +#include + +#include "talk/base/buffer.h" +#include "talk/base/stringutils.h" +#include "talk/media/base/audiorenderer.h" +#include "talk/media/base/mediaengine.h" +#include "talk/media/base/rtputils.h" +#include "talk/media/base/streamparams.h" +#include "talk/p2p/base/sessiondescription.h" + +namespace cricket { + +class FakeMediaEngine; +class FakeVideoEngine; +class FakeVoiceEngine; + +// A common helper class that handles sending and receiving RTP/RTCP packets. +template class RtpHelper : public Base { + public: + RtpHelper() + : sending_(false), + playout_(false), + fail_set_send_codecs_(false), + fail_set_recv_codecs_(false), + send_ssrc_(0), + ready_to_send_(false) {} + const std::vector& recv_extensions() { + return recv_extensions_; + } + const std::vector& send_extensions() { + return send_extensions_; + } + bool sending() const { return sending_; } + bool playout() const { return playout_; } + const std::list& rtp_packets() const { return rtp_packets_; } + const std::list& rtcp_packets() const { return rtcp_packets_; } + + bool SendRtp(const void* data, int len) { + if (!sending_) { + return false; + } + talk_base::Buffer packet(data, len, kMaxRtpPacketLen); + return Base::SendPacket(&packet); + } + bool SendRtcp(const void* data, int len) { + talk_base::Buffer packet(data, len, kMaxRtpPacketLen); + return Base::SendRtcp(&packet); + } + + bool CheckRtp(const void* data, int len) { + bool success = !rtp_packets_.empty(); + if (success) { + std::string packet = rtp_packets_.front(); + rtp_packets_.pop_front(); + success = (packet == std::string(static_cast(data), len)); + } + return success; + } + bool CheckRtcp(const void* data, int len) { + bool success = !rtcp_packets_.empty(); + if (success) { + std::string packet = rtcp_packets_.front(); + rtcp_packets_.pop_front(); + success = (packet == std::string(static_cast(data), len)); + } + return success; + } + bool CheckNoRtp() { return rtp_packets_.empty(); } + bool CheckNoRtcp() { return rtcp_packets_.empty(); } + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions) { + recv_extensions_ = extensions; + return true; + } + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions) { + send_extensions_ = extensions; + return true; + } + void set_fail_set_send_codecs(bool fail) { fail_set_send_codecs_ = fail; } + void set_fail_set_recv_codecs(bool fail) { fail_set_recv_codecs_ = fail; } + virtual bool AddSendStream(const StreamParams& sp) { + if (std::find(send_streams_.begin(), send_streams_.end(), sp) != + send_streams_.end()) { + return false; + } + send_streams_.push_back(sp); + return true; + } + virtual bool RemoveSendStream(uint32 ssrc) { + return RemoveStreamBySsrc(&send_streams_, ssrc); + } + virtual bool AddRecvStream(const StreamParams& sp) { + if (std::find(receive_streams_.begin(), receive_streams_.end(), sp) != + receive_streams_.end()) { + return false; + } + receive_streams_.push_back(sp); + return true; + } + virtual bool RemoveRecvStream(uint32 ssrc) { + return RemoveStreamBySsrc(&receive_streams_, ssrc); + } + virtual bool MuteStream(uint32 ssrc, bool on) { + if (!HasSendStream(ssrc) && ssrc != 0) + return false; + if (on) + muted_streams_.insert(ssrc); + else + muted_streams_.erase(ssrc); + return true; + } + bool IsStreamMuted(uint32 ssrc) const { + bool ret = muted_streams_.find(ssrc) != muted_streams_.end(); + // If |ssrc = 0| check if the first send stream is muted. + if (!ret && ssrc == 0 && !send_streams_.empty()) { + return muted_streams_.find(send_streams_[0].first_ssrc()) != + muted_streams_.end(); + } + return ret; + } + const std::vector& send_streams() const { + return send_streams_; + } + const std::vector& recv_streams() const { + return receive_streams_; + } + bool HasRecvStream(uint32 ssrc) const { + return GetStreamBySsrc(receive_streams_, ssrc, NULL); + } + bool HasSendStream(uint32 ssrc) const { + return GetStreamBySsrc(send_streams_, ssrc, NULL); + } + // TODO(perkj): This is to support legacy unit test that only check one + // sending stream. + const uint32 send_ssrc() { + if (send_streams_.empty()) + return 0; + return send_streams_[0].first_ssrc(); + } + + // TODO(perkj): This is to support legacy unit test that only check one + // sending stream. + const std::string rtcp_cname() { + if (send_streams_.empty()) + return ""; + return send_streams_[0].cname; + } + + bool ready_to_send() const { + return ready_to_send_; + } + + protected: + bool set_sending(bool send) { + sending_ = send; + return true; + } + void set_playout(bool playout) { playout_ = playout; } + virtual void OnPacketReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time) { + rtp_packets_.push_back(std::string(packet->data(), packet->length())); + } + virtual void OnRtcpReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time) { + rtcp_packets_.push_back(std::string(packet->data(), packet->length())); + } + virtual void OnReadyToSend(bool ready) { + ready_to_send_ = ready; + } + bool fail_set_send_codecs() const { return fail_set_send_codecs_; } + bool fail_set_recv_codecs() const { return fail_set_recv_codecs_; } + + private: + bool sending_; + bool playout_; + std::vector recv_extensions_; + std::vector send_extensions_; + std::list rtp_packets_; + std::list rtcp_packets_; + std::vector send_streams_; + std::vector receive_streams_; + std::set muted_streams_; + bool fail_set_send_codecs_; + bool fail_set_recv_codecs_; + uint32 send_ssrc_; + std::string rtcp_cname_; + bool ready_to_send_; +}; + +class FakeVoiceMediaChannel : public RtpHelper { + public: + struct DtmfInfo { + DtmfInfo(uint32 ssrc, int event_code, int duration, int flags) + : ssrc(ssrc), event_code(event_code), duration(duration), flags(flags) { + } + uint32 ssrc; + int event_code; + int duration; + int flags; + }; + explicit FakeVoiceMediaChannel(FakeVoiceEngine* engine) + : engine_(engine), + fail_set_send_(false), + ringback_tone_ssrc_(0), + ringback_tone_play_(false), + ringback_tone_loop_(false), + time_since_last_typing_(-1) { + output_scalings_[0] = OutputScaling(); // For default channel. + } + ~FakeVoiceMediaChannel(); + const std::vector& recv_codecs() const { return recv_codecs_; } + const std::vector& send_codecs() const { return send_codecs_; } + const std::vector& codecs() const { return send_codecs(); } + const std::vector& dtmf_info_queue() const { + return dtmf_info_queue_; + } + const AudioOptions& options() const { return options_; } + + uint32 ringback_tone_ssrc() const { return ringback_tone_ssrc_; } + bool ringback_tone_play() const { return ringback_tone_play_; } + bool ringback_tone_loop() const { return ringback_tone_loop_; } + + virtual bool SetRecvCodecs(const std::vector& codecs) { + if (fail_set_recv_codecs()) { + // Fake the failure in SetRecvCodecs. + return false; + } + recv_codecs_ = codecs; + return true; + } + virtual bool SetSendCodecs(const std::vector& codecs) { + if (fail_set_send_codecs()) { + // Fake the failure in SetSendCodecs. + return false; + } + send_codecs_ = codecs; + return true; + } + virtual bool SetPlayout(bool playout) { + set_playout(playout); + return true; + } + virtual bool SetSend(SendFlags flag) { + if (fail_set_send_) { + return false; + } + return set_sending(flag != SEND_NOTHING); + } + virtual bool SetStartSendBandwidth(int bps) { return true; } + virtual bool SetMaxSendBandwidth(int bps) { return true; } + virtual bool AddRecvStream(const StreamParams& sp) { + if (!RtpHelper::AddRecvStream(sp)) + return false; + output_scalings_[sp.first_ssrc()] = OutputScaling(); + return true; + } + virtual bool RemoveRecvStream(uint32 ssrc) { + if (!RtpHelper::RemoveRecvStream(ssrc)) + return false; + output_scalings_.erase(ssrc); + return true; + } + virtual bool SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer) { + std::map::iterator it = + remote_renderers_.find(ssrc); + if (renderer) { + if (it != remote_renderers_.end()) { + ASSERT(it->second == renderer); + } else { + remote_renderers_.insert(std::make_pair(ssrc, renderer)); + renderer->AddChannel(0); + } + } else { + if (it != remote_renderers_.end()) { + it->second->RemoveChannel(0); + remote_renderers_.erase(it); + } else { + return false; + } + } + return true; + } + virtual bool SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer) { + std::map::iterator it = + local_renderers_.find(ssrc); + if (renderer) { + if (it != local_renderers_.end()) { + ASSERT(it->second->renderer() == renderer); + } else { + local_renderers_.insert(std::make_pair( + ssrc, new VoiceChannelAudioSink(renderer))); + } + } else { + if (it != local_renderers_.end()) { + delete it->second; + local_renderers_.erase(it); + } else { + return false; + } + } + return true; + } + + virtual bool GetActiveStreams(AudioInfo::StreamList* streams) { return true; } + virtual int GetOutputLevel() { return 0; } + void set_time_since_last_typing(int ms) { time_since_last_typing_ = ms; } + virtual int GetTimeSinceLastTyping() { return time_since_last_typing_; } + virtual void SetTypingDetectionParameters( + int time_window, int cost_per_typing, int reporting_threshold, + int penalty_decay, int type_event_delay) {} + + virtual bool SetRingbackTone(const char* buf, int len) { return true; } + virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop) { + ringback_tone_ssrc_ = ssrc; + ringback_tone_play_ = play; + ringback_tone_loop_ = loop; + return true; + } + + virtual bool CanInsertDtmf() { + for (std::vector::const_iterator it = send_codecs_.begin(); + it != send_codecs_.end(); ++it) { + // Find the DTMF telephone event "codec". + if (_stricmp(it->name.c_str(), "telephone-event") == 0) { + return true; + } + } + return false; + } + virtual bool InsertDtmf(uint32 ssrc, int event_code, int duration, + int flags) { + dtmf_info_queue_.push_back(DtmfInfo(ssrc, event_code, duration, flags)); + return true; + } + + virtual bool SetOutputScaling(uint32 ssrc, double left, double right) { + if (0 == ssrc) { + std::map::iterator it; + for (it = output_scalings_.begin(); it != output_scalings_.end(); ++it) { + it->second.left = left; + it->second.right = right; + } + return true; + } else if (output_scalings_.find(ssrc) != output_scalings_.end()) { + output_scalings_[ssrc].left = left; + output_scalings_[ssrc].right = right; + return true; + } + return false; + } + virtual bool GetOutputScaling(uint32 ssrc, double* left, double* right) { + if (output_scalings_.find(ssrc) == output_scalings_.end()) + return false; + *left = output_scalings_[ssrc].left; + *right = output_scalings_[ssrc].right; + return true; + } + + virtual bool GetStats(VoiceMediaInfo* info) { return false; } + virtual void GetLastMediaError(uint32* ssrc, + VoiceMediaChannel::Error* error) { + *ssrc = 0; + *error = fail_set_send_ ? VoiceMediaChannel::ERROR_REC_DEVICE_OPEN_FAILED + : VoiceMediaChannel::ERROR_NONE; + } + + void set_fail_set_send(bool fail) { fail_set_send_ = fail; } + void TriggerError(uint32 ssrc, VoiceMediaChannel::Error error) { + VoiceMediaChannel::SignalMediaError(ssrc, error); + } + + virtual bool SetOptions(const AudioOptions& options) { + // Does a "merge" of current options and set options. + options_.SetAll(options); + return true; + } + virtual bool GetOptions(AudioOptions* options) const { + *options = options_; + return true; + } + + private: + struct OutputScaling { + OutputScaling() : left(1.0), right(1.0) {} + 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 recv_codecs_; + std::vector send_codecs_; + std::map output_scalings_; + std::vector dtmf_info_queue_; + bool fail_set_send_; + uint32 ringback_tone_ssrc_; + bool ringback_tone_play_; + bool ringback_tone_loop_; + int time_since_last_typing_; + AudioOptions options_; + std::map local_renderers_; + std::map remote_renderers_; +}; + +// A helper function to compare the FakeVoiceMediaChannel::DtmfInfo. +inline bool CompareDtmfInfo(const FakeVoiceMediaChannel::DtmfInfo& info, + uint32 ssrc, int event_code, int duration, + int flags) { + return (info.duration == duration && info.event_code == event_code && + info.flags == flags && info.ssrc == ssrc); +} + +class FakeVideoMediaChannel : public RtpHelper { + public: + explicit FakeVideoMediaChannel(FakeVideoEngine* engine) + : engine_(engine), + sent_intra_frame_(false), + requested_intra_frame_(false), + start_bps_(-1), + max_bps_(-1) {} + ~FakeVideoMediaChannel(); + + const std::vector& recv_codecs() const { return recv_codecs_; } + const std::vector& send_codecs() const { return send_codecs_; } + const std::vector& codecs() const { return send_codecs(); } + bool rendering() const { return playout(); } + const VideoOptions& options() const { return options_; } + const std::map& 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; + } + *format = send_formats_[ssrc]; + return true; + } + virtual bool SetSendStreamFormat(uint32 ssrc, const VideoFormat& format) { + if (send_formats_.find(ssrc) == send_formats_.end()) { + return false; + } + send_formats_[ssrc] = format; + return true; + } + + virtual bool AddSendStream(const StreamParams& sp) { + if (!RtpHelper::AddSendStream(sp)) { + return false; + } + SetSendStreamDefaultFormat(sp.first_ssrc()); + return true; + } + virtual bool RemoveSendStream(uint32 ssrc) { + send_formats_.erase(ssrc); + return RtpHelper::RemoveSendStream(ssrc); + } + + virtual bool SetRecvCodecs(const std::vector& codecs) { + if (fail_set_recv_codecs()) { + // Fake the failure in SetRecvCodecs. + return false; + } + recv_codecs_ = codecs; + return true; + } + virtual bool SetSendCodecs(const std::vector& codecs) { + if (fail_set_send_codecs()) { + // Fake the failure in SetSendCodecs. + return false; + } + send_codecs_ = codecs; + + for (std::vector::const_iterator it = send_streams().begin(); + it != send_streams().end(); ++it) { + SetSendStreamDefaultFormat(it->first_ssrc()); + } + return true; + } + virtual bool GetSendCodec(VideoCodec* send_codec) { + if (send_codecs_.empty()) { + return false; + } + *send_codec = send_codecs_[0]; + return true; + } + virtual bool SetRender(bool render) { + set_playout(render); + return true; + } + virtual bool SetRenderer(uint32 ssrc, VideoRenderer* r) { + if (ssrc != 0 && renderers_.find(ssrc) == renderers_.end()) { + return false; + } + if (ssrc != 0) { + renderers_[ssrc] = r; + } + return true; + } + + virtual bool SetSend(bool send) { return set_sending(send); } + virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer) { + capturers_[ssrc] = capturer; + return true; + } + bool HasCapturer(uint32 ssrc) const { + return capturers_.find(ssrc) != capturers_.end(); + } + 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::AddRecvStream(sp)) + return false; + renderers_[sp.first_ssrc()] = NULL; + return true; + } + virtual bool RemoveRecvStream(uint32 ssrc) { + if (!RtpHelper::RemoveRecvStream(ssrc)) + return false; + renderers_.erase(ssrc); + return true; + } + + virtual bool GetStats(const StatsOptions& options, + VideoMediaInfo* info) { return false; } + virtual bool SendIntraFrame() { + sent_intra_frame_ = true; + return true; + } + virtual bool RequestIntraFrame() { + requested_intra_frame_ = true; + return true; + } + virtual bool SetOptions(const VideoOptions& options) { + options_ = options; + return true; + } + virtual bool GetOptions(VideoOptions* options) const { + *options = options_; + return true; + } + virtual void UpdateAspectRatio(int ratio_w, int ratio_h) {} + void set_sent_intra_frame(bool v) { sent_intra_frame_ = v; } + bool sent_intra_frame() const { return sent_intra_frame_; } + void set_requested_intra_frame(bool v) { requested_intra_frame_ = v; } + bool requested_intra_frame() const { return requested_intra_frame_; } + + private: + // Be default, each send stream uses the first send codec format. + void SetSendStreamDefaultFormat(uint32 ssrc) { + if (!send_codecs_.empty()) { + send_formats_[ssrc] = VideoFormat( + send_codecs_[0].width, send_codecs_[0].height, + cricket::VideoFormat::FpsToInterval(send_codecs_[0].framerate), + cricket::FOURCC_I420); + } + } + + FakeVideoEngine* engine_; + std::vector recv_codecs_; + std::vector send_codecs_; + std::map renderers_; + std::map send_formats_; + std::map capturers_; + bool sent_intra_frame_; + bool requested_intra_frame_; + VideoOptions options_; + int start_bps_; + int max_bps_; +}; + +class FakeSoundclipMedia : public SoundclipMedia { + public: + virtual bool PlaySound(const char* buf, int len, int flags) { return true; } +}; + +class FakeDataMediaChannel : public RtpHelper { + public: + explicit FakeDataMediaChannel(void* unused) + : send_blocked_(false), max_bps_(-1) {} + ~FakeDataMediaChannel() {} + const std::vector& recv_codecs() const { return recv_codecs_; } + const std::vector& send_codecs() const { return send_codecs_; } + const std::vector& codecs() const { return send_codecs(); } + int max_bps() const { return max_bps_; } + + virtual bool SetRecvCodecs(const std::vector& codecs) { + if (fail_set_recv_codecs()) { + // Fake the failure in SetRecvCodecs. + return false; + } + recv_codecs_ = codecs; + return true; + } + virtual bool SetSendCodecs(const std::vector& codecs) { + if (fail_set_send_codecs()) { + // Fake the failure in SetSendCodecs. + return false; + } + send_codecs_ = codecs; + return true; + } + virtual bool SetSend(bool send) { return set_sending(send); } + virtual bool SetReceive(bool receive) { + set_playout(receive); + return true; + } + virtual bool SetStartSendBandwidth(int bps) { return true; } + virtual bool SetMaxSendBandwidth(int bps) { + max_bps_ = bps; + return true; + } + virtual bool AddRecvStream(const StreamParams& sp) { + if (!RtpHelper::AddRecvStream(sp)) + return false; + return true; + } + virtual bool RemoveRecvStream(uint32 ssrc) { + if (!RtpHelper::RemoveRecvStream(ssrc)) + return false; + return true; + } + + virtual bool SendData(const SendDataParams& params, + const talk_base::Buffer& payload, + SendDataResult* result) { + if (send_blocked_) { + *result = SDR_BLOCK; + return false; + } else { + last_sent_data_params_ = params; + last_sent_data_ = std::string(payload.data(), payload.length()); + return true; + } + } + + SendDataParams last_sent_data_params() { return last_sent_data_params_; } + std::string last_sent_data() { return last_sent_data_; } + bool is_send_blocked() { return send_blocked_; } + void set_send_blocked(bool blocked) { send_blocked_ = blocked; } + + private: + std::vector recv_codecs_; + std::vector send_codecs_; + SendDataParams last_sent_data_params_; + std::string last_sent_data_; + bool send_blocked_; + int max_bps_; +}; + +// A base class for all of the shared parts between FakeVoiceEngine +// and FakeVideoEngine. +class FakeBaseEngine { + public: + FakeBaseEngine() + : loglevel_(-1), + options_changed_(false), + fail_create_channel_(false) {} + bool Init(talk_base::Thread* worker_thread) { return true; } + void Terminate() {} + + void SetLogging(int level, const char* filter) { + loglevel_ = level; + logfilter_ = filter; + } + + void set_fail_create_channel(bool fail) { fail_create_channel_ = fail; } + + const std::vector& rtp_header_extensions() const { + return rtp_header_extensions_; + } + void set_rtp_header_extensions( + const std::vector& extensions) { + rtp_header_extensions_ = extensions; + } + + protected: + int loglevel_; + std::string logfilter_; + // Flag used by optionsmessagehandler_unittest for checking whether any + // relevant setting has been updated. + // TODO(thaloun): Replace with explicit checks of before & after values. + bool options_changed_; + bool fail_create_channel_; + std::vector rtp_header_extensions_; +}; + +class FakeVoiceEngine : public FakeBaseEngine { + public: + FakeVoiceEngine() + : output_volume_(-1), + delay_offset_(0), + rx_processor_(NULL), + tx_processor_(NULL) { + // Add a fake audio codec. Note that the name must not be "" as there are + // sanity checks against that. + codecs_.push_back(AudioCodec(101, "fake_audio_codec", 0, 0, 1, 0)); + } + int GetCapabilities() { return AUDIO_SEND | AUDIO_RECV; } + AudioOptions GetAudioOptions() const { + return options_; + } + AudioOptions GetOptions() const { + return options_; + } + bool SetOptions(const AudioOptions& options) { + options_ = options; + options_changed_ = true; + return true; + } + + VoiceMediaChannel* CreateChannel() { + if (fail_create_channel_) { + return NULL; + } + + FakeVoiceMediaChannel* ch = new FakeVoiceMediaChannel(this); + channels_.push_back(ch); + return ch; + } + FakeVoiceMediaChannel* GetChannel(size_t index) { + return (channels_.size() > index) ? channels_[index] : NULL; + } + void UnregisterChannel(VoiceMediaChannel* channel) { + channels_.erase(std::find(channels_.begin(), channels_.end(), channel)); + } + SoundclipMedia* CreateSoundclip() { return new FakeSoundclipMedia(); } + + const std::vector& codecs() { return codecs_; } + void SetCodecs(const std::vector codecs) { codecs_ = codecs; } + + bool SetDelayOffset(int offset) { + delay_offset_ = offset; + return true; + } + + bool SetDevices(const Device* in_device, const Device* out_device) { + in_device_ = (in_device) ? in_device->name : ""; + out_device_ = (out_device) ? out_device->name : ""; + options_changed_ = true; + return true; + } + + bool GetOutputVolume(int* level) { + *level = output_volume_; + return true; + } + + bool SetOutputVolume(int level) { + output_volume_ = level; + options_changed_ = true; + return true; + } + + int GetInputLevel() { return 0; } + + 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) { + rx_processor_ = voice_processor; + return true; + } else if (direction == MPD_TX) { + tx_processor_ = voice_processor; + return true; + } + return false; + } + + bool UnregisterProcessor(uint32 ssrc, VoiceProcessor* voice_processor, + MediaProcessorDirection direction) { + bool unregistered = false; + if (direction & MPD_RX) { + rx_processor_ = NULL; + unregistered = true; + } + if (direction & MPD_TX) { + tx_processor_ = NULL; + unregistered = true; + } + return unregistered; + } + + private: + std::vector channels_; + std::vector codecs_; + int output_volume_; + int delay_offset_; + std::string in_device_; + std::string out_device_; + VoiceProcessor* rx_processor_; + VoiceProcessor* tx_processor_; + AudioOptions options_; + + friend class FakeMediaEngine; +}; + +class FakeVideoEngine : public FakeBaseEngine { + public: + FakeVideoEngine() : renderer_(NULL), capture_(false), processor_(NULL) { + // Add a fake video codec. Note that the name must not be "" as there are + // sanity checks against that. + codecs_.push_back(VideoCodec(0, "fake_video_codec", 0, 0, 0, 0)); + } + bool GetOptions(VideoOptions* options) const { + *options = options_; + return true; + } + bool SetOptions(const VideoOptions& options) { + options_ = options; + options_changed_ = true; + return true; + } + int GetCapabilities() { return VIDEO_SEND | VIDEO_RECV; } + bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) { + default_encoder_config_ = config; + return true; + } + VideoEncoderConfig GetDefaultEncoderConfig() const { + return default_encoder_config_; + } + const VideoEncoderConfig& default_encoder_config() const { + return default_encoder_config_; + } + + VideoMediaChannel* CreateChannel(VoiceMediaChannel* channel) { + if (fail_create_channel_) { + return NULL; + } + + FakeVideoMediaChannel* ch = new FakeVideoMediaChannel(this); + channels_.push_back(ch); + return ch; + } + FakeVideoMediaChannel* GetChannel(size_t index) { + return (channels_.size() > index) ? channels_[index] : NULL; + } + void UnregisterChannel(VideoMediaChannel* channel) { + channels_.erase(std::find(channels_.begin(), channels_.end(), channel)); + } + + const std::vector& codecs() const { return codecs_; } + bool FindCodec(const VideoCodec& in) { + for (size_t i = 0; i < codecs_.size(); ++i) { + if (codecs_[i].Matches(in)) { + return true; + } + } + return false; + } + void SetCodecs(const std::vector codecs) { codecs_ = codecs; } + + bool SetCaptureDevice(const Device* device) { + in_device_ = (device) ? device->name : ""; + options_changed_ = true; + return true; + } + bool SetLocalRenderer(VideoRenderer* r) { + renderer_ = r; + return true; + } + bool SetCapture(bool capture) { + capture_ = capture; + return true; + } + VideoFormat GetStartCaptureFormat() const { + return VideoFormat(640, 480, cricket::VideoFormat::FpsToInterval(30), + FOURCC_I420); + } + + sigslot::repeater2 SignalCaptureStateChange; + + private: + std::vector channels_; + std::vector codecs_; + VideoEncoderConfig default_encoder_config_; + std::string in_device_; + VideoRenderer* renderer_; + bool capture_; + VideoProcessor* processor_; + VideoOptions options_; + + friend class FakeMediaEngine; +}; + +class FakeMediaEngine : + public CompositeMediaEngine { + public: + FakeMediaEngine() { + voice_ = FakeVoiceEngine(); + video_ = FakeVideoEngine(); + } + virtual ~FakeMediaEngine() {} + + void SetAudioCodecs(const std::vector& codecs) { + voice_.SetCodecs(codecs); + } + void SetVideoCodecs(const std::vector& codecs) { + video_.SetCodecs(codecs); + } + + void SetAudioRtpHeaderExtensions( + const std::vector& extensions) { + voice_.set_rtp_header_extensions(extensions); + } + void SetVideoRtpHeaderExtensions( + const std::vector& 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); + } + + AudioOptions audio_options() const { return voice_.options_; } + int audio_delay_offset() const { return voice_.delay_offset_; } + int output_volume() const { return voice_.output_volume_; } + const VideoEncoderConfig& default_video_encoder_config() const { + return video_.default_encoder_config_; + } + const std::string& audio_in_device() const { return voice_.in_device_; } + const std::string& audio_out_device() const { return voice_.out_device_; } + VideoRenderer* local_renderer() { return video_.renderer_; } + int voice_loglevel() const { return voice_.loglevel_; } + const std::string& voice_logfilter() const { return voice_.logfilter_; } + int video_loglevel() const { return video_.loglevel_; } + const std::string& video_logfilter() const { return video_.logfilter_; } + bool capture() const { return video_.capture_; } + bool options_changed() const { + return voice_.options_changed_ || video_.options_changed_; + } + void clear_options_changed() { + video_.options_changed_ = false; + voice_.options_changed_ = false; + } + void set_fail_create_channel(bool fail) { + voice_.set_fail_create_channel(fail); + video_.set_fail_create_channel(fail); + } + bool voice_processor_registered(MediaProcessorDirection direction) const { + if (direction == MPD_RX) { + return voice_.rx_processor_ != NULL; + } else if (direction == MPD_TX) { + return voice_.tx_processor_ != NULL; + } + return false; + } +}; + +// CompositeMediaEngine with FakeVoiceEngine to expose SetAudioCodecs to +// establish a media connectionwith minimum set of audio codes required +template +class CompositeMediaEngineWithFakeVoiceEngine : + public CompositeMediaEngine { + public: + CompositeMediaEngineWithFakeVoiceEngine() {} + virtual ~CompositeMediaEngineWithFakeVoiceEngine() {} + + virtual void SetAudioCodecs(const std::vector& codecs) { + CompositeMediaEngine::voice_.SetCodecs(codecs); + } +}; + +// Have to come afterwards due to declaration order +inline FakeVoiceMediaChannel::~FakeVoiceMediaChannel() { + if (engine_) { + engine_->UnregisterChannel(this); + } +} + +inline FakeVideoMediaChannel::~FakeVideoMediaChannel() { + if (engine_) { + engine_->UnregisterChannel(this); + } +} + +class FakeDataEngine : public DataEngineInterface { + public: + FakeDataEngine() : last_channel_type_(DCT_NONE) {} + + virtual DataMediaChannel* CreateChannel(DataChannelType data_channel_type) { + last_channel_type_ = data_channel_type; + FakeDataMediaChannel* ch = new FakeDataMediaChannel(this); + channels_.push_back(ch); + return ch; + } + + FakeDataMediaChannel* GetChannel(size_t index) { + return (channels_.size() > index) ? channels_[index] : NULL; + } + + void UnregisterChannel(DataMediaChannel* channel) { + channels_.erase(std::find(channels_.begin(), channels_.end(), channel)); + } + + virtual void SetDataCodecs(const std::vector& data_codecs) { + data_codecs_ = data_codecs; + } + + virtual const std::vector& data_codecs() { return data_codecs_; } + + DataChannelType last_channel_type() const { return last_channel_type_; } + + private: + std::vector channels_; + std::vector data_codecs_; + DataChannelType last_channel_type_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_FAKEMEDIAENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/fakemediaprocessor.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakemediaprocessor.h new file mode 100644 index 0000000..f600e80 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakemediaprocessor.h @@ -0,0 +1,79 @@ +/* + * 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_BASE_FAKEMEDIAPROCESSOR_H_ +#define TALK_MEDIA_BASE_FAKEMEDIAPROCESSOR_H_ + +#include "talk/media/base/videoprocessor.h" +#include "talk/media/base/voiceprocessor.h" + +namespace cricket { + +class AudioFrame; + +class FakeMediaProcessor : public VoiceProcessor, public VideoProcessor { + public: + FakeMediaProcessor() + : voice_frame_count_(0), + video_frame_count_(0), + drop_frames_(false), + dropped_frame_count_(0) { + } + virtual ~FakeMediaProcessor() {} + + virtual void OnFrame(uint32 ssrc, + MediaProcessorDirection direction, + AudioFrame* frame) { + ++voice_frame_count_; + } + virtual void OnFrame(uint32 ssrc, VideoFrame* frame_ptr, bool* drop_frame) { + ++video_frame_count_; + if (drop_frames_) { + *drop_frame = true; + ++dropped_frame_count_; + } + } + virtual void OnVoiceMute(uint32 ssrc, bool muted) {} + virtual void OnVideoMute(uint32 ssrc, bool muted) {} + + int voice_frame_count() const { return voice_frame_count_; } + int video_frame_count() const { return video_frame_count_; } + + void set_drop_frames(bool b) { drop_frames_ = b; } + int dropped_frame_count() const { return dropped_frame_count_; } + + private: + // TODO(janahan): make is a map so that we can multiple ssrcs + int voice_frame_count_; + int video_frame_count_; + bool drop_frames_; + int dropped_frame_count_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_FAKEMEDIAPROCESSOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/fakenetworkinterface.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakenetworkinterface.h new file mode 100644 index 0000000..d284a1d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakenetworkinterface.h @@ -0,0 +1,259 @@ +/* + * 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_BASE_FAKENETWORKINTERFACE_H_ +#define TALK_MEDIA_BASE_FAKENETWORKINTERFACE_H_ + +#include +#include + +#include "talk/base/buffer.h" +#include "talk/base/byteorder.h" +#include "talk/base/criticalsection.h" +#include "talk/base/dscp.h" +#include "talk/base/messagehandler.h" +#include "talk/base/messagequeue.h" +#include "talk/base/thread.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/rtputils.h" + +namespace cricket { + +// Fake NetworkInterface that sends/receives RTP/RTCP packets. +class FakeNetworkInterface : public MediaChannel::NetworkInterface, + public talk_base::MessageHandler { + public: + FakeNetworkInterface() + : thread_(talk_base::Thread::Current()), + dest_(NULL), + conf_(false), + sendbuf_size_(-1), + recvbuf_size_(-1), + dscp_(talk_base::DSCP_NO_CHANGE) { + } + + void SetDestination(MediaChannel* dest) { dest_ = dest; } + + // Conference mode is a mode where instead of simply forwarding the packets, + // the transport will send multiple copies of the packet with the specified + // SSRCs. This allows us to simulate receiving media from multiple sources. + void SetConferenceMode(bool conf, const std::vector& ssrcs) { + talk_base::CritScope cs(&crit_); + conf_ = conf; + conf_sent_ssrcs_ = ssrcs; + } + + int NumRtpBytes() { + talk_base::CritScope cs(&crit_); + int bytes = 0; + for (size_t i = 0; i < rtp_packets_.size(); ++i) { + bytes += static_cast(rtp_packets_[i].length()); + } + return bytes; + } + + int NumRtpBytes(uint32 ssrc) { + talk_base::CritScope cs(&crit_); + int bytes = 0; + GetNumRtpBytesAndPackets(ssrc, &bytes, NULL); + return bytes; + } + + int NumRtpPackets() { + talk_base::CritScope cs(&crit_); + return static_cast(rtp_packets_.size()); + } + + int NumRtpPackets(uint32 ssrc) { + talk_base::CritScope cs(&crit_); + int packets = 0; + GetNumRtpBytesAndPackets(ssrc, NULL, &packets); + return packets; + } + + int NumSentSsrcs() { + talk_base::CritScope cs(&crit_); + return static_cast(sent_ssrcs_.size()); + } + + // Note: callers are responsible for deleting the returned buffer. + const talk_base::Buffer* GetRtpPacket(int index) { + talk_base::CritScope cs(&crit_); + if (index >= NumRtpPackets()) { + return NULL; + } + return new talk_base::Buffer(rtp_packets_[index]); + } + + int NumRtcpPackets() { + talk_base::CritScope cs(&crit_); + return static_cast(rtcp_packets_.size()); + } + + // Note: callers are responsible for deleting the returned buffer. + const talk_base::Buffer* GetRtcpPacket(int index) { + talk_base::CritScope cs(&crit_); + if (index >= NumRtcpPackets()) { + return NULL; + } + return new talk_base::Buffer(rtcp_packets_[index]); + } + + // Indicate that |n|'th packet for |ssrc| should be dropped. + void AddPacketDrop(uint32 ssrc, uint32 n) { + drop_map_[ssrc].insert(n); + } + + int sendbuf_size() const { return sendbuf_size_; } + int recvbuf_size() const { return recvbuf_size_; } + talk_base::DiffServCodePoint dscp() const { return dscp_; } + + protected: + virtual bool SendPacket(talk_base::Buffer* packet, + talk_base::DiffServCodePoint dscp) { + talk_base::CritScope cs(&crit_); + + uint32 cur_ssrc = 0; + if (!GetRtpSsrc(packet->data(), packet->length(), &cur_ssrc)) { + return false; + } + sent_ssrcs_[cur_ssrc]++; + + // Check if we need to drop this packet. + std::map >::iterator itr = + drop_map_.find(cur_ssrc); + if (itr != drop_map_.end() && + itr->second.count(sent_ssrcs_[cur_ssrc]) > 0) { + // "Drop" the packet. + return true; + } + + rtp_packets_.push_back(*packet); + if (conf_) { + talk_base::Buffer buffer_copy(*packet); + for (size_t i = 0; i < conf_sent_ssrcs_.size(); ++i) { + if (!SetRtpSsrc(buffer_copy.data(), buffer_copy.length(), + conf_sent_ssrcs_[i])) { + return false; + } + PostMessage(ST_RTP, buffer_copy); + } + } else { + PostMessage(ST_RTP, *packet); + } + return true; + } + + virtual bool SendRtcp(talk_base::Buffer* packet, + talk_base::DiffServCodePoint dscp) { + talk_base::CritScope cs(&crit_); + rtcp_packets_.push_back(*packet); + if (!conf_) { + // don't worry about RTCP in conf mode for now + PostMessage(ST_RTCP, *packet); + } + return true; + } + + virtual int SetOption(SocketType type, talk_base::Socket::Option opt, + int option) { + if (opt == talk_base::Socket::OPT_SNDBUF) { + sendbuf_size_ = option; + } else if (opt == talk_base::Socket::OPT_RCVBUF) { + recvbuf_size_ = option; + } else if (opt == talk_base::Socket::OPT_DSCP) { + dscp_ = static_cast(option); + } + return 0; + } + + void PostMessage(int id, const talk_base::Buffer& packet) { + thread_->Post(this, id, talk_base::WrapMessageData(packet)); + } + + virtual void OnMessage(talk_base::Message* msg) { + talk_base::TypedMessageData* msg_data = + static_cast*>( + msg->pdata); + if (dest_) { + if (msg->message_id == ST_RTP) { + dest_->OnPacketReceived(&msg_data->data(), + talk_base::CreatePacketTime(0)); + } else { + dest_->OnRtcpReceived(&msg_data->data(), + talk_base::CreatePacketTime(0)); + } + } + delete msg_data; + } + + private: + void GetNumRtpBytesAndPackets(uint32 ssrc, int* bytes, int* packets) { + if (bytes) { + *bytes = 0; + } + if (packets) { + *packets = 0; + } + uint32 cur_ssrc = 0; + for (size_t i = 0; i < rtp_packets_.size(); ++i) { + if (!GetRtpSsrc(rtp_packets_[i].data(), + rtp_packets_[i].length(), &cur_ssrc)) { + return; + } + if (ssrc == cur_ssrc) { + if (bytes) { + *bytes += static_cast(rtp_packets_[i].length()); + } + if (packets) { + ++(*packets); + } + } + } + } + + talk_base::Thread* thread_; + MediaChannel* dest_; + bool conf_; + // The ssrcs used in sending out packets in conference mode. + std::vector conf_sent_ssrcs_; + // Map to track counts of packets that have been sent per ssrc. + // This includes packets that are dropped. + std::map sent_ssrcs_; + // Map to track packet-number that needs to be dropped per ssrc. + std::map > drop_map_; + talk_base::CriticalSection crit_; + std::vector rtp_packets_; + std::vector rtcp_packets_; + int sendbuf_size_; + int recvbuf_size_; + talk_base::DiffServCodePoint dscp_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_FAKENETWORKINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/fakertp.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakertp.h new file mode 100644 index 0000000..ae3ffbd --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakertp.h @@ -0,0 +1,104 @@ +/* + * 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. + */ + +// Fake RTP and RTCP packets to use in unit tests. + +#ifndef TALK_MEDIA_BASE_FAKERTP_H_ +#define TALK_MEDIA_BASE_FAKERTP_H_ + +// A typical PCMU RTP packet. +// PT=0, SN=1, TS=0, SSRC=1 +// all data FF +static const unsigned char kPcmuFrame[] = { + 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +// A typical Receiver Report RTCP packet. +// PT=RR, LN=1, SSRC=1 +// send SSRC=2, all other fields 0 +static const unsigned char kRtcpReport[] = { + 0x80, 0xc9, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// PT = 97, TS = 0, Seq = 1, SSRC = 2 +// H264 - NRI = 1, Type = 1, bit stream = FF + +static const unsigned char kH264Packet[] = { + 0x80, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x21, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +// PT= 101, SN=2, TS=3, SSRC = 4 +static const unsigned char kDataPacket[] = { + 0x80, 0x65, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, +}; + +#endif // TALK_MEDIA_BASE_FAKERTP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/fakevideocapturer.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakevideocapturer.h new file mode 100644 index 0000000..e035a7e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakevideocapturer.h @@ -0,0 +1,154 @@ +/* + * 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_BASE_FAKEVIDEOCAPTURER_H_ +#define TALK_MEDIA_BASE_FAKEVIDEOCAPTURER_H_ + +#include + +#include + +#include "talk/base/timeutils.h" +#include "talk/media/base/videocapturer.h" +#include "talk/media/base/videocommon.h" +#include "talk/media/base/videoframe.h" + +namespace cricket { + +// Fake video capturer that allows the test to manually pump in frames. +class FakeVideoCapturer : public cricket::VideoCapturer { + public: + FakeVideoCapturer() + : running_(false), + initial_unix_timestamp_(time(NULL) * talk_base::kNumNanosecsPerSec), + next_timestamp_(talk_base::kNumNanosecsPerMillisec), + is_screencast_(false) { + // Default supported formats. Use ResetSupportedFormats to over write. + std::vector formats; + formats.push_back(cricket::VideoFormat(1280, 720, + cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); + formats.push_back(cricket::VideoFormat(640, 480, + cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); + formats.push_back(cricket::VideoFormat(320, 240, + cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); + formats.push_back(cricket::VideoFormat(160, 120, + cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); + ResetSupportedFormats(formats); + } + ~FakeVideoCapturer() { + SignalDestroyed(this); + } + + void ResetSupportedFormats(const std::vector& formats) { + SetSupportedFormats(formats); + } + bool CaptureFrame() { + if (!GetCaptureFormat()) { + return false; + } + return CaptureCustomFrame(GetCaptureFormat()->width, + GetCaptureFormat()->height, + GetCaptureFormat()->fourcc); + } + bool CaptureCustomFrame(int width, int height, uint32 fourcc) { + if (!running_) { + return false; + } + // Currently, |fourcc| is always I420 or ARGB. + // TODO(fbarchard): Extend SizeOf to take fourcc. + uint32 size = 0u; + if (fourcc == cricket::FOURCC_ARGB) { + size = width * 4 * height; + } else if (fourcc == cricket::FOURCC_I420) { + size = static_cast(cricket::VideoFrame::SizeOf(width, height)); + } else { + return false; // Unsupported FOURCC. + } + if (size == 0u) { + return false; // Width and/or Height were zero. + } + + cricket::CapturedFrame frame; + frame.width = width; + frame.height = height; + frame.fourcc = fourcc; + frame.data_size = size; + frame.elapsed_time = next_timestamp_; + frame.time_stamp = initial_unix_timestamp_ + next_timestamp_; + next_timestamp_ += 33333333; // 30 fps + + talk_base::scoped_ptr data(new char[size]); + frame.data = data.get(); + // Copy something non-zero into the buffer so Validate wont complain that + // the frame is all duplicate. + memset(frame.data, 1, size / 2); + memset(reinterpret_cast(frame.data) + (size / 2), 2, + size - (size / 2)); + memcpy(frame.data, reinterpret_cast(&fourcc), 4); + // TODO(zhurunz): SignalFrameCaptured carry returned value to be able to + // capture results from downstream. + SignalFrameCaptured(this, &frame); + return true; + } + + sigslot::signal1 SignalDestroyed; + + virtual cricket::CaptureState Start(const cricket::VideoFormat& format) { + cricket::VideoFormat supported; + if (GetBestCaptureFormat(format, &supported)) { + SetCaptureFormat(&supported); + } + running_ = true; + SetCaptureState(cricket::CS_RUNNING); + return cricket::CS_RUNNING; + } + virtual void Stop() { + running_ = false; + SetCaptureFormat(NULL); + SetCaptureState(cricket::CS_STOPPED); + } + virtual bool IsRunning() { return running_; } + void SetScreencast(bool is_screencast) { + is_screencast_ = is_screencast; + } + virtual bool IsScreencast() const { return is_screencast_; } + bool GetPreferredFourccs(std::vector* fourccs) { + fourccs->push_back(cricket::FOURCC_I420); + fourccs->push_back(cricket::FOURCC_MJPG); + return true; + } + + private: + bool running_; + int64 initial_unix_timestamp_; + int64 next_timestamp_; + bool is_screencast_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_FAKEVIDEOCAPTURER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/fakevideorenderer.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakevideorenderer.h new file mode 100644 index 0000000..619de46 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/fakevideorenderer.h @@ -0,0 +1,168 @@ +/* + * 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_MEDIA_BASE_FAKEVIDEORENDERER_H_ +#define TALK_MEDIA_BASE_FAKEVIDEORENDERER_H_ + +#include "talk/base/logging.h" +#include "talk/base/sigslot.h" +#include "talk/media/base/videoframe.h" +#include "talk/media/base/videorenderer.h" + +namespace cricket { + +// Faked video renderer that has a callback for actions on rendering. +class FakeVideoRenderer : public VideoRenderer { + public: + FakeVideoRenderer() + : errors_(0), + width_(0), + height_(0), + num_set_sizes_(0), + num_rendered_frames_(0), + black_frame_(false) { + } + + virtual bool SetSize(int width, int height, int reserved) { + talk_base::CritScope cs(&crit_); + width_ = width; + height_ = height; + ++num_set_sizes_; + SignalSetSize(width, height, reserved); + return true; + } + + 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); + // Treat unexpected frame size as error. + if (!frame || + frame->GetWidth() != static_cast(width_) || + frame->GetHeight() != static_cast(height_)) { + if (!frame) { + LOG(LS_WARNING) << "RenderFrame expected non-null frame."; + } else { + LOG(LS_WARNING) << "RenderFrame expected frame of size " << width_ + << "x" << height_ << " but received frame of size " + << frame->GetWidth() << "x" << frame->GetHeight(); + } + ++errors_; + return false; + } + ++num_rendered_frames_; + SignalRenderFrame(frame); + return true; + } + + int errors() const { return errors_; } + 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 SignalSetSize; + sigslot::signal1 SignalRenderFrame; + + private: + static bool CheckFrameColorYuv(uint8 y_min, uint8 y_max, + uint8 u_min, uint8 u_max, + uint8 v_min, uint8 v_max, + const cricket::VideoFrame* frame) { + if (!frame) { + return false; + } + // Y + size_t y_width = frame->GetWidth(); + size_t y_height = frame->GetHeight(); + const uint8* y_plane = frame->GetYPlane(); + const uint8* y_pos = y_plane; + int32 y_pitch = frame->GetYPitch(); + for (size_t i = 0; i < y_height; ++i) { + for (size_t j = 0; j < y_width; ++j) { + uint8 y_value = *(y_pos + j); + if (y_value < y_min || y_value > y_max) { + return false; + } + } + y_pos += y_pitch; + } + // U and V + size_t chroma_width = frame->GetChromaWidth(); + size_t chroma_height = frame->GetChromaHeight(); + const uint8* u_plane = frame->GetUPlane(); + const uint8* v_plane = frame->GetVPlane(); + const uint8* u_pos = u_plane; + const uint8* v_pos = v_plane; + int32 u_pitch = frame->GetUPitch(); + int32 v_pitch = frame->GetVPitch(); + for (size_t i = 0; i < chroma_height; ++i) { + for (size_t j = 0; j < chroma_width; ++j) { + uint8 u_value = *(u_pos + j); + if (u_value < u_min || u_value > u_max) { + return false; + } + uint8 v_value = *(v_pos + j); + if (v_value < v_min || v_value > v_max) { + return false; + } + } + u_pos += u_pitch; + v_pos += v_pitch; + } + return true; + } + + int errors_; + int width_; + int height_; + int num_set_sizes_; + int num_rendered_frames_; + bool black_frame_; + mutable talk_base::CriticalSection crit_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_FAKEVIDEORENDERER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/filemediaengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/filemediaengine.h new file mode 100644 index 0000000..e8a65f9 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/filemediaengine.h @@ -0,0 +1,339 @@ +// 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_BASE_FILEMEDIAENGINE_H_ +#define TALK_MEDIA_BASE_FILEMEDIAENGINE_H_ + +#include +#include + +#include "talk/base/scoped_ptr.h" +#include "talk/base/stream.h" +#include "talk/media/base/codec.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/mediaengine.h" + +namespace talk_base { +class StreamInterface; +} + +namespace cricket { + +// A media engine contains a capturer, an encoder, and a sender in the sender +// side and a receiver, a decoder, and a renderer in the receiver side. +// FileMediaEngine simulates the capturer and the encoder via an input RTP dump +// stream and simulates the decoder and the renderer via an output RTP dump +// stream. Depending on the parameters of the constructor, FileMediaEngine can +// act as file voice engine, file video engine, or both. Currently, we use +// only the RTP dump packets. TODO(whyuan): Enable RTCP packets. +class FileMediaEngine : public MediaEngineInterface { + public: + FileMediaEngine() : rtp_sender_thread_(NULL) {} + virtual ~FileMediaEngine() {} + + // Set the file name of the input or output RTP dump for voice or video. + // Should be called before the channel is created. + void set_voice_input_filename(const std::string& filename) { + voice_input_filename_ = filename; + } + void set_voice_output_filename(const std::string& filename) { + voice_output_filename_ = filename; + } + void set_video_input_filename(const std::string& filename) { + video_input_filename_ = filename; + } + void set_video_output_filename(const std::string& filename) { + video_output_filename_ = filename; + } + + // Should be called before codecs() and video_codecs() are called. We need to + // set the voice and video codecs; otherwise, Jingle initiation will fail. + void set_voice_codecs(const std::vector& codecs) { + voice_codecs_ = codecs; + } + void set_video_codecs(const std::vector& codecs) { + video_codecs_ = codecs; + } + + // Implement pure virtual methods of MediaEngine. + virtual bool Init(talk_base::Thread* worker_thread) { + return true; + } + virtual void Terminate() {} + virtual int GetCapabilities(); + virtual VoiceMediaChannel* CreateChannel(); + virtual VideoMediaChannel* CreateVideoChannel(VoiceMediaChannel* voice_ch); + virtual SoundclipMedia* CreateSoundclip() { return NULL; } + virtual AudioOptions GetAudioOptions() const { return AudioOptions(); } + virtual bool SetAudioOptions(const AudioOptions& options) { return true; } + virtual bool SetVideoOptions(const VideoOptions& options) { return true; } + virtual bool SetAudioDelayOffset(int offset) { return true; } + virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) { + return true; + } + virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const { + return VideoEncoderConfig(); + } + virtual bool SetSoundDevices(const Device* in_dev, const Device* out_dev) { + return true; + } + virtual bool SetVideoCaptureDevice(const Device* cam_device) { return true; } + virtual bool SetVideoCapturer(VideoCapturer* /*capturer*/) { + return true; + } + virtual VideoCapturer* GetVideoCapturer() const { + return NULL; + } + virtual bool GetOutputVolume(int* level) { + *level = 0; + return true; + } + virtual bool SetOutputVolume(int level) { return true; } + virtual int GetInputLevel() { return 0; } + virtual bool SetLocalMonitor(bool enable) { return true; } + virtual bool SetLocalRenderer(VideoRenderer* renderer) { return true; } + // TODO(whyuan): control channel send? + virtual bool SetVideoCapture(bool capture) { return true; } + virtual const std::vector& audio_codecs() { + return voice_codecs_; + } + virtual const std::vector& video_codecs() { + return video_codecs_; + } + virtual const std::vector& audio_rtp_header_extensions() { + return audio_rtp_header_extensions_; + } + virtual const std::vector& video_rtp_header_extensions() { + return video_rtp_header_extensions_; + } + + virtual bool FindAudioCodec(const AudioCodec& codec) { return true; } + 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; + } + virtual bool UnregisterVideoProcessor(VideoProcessor* processor) { + return true; + } + virtual bool RegisterVoiceProcessor(uint32 ssrc, + VoiceProcessor* processor, + MediaProcessorDirection direction) { + return true; + } + virtual bool UnregisterVoiceProcessor(uint32 ssrc, + VoiceProcessor* processor, + MediaProcessorDirection direction) { + return true; + } + VideoFormat GetStartCaptureFormat() const { + return VideoFormat(); + } + + virtual sigslot::repeater2& + SignalVideoCaptureStateChange() { + return signal_state_change_; + } + + void set_rtp_sender_thread(talk_base::Thread* thread) { + rtp_sender_thread_ = thread; + } + + private: + std::string voice_input_filename_; + std::string voice_output_filename_; + std::string video_input_filename_; + std::string video_output_filename_; + std::vector voice_codecs_; + std::vector video_codecs_; + std::vector audio_rtp_header_extensions_; + std::vector video_rtp_header_extensions_; + sigslot::repeater2 + signal_state_change_; + talk_base::Thread* rtp_sender_thread_; + + DISALLOW_COPY_AND_ASSIGN(FileMediaEngine); +}; + +class RtpSenderReceiver; // Forward declaration. Defined in the .cc file. + +class FileVoiceChannel : public VoiceMediaChannel { + public: + FileVoiceChannel(talk_base::StreamInterface* input_file_stream, + talk_base::StreamInterface* output_file_stream, + talk_base::Thread* rtp_sender_thread); + virtual ~FileVoiceChannel(); + + // Implement pure virtual methods of VoiceMediaChannel. + virtual bool SetRecvCodecs(const std::vector& codecs) { + return true; + } + virtual bool SetSendCodecs(const std::vector& codecs); + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions) { + return true; + } + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions) { + return true; + } + virtual bool SetPlayout(bool playout) { return true; } + virtual bool SetSend(SendFlags flag); + virtual bool SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer) { + return false; + } + virtual bool SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer) { + return false; + } + virtual bool GetActiveStreams(AudioInfo::StreamList* actives) { return true; } + virtual int GetOutputLevel() { return 0; } + virtual int GetTimeSinceLastTyping() { return -1; } + virtual void SetTypingDetectionParameters(int time_window, + int cost_per_typing, int reporting_threshold, int penalty_decay, + int type_event_delay) {} + + virtual bool SetOutputScaling(uint32 ssrc, double left, double right) { + return false; + } + virtual bool GetOutputScaling(uint32 ssrc, double* left, double* right) { + return false; + } + virtual bool SetRingbackTone(const char* buf, int len) { return true; } + virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop) { + return true; + } + virtual bool InsertDtmf(uint32 ssrc, int event, int duration, int flags) { + return false; + } + virtual bool GetStats(VoiceMediaInfo* info) { return true; } + + // Implement pure virtual methods of MediaChannel. + virtual void OnPacketReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + virtual void OnRtcpReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time) {} + virtual void OnReadyToSend(bool ready) {} + virtual bool AddSendStream(const StreamParams& sp); + virtual bool RemoveSendStream(uint32 ssrc); + 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 SetStartSendBandwidth(int bps) { return true; } + virtual bool SetMaxSendBandwidth(int bps) { return true; } + virtual bool SetOptions(const AudioOptions& options) { + options_ = options; + return true; + } + virtual bool GetOptions(AudioOptions* options) const { + *options = options_; + return true; + } + + private: + uint32 send_ssrc_; + talk_base::scoped_ptr rtp_sender_receiver_; + AudioOptions options_; + + DISALLOW_COPY_AND_ASSIGN(FileVoiceChannel); +}; + +class FileVideoChannel : public VideoMediaChannel { + public: + FileVideoChannel(talk_base::StreamInterface* input_file_stream, + talk_base::StreamInterface* output_file_stream, + talk_base::Thread* rtp_sender_thread); + virtual ~FileVideoChannel(); + + // Implement pure virtual methods of VideoMediaChannel. + virtual bool SetRecvCodecs(const std::vector& codecs) { + return true; + } + virtual bool SetSendCodecs(const std::vector& codecs); + virtual bool GetSendCodec(VideoCodec* send_codec) { + *send_codec = VideoCodec(); + return true; + } + virtual bool SetSendStreamFormat(uint32 ssrc, const VideoFormat& format) { + return true; + } + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions) { + return true; + } + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions) { + return true; + } + virtual bool SetRender(bool render) { return true; } + virtual bool SetSend(bool send); + virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer) { + return true; + } + virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer) { + return false; + } + virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info) { + return true; + } + virtual bool SendIntraFrame() { return false; } + virtual bool RequestIntraFrame() { return false; } + + // Implement pure virtual methods of MediaChannel. + virtual void OnPacketReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + virtual void OnRtcpReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time) {} + virtual void OnReadyToSend(bool ready) {} + virtual bool AddSendStream(const StreamParams& sp); + virtual bool RemoveSendStream(uint32 ssrc); + 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 SetStartSendBandwidth(int bps) { return true; } + virtual bool SetMaxSendBandwidth(int bps) { return true; } + virtual bool SetOptions(const VideoOptions& options) { + options_ = options; + return true; + } + virtual bool GetOptions(VideoOptions* options) const { + *options = options_; + return true; + } + virtual void UpdateAspectRatio(int ratio_w, int ratio_h) {} + + private: + uint32 send_ssrc_; + talk_base::scoped_ptr rtp_sender_receiver_; + VideoOptions options_; + + DISALLOW_COPY_AND_ASSIGN(FileVideoChannel); +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_FILEMEDIAENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/hybriddataengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/hybriddataengine.h new file mode 100644 index 0000000..c18da67 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/hybriddataengine.h @@ -0,0 +1,76 @@ +/* + * libjingle + * Copyright 2012 Google Inc, and Robin Seggelmann + * + * 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_SCTP_HYBRIDDATAENGINE_H_ +#define TALK_MEDIA_SCTP_HYBRIDDATAENGINE_H_ + +#include +#include + +#include "talk/base/scoped_ptr.h" +#include "talk/media/base/codec.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/mediaengine.h" + +namespace cricket { + +class HybridDataEngine : public DataEngineInterface { + public: + // Takes ownership. + HybridDataEngine(DataEngineInterface* first, + DataEngineInterface* second) + : first_(first), + second_(second) { + codecs_ = first_->data_codecs(); + codecs_.insert( + codecs_.end(), + second_->data_codecs().begin(), + second_->data_codecs().end()); + } + + virtual DataMediaChannel* CreateChannel(DataChannelType data_channel_type) { + DataMediaChannel* channel = NULL; + if (first_) { + channel = first_->CreateChannel(data_channel_type); + } + if (!channel && second_) { + channel = second_->CreateChannel(data_channel_type); + } + return channel; + } + + virtual const std::vector& data_codecs() { return codecs_; } + + private: + talk_base::scoped_ptr first_; + talk_base::scoped_ptr second_; + std::vector codecs_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_SCTP_HYBRIDDATAENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/hybridvideoengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/hybridvideoengine.h new file mode 100644 index 0000000..3f9164d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/hybridvideoengine.h @@ -0,0 +1,286 @@ +/* + * 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_BASE_HYBRIDVIDEOENGINE_H_ +#define TALK_MEDIA_BASE_HYBRIDVIDEOENGINE_H_ + +#include +#include + +#include "talk/base/logging.h" +#include "talk/base/sigslotrepeater.h" +#include "talk/media/base/codec.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/videocapturer.h" +#include "talk/media/base/videocommon.h" + +namespace cricket { + +struct Device; +struct VideoFormat; +class HybridVideoEngineInterface; +class VideoCapturer; +class VideoFrame; +class VideoRenderer; + +// HybridVideoMediaChannels work with a HybridVideoEngine to combine +// two unrelated VideoMediaChannel implementations into a single class. +class HybridVideoMediaChannel : public VideoMediaChannel { + public: + HybridVideoMediaChannel(HybridVideoEngineInterface* engine, + VideoMediaChannel* channel1, + VideoMediaChannel* channel2); + virtual ~HybridVideoMediaChannel(); + + // VideoMediaChannel methods + virtual void SetInterface(NetworkInterface* iface); + virtual bool SetOptions(const VideoOptions& options); + virtual bool GetOptions(VideoOptions* options) const; + virtual bool AddSendStream(const StreamParams& sp); + virtual bool RemoveSendStream(uint32 ssrc); + virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer); + virtual bool SetRender(bool render); + virtual bool MuteStream(uint32 ssrc, bool muted); + + virtual bool SetRecvCodecs(const std::vector& codecs); + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions); + + virtual bool SetSendCodecs(const std::vector& codecs); + virtual bool GetSendCodec(VideoCodec* codec); + virtual bool SetSendStreamFormat(uint32 ssrc, const VideoFormat& format); + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions); + virtual bool SetStartSendBandwidth(int bps); + virtual bool SetMaxSendBandwidth(int bps); + virtual bool SetSend(bool send); + + virtual bool AddRecvStream(const StreamParams& sp); + virtual bool RemoveRecvStream(uint32 ssrc); + virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer); + + virtual bool SendIntraFrame(); + virtual bool RequestIntraFrame(); + + virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info); + + virtual void OnPacketReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + virtual void OnRtcpReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + virtual void OnReadyToSend(bool ready); + + virtual void UpdateAspectRatio(int ratio_w, int ratio_h); + + void OnLocalFrame(VideoCapturer*, const VideoFrame*); + void OnLocalFrameFormat(VideoCapturer*, const VideoFormat*); + + bool sending() const { return sending_; } + + private: + bool SelectActiveChannel(const std::vector& codecs); + void SplitCodecs(const std::vector& codecs, + std::vector* codecs1, + std::vector* codecs2); + + void OnMediaError(uint32 ssrc, Error error); + + HybridVideoEngineInterface* engine_; + talk_base::scoped_ptr channel1_; + talk_base::scoped_ptr channel2_; + VideoMediaChannel* active_channel_; + bool sending_; +}; + +// Interface class for HybridVideoChannels to talk to the engine. +class HybridVideoEngineInterface { + public: + virtual ~HybridVideoEngineInterface() {} + virtual bool HasCodec1(const VideoCodec& codec) = 0; + virtual bool HasCodec2(const VideoCodec& codec) = 0; + virtual void OnSendChange1(VideoMediaChannel* channel1, bool send) = 0; + virtual void OnSendChange2(VideoMediaChannel* channel1, bool send) = 0; + virtual void OnNewSendResolution(int width, int height) = 0; +}; + +// The HybridVideoEngine class combines two unrelated VideoEngine impls +// into a single class. It creates HybridVideoMediaChannels that also contain +// a VideoMediaChannel implementation from each engine. Policy is then used +// during call setup to determine which VideoMediaChannel should be used. +// Currently, this policy is based on what codec the remote side wants to use. +template +class HybridVideoEngine : public HybridVideoEngineInterface { + public: + HybridVideoEngine() { + // Unify the codec lists. + codecs_ = video1_.codecs(); + codecs_.insert(codecs_.end(), video2_.codecs().begin(), + video2_.codecs().end()); + + rtp_header_extensions_ = video1_.rtp_header_extensions(); + rtp_header_extensions_.insert(rtp_header_extensions_.end(), + video2_.rtp_header_extensions().begin(), + video2_.rtp_header_extensions().end()); + + SignalCaptureStateChange.repeat(video2_.SignalCaptureStateChange); + } + + bool Init(talk_base::Thread* worker_thread) { + if (!video1_.Init(worker_thread)) { + LOG(LS_ERROR) << "Failed to init VideoEngine1"; + return false; + } + if (!video2_.Init(worker_thread)) { + LOG(LS_ERROR) << "Failed to init VideoEngine2"; + video1_.Terminate(); + return false; + } + return true; + } + void Terminate() { + video1_.Terminate(); + video2_.Terminate(); + } + + int GetCapabilities() { + return (video1_.GetCapabilities() | video2_.GetCapabilities()); + } + HybridVideoMediaChannel* CreateChannel(VoiceMediaChannel* channel) { + talk_base::scoped_ptr channel1( + video1_.CreateChannel(channel)); + if (!channel1) { + LOG(LS_ERROR) << "Failed to create VideoMediaChannel1"; + return NULL; + } + talk_base::scoped_ptr channel2( + video2_.CreateChannel(channel)); + if (!channel2) { + LOG(LS_ERROR) << "Failed to create VideoMediaChannel2"; + return NULL; + } + return new HybridVideoMediaChannel(this, + channel1.release(), channel2.release()); + } + + bool SetOptions(const VideoOptions& options) { + return video1_.SetOptions(options) && video2_.SetOptions(options); + } + bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) { + VideoEncoderConfig conf = config; + if (video1_.codecs().size() > 0) { + conf.max_codec.name = video1_.codecs()[0].name; + if (!video1_.SetDefaultEncoderConfig(conf)) { + LOG(LS_ERROR) << "Failed to SetDefaultEncoderConfig for video1"; + return false; + } + } + if (video2_.codecs().size() > 0) { + conf.max_codec.name = video2_.codecs()[0].name; + if (!video2_.SetDefaultEncoderConfig(conf)) { + LOG(LS_ERROR) << "Failed to SetDefaultEncoderConfig for video2"; + return false; + } + } + return true; + } + VideoEncoderConfig GetDefaultEncoderConfig() const { + // This looks pretty strange, but, in practice, it'll do sane things if + // GetDefaultEncoderConfig is only called after SetDefaultEncoderConfig, + // since both engines should be essentially equivalent at that point. If it + // hasn't been called, though, we'll use the first meaningful encoder + // config, or the config from the second video engine if neither are + // meaningful. + VideoEncoderConfig config = video1_.GetDefaultEncoderConfig(); + if (config.max_codec.width != 0) { + return config; + } else { + return video2_.GetDefaultEncoderConfig(); + } + } + const std::vector& codecs() const { + return codecs_; + } + const std::vector& rtp_header_extensions() const { + return rtp_header_extensions_; + } + void SetLogging(int min_sev, const char* filter) { + video1_.SetLogging(min_sev, filter); + video2_.SetLogging(min_sev, filter); + } + + VideoFormat GetStartCaptureFormat() const { + return video2_.GetStartCaptureFormat(); + } + + // TODO(juberti): Remove these functions after we do the capturer refactoring. + // For now they are set to always use the second engine for capturing, which + // is convenient given our intended use case. + bool SetCaptureDevice(const Device* device) { + return video2_.SetCaptureDevice(device); + } + VideoCapturer* GetVideoCapturer() const { + return video2_.GetVideoCapturer(); + } + bool SetLocalRenderer(VideoRenderer* renderer) { + return video2_.SetLocalRenderer(renderer); + } + sigslot::repeater2 SignalCaptureStateChange; + + virtual bool HasCodec1(const VideoCodec& codec) { + return HasCodec(video1_, codec); + } + virtual bool HasCodec2(const VideoCodec& codec) { + return HasCodec(video2_, codec); + } + template + bool HasCodec(const VIDEO& engine, const VideoCodec& codec) const { + for (std::vector::const_iterator i = engine.codecs().begin(); + i != engine.codecs().end(); + ++i) { + if (i->Matches(codec)) { + return true; + } + } + return false; + } + virtual void OnSendChange1(VideoMediaChannel* channel1, bool send) { + } + virtual void OnSendChange2(VideoMediaChannel* channel2, bool send) { + } + virtual void OnNewSendResolution(int width, int height) { + } + + protected: + VIDEO1 video1_; + VIDEO2 video2_; + std::vector codecs_; + std::vector rtp_header_extensions_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_HYBRIDVIDEOENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/mediachannel.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/mediachannel.h new file mode 100644 index 0000000..d163479 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/mediachannel.h @@ -0,0 +1,1284 @@ +/* + * 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_BASE_MEDIACHANNEL_H_ +#define TALK_MEDIA_BASE_MEDIACHANNEL_H_ + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/buffer.h" +#include "talk/base/dscp.h" +#include "talk/base/logging.h" +#include "talk/base/sigslot.h" +#include "talk/base/socket.h" +#include "talk/base/window.h" +#include "talk/media/base/codec.h" +#include "talk/media/base/constants.h" +#include "talk/media/base/streamparams.h" +// TODO(juberti): re-evaluate this include +#include "talk/session/media/audiomonitor.h" + +namespace talk_base { +class Buffer; +class RateLimiter; +class Timing; +} + +namespace cricket { + +class AudioRenderer; +struct RtpHeader; +class ScreencastId; +struct VideoFormat; +class VideoCapturer; +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 Settable { + public: + Settable() : set_(false), val_() {} + explicit Settable(T val) : set_(true), val_(val) {} + + bool IsSet() const { + return set_; + } + + bool Get(T* out) const { + *out = val_; + return set_; + } + + T GetWithDefaultIfUnset(const T& default_value) const { + return set_ ? val_ : default_value; + } + + virtual void Set(T val) { + set_ = true; + val_ = val; + } + + void Clear() { + Set(T()); + set_ = false; + } + + void SetFrom(const Settable& o) { + // Set this value based on the value of o, iff o is set. If this value is + // set and o is unset, the current value will be unchanged. + T val; + if (o.Get(&val)) { + Set(val); + } + } + + std::string ToString() const { + return set_ ? talk_base::ToString(val_) : ""; + } + + bool operator==(const Settable& o) const { + // Equal if both are unset with any value or both set with the same value. + return (set_ == o.set_) && (!set_ || (val_ == o.val_)); + } + + bool operator!=(const Settable& o) const { + return !operator==(o); + } + + protected: + void InitializeValue(const T &val) { + val_ = val; + } + + private: + bool set_; + T val_; +}; + +class SettablePercent : public Settable { + public: + virtual void Set(float val) { + if (val < 0) { + val = 0; + } + if (val > 1.0) { + val = 1.0; + } + Settable::Set(val); + } +}; + +template +static std::string ToStringIfSet(const char* key, const Settable& val) { + std::string str; + if (val.IsSet()) { + str = key; + str += ": "; + str += val.ToString(); + str += ", "; + } + return str; +} + +// Options that can be applied to a VoiceMediaChannel or a VoiceMediaEngine. +// Used to be flags, but that makes it hard to selectively apply options. +// We are moving all of the setting of options to structs like this, +// but some things currently still use flags. +struct AudioOptions { + void SetAll(const AudioOptions& change) { + echo_cancellation.SetFrom(change.echo_cancellation); + auto_gain_control.SetFrom(change.auto_gain_control); + rx_auto_gain_control.SetFrom(change.rx_auto_gain_control); + noise_suppression.SetFrom(change.noise_suppression); + highpass_filter.SetFrom(change.highpass_filter); + stereo_swapping.SetFrom(change.stereo_swapping); + typing_detection.SetFrom(change.typing_detection); + aecm_generate_comfort_noise.SetFrom(change.aecm_generate_comfort_noise); + conference_mode.SetFrom(change.conference_mode); + 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); + tx_agc_target_dbov.SetFrom(change.tx_agc_target_dbov); + tx_agc_digital_compression_gain.SetFrom( + change.tx_agc_digital_compression_gain); + tx_agc_limiter.SetFrom(change.tx_agc_limiter); + rx_agc_target_dbov.SetFrom(change.rx_agc_target_dbov); + rx_agc_digital_compression_gain.SetFrom( + change.rx_agc_digital_compression_gain); + rx_agc_limiter.SetFrom(change.rx_agc_limiter); + recording_sample_rate.SetFrom(change.recording_sample_rate); + playout_sample_rate.SetFrom(change.playout_sample_rate); + dscp.SetFrom(change.dscp); + } + + bool operator==(const AudioOptions& o) const { + return echo_cancellation == o.echo_cancellation && + auto_gain_control == o.auto_gain_control && + rx_auto_gain_control == o.rx_auto_gain_control && + noise_suppression == o.noise_suppression && + highpass_filter == o.highpass_filter && + stereo_swapping == o.stereo_swapping && + typing_detection == o.typing_detection && + aecm_generate_comfort_noise == o.aecm_generate_comfort_noise && + 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 && + 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 && + rx_agc_target_dbov == o.rx_agc_target_dbov && + rx_agc_digital_compression_gain == o.rx_agc_digital_compression_gain && + rx_agc_limiter == o.rx_agc_limiter && + recording_sample_rate == o.recording_sample_rate && + playout_sample_rate == o.playout_sample_rate && + dscp == o.dscp; + } + + std::string ToString() const { + std::ostringstream ost; + ost << "AudioOptions {"; + ost << ToStringIfSet("aec", echo_cancellation); + ost << ToStringIfSet("agc", auto_gain_control); + ost << ToStringIfSet("rx_agc", rx_auto_gain_control); + ost << ToStringIfSet("ns", noise_suppression); + ost << ToStringIfSet("hf", highpass_filter); + ost << ToStringIfSet("swap", stereo_swapping); + ost << ToStringIfSet("typing", typing_detection); + ost << ToStringIfSet("comfort_noise", aecm_generate_comfort_noise); + ost << ToStringIfSet("conference", conference_mode); + 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("tx_agc_target_dbov", tx_agc_target_dbov); + ost << ToStringIfSet("tx_agc_digital_compression_gain", + tx_agc_digital_compression_gain); + ost << ToStringIfSet("tx_agc_limiter", tx_agc_limiter); + ost << ToStringIfSet("rx_agc_target_dbov", rx_agc_target_dbov); + ost << ToStringIfSet("rx_agc_digital_compression_gain", + rx_agc_digital_compression_gain); + ost << ToStringIfSet("rx_agc_limiter", rx_agc_limiter); + ost << ToStringIfSet("recording_sample_rate", recording_sample_rate); + ost << ToStringIfSet("playout_sample_rate", playout_sample_rate); + ost << ToStringIfSet("dscp", dscp); + ost << "}"; + return ost.str(); + } + + // Audio processing that attempts to filter away the output signal from + // later inbound pickup. + Settable echo_cancellation; + // Audio processing to adjust the sensitivity of the local mic dynamically. + Settable auto_gain_control; + // Audio processing to apply gain to the remote audio. + Settable rx_auto_gain_control; + // Audio processing to filter out background noise. + Settable noise_suppression; + // Audio processing to remove background noise of lower frequencies. + Settable highpass_filter; + // Audio processing to swap the left and right channels. + Settable stereo_swapping; + // Audio processing to detect typing. + Settable typing_detection; + Settable aecm_generate_comfort_noise; + Settable conference_mode; + Settable adjust_agc_delta; + Settable experimental_agc; + Settable experimental_aec; + Settable experimental_ns; + Settable aec_dump; + // Note that tx_agc_* only applies to non-experimental AGC. + Settable tx_agc_target_dbov; + Settable tx_agc_digital_compression_gain; + Settable tx_agc_limiter; + Settable rx_agc_target_dbov; + Settable rx_agc_digital_compression_gain; + Settable rx_agc_limiter; + Settable recording_sample_rate; + Settable playout_sample_rate; + // Set DSCP value for packet sent from audio channel. + Settable dscp; +}; + +// Options that can be applied to a VideoMediaChannel or a VideoMediaEngine. +// Used to be flags, but that makes it hard to selectively apply options. +// 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) { + adapt_input_to_encoder.SetFrom(change.adapt_input_to_encoder); + adapt_input_to_cpu_usage.SetFrom(change.adapt_input_to_cpu_usage); + adapt_cpu_with_smoothing.SetFrom(change.adapt_cpu_with_smoothing); + adapt_view_switch.SetFrom(change.adapt_view_switch); + video_adapt_third.SetFrom(change.video_adapt_third); + 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_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_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( + change.system_low_adaptation_threshhold); + system_high_adaptation_threshhold.SetFrom( + change.system_high_adaptation_threshhold); + buffered_mode_latency.SetFrom(change.buffered_mode_latency); + 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); + } + + bool operator==(const VideoOptions& o) const { + return adapt_input_to_encoder == o.adapt_input_to_encoder && + adapt_input_to_cpu_usage == o.adapt_input_to_cpu_usage && + adapt_cpu_with_smoothing == o.adapt_cpu_with_smoothing && + adapt_view_switch == o.adapt_view_switch && + video_adapt_third == o.video_adapt_third && + video_noise_reduction == o.video_noise_reduction && + video_one_layer_screencast == o.video_one_layer_screencast && + video_high_bitrate == o.video_high_bitrate && + 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_overuse_encode_usage == o.cpu_overuse_encode_usage && + conference_mode == o.conference_mode && + process_adaptation_threshhold == o.process_adaptation_threshhold && + system_low_adaptation_threshhold == + o.system_low_adaptation_threshhold && + system_high_adaptation_threshhold == + o.system_high_adaptation_threshhold && + 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 && + 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; + } + + std::string ToString() const { + std::ostringstream ost; + ost << "VideoOptions {"; + ost << ToStringIfSet("encoder adaption", adapt_input_to_encoder); + ost << ToStringIfSet("cpu adaption", adapt_input_to_cpu_usage); + ost << ToStringIfSet("cpu adaptation smoothing", adapt_cpu_with_smoothing); + ost << ToStringIfSet("adapt view switch", adapt_view_switch); + ost << ToStringIfSet("video adapt third", video_adapt_third); + 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("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 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); + ost << ToStringIfSet("high", system_high_adaptation_threshhold); + ost << ToStringIfSet("buffered mode latency", buffered_mode_latency); + ost << ToStringIfSet("lower min bitrate", lower_min_bitrate); + 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 << "}"; + return ost.str(); + } + + // Encoder adaption, which is the gd callback in LMI, and TBA in WebRTC. + Settable adapt_input_to_encoder; + // Enable CPU adaptation? + Settable adapt_input_to_cpu_usage; + // Enable CPU adaptation smoothing? + Settable adapt_cpu_with_smoothing; + // Enable Adapt View Switch? + Settable adapt_view_switch; + // Enable video adapt third? + Settable video_adapt_third; + // Enable denoising? + Settable video_noise_reduction; + // Experimental: Enable one layer screencast? + Settable video_one_layer_screencast; + // Experimental: Enable WebRtc higher bitrate? + Settable video_high_bitrate; + // Experimental: Enable WebRtc higher start bitrate? + Settable video_start_bitrate; + // Experimental: Enable WebRTC layered screencast. + Settable video_temporal_layer_screencast; + // Experimental: Enable WebRTC temporal layer strategy for realtime video. + Settable video_temporal_layer_realtime; + // Enable WebRTC leaky bucket when sending media packets. + Settable video_leaky_bucket; + // Set highest bitrate mode for video. + Settable 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 cpu_overuse_detection; + // Low threshold for cpu overuse adaptation in ms. (Adapt up) + Settable cpu_underuse_threshold; + // High threshold for cpu overuse adaptation in ms. (Adapt down) + Settable cpu_overuse_threshold; + // Use encode usage for cpu detection. + Settable cpu_overuse_encode_usage; + // Use conference mode? + Settable conference_mode; + // Threshhold for process cpu adaptation. (Process limit) + SettablePercent process_adaptation_threshhold; + // Low threshhold for cpu adaptation. (Adapt up) + SettablePercent system_low_adaptation_threshhold; + // High threshhold for cpu adaptation. (Adapt down) + SettablePercent system_high_adaptation_threshhold; + // Specify buffered mode latency in milliseconds. + Settable buffered_mode_latency; + // Make minimum configured send bitrate even lower than usual, at 30kbit. + Settable lower_min_bitrate; + // Set DSCP value for packet sent from video channel. + Settable dscp; + // Enable WebRTC suspension of video. No video frames will be sent when the + // bitrate is below the configured minimum bitrate. + Settable suspend_below_min_bitrate; + // Limit on the number of early receive channels that can be created. + Settable unsignalled_recv_stream_limit; + // Enable use of simulcast adapter. + Settable use_simulcast_adapter; + // Enables the encoder to skip encoding stream not actually sent due to too + // low available bit rate. + Settable skip_encoding_unused_streams; + // Force screencast to use a minimum bitrate + Settable screencast_min_bitrate; + // Enable improved bandwidth estiamtor on wifi. + Settable use_improved_wifi_bandwidth_estimator; +}; + +// A class for playing out soundclips. +class SoundclipMedia { + public: + enum SoundclipFlags { + SF_LOOP = 1, + }; + + virtual ~SoundclipMedia() {} + + // Plays a sound out to the speakers with the given audio stream. The stream + // must be 16-bit little-endian 16 kHz PCM. If a stream is already playing + // on this SoundclipMedia, it is stopped. If clip is NULL, nothing is played. + // Returns whether it was successful. + virtual bool PlaySound(const char *clip, int len, int flags) = 0; +}; + +struct RtpHeaderExtension { + RtpHeaderExtension() : id(0) {} + RtpHeaderExtension(const std::string& u, int i) : uri(u), id(i) {} + std::string uri; + int id; + // TODO(juberti): SendRecv direction; + + bool operator==(const RtpHeaderExtension& ext) const { + // id is a reserved word in objective-c. Therefore the id attribute has to + // be a fully qualified name in order to compile on IOS. + return this->id == ext.id && + uri == ext.uri; + } +}; + +// Returns the named header extension if found among all extensions, NULL +// otherwise. +inline const RtpHeaderExtension* FindHeaderExtension( + const std::vector& extensions, + const std::string& name) { + for (std::vector::const_iterator it = extensions.begin(); + it != extensions.end(); ++it) { + if (it->uri == name) + return &(*it); + } + return NULL; +} + +enum MediaChannelOptions { + // Tune the stream for conference mode. + OPT_CONFERENCE = 0x0001 +}; + +enum VoiceMediaChannelOptions { + // Tune the audio stream for vcs with different target levels. + OPT_AGC_MINUS_10DB = 0x80000000 +}; + +// DTMF flags to control if a DTMF tone should be played and/or sent. +enum DtmfFlags { + DF_PLAY = 0x01, + DF_SEND = 0x02, +}; + +class MediaChannel : public sigslot::has_slots<> { + public: + class NetworkInterface { + public: + enum SocketType { ST_RTP, ST_RTCP }; + virtual bool SendPacket( + talk_base::Buffer* packet, + talk_base::DiffServCodePoint dscp = talk_base::DSCP_NO_CHANGE) = 0; + virtual bool SendRtcp( + talk_base::Buffer* packet, + talk_base::DiffServCodePoint dscp = talk_base::DSCP_NO_CHANGE) = 0; + virtual int SetOption(SocketType type, talk_base::Socket::Option opt, + int option) = 0; + virtual ~NetworkInterface() {} + }; + + MediaChannel() : network_interface_(NULL) {} + virtual ~MediaChannel() {} + + // Sets the abstract interface class for sending RTP/RTCP data. + virtual void SetInterface(NetworkInterface *iface) { + talk_base::CritScope cs(&network_interface_crit_); + network_interface_ = iface; + } + + // Called when a RTP packet is received. + virtual void OnPacketReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time) = 0; + // Called when a RTCP packet is received. + virtual void OnRtcpReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time) = 0; + // Called when the socket's ability to send has changed. + virtual void OnReadyToSend(bool ready) = 0; + // Creates a new outgoing media stream with SSRCs and CNAME as described + // by sp. + virtual bool AddSendStream(const StreamParams& sp) = 0; + // Removes an outgoing media stream. + // ssrc must be the first SSRC of the media stream if the stream uses + // multiple SSRCs. + virtual bool RemoveSendStream(uint32 ssrc) = 0; + // Creates a new incoming media stream with SSRCs and CNAME as described + // by sp. + virtual bool AddRecvStream(const StreamParams& sp) = 0; + // Removes an incoming media stream. + // ssrc must be the first SSRC of the media stream if the stream uses + // multiple SSRCs. + virtual bool RemoveRecvStream(uint32 ssrc) = 0; + + // Mutes the channel. + virtual bool MuteStream(uint32 ssrc, bool on) = 0; + + // Sets the RTP extension headers and IDs to use when sending RTP. + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions) = 0; + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions) = 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) { + return DoSendPacket(packet, false); + } + + bool SendRtcp(talk_base::Buffer* packet) { + return DoSendPacket(packet, true); + } + + int SetOption(NetworkInterface::SocketType type, + talk_base::Socket::Option opt, + int option) { + talk_base::CritScope cs(&network_interface_crit_); + if (!network_interface_) + return -1; + + return network_interface_->SetOption(type, opt, option); + } + + protected: + // This method sets DSCP |value| on both RTP and RTCP channels. + int SetDscp(talk_base::DiffServCodePoint value) { + int ret; + ret = SetOption(NetworkInterface::ST_RTP, + talk_base::Socket::OPT_DSCP, + value); + if (ret == 0) { + ret = SetOption(NetworkInterface::ST_RTCP, + talk_base::Socket::OPT_DSCP, + value); + } + return ret; + } + + private: + bool DoSendPacket(talk_base::Buffer* packet, bool rtcp) { + talk_base::CritScope cs(&network_interface_crit_); + if (!network_interface_) + return false; + + return (!rtcp) ? network_interface_->SendPacket(packet) : + network_interface_->SendRtcp(packet); + } + + // |network_interface_| can be accessed from the worker_thread and + // from any MediaEngine threads. This critical section is to protect accessing + // of network_interface_ object. + talk_base::CriticalSection network_interface_crit_; + NetworkInterface* network_interface_; +}; + +enum SendFlags { + SEND_NOTHING, + SEND_RINGBACKTONE, + SEND_MICROPHONE +}; + +// The stats information is structured as follows: +// Media are represented by either MediaSenderInfo or MediaReceiverInfo. +// Media contains a vector of SSRC infos that are exclusively used by this +// media. (SSRCs shared between media streams can't be represented.) + +// Information about an SSRC. +// This data may be locally recorded, or received in an RTCP SR or RR. +struct SsrcSenderInfo { + SsrcSenderInfo() + : ssrc(0), + timestamp(0) { + } + uint32 ssrc; + double timestamp; // NTP timestamp, represented as seconds since epoch. +}; + +struct SsrcReceiverInfo { + SsrcReceiverInfo() + : ssrc(0), + timestamp(0) { + } + uint32 ssrc; + double timestamp; +}; + +struct MediaSenderInfo { + MediaSenderInfo() + : bytes_sent(0), + packets_sent(0), + packets_lost(0), + fraction_lost(0.0), + rtt_ms(0) { + } + void add_ssrc(const SsrcSenderInfo& stat) { + local_stats.push_back(stat); + } + // Temporary utility function for call sites that only provide SSRC. + // As more info is added into SsrcSenderInfo, this function should go away. + void add_ssrc(uint32 ssrc) { + SsrcSenderInfo stat; + stat.ssrc = ssrc; + add_ssrc(stat); + } + // Utility accessor for clients that are only interested in ssrc numbers. + std::vector ssrcs() const { + std::vector retval; + for (std::vector::const_iterator it = local_stats.begin(); + it != local_stats.end(); ++it) { + retval.push_back(it->ssrc); + } + return retval; + } + // Utility accessor for clients that make the assumption only one ssrc + // exists per media. + // This will eventually go away. + uint32 ssrc() const { + if (local_stats.size() > 0) { + return local_stats[0].ssrc; + } else { + return 0; + } + } + int64 bytes_sent; + int packets_sent; + int packets_lost; + float fraction_lost; + int rtt_ms; + std::string codec_name; + std::vector local_stats; + std::vector remote_stats; +}; + +template +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), + packets_rcvd(0), + packets_lost(0), + fraction_lost(0.0) { + } + void add_ssrc(const SsrcReceiverInfo& stat) { + local_stats.push_back(stat); + } + // Temporary utility function for call sites that only provide SSRC. + // As more info is added into SsrcSenderInfo, this function should go away. + void add_ssrc(uint32 ssrc) { + SsrcReceiverInfo stat; + stat.ssrc = ssrc; + add_ssrc(stat); + } + std::vector ssrcs() const { + std::vector retval; + for (std::vector::const_iterator it = local_stats.begin(); + it != local_stats.end(); ++it) { + retval.push_back(it->ssrc); + } + return retval; + } + // Utility accessor for clients that make the assumption only one ssrc + // exists per media. + // This will eventually go away. + uint32 ssrc() const { + if (local_stats.size() > 0) { + return local_stats[0].ssrc; + } else { + return 0; + } + } + + int64 bytes_rcvd; + int packets_rcvd; + int packets_lost; + float fraction_lost; + std::vector local_stats; + std::vector remote_stats; +}; + +struct VoiceSenderInfo : public MediaSenderInfo { + VoiceSenderInfo() + : ext_seqnum(0), + jitter_ms(0), + audio_level(0), + aec_quality_min(0.0), + echo_delay_median_ms(0), + echo_delay_std_ms(0), + echo_return_loss(0), + echo_return_loss_enhancement(0), + typing_noise_detected(false) { + } + + int ext_seqnum; + int jitter_ms; + int audio_level; + float aec_quality_min; + int echo_delay_median_ms; + int echo_delay_std_ms; + int echo_return_loss; + int echo_return_loss_enhancement; + bool typing_noise_detected; +}; + +struct VoiceReceiverInfo : public MediaReceiverInfo { + VoiceReceiverInfo() + : ext_seqnum(0), + jitter_ms(0), + jitter_buffer_ms(0), + jitter_buffer_preferred_ms(0), + delay_estimate_ms(0), + audio_level(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) { + } + + int ext_seqnum; + int jitter_ms; + int jitter_buffer_ms; + int jitter_buffer_preferred_ms; + int delay_estimate_ms; + 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; +}; + +struct VideoSenderInfo : public MediaSenderInfo { + VideoSenderInfo() + : packets_cached(0), + firs_rcvd(0), + plis_rcvd(0), + nacks_rcvd(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), + preferred_bitrate(0), + adapt_reason(0), + capture_jitter_ms(0), + avg_encode_ms(0), + encode_usage_percent(0), + capture_queue_delay_ms_per_s(0) { + } + + std::vector ssrc_groups; + int packets_cached; + int firs_rcvd; + int plis_rcvd; + int nacks_rcvd; + 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; + int preferred_bitrate; + int adapt_reason; + int capture_jitter_ms; + int avg_encode_ms; + int encode_usage_percent; + int capture_queue_delay_ms_per_s; + VariableInfo adapt_frame_drops; + VariableInfo effects_frame_drops; + VariableInfo 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), + framerate_rcvd(0), + framerate_decoded(0), + framerate_output(0), + framerate_render_input(0), + framerate_render_output(0), + decode_ms(0), + max_decode_ms(0), + jitter_buffer_ms(0), + min_playout_delay_ms(0), + render_delay_ms(0), + target_delay_ms(0), + current_delay_ms(0), + capture_start_ntp_time_ms(0) { + } + + std::vector ssrc_groups; + int packets_concealed; + int firs_sent; + int plis_sent; + int nacks_sent; + int frame_width; + int frame_height; + int framerate_rcvd; + int framerate_decoded; + int framerate_output; + // Framerate as sent to the renderer. + int framerate_render_input; + // Framerate that the renderer reports. + int framerate_render_output; + + // All stats below are gathered per-VideoReceiver, but some will be correlated + // across MediaStreamTracks. NOTE(hta): when sinking stats into per-SSRC + // structures, reflect this in the new layout. + + // Current frame decode latency. + int decode_ms; + // Maximum observed frame decode latency. + int max_decode_ms; + // Jitter (network-related) latency. + int jitter_buffer_ms; + // Requested minimum playout latency. + int min_playout_delay_ms; + // Requested latency to account for rendering delay. + int render_delay_ms; + // Target overall delay: network+decode+render, accounting for + // min_playout_delay_ms. + 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 { + DataSenderInfo() + : ssrc(0) { + } + + uint32 ssrc; +}; + +struct DataReceiverInfo : public MediaReceiverInfo { + DataReceiverInfo() + : ssrc(0) { + } + + uint32 ssrc; +}; + +struct BandwidthEstimationInfo { + BandwidthEstimationInfo() + : available_send_bandwidth(0), + available_recv_bandwidth(0), + target_enc_bitrate(0), + actual_enc_bitrate(0), + retransmit_bitrate(0), + transmit_bitrate(0), + bucket_delay(0), + total_received_propagation_delta_ms(0) { + } + + int available_send_bandwidth; + int available_recv_bandwidth; + int target_enc_bitrate; + int actual_enc_bitrate; + 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 recent_received_propagation_delta_ms; + std::vector recent_received_packet_group_arrival_time_ms; +}; + +struct VoiceMediaInfo { + void Clear() { + senders.clear(); + receivers.clear(); + } + std::vector senders; + std::vector receivers; +}; + +struct VideoMediaInfo { + void Clear() { + senders.clear(); + receivers.clear(); + bw_estimations.clear(); + } + std::vector senders; + std::vector receivers; + std::vector bw_estimations; +}; + +struct DataMediaInfo { + void Clear() { + senders.clear(); + receivers.clear(); + } + std::vector senders; + std::vector receivers; +}; + +struct StatsOptions { + StatsOptions() : include_received_propagation_stats(false) {} + + bool include_received_propagation_stats; +}; + +class VoiceMediaChannel : public MediaChannel { + public: + enum Error { + ERROR_NONE = 0, // No error. + ERROR_OTHER, // Other errors. + ERROR_REC_DEVICE_OPEN_FAILED = 100, // Could not open mic. + ERROR_REC_DEVICE_MUTED, // Mic was muted by OS. + ERROR_REC_DEVICE_SILENT, // No background noise picked up. + ERROR_REC_DEVICE_SATURATION, // Mic input is clipping. + ERROR_REC_DEVICE_REMOVED, // Mic was removed while active. + ERROR_REC_RUNTIME_ERROR, // Processing is encountering errors. + ERROR_REC_SRTP_ERROR, // Generic SRTP failure. + ERROR_REC_SRTP_AUTH_FAILED, // Failed to authenticate packets. + ERROR_REC_TYPING_NOISE_DETECTED, // Typing noise is detected. + ERROR_PLAY_DEVICE_OPEN_FAILED = 200, // Could not open playout. + ERROR_PLAY_DEVICE_MUTED, // Playout muted by OS. + ERROR_PLAY_DEVICE_REMOVED, // Playout removed while active. + ERROR_PLAY_RUNTIME_ERROR, // Errors in voice processing. + ERROR_PLAY_SRTP_ERROR, // Generic SRTP failure. + ERROR_PLAY_SRTP_AUTH_FAILED, // Failed to authenticate packets. + ERROR_PLAY_SRTP_REPLAY, // Packet replay detected. + }; + + VoiceMediaChannel() {} + virtual ~VoiceMediaChannel() {} + // Sets the codecs/payload types to be used for incoming media. + virtual bool SetRecvCodecs(const std::vector& codecs) = 0; + // Sets the codecs/payload types to be used for outgoing media. + virtual bool SetSendCodecs(const std::vector& codecs) = 0; + // Starts or stops playout of received audio. + virtual bool SetPlayout(bool playout) = 0; + // Starts or stops sending (and potentially capture) of local audio. + virtual bool SetSend(SendFlags flag) = 0; + // Sets the renderer object to be used for the specified remote audio stream. + virtual bool SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer) = 0; + // Sets the renderer object to be used for the specified local audio stream. + virtual bool SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer) = 0; + // Gets current energy levels for all incoming streams. + virtual bool GetActiveStreams(AudioInfo::StreamList* actives) = 0; + // Get the current energy level of the stream sent to the speaker. + virtual int GetOutputLevel() = 0; + // Get the time in milliseconds since last recorded keystroke, or negative. + virtual int GetTimeSinceLastTyping() = 0; + // Temporarily exposed field for tuning typing detect options. + virtual void SetTypingDetectionParameters(int time_window, + int cost_per_typing, int reporting_threshold, int penalty_decay, + int type_event_delay) = 0; + // Set left and right scale for speaker output volume of the specified ssrc. + virtual bool SetOutputScaling(uint32 ssrc, double left, double right) = 0; + // Get left and right scale for speaker output volume of the specified ssrc. + virtual bool GetOutputScaling(uint32 ssrc, double* left, double* right) = 0; + // Specifies a ringback tone to be played during call setup. + virtual bool SetRingbackTone(const char *buf, int len) = 0; + // Plays or stops the aforementioned ringback tone + virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop) = 0; + // Returns if the telephone-event has been negotiated. + virtual bool CanInsertDtmf() { return false; } + // Send and/or play a DTMF |event| according to the |flags|. + // The DTMF out-of-band signal will be used on sending. + // The |ssrc| should be either 0 or a valid send stream ssrc. + // The valid value for the |event| are 0 to 15 which corresponding to + // DTMF event 0-9, *, #, A-D. + virtual bool InsertDtmf(uint32 ssrc, int event, int duration, int flags) = 0; + // Gets quality stats for the channel. + virtual bool GetStats(VoiceMediaInfo* info) = 0; + // Gets last reported error for this media channel. + virtual void GetLastMediaError(uint32* ssrc, + VoiceMediaChannel::Error* error) { + ASSERT(error != NULL); + *error = ERROR_NONE; + } + // Sets the media options to use. + virtual bool SetOptions(const AudioOptions& options) = 0; + virtual bool GetOptions(AudioOptions* options) const = 0; + + // Signal errors from MediaChannel. Arguments are: + // ssrc(uint32), and error(VoiceMediaChannel::Error). + sigslot::signal2 SignalMediaError; +}; + +class VideoMediaChannel : public MediaChannel { + public: + enum Error { + ERROR_NONE = 0, // No error. + ERROR_OTHER, // Other errors. + ERROR_REC_DEVICE_OPEN_FAILED = 100, // Could not open camera. + ERROR_REC_DEVICE_NO_DEVICE, // No camera. + ERROR_REC_DEVICE_IN_USE, // Device is in already use. + ERROR_REC_DEVICE_REMOVED, // Device is removed. + ERROR_REC_SRTP_ERROR, // Generic sender SRTP failure. + ERROR_REC_SRTP_AUTH_FAILED, // Failed to authenticate packets. + ERROR_REC_CPU_MAX_CANT_DOWNGRADE, // Can't downgrade capture anymore. + ERROR_PLAY_SRTP_ERROR = 200, // Generic receiver SRTP failure. + ERROR_PLAY_SRTP_AUTH_FAILED, // Failed to authenticate packets. + ERROR_PLAY_SRTP_REPLAY, // Packet replay detected. + }; + + VideoMediaChannel() : renderer_(NULL) {} + virtual ~VideoMediaChannel() {} + // Sets the codecs/payload types to be used for incoming media. + virtual bool SetRecvCodecs(const std::vector& codecs) = 0; + // Sets the codecs/payload types to be used for outgoing media. + virtual bool SetSendCodecs(const std::vector& codecs) = 0; + // Gets the currently set codecs/payload types to be used for outgoing media. + virtual bool GetSendCodec(VideoCodec* send_codec) = 0; + // Sets the format of a specified outgoing stream. + virtual bool SetSendStreamFormat(uint32 ssrc, const VideoFormat& format) = 0; + // Starts or stops playout of received video. + virtual bool SetRender(bool render) = 0; + // Starts or stops transmission (and potentially capture) of local video. + virtual bool SetSend(bool send) = 0; + // Sets the renderer object to be used for the specified stream. + // If SSRC is 0, the renderer is used for the 'default' stream. + virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer) = 0; + // If |ssrc| is 0, replace the default capturer (engine capturer) with + // |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(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; + // Reuqest each of the remote senders to send an intra frame. + virtual bool RequestIntraFrame() = 0; + // Sets the media options to use. + virtual bool SetOptions(const VideoOptions& options) = 0; + virtual bool GetOptions(VideoOptions* options) const = 0; + virtual void UpdateAspectRatio(int ratio_w, int ratio_h) = 0; + + // Signal errors from MediaChannel. Arguments are: + // ssrc(uint32), and error(VideoMediaChannel::Error). + sigslot::signal2 SignalMediaError; + + protected: + VideoRenderer *renderer_; +}; + +enum DataMessageType { + // Chrome-Internal use only. See SctpDataMediaChannel for the actual PPID + // values. + DMT_NONE = 0, + DMT_CONTROL = 1, + DMT_BINARY = 2, + DMT_TEXT = 3, +}; + +// Info about data received in DataMediaChannel. For use in +// DataMediaChannel::SignalDataReceived and in all of the signals that +// signal fires, on up the chain. +struct ReceiveDataParams { + // The in-packet stream indentifier. + // For SCTP, this is really SID, not SSRC. + uint32 ssrc; + // The type of message (binary, text, or control). + DataMessageType type; + // A per-stream value incremented per packet in the stream. + int seq_num; + // A per-stream value monotonically increasing with time. + int timestamp; + + ReceiveDataParams() : + ssrc(0), + type(DMT_TEXT), + seq_num(0), + timestamp(0) { + } +}; + +struct SendDataParams { + // The in-packet stream indentifier. + // For SCTP, this is really SID, not SSRC. + uint32 ssrc; + // The type of message (binary, text, or control). + DataMessageType type; + + // For SCTP, whether to send messages flagged as ordered or not. + // If false, messages can be received out of order. + bool ordered; + // For SCTP, whether the messages are sent reliably or not. + // If false, messages may be lost. + bool reliable; + // For SCTP, if reliable == false, provide partial reliability by + // resending up to this many times. Either count or millis + // is supported, not both at the same time. + int max_rtx_count; + // For SCTP, if reliable == false, provide partial reliability by + // resending for up to this many milliseconds. Either count or millis + // is supported, not both at the same time. + int max_rtx_ms; + + SendDataParams() : + ssrc(0), + type(DMT_TEXT), + // TODO(pthatcher): Make these true by default? + ordered(false), + reliable(false), + max_rtx_count(0), + max_rtx_ms(0) { + } +}; + +enum SendDataResult { SDR_SUCCESS, SDR_ERROR, SDR_BLOCK }; + +class DataMediaChannel : public MediaChannel { + public: + enum Error { + ERROR_NONE = 0, // No error. + ERROR_OTHER, // Other errors. + ERROR_SEND_SRTP_ERROR = 200, // Generic SRTP failure. + ERROR_SEND_SRTP_AUTH_FAILED, // Failed to authenticate packets. + ERROR_RECV_SRTP_ERROR, // Generic SRTP failure. + ERROR_RECV_SRTP_AUTH_FAILED, // Failed to authenticate packets. + ERROR_RECV_SRTP_REPLAY, // Packet replay detected. + }; + + virtual ~DataMediaChannel() {} + + virtual bool SetSendCodecs(const std::vector& codecs) = 0; + virtual bool SetRecvCodecs(const std::vector& codecs) = 0; + + virtual bool MuteStream(uint32 ssrc, bool on) { return false; } + // TODO(pthatcher): Implement this. + virtual bool GetStats(DataMediaInfo* info) { return true; } + + virtual bool SetSend(bool send) = 0; + virtual bool SetReceive(bool receive) = 0; + + virtual bool SendData( + const SendDataParams& params, + const talk_base::Buffer& payload, + SendDataResult* result = NULL) = 0; + // Signals when data is received (params, data, len) + sigslot::signal3 SignalDataReceived; + // Signal errors from MediaChannel. Arguments are: + // ssrc(uint32), and error(DataMediaChannel::Error). + sigslot::signal2 SignalMediaError; + // Signal when the media channel is ready to send the stream. Arguments are: + // writable(bool) + sigslot::signal1 SignalReadyToSend; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_MEDIACHANNEL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/mediacommon.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/mediacommon.h new file mode 100644 index 0000000..323c39c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/mediacommon.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_BASE_MEDIACOMMON_H_ +#define TALK_MEDIA_BASE_MEDIACOMMON_H_ + +#include "talk/base/stringencode.h" + +namespace cricket { + +enum MediaCapabilities { + AUDIO_RECV = 1 << 0, + AUDIO_SEND = 1 << 1, + VIDEO_RECV = 1 << 2, + VIDEO_SEND = 1 << 3, +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_MEDIACOMMON_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/mediaengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/mediaengine.h new file mode 100644 index 0000000..2b9d810 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/mediaengine.h @@ -0,0 +1,395 @@ +/* + * 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_BASE_MEDIAENGINE_H_ +#define TALK_MEDIA_BASE_MEDIAENGINE_H_ + +#ifdef OSX +#include +#endif + +#include + +#include +#include + +#include "talk/base/fileutils.h" +#include "talk/base/sigslotrepeater.h" +#include "talk/media/base/codec.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/mediacommon.h" +#include "talk/media/base/videocapturer.h" +#include "talk/media/base/videocommon.h" +#include "talk/media/base/videoprocessor.h" +#include "talk/media/base/voiceprocessor.h" +#include "talk/media/devices/devicemanager.h" + +#if defined(GOOGLE_CHROME_BUILD) || defined(CHROMIUM_BUILD) +#define DISABLE_MEDIA_ENGINE_FACTORY +#endif + +namespace cricket { + +class VideoCapturer; + +// MediaEngineInterface is an abstraction of a media engine which can be +// subclassed to support different media componentry backends. +// It supports voice and video operations in the same class to facilitate +// proper synchronization between both media types. +class MediaEngineInterface { + public: + // Default value to be used for SetAudioDelayOffset(). + static const int kDefaultAudioDelayOffset; + + virtual ~MediaEngineInterface() {} + + // Initialization + // Starts the engine. + virtual bool Init(talk_base::Thread* worker_thread) = 0; + // Shuts down the engine. + virtual void Terminate() = 0; + // Returns what the engine is capable of, as a set of Capabilities, above. + virtual int GetCapabilities() = 0; + + // MediaChannel creation + // Creates a voice media channel. Returns NULL on failure. + virtual VoiceMediaChannel *CreateChannel() = 0; + // Creates a video media channel, paired with the specified voice channel. + // Returns NULL on failure. + virtual VideoMediaChannel *CreateVideoChannel( + VoiceMediaChannel* voice_media_channel) = 0; + + // Creates a soundclip object for playing sounds on. Returns NULL on failure. + virtual SoundclipMedia *CreateSoundclip() = 0; + + // Configuration + // Gets global audio options. + virtual AudioOptions GetAudioOptions() const = 0; + // Sets global audio options. "options" are from AudioOptions, above. + virtual bool SetAudioOptions(const AudioOptions& options) = 0; + // Sets global video options. "options" are from VideoOptions, above. + virtual bool SetVideoOptions(const VideoOptions& options) = 0; + // Sets the value used by the echo canceller to offset delay values obtained + // from the OS. + virtual bool SetAudioDelayOffset(int offset) = 0; + // Sets the default (maximum) codec/resolution and encoder option to capture + // and encode video. + virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) + = 0; + // Gets the default (maximum) codec/resolution and encoder option used to + // capture and encode video, as set by SetDefaultVideoEncoderConfig or the + // default from the video engine if not previously set. + virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const = 0; + + // Device selection + // TODO(tschmelcher): Add method for selecting the soundclip device. + virtual bool SetSoundDevices(const Device* in_device, + const Device* out_device) = 0; + + // Device configuration + // Gets the current speaker volume, as a value between 0 and 255. + virtual bool GetOutputVolume(int* level) = 0; + // Sets the current speaker volume, as a value between 0 and 255. + virtual bool SetOutputVolume(int level) = 0; + + // Local monitoring + // Gets the current microphone level, as a value between 0 and 10. + virtual int GetInputLevel() = 0; + // Starts or stops the local microphone. Useful if local mic info is needed + // prior to a call being connected; the mic will be started automatically + // when a VoiceMediaChannel starts sending. + virtual bool SetLocalMonitor(bool enable) = 0; + // Installs a callback for raw frames from the local camera. + virtual bool SetLocalRenderer(VideoRenderer* renderer) = 0; + + virtual const std::vector& audio_codecs() = 0; + virtual const std::vector& + audio_rtp_header_extensions() = 0; + virtual const std::vector& video_codecs() = 0; + virtual const std::vector& + video_rtp_header_extensions() = 0; + + // Logging control + 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, + MediaProcessorDirection direction) = 0; + virtual bool UnregisterVoiceProcessor(uint32 ssrc, + VoiceProcessor* video_processor, + MediaProcessorDirection direction) = 0; + + virtual VideoFormat GetStartCaptureFormat() const = 0; + + virtual sigslot::repeater2& + SignalVideoCaptureStateChange() = 0; +}; + + +#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 + +// CompositeMediaEngine constructs a MediaEngine from separate +// voice and video engine classes. +template +class CompositeMediaEngine : public MediaEngineInterface { + public: + CompositeMediaEngine() {} + virtual ~CompositeMediaEngine() {} + virtual bool Init(talk_base::Thread* worker_thread) { + if (!voice_.Init(worker_thread)) + return false; + if (!video_.Init(worker_thread)) { + voice_.Terminate(); + return false; + } + SignalVideoCaptureStateChange().repeat(video_.SignalCaptureStateChange); + return true; + } + virtual void Terminate() { + video_.Terminate(); + voice_.Terminate(); + } + + virtual int GetCapabilities() { + return (voice_.GetCapabilities() | video_.GetCapabilities()); + } + virtual VoiceMediaChannel *CreateChannel() { + return voice_.CreateChannel(); + } + virtual VideoMediaChannel *CreateVideoChannel(VoiceMediaChannel* channel) { + return video_.CreateChannel(channel); + } + virtual SoundclipMedia *CreateSoundclip() { + return voice_.CreateSoundclip(); + } + + virtual AudioOptions GetAudioOptions() const { + return voice_.GetOptions(); + } + virtual bool SetAudioOptions(const AudioOptions& options) { + return voice_.SetOptions(options); + } + virtual bool SetVideoOptions(const VideoOptions& options) { + return video_.SetOptions(options); + } + virtual bool SetAudioDelayOffset(int offset) { + return voice_.SetDelayOffset(offset); + } + virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) { + return video_.SetDefaultEncoderConfig(config); + } + virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const { + return video_.GetDefaultEncoderConfig(); + } + + virtual bool SetSoundDevices(const Device* in_device, + const Device* out_device) { + return voice_.SetDevices(in_device, out_device); + } + + virtual bool GetOutputVolume(int* level) { + return voice_.GetOutputVolume(level); + } + virtual bool SetOutputVolume(int level) { + return voice_.SetOutputVolume(level); + } + + virtual int GetInputLevel() { + return voice_.GetInputLevel(); + } + virtual bool SetLocalMonitor(bool enable) { + return voice_.SetLocalMonitor(enable); + } + virtual bool SetLocalRenderer(VideoRenderer* renderer) { + return video_.SetLocalRenderer(renderer); + } + + virtual const std::vector& audio_codecs() { + return voice_.codecs(); + } + virtual const std::vector& audio_rtp_header_extensions() { + return voice_.rtp_header_extensions(); + } + virtual const std::vector& video_codecs() { + return video_.codecs(); + } + virtual const std::vector& video_rtp_header_extensions() { + return video_.rtp_header_extensions(); + } + + virtual void SetVoiceLogging(int min_sev, const char* filter) { + voice_.SetLogging(min_sev, filter); + } + virtual void SetVideoLogging(int min_sev, const char* filter) { + 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) { + return voice_.RegisterProcessor(ssrc, processor, direction); + } + virtual bool UnregisterVoiceProcessor(uint32 ssrc, + VoiceProcessor* processor, + MediaProcessorDirection direction) { + return voice_.UnregisterProcessor(ssrc, processor, direction); + } + virtual VideoFormat GetStartCaptureFormat() const { + return video_.GetStartCaptureFormat(); + } + virtual sigslot::repeater2& + SignalVideoCaptureStateChange() { + return signal_state_change_; + } + + protected: + VOICE voice_; + VIDEO video_; + sigslot::repeater2 signal_state_change_; +}; + +// NullVoiceEngine can be used with CompositeMediaEngine in the case where only +// a video engine is desired. +class NullVoiceEngine { + public: + bool Init(talk_base::Thread* worker_thread) { return true; } + void Terminate() {} + int GetCapabilities() { return 0; } + // If you need this to return an actual channel, use FakeMediaEngine instead. + VoiceMediaChannel* CreateChannel() { + return NULL; + } + SoundclipMedia* CreateSoundclip() { + return NULL; + } + bool SetDelayOffset(int offset) { return true; } + AudioOptions GetOptions() const { return AudioOptions(); } + bool SetOptions(const AudioOptions& options) { return true; } + bool SetDevices(const Device* in_device, const Device* out_device) { + return true; + } + bool GetOutputVolume(int* level) { + *level = 0; + return true; + } + bool SetOutputVolume(int level) { return true; } + int GetInputLevel() { return 0; } + bool SetLocalMonitor(bool enable) { return true; } + const std::vector& codecs() { return codecs_; } + const std::vector& rtp_header_extensions() { + 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; } + bool UnregisterProcessor(uint32 ssrc, + VoiceProcessor* voice_processor, + MediaProcessorDirection direction) { return true; } + + private: + std::vector codecs_; + std::vector rtp_header_extensions_; +}; + +// NullVideoEngine can be used with CompositeMediaEngine in the case where only +// a voice engine is desired. +class NullVideoEngine { + public: + bool Init(talk_base::Thread* worker_thread) { return true; } + void Terminate() {} + int GetCapabilities() { return 0; } + // If you need this to return an actual channel, use FakeMediaEngine instead. + VideoMediaChannel* CreateChannel( + VoiceMediaChannel* voice_media_channel) { + return NULL; + } + bool SetOptions(const VideoOptions& options) { return true; } + VideoEncoderConfig GetDefaultEncoderConfig() const { + return VideoEncoderConfig(); + } + bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) { + return true; + } + bool SetLocalRenderer(VideoRenderer* renderer) { return true; } + const std::vector& codecs() { return codecs_; } + const std::vector& rtp_header_extensions() { + return rtp_header_extensions_; + } + void SetLogging(int min_sev, const char* filter) {} + VideoFormat GetStartCaptureFormat() const { return VideoFormat(); } + + sigslot::signal2 SignalCaptureStateChange; + private: + std::vector codecs_; + std::vector rtp_header_extensions_; +}; + +typedef CompositeMediaEngine NullMediaEngine; + +enum DataChannelType { + DCT_NONE = 0, + DCT_RTP = 1, + DCT_SCTP = 2 +}; + +class DataEngineInterface { + public: + virtual ~DataEngineInterface() {} + virtual DataMediaChannel* CreateChannel(DataChannelType type) = 0; + virtual const std::vector& data_codecs() = 0; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_MEDIAENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/mutedvideocapturer.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/mutedvideocapturer.h new file mode 100644 index 0000000..8e8ea4b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/mutedvideocapturer.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef TALK_MEDIA_BASE_MUTEDVIDEOCAPTURER_H_ +#define TALK_MEDIA_BASE_MUTEDVIDEOCAPTURER_H_ + +#include "talk/base/thread.h" +#include "talk/media/base/videocapturer.h" + +namespace cricket { + +class MutedFramesGenerator; + +class MutedVideoCapturer : public VideoCapturer { + public: + static const char kCapturerId[]; + + MutedVideoCapturer(); + virtual ~MutedVideoCapturer(); + virtual bool GetBestCaptureFormat(const VideoFormat& desired, + VideoFormat* best_format); + virtual CaptureState Start(const VideoFormat& capture_format); + virtual void Stop(); + virtual bool IsRunning(); + virtual bool IsScreencast() const { return false; } + virtual bool GetPreferredFourccs(std::vector* fourccs); + + protected: + void OnMutedFrame(VideoFrame* muted_frame); + + talk_base::scoped_ptr frame_generator_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_MUTEDVIDEOCAPTURER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/nullvideoframe.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/nullvideoframe.h new file mode 100644 index 0000000..7582c4b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/nullvideoframe.h @@ -0,0 +1,94 @@ +/* + * 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_BASE_NULLVIDEOFRAME_H_ +#define TALK_MEDIA_BASE_NULLVIDEOFRAME_H_ + +#include "talk/media/base/videoframe.h" + +namespace cricket { + +// Simple subclass for use in mocks. +class NullVideoFrame : public VideoFrame { + public: + virtual bool Reset(uint32 format, 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) { + return false; + } + virtual bool InitToBlack(int w, int h, size_t pixel_width, + size_t pixel_height, int64 elapsed_time, + int64 time_stamp) { + return false; + } + virtual size_t GetWidth() const { return 0; } + virtual size_t GetHeight() const { return 0; } + virtual const uint8 *GetYPlane() const { return NULL; } + virtual const uint8 *GetUPlane() const { return NULL; } + virtual const uint8 *GetVPlane() const { return NULL; } + virtual uint8 *GetYPlane() { return NULL; } + virtual uint8 *GetUPlane() { return NULL; } + virtual uint8 *GetVPlane() { return NULL; } + virtual int32 GetYPitch() const { return 0; } + virtual int32 GetUPitch() const { return 0; } + virtual int32 GetVPitch() const { return 0; } + virtual void* GetNativeHandle() const { return NULL; } + + virtual size_t GetPixelWidth() const { return 1; } + virtual size_t GetPixelHeight() const { return 1; } + virtual int64 GetElapsedTime() const { return 0; } + virtual int64 GetTimeStamp() const { return 0; } + virtual void SetElapsedTime(int64 elapsed_time) {} + virtual void SetTimeStamp(int64 time_stamp) {} + virtual int GetRotation() const { return 0; } + + virtual VideoFrame *Copy() const { return NULL; } + + virtual bool MakeExclusive() { return false; } + + virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const { return 0; } + + virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8 *buffer, + size_t size, int stride_rgb) const { + return 0; + } + + virtual void StretchToPlanes( + uint8 *y, uint8 *u, uint8 *v, int32 pitchY, int32 pitchU, int32 pitchV, + size_t width, size_t height, bool interpolate, bool crop) const {} + + virtual VideoFrame *CreateEmptyFrame(int w, int h, size_t pixel_width, + size_t pixel_height, int64 elapsed_time, + int64 time_stamp) const { + return NULL; + } +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_NULLVIDEOFRAME_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/nullvideorenderer.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/nullvideorenderer.h new file mode 100644 index 0000000..a2fd124 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/nullvideorenderer.h @@ -0,0 +1,48 @@ +/* + * 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_BASE_NULLVIDEORENDERER_H_ +#define TALK_MEDIA_BASE_NULLVIDEORENDERER_H_ + +#include "talk/media/base/videorenderer.h" + +namespace cricket { + +// Simple implementation for use in tests. +class NullVideoRenderer : public VideoRenderer { + virtual bool SetSize(int width, int height, int reserved) { + return true; + } + // Called when a new frame is available for display. + virtual bool RenderFrame(const VideoFrame *frame) { + return true; + } +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_NULLVIDEORENDERER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/rtpdataengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/rtpdataengine.h new file mode 100644 index 0000000..23a3c3e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/rtpdataengine.h @@ -0,0 +1,145 @@ +/* + * 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. + */ + +#ifndef TALK_MEDIA_BASE_RTPDATAENGINE_H_ +#define TALK_MEDIA_BASE_RTPDATAENGINE_H_ + +#include +#include + +#include "talk/base/timing.h" +#include "talk/media/base/constants.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/mediaengine.h" + +namespace cricket { + +struct DataCodec; + +class RtpDataEngine : public DataEngineInterface { + public: + RtpDataEngine(); + + virtual DataMediaChannel* CreateChannel(DataChannelType data_channel_type); + + virtual const std::vector& data_codecs() { + return data_codecs_; + } + + // Mostly for testing with a fake clock. Ownership is passed in. + void SetTiming(talk_base::Timing* timing) { + timing_.reset(timing); + } + + private: + std::vector data_codecs_; + talk_base::scoped_ptr timing_; +}; + +// Keep track of sequence number and timestamp of an RTP stream. The +// sequence number starts with a "random" value and increments. The +// timestamp starts with a "random" value and increases monotonically +// according to the clockrate. +class RtpClock { + public: + RtpClock(int clockrate, uint16 first_seq_num, uint32 timestamp_offset) + : clockrate_(clockrate), + last_seq_num_(first_seq_num), + timestamp_offset_(timestamp_offset) { + } + + // Given the current time (in number of seconds which must be + // monotonically increasing), Return the next sequence number and + // timestamp. + void Tick(double now, int* seq_num, uint32* timestamp); + + private: + int clockrate_; + uint16 last_seq_num_; + uint32 timestamp_offset_; +}; + +class RtpDataMediaChannel : public DataMediaChannel { + public: + // Timing* Used for the RtpClock + explicit RtpDataMediaChannel(talk_base::Timing* timing); + // Sets Timing == NULL, so you'll need to call set_timer() before + // using it. This is needed by FakeMediaEngine. + RtpDataMediaChannel(); + virtual ~RtpDataMediaChannel(); + + void set_timing(talk_base::Timing* timing) { + timing_ = timing; + } + + virtual bool SetStartSendBandwidth(int bps) { return true; } + virtual bool SetMaxSendBandwidth(int bps); + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions) { return true; } + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions) { return true; } + virtual bool SetSendCodecs(const std::vector& codecs); + virtual bool SetRecvCodecs(const std::vector& codecs); + virtual bool AddSendStream(const StreamParams& sp); + virtual bool RemoveSendStream(uint32 ssrc); + virtual bool AddRecvStream(const StreamParams& sp); + virtual bool RemoveRecvStream(uint32 ssrc); + virtual bool SetSend(bool send) { + sending_ = send; + return true; + } + virtual bool SetReceive(bool receive) { + receiving_ = receive; + return true; + } + virtual void OnPacketReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + virtual void OnRtcpReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time) {} + virtual void OnReadyToSend(bool ready) {} + virtual bool SendData( + const SendDataParams& params, + const talk_base::Buffer& payload, + SendDataResult* result); + + private: + void Construct(talk_base::Timing* timing); + + bool sending_; + bool receiving_; + talk_base::Timing* timing_; + std::vector send_codecs_; + std::vector recv_codecs_; + std::vector send_streams_; + std::vector recv_streams_; + std::map rtp_clock_by_send_ssrc_; + talk_base::scoped_ptr send_limiter_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_RTPDATAENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/rtpdump.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/rtpdump.h new file mode 100644 index 0000000..0807899 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/rtpdump.h @@ -0,0 +1,233 @@ +/* + * 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. + */ + +#ifndef TALK_MEDIA_BASE_RTPDUMP_H_ +#define TALK_MEDIA_BASE_RTPDUMP_H_ + +#include + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/bytebuffer.h" +#include "talk/base/stream.h" + +namespace cricket { + +// We use the RTP dump file format compatible to the format used by rtptools +// (http://www.cs.columbia.edu/irt/software/rtptools/) and Wireshark +// (http://wiki.wireshark.org/rtpdump). In particular, the file starts with the +// first line "#!rtpplay1.0 address/port\n", followed by a 16 byte file header. +// For each packet, the file contains a 8 byte dump packet header, followed by +// the actual RTP or RTCP packet. + +enum RtpDumpPacketFilter { + PF_NONE = 0x0, + PF_RTPHEADER = 0x1, + PF_RTPPACKET = 0x3, // includes header + // PF_RTCPHEADER = 0x4, // TODO(juberti) + PF_RTCPPACKET = 0xC, // includes header + PF_ALL = 0xF +}; + +struct RtpDumpFileHeader { + RtpDumpFileHeader(uint32 start_ms, uint32 s, uint16 p); + void WriteToByteBuffer(talk_base::ByteBuffer* buf); + + static const char kFirstLine[]; + static const size_t kHeaderLength = 16; + uint32 start_sec; // start of recording, the seconds part. + uint32 start_usec; // start of recording, the microseconds part. + uint32 source; // network source (multicast address). + uint16 port; // UDP port. + uint16 padding; // 2 bytes padding. +}; + +struct RtpDumpPacket { + RtpDumpPacket() {} + + RtpDumpPacket(const void* d, size_t s, uint32 elapsed, bool rtcp) + : elapsed_time(elapsed), + original_data_len((rtcp) ? 0 : s) { + data.resize(s); + memcpy(&data[0], d, s); + } + + // In the rtpdump file format, RTCP packets have their data len set to zero, + // since RTCP has an internal length field. + bool is_rtcp() const { return original_data_len == 0; } + bool IsValidRtpPacket() const; + bool IsValidRtcpPacket() const; + // Get the payload type, sequence number, timestampe, and SSRC of the RTP + // packet. Return true and set the output parameter if successful. + bool GetRtpPayloadType(int* pt) const; + bool GetRtpSeqNum(int* seq_num) const; + bool GetRtpTimestamp(uint32* ts) const; + bool GetRtpSsrc(uint32* ssrc) const; + bool GetRtpHeaderLen(size_t* len) const; + // Get the type of the RTCP packet. Return true and set the output parameter + // if successful. + bool GetRtcpType(int* type) const; + + static const size_t kHeaderLength = 8; + uint32 elapsed_time; // Milliseconds since the start of recording. + std::vector data; // The actual RTP or RTCP packet. + size_t original_data_len; // The original length of the packet; may be + // greater than data.size() if only part of the + // packet was recorded. +}; + +class RtpDumpReader { + public: + explicit RtpDumpReader(talk_base::StreamInterface* stream) + : stream_(stream), + file_header_read_(false), + first_line_and_file_header_len_(0), + start_time_ms_(0), + ssrc_override_(0) { + } + virtual ~RtpDumpReader() {} + + // Use the specified ssrc, rather than the ssrc from dump, for RTP packets. + void SetSsrc(uint32 ssrc); + virtual talk_base::StreamResult ReadPacket(RtpDumpPacket* packet); + + protected: + talk_base::StreamResult ReadFileHeader(); + bool RewindToFirstDumpPacket() { + return stream_->SetPosition(first_line_and_file_header_len_); + } + + private: + // Check if its matches "#!rtpplay1.0 address/port\n". + bool CheckFirstLine(const std::string& first_line); + + talk_base::StreamInterface* stream_; + bool file_header_read_; + size_t first_line_and_file_header_len_; + uint32 start_time_ms_; + uint32 ssrc_override_; + + DISALLOW_COPY_AND_ASSIGN(RtpDumpReader); +}; + +// RtpDumpLoopReader reads RTP dump packets from the input stream and rewinds +// the stream when it ends. RtpDumpLoopReader maintains the elapsed time, the +// RTP sequence number and the RTP timestamp properly. RtpDumpLoopReader can +// handle both RTP dump and RTCP dump. We assume that the dump does not mix +// RTP packets and RTCP packets. +class RtpDumpLoopReader : public RtpDumpReader { + public: + explicit RtpDumpLoopReader(talk_base::StreamInterface* stream); + virtual talk_base::StreamResult ReadPacket(RtpDumpPacket* packet); + + private: + // During the first loop, update the statistics, including packet count, frame + // count, timestamps, and sequence number, of the input stream. + void UpdateStreamStatistics(const RtpDumpPacket& packet); + + // At the end of first loop, calculate elapsed_time_increases_, + // rtp_seq_num_increase_, and rtp_timestamp_increase_. + void CalculateIncreases(); + + // During the second and later loops, update the elapsed time of the dump + // packet. If the dumped packet is a RTP packet, update its RTP sequence + // number and timestamp as well. + void UpdateDumpPacket(RtpDumpPacket* packet); + + int loop_count_; + // How much to increase the elapsed time, RTP sequence number, RTP timestampe + // for each loop. They are calcualted with the variables below during the + // first loop. + uint32 elapsed_time_increases_; + int rtp_seq_num_increase_; + uint32 rtp_timestamp_increase_; + // How many RTP packets and how many payload frames in the input stream. RTP + // packets belong to the same frame have the same RTP timestamp, different + // dump timestamp, and different RTP sequence number. + uint32 packet_count_; + uint32 frame_count_; + // The elapsed time, RTP sequence number, and RTP timestamp of the first and + // the previous dump packets in the input stream. + uint32 first_elapsed_time_; + int first_rtp_seq_num_; + uint32 first_rtp_timestamp_; + uint32 prev_elapsed_time_; + int prev_rtp_seq_num_; + uint32 prev_rtp_timestamp_; + + DISALLOW_COPY_AND_ASSIGN(RtpDumpLoopReader); +}; + +class RtpDumpWriter { + public: + explicit RtpDumpWriter(talk_base::StreamInterface* stream); + + // Filter to control what packets we actually record. + void set_packet_filter(int filter); + // Write a RTP or RTCP packet. The parameters data points to the packet and + // data_len is its length. + talk_base::StreamResult WriteRtpPacket(const void* data, size_t data_len) { + return WritePacket(data, data_len, GetElapsedTime(), false); + } + talk_base::StreamResult WriteRtcpPacket(const void* data, size_t data_len) { + return WritePacket(data, data_len, GetElapsedTime(), true); + } + talk_base::StreamResult WritePacket(const RtpDumpPacket& packet) { + return WritePacket(&packet.data[0], packet.data.size(), packet.elapsed_time, + packet.is_rtcp()); + } + uint32 GetElapsedTime() const; + + bool GetDumpSize(size_t* size) { + // Note that we use GetPosition(), rather than GetSize(), to avoid flush the + // stream per write. + return stream_ && size && stream_->GetPosition(size); + } + + protected: + talk_base::StreamResult WriteFileHeader(); + + private: + talk_base::StreamResult WritePacket(const void* data, size_t data_len, + uint32 elapsed, bool rtcp); + size_t FilterPacket(const void* data, size_t data_len, bool rtcp); + talk_base::StreamResult WriteToStream(const void* data, size_t data_len); + + talk_base::StreamInterface* stream_; + int packet_filter_; + bool file_header_written_; + uint32 start_time_ms_; // Time when the record starts. + // If writing to the stream takes longer than this many ms, log a warning. + uint32 warn_slow_writes_delay_; + DISALLOW_COPY_AND_ASSIGN(RtpDumpWriter); +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_RTPDUMP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/rtputils.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/rtputils.h new file mode 100644 index 0000000..4d1e13e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/rtputils.h @@ -0,0 +1,79 @@ +/* + * 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_MEDIA_BASE_RTPUTILS_H_ +#define TALK_MEDIA_BASE_RTPUTILS_H_ + +#include "talk/base/byteorder.h" + +namespace cricket { + +const size_t kMinRtpPacketLen = 12; +const size_t kMaxRtpPacketLen = 2048; +const size_t kMinRtcpPacketLen = 4; + +struct RtpHeader { + int payload_type; + int seq_num; + uint32 timestamp; + uint32 ssrc; +}; + +enum RtcpTypes { + kRtcpTypeSR = 200, // Sender report payload type. + kRtcpTypeRR = 201, // Receiver report payload type. + kRtcpTypeSDES = 202, // SDES payload type. + kRtcpTypeBye = 203, // BYE payload type. + kRtcpTypeApp = 204, // APP payload type. + kRtcpTypeRTPFB = 205, // Transport layer Feedback message payload type. + kRtcpTypePSFB = 206, // Payload-specific Feedback message payload type. +}; + +bool GetRtpVersion(const void* data, size_t len, int* version); +bool GetRtpPayloadType(const void* data, size_t len, int* value); +bool GetRtpSeqNum(const void* data, size_t len, int* value); +bool GetRtpTimestamp(const void* data, size_t len, uint32* value); +bool GetRtpSsrc(const void* data, size_t len, uint32* value); +bool GetRtpHeaderLen(const void* data, size_t len, size_t* value); +bool GetRtcpType(const void* data, size_t len, int* value); +bool GetRtcpSsrc(const void* data, size_t len, uint32* value); +bool GetRtpHeader(const void* data, size_t len, RtpHeader* header); + +// Assumes marker bit is 0. +bool SetRtpHeaderFlags( + void* data, size_t len, + bool padding, bool extension, int csrc_count); +bool SetRtpPayloadType(void* data, size_t len, int value); +bool SetRtpSeqNum(void* data, size_t len, int value); +bool SetRtpTimestamp(void* data, size_t len, uint32 value); +bool SetRtpSsrc(void* data, size_t len, uint32 value); +// Assumes version 2, no padding, no extensions, no csrcs. +bool SetRtpHeader(void* data, size_t len, const RtpHeader& header); + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_RTPUTILS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/screencastid.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/screencastid.h new file mode 100644 index 0000000..4b01e59 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/screencastid.h @@ -0,0 +1,88 @@ +// Copyright 2012 Google Inc. +// Author: thorcarpenter@google.com (Thor Carpenter) +// +// Defines variant class ScreencastId that combines WindowId and DesktopId. + +#ifndef TALK_MEDIA_BASE_SCREENCASTID_H_ +#define TALK_MEDIA_BASE_SCREENCASTID_H_ + +#include +#include + +#include "talk/base/window.h" +#include "talk/base/windowpicker.h" + +namespace cricket { + +class ScreencastId; +typedef std::vector ScreencastIdList; + +// Used for identifying a window or desktop to be screencast. +class ScreencastId { + public: + enum Type { INVALID, WINDOW, DESKTOP }; + + // Default constructor indicates invalid ScreencastId. + ScreencastId() : type_(INVALID) {} + explicit ScreencastId(const talk_base::WindowId& id) + : type_(WINDOW), window_(id) { + } + explicit ScreencastId(const talk_base::DesktopId& id) + : type_(DESKTOP), desktop_(id) { + } + + Type type() const { return type_; } + const talk_base::WindowId& window() const { return window_; } + const talk_base::DesktopId& desktop() const { return desktop_; } + + // Title is an optional parameter. + const std::string& title() const { return title_; } + void set_title(const std::string& desc) { title_ = desc; } + + bool IsValid() const { + if (type_ == INVALID) { + return false; + } else if (type_ == WINDOW) { + return window_.IsValid(); + } else { + return desktop_.IsValid(); + } + } + bool IsWindow() const { return type_ == WINDOW; } + bool IsDesktop() const { return type_ == DESKTOP; } + bool EqualsId(const ScreencastId& other) const { + if (type_ != other.type_) { + return false; + } + if (type_ == INVALID) { + return true; + } else if (type_ == WINDOW) { + return window_.Equals(other.window()); + } + return desktop_.Equals(other.desktop()); + } + + // T is assumed to be WindowDescription or DesktopDescription. + template + static cricket::ScreencastIdList Convert(const std::vector& list) { + ScreencastIdList screencast_list; + screencast_list.reserve(list.size()); + for (typename std::vector::const_iterator it = list.begin(); + it != list.end(); ++it) { + ScreencastId id(it->id()); + id.set_title(it->title()); + screencast_list.push_back(id); + } + return screencast_list; + } + + private: + Type type_; + talk_base::WindowId window_; + talk_base::DesktopId desktop_; + std::string title_; // Optional. +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_SCREENCASTID_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/streamparams.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/streamparams.h new file mode 100644 index 0000000..7e5ea12 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/streamparams.h @@ -0,0 +1,228 @@ +/* + * 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. + */ + +// This file contains structures for describing SSRCs from a media source such +// as a MediaStreamTrack when it is sent across an RTP session. Multiple media +// sources may be sent across the same RTP session, each of them will be +// described by one StreamParams object +// SsrcGroup is used to describe the relationship between the SSRCs that +// are used for this media source. +// E.x: Consider a source that is sent as 3 simulcast streams +// Let the simulcast elements have SSRC 10, 20, 30. +// Let each simulcast element use FEC and let the protection packets have +// SSRC 11,21,31. +// To describe this 4 SsrcGroups are needed, +// StreamParams would then contain ssrc = {10,11,20,21,30,31} and +// ssrc_groups = {{SIM,{10,20,30}, {FEC,{10,11}, {FEC, {20,21}, {FEC {30,31}}} +// Please see RFC 5576. + +#ifndef TALK_MEDIA_BASE_STREAMPARAMS_H_ +#define TALK_MEDIA_BASE_STREAMPARAMS_H_ + +#include +#include +#include +#include + +#include "talk/base/basictypes.h" + +namespace cricket { + +extern const char kFecSsrcGroupSemantics[]; +extern const char kFidSsrcGroupSemantics[]; +extern const char kSimSsrcGroupSemantics[]; + +struct SsrcGroup { + SsrcGroup(const std::string& usage, const std::vector& ssrcs) + : semantics(usage), ssrcs(ssrcs) { + } + + bool operator==(const SsrcGroup& other) const { + return (semantics == other.semantics && ssrcs == other.ssrcs); + } + bool operator!=(const SsrcGroup &other) const { + return !(*this == other); + } + + bool has_semantics(const std::string& semantics) const; + + std::string ToString() const; + + std::string semantics; // e.g FIX, FEC, SIM. + std::vector ssrcs; // SSRCs of this type. +}; + +struct StreamParams { + static StreamParams CreateLegacy(uint32 ssrc) { + StreamParams stream; + stream.ssrcs.push_back(ssrc); + return stream; + } + + bool operator==(const StreamParams& other) const { + return (groupid == other.groupid && + id == other.id && + ssrcs == other.ssrcs && + ssrc_groups == other.ssrc_groups && + type == other.type && + display == other.display && + cname == other.cname && + sync_label == other.sync_label); + } + bool operator!=(const StreamParams &other) const { + return !(*this == other); + } + + uint32 first_ssrc() const { + if (ssrcs.empty()) { + return 0; + } + + return ssrcs[0]; + } + bool has_ssrcs() const { + return !ssrcs.empty(); + } + bool has_ssrc(uint32 ssrc) const { + return std::find(ssrcs.begin(), ssrcs.end(), ssrc) != ssrcs.end(); + } + void add_ssrc(uint32 ssrc) { + ssrcs.push_back(ssrc); + } + bool has_ssrc_groups() const { + return !ssrc_groups.empty(); + } + bool has_ssrc_group(const std::string& semantics) const { + return (get_ssrc_group(semantics) != NULL); + } + const SsrcGroup* get_ssrc_group(const std::string& semantics) const { + for (std::vector::const_iterator it = ssrc_groups.begin(); + it != ssrc_groups.end(); ++it) { + if (it->has_semantics(semantics)) { + return &(*it); + } + } + return NULL; + } + + // Convenience function to add an FID ssrc for a primary_ssrc + // that's already been added. + inline bool AddFidSsrc(uint32 primary_ssrc, uint32 fid_ssrc) { + return AddSecondarySsrc(kFidSsrcGroupSemantics, primary_ssrc, fid_ssrc); + } + + // Convenience function to lookup the FID ssrc for a primary_ssrc. + // Returns false if primary_ssrc not found or FID not defined for it. + inline bool GetFidSsrc(uint32 primary_ssrc, uint32* fid_ssrc) const { + return GetSecondarySsrc(kFidSsrcGroupSemantics, primary_ssrc, fid_ssrc); + } + + std::string ToString() const; + + // Resource of the MUC jid of the participant of with this stream. + // For 1:1 calls, should be left empty (which means remote streams + // and local streams should not be mixed together). + std::string groupid; + // Unique per-groupid, not across all groupids + std::string id; + std::vector ssrcs; // All SSRCs for this source + std::vector ssrc_groups; // e.g. FID, FEC, SIM + // Examples: "camera", "screencast" + std::string type; + // Friendly name describing stream + std::string display; + std::string cname; // RTCP CNAME + std::string sync_label; // Friendly name of cname. + + private: + bool AddSecondarySsrc(const std::string& semantics, uint32 primary_ssrc, + uint32 secondary_ssrc); + bool GetSecondarySsrc(const std::string& semantics, uint32 primary_ssrc, + uint32* secondary_ssrc) const; +}; + +// A Stream can be selected by either groupid+id or ssrc. +struct StreamSelector { + explicit StreamSelector(uint32 ssrc) : + ssrc(ssrc) { + } + + StreamSelector(const std::string& groupid, + const std::string& streamid) : + ssrc(0), + groupid(groupid), + streamid(streamid) { + } + + bool Matches(const StreamParams& stream) const { + if (ssrc == 0) { + return stream.groupid == groupid && stream.id == streamid; + } else { + return stream.has_ssrc(ssrc); + } + } + + uint32 ssrc; + std::string groupid; + std::string streamid; +}; + +typedef std::vector StreamParamsVec; + +// Finds the stream in streams. Returns true if found. +bool GetStream(const StreamParamsVec& streams, + const StreamSelector& selector, + StreamParams* stream_out); +bool GetStreamBySsrc(const StreamParamsVec& streams, uint32 ssrc, + StreamParams* stream_out); +bool GetStreamByIds(const StreamParamsVec& streams, + const std::string& groupid, + const std::string& id, + StreamParams* stream_out); + +// Removes the stream from streams. Returns true if a stream is +// found and removed. +bool RemoveStream(StreamParamsVec* streams, + const StreamSelector& selector); +bool RemoveStreamBySsrc(StreamParamsVec* streams, uint32 ssrc); +bool RemoveStreamByIds(StreamParamsVec* streams, + const std::string& groupid, + const std::string& id); + +// Checks if |sp| defines parameters for a single primary stream. There may +// be an RTX stream associated with the primary stream. Leaving as non-static so +// we can test this function. +bool IsOneSsrcStream(const StreamParams& sp); + +// Checks if |sp| defines parameters for one Simulcast stream. There may be RTX +// streams associated with the simulcast streams. Leaving as non-static so we +// can test this function. +bool IsSimulcastStream(const StreamParams& sp); + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_STREAMPARAMS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/testutils.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/testutils.h new file mode 100644 index 0000000..6c2b873 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/testutils.h @@ -0,0 +1,252 @@ +/* + * 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_BASE_TESTUTILS_H_ +#define TALK_MEDIA_BASE_TESTUTILS_H_ + +#include +#include + +#if !defined(DISABLE_YUV) +#include "libyuv/compare.h" +#endif +#include "talk/base/basictypes.h" +#include "talk/base/sigslot.h" +#include "talk/base/window.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/videocapturer.h" +#include "talk/media/base/videocommon.h" + +namespace talk_base { +class ByteBuffer; +class StreamInterface; +} + +namespace cricket { + +// Returns size of 420 image with rounding on chroma for odd sizes. +#define I420_SIZE(w, h) (w * h + (((w + 1) / 2) * ((h + 1) / 2)) * 2) +// Returns size of ARGB image. +#define ARGB_SIZE(w, h) (w * h * 4) + +template inline std::vector MakeVector(const T a[], size_t s) { + return std::vector(a, a + s); +} +#define MAKE_VECTOR(a) cricket::MakeVector(a, ARRAY_SIZE(a)) + +struct RtpDumpPacket; +class RtpDumpWriter; +class VideoFrame; + +struct RawRtpPacket { + void WriteToByteBuffer(uint32 in_ssrc, talk_base::ByteBuffer* buf) const; + bool ReadFromByteBuffer(talk_base::ByteBuffer* buf); + // Check if this packet is the same as the specified packet except the + // sequence number and timestamp, which should be the same as the specified + // parameters. + bool SameExceptSeqNumTimestampSsrc( + const RawRtpPacket& packet, uint16 seq, uint32 ts, uint32 ssc) const; + int size() const { return 28; } + + uint8 ver_to_cc; + uint8 m_to_pt; + uint16 sequence_number; + uint32 timestamp; + uint32 ssrc; + char payload[16]; +}; + +struct RawRtcpPacket { + void WriteToByteBuffer(talk_base::ByteBuffer* buf) const; + bool ReadFromByteBuffer(talk_base::ByteBuffer* buf); + bool EqualsTo(const RawRtcpPacket& packet) const; + + uint8 ver_to_count; + uint8 type; + uint16 length; + char payload[16]; +}; + +class RtpTestUtility { + public: + static size_t GetTestPacketCount(); + + // Write the first count number of kTestRawRtcpPackets or kTestRawRtpPackets, + // depending on the flag rtcp. If it is RTP, use the specified SSRC. Return + // true if successful. + static bool WriteTestPackets( + size_t count, bool rtcp, uint32 rtp_ssrc, RtpDumpWriter* writer); + + // Loop read the first count number of packets from the specified stream. + // Verify the elapsed time of the dump packets increase monotonically. If the + // stream is a RTP stream, verify the RTP sequence number, timestamp, and + // payload. If the stream is a RTCP stream, verify the RTCP header and + // payload. + static bool VerifyTestPacketsFromStream( + size_t count, talk_base::StreamInterface* stream, uint32 ssrc); + + // Verify the dump packet is the same as the raw RTP packet. + static bool VerifyPacket(const RtpDumpPacket* dump, + const RawRtpPacket* raw, + bool header_only); + + static const uint32 kDefaultSsrc = 1; + static const uint32 kRtpTimestampIncrease = 90; + static const uint32 kDefaultTimeIncrease = 30; + static const uint32 kElapsedTimeInterval = 10; + static const RawRtpPacket kTestRawRtpPackets[]; + static const RawRtcpPacket kTestRawRtcpPackets[]; + + private: + RtpTestUtility() {} +}; + +// Test helper for testing VideoCapturer implementations. +class VideoCapturerListener : public sigslot::has_slots<> { + public: + explicit VideoCapturerListener(VideoCapturer* cap); + + CaptureState last_capture_state() const { return last_capture_state_; } + int frame_count() const { return frame_count_; } + uint32 frame_fourcc() const { return frame_fourcc_; } + int frame_width() const { return frame_width_; } + int frame_height() const { return frame_height_; } + uint32 frame_size() const { return frame_size_; } + bool resolution_changed() const { return resolution_changed_; } + + void OnStateChange(VideoCapturer* capturer, CaptureState state); + void OnFrameCaptured(VideoCapturer* capturer, const CapturedFrame* frame); + + private: + CaptureState last_capture_state_; + int frame_count_; + uint32 frame_fourcc_; + int frame_width_; + int frame_height_; + uint32 frame_size_; + bool resolution_changed_; +}; + +class ScreencastEventCatcher : public sigslot::has_slots<> { + public: + ScreencastEventCatcher() : ssrc_(0), ev_(talk_base::WE_RESIZE) { } + uint32 ssrc() const { return ssrc_; } + talk_base::WindowEvent event() const { return ev_; } + void OnEvent(uint32 ssrc, talk_base::WindowEvent ev) { + ssrc_ = ssrc; + ev_ = ev; + } + private: + uint32 ssrc_; + talk_base::WindowEvent ev_; +}; + +class VideoMediaErrorCatcher : public sigslot::has_slots<> { + public: + VideoMediaErrorCatcher() : ssrc_(0), error_(VideoMediaChannel::ERROR_NONE) { } + uint32 ssrc() const { return ssrc_; } + VideoMediaChannel::Error error() const { return error_; } + void OnError(uint32 ssrc, VideoMediaChannel::Error error) { + ssrc_ = ssrc; + error_ = error; + } + private: + uint32 ssrc_; + VideoMediaChannel::Error error_; +}; + +// Returns the absolute path to a file in the testdata/ directory. +std::string GetTestFilePath(const std::string& filename); + +// PSNR formula: psnr = 10 * log10 (Peak Signal^2 / mse) +// sse is set to a small number for identical frames or sse == 0 +static inline double ComputePSNR(double sse, double count) { +#if !defined(DISABLE_YUV) + return libyuv::SumSquareErrorToPsnr(static_cast(sse), + static_cast(count)); +#else + if (sse <= 0.) + sse = 65025.0 * count / pow(10., 128./10.); // produces max PSNR of 128 + return 10.0 * log10(65025.0 * count / sse); +#endif +} + +static inline double ComputeSumSquareError(const uint8 *org, const uint8 *rec, + int size) { +#if !defined(DISABLE_YUV) + return static_cast(libyuv::ComputeSumSquareError(org, rec, size)); +#else + double sse = 0.; + for (int j = 0; j < size; ++j) { + const int diff = static_cast(org[j]) - static_cast(rec[j]); + sse += static_cast(diff * diff); + } + return sse; +#endif +} + +// Loads the image with the specified prefix and size into |out|. +bool LoadPlanarYuvTestImage(const std::string& prefix, + int width, int height, uint8* out); + +// Dumps the YUV image out to a file, for visual inspection. +// PYUV tool can be used to view dump files. +void DumpPlanarYuvTestImage(const std::string& prefix, const uint8* img, + int w, int h); + +// Dumps the ARGB image out to a file, for visual inspection. +// ffplay tool can be used to view dump files. +void DumpPlanarArgbTestImage(const std::string& prefix, const uint8* img, + int w, int h); + +// Compare two I420 frames. +bool VideoFrameEqual(const VideoFrame* frame0, const VideoFrame* frame1); + +// Checks whether |codecs| contains |codec|; checks using Codec::Matches(). +template +bool ContainsMatchingCodec(const std::vector& codecs, const C& codec) { + typename std::vector::const_iterator it; + for (it = codecs.begin(); it != codecs.end(); ++it) { + if (it->Matches(codec)) { + return true; + } + } + return false; +} + +// Create Simulcast StreamParams with given |ssrcs| and |cname|. +cricket::StreamParams CreateSimStreamParams( + const std::string& cname, const std::vector& ssrcs); +// Create Simulcast stream with given |ssrcs| and |rtx_ssrcs|. +// The number of |rtx_ssrcs| must match number of |ssrcs|. +cricket::StreamParams CreateSimWithRtxStreamParams( + const std::string& cname, const std::vector& ssrcs, + const std::vector& rtx_ssrcs); + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_TESTUTILS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/videoadapter.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/videoadapter.h new file mode 100644 index 0000000..0742956 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/videoadapter.h @@ -0,0 +1,214 @@ +// 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. + +#ifndef TALK_MEDIA_BASE_VIDEOADAPTER_H_ // NOLINT +#define TALK_MEDIA_BASE_VIDEOADAPTER_H_ + +#include "talk/base/common.h" // For ASSERT +#include "talk/base/criticalsection.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sigslot.h" +#include "talk/media/base/videocommon.h" + +namespace cricket { + +class VideoFrame; + +// VideoAdapter adapts an input video frame to an output frame based on the +// specified input and output formats. The adaptation includes dropping frames +// to reduce frame rate and scaling frames. VideoAdapter is thread safe. +class VideoAdapter { + public: + VideoAdapter(); + virtual ~VideoAdapter(); + + virtual void SetInputFormat(const VideoFormat& format); + void SetOutputFormat(const VideoFormat& format); + // Constrain output resolution to this many pixels overall + void SetOutputNumPixels(int num_pixels); + 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); + + // Adapt the input frame from the input format to the output format. Return + // 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); + bool scale_third() const { return scale_third_; } + + protected: + float FindClosestScale(int width, int height, int target_num_pixels); + float FindClosestViewScale(int width, int height, int target_num_pixels); + float FindLowerScale(int width, int height, int target_num_pixels); + + private: + const float* GetViewScaleFactors() const; + float FindScale(const float* scale_factors, + const float upbias, int width, int height, + int target_num_pixels); + bool StretchToOutputFrame(const VideoFrame* in_frame); + + VideoFormat input_format_; + VideoFormat output_format_; + int output_num_pixels_; + bool scale_third_; // True if adapter allows scaling to 1/3 and 2/3. + 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. + bool black_output_; // Flag to tell if we need to black output_frame_. + bool is_black_; // Flag to tell if output_frame_ is currently black. + int64 interval_next_frame_; + talk_base::scoped_ptr output_frame_; + // The critical section to protect the above variables. + talk_base::CriticalSection critical_section_; + + DISALLOW_COPY_AND_ASSIGN(VideoAdapter); +}; + +// CoordinatedVideoAdapter adapts the video input to the encoder by coordinating +// the format request from the server, the resolution request from the encoder, +// and the CPU load. +class CoordinatedVideoAdapter + : public VideoAdapter, public sigslot::has_slots<> { + public: + enum AdaptRequest { UPGRADE, KEEP, DOWNGRADE }; + enum AdaptReasonEnum { + ADAPTREASON_NONE = 0, + ADAPTREASON_CPU = 1, + ADAPTREASON_BANDWIDTH = 2, + ADAPTREASON_VIEW = 4 + }; + typedef int AdaptReason; + + CoordinatedVideoAdapter(); + virtual ~CoordinatedVideoAdapter() {} + + virtual void SetInputFormat(const VideoFormat& format); + + // Enable or disable video adaptation due to the change of the CPU load. + void set_cpu_adaptation(bool enable) { cpu_adaptation_ = enable; } + bool cpu_adaptation() const { return cpu_adaptation_; } + // 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); + 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; } + bool gd_adaptation() const { return gd_adaptation_; } + // Enable or disable video adaptation due to the change of the View + void set_view_adaptation(bool enable) { view_adaptation_ = enable; } + bool view_adaptation() const { return view_adaptation_; } + // Enable or disable video adaptation to fast switch View + void set_view_switch(bool enable) { view_switch_ = enable; } + bool view_switch() const { return view_switch_; } + + CoordinatedVideoAdapter::AdaptReason adapt_reason() const { + return adapt_reason_; + } + + // When the video is decreased, set the waiting time for CPU adaptation to + // decrease video again. + 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); + 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); + 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); + float process_threshold() const { return process_threshold_; } + + // Handle the format request from the server via Jingle update message. + void OnOutputFormatRequest(const VideoFormat& format); + // Handle the resolution request from the encoder due to bandwidth changes. + void OnEncoderResolutionRequest(int width, int height, AdaptRequest request); + // Handle the resolution request for CPU overuse. + void OnCpuResolutionRequest(AdaptRequest request); + // Handle the CPU load provided by a CPU monitor. + void OnCpuLoadUpdated(int current_cpus, int max_cpus, + float process_load, float system_load); + + sigslot::signal0<> SignalCpuAdaptationUnable; + + private: + // Adapt to the minimum of the formats the server requests, the CPU wants, and + // the encoder wants. Returns true if resolution changed. + bool AdaptToMinimumFormat(int* new_width, int* new_height); + bool IsMinimumFormat(int pixels); + void StepPixelCount(CoordinatedVideoAdapter::AdaptRequest request, + int* num_pixels); + CoordinatedVideoAdapter::AdaptRequest FindCpuRequest( + int current_cpus, int max_cpus, + float process_load, float system_load); + + bool cpu_adaptation_; // True if cpu adaptation is enabled. + bool cpu_smoothing_; // True if cpu smoothing is enabled (with adaptation). + bool gd_adaptation_; // True if gd adaptation is enabled. + bool view_adaptation_; // True if view adaptation is enabled. + bool view_switch_; // True if view switch is enabled. + int cpu_downgrade_count_; + 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_; + // cpu process load thresholds relative to current cpus. + float process_threshold_; + // Video formats that the server view requests, the CPU wants, and the encoder + // wants respectively. The adapted output format is the minimum of these. + int view_desired_num_pixels_; + int64 view_desired_interval_; + int encoder_desired_num_pixels_; + int cpu_desired_num_pixels_; + CoordinatedVideoAdapter::AdaptReason adapt_reason_; + // The critical section to protect handling requests. + talk_base::CriticalSection request_critical_section_; + + // The weighted average of cpu load over time. It's always updated (if cpu + // adaptation is on), but only used if cpu_smoothing_ is set. + float system_load_average_; + + DISALLOW_COPY_AND_ASSIGN(CoordinatedVideoAdapter); +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_VIDEOADAPTER_H_ // NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/videocapturer.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/videocapturer.h new file mode 100644 index 0000000..77ed0d4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/videocapturer.h @@ -0,0 +1,402 @@ +// 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. +// +// Declaration of abstract class VideoCapturer + +#ifndef TALK_MEDIA_BASE_VIDEOCAPTURER_H_ +#define TALK_MEDIA_BASE_VIDEOCAPTURER_H_ + +#include +#include + +#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" + + +namespace cricket { + +class VideoProcessor; + +// Current state of the capturer. +// TODO(hellner): CS_NO_DEVICE is an error code not a capture state. Separate +// error codes and states. +enum CaptureState { + CS_STOPPED, // The capturer has been stopped or hasn't started yet. + CS_STARTING, // The capturer is in the process of starting. Note, it may + // still fail to start. + CS_RUNNING, // The capturer has been started successfully and is now + // capturing. + CS_PAUSED, // The capturer has been paused. + CS_FAILED, // The capturer failed to start. + CS_NO_DEVICE, // The capturer has no device and consequently failed to start. +}; + +class VideoFrame; + +struct CapturedFrame { + static const uint32 kFrameHeaderSize = 40; // Size from width to data_size. + static const uint32 kUnknownDataSize = 0xFFFFFFFF; + + CapturedFrame(); + + // Get the number of bytes of the frame data. If data_size is known, return + // it directly. Otherwise, calculate the size based on width, height, and + // fourcc. Return true if succeeded. + bool GetDataSize(uint32* size) const; + + // The width and height of the captured frame could be different from those + // of VideoFormat. Once the first frame is captured, the width, height, + // fourcc, pixel_width, and pixel_height should keep the same over frames. + int width; // in number of pixels + int height; // in number of pixels + uint32 fourcc; // compression + uint32 pixel_width; // width of a pixel, default is 1 + uint32 pixel_height; // height of a pixel, default is 1 + int64 elapsed_time; // elapsed time since the creation of the frame + // source (that is, the camera), in nanoseconds. + int64 time_stamp; // timestamp of when the frame was captured, in unix + // time with nanosecond units. + uint32 data_size; // number of bytes of the frame data + int rotation; // rotation in degrees of the frame (0, 90, 180, 270) + void* data; // pointer to the frame data. This object allocates the + // memory or points to an existing memory. + + private: + DISALLOW_COPY_AND_ASSIGN(CapturedFrame); +}; + +// VideoCapturer is an abstract class that defines the interfaces for video +// 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). +// 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 +// Initialize +// SignalStateChange.connect() +// 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() +// +// Assumption: +// The Start() and Stop() methods are called by a single thread (E.g., the +// media engine thread). Hence, the VideoCapture subclasses dont need to be +// thread safe. +// +class VideoCapturer + : public sigslot::has_slots<>, + public talk_base::MessageHandler { + public: + typedef std::vector VideoProcessors; + + // All signals are marshalled to |thread| or the creating thread if + // none is provided. + VideoCapturer(); + explicit VideoCapturer(talk_base::Thread* thread); + virtual ~VideoCapturer() {} + + // Gets the id of the underlying device, which is available after the capturer + // is initialized. Can be used to determine if two capturers reference the + // same device. + const std::string& GetId() const { return id_; } + + // Get the capture formats supported by the video capturer. The supported + // formats are non empty after the device has been opened successfully. + const std::vector* GetSupportedFormats() const; + + // Get the best capture format for the desired format. The best format is the + // same as one of the supported formats except that the frame interval may be + // different. If the application asks for 16x9 and the camera does not support + // 16x9 HD or the application asks for 16x10, we find the closest 4x3 and then + // crop; Otherwise, we find what the application asks for. Note that we assume + // that for HD, the desired format is always 16x9. The subclasses can override + // the default implementation. + // Parameters + // desired: the input desired format. If desired.fourcc is not kAnyFourcc, + // the best capture format has the exactly same fourcc. Otherwise, + // the best capture format uses a fourcc in GetPreferredFourccs(). + // best_format: the output of the best capture format. + // Return false if there is no such a best format, that is, the desired format + // is not supported. + virtual bool GetBestCaptureFormat(const VideoFormat& desired, + VideoFormat* best_format); + + // TODO(hellner): deprecate (make private) the Start API in favor of this one. + // Also remove CS_STARTING as it is implied by the return + // value of StartCapturing(). + bool StartCapturing(const VideoFormat& capture_format); + // Start the video capturer with the specified capture format. + // Parameter + // capture_format: The caller got this parameter by either calling + // GetSupportedFormats() and selecting one of the supported + // or calling GetBestCaptureFormat(). + // Return + // CS_STARTING: The capturer is trying to start. Success or failure will + // be notified via the |SignalStateChange| callback. + // CS_RUNNING: if the capturer is started and capturing. + // CS_PAUSED: Will never be returned. + // CS_FAILED: if the capturer failes to start.. + // CS_NO_DEVICE: if the capturer has no device and fails to start. + virtual CaptureState Start(const VideoFormat& capture_format) = 0; + // Sets the desired aspect ratio. If the capturer is capturing at another + // aspect ratio it will crop the width or the height so that asked for + // aspect ratio is acheived. Note that ratio_w and ratio_h do not need to be + // relatively prime. + void UpdateAspectRatio(int ratio_w, int ratio_h); + void ClearAspectRatio(); + + // Get the current capture format, which is set by the Start() call. + // Note that the width and height of the captured frames may differ from the + // capture format. For example, the capture format is HD but the captured + // frames may be smaller than HD. + const VideoFormat* GetCaptureFormat() const { + return capture_format_.get(); + } + + // Pause the video capturer. + virtual bool Pause(bool paused); + // Stop the video capturer. + virtual void Stop() = 0; + // Check if the video capturer is running. + virtual bool IsRunning() = 0; + // Restart the video capturer with the new |capture_format|. + // Default implementation stops and starts the capturer. + virtual bool Restart(const VideoFormat& capture_format); + // TODO(thorcarpenter): This behavior of keeping the camera open just to emit + // black frames is a total hack and should be fixed. + // When muting, produce black frames then pause the camera. + // When unmuting, start the camera. Camera starts unmuted. + virtual bool MuteToBlackThenPause(bool muted); + virtual bool IsMuted() const { + return muted_; + } + CaptureState capture_state() const { + return capture_state_; + } + + // Adds a video processor that will be applied on VideoFrames returned by + // |SignalVideoFrame|. Multiple video processors can be added. The video + // processors will be applied in the order they were added. + void AddVideoProcessor(VideoProcessor* video_processor); + // Removes the |video_processor| from the list of video processors or + // returns false. + bool RemoveVideoProcessor(VideoProcessor* video_processor); + + // Returns true if the capturer is screencasting. This can be used to + // implement screencast specific behavior. + virtual bool IsScreencast() const = 0; + + // Caps the VideoCapturer's format according to max_format. It can e.g. be + // used to prevent cameras from capturing at a resolution or framerate that + // the capturer is capable of but not performing satisfactorily at. + // The capping is an upper bound for each component of the capturing format. + // The fourcc component is ignored. + void ConstrainSupportedFormats(const VideoFormat& max_format); + + void set_enable_camera_list(bool enable_camera_list) { + enable_camera_list_ = enable_camera_list; + } + bool enable_camera_list() { + return enable_camera_list_; + } + + // Enable scaling to ensure square pixels. + void set_square_pixel_aspect_ratio(bool square_pixel_aspect_ratio) { + square_pixel_aspect_ratio_ = square_pixel_aspect_ratio; + } + bool square_pixel_aspect_ratio() { + return square_pixel_aspect_ratio_; + } + + // Signal all capture state changes that are not a direct result of calling + // Start(). + sigslot::signal2 SignalStateChange; + // Frame callbacks are multithreaded to allow disconnect and connect to be + // called concurrently. It also ensures that it is safe to call disconnect + // at any time which is needed since the signal may be called from an + // unmarshalled thread owned by the VideoCapturer. + // Signal the captured frame to downstream. + sigslot::signal2 SignalFrameCaptured; + // Signal the captured and possibly adapted frame to downstream consumers + // such as the encoder. + sigslot::signal2 SignalVideoFrame; + + const VideoProcessors& video_processors() const { return video_processors_; } + + // If 'screencast_max_pixels' is set greater than zero, screencasts will be + // scaled to be no larger than this value. + // If set to zero, the max pixels will be limited to + // Retina MacBookPro 15" resolution of 2880 x 1800. + // For high fps, maximum pixels limit is set based on common 24" monitor + // resolution of 2048 x 1280. + int screencast_max_pixels() const { return screencast_max_pixels_; } + void set_screencast_max_pixels(int p) { + 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* adapt_drop_stats, + VariableInfo* effect_drop_stats, + VariableInfo* frame_time_stats, + VideoFormat* last_captured_frame_format); + + protected: + // Callback attached to SignalFrameCaptured where SignalVideoFrames is called. + void OnFrameCaptured(VideoCapturer* video_capturer, + const CapturedFrame* captured_frame); + void SetCaptureState(CaptureState state); + + // Marshals SignalStateChange onto thread_. + void OnMessage(talk_base::Message* message); + + // subclasses override this virtual method to provide a vector of fourccs, in + // order of preference, that are expected by the media engine. + virtual bool GetPreferredFourccs(std::vector* fourccs) = 0; + + // mutators to set private attributes + void SetId(const std::string& id) { + id_ = id; + } + + 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& formats); + + private: + void Construct(); + // Get the distance between the desired format and the supported format. + // Return the max distance if they mismatch. See the implementation for + // details. + int64 GetFormatDistance(const VideoFormat& desired, + const VideoFormat& supported); + + // Convert captured frame to readable string for LOG messages. + std::string ToString(const CapturedFrame* frame) const; + + // Applies all registered processors. If any of the processors signal that + // the frame should be dropped the return value will be false. Note that + // this frame should be dropped as it has not applied all processors. + bool ApplyProcessors(VideoFrame* video_frame); + + // Updates filtered_supported_formats_ so that it contains the formats in + // supported_formats_ that fulfill all applied restrictions. + void UpdateFilteredSupportedFormats(); + // 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 + static void GetVariableSnapshot( + const talk_base::RollingAccumulator& data, + VariableInfo* stats); + + talk_base::Thread* thread_; + std::string id_; + CaptureState capture_state_; + talk_base::scoped_ptr capture_format_; + std::vector supported_formats_; + talk_base::scoped_ptr max_format_; + std::vector filtered_supported_formats_; + + int ratio_w_; // View resolution. e.g. 1280 x 720. + int ratio_h_; + bool enable_camera_list_; + bool square_pixel_aspect_ratio_; // Enable scaling to square pixels. + int scaled_width_; // Current output size from ComputeScale. + int scaled_height_; + int screencast_max_pixels_; // Downscale screencasts further if requested. + 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 adapt_frame_drops_data_; + int effect_frame_drops_; + talk_base::RollingAccumulator effect_frame_drops_data_; + double previous_frame_time_; + talk_base::RollingAccumulator frame_time_data_; + // The captured frame format before potential adapation. + VideoFormat last_captured_frame_format_; + + talk_base::CriticalSection crit_; + VideoProcessors video_processors_; + + DISALLOW_COPY_AND_ASSIGN(VideoCapturer); +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_VIDEOCAPTURER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/videocommon.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/videocommon.h new file mode 100644 index 0000000..a6926a4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/videocommon.h @@ -0,0 +1,265 @@ +// 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. +// +// Common definition for video, including fourcc and VideoFormat. + +#ifndef TALK_MEDIA_BASE_VIDEOCOMMON_H_ // NOLINT +#define TALK_MEDIA_BASE_VIDEOCOMMON_H_ + +#include + +#include "talk/base/basictypes.h" +#include "talk/base/timeutils.h" + +namespace cricket { + +// TODO(janahan): For now, a hard-coded ssrc is used as the video ssrc. +// This is because when the video frame is passed to the mediaprocessor for +// processing, it doesn't have the correct ssrc. Since currently only Tx +// Video processing is supported, this is ok. When we switch over to trigger +// from capturer, this should be fixed and this const removed. +const uint32 kDummyVideoSsrc = 0xFFFFFFFF; + +// Minimum interval is 10k fps. +#define FPS_TO_INTERVAL(fps) \ + (fps ? talk_base::kNumNanosecsPerSec / fps : \ + talk_base::kNumNanosecsPerSec / 10000) + +////////////////////////////////////////////////////////////////////////////// +// Definition of FourCC codes +////////////////////////////////////////////////////////////////////////////// +// Convert four characters to a FourCC code. +// Needs to be a macro otherwise the OS X compiler complains when the kFormat* +// constants are used in a switch. +#define FOURCC(a, b, c, d) ( \ + (static_cast(a)) | (static_cast(b) << 8) | \ + (static_cast(c) << 16) | (static_cast(d) << 24)) +// Some pages discussing FourCC codes: +// http://www.fourcc.org/yuv.php +// http://v4l2spec.bytesex.org/spec/book1.htm +// http://developer.apple.com/quicktime/icefloe/dispatch020.html +// http://msdn.microsoft.com/library/windows/desktop/dd206750.aspx#nv12 +// http://people.xiph.org/~xiphmont/containers/nut/nut4cc.txt + +// FourCC codes grouped according to implementation efficiency. +// Primary formats should convert in 1 efficient step. +// Secondary formats are converted in 2 steps. +// Auxilliary formats call primary converters. +enum FourCC { + // 9 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. + FOURCC_I420 = FOURCC('I', '4', '2', '0'), + FOURCC_I422 = FOURCC('I', '4', '2', '2'), + FOURCC_I444 = FOURCC('I', '4', '4', '4'), + FOURCC_I411 = FOURCC('I', '4', '1', '1'), + FOURCC_I400 = FOURCC('I', '4', '0', '0'), + FOURCC_NV21 = FOURCC('N', 'V', '2', '1'), + FOURCC_NV12 = FOURCC('N', 'V', '1', '2'), + FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'), + FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'), + + // 2 Secondary YUV formats: row biplanar. + FOURCC_M420 = FOURCC('M', '4', '2', '0'), + FOURCC_Q420 = FOURCC('Q', '4', '2', '0'), + + // 9 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp. + FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'), + FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'), + FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'), + FOURCC_24BG = FOURCC('2', '4', 'B', 'G'), + FOURCC_RAW = FOURCC('r', 'a', 'w', ' '), + FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'), + FOURCC_RGBP = FOURCC('R', 'G', 'B', 'P'), // bgr565. + FOURCC_RGBO = FOURCC('R', 'G', 'B', 'O'), // abgr1555. + FOURCC_R444 = FOURCC('R', '4', '4', '4'), // argb4444. + + // 4 Secondary RGB formats: 4 Bayer Patterns. + FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'), + FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'), + FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'), + FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'), + + // 1 Primary Compressed YUV format. + FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'), + + // 5 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias. + FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'), + FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'), + FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'), + FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'), // Linux version of I420. + FOURCC_J420 = FOURCC('J', '4', '2', '0'), + FOURCC_J400 = FOURCC('J', '4', '0', '0'), + + // 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc. + FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420. + FOURCC_YU16 = FOURCC('Y', 'U', '1', '6'), // Alias for I422. + FOURCC_YU24 = FOURCC('Y', 'U', '2', '4'), // Alias for I444. + FOURCC_YUYV = FOURCC('Y', 'U', 'Y', 'V'), // Alias for YUY2. + FOURCC_YUVS = FOURCC('y', 'u', 'v', 's'), // Alias for YUY2 on Mac. + FOURCC_HDYC = FOURCC('H', 'D', 'Y', 'C'), // Alias for UYVY. + FOURCC_2VUY = FOURCC('2', 'v', 'u', 'y'), // Alias for UYVY on Mac. + FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'), // Alias for MJPG. + FOURCC_DMB1 = FOURCC('d', 'm', 'b', '1'), // Alias for MJPG on Mac. + FOURCC_BA81 = FOURCC('B', 'A', '8', '1'), // Alias for BGGR. + FOURCC_RGB3 = FOURCC('R', 'G', 'B', '3'), // Alias for RAW. + FOURCC_BGR3 = FOURCC('B', 'G', 'R', '3'), // Alias for 24BG. + FOURCC_CM32 = FOURCC(0, 0, 0, 32), // Alias for BGRA kCMPixelFormat_32ARGB + FOURCC_CM24 = FOURCC(0, 0, 0, 24), // Alias for RAW kCMPixelFormat_24RGB + + // 1 Auxiliary compressed YUV format set aside for capturer. + FOURCC_H264 = FOURCC('H', '2', '6', '4'), + + // Match any fourcc. + FOURCC_ANY = 0xFFFFFFFF, +}; + +// Converts fourcc aliases into canonical ones. +uint32 CanonicalFourCC(uint32 fourcc); + +// Get FourCC code as a string. +inline std::string GetFourccName(uint32 fourcc) { + std::string name; + name.push_back(static_cast(fourcc & 0xFF)); + name.push_back(static_cast((fourcc >> 8) & 0xFF)); + name.push_back(static_cast((fourcc >> 16) & 0xFF)); + name.push_back(static_cast((fourcc >> 24) & 0xFF)); + return name; +} + +// Computes a scale less to fit in max_pixels while maintaining aspect ratio. +void ComputeScaleMaxPixels(int frame_width, int frame_height, int max_pixels, + int* scaled_width, int* scaled_height); + +// For low fps, max pixels limit is set to Retina MacBookPro 15" resolution of +// 2880 x 1800 as of 4/18/2013. +// For high fps, maximum pixels limit is set based on common 24" monitor +// resolution of 2048 x 1280 as of 6/13/2013. The Retina resolution is +// therefore reduced to 1440 x 900. +void ComputeScale(int frame_width, int frame_height, int fps, + int* scaled_width, int* scaled_height); + +// Compute the frame size that conversion should crop to based on aspect ratio. +// Ensures size is multiple of 2 due to I420 and conversion limitations. +void ComputeCrop(int cropped_format_width, int cropped_format_height, + int frame_width, int frame_height, + int pixel_width, int pixel_height, + int rotation, + int* cropped_width, int* cropped_height); + +// Compute the frame size that makes pixels square pixel aspect ratio. +void ComputeScaleToSquarePixels(int in_width, int in_height, + int pixel_width, int pixel_height, + int* scaled_width, int* scaled_height); + +////////////////////////////////////////////////////////////////////////////// +// Definition of VideoFormat. +////////////////////////////////////////////////////////////////////////////// + +// VideoFormat with Plain Old Data for global variables. +struct VideoFormatPod { + int width; // Number of pixels. + int height; // Number of pixels. + int64 interval; // Nanoseconds. + uint32 fourcc; // Color space. FOURCC_ANY means that any color space is OK. +}; + +struct VideoFormat : VideoFormatPod { + static const int64 kMinimumInterval = + talk_base::kNumNanosecsPerSec / 10000; // 10k fps. + + VideoFormat() { + Construct(0, 0, 0, 0); + } + + VideoFormat(int w, int h, int64 interval_ns, uint32 cc) { + Construct(w, h, interval_ns, cc); + } + + explicit VideoFormat(const VideoFormatPod& format) { + Construct(format.width, format.height, format.interval, format.fourcc); + } + + void Construct(int w, int h, int64 interval_ns, uint32 cc) { + width = w; + height = h; + interval = interval_ns; + fourcc = cc; + } + + static int64 FpsToInterval(int fps) { + return fps ? talk_base::kNumNanosecsPerSec / fps : kMinimumInterval; + } + + static int IntervalToFps(int64 interval) { + if (!interval) { + return 0; + } + return static_cast(talk_base::kNumNanosecsPerSec / interval); + } + + static float IntervalToFpsFloat(int64 interval) { + if (!interval) { + return 0.f; + } + return static_cast(talk_base::kNumNanosecsPerSec) / + static_cast(interval); + } + + bool operator==(const VideoFormat& format) const { + return width == format.width && height == format.height && + interval == format.interval && fourcc == format.fourcc; + } + + bool operator!=(const VideoFormat& format) const { + return !(*this == format); + } + + bool operator<(const VideoFormat& format) const { + return (fourcc < format.fourcc) || + (fourcc == format.fourcc && width < format.width) || + (fourcc == format.fourcc && width == format.width && + height < format.height) || + (fourcc == format.fourcc && width == format.width && + height == format.height && interval > format.interval); + } + + int framerate() const { return IntervalToFps(interval); } + + // Check if both width and height are 0. + bool IsSize0x0() const { return 0 == width && 0 == height; } + + // Check if this format is less than another one by comparing the resolution + // and frame rate. + bool IsPixelRateLess(const VideoFormat& format) const { + return width * height * framerate() < + format.width * format.height * format.framerate(); + } + + // Get a string presentation in the form of "fourcc width x height x fps" + std::string ToString() const; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_VIDEOCOMMON_H_ // NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/videoengine_unittest.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/videoengine_unittest.h new file mode 100644 index 0000000..856966b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/videoengine_unittest.h @@ -0,0 +1,1834 @@ +// libjingle +// Copyright 2004 Google Inc. All rights reserved. +// +// 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_BASE_VIDEOENGINE_UNITTEST_H_ // NOLINT +#define TALK_MEDIA_BASE_VIDEOENGINE_UNITTEST_H_ + +#include +#include + +#include "talk/base/bytebuffer.h" +#include "talk/base/gunit.h" +#include "talk/base/timeutils.h" +#include "talk/media/base/fakenetworkinterface.h" +#include "talk/media/base/fakevideocapturer.h" +#include "talk/media/base/fakevideorenderer.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/streamparams.h" + +#ifdef WIN32 +#include // NOLINT +#endif + +#define EXPECT_FRAME_WAIT(c, w, h, t) \ + EXPECT_EQ_WAIT((c), renderer_.num_rendered_frames(), (t)); \ + EXPECT_EQ((w), renderer_.width()); \ + EXPECT_EQ((h), renderer_.height()); \ + EXPECT_EQ(0, renderer_.errors()); \ + +#define EXPECT_FRAME_ON_RENDERER_WAIT(r, c, w, h, t) \ + EXPECT_EQ_WAIT((c), (r).num_rendered_frames(), (t)); \ + EXPECT_EQ((w), (r).width()); \ + EXPECT_EQ((h), (r).height()); \ + EXPECT_EQ(0, (r).errors()); \ + +#define EXPECT_GT_FRAME_ON_RENDERER_WAIT(r, c, w, h, t) \ + EXPECT_TRUE_WAIT((r).num_rendered_frames() >= (c) && \ + (w) == (r).width() && \ + (h) == (r).height(), (t)); \ + EXPECT_EQ(0, (r).errors()); \ + +static const uint32 kTimeout = 5000U; +static const uint32 kSsrc = 1234u; +static const uint32 kRtxSsrc = 4321u; +static const uint32 kSsrcs4[] = {1, 2, 3, 4}; + +inline bool IsEqualRes(const cricket::VideoCodec& a, int w, int h, int fps) { + return a.width == w && a.height == h && a.framerate == fps; +} + +inline bool IsEqualCodec(const cricket::VideoCodec& a, + const cricket::VideoCodec& b) { + return a.id == b.id && a.name == b.name && + IsEqualRes(a, b.width, b.height, b.framerate); +} + +namespace std { +inline std::ostream& operator<<(std::ostream& s, const cricket::VideoCodec& c) { + s << "{" << c.name << "(" << c.id << "), " + << c.width << "x" << c.height << "x" << c.framerate << "}"; + return s; +} +} // namespace std + +inline int TimeBetweenSend(const cricket::VideoCodec& codec) { + return static_cast( + cricket::VideoFormat::FpsToInterval(codec.framerate) / + talk_base::kNumNanosecsPerMillisec); +} + +// Fake video engine that makes it possible to test enabling and disabling +// capturer (checking that the engine state is updated and that the capturer +// is indeed capturing) without having to create a channel. It also makes it +// possible to test that the media processors are indeed being called when +// registered. +template +class VideoEngineOverride : public T { + public: + VideoEngineOverride() { + } + virtual ~VideoEngineOverride() { + } + bool is_camera_on() const { return T::GetVideoCapturer()->IsRunning(); } + void set_has_senders(bool has_senders) { + cricket::VideoCapturer* video_capturer = T::GetVideoCapturer(); + if (has_senders) { + video_capturer->SignalVideoFrame.connect(this, + &VideoEngineOverride::OnLocalFrame); + } else { + video_capturer->SignalVideoFrame.disconnect(this); + } + } + void OnLocalFrame(cricket::VideoCapturer*, + const cricket::VideoFrame*) { + } + void OnLocalFrameFormat(cricket::VideoCapturer*, + const cricket::VideoFormat*) { + } + + void TriggerMediaFrame( + uint32 ssrc, cricket::VideoFrame* frame, bool* drop_frame) { + T::SignalMediaFrame(ssrc, frame, drop_frame); + } +}; + +// Macroes that declare test functions for a given test class, before and after +// Init(). +// To use, define a test function called FooBody and pass Foo to the macro. +#define TEST_PRE_VIDEOENGINE_INIT(TestClass, func) \ + TEST_F(TestClass, func##PreInit) { \ + func##Body(); \ + } +#define TEST_POST_VIDEOENGINE_INIT(TestClass, func) \ + TEST_F(TestClass, func##PostInit) { \ + EXPECT_TRUE(engine_.Init(talk_base::Thread::Current())); \ + func##Body(); \ + engine_.Terminate(); \ + } + +template +class VideoEngineTest : public testing::Test { + protected: + // Tests starting and stopping the engine, and creating a channel. + void StartupShutdown() { + EXPECT_TRUE(engine_.Init(talk_base::Thread::Current())); + cricket::VideoMediaChannel* channel = engine_.CreateChannel(NULL); + EXPECT_TRUE(channel != NULL); + delete channel; + engine_.Terminate(); + } + +#ifdef WIN32 + // Tests that the COM reference count is not munged by the engine. + // Test to make sure LMI does not munge the CoInitialize reference count. + void CheckCoInitialize() { + // Initial refcount should be 0. + EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED)); + + // Engine should start even with COM already inited. + EXPECT_TRUE(engine_.Init(talk_base::Thread::Current())); + engine_.Terminate(); + // Refcount after terminate should be 1; this tests if it is nonzero. + EXPECT_EQ(S_FALSE, CoInitializeEx(NULL, COINIT_MULTITHREADED)); + // Decrement refcount to (hopefully) 0. + CoUninitialize(); + CoUninitialize(); + + // Ensure refcount is 0. + EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED)); + CoUninitialize(); + } +#endif + + void ConstrainNewCodecBody() { + cricket::VideoCodec empty, in, out; + cricket::VideoCodec max_settings(engine_.codecs()[0].id, + engine_.codecs()[0].name, + 1280, 800, 30, 0); + + // set max settings of 1280x960x30 + EXPECT_TRUE(engine_.SetDefaultEncoderConfig( + cricket::VideoEncoderConfig(max_settings))); + + // don't constrain the max resolution + in = max_settings; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED2(IsEqualCodec, out, in); + + // constrain resolution greater than the max and wider aspect, + // picking best aspect (16:10) + in.width = 1380; + in.height = 800; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30); + + // constrain resolution greater than the max and narrow aspect, + // picking best aspect (16:9) + in.width = 1280; + in.height = 740; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30); + + // constrain resolution greater than the max, picking equal aspect (4:3) + in.width = 1280; + in.height = 960; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30); + + // constrain resolution greater than the max, picking equal aspect (16:10) + in.width = 1280; + in.height = 800; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30); + + // reduce max settings to 640x480x30 + max_settings.width = 640; + max_settings.height = 480; + EXPECT_TRUE(engine_.SetDefaultEncoderConfig( + cricket::VideoEncoderConfig(max_settings))); + + // don't constrain the max resolution + in = max_settings; + in.width = 640; + in.height = 480; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED2(IsEqualCodec, out, in); + + // keep 16:10 if they request it + in.height = 400; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED2(IsEqualCodec, out, in); + + // don't constrain lesser 4:3 resolutions + in.width = 320; + in.height = 240; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED2(IsEqualCodec, out, in); + + // don't constrain lesser 16:10 resolutions + in.width = 320; + in.height = 200; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED2(IsEqualCodec, out, in); + + // requested resolution of 0x0 succeeds + in.width = 0; + in.height = 0; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED2(IsEqualCodec, out, in); + + // constrain resolution lesser than the max and wider aspect, + // picking best aspect (16:9) + in.width = 350; + in.height = 201; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 320, 180, 30); + + // constrain resolution greater than the max and narrow aspect, + // picking best aspect (4:3) + in.width = 350; + in.height = 300; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 320, 240, 30); + + // constrain resolution greater than the max and wider aspect, + // picking best aspect (16:9) + in.width = 1380; + in.height = 800; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 360, 30); + + // constrain resolution greater than the max and narrow aspect, + // picking best aspect (4:3) + in.width = 1280; + in.height = 900; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 480, 30); + + // constrain resolution greater than the max, picking equal aspect (4:3) + in.width = 1280; + in.height = 960; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 480, 30); + + // constrain resolution greater than the max, picking equal aspect (16:10) + in.width = 1280; + in.height = 800; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); + + // constrain res & fps greater than the max + in.framerate = 50; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); + + // reduce max settings to 160x100x10 + max_settings.width = 160; + max_settings.height = 100; + max_settings.framerate = 10; + EXPECT_TRUE(engine_.SetDefaultEncoderConfig( + cricket::VideoEncoderConfig(max_settings))); + + // constrain res & fps to new max + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 160, 100, 10); + + // allow 4:3 "comparable" resolutions + in.width = 160; + in.height = 120; + in.framerate = 10; + EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out)); + EXPECT_PRED4(IsEqualRes, out, 160, 120, 10); + } + + void ConstrainRunningCodecBody() { + cricket::VideoCodec in, out, current; + cricket::VideoCodec max_settings(engine_.codecs()[0].id, + engine_.codecs()[0].name, + 1280, 800, 30, 0); + + // set max settings of 1280x960x30 + EXPECT_TRUE(engine_.SetDefaultEncoderConfig( + cricket::VideoEncoderConfig(max_settings))); + + // establish current call at 1280x800x30 (16:10) + current = max_settings; + current.height = 800; + + // Don't constrain current resolution + in = current; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED2(IsEqualCodec, out, in); + + // requested resolution of 0x0 succeeds + in.width = 0; + in.height = 0; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED2(IsEqualCodec, out, in); + + // Reduce an intermediate resolution down to the next lowest one, preserving + // aspect ratio. + in.width = 800; + in.height = 600; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); + + // Clamping by aspect ratio, but still never return a dimension higher than + // requested. + in.width = 1280; + in.height = 720; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30); + + in.width = 1279; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 960, 600, 30); + + in.width = 1281; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30); + + // Clamp large resolutions down, always preserving aspect + in.width = 1920; + in.height = 1080; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30); + + in.width = 1921; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30); + + in.width = 1919; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30); + + // reduce max settings to 640x480x30 + max_settings.width = 640; + max_settings.height = 480; + EXPECT_TRUE(engine_.SetDefaultEncoderConfig( + cricket::VideoEncoderConfig(max_settings))); + + // establish current call at 640x400x30 (16:10) + current = max_settings; + current.height = 400; + + // Don't constrain current resolution + in = current; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED2(IsEqualCodec, out, in); + + // requested resolution of 0x0 succeeds + in.width = 0; + in.height = 0; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED2(IsEqualCodec, out, in); + + // Reduce an intermediate resolution down to the next lowest one, preserving + // aspect ratio. + in.width = 400; + in.height = 300; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 320, 200, 30); + + // Clamping by aspect ratio, but still never return a dimension higher than + // requested. + in.width = 640; + in.height = 360; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 360, 30); + + in.width = 639; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 480, 300, 30); + + in.width = 641; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 360, 30); + + // Clamp large resolutions down, always preserving aspect + in.width = 1280; + in.height = 800; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); + + in.width = 1281; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); + + in.width = 1279; + EXPECT_TRUE(engine_.CanSendCodec(in, current, &out)); + EXPECT_PRED4(IsEqualRes, out, 640, 400, 30); + + // Should fail for any that are smaller than our supported formats + in.width = 80; + in.height = 80; + EXPECT_FALSE(engine_.CanSendCodec(in, current, &out)); + + in.height = 50; + EXPECT_FALSE(engine_.CanSendCodec(in, current, &out)); + } + + VideoEngineOverride engine_; + talk_base::scoped_ptr video_capturer_; +}; + +template +class VideoMediaChannelTest : public testing::Test, + public sigslot::has_slots<> { + protected: + virtual cricket::VideoCodec DefaultCodec() = 0; + + virtual cricket::StreamParams DefaultSendStreamParams() { + return cricket::StreamParams::CreateLegacy(kSsrc); + } + + virtual void SetUp() { + cricket::Device device("test", "device"); + EXPECT_TRUE(engine_.Init(talk_base::Thread::Current())); + channel_.reset(engine_.CreateChannel(NULL)); + EXPECT_TRUE(channel_.get() != NULL); + ConnectVideoChannelError(); + network_interface_.SetDestination(channel_.get()); + channel_->SetInterface(&network_interface_); + SetRendererAsDefault(); + media_error_ = cricket::VideoMediaChannel::ERROR_NONE; + channel_->SetRecvCodecs(engine_.codecs()); + EXPECT_TRUE(channel_->AddSendStream(DefaultSendStreamParams())); + + video_capturer_.reset(new cricket::FakeVideoCapturer); + cricket::VideoFormat format(640, 480, + cricket::VideoFormat::FpsToInterval(30), + cricket::FOURCC_I420); + 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() { + 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), + cricket::FOURCC_I420); + EXPECT_EQ(cricket::CS_RUNNING, video_capturer_2_->Start(format)); + + EXPECT_TRUE(channel_->SetCapturer(kSsrc + 2, video_capturer_2_.get())); + } + virtual void TearDown() { + channel_.reset(); + engine_.Terminate(); + } + void ConnectVideoChannelError() { + channel_->SignalMediaError.connect(this, + &VideoMediaChannelTest::OnVideoChannelError); + } + bool SetDefaultCodec() { + return SetOneCodec(DefaultCodec()); + } + void SetRendererAsDefault() { + EXPECT_TRUE(channel_->SetRenderer(0, &renderer_)); + } + + bool SetOneCodec(int pt, const char* name, int w, int h, int fr) { + return SetOneCodec(cricket::VideoCodec(pt, name, w, h, fr, 0)); + } + bool SetOneCodec(const cricket::VideoCodec& codec) { + std::vector codecs; + codecs.push_back(codec); + + cricket::VideoFormat capture_format(codec.width, codec.height, + cricket::VideoFormat::FpsToInterval(codec.framerate), + cricket::FOURCC_I420); + + 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)); + } + + bool sending = channel_->sending(); + bool success = SetSend(false); + if (success) + success = channel_->SetSendCodecs(codecs); + if (success) + success = SetSend(sending); + return success; + } + 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 { + packets = NumRtpPackets(); + // 100 ms should be long enough. + talk_base::Thread::Current()->ProcessMessages(100); + } while (NumRtpPackets() > packets); + return NumRtpPackets(); + } + bool SendFrame() { + if (video_capturer_2_) { + video_capturer_2_->CaptureFrame(); + } + return video_capturer_.get() && + video_capturer_->CaptureFrame(); + } + bool WaitAndSendFrame(int wait_ms) { + bool ret = talk_base::Thread::Current()->ProcessMessages(wait_ms); + ret &= SendFrame(); + return ret; + } + // Sends frames and waits for the decoder to be fully initialized. + // Returns the number of frames that were sent. + int WaitForDecoder() { +#if defined(HAVE_OPENMAX) + // Send enough frames for the OpenMAX decoder to continue processing, and + // return the number of frames sent. + // Send frames for a full kTimeout's worth of 15fps video. + int frame_count = 0; + while (frame_count < static_cast(kTimeout) / 66) { + EXPECT_TRUE(WaitAndSendFrame(66)); + ++frame_count; + } + return frame_count; +#else + return 0; +#endif + } + bool SendCustomVideoFrame(int w, int h) { + if (!video_capturer_.get()) return false; + return video_capturer_->CaptureCustomFrame(w, h, cricket::FOURCC_I420); + } + int NumRtpBytes() { + return network_interface_.NumRtpBytes(); + } + int NumRtpBytes(uint32 ssrc) { + return network_interface_.NumRtpBytes(ssrc); + } + int NumRtpPackets() { + return network_interface_.NumRtpPackets(); + } + int NumRtpPackets(uint32 ssrc) { + return network_interface_.NumRtpPackets(ssrc); + } + int NumSentSsrcs() { + return network_interface_.NumSentSsrcs(); + } + const talk_base::Buffer* GetRtpPacket(int index) { + return network_interface_.GetRtpPacket(index); + } + int NumRtcpPackets() { + return network_interface_.NumRtcpPackets(); + } + const talk_base::Buffer* GetRtcpPacket(int index) { + return network_interface_.GetRtcpPacket(index); + } + static int GetPayloadType(const talk_base::Buffer* p) { + int pt = -1; + ParseRtpPacket(p, NULL, &pt, NULL, NULL, NULL, NULL); + return pt; + } + static bool ParseRtpPacket(const talk_base::Buffer* p, bool* x, int* pt, + int* seqnum, uint32* tstamp, uint32* ssrc, + std::string* payload) { + talk_base::ByteBuffer buf(p->data(), p->length()); + uint8 u08 = 0; + uint16 u16 = 0; + uint32 u32 = 0; + + // Read X and CC fields. + if (!buf.ReadUInt8(&u08)) return false; + bool extension = ((u08 & 0x10) != 0); + uint8 cc = (u08 & 0x0F); + if (x) *x = extension; + + // Read PT field. + if (!buf.ReadUInt8(&u08)) return false; + if (pt) *pt = (u08 & 0x7F); + + // Read Sequence Number field. + if (!buf.ReadUInt16(&u16)) return false; + if (seqnum) *seqnum = u16; + + // Read Timestamp field. + if (!buf.ReadUInt32(&u32)) return false; + if (tstamp) *tstamp = u32; + + // Read SSRC field. + if (!buf.ReadUInt32(&u32)) return false; + if (ssrc) *ssrc = u32; + + // Skip CSRCs. + for (uint8 i = 0; i < cc; ++i) { + if (!buf.ReadUInt32(&u32)) return false; + } + + // Skip extension header. + if (extension) { + // Read Profile-specific extension header ID + if (!buf.ReadUInt16(&u16)) return false; + + // Read Extension header length + if (!buf.ReadUInt16(&u16)) return false; + uint16 ext_header_len = u16; + + // Read Extension header + for (uint16 i = 0; i < ext_header_len; ++i) { + if (!buf.ReadUInt32(&u32)) return false; + } + } + + if (payload) { + return buf.ReadString(payload, buf.Length()); + } + return true; + } + + // Parse all RTCP packet, from start_index to stop_index, and count how many + // FIR (PT=206 and FMT=4 according to RFC 5104). If successful, set the count + // and return true. + bool CountRtcpFir(int start_index, int stop_index, int* fir_count) { + int count = 0; + for (int i = start_index; i < stop_index; ++i) { + talk_base::scoped_ptr p(GetRtcpPacket(i)); + talk_base::ByteBuffer buf(p->data(), p->length()); + size_t total_len = 0; + // The packet may be a compound RTCP packet. + while (total_len < p->length()) { + // Read FMT, type and length. + uint8 fmt = 0; + uint8 type = 0; + uint16 length = 0; + if (!buf.ReadUInt8(&fmt)) return false; + fmt &= 0x1F; + if (!buf.ReadUInt8(&type)) return false; + if (!buf.ReadUInt16(&length)) return false; + buf.Consume(length * 4); // Skip RTCP data. + total_len += (length + 1) * 4; + if ((192 == type) || ((206 == type) && (4 == fmt))) { + ++count; + } + } + } + + if (fir_count) { + *fir_count = count; + } + return true; + } + + void OnVideoChannelError(uint32 ssrc, + cricket::VideoMediaChannel::Error error) { + media_error_ = error; + } + + // Test that SetSend works. + void SetSend() { + EXPECT_FALSE(channel_->sending()); + EXPECT_TRUE(channel_->SetCapturer(kSsrc, video_capturer_.get())); + EXPECT_TRUE(SetOneCodec(DefaultCodec())); + EXPECT_FALSE(channel_->sending()); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->sending()); + EXPECT_TRUE(SendFrame()); + EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout); + EXPECT_TRUE(SetSend(false)); + EXPECT_FALSE(channel_->sending()); + } + // Test that SetSend fails without codecs being set. + void SetSendWithoutCodecs() { + EXPECT_FALSE(channel_->sending()); + EXPECT_FALSE(SetSend(true)); + EXPECT_FALSE(channel_->sending()); + } + // Test that we properly set the send and recv buffer sizes by the time + // SetSend is called. + void SetSendSetsTransportBufferSizes() { + EXPECT_TRUE(SetOneCodec(DefaultCodec())); + EXPECT_TRUE(SetSend(true)); + // TODO(sriniv): Remove or re-enable this. + // As part of b/8030474, send-buffer is size now controlled through + // portallocator flags. Its not set by channels. + // EXPECT_EQ(64 * 1024, network_interface_.sendbuf_size()); + EXPECT_EQ(64 * 1024, network_interface_.recvbuf_size()); + } + // Tests that we can send frames and the right payload type is used. + void Send(const cricket::VideoCodec& codec) { + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(SendFrame()); + EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout); + talk_base::scoped_ptr p(GetRtpPacket(0)); + EXPECT_EQ(codec.id, GetPayloadType(p.get())); + } + // Tests that we can send and receive frames. + void SendAndReceive(const cricket::VideoCodec& codec) { + EXPECT_TRUE(SetOneCodec(codec)); + 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); + talk_base::scoped_ptr p(GetRtpPacket(0)); + EXPECT_EQ(codec.id, GetPayloadType(p.get())); + } + // Tests that we only get a VideoRenderer::SetSize() callback when needed. + void SendManyResizeOnce() { + cricket::VideoCodec codec(DefaultCodec()); + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_EQ(0, renderer_.num_rendered_frames()); + EXPECT_TRUE(WaitAndSendFrame(30)); + EXPECT_FRAME_WAIT(1, codec.width, codec.height, kTimeout); + EXPECT_TRUE(WaitAndSendFrame(30)); + EXPECT_FRAME_WAIT(2, codec.width, codec.height, kTimeout); + talk_base::scoped_ptr p(GetRtpPacket(0)); + EXPECT_EQ(codec.id, GetPayloadType(p.get())); + EXPECT_EQ(1, renderer_.num_set_sizes()); + + codec.width /= 2; + codec.height /= 2; + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(WaitAndSendFrame(30)); + EXPECT_FRAME_WAIT(3, codec.width, codec.height, kTimeout); + EXPECT_EQ(2, renderer_.num_set_sizes()); + } + // Test that stats work properly for a 1-1 call. + void GetStats() { + SendAndReceive(DefaultCodec()); + cricket::VideoMediaInfo 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? + 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].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); + + ASSERT_EQ(1U, info.receivers.size()); + EXPECT_EQ(1U, info.senders[0].ssrcs().size()); + EXPECT_EQ(1U, info.receivers[0].ssrcs().size()); + EXPECT_EQ(info.senders[0].ssrcs()[0], info.receivers[0].ssrcs()[0]); + EXPECT_EQ(NumRtpBytes(), info.receivers[0].bytes_rcvd); + 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); + 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); + EXPECT_GT(info.receivers[0].framerate_rcvd, 0); + EXPECT_GT(info.receivers[0].framerate_decoded, 0); + EXPECT_GT(info.receivers[0].framerate_output, 0); + } + // Test that stats work properly for a conf call with multiple recv streams. + void GetStatsMultipleRecvStreams() { + cricket::FakeVideoRenderer renderer1, renderer2; + EXPECT_TRUE(SetOneCodec(DefaultCodec())); + cricket::VideoOptions vmo; + vmo.conference_mode.Set(true); + EXPECT_TRUE(channel_->SetOptions(vmo)); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(1))); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(2))); + EXPECT_TRUE(channel_->SetRenderer(1, &renderer1)); + EXPECT_TRUE(channel_->SetRenderer(2, &renderer2)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_EQ(0, renderer1.num_rendered_frames()); + EXPECT_EQ(0, renderer2.num_rendered_frames()); + std::vector ssrcs; + ssrcs.push_back(1); + ssrcs.push_back(2); + network_interface_.SetConferenceMode(true, ssrcs); + EXPECT_TRUE(SendFrame()); + EXPECT_FRAME_ON_RENDERER_WAIT( + renderer1, 1, DefaultCodec().width, DefaultCodec().height, kTimeout); + EXPECT_FRAME_ON_RENDERER_WAIT( + renderer2, 1, DefaultCodec().width, DefaultCodec().height, kTimeout); + cricket::VideoMediaInfo 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? + 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].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); + + ASSERT_EQ(2U, info.receivers.size()); + for (size_t i = 0; i < info.receivers.size(); ++i) { + EXPECT_EQ(1U, info.receivers[i].ssrcs().size()); + 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].plis_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. + void GetStatsMultipleSendStreams() { + // Normal setup; note that we set the SSRC explicitly to ensure that + // it will come first in the senders map. + EXPECT_TRUE(SetOneCodec(DefaultCodec())); + cricket::VideoOptions vmo; + vmo.conference_mode.Set(true); + EXPECT_TRUE(channel_->SetOptions(vmo)); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(1234))); + channel_->UpdateAspectRatio(640, 400); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_TRUE(SendFrame()); + EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout); + EXPECT_FRAME_WAIT(1, DefaultCodec().width, DefaultCodec().height, kTimeout); + + // Add an additional capturer, and hook up a renderer to receive it. + cricket::FakeVideoRenderer renderer1; + talk_base::scoped_ptr capturer( + new cricket::FakeVideoCapturer); + capturer->SetScreencast(true); + 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))); + EXPECT_TRUE(channel_->SetCapturer(5678, capturer.get())); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(5678))); + EXPECT_TRUE(channel_->SetRenderer(5678, &renderer1)); + 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(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].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(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. + void SetSendBandwidth() { + 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); + uint32 ssrc = 0; + talk_base::scoped_ptr p(GetRtpPacket(0)); + ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL); + EXPECT_EQ(kSsrc, ssrc); + EXPECT_EQ(NumRtpPackets(), NumRtpPackets(ssrc)); + EXPECT_EQ(NumRtpBytes(), NumRtpBytes(ssrc)); + EXPECT_EQ(1, NumSentSsrcs()); + EXPECT_EQ(0, NumRtpPackets(kSsrc - 1)); + EXPECT_EQ(0, NumRtpBytes(kSsrc - 1)); + } + // Test that we can set the SSRC even after codecs are set. + void SetSendSsrcAfterSetCodecs() { + // Remove stream added in Setup. + EXPECT_TRUE(channel_->RemoveSendStream(kSsrc)); + EXPECT_TRUE(SetDefaultCodec()); + 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); + uint32 ssrc = 0; + talk_base::scoped_ptr p(GetRtpPacket(0)); + ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL); + EXPECT_EQ(999u, ssrc); + EXPECT_EQ(NumRtpPackets(), NumRtpPackets(ssrc)); + EXPECT_EQ(NumRtpBytes(), NumRtpBytes(ssrc)); + EXPECT_EQ(1, NumSentSsrcs()); + EXPECT_EQ(0, NumRtpPackets(kSsrc)); + EXPECT_EQ(0, NumRtpBytes(kSsrc)); + } + // Test that we can set the default video renderer before and after + // media is received. + void SetRenderer() { + uint8 data1[] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + talk_base::Buffer packet1(data1, sizeof(data1)); + talk_base::SetBE32(packet1.data() + 8, kSsrc); + channel_->SetRenderer(0, NULL); + EXPECT_TRUE(SetDefaultCodec()); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_EQ(0, renderer_.num_rendered_frames()); + channel_->OnPacketReceived(&packet1, talk_base::PacketTime()); + SetRendererAsDefault(); + EXPECT_TRUE(SendFrame()); + EXPECT_FRAME_WAIT(1, DefaultCodec().width, DefaultCodec().height, kTimeout); + } + + // Tests empty StreamParams is rejected. + void RejectEmptyStreamParams() { + // Remove the send stream that was added during Setup. + EXPECT_TRUE(channel_->RemoveSendStream(kSsrc)); + + cricket::StreamParams empty; + EXPECT_FALSE(channel_->AddSendStream(empty)); + EXPECT_TRUE(channel_->AddSendStream( + cricket::StreamParams::CreateLegacy(789u))); + } + + // Tests setting up and configuring a send stream. + void AddRemoveSendStreams() { + EXPECT_TRUE(SetOneCodec(DefaultCodec())); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_TRUE(SendFrame()); + EXPECT_FRAME_WAIT(1, DefaultCodec().width, DefaultCodec().height, kTimeout); + EXPECT_GE(2, NumRtpPackets()); + uint32 ssrc = 0; + size_t last_packet = NumRtpPackets() - 1; + talk_base::scoped_ptr + p(GetRtpPacket(static_cast(last_packet))); + ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL); + EXPECT_EQ(kSsrc, ssrc); + + // Remove the send stream that was added during Setup. + EXPECT_TRUE(channel_->RemoveSendStream(kSsrc)); + int rtp_packets = NumRtpPackets(); + + EXPECT_TRUE(channel_->AddSendStream( + cricket::StreamParams::CreateLegacy(789u))); + EXPECT_TRUE(channel_->SetCapturer(789u, video_capturer_.get())); + EXPECT_EQ(rtp_packets, NumRtpPackets()); + // Wait 30ms to guarantee the engine does not drop the frame. + EXPECT_TRUE(WaitAndSendFrame(30)); + EXPECT_TRUE_WAIT(NumRtpPackets() > rtp_packets, kTimeout); + + last_packet = NumRtpPackets() - 1; + p.reset(GetRtpPacket(static_cast(last_packet))); + ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL); + EXPECT_EQ(789u, ssrc); + } + + // Tests adding streams already exists returns false. + void AddRecvStreamsAlreadyExist() { + cricket::VideoOptions vmo; + vmo.conference_mode.Set(true); + EXPECT_TRUE(channel_->SetOptions(vmo)); + + EXPECT_FALSE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(0))); + + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(1))); + EXPECT_FALSE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(1))); + + EXPECT_TRUE(channel_->RemoveRecvStream(1)); + EXPECT_FALSE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(0))); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(1))); + } + + // Tests setting up and configuring multiple incoming streams. + void AddRemoveRecvStreams() { + cricket::FakeVideoRenderer renderer1, renderer2; + cricket::VideoOptions vmo; + vmo.conference_mode.Set(true); + EXPECT_TRUE(channel_->SetOptions(vmo)); + // Ensure we can't set the renderer on a non-existent stream. + EXPECT_FALSE(channel_->SetRenderer(1, &renderer1)); + EXPECT_FALSE(channel_->SetRenderer(2, &renderer2)); + cricket::VideoRenderer* renderer; + EXPECT_FALSE(channel_->GetRenderer(1, &renderer)); + EXPECT_FALSE(channel_->GetRenderer(2, &renderer)); + + // Ensure we can add streams. + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(1))); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(2))); + EXPECT_TRUE(channel_->GetRenderer(1, &renderer)); + // Verify the first AddRecvStream hook up to the default renderer. + EXPECT_EQ(&renderer_, renderer); + EXPECT_TRUE(channel_->GetRenderer(2, &renderer)); + EXPECT_TRUE(NULL == renderer); + + // Ensure we can now set the renderers. + EXPECT_TRUE(channel_->SetRenderer(1, &renderer1)); + EXPECT_TRUE(channel_->SetRenderer(2, &renderer2)); + EXPECT_TRUE(channel_->GetRenderer(1, &renderer)); + EXPECT_TRUE(&renderer1 == renderer); + EXPECT_TRUE(channel_->GetRenderer(2, &renderer)); + EXPECT_TRUE(&renderer2 == renderer); + + // Ensure we can change the renderers if needed. + EXPECT_TRUE(channel_->SetRenderer(1, &renderer2)); + EXPECT_TRUE(channel_->SetRenderer(2, &renderer1)); + EXPECT_TRUE(channel_->GetRenderer(1, &renderer)); + EXPECT_TRUE(&renderer2 == renderer); + EXPECT_TRUE(channel_->GetRenderer(2, &renderer)); + EXPECT_TRUE(&renderer1 == renderer); + + EXPECT_TRUE(channel_->RemoveRecvStream(2)); + EXPECT_TRUE(channel_->RemoveRecvStream(1)); + EXPECT_FALSE(channel_->GetRenderer(1, &renderer)); + EXPECT_FALSE(channel_->GetRenderer(2, &renderer)); + } + + // Tests setting up and configuring multiple incoming streams in a + // non-conference call. + void AddRemoveRecvStreamsNoConference() { + cricket::FakeVideoRenderer renderer1, renderer2; + // Ensure we can't set the renderer on a non-existent stream. + EXPECT_FALSE(channel_->SetRenderer(1, &renderer1)); + EXPECT_FALSE(channel_->SetRenderer(2, &renderer2)); + cricket::VideoRenderer* renderer; + EXPECT_FALSE(channel_->GetRenderer(1, &renderer)); + EXPECT_FALSE(channel_->GetRenderer(2, &renderer)); + + // Ensure we can add streams. + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(1))); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(2))); + EXPECT_TRUE(channel_->GetRenderer(1, &renderer)); + // Verify the first AddRecvStream hook up to the default renderer. + EXPECT_EQ(&renderer_, renderer); + EXPECT_TRUE(channel_->GetRenderer(2, &renderer)); + EXPECT_TRUE(NULL == renderer); + + // Ensure we can now set the renderers. + EXPECT_TRUE(channel_->SetRenderer(1, &renderer1)); + EXPECT_TRUE(channel_->SetRenderer(2, &renderer2)); + EXPECT_TRUE(channel_->GetRenderer(1, &renderer)); + EXPECT_TRUE(&renderer1 == renderer); + EXPECT_TRUE(channel_->GetRenderer(2, &renderer)); + EXPECT_TRUE(&renderer2 == renderer); + + // Ensure we can change the renderers if needed. + EXPECT_TRUE(channel_->SetRenderer(1, &renderer2)); + EXPECT_TRUE(channel_->SetRenderer(2, &renderer1)); + EXPECT_TRUE(channel_->GetRenderer(1, &renderer)); + EXPECT_TRUE(&renderer2 == renderer); + EXPECT_TRUE(channel_->GetRenderer(2, &renderer)); + EXPECT_TRUE(&renderer1 == renderer); + + EXPECT_TRUE(channel_->RemoveRecvStream(2)); + EXPECT_TRUE(channel_->RemoveRecvStream(1)); + EXPECT_FALSE(channel_->GetRenderer(1, &renderer)); + EXPECT_FALSE(channel_->GetRenderer(2, &renderer)); + } + + // Test that no frames are rendered after the receive stream have been + // removed. + void AddRemoveRecvStreamAndRender() { + cricket::FakeVideoRenderer renderer1; + EXPECT_TRUE(SetDefaultCodec()); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(kSsrc))); + EXPECT_TRUE(channel_->SetRenderer(kSsrc, &renderer1)); + + EXPECT_TRUE(SendFrame()); + EXPECT_FRAME_ON_RENDERER_WAIT( + renderer1, 1, DefaultCodec().width, DefaultCodec().height, kTimeout); + EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc)); + // Send three more frames. This is to avoid that the test might be flaky + // due to frame dropping. + for (size_t i = 0; i < 3; ++i) + EXPECT_TRUE(WaitAndSendFrame(100)); + + // Test that no more frames have been rendered. + EXPECT_EQ(1, renderer1.num_rendered_frames()); + + // Re-add the stream again and make sure it renders. + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(kSsrc))); + // Force the next frame to be a key frame to make the receiving + // decoder happy. + EXPECT_TRUE(channel_->SendIntraFrame()); + + EXPECT_TRUE(channel_->SetRenderer(kSsrc, &renderer1)); + EXPECT_TRUE(SendFrame()); + // Because the default channel is used, RemoveRecvStream above is not going + // to delete the channel. As a result the engine will continue to receive + // and decode the 3 frames sent above. So it is possible we will receive + // 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. + void SimulateConference() { + cricket::FakeVideoRenderer renderer1, renderer2; + EXPECT_TRUE(SetDefaultCodec()); + cricket::VideoOptions vmo; + vmo.conference_mode.Set(true); + EXPECT_TRUE(channel_->SetOptions(vmo)); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(1))); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(2))); + EXPECT_TRUE(channel_->SetRenderer(1, &renderer1)); + EXPECT_TRUE(channel_->SetRenderer(2, &renderer2)); + EXPECT_EQ(0, renderer1.num_rendered_frames()); + EXPECT_EQ(0, renderer2.num_rendered_frames()); + std::vector ssrcs; + ssrcs.push_back(1); + ssrcs.push_back(2); + network_interface_.SetConferenceMode(true, ssrcs); + EXPECT_TRUE(SendFrame()); + EXPECT_FRAME_ON_RENDERER_WAIT( + renderer1, 1, DefaultCodec().width, DefaultCodec().height, kTimeout); + EXPECT_FRAME_ON_RENDERER_WAIT( + renderer2, 1, DefaultCodec().width, DefaultCodec().height, kTimeout); + + talk_base::scoped_ptr p(GetRtpPacket(0)); + EXPECT_EQ(DefaultCodec().id, GetPayloadType(p.get())); + EXPECT_EQ(DefaultCodec().width, renderer1.width()); + EXPECT_EQ(DefaultCodec().height, renderer1.height()); + EXPECT_EQ(DefaultCodec().width, renderer2.width()); + EXPECT_EQ(DefaultCodec().height, renderer2.height()); + EXPECT_TRUE(channel_->RemoveRecvStream(2)); + EXPECT_TRUE(channel_->RemoveRecvStream(1)); + } + + // Tests that we can add and remove capturers and frames are sent out properly + void AddRemoveCapturer() { + cricket::VideoCodec codec = DefaultCodec(); + codec.width = 320; + codec.height = 240; + const int time_between_send = TimeBetweenSend(codec); + EXPECT_TRUE(SetOneCodec(codec)); + 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); + talk_base::scoped_ptr capturer( + new cricket::FakeVideoCapturer); + capturer->SetScreencast(true); + 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 + // associating the capturer with the channel. + EXPECT_TRUE(capturer->CaptureCustomFrame(format.width, format.height, + cricket::FOURCC_I420)); + + int captured_frames = 1; + for (int iterations = 0; iterations < 2; ++iterations) { + EXPECT_TRUE(channel_->SetCapturer(kSsrc, capturer.get())); + talk_base::Thread::Current()->ProcessMessages(time_between_send); + EXPECT_TRUE(capturer->CaptureCustomFrame(format.width, format.height, + cricket::FOURCC_I420)); + ++captured_frames; + // Wait until frame of right size is captured. + EXPECT_TRUE_WAIT(renderer_.num_rendered_frames() >= captured_frames && + format.width == renderer_.width() && + format.height == renderer_.height() && + !renderer_.black_frame(), kTimeout); + EXPECT_GE(renderer_.num_rendered_frames(), captured_frames); + EXPECT_EQ(format.width, renderer_.width()); + EXPECT_EQ(format.height, renderer_.height()); + captured_frames = renderer_.num_rendered_frames() + 1; + EXPECT_FALSE(renderer_.black_frame()); + EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL)); + // Make sure a black frame is generated within the specified timeout. + // The black frame should be the resolution of the send codec. + EXPECT_TRUE_WAIT(renderer_.num_rendered_frames() >= captured_frames && + codec.width == renderer_.width() && + codec.height == renderer_.height() && + renderer_.black_frame(), kTimeout); + EXPECT_GE(renderer_.num_rendered_frames(), captured_frames); + EXPECT_EQ(codec.width, renderer_.width()); + EXPECT_EQ(codec.height, renderer_.height()); + EXPECT_TRUE(renderer_.black_frame()); + + // The black frame has the same timestamp as the next frame since it's + // timestamp is set to the last frame's timestamp + interval. WebRTC will + // not render a frame with the same timestamp so capture another frame + // with the frame capturer to increment the next frame's timestamp. + EXPECT_TRUE(capturer->CaptureCustomFrame(format.width, format.height, + cricket::FOURCC_I420)); + } + } + + // Tests that if RemoveCapturer is called without a capturer ever being + // added, the plugin shouldn't crash (and no black frame should be sent). + void RemoveCapturerWithoutAdd() { + EXPECT_TRUE(SetOneCodec(DefaultCodec())); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_EQ(0, renderer_.num_rendered_frames()); + EXPECT_TRUE(SendFrame()); + EXPECT_FRAME_WAIT(1, 640, 400, kTimeout); + // Remove the capturer. + EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL)); + // Wait for one black frame for removing the capturer. + EXPECT_FRAME_WAIT(2, 640, 400, kTimeout); + + // No capturer was added, so this RemoveCapturer should + // fail. + EXPECT_FALSE(channel_->SetCapturer(kSsrc, NULL)); + talk_base::Thread::Current()->ProcessMessages(300); + // Verify no more frames were sent. + EXPECT_EQ(2, renderer_.num_rendered_frames()); + } + + // Tests that we can add and remove capturer as unique sources. + void AddRemoveCapturerMultipleSources() { + // WebRTC implementation will drop frames if pushed to quickly. Wait the + // interval time to avoid that. + // WebRTC implementation will drop frames if pushed to quickly. Wait the + // interval time to avoid that. + // Set up the stream associated with the engine. + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(kSsrc))); + EXPECT_TRUE(channel_->SetRenderer(kSsrc, &renderer_)); + cricket::VideoFormat capture_format; // default format + capture_format.interval = cricket::VideoFormat::FpsToInterval(30); + // Set up additional stream 1. + cricket::FakeVideoRenderer renderer1; + EXPECT_FALSE(channel_->SetRenderer(1, &renderer1)); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(1))); + EXPECT_TRUE(channel_->SetRenderer(1, &renderer1)); + EXPECT_TRUE(channel_->AddSendStream( + cricket::StreamParams::CreateLegacy(1))); + talk_base::scoped_ptr capturer1( + new cricket::FakeVideoCapturer); + capturer1->SetScreencast(true); + EXPECT_EQ(cricket::CS_RUNNING, capturer1->Start(capture_format)); + // Set up additional stream 2. + cricket::FakeVideoRenderer renderer2; + EXPECT_FALSE(channel_->SetRenderer(2, &renderer2)); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(2))); + EXPECT_TRUE(channel_->SetRenderer(2, &renderer2)); + EXPECT_TRUE(channel_->AddSendStream( + cricket::StreamParams::CreateLegacy(2))); + talk_base::scoped_ptr capturer2( + new cricket::FakeVideoCapturer); + capturer2->SetScreencast(true); + EXPECT_EQ(cricket::CS_RUNNING, capturer2->Start(capture_format)); + // State for all the streams. + EXPECT_TRUE(SetOneCodec(DefaultCodec())); + // A limitation in the lmi implementation requires that SetCapturer() is + // called after SetOneCodec(). + // TODO(hellner): this seems like an unnecessary constraint, fix it. + EXPECT_TRUE(channel_->SetCapturer(1, capturer1.get())); + EXPECT_TRUE(channel_->SetCapturer(2, capturer2.get())); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + // Test capturer associated with engine. + 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( + 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. + EXPECT_FALSE(channel_->SetCapturer(kSsrc, NULL)); + // The capturers must be unregistered here as it runs out of it's scope + // next. + EXPECT_TRUE(channel_->SetCapturer(1, NULL)); + EXPECT_TRUE(channel_->SetCapturer(2, NULL)); + } + + void HighAspectHighHeightCapturer() { + const int kWidth = 80; + const int kHeight = 10000; + const int kScaledWidth = 20; + const int kScaledHeight = 2500; + + cricket::VideoCodec codec(DefaultCodec()); + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(SetSend(true)); + + cricket::FakeVideoRenderer renderer; + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(kSsrc))); + EXPECT_TRUE(channel_->SetRenderer(kSsrc, &renderer)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_EQ(0, renderer.num_rendered_frames()); + + EXPECT_TRUE(SendFrame()); + EXPECT_GT_FRAME_ON_RENDERER_WAIT( + renderer, 1, codec.width, codec.height, kTimeout); + + // Registering an external capturer is currently the same as screen casting + // (update the test when this changes). + talk_base::scoped_ptr capturer( + new cricket::FakeVideoCapturer); + capturer->SetScreencast(true); + const std::vector* formats = + capturer->GetSupportedFormats(); + cricket::VideoFormat capture_format = (*formats)[0]; + EXPECT_EQ(cricket::CS_RUNNING, capturer->Start(capture_format)); + // Capture frame to not get same frame timestamps as previous capturer. + capturer->CaptureFrame(); + EXPECT_TRUE(channel_->SetCapturer(kSsrc, capturer.get())); + EXPECT_TRUE(talk_base::Thread::Current()->ProcessMessages(30)); + EXPECT_TRUE(capturer->CaptureCustomFrame(kWidth, kHeight, + cricket::FOURCC_ARGB)); + EXPECT_TRUE(capturer->CaptureFrame()); + EXPECT_GT_FRAME_ON_RENDERER_WAIT( + renderer, 2, kScaledWidth, kScaledHeight, kTimeout); + EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL)); + } + + // Tests that we can adapt video resolution with 16:10 aspect ratio properly. + void AdaptResolution16x10() { + cricket::VideoCodec codec(DefaultCodec()); + codec.width = 640; + codec.height = 400; + SendAndReceive(codec); + codec.width /= 2; + codec.height /= 2; + // Adapt the resolution. + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(WaitAndSendFrame(30)); + EXPECT_FRAME_WAIT(2, codec.width, codec.height, kTimeout); + } + // Tests that we can adapt video resolution with 4:3 aspect ratio properly. + void AdaptResolution4x3() { + cricket::VideoCodec codec(DefaultCodec()); + codec.width = 640; + codec.height = 400; + SendAndReceive(codec); + codec.width /= 2; + codec.height /= 2; + // Adapt the resolution. + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(WaitAndSendFrame(30)); + EXPECT_FRAME_WAIT(2, codec.width, codec.height, kTimeout); + } + // Tests that we can drop all frames properly. + void AdaptDropAllFrames() { + // Set the channel codec's resolution to 0, which will require the adapter + // to drop all frames. + cricket::VideoCodec codec(DefaultCodec()); + codec.width = codec.height = codec.framerate = 0; + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_EQ(0, renderer_.num_rendered_frames()); + EXPECT_TRUE(SendFrame()); + EXPECT_TRUE(SendFrame()); + talk_base::Thread::Current()->ProcessMessages(500); + EXPECT_EQ(0, renderer_.num_rendered_frames()); + } + // Tests that we can reduce the frame rate on demand properly. + // TODO(fbarchard): This test is flakey on pulse. Fix and re-enable + void AdaptFramerate() { + cricket::VideoCodec codec(DefaultCodec()); + int frame_count = 0; + // The capturer runs at 30 fps. The channel requires 30 fps. + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_EQ(frame_count, renderer_.num_rendered_frames()); + EXPECT_TRUE(WaitAndSendFrame(0)); // Should be rendered. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be rendered. + frame_count += 2; + EXPECT_FRAME_WAIT(frame_count, codec.width, codec.height, kTimeout); + talk_base::scoped_ptr p(GetRtpPacket(0)); + EXPECT_EQ(codec.id, GetPayloadType(p.get())); + + // The channel requires 15 fps. + codec.framerate = 15; + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(WaitAndSendFrame(0)); // Should be rendered. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be rendered. + frame_count += 2; + EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout); + + // The channel requires 10 fps. + codec.framerate = 10; + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(WaitAndSendFrame(0)); // Should be rendered. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be rendered. + frame_count += 2; + EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout); + + // The channel requires 8 fps. The adapter adapts to 10 fps, which is the + // closest factor of 30. + codec.framerate = 8; + EXPECT_TRUE(SetOneCodec(codec)); + EXPECT_TRUE(WaitAndSendFrame(0)); // Should be rendered. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be rendered. + frame_count += 2; + EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout); + } + // Tests that we can set the send stream format properly. + void SetSendStreamFormat() { + cricket::VideoCodec codec(DefaultCodec()); + SendAndReceive(codec); + int frame_count = 1; + EXPECT_FRAME_WAIT(frame_count, codec.width, codec.height, kTimeout); + + // Adapt the resolution and frame rate to half. + cricket::VideoFormat format( + codec.width / 2, + codec.height / 2, + cricket::VideoFormat::FpsToInterval(codec.framerate / 2), + cricket::FOURCC_I420); + // The SSRC differs from the send SSRC. + EXPECT_FALSE(channel_->SetSendStreamFormat(kSsrc - 1, format)); + EXPECT_TRUE(channel_->SetSendStreamFormat(kSsrc, format)); + + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be rendered. + EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped. + frame_count += 1; + EXPECT_FRAME_WAIT(frame_count, format.width, format.height, kTimeout); + + // Adapt the resolution to 0x0, which should drop all frames. + format.width = 0; + format.height = 0; + EXPECT_TRUE(channel_->SetSendStreamFormat(kSsrc, format)); + EXPECT_TRUE(SendFrame()); + EXPECT_TRUE(SendFrame()); + talk_base::Thread::Current()->ProcessMessages(500); + EXPECT_EQ(frame_count, renderer_.num_rendered_frames()); + } + // Test that setting send stream format to 0x0 resolution will result in + // 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()); + // This frame should be received. + EXPECT_TRUE(SendFrame()); + EXPECT_FRAME_WAIT(1, DefaultCodec().width, DefaultCodec().height, kTimeout); + const int64 interval = cricket::VideoFormat::FpsToInterval( + DefaultCodec().framerate); + cricket::VideoFormat format( + 0, + 0, + interval, + cricket::FOURCC_I420); + EXPECT_TRUE(channel_->SetSendStreamFormat(kSsrc, format)); + // This frame should not be received. + EXPECT_TRUE(WaitAndSendFrame( + static_cast(interval/talk_base::kNumNanosecsPerMillisec))); + talk_base::Thread::Current()->ProcessMessages(500); + EXPECT_EQ(1, renderer_.num_rendered_frames()); + } + + // Tests that we can mute and unmute the channel properly. + void MuteStream() { + int frame_count = 0; + EXPECT_TRUE(SetDefaultCodec()); + cricket::FakeVideoCapturer video_capturer; + video_capturer.Start( + cricket::VideoFormat( + 640, 480, + cricket::VideoFormat::FpsToInterval(30), + cricket::FOURCC_I420)); + EXPECT_TRUE(channel_->SetCapturer(kSsrc, &video_capturer)); + EXPECT_TRUE(SetSend(true)); + EXPECT_TRUE(channel_->SetRender(true)); + EXPECT_EQ(frame_count, renderer_.num_rendered_frames()); + + // Mute the channel and expect black output frame. + EXPECT_TRUE(channel_->MuteStream(kSsrc, true)); + EXPECT_TRUE(video_capturer.CaptureFrame()); + ++frame_count; + EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout); + EXPECT_TRUE(renderer_.black_frame()); + + // Unmute the channel and expect non-black output frame. + EXPECT_TRUE(channel_->MuteStream(kSsrc, false)); + EXPECT_TRUE(talk_base::Thread::Current()->ProcessMessages(30)); + EXPECT_TRUE(video_capturer.CaptureFrame()); + ++frame_count; + EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout); + EXPECT_FALSE(renderer_.black_frame()); + + // Test that we can also Mute using the correct send stream SSRC. + EXPECT_TRUE(channel_->MuteStream(kSsrc, true)); + EXPECT_TRUE(talk_base::Thread::Current()->ProcessMessages(30)); + EXPECT_TRUE(video_capturer.CaptureFrame()); + ++frame_count; + EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout); + EXPECT_TRUE(renderer_.black_frame()); + + EXPECT_TRUE(channel_->MuteStream(kSsrc, false)); + EXPECT_TRUE(talk_base::Thread::Current()->ProcessMessages(30)); + EXPECT_TRUE(video_capturer.CaptureFrame()); + ++frame_count; + EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout); + EXPECT_FALSE(renderer_.black_frame()); + + // Test that muting an invalid stream fails. + EXPECT_FALSE(channel_->MuteStream(kSsrc+1, true)); + EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL)); + } + + // Test that multiple send streams can be created and deleted properly. + void MultipleSendStreams() { + // Remove stream added in Setup. I.e. remove stream corresponding to default + // channel. + EXPECT_TRUE(channel_->RemoveSendStream(kSsrc)); + const unsigned int kSsrcsSize = sizeof(kSsrcs4)/sizeof(kSsrcs4[0]); + for (unsigned int i = 0; i < kSsrcsSize; ++i) { + EXPECT_TRUE(channel_->AddSendStream( + cricket::StreamParams::CreateLegacy(kSsrcs4[i]))); + } + // Delete one of the non default channel streams, let the destructor delete + // the remaining ones. + EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs4[kSsrcsSize - 1])); + // Stream should already be deleted. + EXPECT_FALSE(channel_->RemoveSendStream(kSsrcs4[kSsrcsSize - 1])); + } + + + // Two streams one channel tests. + + // Tests that we can send and receive frames. + void TwoStreamsSendAndReceive(const cricket::VideoCodec& codec) { + SetUpSecondStream(); + // Test sending and receiving on first stream. + SendAndReceive(codec); + // Test sending and receiving on second stream. + EXPECT_EQ_WAIT(1, renderer2_.num_rendered_frames(), kTimeout); + EXPECT_EQ(2, NumRtpPackets()); + EXPECT_EQ(1, renderer2_.num_rendered_frames()); + } + + // 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)); + EXPECT_TRUE(channel_->RemoveSendStream(kSsrc)); + EXPECT_FALSE(channel_->RemoveSendStream(kSsrc)); + // 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(new_ssrc))); + // Re-use default channel. + EXPECT_EQ(new_ssrc, channel_->GetDefaultChannelSsrc()); + EXPECT_FALSE(channel_->AddSendStream( + cricket::StreamParams::CreateLegacy(new_ssrc))); + EXPECT_TRUE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(new_ssrc))); + EXPECT_FALSE(channel_->AddRecvStream( + cricket::StreamParams::CreateLegacy(new_ssrc))); + + EXPECT_TRUE(channel_->SetCapturer(new_ssrc, video_capturer_.get())); + + SendAndReceive(codec); + 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 engine_; + talk_base::scoped_ptr video_capturer_; + talk_base::scoped_ptr video_capturer_2_; + talk_base::scoped_ptr channel_; + cricket::FakeNetworkInterface network_interface_; + cricket::FakeVideoRenderer renderer_; + cricket::VideoMediaChannel::Error media_error_; + + // Used by test cases where 2 streams are run on the same channel. + cricket::FakeVideoRenderer renderer2_; +}; + +#endif // TALK_MEDIA_BASE_VIDEOENGINE_UNITTEST_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/videoframe.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/videoframe.h new file mode 100644 index 0000000..69cb753 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/videoframe.h @@ -0,0 +1,195 @@ +/* + * 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_BASE_VIDEOFRAME_H_ +#define TALK_MEDIA_BASE_VIDEOFRAME_H_ + +#include "talk/base/basictypes.h" +#include "talk/base/stream.h" + +namespace cricket { + +// Simple rotation constants. +enum { + ROTATION_0 = 0, + ROTATION_90 = 90, + ROTATION_180 = 180, + ROTATION_270 = 270 +}; + +// Represents a YUV420 (a.k.a. I420) video frame. +class VideoFrame { + public: + VideoFrame() {} + virtual ~VideoFrame() {} + + virtual bool InitToBlack(int w, int h, size_t pixel_width, + size_t pixel_height, int64 elapsed_time, + int64 time_stamp) = 0; + // Creates a frame from a raw sample with FourCC |format| and size |w| x |h|. + // |h| can be negative indicating a vertically flipped image. + // |dw| is destination width; can be less than |w| if cropping is desired. + // |dh| is destination height, like |dw|, but must be a positive number. + // Returns whether the function succeeded or failed. + 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) = 0; + + // Basic accessors. + virtual size_t GetWidth() const = 0; + virtual size_t GetHeight() const = 0; + size_t GetChromaWidth() const { return (GetWidth() + 1) / 2; } + size_t GetChromaHeight() const { return (GetHeight() + 1) / 2; } + size_t GetChromaSize() const { return GetUPitch() * GetChromaHeight(); } + // These can return NULL if the object is not backed by a buffer. + virtual const uint8 *GetYPlane() const = 0; + virtual const uint8 *GetUPlane() const = 0; + virtual const uint8 *GetVPlane() const = 0; + virtual uint8 *GetYPlane() = 0; + virtual uint8 *GetUPlane() = 0; + virtual uint8 *GetVPlane() = 0; + + virtual int32 GetYPitch() const = 0; + virtual int32 GetUPitch() const = 0; + virtual int32 GetVPitch() const = 0; + + // Returns the handle of the underlying video frame. This is used when the + // frame is backed by a texture. The object should be destroyed when it is no + // longer in use, so the underlying resource can be freed. + virtual void* GetNativeHandle() const = 0; + + // For retrieving the aspect ratio of each pixel. Usually this is 1x1, but + // the aspect_ratio_idc parameter of H.264 can specify non-square pixels. + virtual size_t GetPixelWidth() const = 0; + virtual size_t GetPixelHeight() const = 0; + + virtual int64 GetElapsedTime() const = 0; + virtual int64 GetTimeStamp() const = 0; + virtual void SetElapsedTime(int64 elapsed_time) = 0; + virtual void SetTimeStamp(int64 time_stamp) = 0; + + // Indicates the rotation angle in degrees. + virtual int GetRotation() const = 0; + + // Make a shallow copy of the frame. The frame buffer itself is not copied. + // Both the current and new VideoFrame will share a single reference-counted + // frame buffer. + virtual VideoFrame *Copy() const = 0; + + // Since VideoFrame supports shallow copy and the internal frame buffer might + // be shared, in case VideoFrame needs exclusive access of the frame buffer, + // user can call MakeExclusive() to make sure the frame buffer is exclusive + // accessable to the current object. This might mean a deep copy of the frame + // buffer if it is currently shared by other objects. + virtual bool MakeExclusive() = 0; + + // Writes the frame into the given frame buffer, provided that it is of + // sufficient size. Returns the frame's actual size, regardless of whether + // it was written or not (like snprintf). If there is insufficient space, + // nothing is written. + virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const = 0; + + // Writes the frame into the given planes, stretched to the given width and + // height. The parameter "interpolate" controls whether to interpolate or just + // take the nearest-point. The parameter "crop" controls whether to crop this + // frame to the aspect ratio of the given dimensions before stretching. + virtual bool CopyToPlanes( + uint8* dst_y, uint8* dst_u, uint8* dst_v, + int32 dst_pitch_y, int32 dst_pitch_u, int32 dst_pitch_v) const; + + // Writes the frame into the target VideoFrame. + virtual void CopyToFrame(VideoFrame* target) const; + + // Writes the frame into the given stream and returns the StreamResult. + // See talk/base/stream.h for a description of StreamResult and error. + // Error may be NULL. If a non-success value is returned from + // StreamInterface::Write(), we immediately return with that value. + virtual talk_base::StreamResult Write(talk_base::StreamInterface *stream, + int *error); + + // Converts the I420 data to RGB of a certain type such as ARGB and ABGR. + // Returns the frame's actual size, regardless of whether it was written or + // not (like snprintf). Parameters size and stride_rgb are in units of bytes. + // If there is insufficient space, nothing is written. + virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8 *buffer, + size_t size, int stride_rgb) const = 0; + + // Writes the frame into the given planes, stretched to the given width and + // height. The parameter "interpolate" controls whether to interpolate or just + // take the nearest-point. The parameter "crop" controls whether to crop this + // frame to the aspect ratio of the given dimensions before stretching. + virtual void StretchToPlanes( + uint8 *y, uint8 *u, uint8 *v, int32 pitchY, int32 pitchU, int32 pitchV, + size_t width, size_t height, bool interpolate, bool crop) const; + + // Writes the frame into the given frame buffer, stretched to the given width + // and height, provided that it is of sufficient size. Returns the frame's + // actual size, regardless of whether it was written or not (like snprintf). + // If there is insufficient space, nothing is written. The parameter + // "interpolate" controls whether to interpolate or just take the + // nearest-point. The parameter "crop" controls whether to crop this frame to + // the aspect ratio of the given dimensions before stretching. + virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size, + bool interpolate, bool crop) const; + + // Writes the frame into the target VideoFrame, stretched to the size of that + // frame. The parameter "interpolate" controls whether to interpolate or just + // take the nearest-point. The parameter "crop" controls whether to crop this + // frame to the aspect ratio of the target frame before stretching. + virtual void StretchToFrame(VideoFrame *target, bool interpolate, + bool crop) const; + + // Stretches the frame to the given size, creating a new VideoFrame object to + // hold it. The parameter "interpolate" controls whether to interpolate or + // just take the nearest-point. The parameter "crop" controls whether to crop + // this frame to the aspect ratio of the given dimensions before stretching. + virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate, + bool crop) const; + + // Sets the video frame to black. + virtual bool SetToBlack(); + + // Tests if sample is valid. Returns true if valid. + static bool Validate(uint32 fourcc, int w, int h, const uint8 *sample, + size_t sample_size); + + // Size of an I420 image of given dimensions when stored as a frame buffer. + static size_t SizeOf(size_t w, size_t h) { + return w * h + ((w + 1) / 2) * ((h + 1) / 2) * 2; + } + + protected: + // Creates an empty frame. + virtual VideoFrame *CreateEmptyFrame(int w, int h, size_t pixel_width, + size_t pixel_height, int64 elapsed_time, + int64 time_stamp) const = 0; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_VIDEOFRAME_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/videoframe_unittest.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/videoframe_unittest.h new file mode 100644 index 0000000..0ff6f49 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/videoframe_unittest.h @@ -0,0 +1,2107 @@ +/* + * 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_BASE_VIDEOFRAME_UNITTEST_H_ +#define TALK_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_ + +#include + +#include "libyuv/convert.h" +#include "libyuv/convert_from.h" +#include "libyuv/format_conversion.h" +#include "libyuv/planar_functions.h" +#include "libyuv/rotate.h" +#include "talk/base/gunit.h" +#include "talk/base/pathutils.h" +#include "talk/base/stream.h" +#include "talk/base/stringutils.h" +#include "talk/media/base/testutils.h" +#include "talk/media/base/videocommon.h" +#include "talk/media/base/videoframe.h" + +#if defined(_MSC_VER) +#define ALIGN16(var) __declspec(align(16)) var +#else +#define ALIGN16(var) var __attribute__((aligned(16))) +#endif + +#define kImageFilename "faces.1280x720_P420.yuv" +#define kJpeg420Filename "faces_I420.jpg" +#define kJpeg422Filename "faces_I422.jpg" +#define kJpeg444Filename "faces_I444.jpg" +#define kJpeg411Filename "faces_I411.jpg" +#define kJpeg400Filename "faces_I400.jpg" + +// Generic test class for testing various video frame implementations. +template +class VideoFrameTest : public testing::Test { + public: + VideoFrameTest() : repeat_(1) {} + + protected: + static const int kWidth = 1280; + static const int kHeight = 720; + static const int kAlignment = 16; + static const int kMinWidthAll = 1; // Constants for ConstructYUY2AllSizes. + static const int kMinHeightAll = 1; + static const int kMaxWidthAll = 17; + static const int kMaxHeightAll = 23; + + // Load a video frame from disk. + bool LoadFrameNoRepeat(T* frame) { + int save_repeat = repeat_; // This LoadFrame disables repeat. + repeat_ = 1; + bool success = LoadFrame(kImageFilename, cricket::FOURCC_I420, + kWidth, kHeight, frame); + repeat_ = save_repeat; + return success; + } + + bool LoadFrame(const std::string& filename, uint32 format, + int32 width, int32 height, T* frame) { + return LoadFrame(filename, format, width, height, + width, abs(height), 0, frame); + } + bool LoadFrame(const std::string& filename, uint32 format, + int32 width, int32 height, int dw, int dh, int rotation, + T* frame) { + talk_base::scoped_ptr ms(LoadSample(filename)); + return LoadFrame(ms.get(), format, width, height, dw, dh, rotation, frame); + } + // Load a video frame from a memory stream. + bool LoadFrame(talk_base::MemoryStream* ms, uint32 format, + int32 width, int32 height, T* frame) { + return LoadFrame(ms, format, width, height, + width, abs(height), 0, frame); + } + bool LoadFrame(talk_base::MemoryStream* ms, uint32 format, + int32 width, int32 height, int dw, int dh, int rotation, + T* frame) { + if (!ms) { + return false; + } + size_t data_size; + bool ret = ms->GetSize(&data_size); + EXPECT_TRUE(ret); + if (ret) { + ret = LoadFrame(reinterpret_cast(ms->GetBuffer()), data_size, + format, width, height, dw, dh, rotation, frame); + } + return ret; + } + // Load a frame from a raw buffer. + bool LoadFrame(uint8* sample, size_t sample_size, uint32 format, + int32 width, int32 height, T* frame) { + return LoadFrame(sample, sample_size, format, width, height, + width, abs(height), 0, frame); + } + bool LoadFrame(uint8* sample, size_t sample_size, uint32 format, + int32 width, int32 height, int dw, int dh, int rotation, + T* frame) { + bool ret = false; + for (int i = 0; i < repeat_; ++i) { + ret = frame->Init(format, width, height, dw, dh, + sample, sample_size, 1, 1, 0, 0, rotation); + } + return ret; + } + + talk_base::MemoryStream* LoadSample(const std::string& filename) { + talk_base::Pathname path(cricket::GetTestFilePath(filename)); + talk_base::scoped_ptr fs( + talk_base::Filesystem::OpenFile(path, "rb")); + if (!fs.get()) { + return NULL; + } + + char buf[4096]; + talk_base::scoped_ptr ms( + new talk_base::MemoryStream()); + talk_base::StreamResult res = Flow(fs.get(), buf, sizeof(buf), ms.get()); + if (res != talk_base::SR_SUCCESS) { + return NULL; + } + + return ms.release(); + } + + // Write an I420 frame out to disk. + bool DumpFrame(const std::string& prefix, + const cricket::VideoFrame& frame) { + char filename[256]; + talk_base::sprintfn(filename, sizeof(filename), "%s.%dx%d_P420.yuv", + prefix.c_str(), frame.GetWidth(), frame.GetHeight()); + size_t out_size = cricket::VideoFrame::SizeOf(frame.GetWidth(), + frame.GetHeight()); + talk_base::scoped_ptr out(new uint8[out_size]); + frame.CopyToBuffer(out.get(), out_size); + return DumpSample(filename, out.get(), out_size); + } + + bool DumpSample(const std::string& filename, const void* buffer, int size) { + talk_base::Pathname path(filename); + talk_base::scoped_ptr fs( + talk_base::Filesystem::OpenFile(path, "wb")); + if (!fs.get()) { + return false; + } + + return (fs->Write(buffer, size, NULL, NULL) == talk_base::SR_SUCCESS); + } + + // Create a test image in the desired color space. + // The image is a checkerboard pattern with 63x63 squares, which allows + // I420 chroma artifacts to easily be seen on the square boundaries. + // The pattern is { { green, orange }, { blue, purple } } + // There is also a gradient within each square to ensure that the luma + // values are handled properly. + talk_base::MemoryStream* CreateYuv422Sample(uint32 fourcc, + uint32 width, uint32 height) { + int y1_pos, y2_pos, u_pos, v_pos; + if (!GetYuv422Packing(fourcc, &y1_pos, &y2_pos, &u_pos, &v_pos)) { + return NULL; + } + + talk_base::scoped_ptr ms( + new talk_base::MemoryStream); + int awidth = (width + 1) & ~1; + int size = awidth * 2 * height; + if (!ms->ReserveSize(size)) { + return NULL; + } + for (uint32 y = 0; y < height; ++y) { + for (int x = 0; x < awidth; x += 2) { + uint8 quad[4]; + quad[y1_pos] = (x % 63 + y % 63) + 64; + quad[y2_pos] = ((x + 1) % 63 + y % 63) + 64; + quad[u_pos] = ((x / 63) & 1) ? 192 : 64; + quad[v_pos] = ((y / 63) & 1) ? 192 : 64; + ms->Write(quad, sizeof(quad), NULL, NULL); + } + } + return ms.release(); + } + + // Create a test image for YUV 420 formats with 12 bits per pixel. + talk_base::MemoryStream* CreateYuvSample(uint32 width, uint32 height, + uint32 bpp) { + talk_base::scoped_ptr ms( + new talk_base::MemoryStream); + if (!ms->ReserveSize(width * height * bpp / 8)) { + return NULL; + } + + for (uint32 i = 0; i < width * height * bpp / 8; ++i) { + char value = ((i / 63) & 1) ? 192 : 64; + ms->Write(&value, sizeof(value), NULL, NULL); + } + return ms.release(); + } + + talk_base::MemoryStream* CreateRgbSample(uint32 fourcc, + uint32 width, uint32 height) { + int r_pos, g_pos, b_pos, bytes; + if (!GetRgbPacking(fourcc, &r_pos, &g_pos, &b_pos, &bytes)) { + return NULL; + } + + talk_base::scoped_ptr ms( + new talk_base::MemoryStream); + if (!ms->ReserveSize(width * height * bytes)) { + return NULL; + } + + for (uint32 y = 0; y < height; ++y) { + for (uint32 x = 0; x < width; ++x) { + uint8 rgb[4] = { 255, 255, 255, 255 }; + rgb[r_pos] = ((x / 63) & 1) ? 224 : 32; + rgb[g_pos] = (x % 63 + y % 63) + 96; + rgb[b_pos] = ((y / 63) & 1) ? 224 : 32; + ms->Write(rgb, bytes, NULL, NULL); + } + } + return ms.release(); + } + + // Simple conversion routines to verify the optimized VideoFrame routines. + // Converts from the specified colorspace to I420. + bool ConvertYuv422(const talk_base::MemoryStream* ms, + uint32 fourcc, uint32 width, uint32 height, + T* frame) { + int y1_pos, y2_pos, u_pos, v_pos; + if (!GetYuv422Packing(fourcc, &y1_pos, &y2_pos, &u_pos, &v_pos)) { + return false; + } + + const uint8* start = reinterpret_cast(ms->GetBuffer()); + int awidth = (width + 1) & ~1; + frame->InitToBlack(width, height, 1, 1, 0, 0); + int stride_y = frame->GetYPitch(); + int stride_u = frame->GetUPitch(); + int stride_v = frame->GetVPitch(); + for (uint32 y = 0; y < height; ++y) { + for (uint32 x = 0; x < width; x += 2) { + const uint8* quad1 = start + (y * awidth + x) * 2; + frame->GetYPlane()[stride_y * y + x] = quad1[y1_pos]; + if ((x + 1) < width) { + frame->GetYPlane()[stride_y * y + x + 1] = quad1[y2_pos]; + } + if ((y & 1) == 0) { + const uint8* quad2 = quad1 + awidth * 2; + if ((y + 1) >= height) { + quad2 = quad1; + } + frame->GetUPlane()[stride_u * (y / 2) + x / 2] = + (quad1[u_pos] + quad2[u_pos] + 1) / 2; + frame->GetVPlane()[stride_v * (y / 2) + x / 2] = + (quad1[v_pos] + quad2[v_pos] + 1) / 2; + } + } + } + return true; + } + + // Convert RGB to 420. + // A negative height inverts the image. + bool ConvertRgb(const talk_base::MemoryStream* ms, + uint32 fourcc, int32 width, int32 height, + T* frame) { + int r_pos, g_pos, b_pos, bytes; + if (!GetRgbPacking(fourcc, &r_pos, &g_pos, &b_pos, &bytes)) { + return false; + } + int pitch = width * bytes; + const uint8* start = reinterpret_cast(ms->GetBuffer()); + if (height < 0) { + height = -height; + start = start + pitch * (height - 1); + pitch = -pitch; + } + frame->InitToBlack(width, height, 1, 1, 0, 0); + int stride_y = frame->GetYPitch(); + int stride_u = frame->GetUPitch(); + int stride_v = frame->GetVPitch(); + for (int32 y = 0; y < height; y += 2) { + for (int32 x = 0; x < width; x += 2) { + const uint8* rgb[4]; + uint8 yuv[4][3]; + rgb[0] = start + y * pitch + x * bytes; + rgb[1] = rgb[0] + ((x + 1) < width ? bytes : 0); + rgb[2] = rgb[0] + ((y + 1) < height ? pitch : 0); + rgb[3] = rgb[2] + ((x + 1) < width ? bytes : 0); + for (size_t i = 0; i < 4; ++i) { + ConvertRgbPixel(rgb[i][r_pos], rgb[i][g_pos], rgb[i][b_pos], + &yuv[i][0], &yuv[i][1], &yuv[i][2]); + } + frame->GetYPlane()[stride_y * y + x] = yuv[0][0]; + if ((x + 1) < width) { + frame->GetYPlane()[stride_y * y + x + 1] = yuv[1][0]; + } + if ((y + 1) < height) { + frame->GetYPlane()[stride_y * (y + 1) + x] = yuv[2][0]; + if ((x + 1) < width) { + frame->GetYPlane()[stride_y * (y + 1) + x + 1] = yuv[3][0]; + } + } + frame->GetUPlane()[stride_u * (y / 2) + x / 2] = + (yuv[0][1] + yuv[1][1] + yuv[2][1] + yuv[3][1] + 2) / 4; + frame->GetVPlane()[stride_v * (y / 2) + x / 2] = + (yuv[0][2] + yuv[1][2] + yuv[2][2] + yuv[3][2] + 2) / 4; + } + } + return true; + } + + // Simple and slow RGB->YUV conversion. From NTSC standard, c/o Wikipedia. + void ConvertRgbPixel(uint8 r, uint8 g, uint8 b, + uint8* y, uint8* u, uint8* v) { + *y = static_cast(.257 * r + .504 * g + .098 * b) + 16; + *u = static_cast(-.148 * r - .291 * g + .439 * b) + 128; + *v = static_cast(.439 * r - .368 * g - .071 * b) + 128; + } + + bool GetYuv422Packing(uint32 fourcc, + int* y1_pos, int* y2_pos, int* u_pos, int* v_pos) { + if (fourcc == cricket::FOURCC_YUY2) { + *y1_pos = 0; *u_pos = 1; *y2_pos = 2; *v_pos = 3; + } else if (fourcc == cricket::FOURCC_UYVY) { + *u_pos = 0; *y1_pos = 1; *v_pos = 2; *y2_pos = 3; + } else { + return false; + } + return true; + } + + bool GetRgbPacking(uint32 fourcc, + int* r_pos, int* g_pos, int* b_pos, int* bytes) { + if (fourcc == cricket::FOURCC_RAW) { + *r_pos = 0; *g_pos = 1; *b_pos = 2; *bytes = 3; // RGB in memory. + } else if (fourcc == cricket::FOURCC_24BG) { + *r_pos = 2; *g_pos = 1; *b_pos = 0; *bytes = 3; // BGR in memory. + } else if (fourcc == cricket::FOURCC_ABGR) { + *r_pos = 0; *g_pos = 1; *b_pos = 2; *bytes = 4; // RGBA in memory. + } else if (fourcc == cricket::FOURCC_BGRA) { + *r_pos = 1; *g_pos = 2; *b_pos = 3; *bytes = 4; // ARGB in memory. + } else if (fourcc == cricket::FOURCC_ARGB) { + *r_pos = 2; *g_pos = 1; *b_pos = 0; *bytes = 4; // BGRA in memory. + } else { + return false; + } + return true; + } + + // Comparison functions for testing. + static bool IsNull(const cricket::VideoFrame& frame) { + return !frame.GetYPlane(); + } + + static bool IsSize(const cricket::VideoFrame& frame, + uint32 width, uint32 height) { + return !IsNull(frame) && + frame.GetYPitch() >= static_cast(width) && + frame.GetUPitch() >= static_cast(width) / 2 && + frame.GetVPitch() >= static_cast(width) / 2 && + frame.GetWidth() == width && frame.GetHeight() == height; + } + + static bool IsPlaneEqual(const std::string& name, + const uint8* plane1, uint32 pitch1, + const uint8* plane2, uint32 pitch2, + uint32 width, uint32 height, + int max_error) { + const uint8* r1 = plane1; + const uint8* r2 = plane2; + for (uint32 y = 0; y < height; ++y) { + for (uint32 x = 0; x < width; ++x) { + if (abs(static_cast(r1[x] - r2[x])) > max_error) { + LOG(LS_INFO) << "IsPlaneEqual(" << name << "): pixel[" + << x << "," << y << "] differs: " + << static_cast(r1[x]) << " vs " + << static_cast(r2[x]); + return false; + } + } + r1 += pitch1; + r2 += pitch2; + } + return true; + } + + static bool IsEqual(const cricket::VideoFrame& frame, + size_t width, size_t height, + size_t pixel_width, size_t pixel_height, + int64 elapsed_time, int64 time_stamp, + const uint8* y, uint32 ypitch, + const uint8* u, uint32 upitch, + const uint8* v, uint32 vpitch, + int max_error) { + return IsSize(frame, width, height) && + frame.GetPixelWidth() == pixel_width && + frame.GetPixelHeight() == pixel_height && + frame.GetElapsedTime() == elapsed_time && + frame.GetTimeStamp() == time_stamp && + IsPlaneEqual("y", frame.GetYPlane(), frame.GetYPitch(), y, ypitch, + width, height, max_error) && + IsPlaneEqual("u", frame.GetUPlane(), frame.GetUPitch(), u, upitch, + (width + 1) / 2, (height + 1) / 2, max_error) && + IsPlaneEqual("v", frame.GetVPlane(), frame.GetVPitch(), v, vpitch, + (width + 1) / 2, (height + 1) / 2, max_error); + } + + static bool IsEqual(const cricket::VideoFrame& frame1, + const cricket::VideoFrame& frame2, + int max_error) { + return IsEqual(frame1, + frame2.GetWidth(), frame2.GetHeight(), + frame2.GetPixelWidth(), frame2.GetPixelHeight(), + frame2.GetElapsedTime(), frame2.GetTimeStamp(), + frame2.GetYPlane(), frame2.GetYPitch(), + frame2.GetUPlane(), frame2.GetUPitch(), + frame2.GetVPlane(), frame2.GetVPitch(), + max_error); + } + + static bool IsEqualWithCrop(const cricket::VideoFrame& frame1, + const cricket::VideoFrame& frame2, + int hcrop, int vcrop, int max_error) { + return frame1.GetWidth() <= frame2.GetWidth() && + frame1.GetHeight() <= frame2.GetHeight() && + IsEqual(frame1, + frame2.GetWidth() - hcrop * 2, + frame2.GetHeight() - vcrop * 2, + frame2.GetPixelWidth(), frame2.GetPixelHeight(), + frame2.GetElapsedTime(), frame2.GetTimeStamp(), + frame2.GetYPlane() + vcrop * frame2.GetYPitch() + + hcrop, + frame2.GetYPitch(), + frame2.GetUPlane() + vcrop * frame2.GetUPitch() / 2 + + hcrop / 2, + frame2.GetUPitch(), + frame2.GetVPlane() + vcrop * frame2.GetVPitch() / 2 + + hcrop / 2, + frame2.GetVPitch(), + max_error); + } + + static bool IsBlack(const cricket::VideoFrame& frame) { + return !IsNull(frame) && + *frame.GetYPlane() == 16 && + *frame.GetUPlane() == 128 && + *frame.GetVPlane() == 128; + } + + //////////////////////// + // Construction tests // + //////////////////////// + + // Test constructing an image from a I420 buffer. + void ConstructI420() { + T frame; + EXPECT_TRUE(IsNull(frame)); + talk_base::scoped_ptr ms( + CreateYuvSample(kWidth, kHeight, 12)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, + kWidth, kHeight, &frame)); + + const uint8* y = reinterpret_cast(ms.get()->GetBuffer()); + const uint8* u = y + kWidth * kHeight; + const uint8* v = u + kWidth * kHeight / 4; + EXPECT_TRUE(IsEqual(frame, kWidth, kHeight, 1, 1, 0, 0, + y, kWidth, u, kWidth / 2, v, kWidth / 2, 0)); + } + + // Test constructing an image from a YV12 buffer. + void ConstructYV12() { + T frame; + talk_base::scoped_ptr ms( + CreateYuvSample(kWidth, kHeight, 12)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YV12, + kWidth, kHeight, &frame)); + + const uint8* y = reinterpret_cast(ms.get()->GetBuffer()); + const uint8* v = y + kWidth * kHeight; + const uint8* u = v + kWidth * kHeight / 4; + EXPECT_TRUE(IsEqual(frame, kWidth, kHeight, 1, 1, 0, 0, + y, kWidth, u, kWidth / 2, v, kWidth / 2, 0)); + } + + // Test constructing an image from a I422 buffer. + void ConstructI422() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + size_t buf_size = kWidth * kHeight * 2; + talk_base::scoped_ptr buf(new uint8[buf_size + kAlignment]); + uint8* y = ALIGNP(buf.get(), kAlignment); + uint8* u = y + kWidth * kHeight; + uint8* v = u + (kWidth / 2) * kHeight; + EXPECT_EQ(0, libyuv::I420ToI422(frame1.GetYPlane(), frame1.GetYPitch(), + frame1.GetUPlane(), frame1.GetUPitch(), + frame1.GetVPlane(), frame1.GetVPitch(), + y, kWidth, + u, kWidth / 2, + v, kWidth / 2, + kWidth, kHeight)); + EXPECT_TRUE(LoadFrame(y, buf_size, cricket::FOURCC_I422, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 1)); + } + + // Test constructing an image from a YUY2 buffer. + void ConstructYuy2() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + size_t buf_size = kWidth * kHeight * 2; + talk_base::scoped_ptr buf(new uint8[buf_size + kAlignment]); + uint8* yuy2 = ALIGNP(buf.get(), kAlignment); + EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.GetYPlane(), frame1.GetYPitch(), + frame1.GetUPlane(), frame1.GetUPitch(), + frame1.GetVPlane(), frame1.GetVPitch(), + yuy2, kWidth * 2, + kWidth, kHeight)); + EXPECT_TRUE(LoadFrame(yuy2, buf_size, cricket::FOURCC_YUY2, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + } + + // Test constructing an image from a YUY2 buffer with buffer unaligned. + void ConstructYuy2Unaligned() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + size_t buf_size = kWidth * kHeight * 2; + talk_base::scoped_ptr buf(new uint8[buf_size + kAlignment + 1]); + uint8* yuy2 = ALIGNP(buf.get(), kAlignment) + 1; + EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.GetYPlane(), frame1.GetYPitch(), + frame1.GetUPlane(), frame1.GetUPitch(), + frame1.GetVPlane(), frame1.GetVPitch(), + yuy2, kWidth * 2, + kWidth, kHeight)); + EXPECT_TRUE(LoadFrame(yuy2, buf_size, cricket::FOURCC_YUY2, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + } + + // Test constructing an image from a wide YUY2 buffer. + // Normal is 1280x720. Wide is 12800x72 + void ConstructYuy2Wide() { + T frame1, frame2; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth * 10, kHeight / 10)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, + kWidth * 10, kHeight / 10, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, + kWidth * 10, kHeight / 10, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + } + + // Test constructing an image from a UYVY buffer. + void ConstructUyvy() { + T frame1, frame2; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + } + + // Test constructing an image from a random buffer. + // We are merely verifying that the code succeeds and is free of crashes. + void ConstructM420() { + T frame; + talk_base::scoped_ptr ms( + CreateYuvSample(kWidth, kHeight, 12)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_M420, + kWidth, kHeight, &frame)); + } + + void ConstructQ420() { + T frame; + talk_base::scoped_ptr ms( + CreateYuvSample(kWidth, kHeight, 12)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_Q420, + kWidth, kHeight, &frame)); + } + + void ConstructNV21() { + T frame; + talk_base::scoped_ptr ms( + CreateYuvSample(kWidth, kHeight, 12)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_NV21, + kWidth, kHeight, &frame)); + } + + void ConstructNV12() { + T frame; + talk_base::scoped_ptr ms( + CreateYuvSample(kWidth, kHeight, 12)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_NV12, + kWidth, kHeight, &frame)); + } + + // Test constructing an image from a ABGR buffer + // Due to rounding, some pixels may differ slightly from the VideoFrame impl. + void ConstructABGR() { + T frame1, frame2; + talk_base::scoped_ptr ms( + CreateRgbSample(cricket::FOURCC_ABGR, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ABGR, kWidth, kHeight, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ABGR, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 2)); + } + + // Test constructing an image from a ARGB buffer + // Due to rounding, some pixels may differ slightly from the VideoFrame impl. + void ConstructARGB() { + T frame1, frame2; + talk_base::scoped_ptr ms( + CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 2)); + } + + // Test constructing an image from a wide ARGB buffer + // Normal is 1280x720. Wide is 12800x72 + void ConstructARGBWide() { + T frame1, frame2; + talk_base::scoped_ptr ms( + CreateRgbSample(cricket::FOURCC_ARGB, kWidth * 10, kHeight / 10)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, + kWidth * 10, kHeight / 10, &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, + kWidth * 10, kHeight / 10, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 2)); + } + + // Test constructing an image from an BGRA buffer. + // Due to rounding, some pixels may differ slightly from the VideoFrame impl. + void ConstructBGRA() { + T frame1, frame2; + talk_base::scoped_ptr ms( + CreateRgbSample(cricket::FOURCC_BGRA, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_BGRA, kWidth, kHeight, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_BGRA, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 2)); + } + + // Test constructing an image from a 24BG buffer. + // Due to rounding, some pixels may differ slightly from the VideoFrame impl. + void Construct24BG() { + T frame1, frame2; + talk_base::scoped_ptr ms( + CreateRgbSample(cricket::FOURCC_24BG, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_24BG, kWidth, kHeight, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_24BG, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 2)); + } + + // Test constructing an image from a raw RGB buffer. + // Due to rounding, some pixels may differ slightly from the VideoFrame impl. + void ConstructRaw() { + T frame1, frame2; + talk_base::scoped_ptr ms( + CreateRgbSample(cricket::FOURCC_RAW, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_RAW, kWidth, kHeight, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_RAW, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 2)); + } + + // Test constructing an image from a RGB565 buffer + void ConstructRGB565() { + T frame1, frame2; + size_t out_size = kWidth * kHeight * 2; + talk_base::scoped_ptr outbuf(new uint8[out_size + kAlignment]); + uint8 *out = ALIGNP(outbuf.get(), kAlignment); + T frame; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(cricket::FOURCC_RGBP, + out, + out_size, kWidth * 2)); + EXPECT_TRUE(LoadFrame(out, out_size, cricket::FOURCC_RGBP, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 20)); + } + + // Test constructing an image from a ARGB1555 buffer + void ConstructARGB1555() { + T frame1, frame2; + size_t out_size = kWidth * kHeight * 2; + talk_base::scoped_ptr outbuf(new uint8[out_size + kAlignment]); + uint8 *out = ALIGNP(outbuf.get(), kAlignment); + T frame; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(cricket::FOURCC_RGBO, + out, + out_size, kWidth * 2)); + EXPECT_TRUE(LoadFrame(out, out_size, cricket::FOURCC_RGBO, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 20)); + } + + // Test constructing an image from a ARGB4444 buffer + void ConstructARGB4444() { + T frame1, frame2; + size_t out_size = kWidth * kHeight * 2; + talk_base::scoped_ptr outbuf(new uint8[out_size + kAlignment]); + uint8 *out = ALIGNP(outbuf.get(), kAlignment); + T frame; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(cricket::FOURCC_R444, + out, + out_size, kWidth * 2)); + EXPECT_TRUE(LoadFrame(out, out_size, cricket::FOURCC_R444, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 20)); + } + + // Macro to help test different Bayer formats. + // Error threshold of 60 allows for Bayer format subsampling. + // TODO(fbarchard): Refactor this test to go from Bayer to I420 and + // back to bayer, which would be less lossy. + #define TEST_BYR(NAME, BAYER) \ + void NAME() { \ + size_t bayer_size = kWidth * kHeight; \ + talk_base::scoped_ptr bayerbuf(new uint8[ \ + bayer_size + kAlignment]); \ + uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment); \ + T frame1, frame2; \ + talk_base::scoped_ptr ms( \ + CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \ + ASSERT_TRUE(ms.get() != NULL); \ + libyuv::ARGBToBayer##BAYER(reinterpret_cast(ms->GetBuffer()), \ + kWidth * 4, \ + bayer, kWidth, \ + kWidth, kHeight); \ + EXPECT_TRUE(LoadFrame(bayer, bayer_size, cricket::FOURCC_##BAYER, \ + kWidth, kHeight, &frame1)); \ + EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight, \ + &frame2)); \ + EXPECT_TRUE(IsEqual(frame1, frame2, 60)); \ + } + + // Test constructing an image from Bayer formats. + TEST_BYR(ConstructBayerGRBG, GRBG) + TEST_BYR(ConstructBayerGBRG, GBRG) + TEST_BYR(ConstructBayerBGGR, BGGR) + TEST_BYR(ConstructBayerRGGB, RGGB) + + +// Macro to help test different rotations +#define TEST_MIRROR(FOURCC, BPP) \ +void Construct##FOURCC##Mirror() { \ + T frame1, frame2, frame3; \ + talk_base::scoped_ptr ms( \ + CreateYuvSample(kWidth, kHeight, BPP)); \ + ASSERT_TRUE(ms.get() != NULL); \ + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_##FOURCC, \ + kWidth, -kHeight, kWidth, kHeight, \ + cricket::ROTATION_180, &frame1)); \ + size_t data_size; \ + bool ret = ms->GetSize(&data_size); \ + EXPECT_TRUE(ret); \ + EXPECT_TRUE(frame2.Init(cricket::FOURCC_##FOURCC, \ + kWidth, kHeight, kWidth, kHeight, \ + reinterpret_cast(ms->GetBuffer()), \ + data_size, \ + 1, 1, 0, 0, 0)); \ + int width_rotate = frame1.GetWidth(); \ + int height_rotate = frame1.GetHeight(); \ + EXPECT_TRUE(frame3.InitToBlack(width_rotate, height_rotate, 1, 1, 0, 0)); \ + libyuv::I420Mirror(frame2.GetYPlane(), frame2.GetYPitch(), \ + frame2.GetUPlane(), frame2.GetUPitch(), \ + frame2.GetVPlane(), frame2.GetVPitch(), \ + frame3.GetYPlane(), frame3.GetYPitch(), \ + frame3.GetUPlane(), frame3.GetUPitch(), \ + frame3.GetVPlane(), frame3.GetVPitch(), \ + kWidth, kHeight); \ + EXPECT_TRUE(IsEqual(frame1, frame3, 0)); \ + } + + TEST_MIRROR(I420, 420) + +// Macro to help test different rotations +#define TEST_ROTATE(FOURCC, BPP, ROTATE) \ +void Construct##FOURCC##Rotate##ROTATE() { \ + T frame1, frame2, frame3; \ + talk_base::scoped_ptr ms( \ + CreateYuvSample(kWidth, kHeight, BPP)); \ + ASSERT_TRUE(ms.get() != NULL); \ + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_##FOURCC, \ + kWidth, kHeight, kWidth, kHeight, \ + cricket::ROTATION_##ROTATE, &frame1)); \ + size_t data_size; \ + bool ret = ms->GetSize(&data_size); \ + EXPECT_TRUE(ret); \ + EXPECT_TRUE(frame2.Init(cricket::FOURCC_##FOURCC, \ + kWidth, kHeight, kWidth, kHeight, \ + reinterpret_cast(ms->GetBuffer()), \ + data_size, \ + 1, 1, 0, 0, 0)); \ + int width_rotate = frame1.GetWidth(); \ + int height_rotate = frame1.GetHeight(); \ + EXPECT_TRUE(frame3.InitToBlack(width_rotate, height_rotate, 1, 1, 0, 0)); \ + libyuv::I420Rotate(frame2.GetYPlane(), frame2.GetYPitch(), \ + frame2.GetUPlane(), frame2.GetUPitch(), \ + frame2.GetVPlane(), frame2.GetVPitch(), \ + frame3.GetYPlane(), frame3.GetYPitch(), \ + frame3.GetUPlane(), frame3.GetUPitch(), \ + frame3.GetVPlane(), frame3.GetVPitch(), \ + kWidth, kHeight, libyuv::kRotate##ROTATE); \ + EXPECT_TRUE(IsEqual(frame1, frame3, 0)); \ + } + + // Test constructing an image with rotation. + TEST_ROTATE(I420, 12, 0) + TEST_ROTATE(I420, 12, 90) + TEST_ROTATE(I420, 12, 180) + TEST_ROTATE(I420, 12, 270) + TEST_ROTATE(YV12, 12, 0) + TEST_ROTATE(YV12, 12, 90) + TEST_ROTATE(YV12, 12, 180) + TEST_ROTATE(YV12, 12, 270) + TEST_ROTATE(NV12, 12, 0) + TEST_ROTATE(NV12, 12, 90) + TEST_ROTATE(NV12, 12, 180) + TEST_ROTATE(NV12, 12, 270) + TEST_ROTATE(NV21, 12, 0) + TEST_ROTATE(NV21, 12, 90) + TEST_ROTATE(NV21, 12, 180) + TEST_ROTATE(NV21, 12, 270) + TEST_ROTATE(UYVY, 16, 0) + TEST_ROTATE(UYVY, 16, 90) + TEST_ROTATE(UYVY, 16, 180) + TEST_ROTATE(UYVY, 16, 270) + TEST_ROTATE(YUY2, 16, 0) + TEST_ROTATE(YUY2, 16, 90) + TEST_ROTATE(YUY2, 16, 180) + TEST_ROTATE(YUY2, 16, 270) + + // Test constructing an image from a UYVY buffer rotated 90 degrees. + void ConstructUyvyRotate90() { + T frame2; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, + kWidth, kHeight, kWidth, kHeight, + cricket::ROTATION_90, &frame2)); + } + + // Test constructing an image from a UYVY buffer rotated 180 degrees. + void ConstructUyvyRotate180() { + T frame2; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, + kWidth, kHeight, kWidth, kHeight, + cricket::ROTATION_180, &frame2)); + } + + // Test constructing an image from a UYVY buffer rotated 270 degrees. + void ConstructUyvyRotate270() { + T frame2; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, + kWidth, kHeight, kWidth, kHeight, + cricket::ROTATION_270, &frame2)); + } + + // Test constructing an image from a YUY2 buffer rotated 90 degrees. + void ConstructYuy2Rotate90() { + T frame2; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, + kWidth, kHeight, kWidth, kHeight, + cricket::ROTATION_90, &frame2)); + } + + // Test constructing an image from a YUY2 buffer rotated 180 degrees. + void ConstructYuy2Rotate180() { + T frame2; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, + kWidth, kHeight, kWidth, kHeight, + cricket::ROTATION_180, &frame2)); + } + + // Test constructing an image from a YUY2 buffer rotated 270 degrees. + void ConstructYuy2Rotate270() { + T frame2; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, + kWidth, kHeight, kWidth, kHeight, + cricket::ROTATION_270, &frame2)); + } + + // Test 1 pixel edge case image I420 buffer. + void ConstructI4201Pixel() { + T frame; + uint8 pixel[3] = { 1, 2, 3 }; + for (int i = 0; i < repeat_; ++i) { + EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 1, 1, 1, 1, + pixel, sizeof(pixel), + 1, 1, 0, 0, 0)); + } + const uint8* y = pixel; + const uint8* u = y + 1; + const uint8* v = u + 1; + EXPECT_TRUE(IsEqual(frame, 1, 1, 1, 1, 0, 0, + y, 1, u, 1, v, 1, 0)); + } + + // Test 5 pixel edge case image I420 buffer rounds down to 4. + void ConstructI4205Pixel() { + T frame; + uint8 pixels5x5[5 * 5 + ((5 + 1) / 2 * (5 + 1) / 2) * 2]; + memset(pixels5x5, 1, 5 * 5 + ((5 + 1) / 2 * (5 + 1) / 2) * 2); + for (int i = 0; i < repeat_; ++i) { + EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 5, 5, 5, 5, + pixels5x5, sizeof(pixels5x5), + 1, 1, 0, 0, 0)); + } + EXPECT_EQ(4u, frame.GetWidth()); + EXPECT_EQ(4u, frame.GetHeight()); + EXPECT_EQ(4, frame.GetYPitch()); + EXPECT_EQ(2, frame.GetUPitch()); + EXPECT_EQ(2, frame.GetVPitch()); + } + + // Test 1 pixel edge case image ARGB buffer. + void ConstructARGB1Pixel() { + T frame; + uint8 pixel[4] = { 64, 128, 192, 255 }; + for (int i = 0; i < repeat_; ++i) { + EXPECT_TRUE(frame.Init(cricket::FOURCC_ARGB, 1, 1, 1, 1, + pixel, sizeof(pixel), + 1, 1, 0, 0, 0)); + } + // Convert back to ARGB. + size_t out_size = 4; + talk_base::scoped_ptr outbuf(new uint8[out_size + kAlignment]); + uint8 *out = ALIGNP(outbuf.get(), kAlignment); + + EXPECT_EQ(out_size, frame.ConvertToRgbBuffer(cricket::FOURCC_ARGB, + out, + out_size, // buffer size + out_size)); // stride + #ifdef USE_LMI_CONVERT + // TODO(fbarchard): Expected to fail, but not crash. + EXPECT_FALSE(IsPlaneEqual("argb", pixel, 4, out, 4, 3, 1, 2)); + #else + // TODO(fbarchard): Check for overwrite. + EXPECT_TRUE(IsPlaneEqual("argb", pixel, 4, out, 4, 3, 1, 2)); + #endif + } + + // Test Black, White and Grey pixels. + void ConstructARGBBlackWhitePixel() { + T frame; + uint8 pixel[10 * 4] = { 0, 0, 0, 255, // Black. + 0, 0, 0, 255, + 64, 64, 64, 255, // Dark Grey. + 64, 64, 64, 255, + 128, 128, 128, 255, // Grey. + 128, 128, 128, 255, + 196, 196, 196, 255, // Light Grey. + 196, 196, 196, 255, + 255, 255, 255, 255, // White. + 255, 255, 255, 255 }; + + for (int i = 0; i < repeat_; ++i) { + EXPECT_TRUE(frame.Init(cricket::FOURCC_ARGB, 10, 1, 10, 1, + pixel, sizeof(pixel), + 1, 1, 0, 0, 0)); + } + // Convert back to ARGB + size_t out_size = 10 * 4; + talk_base::scoped_ptr outbuf(new uint8[out_size + kAlignment]); + uint8 *out = ALIGNP(outbuf.get(), kAlignment); + + EXPECT_EQ(out_size, frame.ConvertToRgbBuffer(cricket::FOURCC_ARGB, + out, + out_size, // buffer size. + out_size)); // stride. + EXPECT_TRUE(IsPlaneEqual("argb", pixel, out_size, + out, out_size, + out_size, 1, 2)); + } + + // Test constructing an image from an I420 buffer with horizontal cropping. + void ConstructI420CropHorizontal() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_I420, kWidth, kHeight, + kWidth * 3 / 4, kHeight, 0, &frame2)); + EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 0)); + } + + // Test constructing an image from a YUY2 buffer with horizontal cropping. + void ConstructYuy2CropHorizontal() { + T frame1, frame2; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight, + kWidth * 3 / 4, kHeight, 0, &frame2)); + EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 0)); + } + + // Test constructing an image from an ARGB buffer with horizontal cropping. + void ConstructARGBCropHorizontal() { + T frame1, frame2; + talk_base::scoped_ptr ms( + CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, kWidth, kHeight, + kWidth * 3 / 4, kHeight, 0, &frame2)); + EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, kWidth / 8, 0, 2)); + } + + // Test constructing an image from an I420 buffer, cropping top and bottom. + void ConstructI420CropVertical() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_I420, kWidth, kHeight, + kWidth, kHeight * 3 / 4, 0, &frame2)); + EXPECT_TRUE(IsEqualWithCrop(frame2, frame1, 0, kHeight / 8, 0)); + } + + // Test constructing an image from I420 synonymous formats. + void ConstructI420Aliases() { + T frame1, frame2, frame3; + ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_I420, kWidth, kHeight, + &frame1)); + ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_IYUV, kWidth, kHeight, + &frame2)); + ASSERT_TRUE(LoadFrame(kImageFilename, cricket::FOURCC_YU12, kWidth, kHeight, + &frame3)); + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + EXPECT_TRUE(IsEqual(frame1, frame3, 0)); + } + + // Test constructing an image from an I420 MJPG buffer. + void ConstructMjpgI420() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + ASSERT_TRUE(LoadFrame(kJpeg420Filename, + cricket::FOURCC_MJPG, kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 32)); + } + + // Test constructing an image from an I422 MJPG buffer. + void ConstructMjpgI422() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + ASSERT_TRUE(LoadFrame(kJpeg422Filename, + cricket::FOURCC_MJPG, kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 32)); + } + + // Test constructing an image from an I444 MJPG buffer. + void ConstructMjpgI444() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + ASSERT_TRUE(LoadFrame(kJpeg444Filename, + cricket::FOURCC_MJPG, kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 32)); + } + + // Test constructing an image from an I444 MJPG buffer. + void ConstructMjpgI411() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + ASSERT_TRUE(LoadFrame(kJpeg411Filename, + cricket::FOURCC_MJPG, kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 32)); + } + + // Test constructing an image from an I400 MJPG buffer. + // TODO(fbarchard): Stronger compare on chroma. Compare agaisnt a grey image. + void ConstructMjpgI400() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + ASSERT_TRUE(LoadFrame(kJpeg400Filename, + cricket::FOURCC_MJPG, kWidth, kHeight, &frame2)); + EXPECT_TRUE(IsPlaneEqual("y", frame1.GetYPlane(), frame1.GetYPitch(), + frame2.GetYPlane(), frame2.GetYPitch(), + kWidth, kHeight, 32)); + EXPECT_TRUE(IsEqual(frame1, frame2, 128)); + } + + // Test constructing an image from an I420 MJPG buffer. + void ValidateFrame(const char* name, uint32 fourcc, int data_adjust, + int size_adjust, bool expected_result) { + T frame; + talk_base::scoped_ptr ms(LoadSample(name)); + ASSERT_TRUE(ms.get() != NULL); + const uint8* sample = reinterpret_cast(ms.get()->GetBuffer()); + size_t sample_size; + ms->GetSize(&sample_size); + // Optional adjust size to test invalid size. + size_t data_size = sample_size + data_adjust; + + // Allocate a buffer with end page aligned. + const int kPadToHeapSized = 16 * 1024 * 1024; + talk_base::scoped_ptr page_buffer( + new uint8[((data_size + kPadToHeapSized + 4095) & ~4095)]); + uint8* data_ptr = page_buffer.get(); + if (!data_ptr) { + LOG(LS_WARNING) << "Failed to allocate memory for ValidateFrame test."; + EXPECT_FALSE(expected_result); // NULL is okay if failure was expected. + return; + } + data_ptr += kPadToHeapSized + (-(static_cast(data_size)) & 4095); + memcpy(data_ptr, sample, talk_base::_min(data_size, sample_size)); + for (int i = 0; i < repeat_; ++i) { + EXPECT_EQ(expected_result, frame.Validate(fourcc, kWidth, kHeight, + data_ptr, + sample_size + size_adjust)); + } + } + + // Test validate for I420 MJPG buffer. + void ValidateMjpgI420() { + ValidateFrame(kJpeg420Filename, cricket::FOURCC_MJPG, 0, 0, true); + } + + // Test validate for I422 MJPG buffer. + void ValidateMjpgI422() { + ValidateFrame(kJpeg422Filename, cricket::FOURCC_MJPG, 0, 0, true); + } + + // Test validate for I444 MJPG buffer. + void ValidateMjpgI444() { + ValidateFrame(kJpeg444Filename, cricket::FOURCC_MJPG, 0, 0, true); + } + + // Test validate for I411 MJPG buffer. + void ValidateMjpgI411() { + ValidateFrame(kJpeg411Filename, cricket::FOURCC_MJPG, 0, 0, true); + } + + // Test validate for I400 MJPG buffer. + void ValidateMjpgI400() { + ValidateFrame(kJpeg400Filename, cricket::FOURCC_MJPG, 0, 0, true); + } + + // Test validate for I420 buffer. + void ValidateI420() { + ValidateFrame(kImageFilename, cricket::FOURCC_I420, 0, 0, true); + } + + // Test validate for I420 buffer where size is too small + void ValidateI420SmallSize() { + ValidateFrame(kImageFilename, cricket::FOURCC_I420, 0, -16384, false); + } + + // Test validate for I420 buffer where size is too large (16 MB) + // Will produce warning but pass. + void ValidateI420LargeSize() { + ValidateFrame(kImageFilename, cricket::FOURCC_I420, 16000000, 16000000, + true); + } + + // Test validate for I420 buffer where size is 1 GB (not reasonable). + void ValidateI420HugeSize() { +#ifndef WIN32 // TODO(fbarchard): Reenable when fixing bug 9603762. + ValidateFrame(kImageFilename, cricket::FOURCC_I420, 1000000000u, + 1000000000u, false); +#endif + } + + // The following test that Validate crashes if the size is greater than the + // actual buffer size. + // TODO(fbarchard): Consider moving a filter into the capturer/plugin. +#if defined(_MSC_VER) && defined(_DEBUG) + int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) { + if (code == EXCEPTION_ACCESS_VIOLATION) { + LOG(LS_INFO) << "Caught EXCEPTION_ACCESS_VIOLATION as expected."; + return EXCEPTION_EXECUTE_HANDLER; + } else { + LOG(LS_INFO) << "Did not catch EXCEPTION_ACCESS_VIOLATION. Unexpected."; + return EXCEPTION_CONTINUE_SEARCH; + } + } + + // Test validate fails for truncated MJPG data buffer. If ValidateFrame + // crashes the exception handler will return and unittest passes with OK. + void ValidateMjpgI420InvalidSize() { + __try { + ValidateFrame(kJpeg420Filename, cricket::FOURCC_MJPG, -16384, 0, false); + FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION."; + } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) { + return; // Successfully crashed in ValidateFrame. + } + } + + // Test validate fails for truncated I420 buffer. + void ValidateI420InvalidSize() { + __try { + ValidateFrame(kImageFilename, cricket::FOURCC_I420, -16384, 0, false); + FAIL() << "Validate was expected to cause EXCEPTION_ACCESS_VIOLATION."; + } __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) { + return; // Successfully crashed in ValidateFrame. + } + } +#endif + + // Test constructing an image from a YUY2 buffer (and synonymous formats). + void ConstructYuy2Aliases() { + T frame1, frame2, frame3, frame4; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_YUY2, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, kWidth, kHeight, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUVS, + kWidth, kHeight, &frame3)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUYV, + kWidth, kHeight, &frame4)); + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + EXPECT_TRUE(IsEqual(frame1, frame3, 0)); + EXPECT_TRUE(IsEqual(frame1, frame4, 0)); + } + + // Test constructing an image from a UYVY buffer (and synonymous formats). + void ConstructUyvyAliases() { + T frame1, frame2, frame3, frame4; + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_UYVY, kWidth, kHeight)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_UYVY, kWidth, kHeight, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_UYVY, + kWidth, kHeight, &frame2)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_2VUY, + kWidth, kHeight, &frame3)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_HDYC, + kWidth, kHeight, &frame4)); + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + EXPECT_TRUE(IsEqual(frame1, frame3, 0)); + EXPECT_TRUE(IsEqual(frame1, frame4, 0)); + } + + // Test creating a copy. + void ConstructCopy() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + for (int i = 0; i < repeat_; ++i) { + EXPECT_TRUE(frame2.Init(frame1)); + } + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + } + + // Test creating a copy and check that it just increments the refcount. + void ConstructCopyIsRef() { + T frame1, frame2; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + for (int i = 0; i < repeat_; ++i) { + EXPECT_TRUE(frame2.Init(frame1)); + } + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + EXPECT_EQ(frame1.GetYPlane(), frame2.GetYPlane()); + EXPECT_EQ(frame1.GetUPlane(), frame2.GetUPlane()); + EXPECT_EQ(frame1.GetVPlane(), frame2.GetVPlane()); + } + + // Test creating an empty image and initing it to black. + void ConstructBlack() { + T frame; + for (int i = 0; i < repeat_; ++i) { + EXPECT_TRUE(frame.InitToBlack(kWidth, kHeight, 1, 1, 0, 0)); + } + EXPECT_TRUE(IsSize(frame, kWidth, kHeight)); + EXPECT_TRUE(IsBlack(frame)); + } + + // Test constructing an image from a YUY2 buffer with a range of sizes. + // Only tests that conversion does not crash or corrupt heap. + void ConstructYuy2AllSizes() { + T frame1, frame2; + for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) { + for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) { + talk_base::scoped_ptr ms( + CreateYuv422Sample(cricket::FOURCC_YUY2, width, height)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertYuv422(ms.get(), cricket::FOURCC_YUY2, width, height, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_YUY2, + width, height, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + } + } + } + + // Test constructing an image from a ARGB buffer with a range of sizes. + // Only tests that conversion does not crash or corrupt heap. + void ConstructARGBAllSizes() { + T frame1, frame2; + for (int height = kMinHeightAll; height <= kMaxHeightAll; ++height) { + for (int width = kMinWidthAll; width <= kMaxWidthAll; ++width) { + talk_base::scoped_ptr ms( + CreateRgbSample(cricket::FOURCC_ARGB, width, height)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, width, height, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, + width, height, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 64)); + } + } + // Test a practical window size for screencasting usecase. + const int kOddWidth = 1228; + const int kOddHeight = 260; + for (int j = 0; j < 2; ++j) { + for (int i = 0; i < 2; ++i) { + talk_base::scoped_ptr ms( + CreateRgbSample(cricket::FOURCC_ARGB, kOddWidth + i, kOddHeight + j)); + ASSERT_TRUE(ms.get() != NULL); + EXPECT_TRUE(ConvertRgb(ms.get(), cricket::FOURCC_ARGB, + kOddWidth + i, kOddHeight + j, + &frame1)); + EXPECT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_ARGB, + kOddWidth + i, kOddHeight + j, &frame2)); + EXPECT_TRUE(IsEqual(frame1, frame2, 64)); + } + } + } + + // Tests re-initing an existing image. + void Reset() { + T frame1, frame2; + talk_base::scoped_ptr ms( + LoadSample(kImageFilename)); + ASSERT_TRUE(ms.get() != NULL); + size_t data_size; + ms->GetSize(&data_size); + EXPECT_TRUE(frame1.InitToBlack(kWidth, kHeight, 1, 1, 0, 0)); + EXPECT_TRUE(frame2.InitToBlack(kWidth, kHeight, 1, 1, 0, 0)); + EXPECT_TRUE(IsBlack(frame1)); + EXPECT_TRUE(IsEqual(frame1, frame2, 0)); + EXPECT_TRUE(frame1.Reset(cricket::FOURCC_I420, + kWidth, kHeight, kWidth, kHeight, + reinterpret_cast(ms->GetBuffer()), + data_size, 1, 1, 0, 0, 0)); + EXPECT_FALSE(IsBlack(frame1)); + EXPECT_FALSE(IsEqual(frame1, frame2, 0)); + } + + ////////////////////// + // Conversion tests // + ////////////////////// + + enum ToFrom { TO, FROM }; + + // Helper function for test converting from I420 to packed formats. + inline void ConvertToBuffer(int bpp, int rowpad, bool invert, ToFrom to_from, + int error, uint32 fourcc, + int (*RGBToI420)(const uint8* src_frame, int src_stride_frame, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height)) { + T frame1, frame2; + int repeat_to = (to_from == TO) ? repeat_ : 1; + int repeat_from = (to_from == FROM) ? repeat_ : 1; + + int astride = kWidth * bpp + rowpad; + size_t out_size = astride * kHeight; + talk_base::scoped_ptr outbuf(new uint8[out_size + kAlignment + 1]); + memset(outbuf.get(), 0, out_size + kAlignment + 1); + uint8 *outtop = ALIGNP(outbuf.get(), kAlignment); + uint8 *out = outtop; + int stride = astride; + if (invert) { + out += (kHeight - 1) * stride; // Point to last row. + stride = -stride; + } + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + + for (int i = 0; i < repeat_to; ++i) { + EXPECT_EQ(out_size, frame1.ConvertToRgbBuffer(fourcc, + out, + out_size, stride)); + } + EXPECT_TRUE(frame2.InitToBlack(kWidth, kHeight, 1, 1, 0, 0)); + for (int i = 0; i < repeat_from; ++i) { + EXPECT_EQ(0, RGBToI420(out, stride, + frame2.GetYPlane(), frame2.GetYPitch(), + frame2.GetUPlane(), frame2.GetUPitch(), + frame2.GetVPlane(), frame2.GetVPitch(), + kWidth, kHeight)); + } + if (rowpad) { + EXPECT_EQ(0, outtop[kWidth * bpp]); // Ensure stride skipped end of row. + EXPECT_NE(0, outtop[astride]); // Ensure pixel at start of 2nd row. + } else { + EXPECT_NE(0, outtop[kWidth * bpp]); // Expect something to be here. + } + EXPECT_EQ(0, outtop[out_size]); // Ensure no overrun. + EXPECT_TRUE(IsEqual(frame1, frame2, error)); + } + + static const int kError = 20; + static const int kErrorHigh = 40; + static const int kOddStride = 23; + + // Tests ConvertToRGBBuffer formats. + void ConvertToARGBBuffer() { + ConvertToBuffer(4, 0, false, TO, kError, + cricket::FOURCC_ARGB, libyuv::ARGBToI420); + } + void ConvertToBGRABuffer() { + ConvertToBuffer(4, 0, false, TO, kError, + cricket::FOURCC_BGRA, libyuv::BGRAToI420); + } + void ConvertToABGRBuffer() { + ConvertToBuffer(4, 0, false, TO, kError, + cricket::FOURCC_ABGR, libyuv::ABGRToI420); + } + void ConvertToRGB24Buffer() { + ConvertToBuffer(3, 0, false, TO, kError, + cricket::FOURCC_24BG, libyuv::RGB24ToI420); + } + void ConvertToRAWBuffer() { + ConvertToBuffer(3, 0, false, TO, kError, + cricket::FOURCC_RAW, libyuv::RAWToI420); + } + void ConvertToRGB565Buffer() { + ConvertToBuffer(2, 0, false, TO, kError, + cricket::FOURCC_RGBP, libyuv::RGB565ToI420); + } + void ConvertToARGB1555Buffer() { + ConvertToBuffer(2, 0, false, TO, kError, + cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420); + } + void ConvertToARGB4444Buffer() { + ConvertToBuffer(2, 0, false, TO, kError, + cricket::FOURCC_R444, libyuv::ARGB4444ToI420); + } + void ConvertToBayerBGGRBuffer() { + ConvertToBuffer(1, 0, false, TO, kErrorHigh, + cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420); + } + void ConvertToBayerGBRGBuffer() { + ConvertToBuffer(1, 0, false, TO, kErrorHigh, + cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420); + } + void ConvertToBayerGRBGBuffer() { + ConvertToBuffer(1, 0, false, TO, kErrorHigh, + cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420); + } + void ConvertToBayerRGGBBuffer() { + ConvertToBuffer(1, 0, false, TO, kErrorHigh, + cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420); + } + void ConvertToI400Buffer() { + ConvertToBuffer(1, 0, false, TO, 128, + cricket::FOURCC_I400, libyuv::I400ToI420); + } + void ConvertToYUY2Buffer() { + ConvertToBuffer(2, 0, false, TO, kError, + cricket::FOURCC_YUY2, libyuv::YUY2ToI420); + } + void ConvertToUYVYBuffer() { + ConvertToBuffer(2, 0, false, TO, kError, + cricket::FOURCC_UYVY, libyuv::UYVYToI420); + } + + // Tests ConvertToRGBBuffer formats with odd stride. + void ConvertToARGBBufferStride() { + ConvertToBuffer(4, kOddStride, false, TO, kError, + cricket::FOURCC_ARGB, libyuv::ARGBToI420); + } + void ConvertToBGRABufferStride() { + ConvertToBuffer(4, kOddStride, false, TO, kError, + cricket::FOURCC_BGRA, libyuv::BGRAToI420); + } + void ConvertToABGRBufferStride() { + ConvertToBuffer(4, kOddStride, false, TO, kError, + cricket::FOURCC_ABGR, libyuv::ABGRToI420); + } + void ConvertToRGB24BufferStride() { + ConvertToBuffer(3, kOddStride, false, TO, kError, + cricket::FOURCC_24BG, libyuv::RGB24ToI420); + } + void ConvertToRAWBufferStride() { + ConvertToBuffer(3, kOddStride, false, TO, kError, + cricket::FOURCC_RAW, libyuv::RAWToI420); + } + void ConvertToRGB565BufferStride() { + ConvertToBuffer(2, kOddStride, false, TO, kError, + cricket::FOURCC_RGBP, libyuv::RGB565ToI420); + } + void ConvertToARGB1555BufferStride() { + ConvertToBuffer(2, kOddStride, false, TO, kError, + cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420); + } + void ConvertToARGB4444BufferStride() { + ConvertToBuffer(2, kOddStride, false, TO, kError, + cricket::FOURCC_R444, libyuv::ARGB4444ToI420); + } + void ConvertToBayerBGGRBufferStride() { + ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh, + cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420); + } + void ConvertToBayerGBRGBufferStride() { + ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh, + cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420); + } + void ConvertToBayerGRBGBufferStride() { + ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh, + cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420); + } + void ConvertToBayerRGGBBufferStride() { + ConvertToBuffer(1, kOddStride, false, TO, kErrorHigh, + cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420); + } + void ConvertToI400BufferStride() { + ConvertToBuffer(1, kOddStride, false, TO, 128, + cricket::FOURCC_I400, libyuv::I400ToI420); + } + void ConvertToYUY2BufferStride() { + ConvertToBuffer(2, kOddStride, false, TO, kError, + cricket::FOURCC_YUY2, libyuv::YUY2ToI420); + } + void ConvertToUYVYBufferStride() { + ConvertToBuffer(2, kOddStride, false, TO, kError, + cricket::FOURCC_UYVY, libyuv::UYVYToI420); + } + + // Tests ConvertToRGBBuffer formats with negative stride to invert image. + void ConvertToARGBBufferInverted() { + ConvertToBuffer(4, 0, true, TO, kError, + cricket::FOURCC_ARGB, libyuv::ARGBToI420); + } + void ConvertToBGRABufferInverted() { + ConvertToBuffer(4, 0, true, TO, kError, + cricket::FOURCC_BGRA, libyuv::BGRAToI420); + } + void ConvertToABGRBufferInverted() { + ConvertToBuffer(4, 0, true, TO, kError, + cricket::FOURCC_ABGR, libyuv::ABGRToI420); + } + void ConvertToRGB24BufferInverted() { + ConvertToBuffer(3, 0, true, TO, kError, + cricket::FOURCC_24BG, libyuv::RGB24ToI420); + } + void ConvertToRAWBufferInverted() { + ConvertToBuffer(3, 0, true, TO, kError, + cricket::FOURCC_RAW, libyuv::RAWToI420); + } + void ConvertToRGB565BufferInverted() { + ConvertToBuffer(2, 0, true, TO, kError, + cricket::FOURCC_RGBP, libyuv::RGB565ToI420); + } + void ConvertToARGB1555BufferInverted() { + ConvertToBuffer(2, 0, true, TO, kError, + cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420); + } + void ConvertToARGB4444BufferInverted() { + ConvertToBuffer(2, 0, true, TO, kError, + cricket::FOURCC_R444, libyuv::ARGB4444ToI420); + } + void ConvertToBayerBGGRBufferInverted() { + ConvertToBuffer(1, 0, true, TO, kErrorHigh, + cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420); + } + void ConvertToBayerGBRGBufferInverted() { + ConvertToBuffer(1, 0, true, TO, kErrorHigh, + cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420); + } + void ConvertToBayerGRBGBufferInverted() { + ConvertToBuffer(1, 0, true, TO, kErrorHigh, + cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420); + } + void ConvertToBayerRGGBBufferInverted() { + ConvertToBuffer(1, 0, true, TO, kErrorHigh, + cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420); + } + void ConvertToI400BufferInverted() { + ConvertToBuffer(1, 0, true, TO, 128, + cricket::FOURCC_I400, libyuv::I400ToI420); + } + void ConvertToYUY2BufferInverted() { + ConvertToBuffer(2, 0, true, TO, kError, + cricket::FOURCC_YUY2, libyuv::YUY2ToI420); + } + void ConvertToUYVYBufferInverted() { + ConvertToBuffer(2, 0, true, TO, kError, + cricket::FOURCC_UYVY, libyuv::UYVYToI420); + } + + // Tests ConvertFrom formats. + void ConvertFromARGBBuffer() { + ConvertToBuffer(4, 0, false, FROM, kError, + cricket::FOURCC_ARGB, libyuv::ARGBToI420); + } + void ConvertFromBGRABuffer() { + ConvertToBuffer(4, 0, false, FROM, kError, + cricket::FOURCC_BGRA, libyuv::BGRAToI420); + } + void ConvertFromABGRBuffer() { + ConvertToBuffer(4, 0, false, FROM, kError, + cricket::FOURCC_ABGR, libyuv::ABGRToI420); + } + void ConvertFromRGB24Buffer() { + ConvertToBuffer(3, 0, false, FROM, kError, + cricket::FOURCC_24BG, libyuv::RGB24ToI420); + } + void ConvertFromRAWBuffer() { + ConvertToBuffer(3, 0, false, FROM, kError, + cricket::FOURCC_RAW, libyuv::RAWToI420); + } + void ConvertFromRGB565Buffer() { + ConvertToBuffer(2, 0, false, FROM, kError, + cricket::FOURCC_RGBP, libyuv::RGB565ToI420); + } + void ConvertFromARGB1555Buffer() { + ConvertToBuffer(2, 0, false, FROM, kError, + cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420); + } + void ConvertFromARGB4444Buffer() { + ConvertToBuffer(2, 0, false, FROM, kError, + cricket::FOURCC_R444, libyuv::ARGB4444ToI420); + } + void ConvertFromBayerBGGRBuffer() { + ConvertToBuffer(1, 0, false, FROM, kErrorHigh, + cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420); + } + void ConvertFromBayerGBRGBuffer() { + ConvertToBuffer(1, 0, false, FROM, kErrorHigh, + cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420); + } + void ConvertFromBayerGRBGBuffer() { + ConvertToBuffer(1, 0, false, FROM, kErrorHigh, + cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420); + } + void ConvertFromBayerRGGBBuffer() { + ConvertToBuffer(1, 0, false, FROM, kErrorHigh, + cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420); + } + void ConvertFromI400Buffer() { + ConvertToBuffer(1, 0, false, FROM, 128, + cricket::FOURCC_I400, libyuv::I400ToI420); + } + void ConvertFromYUY2Buffer() { + ConvertToBuffer(2, 0, false, FROM, kError, + cricket::FOURCC_YUY2, libyuv::YUY2ToI420); + } + void ConvertFromUYVYBuffer() { + ConvertToBuffer(2, 0, false, FROM, kError, + cricket::FOURCC_UYVY, libyuv::UYVYToI420); + } + + // Tests ConvertFrom formats with odd stride. + void ConvertFromARGBBufferStride() { + ConvertToBuffer(4, kOddStride, false, FROM, kError, + cricket::FOURCC_ARGB, libyuv::ARGBToI420); + } + void ConvertFromBGRABufferStride() { + ConvertToBuffer(4, kOddStride, false, FROM, kError, + cricket::FOURCC_BGRA, libyuv::BGRAToI420); + } + void ConvertFromABGRBufferStride() { + ConvertToBuffer(4, kOddStride, false, FROM, kError, + cricket::FOURCC_ABGR, libyuv::ABGRToI420); + } + void ConvertFromRGB24BufferStride() { + ConvertToBuffer(3, kOddStride, false, FROM, kError, + cricket::FOURCC_24BG, libyuv::RGB24ToI420); + } + void ConvertFromRAWBufferStride() { + ConvertToBuffer(3, kOddStride, false, FROM, kError, + cricket::FOURCC_RAW, libyuv::RAWToI420); + } + void ConvertFromRGB565BufferStride() { + ConvertToBuffer(2, kOddStride, false, FROM, kError, + cricket::FOURCC_RGBP, libyuv::RGB565ToI420); + } + void ConvertFromARGB1555BufferStride() { + ConvertToBuffer(2, kOddStride, false, FROM, kError, + cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420); + } + void ConvertFromARGB4444BufferStride() { + ConvertToBuffer(2, kOddStride, false, FROM, kError, + cricket::FOURCC_R444, libyuv::ARGB4444ToI420); + } + void ConvertFromBayerBGGRBufferStride() { + ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh, + cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420); + } + void ConvertFromBayerGBRGBufferStride() { + ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh, + cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420); + } + void ConvertFromBayerGRBGBufferStride() { + ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh, + cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420); + } + void ConvertFromBayerRGGBBufferStride() { + ConvertToBuffer(1, kOddStride, false, FROM, kErrorHigh, + cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420); + } + void ConvertFromI400BufferStride() { + ConvertToBuffer(1, kOddStride, false, FROM, 128, + cricket::FOURCC_I400, libyuv::I400ToI420); + } + void ConvertFromYUY2BufferStride() { + ConvertToBuffer(2, kOddStride, false, FROM, kError, + cricket::FOURCC_YUY2, libyuv::YUY2ToI420); + } + void ConvertFromUYVYBufferStride() { + ConvertToBuffer(2, kOddStride, false, FROM, kError, + cricket::FOURCC_UYVY, libyuv::UYVYToI420); + } + + // Tests ConvertFrom formats with negative stride to invert image. + void ConvertFromARGBBufferInverted() { + ConvertToBuffer(4, 0, true, FROM, kError, + cricket::FOURCC_ARGB, libyuv::ARGBToI420); + } + void ConvertFromBGRABufferInverted() { + ConvertToBuffer(4, 0, true, FROM, kError, + cricket::FOURCC_BGRA, libyuv::BGRAToI420); + } + void ConvertFromABGRBufferInverted() { + ConvertToBuffer(4, 0, true, FROM, kError, + cricket::FOURCC_ABGR, libyuv::ABGRToI420); + } + void ConvertFromRGB24BufferInverted() { + ConvertToBuffer(3, 0, true, FROM, kError, + cricket::FOURCC_24BG, libyuv::RGB24ToI420); + } + void ConvertFromRAWBufferInverted() { + ConvertToBuffer(3, 0, true, FROM, kError, + cricket::FOURCC_RAW, libyuv::RAWToI420); + } + void ConvertFromRGB565BufferInverted() { + ConvertToBuffer(2, 0, true, FROM, kError, + cricket::FOURCC_RGBP, libyuv::RGB565ToI420); + } + void ConvertFromARGB1555BufferInverted() { + ConvertToBuffer(2, 0, true, FROM, kError, + cricket::FOURCC_RGBO, libyuv::ARGB1555ToI420); + } + void ConvertFromARGB4444BufferInverted() { + ConvertToBuffer(2, 0, true, FROM, kError, + cricket::FOURCC_R444, libyuv::ARGB4444ToI420); + } + void ConvertFromBayerBGGRBufferInverted() { + ConvertToBuffer(1, 0, true, FROM, kErrorHigh, + cricket::FOURCC_BGGR, libyuv::BayerBGGRToI420); + } + void ConvertFromBayerGBRGBufferInverted() { + ConvertToBuffer(1, 0, true, FROM, kErrorHigh, + cricket::FOURCC_GBRG, libyuv::BayerGBRGToI420); + } + void ConvertFromBayerGRBGBufferInverted() { + ConvertToBuffer(1, 0, true, FROM, kErrorHigh, + cricket::FOURCC_GRBG, libyuv::BayerGRBGToI420); + } + void ConvertFromBayerRGGBBufferInverted() { + ConvertToBuffer(1, 0, true, FROM, kErrorHigh, + cricket::FOURCC_RGGB, libyuv::BayerRGGBToI420); + } + void ConvertFromI400BufferInverted() { + ConvertToBuffer(1, 0, true, FROM, 128, + cricket::FOURCC_I400, libyuv::I400ToI420); + } + void ConvertFromYUY2BufferInverted() { + ConvertToBuffer(2, 0, true, FROM, kError, + cricket::FOURCC_YUY2, libyuv::YUY2ToI420); + } + void ConvertFromUYVYBufferInverted() { + ConvertToBuffer(2, 0, true, FROM, kError, + cricket::FOURCC_UYVY, libyuv::UYVYToI420); + } + + // Test converting from I420 to I422. + void ConvertToI422Buffer() { + T frame1, frame2; + size_t out_size = kWidth * kHeight * 2; + talk_base::scoped_ptr buf(new uint8[out_size + kAlignment]); + uint8* y = ALIGNP(buf.get(), kAlignment); + uint8* u = y + kWidth * kHeight; + uint8* v = u + (kWidth / 2) * kHeight; + ASSERT_TRUE(LoadFrameNoRepeat(&frame1)); + for (int i = 0; i < repeat_; ++i) { + EXPECT_EQ(0, libyuv::I420ToI422(frame1.GetYPlane(), frame1.GetYPitch(), + frame1.GetUPlane(), frame1.GetUPitch(), + frame1.GetVPlane(), frame1.GetVPitch(), + y, kWidth, + u, kWidth / 2, + v, kWidth / 2, + kWidth, kHeight)); + } + EXPECT_TRUE(frame2.Init(cricket::FOURCC_I422, + kWidth, kHeight, kWidth, kHeight, + y, + out_size, 1, 1, 0, 0, cricket::ROTATION_0)); + EXPECT_TRUE(IsEqual(frame1, frame2, 1)); + } + + #define TEST_TOBYR(NAME, BAYER) \ + void NAME() { \ + size_t bayer_size = kWidth * kHeight; \ + talk_base::scoped_ptr bayerbuf(new uint8[ \ + bayer_size + kAlignment]); \ + uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment); \ + T frame; \ + talk_base::scoped_ptr ms( \ + CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \ + ASSERT_TRUE(ms.get() != NULL); \ + for (int i = 0; i < repeat_; ++i) { \ + libyuv::ARGBToBayer##BAYER(reinterpret_cast(ms->GetBuffer()), \ + kWidth * 4, \ + bayer, kWidth, \ + kWidth, kHeight); \ + } \ + talk_base::scoped_ptr ms2( \ + CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \ + size_t data_size; \ + bool ret = ms2->GetSize(&data_size); \ + EXPECT_TRUE(ret); \ + libyuv::Bayer##BAYER##ToARGB(bayer, kWidth, \ + reinterpret_cast(ms2->GetBuffer()), \ + kWidth * 4, \ + kWidth, kHeight); \ + EXPECT_TRUE(IsPlaneEqual("argb", \ + reinterpret_cast(ms->GetBuffer()), kWidth * 4, \ + reinterpret_cast(ms2->GetBuffer()), kWidth * 4, \ + kWidth * 4, kHeight, 240)); \ + } \ + void NAME##Unaligned() { \ + size_t bayer_size = kWidth * kHeight; \ + talk_base::scoped_ptr bayerbuf(new uint8[ \ + bayer_size + 1 + kAlignment]); \ + uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment) + 1; \ + T frame; \ + talk_base::scoped_ptr ms( \ + CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \ + ASSERT_TRUE(ms.get() != NULL); \ + for (int i = 0; i < repeat_; ++i) { \ + libyuv::ARGBToBayer##BAYER(reinterpret_cast(ms->GetBuffer()), \ + kWidth * 4, \ + bayer, kWidth, \ + kWidth, kHeight); \ + } \ + talk_base::scoped_ptr ms2( \ + CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \ + size_t data_size; \ + bool ret = ms2->GetSize(&data_size); \ + EXPECT_TRUE(ret); \ + libyuv::Bayer##BAYER##ToARGB(bayer, kWidth, \ + reinterpret_cast(ms2->GetBuffer()), \ + kWidth * 4, \ + kWidth, kHeight); \ + EXPECT_TRUE(IsPlaneEqual("argb", \ + reinterpret_cast(ms->GetBuffer()), kWidth * 4, \ + reinterpret_cast(ms2->GetBuffer()), kWidth * 4, \ + kWidth * 4, kHeight, 240)); \ + } + + // Tests ARGB to Bayer formats. + TEST_TOBYR(ConvertARGBToBayerGRBG, GRBG) + TEST_TOBYR(ConvertARGBToBayerGBRG, GBRG) + TEST_TOBYR(ConvertARGBToBayerBGGR, BGGR) + TEST_TOBYR(ConvertARGBToBayerRGGB, RGGB) + + #define TEST_BYRTORGB(NAME, BAYER) \ + void NAME() { \ + size_t bayer_size = kWidth * kHeight; \ + talk_base::scoped_ptr bayerbuf(new uint8[ \ + bayer_size + kAlignment]); \ + uint8 *bayer1 = ALIGNP(bayerbuf.get(), kAlignment); \ + for (int i = 0; i < kWidth * kHeight; ++i) { \ + bayer1[i] = static_cast(i * 33u + 183u); \ + } \ + T frame; \ + talk_base::scoped_ptr ms( \ + CreateRgbSample(cricket::FOURCC_ARGB, kWidth, kHeight)); \ + ASSERT_TRUE(ms.get() != NULL); \ + for (int i = 0; i < repeat_; ++i) { \ + libyuv::Bayer##BAYER##ToARGB(bayer1, kWidth, \ + reinterpret_cast(ms->GetBuffer()), \ + kWidth * 4, \ + kWidth, kHeight); \ + } \ + talk_base::scoped_ptr bayer2buf(new uint8[ \ + bayer_size + kAlignment]); \ + uint8 *bayer2 = ALIGNP(bayer2buf.get(), kAlignment); \ + libyuv::ARGBToBayer##BAYER(reinterpret_cast(ms->GetBuffer()), \ + kWidth * 4, \ + bayer2, kWidth, \ + kWidth, kHeight); \ + EXPECT_TRUE(IsPlaneEqual("bayer", \ + bayer1, kWidth, \ + bayer2, kWidth, \ + kWidth, kHeight, 0)); \ + } + + // Tests Bayer formats to ARGB. + TEST_BYRTORGB(ConvertBayerGRBGToARGB, GRBG) + TEST_BYRTORGB(ConvertBayerGBRGToARGB, GBRG) + TEST_BYRTORGB(ConvertBayerBGGRToARGB, BGGR) + TEST_BYRTORGB(ConvertBayerRGGBToARGB, RGGB) + + /////////////////// + // General tests // + /////////////////// + + void Copy() { + talk_base::scoped_ptr source(new T); + talk_base::scoped_ptr target; + ASSERT_TRUE(LoadFrameNoRepeat(source.get())); + target.reset(source->Copy()); + EXPECT_TRUE(IsEqual(*source, *target, 0)); + source.reset(); + EXPECT_TRUE(target->GetYPlane() != NULL); + } + + void CopyIsRef() { + talk_base::scoped_ptr source(new T); + talk_base::scoped_ptr target; + ASSERT_TRUE(LoadFrameNoRepeat(source.get())); + target.reset(source->Copy()); + EXPECT_TRUE(IsEqual(*source, *target, 0)); + EXPECT_EQ(source->GetYPlane(), target->GetYPlane()); + EXPECT_EQ(source->GetUPlane(), target->GetUPlane()); + EXPECT_EQ(source->GetVPlane(), target->GetVPlane()); + } + + void MakeExclusive() { + talk_base::scoped_ptr source(new T); + talk_base::scoped_ptr target; + ASSERT_TRUE(LoadFrameNoRepeat(source.get())); + target.reset(source->Copy()); + EXPECT_TRUE(target->MakeExclusive()); + EXPECT_TRUE(IsEqual(*source, *target, 0)); + EXPECT_NE(target->GetYPlane(), source->GetYPlane()); + EXPECT_NE(target->GetUPlane(), source->GetUPlane()); + EXPECT_NE(target->GetVPlane(), source->GetVPlane()); + } + + void CopyToBuffer() { + T frame; + talk_base::scoped_ptr ms( + LoadSample(kImageFilename)); + ASSERT_TRUE(ms.get() != NULL); + ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight, + &frame)); + size_t out_size = kWidth * kHeight * 3 / 2; + talk_base::scoped_ptr out(new uint8[out_size]); + for (int i = 0; i < repeat_; ++i) { + EXPECT_EQ(out_size, frame.CopyToBuffer(out.get(), out_size)); + } + EXPECT_EQ(0, memcmp(out.get(), ms->GetBuffer(), out_size)); + } + + void CopyToFrame() { + T source; + talk_base::scoped_ptr ms( + LoadSample(kImageFilename)); + ASSERT_TRUE(ms.get() != NULL); + ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight, + &source)); + + // Create the target frame by loading from a file. + T target; + ASSERT_TRUE(LoadFrameNoRepeat(&target)); + EXPECT_FALSE(IsBlack(target)); + + // Stretch and check if the stretched target is black. + source.CopyToFrame(&target); + + EXPECT_TRUE(IsEqual(source, target, 0)); + } + + void Write() { + T frame; + talk_base::scoped_ptr ms( + LoadSample(kImageFilename)); + ASSERT_TRUE(ms.get() != NULL); + talk_base::MemoryStream ms2; + size_t size; + ASSERT_TRUE(ms->GetSize(&size)); + ASSERT_TRUE(ms2.ReserveSize(size)); + ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight, + &frame)); + for (int i = 0; i < repeat_; ++i) { + ms2.SetPosition(0u); // Useful when repeat_ > 1. + int error; + EXPECT_EQ(talk_base::SR_SUCCESS, frame.Write(&ms2, &error)); + } + size_t out_size = cricket::VideoFrame::SizeOf(kWidth, kHeight); + EXPECT_EQ(0, memcmp(ms2.GetBuffer(), ms->GetBuffer(), out_size)); + } + + void CopyToBuffer1Pixel() { + size_t out_size = 3; + talk_base::scoped_ptr out(new uint8[out_size + 1]); + memset(out.get(), 0xfb, out_size + 1); // Fill buffer + uint8 pixel[3] = { 1, 2, 3 }; + T frame; + EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, 1, 1, 1, 1, + pixel, sizeof(pixel), + 1, 1, 0, 0, 0)); + for (int i = 0; i < repeat_; ++i) { + EXPECT_EQ(out_size, frame.CopyToBuffer(out.get(), out_size)); + } + EXPECT_EQ(1, out.get()[0]); // Check Y. Should be 1. + EXPECT_EQ(2, out.get()[1]); // Check U. Should be 2. + EXPECT_EQ(3, out.get()[2]); // Check V. Should be 3. + EXPECT_EQ(0xfb, out.get()[3]); // Check sentinel is still intact. + } + + void StretchToFrame() { + // Create the source frame as a black frame. + T source; + EXPECT_TRUE(source.InitToBlack(kWidth * 2, kHeight * 2, 1, 1, 0, 0)); + EXPECT_TRUE(IsSize(source, kWidth * 2, kHeight * 2)); + + // Create the target frame by loading from a file. + T target1; + ASSERT_TRUE(LoadFrameNoRepeat(&target1)); + EXPECT_FALSE(IsBlack(target1)); + + // Stretch and check if the stretched target is black. + source.StretchToFrame(&target1, true, false); + EXPECT_TRUE(IsBlack(target1)); + + // Crop and stretch and check if the stretched target is black. + T target2; + ASSERT_TRUE(LoadFrameNoRepeat(&target2)); + source.StretchToFrame(&target2, true, true); + EXPECT_TRUE(IsBlack(target2)); + EXPECT_EQ(source.GetElapsedTime(), target2.GetElapsedTime()); + EXPECT_EQ(source.GetTimeStamp(), target2.GetTimeStamp()); + } + + int repeat_; +}; + +#endif // TALK_MEDIA_BASE_VIDEOFRAME_UNITTEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/videoprocessor.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/videoprocessor.h new file mode 100644 index 0000000..8285678 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/videoprocessor.h @@ -0,0 +1,50 @@ +/* + * 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_BASE_VIDEOPROCESSOR_H_ +#define TALK_MEDIA_BASE_VIDEOPROCESSOR_H_ + +#include "talk/base/sigslot.h" +#include "talk/media/base/videoframe.h" + +namespace cricket { + +class VideoProcessor : public sigslot::has_slots<> { + public: + virtual ~VideoProcessor() {} + // Contents of frame may be manipulated by the processor. + // The processed data is expected to be the same size as the + // original data. VideoProcessors may be chained together and may decide + // that the current frame should be dropped. If *drop_frame is true, + // the current processor should skip processing. If the current processor + // decides it cannot process the current frame in a timely manner, it may set + // *drop_frame = true and the frame will be dropped. + virtual void OnFrame(uint32 ssrc, VideoFrame* frame, bool* drop_frame) = 0; +}; + +} // namespace cricket +#endif // TALK_MEDIA_BASE_VIDEOPROCESSOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/videorenderer.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/videorenderer.h new file mode 100644 index 0000000..ed490e5 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/videorenderer.h @@ -0,0 +1,58 @@ +/* + * 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_BASE_VIDEORENDERER_H_ +#define TALK_MEDIA_BASE_VIDEORENDERER_H_ + +#ifdef _DEBUG +#include +#endif // _DEBUG + +#include "talk/base/sigslot.h" + +namespace cricket { + +class VideoFrame; + +// Abstract interface for rendering VideoFrames. +class VideoRenderer { + public: + virtual ~VideoRenderer() {} + // Called when the video has changed size. + virtual bool SetSize(int width, int height, int reserved) = 0; + // Called when a new frame is available for display. + virtual bool RenderFrame(const VideoFrame *frame) = 0; + +#ifdef _DEBUG + // Allow renderer dumping out rendered frames. + virtual bool SetDumpPath(const std::string &path) { return true; } +#endif // _DEBUG +}; + +} // namespace cricket + +#endif // TALK_MEDIA_BASE_VIDEORENDERER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/voiceprocessor.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/voiceprocessor.h new file mode 100644 index 0000000..be626c4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/base/voiceprocessor.h @@ -0,0 +1,56 @@ +/* + * 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_BASE_VOICEPROCESSOR_H_ +#define TALK_MEDIA_BASE_VOICEPROCESSOR_H_ + +#include "talk/base/basictypes.h" +#include "talk/base/sigslot.h" +#include "talk/media/base/audioframe.h" + +namespace cricket { + +enum MediaProcessorDirection { + MPD_INVALID = 0, + MPD_RX = 1 << 0, + MPD_TX = 1 << 1, + MPD_RX_AND_TX = MPD_RX | MPD_TX, +}; + +class VoiceProcessor : public sigslot::has_slots<> { + public: + virtual ~VoiceProcessor() {} + // Contents of frame may be manipulated by the processor. + // The processed data is expected to be the same size as the + // original data. + virtual void OnFrame(uint32 ssrc, + MediaProcessorDirection direction, + AudioFrame* frame) = 0; +}; + +} // namespace cricket +#endif // TALK_MEDIA_BASE_VOICEPROCESSOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/base/yuvframegenerator.h b/thirdparties/common/include/webrtc-sdk/talk/media/base/yuvframegenerator.h new file mode 100644 index 0000000..8f99cdc --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/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/thirdparties/common/include/webrtc-sdk/talk/media/devices/carbonvideorenderer.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/carbonvideorenderer.h new file mode 100644 index 0000000..3ebc174 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/carbonvideorenderer.h @@ -0,0 +1,72 @@ +// 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. +// +// Definition of class CarbonVideoRenderer that implements the abstract class +// cricket::VideoRenderer via Carbon. + +#ifndef TALK_MEDIA_DEVICES_CARBONVIDEORENDERER_H_ +#define TALK_MEDIA_DEVICES_CARBONVIDEORENDERER_H_ + +#include + +#include "talk/base/criticalsection.h" +#include "talk/base/scoped_ptr.h" +#include "talk/media/base/videorenderer.h" + +namespace cricket { + +class CarbonVideoRenderer : public VideoRenderer { + public: + CarbonVideoRenderer(int x, int y); + virtual ~CarbonVideoRenderer(); + + // Implementation of pure virtual methods of VideoRenderer. + // These two methods may be executed in different threads. + // SetSize is called before RenderFrame. + virtual bool SetSize(int width, int height, int reserved); + virtual bool RenderFrame(const VideoFrame* frame); + + // Needs to be called on the main thread. + bool Initialize(); + + private: + bool DrawFrame(); + + static OSStatus DrawEventHandler(EventHandlerCallRef handler, + EventRef event, + void* data); + talk_base::scoped_ptr image_; + talk_base::CriticalSection image_crit_; + int image_width_; + int image_height_; + int x_; + int y_; + CGImageRef image_ref_; + WindowRef window_ref_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_CARBONVIDEORENDERER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/deviceinfo.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/deviceinfo.h new file mode 100644 index 0000000..a069dd8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/deviceinfo.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#ifndef TALK_MEDIA_DEVICES_DEVICEINFO_H_ +#define TALK_MEDIA_DEVICES_DEVICEINFO_H_ + +#include + +#include "talk/media/devices/devicemanager.h" + +namespace cricket { + +bool GetUsbId(const Device& device, std::string* usb_id); +bool GetUsbVersion(const Device& device, std::string* usb_version); + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_DEVICEINFO_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/devicemanager.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/devicemanager.h new file mode 100644 index 0000000..5950143 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/devicemanager.h @@ -0,0 +1,216 @@ +/* + * 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_DEVICES_DEVICEMANAGER_H_ +#define TALK_MEDIA_DEVICES_DEVICEMANAGER_H_ + +#include +#include +#include + +#include "talk/base/scoped_ptr.h" +#include "talk/base/sigslot.h" +#include "talk/base/stringencode.h" +#include "talk/base/window.h" +#include "talk/media/base/videocommon.h" + +namespace talk_base { + +class DesktopDescription; +class WindowDescription; +class WindowPicker; + +} +namespace cricket { + +class VideoCapturer; + +// Used to represent an audio or video capture or render device. +struct Device { + Device() {} + Device(const std::string& first, int second) + : name(first), + id(talk_base::ToString(second)) { + } + Device(const std::string& first, const std::string& second) + : name(first), id(second) {} + + std::string name; + std::string id; +}; + +class VideoCapturerFactory { + public: + VideoCapturerFactory() {} + virtual ~VideoCapturerFactory() {} + + virtual VideoCapturer* Create(const Device& device) = 0; +}; + +// DeviceManagerInterface - interface to manage the audio and +// video devices on the system. +class DeviceManagerInterface { + public: + virtual ~DeviceManagerInterface() { } + + // Initialization + virtual bool Init() = 0; + virtual void Terminate() = 0; + + // Capabilities + virtual int GetCapabilities() = 0; + + // Device enumeration + virtual bool GetAudioInputDevices(std::vector* devices) = 0; + virtual bool GetAudioOutputDevices(std::vector* devices) = 0; + + virtual bool GetAudioInputDevice(const std::string& name, Device* out) = 0; + virtual bool GetAudioOutputDevice(const std::string& name, Device* out) = 0; + + virtual bool GetVideoCaptureDevices(std::vector* devs) = 0; + virtual bool GetVideoCaptureDevice(const std::string& name, Device* out) = 0; + + // Caps the capture format according to max format for capturers created + // by CreateVideoCapturer(). See ConstrainSupportedFormats() in + // videocapturer.h for more detail. + // Note that once a VideoCapturer has been created, calling this API will + // not affect it. + virtual void SetVideoCaptureDeviceMaxFormat( + const std::string& usb_id, + const VideoFormat& max_format) = 0; + virtual void ClearVideoCaptureDeviceMaxFormat(const std::string& usb_id) = 0; + + // Device creation + virtual VideoCapturer* CreateVideoCapturer(const Device& device) const = 0; + + virtual bool GetWindows( + std::vector* descriptions) = 0; + virtual VideoCapturer* CreateWindowCapturer(talk_base::WindowId window) = 0; + + virtual bool GetDesktops( + std::vector* descriptions) = 0; + virtual VideoCapturer* CreateDesktopCapturer( + talk_base::DesktopId desktop) = 0; + + sigslot::signal0<> SignalDevicesChange; + + static const char kDefaultDeviceName[]; +}; + +class DeviceWatcher { + public: + explicit DeviceWatcher(DeviceManagerInterface* dm) {} + virtual ~DeviceWatcher() {} + virtual bool Start() { return true; } + virtual void Stop() {} +}; + +class DeviceManagerFactory { + public: + static DeviceManagerInterface* Create(); + + private: + DeviceManagerFactory() {} +}; + +class DeviceManager : public DeviceManagerInterface { + public: + DeviceManager(); + virtual ~DeviceManager(); + + void set_device_video_capturer_factory( + VideoCapturerFactory* device_video_capturer_factory) { + device_video_capturer_factory_.reset(device_video_capturer_factory); + } + + // Initialization + virtual bool Init(); + virtual void Terminate(); + + // Capabilities + virtual int GetCapabilities(); + + // Device enumeration + virtual bool GetAudioInputDevices(std::vector* devices); + virtual bool GetAudioOutputDevices(std::vector* devices); + + virtual bool GetAudioInputDevice(const std::string& name, Device* out); + virtual bool GetAudioOutputDevice(const std::string& name, Device* out); + + virtual bool GetVideoCaptureDevices(std::vector* devs); + virtual bool GetVideoCaptureDevice(const std::string& name, Device* out); + + virtual void SetVideoCaptureDeviceMaxFormat(const std::string& usb_id, + const VideoFormat& max_format); + virtual void ClearVideoCaptureDeviceMaxFormat(const std::string& usb_id); + + virtual VideoCapturer* CreateVideoCapturer(const Device& device) const; + + virtual bool GetWindows( + std::vector* descriptions); + virtual VideoCapturer* CreateWindowCapturer(talk_base::WindowId window); + + virtual bool GetDesktops( + std::vector* descriptions); + virtual VideoCapturer* CreateDesktopCapturer(talk_base::DesktopId desktop); + + // The exclusion_list MUST be a NULL terminated list. + static bool FilterDevices(std::vector* devices, + const char* const exclusion_list[]); + bool initialized() const { return initialized_; } + + protected: + virtual bool GetAudioDevices(bool input, std::vector* devs); + virtual bool GetAudioDevice(bool is_input, const std::string& name, + Device* out); + virtual bool GetDefaultVideoCaptureDevice(Device* device); + bool IsInWhitelist(const std::string& key, VideoFormat* video_format) const; + virtual bool GetMaxFormat(const Device& device, + VideoFormat* video_format) const; + + void set_initialized(bool initialized) { initialized_ = initialized; } + + void set_watcher(DeviceWatcher* watcher) { watcher_.reset(watcher); } + DeviceWatcher* watcher() { return watcher_.get(); } + + private: + // 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 device_video_capturer_factory_; + std::map max_formats_; + talk_base::scoped_ptr watcher_; + talk_base::scoped_ptr window_picker_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_DEVICEMANAGER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/dummydevicemanager.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/dummydevicemanager.h new file mode 100644 index 0000000..85b67d9 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/dummydevicemanager.h @@ -0,0 +1,51 @@ +/* + * 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_MEDIA_DEVICES_DUMMYDEVICEMANAGER_H_ +#define TALK_MEDIA_DEVICES_DUMMYDEVICEMANAGER_H_ + +#include + +#include "talk/media/base/mediacommon.h" +#include "talk/media/devices/fakedevicemanager.h" + +namespace cricket { + +class DummyDeviceManager : public FakeDeviceManager { + public: + DummyDeviceManager() { + std::vector devices; + devices.push_back(DeviceManagerInterface::kDefaultDeviceName); + SetAudioInputDevices(devices); + SetAudioOutputDevices(devices); + SetVideoCaptureDevices(devices); + } +}; + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_DUMMYDEVICEMANAGER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/fakedevicemanager.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/fakedevicemanager.h new file mode 100644 index 0000000..14ea0b8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/fakedevicemanager.h @@ -0,0 +1,222 @@ +/* + * 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. + */ + +#ifndef TALK_MEDIA_DEVICES_FAKEDEVICEMANAGER_H_ +#define TALK_MEDIA_DEVICES_FAKEDEVICEMANAGER_H_ + +#include +#include + +#include "talk/base/window.h" +#include "talk/base/windowpicker.h" +#include "talk/media/base/fakevideocapturer.h" +#include "talk/media/base/mediacommon.h" +#include "talk/media/devices/devicemanager.h" + +namespace cricket { + +class FakeDeviceManager : public DeviceManagerInterface { + public: + FakeDeviceManager() {} + virtual bool Init() { + return true; + } + virtual void Terminate() { + } + virtual int GetCapabilities() { + std::vector devices; + int caps = VIDEO_RECV; + if (!input_devices_.empty()) { + caps |= AUDIO_SEND; + } + if (!output_devices_.empty()) { + caps |= AUDIO_RECV; + } + if (!vidcap_devices_.empty()) { + caps |= VIDEO_SEND; + } + return caps; + } + virtual bool GetAudioInputDevices(std::vector* devs) { + *devs = input_devices_; + return true; + } + virtual bool GetAudioOutputDevices(std::vector* devs) { + *devs = output_devices_; + return true; + } + virtual bool GetAudioInputDevice(const std::string& name, Device* out) { + return GetAudioDevice(true, name, out); + } + virtual bool GetAudioOutputDevice(const std::string& name, Device* out) { + return GetAudioDevice(false, name, out); + } + virtual bool GetVideoCaptureDevices(std::vector* devs) { + *devs = vidcap_devices_; + return true; + } + virtual void SetVideoCaptureDeviceMaxFormat(const std::string& usb_id, + const VideoFormat& max_format) { + max_formats_[usb_id] = max_format; + } + bool IsMaxFormatForDevice(const std::string& usb_id, + const VideoFormat& max_format) const { + std::map::const_iterator found = + max_formats_.find(usb_id); + return (found != max_formats_.end()) ? + max_format == found->second : + false; + } + virtual void ClearVideoCaptureDeviceMaxFormat(const std::string& usb_id) { + max_formats_.erase(usb_id); + } + virtual VideoCapturer* CreateVideoCapturer(const Device& device) const { + return new FakeVideoCapturer(); + } + virtual bool GetWindows( + std::vector* descriptions) { + descriptions->clear(); + const uint32_t id = 1u; // Note that 0 is not a valid ID. + const talk_base::WindowId window_id = + talk_base::WindowId::Cast(id); + std::string title = "FakeWindow"; + talk_base::WindowDescription window_description(window_id, title); + descriptions->push_back(window_description); + return true; + } + virtual VideoCapturer* CreateWindowCapturer(talk_base::WindowId window) { + if (!window.IsValid()) { + return NULL; + } + return new FakeVideoCapturer; + } + virtual bool GetDesktops( + std::vector* descriptions) { + descriptions->clear(); + const int id = 0; + const int valid_index = 0; + const talk_base::DesktopId desktop_id = + talk_base::DesktopId::Cast(id, valid_index); + std::string title = "FakeDesktop"; + talk_base::DesktopDescription desktop_description(desktop_id, title); + descriptions->push_back(desktop_description); + return true; + } + virtual VideoCapturer* CreateDesktopCapturer(talk_base::DesktopId desktop) { + if (!desktop.IsValid()) { + return NULL; + } + return new FakeVideoCapturer; + } + + virtual bool GetDefaultVideoCaptureDevice(Device* device) { + if (vidcap_devices_.empty()) { + return false; + } + *device = vidcap_devices_[0]; + return true; + } + +#ifdef OSX + bool QtKitToSgDevice(const std::string& qtkit_name, Device* out) { + out->name = qtkit_name; + out->id = "sg:" + qtkit_name; + return true; + } +#endif + + void SetAudioInputDevices(const std::vector& devices) { + input_devices_.clear(); + for (size_t i = 0; i < devices.size(); ++i) { + input_devices_.push_back(Device(devices[i], + static_cast(i))); + } + SignalDevicesChange(); + } + void SetAudioOutputDevices(const std::vector& devices) { + output_devices_.clear(); + for (size_t i = 0; i < devices.size(); ++i) { + output_devices_.push_back(Device(devices[i], + static_cast(i))); + } + SignalDevicesChange(); + } + void SetVideoCaptureDevices(const std::vector& devices) { + vidcap_devices_.clear(); + for (size_t i = 0; i < devices.size(); ++i) { + vidcap_devices_.push_back(Device(devices[i], + static_cast(i))); + } + SignalDevicesChange(); + } + virtual bool GetVideoCaptureDevice(const std::string& name, + Device* out) { + if (vidcap_devices_.empty()) + return false; + + // If the name is empty, return the default device. + if (name.empty() || name == kDefaultDeviceName) { + *out = vidcap_devices_[0]; + return true; + } + + return FindDeviceByName(vidcap_devices_, name, out); + } + bool GetAudioDevice(bool is_input, const std::string& name, + Device* out) { + // If the name is empty, return the default device. + if (name.empty() || name == kDefaultDeviceName) { + *out = Device(name, -1); + return true; + } + + return FindDeviceByName((is_input ? input_devices_ : output_devices_), + name, out); + } + static bool FindDeviceByName(const std::vector& devices, + const std::string& name, + Device* out) { + for (std::vector::const_iterator it = devices.begin(); + it != devices.end(); ++it) { + if (name == it->name) { + *out = *it; + return true; + } + } + return false; + } + + private: + std::vector input_devices_; + std::vector output_devices_; + std::vector vidcap_devices_; + std::map max_formats_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_FAKEDEVICEMANAGER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/filevideocapturer.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/filevideocapturer.h new file mode 100644 index 0000000..f7956a8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/filevideocapturer.h @@ -0,0 +1,156 @@ +// 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. +// +// This file contains two classes, VideoRecorder and FileVideoCapturer. +// VideoRecorder records the captured frames into a file. The file stores a +// sequence of captured frames; each frame has a header defined in struct +// CapturedFrame, followed by the frame data. +// +// FileVideoCapturer, a subclass of VideoCapturer, is a simulated video capturer +// that periodically reads images from a previously recorded file. + +#ifndef TALK_MEDIA_DEVICES_FILEVIDEOCAPTURER_H_ +#define TALK_MEDIA_DEVICES_FILEVIDEOCAPTURER_H_ + +#include +#include + +#include "talk/base/stream.h" +#include "talk/base/stringutils.h" +#include "talk/media/base/videocapturer.h" + +namespace talk_base { +class FileStream; +} + +namespace cricket { + +// Utility class to record the frames captured by a video capturer into a file. +class VideoRecorder { + public: + VideoRecorder() {} + ~VideoRecorder() { Stop(); } + + // Start the recorder by opening the specified file. Return true if the file + // is opened successfully. write_header should normally be true; false means + // write raw frame pixel data to file without any headers. + bool Start(const std::string& filename, bool write_header); + // Stop the recorder by closing the file. + void Stop(); + // Record a video frame to the file. Return true if the frame is written to + // the file successfully. This method needs to be called after Start() and + // before Stop(). + bool RecordFrame(const CapturedFrame& frame); + + private: + talk_base::FileStream video_file_; + bool write_header_; + + DISALLOW_COPY_AND_ASSIGN(VideoRecorder); +}; + +// Simulated video capturer that periodically reads frames from a file. +class FileVideoCapturer : public VideoCapturer { + public: + FileVideoCapturer(); + virtual ~FileVideoCapturer(); + + // Determines if the given device is actually a video file, to be captured + // with a FileVideoCapturer. + static bool IsFileVideoCapturerDevice(const Device& device) { + return talk_base::starts_with(device.id.c_str(), kVideoFileDevicePrefix); + } + + // Creates a fake device for the given filename. + static Device CreateFileVideoCapturerDevice(const std::string& filename) { + std::stringstream id; + id << kVideoFileDevicePrefix << filename; + return Device(filename, id.str()); + } + + // Set how many times to repeat reading the file. Repeat forever if the + // parameter is talk_base::kForever(-1); no repeat if the parameter is 0 or + // less than -1. + void set_repeat(int repeat) { repeat_ = repeat; } + + // If ignore_framerate is true, file is read as quickly as possible. If + // false, read rate is controlled by the timestamps in the video file + // (thus simulating camera capture). Default value set to false. + void set_ignore_framerate(bool ignore_framerate) { + ignore_framerate_ = ignore_framerate; + } + + // Initializes the capturer with the given file. + bool Init(const std::string& filename); + + // Initializes the capturer with the given device. This should only be used + // if IsFileVideoCapturerDevice returned true for the given device. + bool Init(const Device& device); + + // 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* fourccs); + + // Read the frame header from the file stream, video_file_. + talk_base::StreamResult ReadFrameHeader(CapturedFrame* frame); + + // Read a frame and determine how long to wait for the next frame. If the + // frame is read successfully, Set the output parameter, wait_time_ms and + // return true. Otherwise, do not change wait_time_ms and return false. + bool ReadFrame(bool first_frame, int* wait_time_ms); + + // Return the CapturedFrame - useful for extracting contents after reading + // a frame. Should be used only while still reading a file (i.e. only while + // the CapturedFrame object still exists). + const CapturedFrame* frame() const { + return &captured_frame_; + } + + private: + class FileReadThread; // Forward declaration, defined in .cc. + + static const char* kVideoFileDevicePrefix; + talk_base::FileStream video_file_; + CapturedFrame captured_frame_; + // The number of bytes allocated buffer for captured_frame_.data. + uint32 frame_buffer_size_; + FileReadThread* file_read_thread_; + int repeat_; // How many times to repeat the file. + int64 start_time_ns_; // Time when the file video capturer starts. + int64 last_frame_timestamp_ns_; // Timestamp of last read frame. + bool ignore_framerate_; + + DISALLOW_COPY_AND_ASSIGN(FileVideoCapturer); +}; + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_FILEVIDEOCAPTURER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/gdivideorenderer.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/gdivideorenderer.h new file mode 100644 index 0000000..82fe99c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/gdivideorenderer.h @@ -0,0 +1,60 @@ +// 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. +// +// Definition of class GdiVideoRenderer that implements the abstract class +// cricket::VideoRenderer via GDI on Windows. + +#ifndef TALK_MEDIA_DEVICES_GDIVIDEORENDERER_H_ +#define TALK_MEDIA_DEVICES_GDIVIDEORENDERER_H_ + +#ifdef WIN32 +#include "talk/base/scoped_ptr.h" +#include "talk/media/base/videorenderer.h" + +namespace cricket { + +class GdiVideoRenderer : public VideoRenderer { + public: + GdiVideoRenderer(int x, int y); + virtual ~GdiVideoRenderer(); + + // Implementation of pure virtual methods of VideoRenderer. + // These two methods may be executed in different threads. + // SetSize is called before RenderFrame. + virtual bool SetSize(int width, int height, int reserved); + virtual bool RenderFrame(const VideoFrame* frame); + + private: + class VideoWindow; // forward declaration, defined in the .cc file + talk_base::scoped_ptr window_; + // The initial position of the window. + int initial_x_; + int initial_y_; +}; + +} // namespace cricket + +#endif // WIN32 +#endif // TALK_MEDIA_DEVICES_GDIVIDEORENDERER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/gtkvideorenderer.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/gtkvideorenderer.h new file mode 100644 index 0000000..522e05d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/gtkvideorenderer.h @@ -0,0 +1,69 @@ +// 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. +// +// Definition of class GtkVideoRenderer that implements the abstract class +// cricket::VideoRenderer via GTK. + +#ifndef TALK_MEDIA_DEVICES_GTKVIDEORENDERER_H_ +#define TALK_MEDIA_DEVICES_GTKVIDEORENDERER_H_ + +#include "talk/base/basictypes.h" +#include "talk/base/scoped_ptr.h" +#include "talk/media/base/videorenderer.h" + +typedef struct _GtkWidget GtkWidget; // forward declaration, defined in gtk.h + +namespace cricket { + +class GtkVideoRenderer : public VideoRenderer { + public: + GtkVideoRenderer(int x, int y); + virtual ~GtkVideoRenderer(); + + // Implementation of pure virtual methods of VideoRenderer. + // These two methods may be executed in different threads. + // SetSize is called before RenderFrame. + virtual bool SetSize(int width, int height, int reserved); + virtual bool RenderFrame(const VideoFrame* frame); + + private: + // Initialize the attributes when the first frame arrives. + bool Initialize(int width, int height); + // Pump the Gtk event loop until there are no events left. + void Pump(); + // Check if the window has been closed. + bool IsClosed() const; + + talk_base::scoped_ptr image_; + GtkWidget* window_; + GtkWidget* draw_area_; + // The initial position of the window. + int initial_x_; + int initial_y_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_GTKVIDEORENDERER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/libudevsymboltable.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/libudevsymboltable.h new file mode 100644 index 0000000..7190a70 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/libudevsymboltable.h @@ -0,0 +1,79 @@ +/* + * 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_DEVICES_LIBUDEVSYMBOLTABLE_H_ +#define TALK_MEDIA_DEVICES_LIBUDEVSYMBOLTABLE_H_ + +#include + +#include "talk/base/latebindingsymboltable.h" + +namespace cricket { + +#define LIBUDEV_SYMBOLS_CLASS_NAME LibUDevSymbolTable +// The libudev symbols we need, as an X-Macro list. +// This list must contain precisely every libudev function that is used in +// linuxdevicemanager.cc. +#define LIBUDEV_SYMBOLS_LIST \ + X(udev_device_get_devnode) \ + X(udev_device_get_parent_with_subsystem_devtype) \ + X(udev_device_get_sysattr_value) \ + X(udev_device_new_from_syspath) \ + X(udev_device_unref) \ + X(udev_enumerate_add_match_subsystem) \ + X(udev_enumerate_get_list_entry) \ + X(udev_enumerate_new) \ + X(udev_enumerate_scan_devices) \ + X(udev_enumerate_unref) \ + X(udev_list_entry_get_name) \ + X(udev_list_entry_get_next) \ + X(udev_monitor_enable_receiving) \ + X(udev_monitor_filter_add_match_subsystem_devtype) \ + X(udev_monitor_get_fd) \ + X(udev_monitor_new_from_netlink) \ + X(udev_monitor_receive_device) \ + X(udev_monitor_unref) \ + X(udev_new) \ + X(udev_unref) + +#define LATE_BINDING_SYMBOL_TABLE_CLASS_NAME LIBUDEV_SYMBOLS_CLASS_NAME +#define LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST LIBUDEV_SYMBOLS_LIST +#include "talk/base/latebindingsymboltable.h.def" +#undef LATE_BINDING_SYMBOL_TABLE_CLASS_NAME +#undef LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST + +// libudev has changed ABIs to libudev.so.1 in recent distros and lots of users +// and/or software (including Google Chrome) are symlinking the old to the new. +// The entire point of ABI versions is that you can't safely do that, and +// it has caused crashes in the wild. This function checks if the DllHandle that +// we got back for libudev.so.0 is actually for libudev.so.1. If so, the library +// cannot safely be used. +bool IsWrongLibUDevAbiVersion(talk_base::DllHandle libudev_0); + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_LIBUDEVSYMBOLTABLE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/linuxdevicemanager.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/linuxdevicemanager.h new file mode 100644 index 0000000..65e558d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/linuxdevicemanager.h @@ -0,0 +1,55 @@ +/* + * 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_DEVICES_LINUXDEVICEMANAGER_H_ +#define TALK_MEDIA_DEVICES_LINUXDEVICEMANAGER_H_ + +#include +#include + +#include "talk/base/sigslot.h" +#include "talk/base/stringencode.h" +#include "talk/media/devices/devicemanager.h" +#include "talk/sound/soundsystemfactory.h" + +namespace cricket { + +class LinuxDeviceManager : public DeviceManager { + public: + LinuxDeviceManager(); + virtual ~LinuxDeviceManager(); + + virtual bool GetVideoCaptureDevices(std::vector* devs); + + private: + virtual bool GetAudioDevices(bool input, std::vector* devs); + SoundSystemHandle sound_system_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_LINUXDEVICEMANAGER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/macdevicemanager.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/macdevicemanager.h new file mode 100644 index 0000000..a93524f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/macdevicemanager.h @@ -0,0 +1,56 @@ +/* + * 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_DEVICES_MACDEVICEMANAGER_H_ +#define TALK_MEDIA_DEVICES_MACDEVICEMANAGER_H_ + +#include +#include + +#include "talk/base/sigslot.h" +#include "talk/base/stringencode.h" +#include "talk/media/devices/devicemanager.h" + +namespace cricket { + +class DeviceWatcher; + +class MacDeviceManager : public DeviceManager { + public: + MacDeviceManager(); + virtual ~MacDeviceManager(); + + virtual bool GetVideoCaptureDevices(std::vector* devs); + + private: + virtual bool GetAudioDevices(bool input, std::vector* devs); + bool FilterDevice(const Device& d); +}; + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_MACDEVICEMANAGER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/v4llookup.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/v4llookup.h new file mode 100644 index 0000000..72e8cc0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/v4llookup.h @@ -0,0 +1,44 @@ +/* + * Copyright 2009 Google Inc. + * Author: lexnikitin@google.com (Alexey Nikitin) + * + * V4LLookup provides basic functionality to work with V2L2 devices in Linux + * The functionality is implemented as a class with virtual methods for + * the purpose of unit testing. + */ +#ifndef TALK_MEDIA_DEVICES_V4LLOOKUP_H_ +#define TALK_MEDIA_DEVICES_V4LLOOKUP_H_ + +#include + +#ifdef LINUX +namespace cricket { +class V4LLookup { + public: + virtual ~V4LLookup() {} + + static bool IsV4L2Device(const std::string& device_path) { + return GetV4LLookup()->CheckIsV4L2Device(device_path); + } + + static void SetV4LLookup(V4LLookup* v4l_lookup) { + v4l_lookup_ = v4l_lookup; + } + + static V4LLookup* GetV4LLookup() { + if (!v4l_lookup_) { + v4l_lookup_ = new V4LLookup(); + } + return v4l_lookup_; + } + + protected: + static V4LLookup* v4l_lookup_; + // Making virtual so it is easier to mock + virtual bool CheckIsV4L2Device(const std::string& device_path); +}; + +} // namespace cricket + +#endif // LINUX +#endif // TALK_MEDIA_DEVICES_V4LLOOKUP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/videorendererfactory.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/videorendererfactory.h new file mode 100644 index 0000000..b3811a9 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/videorendererfactory.h @@ -0,0 +1,66 @@ +// 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. +// +// A factory to create a GUI video renderer. + +#ifndef TALK_MEDIA_DEVICES_VIDEORENDERERFACTORY_H_ +#define TALK_MEDIA_DEVICES_VIDEORENDERERFACTORY_H_ + +#include "talk/media/base/videorenderer.h" +#if defined(LINUX) && defined(HAVE_GTK) +#include "talk/media/devices/gtkvideorenderer.h" +#elif defined(OSX) && !defined(CARBON_DEPRECATED) +#include "talk/media/devices/carbonvideorenderer.h" +#elif defined(WIN32) +#include "talk/media/devices/gdivideorenderer.h" +#endif + +namespace cricket { + +class VideoRendererFactory { + public: + static VideoRenderer* CreateGuiVideoRenderer(int x, int y) { + #if defined(LINUX) && defined(HAVE_GTK) + return new GtkVideoRenderer(x, y); + #elif defined(OSX) && !defined(CARBON_DEPRECATED) + CarbonVideoRenderer* renderer = new CarbonVideoRenderer(x, y); + // Needs to be initialized on the main thread. + if (renderer->Initialize()) { + return renderer; + } else { + delete renderer; + return NULL; + } + #elif defined(WIN32) + return new GdiVideoRenderer(x, y); + #else + return NULL; + #endif + } +}; + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_VIDEORENDERERFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/win32devicemanager.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/win32devicemanager.h new file mode 100644 index 0000000..6617a7d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/win32devicemanager.h @@ -0,0 +1,60 @@ +/* + * 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_DEVICES_WIN32DEVICEMANAGER_H_ +#define TALK_MEDIA_DEVICES_WIN32DEVICEMANAGER_H_ + +#include +#include + +#include "talk/base/sigslot.h" +#include "talk/base/stringencode.h" +#include "talk/media/devices/devicemanager.h" + +namespace cricket { + +class Win32DeviceManager : public DeviceManager { + public: + Win32DeviceManager(); + virtual ~Win32DeviceManager(); + + // Initialization + virtual bool Init(); + virtual void Terminate(); + + virtual bool GetVideoCaptureDevices(std::vector* devs); + + private: + virtual bool GetAudioDevices(bool input, std::vector* devs); + virtual bool GetDefaultVideoCaptureDevice(Device* device); + + bool need_couninitialize_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_DEVICES_WIN32DEVICEMANAGER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/devices/yuvframescapturer.h b/thirdparties/common/include/webrtc-sdk/talk/media/devices/yuvframescapturer.h new file mode 100644 index 0000000..f91faaf --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/devices/yuvframescapturer.h @@ -0,0 +1,71 @@ +#ifndef TALK_MEDIA_DEVICES_YUVFRAMESCAPTURER_H_ +#define TALK_MEDIA_DEVICES_YUVFRAMESCAPTURER_H_ + +#include +#include + +#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* 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/thirdparties/common/include/webrtc-sdk/talk/media/other/linphonemediaengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/other/linphonemediaengine.h new file mode 100644 index 0000000..ef0ddb2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/other/linphonemediaengine.h @@ -0,0 +1,174 @@ +/* + * 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. + */ + +// LinphoneMediaEngine is a Linphone implementation of MediaEngine + +#ifndef TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_ +#define TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_ + +#include +#include + +extern "C" { +#include +} + +#include "talk/base/scoped_ptr.h" +#include "talk/media/base/codec.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/mediaengine.h" + +namespace talk_base { +class StreamInterface; +} + +namespace cricket { + +class LinphoneMediaEngine : public MediaEngineInterface { + public: + LinphoneMediaEngine(const std::string& ringWav, const std::string& callWav); + virtual ~LinphoneMediaEngine() {} + + // Should be called before codecs() and video_codecs() are called. We need to + // set the voice and video codecs; otherwise, Jingle initiation will fail. + void set_voice_codecs(const std::vector& codecs) { + voice_codecs_ = codecs; + } + void set_video_codecs(const std::vector& codecs) { + video_codecs_ = codecs; + } + + // Implement pure virtual methods of MediaEngine. + virtual bool Init(); + virtual void Terminate(); + virtual int GetCapabilities(); + virtual VoiceMediaChannel* CreateChannel(); + virtual VideoMediaChannel* CreateVideoChannel(VoiceMediaChannel* voice_ch); + virtual SoundclipMedia* CreateSoundclip() { return NULL; } + virtual bool SetAudioOptions(int options) { return true; } + virtual bool SetVideoOptions(int options) { return true; } + virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) { + return true; + } + virtual bool SetSoundDevices(const Device* in_dev, const Device* out_dev) { + return true; + } + virtual bool SetVideoCaptureDevice(const Device* cam_device) { return true; } + virtual bool SetOutputVolume(int level) { return true; } + virtual int GetInputLevel() { return 0; } + virtual bool SetLocalMonitor(bool enable) { return true; } + virtual bool SetLocalRenderer(VideoRenderer* renderer) { return true; } + // TODO: control channel send? + virtual bool SetVideoCapture(bool capture) { return true; } + virtual const std::vector& audio_codecs() { + return voice_codecs_; + } + virtual const std::vector& video_codecs() { + return video_codecs_; + } + virtual bool FindAudioCodec(const AudioCodec& codec); + 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) {} + + std::string GetRingWav(){return ring_wav_;} + std::string GetCallWav(){return call_wav_;} + + int have_ilbc; + + private: + std::string voice_input_filename_; + std::string voice_output_filename_; + std::string video_input_filename_; + std::string video_output_filename_; + std::vector voice_codecs_; + std::vector video_codecs_; + + std::string ring_wav_; + std::string call_wav_; + + DISALLOW_COPY_AND_ASSIGN(LinphoneMediaEngine); +}; + +class LinphoneVoiceChannel : public VoiceMediaChannel { + public: + LinphoneVoiceChannel(LinphoneMediaEngine *eng); + virtual ~LinphoneVoiceChannel(); + + // Implement pure virtual methods of VoiceMediaChannel. + virtual bool SetRecvCodecs(const std::vector& codecs) { return true; } + virtual bool SetSendCodecs(const std::vector& codecs); + virtual bool SetPlayout(bool playout); + virtual bool SetSend(SendFlags flag); + virtual bool AddStream(uint32 ssrc) { return true; } + virtual bool RemoveStream(uint32 ssrc) { return true; } + virtual bool GetActiveStreams(AudioInfo::StreamList* actives) { return true; } + virtual int GetOutputLevel() { return 0; } + virtual bool SetOutputScaling(uint32 ssrc, double left, double right) { + return false; + } + virtual bool GetOutputScaling(uint32 ssrc, double* left, double* right) { + return false; + } + virtual void SetRingbackTone(const char* buf, int len) {} + virtual bool PlayRingbackTone(bool play, bool loop) { return true; } + virtual bool PressDTMF(int event, bool playout) { return true; } + virtual bool GetStats(VoiceMediaInfo* info) { return true; } + + // Implement pure virtual methods of MediaChannel. + virtual void OnPacketReceived(talk_base::Buffer* packet); + virtual void OnRtcpReceived(talk_base::Buffer* packet) {} + 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 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& extensions) { return true; } + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions) { return true; } + + virtual void StartRing(bool bIncomingCall); + virtual void StopRing(); + + private: + int pt_; + bool mute_; + bool play_; + AudioStream *audio_stream_; + LinphoneMediaEngine *engine_; + RingStream* ring_stream_; + talk_base::scoped_ptr socket_; + void OnIncomingData(talk_base::AsyncSocket *s); + + DISALLOW_COPY_AND_ASSIGN(LinphoneVoiceChannel); +}; + +} // namespace cricket + +#endif // TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/sctp/sctpdataengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/sctp/sctpdataengine.h new file mode 100644 index 0000000..9568b3e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/sctp/sctpdataengine.h @@ -0,0 +1,262 @@ +/* + * libjingle SCTP + * Copyright 2012 Google Inc, and Robin Seggelmann + * + * 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_SCTP_SCTPDATAENGINE_H_ +#define TALK_MEDIA_SCTP_SCTPDATAENGINE_H_ + +#include +#include +#include + +namespace cricket { +// Some ERRNO values get re-#defined to WSA* equivalents in some talk/ +// headers. We save the original ones in an enum. +enum PreservedErrno { + SCTP_EINPROGRESS = EINPROGRESS, + SCTP_EWOULDBLOCK = EWOULDBLOCK +}; +} // namespace cricket + +#include "talk/base/buffer.h" +#include "talk/base/scoped_ptr.h" +#include "talk/media/base/codec.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/mediaengine.h" + +// Defined by "usrsctplib/usrsctp.h" +struct sockaddr_conn; +struct sctp_assoc_change; +struct sctp_stream_reset_event; +// Defined by +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: +// [worker thread (although it can in princple be another thread)] +// 1. SctpDataMediaChannel::SendData(data) +// 2. usrsctp_sendv(data) +// [worker thread returns; sctp thread then calls the following] +// 3. OnSctpOutboundPacket(wrapped_data) +// [sctp thread returns having posted a message for the worker thread] +// 4. SctpDataMediaChannel::OnMessage(wrapped_data) +// 5. SctpDataMediaChannel::OnPacketFromSctpToNetwork(wrapped_data) +// 6. NetworkInterface::SendPacket(wrapped_data) +// 7. ... across network ... a packet is sent back ... +// 8. SctpDataMediaChannel::OnPacketReceived(wrapped_data) +// 9. usrsctp_conninput(wrapped_data) +// [worker thread returns; sctp thread then calls the following] +// 10. OnSctpInboundData(data) +// [sctp thread returns having posted a message fot the worker thread] +// 11. SctpDataMediaChannel::OnMessage(inboundpacket) +// 12. SctpDataMediaChannel::OnInboundPacketFromSctpToChannel(inboundpacket) +// 13. SctpDataMediaChannel::OnDataFromSctpToChannel(data) +// 14. SctpDataMediaChannel::SignalDataReceived(data) +// [from the same thread, methods registered/connected to +// SctpDataMediaChannel are called with the recieved data] +class SctpDataEngine : public DataEngineInterface { + public: + SctpDataEngine(); + virtual ~SctpDataEngine(); + + virtual DataMediaChannel* CreateChannel(DataChannelType data_channel_type); + + virtual const std::vector& data_codecs() { return codecs_; } + + private: + static int usrsctp_engines_count; + std::vector codecs_; +}; + +// TODO(ldixon): Make into a special type of TypedMessageData. +// Holds data to be passed on to a channel. +struct SctpInboundPacket; + +class SctpDataMediaChannel : public DataMediaChannel, + public talk_base::MessageHandler { + public: + // DataMessageType is used for the SCTP "Payload Protocol Identifier", as + // defined in http://tools.ietf.org/html/rfc4960#section-14.4 + // + // For the list of IANA approved values see: + // http://www.iana.org/assignments/sctp-parameters/sctp-parameters.xml + // The value is not used by SCTP itself. It indicates the protocol running + // on top of SCTP. + enum PayloadProtocolIdentifier { + PPID_NONE = 0, // No protocol is specified. + // Matches the PPIDs in mozilla source and + // https://datatracker.ietf.org/doc/draft-ietf-rtcweb-data-protocol Sec. 9 + // They're not yet assigned by IANA. + PPID_CONTROL = 50, + PPID_BINARY_PARTIAL = 52, + PPID_BINARY_LAST = 53, + PPID_TEXT_PARTIAL = 54, + PPID_TEXT_LAST = 51 + }; + + typedef std::set StreamSet; + + // Given a thread which will be used to post messages (received data) to this + // SctpDataMediaChannel instance. + explicit SctpDataMediaChannel(talk_base::Thread* thread); + virtual ~SctpDataMediaChannel(); + + // When SetSend is set to true, connects. When set to false, disconnects. + // Calling: "SetSend(true); SetSend(false); SetSend(true);" will connect, + // disconnect, and reconnect. + virtual bool SetSend(bool send); + // Unless SetReceive(true) is called, received packets will be discarded. + virtual bool SetReceive(bool receive); + + virtual bool AddSendStream(const StreamParams& sp); + virtual bool RemoveSendStream(uint32 ssrc); + virtual bool AddRecvStream(const StreamParams& sp); + virtual bool RemoveRecvStream(uint32 ssrc); + + // Called when Sctp gets data. The data may be a notification or data for + // OnSctpInboundData. Called from the worker thread. + virtual void OnMessage(talk_base::Message* msg); + // Send data down this channel (will be wrapped as SCTP packets then given to + // sctp that will then post the network interface by OnMessage). + // Returns true iff successful data somewhere on the send-queue/network. + virtual bool SendData(const SendDataParams& params, + const talk_base::Buffer& payload, + SendDataResult* result = NULL); + // A packet is received from the network interface. Posted to OnMessage. + virtual void OnPacketReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + + // Exposed to allow Post call from c-callbacks. + talk_base::Thread* worker_thread() const { return worker_thread_; } + + // TODO(ldixon): add a DataOptions class to mediachannel.h + virtual bool SetOptions(int options) { return false; } + virtual int GetOptions() const { return 0; } + + // Many of these things are unused by SCTP, but are needed to fulfill + // the MediaChannel interface. + // 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 SetStartSendBandwidth(int bps) { return true; } + virtual bool SetMaxSendBandwidth(int bps) { return true; } + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions) { return true; } + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions) { return true; } + virtual bool SetSendCodecs(const std::vector& codecs); + virtual bool SetRecvCodecs(const std::vector& codecs); + virtual void OnRtcpReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time) {} + virtual void OnReadyToSend(bool ready) {} + + // Helper for debugging. + void set_debug_name(const std::string& debug_name) { + debug_name_ = debug_name; + } + const std::string& debug_name() const { return debug_name_; } + + // Called with the SSID of a remote stream that's been closed. + sigslot::signal1 SignalStreamClosed; + + private: + sockaddr_conn GetSctpSockAddr(int port); + + // Creates the socket and connects. Sets sending_ to true. + bool Connect(); + // Closes the socket. Sets sending_ to false. + void Disconnect(); + + // Returns false when openning the socket failed; when successfull sets + // sending_ to true + bool OpenSctpSocket(); + // 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. + void OnInboundPacketFromSctpToChannel(SctpInboundPacket* packet); + void OnDataFromSctpToChannel(const ReceiveDataParams& params, + talk_base::Buffer* buffer); + 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_; + // The local and remote SCTP port to use. These are 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. If set to -1, we default to + // kSctpDefaultPort. + int local_port_; + int remote_port_; + struct socket* sock_; // The socket created by usrsctp_socket(...). + + // sending_ is true iff there is a connected socket. + bool sending_; + // receiving_ controls whether inbound packets are thrown away. + bool receiving_; + + // 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_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_SCTP_SCTPDATAENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtccommon.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtccommon.h new file mode 100644 index 0000000..d82ef64 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtccommon.h @@ -0,0 +1,66 @@ +/* + * 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_SESSION_PHONE_FAKEWEBRTCCOMMON_H_ +#define TALK_SESSION_PHONE_FAKEWEBRTCCOMMON_H_ + +#include "talk/base/common.h" + +namespace cricket { + +#define WEBRTC_STUB(method, args) \ + virtual int method args OVERRIDE { return 0; } + +#define WEBRTC_STUB_CONST(method, args) \ + virtual int method args const OVERRIDE { return 0; } + +#define WEBRTC_BOOL_STUB(method, args) \ + virtual bool method args OVERRIDE { return true; } + +#define WEBRTC_VOID_STUB(method, args) \ + virtual void method args OVERRIDE {} + +#define WEBRTC_FUNC(method, args) \ + virtual int method args OVERRIDE + +#define WEBRTC_FUNC_CONST(method, args) \ + virtual int method args const OVERRIDE + +#define WEBRTC_BOOL_FUNC(method, args) \ + virtual bool method args OVERRIDE + +#define WEBRTC_VOID_FUNC(method, args) \ + virtual void method args OVERRIDE + +#define WEBRTC_CHECK_CHANNEL(channel) \ + if (channels_.find(channel) == channels_.end()) return -1; + +#define WEBRTC_ASSERT_CHANNEL(channel) \ + ASSERT(channels_.find(channel) != channels_.end()); +} // namespace cricket + +#endif // TALK_SESSION_PHONE_FAKEWEBRTCCOMMON_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcdeviceinfo.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcdeviceinfo.h new file mode 100644 index 0000000..9cdffee --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcdeviceinfo.h @@ -0,0 +1,123 @@ +// 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_SESSION_PHONE_FAKEWEBRTCDEVICEINFO_H_ +#define TALK_SESSION_PHONE_FAKEWEBRTCDEVICEINFO_H_ + +#include + +#include "talk/base/stringutils.h" +#include "talk/media/webrtc/webrtcvideocapturer.h" + +// Fake class for mocking out webrtc::VideoCaptureModule::DeviceInfo. +class FakeWebRtcDeviceInfo : public webrtc::VideoCaptureModule::DeviceInfo { + public: + struct Device { + Device(const std::string& n, const std::string& i) : name(n), id(i) {} + std::string name; + std::string id; + std::string product; + std::vector caps; + }; + FakeWebRtcDeviceInfo() {} + void AddDevice(const std::string& device_name, const std::string& device_id) { + devices_.push_back(Device(device_name, device_id)); + } + void AddCapability(const std::string& device_id, + const webrtc::VideoCaptureCapability& cap) { + Device* dev = GetDeviceById( + reinterpret_cast(device_id.c_str())); + if (!dev) return; + dev->caps.push_back(cap); + } + virtual uint32_t NumberOfDevices() { + return static_cast(devices_.size()); + } + virtual int32_t GetDeviceName(uint32_t device_num, + char* device_name, + uint32_t device_name_len, + char* device_id, + uint32_t device_id_len, + char* product_id, + uint32_t product_id_len) { + Device* dev = GetDeviceByIndex(device_num); + if (!dev) return -1; + talk_base::strcpyn(reinterpret_cast(device_name), device_name_len, + dev->name.c_str()); + talk_base::strcpyn(reinterpret_cast(device_id), device_id_len, + dev->id.c_str()); + if (product_id) { + talk_base::strcpyn(reinterpret_cast(product_id), product_id_len, + dev->product.c_str()); + } + return 0; + } + virtual int32_t NumberOfCapabilities(const char* device_id) { + Device* dev = GetDeviceById(device_id); + if (!dev) return -1; + return static_cast(dev->caps.size()); + } + virtual int32_t GetCapability(const char* device_id, + const uint32_t device_cap_num, + webrtc::VideoCaptureCapability& cap) { + Device* dev = GetDeviceById(device_id); + if (!dev) return -1; + if (device_cap_num >= dev->caps.size()) return -1; + cap = dev->caps[device_cap_num]; + return 0; + } + virtual int32_t GetOrientation(const char* device_id, + webrtc::VideoCaptureRotation& rotation) { + return -1; // not implemented + } + virtual int32_t GetBestMatchedCapability( + const char* device_id, + const webrtc::VideoCaptureCapability& requested, + webrtc::VideoCaptureCapability& resulting) { + return -1; // not implemented + } + virtual int32_t DisplayCaptureSettingsDialogBox( + const char* device_id, const char* dialog_title, + void* parent, uint32_t x, uint32_t y) { + return -1; // not implemented + } + + Device* GetDeviceByIndex(size_t num) { + return (num < devices_.size()) ? &devices_[num] : NULL; + } + Device* GetDeviceById(const char* device_id) { + for (size_t i = 0; i < devices_.size(); ++i) { + if (devices_[i].id == reinterpret_cast(device_id)) { + return &devices_[i]; + } + } + return NULL; + } + + private: + std::vector devices_; +}; + +#endif // TALK_SESSION_PHONE_FAKEWEBRTCDEVICEINFO_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvcmfactory.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvcmfactory.h new file mode 100644 index 0000000..03c806e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvcmfactory.h @@ -0,0 +1,63 @@ +// 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_SESSION_PHONE_FAKEWEBRTCVCMFACTORY_H_ +#define TALK_SESSION_PHONE_FAKEWEBRTCVCMFACTORY_H_ + +#include + +#include "talk/media/webrtc/fakewebrtcvideocapturemodule.h" +#include "talk/media/webrtc/webrtcvideocapturer.h" + +// Factory class to allow the fakes above to be injected into +// WebRtcVideoCapturer. +class FakeWebRtcVcmFactory : public cricket::WebRtcVcmFactoryInterface { + public: + virtual webrtc::VideoCaptureModule* Create(int module_id, + const char* device_id) { + if (!device_info.GetDeviceById(device_id)) return NULL; + FakeWebRtcVideoCaptureModule* module = + new FakeWebRtcVideoCaptureModule(this, module_id); + modules.push_back(module); + return module; + } + virtual webrtc::VideoCaptureModule::DeviceInfo* CreateDeviceInfo(int id) { + return &device_info; + } + virtual void DestroyDeviceInfo(webrtc::VideoCaptureModule::DeviceInfo* info) { + } + void OnDestroyed(webrtc::VideoCaptureModule* module) { + std::remove(modules.begin(), modules.end(), module); + } + FakeWebRtcDeviceInfo device_info; + std::vector modules; +}; + +FakeWebRtcVideoCaptureModule::~FakeWebRtcVideoCaptureModule() { + if (factory_) + factory_->OnDestroyed(this); +} + +#endif // TALK_SESSION_PHONE_FAKEWEBRTCVCMFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvideocapturemodule.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvideocapturemodule.h new file mode 100644 index 0000000..156f7fc --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvideocapturemodule.h @@ -0,0 +1,150 @@ +// 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_SESSION_PHONE_FAKEWEBRTCVIDEOCAPTUREMODULE_H_ +#define TALK_SESSION_PHONE_FAKEWEBRTCVIDEOCAPTUREMODULE_H_ + +#include + +#include "talk/media/base/testutils.h" +#include "talk/media/webrtc/fakewebrtcdeviceinfo.h" +#include "talk/media/webrtc/webrtcvideocapturer.h" + +class FakeWebRtcVcmFactory; + +// Fake class for mocking out webrtc::VideoCaptureModule. +class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule { + public: + FakeWebRtcVideoCaptureModule(FakeWebRtcVcmFactory* factory, int32_t id) + : factory_(factory), + id_(id), + callback_(NULL), + running_(false), + delay_(0) { + } + virtual int32_t Version(char* version, + uint32_t& remaining_buffer_in_bytes, + uint32_t& position) const { + return 0; + } + virtual int32_t TimeUntilNextProcess() { + return 0; + } + virtual int32_t Process() { + return 0; + } + virtual int32_t ChangeUniqueId(const int32_t id) { + id_ = id; + return 0; + } + virtual void RegisterCaptureDataCallback( + webrtc::VideoCaptureDataCallback& callback) { + callback_ = &callback; + } + virtual void DeRegisterCaptureDataCallback() { callback_ = NULL; } + virtual void RegisterCaptureCallback(webrtc::VideoCaptureFeedBack& callback) { + // Not implemented. + } + virtual void DeRegisterCaptureCallback() { + // Not implemented. + } + 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) { + if (running_) return -1; + cap_ = cap; + running_ = true; + return 0; + } + virtual int32_t StopCapture() { + running_ = false; + return 0; + } + virtual const char* CurrentDeviceName() const { + return NULL; // not implemented + } + virtual bool CaptureStarted() { + return running_; + } + virtual int32_t CaptureSettings( + webrtc::VideoCaptureCapability& settings) { + if (!running_) return -1; + settings = cap_; + return 0; + } + + virtual int32_t SetCaptureRotation( + webrtc::VideoCaptureRotation rotation) { + return -1; // not implemented + } + virtual VideoCaptureEncodeInterface* GetEncodeInterface( + const webrtc::VideoCodec& codec) { + return NULL; // not implemented + } + virtual int32_t AddRef() { + return 0; + } + virtual int32_t Release() { + delete this; + return 0; + } + + bool SendFrame(int w, int h) { + if (!running_) return false; + webrtc::I420VideoFrame sample; + // Setting stride based on width. + if (sample.CreateEmptyFrame(w, h, w, (w + 1) / 2, (w + 1) / 2) < 0) { + return false; + } + if (callback_) { + callback_->OnIncomingCapturedFrame(id_, sample); + } + return true; + } + + const webrtc::VideoCaptureCapability& cap() const { + return cap_; + } + + private: + // Ref-counted, use Release() instead. + ~FakeWebRtcVideoCaptureModule(); + + FakeWebRtcVcmFactory* factory_; + int id_; + webrtc::VideoCaptureDataCallback* callback_; + bool running_; + webrtc::VideoCaptureCapability cap_; + int delay_; +}; + +#endif // TALK_SESSION_PHONE_FAKEWEBRTCVIDEOCAPTUREMODULE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvideoengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvideoengine.h new file mode 100644 index 0000000..1b31f05 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvideoengine.h @@ -0,0 +1,1283 @@ +/* + * 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. + */ + +#ifndef TALK_MEDIA_WEBRTC_FAKEWEBRTCVIDEOENGINE_H_ +#define TALK_MEDIA_WEBRTC_FAKEWEBRTCVIDEOENGINE_H_ + +#include +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/gunit.h" +#include "talk/base/stringutils.h" +#include "talk/media/base/codec.h" +#include "talk/media/webrtc/fakewebrtccommon.h" +#include "talk/media/webrtc/webrtcvideodecoderfactory.h" +#include "talk/media/webrtc/webrtcvideoencoderfactory.h" +#include "talk/media/webrtc/webrtcvie.h" + +namespace cricket { + +#define WEBRTC_CHECK_CAPTURER(capturer) \ + if (capturers_.find(capturer) == capturers_.end()) return -1; + +#define WEBRTC_ASSERT_CAPTURER(capturer) \ + ASSERT(capturers_.find(capturer) != capturers_.end()); + +static const int kMinVideoBitrate = 100; +static const int kStartVideoBitrate = 300; +static const int kMaxVideoBitrate = 1000; + +// WebRtc channel id and capture id share the same number space. +// This is how AddRenderer(renderId, ...) is able to tell if it is adding a +// renderer for a channel or it is adding a renderer for a capturer. +static const int kViEChannelIdBase = 0; +static const int kViEChannelIdMax = 1000; +static const int kViECaptureIdBase = 10000; // Make sure there is a gap. +static const int kViECaptureIdMax = 11000; + +// Fake class for mocking out webrtc::VideoDecoder +class FakeWebRtcVideoDecoder : public webrtc::VideoDecoder { + public: + FakeWebRtcVideoDecoder() + : num_frames_received_(0) { + } + + virtual int32 InitDecode(const webrtc::VideoCodec*, int32) { + return WEBRTC_VIDEO_CODEC_OK; + } + + virtual int32 Decode( + const webrtc::EncodedImage&, bool, const webrtc::RTPFragmentationHeader*, + const webrtc::CodecSpecificInfo*, int64) { + num_frames_received_++; + return WEBRTC_VIDEO_CODEC_OK; + } + + virtual int32 RegisterDecodeCompleteCallback( + webrtc::DecodedImageCallback*) { + return WEBRTC_VIDEO_CODEC_OK; + } + + virtual int32 Release() { + return WEBRTC_VIDEO_CODEC_OK; + } + + virtual int32 Reset() { + return WEBRTC_VIDEO_CODEC_OK; + } + + int GetNumFramesReceived() const { + return num_frames_received_; + } + + private: + int num_frames_received_; +}; + +// Fake class for mocking out WebRtcVideoDecoderFactory. +class FakeWebRtcVideoDecoderFactory : public WebRtcVideoDecoderFactory { + public: + FakeWebRtcVideoDecoderFactory() + : num_created_decoders_(0) { + } + + virtual webrtc::VideoDecoder* CreateVideoDecoder( + webrtc::VideoCodecType type) { + if (supported_codec_types_.count(type) == 0) { + return NULL; + } + FakeWebRtcVideoDecoder* decoder = new FakeWebRtcVideoDecoder(); + decoders_.push_back(decoder); + num_created_decoders_++; + return decoder; + } + + virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) { + decoders_.erase( + std::remove(decoders_.begin(), decoders_.end(), decoder), + decoders_.end()); + delete decoder; + } + + void AddSupportedVideoCodecType(webrtc::VideoCodecType type) { + supported_codec_types_.insert(type); + } + + int GetNumCreatedDecoders() { + return num_created_decoders_; + } + + const std::vector& decoders() { + return decoders_; + } + + private: + std::set supported_codec_types_; + std::vector decoders_; + int num_created_decoders_; +}; + +// Fake class for mocking out webrtc::VideoEnoder +class FakeWebRtcVideoEncoder : public webrtc::VideoEncoder { + public: + FakeWebRtcVideoEncoder() {} + + virtual int32 InitEncode(const webrtc::VideoCodec* codecSettings, + int32 numberOfCores, + uint32 maxPayloadSize) { + return WEBRTC_VIDEO_CODEC_OK; + } + + virtual int32 Encode( + const webrtc::I420VideoFrame& inputImage, + const webrtc::CodecSpecificInfo* codecSpecificInfo, + const std::vector* frame_types) { + return WEBRTC_VIDEO_CODEC_OK; + } + + virtual int32 RegisterEncodeCompleteCallback( + webrtc::EncodedImageCallback* callback) { + return WEBRTC_VIDEO_CODEC_OK; + } + + virtual int32 Release() { + return WEBRTC_VIDEO_CODEC_OK; + } + + virtual int32 SetChannelParameters(uint32 packetLoss, + int rtt) { + return WEBRTC_VIDEO_CODEC_OK; + } + + virtual int32 SetRates(uint32 newBitRate, + uint32 frameRate) { + return WEBRTC_VIDEO_CODEC_OK; + } +}; + +// Fake class for mocking out WebRtcVideoEncoderFactory. +class FakeWebRtcVideoEncoderFactory : public WebRtcVideoEncoderFactory { + public: + FakeWebRtcVideoEncoderFactory() + : num_created_encoders_(0) { + } + + virtual webrtc::VideoEncoder* CreateVideoEncoder( + webrtc::VideoCodecType type) { + if (supported_codec_types_.count(type) == 0) { + return NULL; + } + FakeWebRtcVideoEncoder* encoder = new FakeWebRtcVideoEncoder(); + encoders_.push_back(encoder); + num_created_encoders_++; + return encoder; + } + + virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) { + encoders_.erase( + std::remove(encoders_.begin(), encoders_.end(), encoder), + encoders_.end()); + delete encoder; + } + + virtual void AddObserver(WebRtcVideoEncoderFactory::Observer* observer) { + bool inserted = observers_.insert(observer).second; + EXPECT_TRUE(inserted); + } + + virtual void RemoveObserver(WebRtcVideoEncoderFactory::Observer* observer) { + size_t erased = observers_.erase(observer); + EXPECT_EQ(erased, 1UL); + } + + virtual const std::vector& codecs() + const { + return codecs_; + } + + void AddSupportedVideoCodecType(webrtc::VideoCodecType type, + const std::string& name) { + supported_codec_types_.insert(type); + codecs_.push_back( + WebRtcVideoEncoderFactory::VideoCodec(type, name, 1280, 720, 30)); + } + + void NotifyCodecsAvailable() { + std::set::iterator it; + for (it = observers_.begin(); it != observers_.end(); ++it) + (*it)->OnCodecsAvailable(); + } + + int GetNumCreatedEncoders() { + return num_created_encoders_; + } + + const std::vector& encoders() { + return encoders_; + } + + private: + std::set supported_codec_types_; + std::vector codecs_; + std::vector encoders_; + std::set observers_; + int num_created_encoders_; +}; + +class FakeWebRtcVideoEngine + : public webrtc::ViEBase, + public webrtc::ViECodec, + public webrtc::ViECapture, + public webrtc::ViENetwork, + public webrtc::ViERender, + public webrtc::ViERTP_RTCP, + public webrtc::ViEImageProcess, + public webrtc::ViEExternalCodec { + public: + struct Channel { + Channel() + : capture_id_(-1), + original_channel_id_(-1), + has_renderer_(false), + render_started_(false), + send(false), + receive_(false), + 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_(-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), + nack_(false), + hybrid_nack_fec_(false), + send_video_bitrate_(0), + send_fec_bitrate_(0), + send_nack_bitrate_(0), + send_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_; + bool has_renderer_; + bool render_started_; + bool send; + bool receive_; + bool can_transmit_; + std::map ssrcs_; + std::map 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_; + bool tmmbr_; + bool remb_contribute_; // This channel contributes to the remb report. + bool remb_bw_partition_; // This channel is allocated part of total bw. + int rtp_offset_send_id_; + int rtp_offset_receive_id_; + int rtp_absolute_send_time_send_id_; + int rtp_absolute_send_time_receive_id_; + int sender_target_delay_; + int receiver_target_delay_; + bool transmission_smoothing_; + bool nack_; + bool hybrid_nack_fec_; + std::vector recv_codecs; + std::set ext_decoder_pl_types_; + std::set ext_encoder_pl_types_; + webrtc::VideoCodec send_codec; + unsigned int send_video_bitrate_; + unsigned int send_fec_bitrate_; + 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: + Capturer() : channel_id_(-1), denoising_(false), + last_capture_time_(0), incoming_frame_num_(0) { } + int channel_id() const { return channel_id_; } + void set_channel_id(int channel_id) { channel_id_ = channel_id; } + bool denoising() const { return denoising_; } + void set_denoising(bool denoising) { denoising_ = denoising; } + int64 last_capture_time() const { return last_capture_time_; } + int incoming_frame_num() const { return incoming_frame_num_; } + + // From ViEExternalCapture + virtual int IncomingFrame(unsigned char* videoFrame, + unsigned int videoFrameLength, + unsigned short width, + unsigned short height, + webrtc::RawVideoType videoType, + unsigned long long captureTime) { + return 0; + } + virtual int IncomingFrameI420( + const webrtc::ViEVideoFrameI420& video_frame, + unsigned long long captureTime) { + last_capture_time_ = captureTime; + ++incoming_frame_num_; + return 0; + } + + private: + int channel_id_; + bool denoising_; + int64 last_capture_time_; + int incoming_frame_num_; + }; + + FakeWebRtcVideoEngine(const cricket::VideoCodec* const* codecs, + int num_codecs) + : inited_(false), + last_channel_(kViEChannelIdBase - 1), + fail_create_channel_(false), + last_capturer_(kViECaptureIdBase - 1), + fail_alloc_capturer_(false), + codecs_(codecs), + num_codecs_(num_codecs), + num_set_send_codecs_(0) { + } + + ~FakeWebRtcVideoEngine() { + ASSERT(0 == channels_.size()); + ASSERT(0 == capturers_.size()); + } + bool IsInited() const { return inited_; } + + int GetLastChannel() const { return last_channel_; } + int GetChannelFromLocalSsrc(int local_ssrc) const { + // ssrcs_[0] is the default local ssrc. + for (std::map::const_iterator iter = channels_.begin(); + iter != channels_.end(); ++iter) { + if (local_ssrc == iter->second->ssrcs_[0]) { + return iter->first; + } + } + return -1; + } + + int GetNumChannels() const { return static_cast(channels_.size()); } + bool IsChannel(int channel) const { + return (channels_.find(channel) != channels_.end()); + } + void set_fail_create_channel(bool fail_create_channel) { + fail_create_channel_ = fail_create_channel; + } + + int GetLastCapturer() const { return last_capturer_; } + int GetNumCapturers() const { return static_cast(capturers_.size()); } + int GetIncomingFrameNum(int channel_id) const { + for (std::map::const_iterator iter = capturers_.begin(); + iter != capturers_.end(); ++iter) { + Capturer* capturer = iter->second; + if (capturer->channel_id() == channel_id) { + return capturer->incoming_frame_num(); + } + } + return -1; + } + void set_fail_alloc_capturer(bool fail_alloc_capturer) { + fail_alloc_capturer_ = fail_alloc_capturer; + } + int GetNumSetSendCodecs() const { return num_set_send_codecs_; } + + int GetCaptureId(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->capture_id_; + } + int GetOriginalChannelId(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->original_channel_id_; + } + bool GetHasRenderer(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->has_renderer_; + } + bool GetRenderStarted(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->render_started_; + } + bool GetSend(int channel) const { + 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(); + } + bool GetCaptureDenoising(int capture_id) const { + WEBRTC_ASSERT_CAPTURER(capture_id); + return capturers_.find(capture_id)->second->denoising(); + } + int64 GetCaptureLastTimestamp(int capture_id) const { + WEBRTC_ASSERT_CAPTURER(capture_id); + return capturers_.find(capture_id)->second->last_capture_time(); + } + webrtc::ViERTCPMode GetRtcpStatus(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->rtcp_status_; + } + webrtc::ViEKeyFrameRequestMethod GetKeyFrameRequestMethod(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->key_frame_request_method_; + } + bool GetTmmbrStatus(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->tmmbr_; + } + bool GetRembStatusBwPartition(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->remb_bw_partition_; + } + bool GetRembStatusContribute(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->remb_contribute_; + } + int GetSendRtpExtensionId(int channel, const std::string& extension) { + WEBRTC_ASSERT_CHANNEL(channel); + 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 GetReceiveRtpExtensionId(int channel, const std::string& extension) { + WEBRTC_ASSERT_CHANNEL(channel); + 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); + return channels_.find(channel)->second->transmission_smoothing_; + } + int GetSenderTargetDelay(int channel) { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->sender_target_delay_; + } + int GetReceiverTargetDelay(int channel) { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->receiver_target_delay_; + } + bool GetNackStatus(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->nack_; + } + bool GetHybridNackFecStatus(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second->hybrid_nack_fec_; + } + int GetNumSsrcs(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return static_cast( + channels_.find(channel)->second->ssrcs_.size()); + } + int GetNumRtxSsrcs(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return static_cast( + channels_.find(channel)->second->rtx_ssrcs_.size()); + } + bool GetIsTransmitting(int channel) const { + 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) == + channels_.find(channel)->second->rtx_ssrcs_.end()) { + return -1; + } + return channels_.find(channel)->second->rtx_ssrcs_[simulcast_idx]; + } + bool ReceiveCodecRegistered(int channel, + const webrtc::VideoCodec& codec) const { + WEBRTC_ASSERT_CHANNEL(channel); + const std::vector& codecs = + channels_.find(channel)->second->recv_codecs; + return std::find(codecs.begin(), codecs.end(), codec) != codecs.end(); + }; + bool ExternalDecoderRegistered(int channel, + unsigned int pl_type) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second-> + ext_decoder_pl_types_.count(pl_type) != 0; + }; + int GetNumExternalDecoderRegistered(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return static_cast( + channels_.find(channel)->second->ext_decoder_pl_types_.size()); + }; + bool ExternalEncoderRegistered(int channel, + unsigned int pl_type) const { + WEBRTC_ASSERT_CHANNEL(channel); + return channels_.find(channel)->second-> + ext_encoder_pl_types_.count(pl_type) != 0; + }; + int GetNumExternalEncoderRegistered(int channel) const { + WEBRTC_ASSERT_CHANNEL(channel); + return static_cast( + channels_.find(channel)->second->ext_encoder_pl_types_.size()); + }; + int GetTotalNumExternalEncoderRegistered() const { + std::map::const_iterator it; + int total_num_registered = 0; + for (it = channels_.begin(); it != channels_.end(); ++it) + total_num_registered += + static_cast(it->second->ext_encoder_pl_types_.size()); + return total_num_registered; + } + void SetSendBitrates(int channel, unsigned int video_bitrate, + unsigned int fec_bitrate, unsigned int nack_bitrate) { + WEBRTC_ASSERT_CHANNEL(channel); + channels_[channel]->send_video_bitrate_ = video_bitrate; + channels_[channel]->send_fec_bitrate_ = fec_bitrate; + channels_[channel]->send_nack_bitrate_ = nack_bitrate; + } + void SetSendBandwidthEstimate(int channel, unsigned int send_bandwidth) { + WEBRTC_ASSERT_CHANNEL(channel); + channels_[GetOriginalChannelId(channel)]->send_bandwidth_ = send_bandwidth; + } + void SetReceiveBandwidthEstimate(int channel, + unsigned int receive_bandwidth) { + WEBRTC_ASSERT_CHANNEL(channel); + 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, ()); + + // webrtc::ViEBase + WEBRTC_FUNC(Init, ()) { + inited_ = true; + return 0; + }; + WEBRTC_STUB(SetVoiceEngine, (webrtc::VoiceEngine*)); + WEBRTC_FUNC(CreateChannel, (int& channel)) { // NOLINT + if (fail_create_channel_) { + return -1; + } + if (kViEChannelIdMax == last_channel_) { + return -1; + } + Channel* ch = new Channel(); + ++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; + }; + WEBRTC_FUNC(CreateChannel, (int& channel, int original_channel)) { + WEBRTC_CHECK_CHANNEL(original_channel); + if (CreateChannel(channel) != 0) { + return -1; + } + channels_[channel]->original_channel_id_ = original_channel; + return 0; + } + WEBRTC_FUNC(CreateReceiveChannel, (int& channel, int original_channel)) { + return CreateChannel(channel, original_channel); + } + WEBRTC_FUNC(DeleteChannel, (const int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + // Make sure we deregister all the decoders before deleting a channel. + EXPECT_EQ(0, GetNumExternalDecoderRegistered(channel)); + delete channels_[channel]; + channels_.erase(channel); + return 0; + } + 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*)); + 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)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->send = true; + return 0; + } + WEBRTC_FUNC(StopSend, (const int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->send = false; + return 0; + } + WEBRTC_FUNC(StartReceive, (const int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->receive_ = true; + return 0; + } + WEBRTC_FUNC(StopReceive, (const int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->receive_ = false; + return 0; + } + WEBRTC_STUB(GetVersion, (char version[1024])); + WEBRTC_STUB(LastError, ()); + + // webrtc::ViECodec + WEBRTC_FUNC_CONST(NumberOfCodecs, ()) { + return num_codecs_; + }; + WEBRTC_FUNC_CONST(GetCodec, (const unsigned char list_number, + webrtc::VideoCodec& out_codec)) { + if (list_number >= NumberOfCodecs()) { + return -1; + } + memset(&out_codec, 0, sizeof(out_codec)); + const cricket::VideoCodec& c(*codecs_[list_number]); + if ("I420" == c.name) { + out_codec.codecType = webrtc::kVideoCodecI420; + } else if ("VP8" == c.name) { + out_codec.codecType = webrtc::kVideoCodecVP8; + } else if ("red" == c.name) { + out_codec.codecType = webrtc::kVideoCodecRED; + } else if ("ulpfec" == c.name) { + out_codec.codecType = webrtc::kVideoCodecULPFEC; + } else { + out_codec.codecType = webrtc::kVideoCodecUnknown; + } + talk_base::strcpyn(out_codec.plName, sizeof(out_codec.plName), + c.name.c_str()); + out_codec.plType = c.id; + out_codec.width = c.width; + out_codec.height = c.height; + out_codec.startBitrate = kStartVideoBitrate; + out_codec.maxBitrate = kMaxVideoBitrate; + out_codec.minBitrate = kMinVideoBitrate; + out_codec.maxFramerate = c.framerate; + return 0; + }; + WEBRTC_FUNC(SetSendCodec, (const int channel, + const webrtc::VideoCodec& codec)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->send_codec = codec; + ++num_set_send_codecs_; + return 0; + }; + WEBRTC_FUNC_CONST(GetSendCodec, (const int channel, + webrtc::VideoCodec& codec)) { // NOLINT + WEBRTC_CHECK_CHANNEL(channel); + codec = channels_.find(channel)->second->send_codec; + return 0; + }; + WEBRTC_FUNC(SetReceiveCodec, (const int channel, + const webrtc::VideoCodec& codec)) { // NOLINT + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->recv_codecs.push_back(codec); + return 0; + }; + WEBRTC_STUB_CONST(GetReceiveCodec, (const int, webrtc::VideoCodec&)); + WEBRTC_STUB_CONST(GetCodecConfigParameters, (const int, + unsigned char*, unsigned char&)); + WEBRTC_STUB(SetImageScaleStatus, (const int, const bool)); + WEBRTC_STUB_CONST(GetSendCodecStastistics, (const int, + unsigned int&, unsigned int&)); + WEBRTC_STUB_CONST(GetReceiveCodecStastistics, (const int, + unsigned int&, unsigned int&)); + WEBRTC_STUB_CONST(GetReceiveSideDelay, (const int video_channel, + int* delay_ms)); + WEBRTC_FUNC_CONST(GetCodecTargetBitrate, (const int channel, + unsigned int* codec_target_bitrate)) { + WEBRTC_CHECK_CHANNEL(channel); + + std::map::const_iterator it = channels_.find(channel); + if (it->second->send) { + // Assume the encoder produces the expected rate. + *codec_target_bitrate = it->second->send_video_bitrate_; + } else { + *codec_target_bitrate = 0; + } + return 0; + } + virtual unsigned int GetDiscardedPackets(const int channel) const { + return 0; + } + + WEBRTC_STUB(SetKeyFrameRequestCallbackStatus, (const int, const bool)); + WEBRTC_STUB(SetSignalKeyPacketLossStatus, (const int, const bool, + const bool)); + WEBRTC_STUB(RegisterEncoderObserver, (const int, + webrtc::ViEEncoderObserver&)); + WEBRTC_STUB(DeregisterEncoderObserver, (const int)); + WEBRTC_STUB(RegisterDecoderObserver, (const int, + webrtc::ViEDecoderObserver&)); + WEBRTC_STUB(DeregisterDecoderObserver, (const int)); + WEBRTC_STUB(SendKeyFrame, (const int)); + WEBRTC_STUB(WaitForFirstKeyFrame, (const int, const bool)); + WEBRTC_STUB(StartDebugRecording, (int, const char*)); + WEBRTC_STUB(StopDebugRecording, (int)); + WEBRTC_VOID_FUNC(SuspendBelowMinBitrate, (int channel)) { + WEBRTC_ASSERT_CHANNEL(channel); + channels_[channel]->suspend_below_min_bitrate_ = true; + } + + // webrtc::ViECapture + WEBRTC_STUB(NumberOfCaptureDevices, ()); + WEBRTC_STUB(GetCaptureDevice, (unsigned int, char*, + const unsigned int, char*, const unsigned int)); + WEBRTC_STUB(AllocateCaptureDevice, (const char*, const unsigned int, int&)); + WEBRTC_FUNC(AllocateExternalCaptureDevice, + (int& capture_id, webrtc::ViEExternalCapture*& capture)) { + if (fail_alloc_capturer_) { + return -1; + } + if (kViECaptureIdMax == last_capturer_) { + return -1; + } + Capturer* cap = new Capturer(); + capturers_[++last_capturer_] = cap; + capture_id = last_capturer_; + capture = cap; + return 0; + } + WEBRTC_STUB(AllocateCaptureDevice, (webrtc::VideoCaptureModule&, int&)); + WEBRTC_FUNC(ReleaseCaptureDevice, (const int capture_id)) { + WEBRTC_CHECK_CAPTURER(capture_id); + delete capturers_[capture_id]; + capturers_.erase(capture_id); + return 0; + } + WEBRTC_FUNC(ConnectCaptureDevice, (const int capture_id, + const int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + WEBRTC_CHECK_CAPTURER(capture_id); + channels_[channel]->capture_id_ = capture_id; + capturers_[capture_id]->set_channel_id(channel); + return 0; + } + WEBRTC_FUNC(DisconnectCaptureDevice, (const int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + int capture_id = channels_[channel]->capture_id_; + WEBRTC_CHECK_CAPTURER(capture_id); + channels_[channel]->capture_id_ = -1; + capturers_[capture_id]->set_channel_id(-1); + return 0; + } + WEBRTC_STUB(StartCapture, (const int, const webrtc::CaptureCapability&)); + WEBRTC_STUB(StopCapture, (const int)); + WEBRTC_STUB(SetRotateCapturedFrames, (const int, + const webrtc::RotateCapturedFrame)); + WEBRTC_STUB(SetCaptureDelay, (const int, const unsigned int)); + WEBRTC_STUB(NumberOfCapabilities, (const char*, const unsigned int)); + WEBRTC_STUB(GetCaptureCapability, (const char*, const unsigned int, + const unsigned int, webrtc::CaptureCapability&)); + WEBRTC_STUB(ShowCaptureSettingsDialogBox, (const char*, const unsigned int, + const char*, void*, const unsigned int, const unsigned int)); + WEBRTC_STUB(GetOrientation, (const char*, webrtc::RotateCapturedFrame&)); + WEBRTC_STUB(EnableBrightnessAlarm, (const int, const bool)); + WEBRTC_STUB(RegisterObserver, (const int, webrtc::ViECaptureObserver&)); + WEBRTC_STUB(DeregisterObserver, (const int)); + + // webrtc::ViENetwork + WEBRTC_VOID_FUNC(SetNetworkTransmissionState, (const int channel, + const bool is_transmitting)) { + WEBRTC_ASSERT_CHANNEL(channel); + channels_[channel]->can_transmit_ = is_transmitting; + } + WEBRTC_STUB(RegisterSendTransport, (const int, webrtc::Transport&)); + WEBRTC_STUB(DeregisterSendTransport, (const int)); + + 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(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&)); + WEBRTC_STUB(DeRegisterVideoRenderModule, (webrtc::VideoRender&)); + WEBRTC_STUB(AddRenderer, (const int, void*, const unsigned int, const float, + const float, const float, const float)); + WEBRTC_FUNC(RemoveRenderer, (const int render_id)) { + if (IsCapturerId(render_id)) { + WEBRTC_CHECK_CAPTURER(render_id); + return 0; + } else if (IsChannelId(render_id)) { + WEBRTC_CHECK_CHANNEL(render_id); + channels_[render_id]->has_renderer_ = false; + return 0; + } + return -1; + } + WEBRTC_FUNC(StartRender, (const int render_id)) { + if (IsCapturerId(render_id)) { + WEBRTC_CHECK_CAPTURER(render_id); + return 0; + } else if (IsChannelId(render_id)) { + WEBRTC_CHECK_CHANNEL(render_id); + channels_[render_id]->render_started_ = true; + return 0; + } + return -1; + } + WEBRTC_FUNC(StopRender, (const int render_id)) { + if (IsCapturerId(render_id)) { + WEBRTC_CHECK_CAPTURER(render_id); + return 0; + } else if (IsChannelId(render_id)) { + WEBRTC_CHECK_CHANNEL(render_id); + channels_[render_id]->render_started_ = false; + return 0; + } + return -1; + } + WEBRTC_STUB(SetExpectedRenderDelay, (int render_id, int render_delay)); + WEBRTC_STUB(ConfigureRender, (int, const unsigned int, const float, + const float, const float, const float)); + WEBRTC_STUB(MirrorRenderStream, (const int, const bool, const bool, + const bool)); + WEBRTC_FUNC(AddRenderer, (const int render_id, + webrtc::RawVideoType video_type, + webrtc::ExternalRenderer* renderer)) { + if (IsCapturerId(render_id)) { + WEBRTC_CHECK_CAPTURER(render_id); + return 0; + } else if (IsChannelId(render_id)) { + WEBRTC_CHECK_CHANNEL(render_id); + channels_[render_id]->has_renderer_ = true; + return 0; + } + return -1; + } + + // webrtc::ViERTP_RTCP + WEBRTC_FUNC(SetLocalSSRC, (const int channel, + const unsigned int ssrc, + const webrtc::StreamType usage, + const unsigned char idx)) { + WEBRTC_CHECK_CHANNEL(channel); + switch (usage) { + case webrtc::kViEStreamTypeNormal: + channels_[channel]->ssrcs_[idx] = ssrc; + break; + case webrtc::kViEStreamTypeRtx: + channels_[channel]->rtx_ssrcs_[idx] = ssrc; + break; + default: + return -1; + } + return 0; + } + + WEBRTC_FUNC_CONST(SetRemoteSSRCType, (const int channel, + const webrtc::StreamType usage, const unsigned int ssrc)) { + WEBRTC_CHECK_CHANNEL(channel); + if (usage == webrtc::kViEStreamTypeRtx) { + channels_.find(channel)->second->remote_rtx_ssrc_ = ssrc; + return 0; + } + return -1; + } + + WEBRTC_FUNC_CONST(GetLocalSSRC, (const int channel, + unsigned int& ssrc)) { + // ssrcs_[0] is the default local ssrc. + WEBRTC_CHECK_CHANNEL(channel); + ssrc = channels_.find(channel)->second->ssrcs_[0]; + return 0; + } + WEBRTC_STUB_CONST(GetRemoteSSRC, (const int, unsigned int&)); + WEBRTC_STUB_CONST(GetRemoteCSRCs, (const int, unsigned int*)); + + WEBRTC_FUNC(SetRtxSendPayloadType, (const int channel, + const uint8 payload_type)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->rtx_send_payload_type = payload_type; + return 0; + } + + 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, + (const int channel, const webrtc::ViERTCPMode mode)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->rtcp_status_ = mode; + return 0; + } + WEBRTC_STUB_CONST(GetRTCPStatus, (const int, webrtc::ViERTCPMode&)); + WEBRTC_FUNC(SetRTCPCName, (const int channel, + const char rtcp_cname[KMaxRTCPCNameLength])) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->cname_.assign(rtcp_cname); + return 0; + } + WEBRTC_FUNC_CONST(GetRTCPCName, (const int channel, + char rtcp_cname[KMaxRTCPCNameLength])) { + WEBRTC_CHECK_CHANNEL(channel); + talk_base::strcpyn(rtcp_cname, KMaxRTCPCNameLength, + channels_.find(channel)->second->cname_.c_str()); + return 0; + } + WEBRTC_STUB_CONST(GetRemoteRTCPCName, (const int, char*)); + WEBRTC_STUB(SendApplicationDefinedRTCPPacket, (const int, const unsigned char, + unsigned int, const char*, unsigned short)); + WEBRTC_FUNC(SetNACKStatus, (const int channel, const bool enable)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->nack_ = enable; + channels_[channel]->hybrid_nack_fec_ = false; + return 0; + } + WEBRTC_STUB(SetFECStatus, (const int, const bool, const unsigned char, + const unsigned char)); + WEBRTC_FUNC(SetHybridNACKFECStatus, (const int channel, const bool enable, + const unsigned char red_type, const unsigned char fec_type)) { + WEBRTC_CHECK_CHANNEL(channel); + if (red_type == fec_type || + red_type == channels_[channel]->send_codec.plType || + fec_type == channels_[channel]->send_codec.plType) { + return -1; + } + channels_[channel]->nack_ = false; + channels_[channel]->hybrid_nack_fec_ = enable; + return 0; + } + WEBRTC_FUNC(SetKeyFrameRequestMethod, + (const int channel, + const webrtc::ViEKeyFrameRequestMethod method)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->key_frame_request_method_ = method; + return 0; + } + WEBRTC_FUNC(SetSenderBufferingMode, (int channel, int target_delay)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->sender_target_delay_ = target_delay; + return 0; + } + WEBRTC_FUNC(SetReceiverBufferingMode, (int channel, int target_delay)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->receiver_target_delay_ = target_delay; + return 0; + } + // |Send| and |receive| are stored locally in variables that more clearly + // explain what they mean. + WEBRTC_FUNC(SetRembStatus, (int channel, bool send, bool receive)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->remb_contribute_ = receive; + channels_[channel]->remb_bw_partition_ = send; + return 0; + } + WEBRTC_FUNC(SetTMMBRStatus, (const int channel, const bool enable)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->tmmbr_ = enable; + return 0; + } + WEBRTC_FUNC(SetSendTimestampOffsetStatus, (int channel, bool enable, + int id)) { + WEBRTC_CHECK_CHANNEL(channel); + 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 : -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 : -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 : -1; + return 0; + } + WEBRTC_STUB(SetRtcpXrRrtrStatus, (int, bool)); + 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&, + unsigned int&, unsigned int&, unsigned int&, int&)); + WEBRTC_STUB_CONST(GetRTPStatistics, (const int, unsigned int&, unsigned int&, + unsigned int&, unsigned int&)); + WEBRTC_STUB_CONST(GetReceiveChannelRtcpStatistics, (const int, + webrtc::RtcpStatistics&, int&)); + WEBRTC_STUB_CONST(GetSendChannelRtcpStatistics, (const int, + webrtc::RtcpStatistics&, int&)); + WEBRTC_STUB_CONST(GetRtpStatistics, (const int, webrtc::StreamDataCounters&, + webrtc::StreamDataCounters&)); + WEBRTC_FUNC_CONST(GetBandwidthUsage, (const int channel, + unsigned int& total_bitrate, unsigned int& video_bitrate, + unsigned int& fec_bitrate, unsigned int& nack_bitrate)) { + WEBRTC_CHECK_CHANNEL(channel); + std::map::const_iterator it = channels_.find(channel); + if (it->second->send) { + video_bitrate = it->second->send_video_bitrate_; + fec_bitrate = it->second->send_fec_bitrate_; + nack_bitrate = it->second->send_nack_bitrate_; + total_bitrate = video_bitrate + fec_bitrate + nack_bitrate; + } else { + total_bitrate = 0; + video_bitrate = 0; + fec_bitrate = 0; + nack_bitrate = 0; + } + return 0; + } + WEBRTC_FUNC_CONST(GetEstimatedSendBandwidth, (const int channel, + unsigned int* send_bandwidth_estimate)) { + WEBRTC_CHECK_CHANNEL(channel); + std::map::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; + } + return 0; + } + WEBRTC_FUNC_CONST(GetEstimatedReceiveBandwidth, (const int channel, + unsigned int* receive_bandwidth_estimate)) { + WEBRTC_CHECK_CHANNEL(channel); + std::map::const_iterator it = channels_.find(channel); + if (it->second->receive_) { + it = channels_.find(GetOriginalChannelId(channel)); + *receive_bandwidth_estimate = it->second->receive_bandwidth_; + } else { + *receive_bandwidth_estimate = 0; + } + return 0; + } + WEBRTC_STUB(RegisterSendChannelRtcpStatisticsCallback, + (int, webrtc::RtcpStatisticsCallback*)); + WEBRTC_STUB(DeregisterSendChannelRtcpStatisticsCallback, + (int, webrtc::RtcpStatisticsCallback*)); + WEBRTC_STUB(RegisterReceiveChannelRtcpStatisticsCallback, + (int, webrtc::RtcpStatisticsCallback*)); + WEBRTC_STUB(DeregisterReceiveChannelRtcpStatisticsCallback, + (int, webrtc::RtcpStatisticsCallback*)); + WEBRTC_STUB(RegisterSendChannelRtpStatisticsCallback, + (int, webrtc::StreamDataCountersCallback*)); + WEBRTC_STUB(DeregisterSendChannelRtpStatisticsCallback, + (int, webrtc::StreamDataCountersCallback*)); + WEBRTC_STUB(RegisterReceiveChannelRtpStatisticsCallback, + (int, webrtc::StreamDataCountersCallback*)); + WEBRTC_STUB(DeregisterReceiveChannelRtpStatisticsCallback, + (int, webrtc::StreamDataCountersCallback*)); + WEBRTC_STUB(RegisterSendBitrateObserver, + (int, webrtc::BitrateStatisticsObserver*)); + WEBRTC_STUB(DeregisterSendBitrateObserver, + (int, webrtc::BitrateStatisticsObserver*)); + WEBRTC_STUB(RegisterSendFrameCountObserver, + (int, webrtc::FrameCountObserver*)); + WEBRTC_STUB(DeregisterSendFrameCountObserver, + (int, webrtc::FrameCountObserver*)); + + WEBRTC_STUB(StartRTPDump, (const int, const char*, webrtc::RTPDirections)); + WEBRTC_STUB(StopRTPDump, (const int, webrtc::RTPDirections)); + WEBRTC_STUB(RegisterRTPObserver, (const int, webrtc::ViERTPObserver&)); + WEBRTC_STUB(DeregisterRTPObserver, (const int)); + WEBRTC_STUB(RegisterRTCPObserver, (const int, webrtc::ViERTCPObserver&)); + WEBRTC_STUB(DeregisterRTCPObserver, (const int)); + + // webrtc::ViEImageProcess + WEBRTC_STUB(RegisterCaptureEffectFilter, (const int, + webrtc::ViEEffectFilter&)); + WEBRTC_STUB(DeregisterCaptureEffectFilter, (const int)); + WEBRTC_STUB(RegisterSendEffectFilter, (const int, + webrtc::ViEEffectFilter&)); + WEBRTC_STUB(DeregisterSendEffectFilter, (const int)); + WEBRTC_STUB(RegisterRenderEffectFilter, (const int, + webrtc::ViEEffectFilter&)); + WEBRTC_STUB(DeregisterRenderEffectFilter, (const int)); + WEBRTC_STUB(EnableDeflickering, (const int, const bool)); + WEBRTC_FUNC(EnableDenoising, (const int capture_id, const bool denoising)) { + WEBRTC_CHECK_CAPTURER(capture_id); + capturers_[capture_id]->set_denoising(denoising); + return 0; + } + WEBRTC_STUB(EnableColorEnhancement, (const int, const bool)); + WEBRTC_VOID_STUB(RegisterPreEncodeCallback, + (int, webrtc::I420FrameCallback*)); + WEBRTC_VOID_STUB(DeRegisterPreEncodeCallback, (int)); + WEBRTC_VOID_STUB(RegisterPreRenderCallback, + (int, webrtc::I420FrameCallback*)); + WEBRTC_VOID_STUB(DeRegisterPreRenderCallback, (int)); + // webrtc::ViEExternalCodec + WEBRTC_FUNC(RegisterExternalSendCodec, + (const int channel, const unsigned char pl_type, webrtc::VideoEncoder*, + bool)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->ext_encoder_pl_types_.insert(pl_type); + return 0; + } + WEBRTC_FUNC(DeRegisterExternalSendCodec, + (const int channel, const unsigned char pl_type)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->ext_encoder_pl_types_.erase(pl_type); + return 0; + } + WEBRTC_FUNC(RegisterExternalReceiveCodec, + (const int channel, const unsigned int pl_type, webrtc::VideoDecoder*, + bool, int)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->ext_decoder_pl_types_.insert(pl_type); + return 0; + } + WEBRTC_FUNC(DeRegisterExternalReceiveCodec, + (const int channel, const unsigned char pl_type)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->ext_decoder_pl_types_.erase(pl_type); + return 0; + } + + private: + bool IsChannelId(int id) const { + return (id >= kViEChannelIdBase && id <= kViEChannelIdMax); + } + bool IsCapturerId(int id) const { + return (id >= kViECaptureIdBase && id <= kViECaptureIdMax); + } + + bool inited_; + int last_channel_; + std::map channels_; + bool fail_create_channel_; + int last_capturer_; + std::map capturers_; + bool fail_alloc_capturer_; + const cricket::VideoCodec* const* codecs_; + int num_codecs_; + int num_set_send_codecs_; // how many times we call SetSendCodec(). +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTC_FAKEWEBRTCVIDEOENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvoiceengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvoiceengine.h new file mode 100644 index 0000000..11151bb --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/fakewebrtcvoiceengine.h @@ -0,0 +1,1152 @@ +/* + * 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. + */ + +#ifndef TALK_SESSION_PHONE_FAKEWEBRTCVOICEENGINE_H_ +#define TALK_SESSION_PHONE_FAKEWEBRTCVOICEENGINE_H_ + +#include +#include +#include + +#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/voiceprocessor.h" +#include "talk/media/webrtc/fakewebrtccommon.h" +#include "talk/media/webrtc/webrtcvoe.h" + +namespace webrtc { +class ViENetwork; +} + +namespace cricket { + +// Function returning stats will return these values +// for all values based on type. +const int kIntStatValue = 123; +const float kFractionLostStatValue = 0.5; + +static const char kFakeDefaultDeviceName[] = "Fake Default"; +static const int kFakeDefaultDeviceId = -1; +static const char kFakeDeviceName[] = "Fake Device"; +#ifdef WIN32 +static const int kFakeDeviceId = 0; +#else +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, + public webrtc::VoEBase, public webrtc::VoECodec, public webrtc::VoEDtmf, + public webrtc::VoEFile, public webrtc::VoEHardware, + public webrtc::VoEExternalMedia, public webrtc::VoENetEqStats, + public webrtc::VoENetwork, public webrtc::VoERTP_RTCP, + public webrtc::VoEVideoSync, public webrtc::VoEVolumeControl { + public: + struct DtmfInfo { + DtmfInfo() + : dtmf_event_code(-1), + dtmf_out_of_band(false), + dtmf_length_ms(-1) {} + int dtmf_event_code; + bool dtmf_out_of_band; + int dtmf_length_ms; + }; + struct Channel { + explicit Channel() + : external_transport(false), + send(false), + playout(false), + volume_scale(1.0), + volume_pan_left(1.0), + volume_pan_right(1.0), + file(false), + vad(false), + fec(false), + nack(false), + media_processor_registered(false), + rx_agc_enabled(false), + rx_agc_mode(webrtc::kAgcDefault), + cn8_type(13), + cn16_type(105), + dtmf_type(106), + fec_type(117), + nack_max_packets(0), + vie_network(NULL), + video_channel(-1), + send_ssrc(0), + 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)); + } + bool external_transport; + bool send; + bool playout; + float volume_scale; + float volume_pan_left; + float volume_pan_right; + bool file; + bool vad; + bool fec; + bool nack; + bool media_processor_registered; + bool rx_agc_enabled; + webrtc::AgcModes rx_agc_mode; + webrtc::AgcConfig rx_agc_config; + int cn8_type; + int cn16_type; + int dtmf_type; + int fec_type; + int nack_max_packets; + webrtc::ViENetwork* vie_network; + int video_channel; + uint32 send_ssrc; + 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 recv_codecs; + webrtc::CodecInst send_codec; + webrtc::PacketTime last_rtp_packet_time; + std::list packets; + }; + + FakeWebRtcVoiceEngine(const cricket::AudioCodec* const* codecs, + int num_codecs) + : inited_(false), + last_channel_(-1), + 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), + ns_enabled_(false), + agc_enabled_(false), + highpass_filter_enabled_(false), + stereo_swapping_enabled_(false), + typing_detection_enabled_(false), + ec_mode_(webrtc::kEcDefault), + aecm_mode_(webrtc::kAecmSpeakerphone), + ns_mode_(webrtc::kNsDefault), + agc_mode_(webrtc::kAgcDefault), + observer_(NULL), + playout_fail_channel_(-1), + send_fail_channel_(-1), + fail_start_recording_microphone_(false), + recording_microphone_(false), + recording_sample_rate_(-1), + playout_sample_rate_(-1), + media_processor_(NULL) { + memset(&agc_config_, 0, sizeof(agc_config_)); + } + ~FakeWebRtcVoiceEngine() { + // Ought to have all been deleted by the WebRtcVoiceMediaChannel + // destructors, but just in case ... + for (std::map::const_iterator i = channels_.begin(); + i != channels_.end(); ++i) { + delete i->second; + } + } + + bool IsExternalMediaProcessorRegistered() const { + return media_processor_ != NULL; + } + bool IsInited() const { return inited_; } + int GetLastChannel() const { return last_channel_; } + int GetChannelFromLocalSsrc(uint32 local_ssrc) const { + for (std::map::const_iterator iter = channels_.begin(); + iter != channels_.end(); ++iter) { + if (local_ssrc == iter->second->send_ssrc) + return iter->first; + } + return -1; + } + int GetNumChannels() const { return static_cast(channels_.size()); } + bool GetPlayout(int channel) { + return channels_[channel]->playout; + } + bool GetSend(int channel) { + return channels_[channel]->send; + } + bool GetRecordingMicrophone() { + return recording_microphone_; + } + bool GetVAD(int channel) { + return channels_[channel]->vad; + } + bool GetFEC(int channel) { + return channels_[channel]->fec; + } + bool GetNACK(int channel) { + return channels_[channel]->nack; + } + int GetNACKMaxPackets(int channel) { + return channels_[channel]->nack_max_packets; + } + 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]->last_rtp_packet_time; + } + int GetSendCNPayloadType(int channel, bool wideband) { + return (wideband) ? + channels_[channel]->cn16_type : + channels_[channel]->cn8_type; + } + int GetSendTelephoneEventPayloadType(int channel) { + return channels_[channel]->dtmf_type; + } + int GetSendFECPayloadType(int channel) { + return channels_[channel]->fec_type; + } + bool CheckPacket(int channel, const void* data, size_t len) { + bool result = !CheckNoPacket(channel); + if (result) { + std::string packet = channels_[channel]->packets.front(); + result = (packet == std::string(static_cast(data), len)); + channels_[channel]->packets.pop_front(); + } + return result; + } + bool CheckNoPacket(int channel) { + return channels_[channel]->packets.empty(); + } + void TriggerCallbackOnError(int channel_num, int err_code) { + ASSERT(observer_ != NULL); + observer_->CallbackOnError(channel_num, err_code); + } + void set_playout_fail_channel(int channel) { + playout_fail_channel_ = channel; + } + void set_send_fail_channel(int channel) { + send_fail_channel_ = channel; + } + void set_fail_start_recording_microphone( + bool fail_start_recording_microphone) { + fail_start_recording_microphone_ = fail_start_recording_microphone; + } + void set_fail_create_channel(bool fail_create_channel) { + fail_create_channel_ = fail_create_channel; + } + void TriggerProcessPacket(MediaProcessorDirection direction) { + webrtc::ProcessingTypes pt = + (direction == cricket::MPD_TX) ? + webrtc::kRecordingPerChannel : webrtc::kPlaybackAllChannelsMixed; + if (media_processor_ != NULL) { + media_processor_->Process(0, + pt, + NULL, + 0, + 0, + true); + } + } + int AddChannel() { + if (fail_create_channel_) { + return -1; + } + Channel* ch = new Channel(); + for (int i = 0; i < NumOfCodecs(); ++i) { + webrtc::CodecInst codec; + GetCodec(i, codec); + ch->recv_codecs.push_back(codec); + } + 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, ()); + + // webrtc::VoEBase + WEBRTC_FUNC(RegisterVoiceEngineObserver, ( + webrtc::VoiceEngineObserver& observer)) { + observer_ = &observer; + return 0; + } + WEBRTC_STUB(DeRegisterVoiceEngineObserver, ()); + WEBRTC_FUNC(Init, (webrtc::AudioDeviceModule* adm, + webrtc::AudioProcessing* audioproc)) { + inited_ = true; + return 0; + } + WEBRTC_FUNC(Terminate, ()) { + inited_ = false; + return 0; + } + virtual webrtc::AudioProcessing* audio_processing() OVERRIDE { + return NULL; + } + WEBRTC_FUNC(CreateChannel, ()) { + return AddChannel(); + } + WEBRTC_FUNC(CreateChannel, (const webrtc::Config& /*config*/)) { + return AddChannel(); + } + WEBRTC_FUNC(DeleteChannel, (int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + delete channels_[channel]; + channels_.erase(channel); + return 0; + } + WEBRTC_STUB(StartReceive, (int channel)); + WEBRTC_FUNC(StartPlayout, (int channel)) { + if (playout_fail_channel_ != channel) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->playout = true; + return 0; + } else { + // When playout_fail_channel_ == channel, fail the StartPlayout on this + // channel. + return -1; + } + } + WEBRTC_FUNC(StartSend, (int channel)) { + if (send_fail_channel_ != channel) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->send = true; + return 0; + } else { + // When send_fail_channel_ == channel, fail the StartSend on this + // channel. + return -1; + } + } + WEBRTC_STUB(StopReceive, (int channel)); + WEBRTC_FUNC(StopPlayout, (int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->playout = false; + return 0; + } + WEBRTC_FUNC(StopSend, (int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->send = false; + return 0; + } + WEBRTC_STUB(GetVersion, (char version[1024])); + WEBRTC_STUB(LastError, ()); + WEBRTC_STUB(SetOnHoldStatus, (int, bool, webrtc::OnHoldModes)); + WEBRTC_STUB(GetOnHoldStatus, (int, bool&, webrtc::OnHoldModes&)); + WEBRTC_STUB(SetNetEQPlayoutMode, (int, webrtc::NetEqModes)); + WEBRTC_STUB(GetNetEQPlayoutMode, (int, webrtc::NetEqModes&)); + + // webrtc::VoECodec + WEBRTC_FUNC(NumOfCodecs, ()) { + return num_codecs_; + } + WEBRTC_FUNC(GetCodec, (int index, webrtc::CodecInst& codec)) { + if (index < 0 || index >= NumOfCodecs()) { + return -1; + } + const cricket::AudioCodec& c(*codecs_[index]); + codec.pltype = c.id; + talk_base::strcpyn(codec.plname, sizeof(codec.plname), c.name.c_str()); + codec.plfreq = c.clockrate; + codec.pacsize = 0; + codec.channels = c.channels; + codec.rate = c.bitrate; + return 0; + } + 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)) { + WEBRTC_CHECK_CHANNEL(channel); + codec = channels_[channel]->send_codec; + return 0; + } + WEBRTC_STUB(SetSecondarySendCodec, (int channel, + const webrtc::CodecInst& codec, + int red_payload_type)); + WEBRTC_STUB(RemoveSecondarySendCodec, (int channel)); + WEBRTC_STUB(GetSecondarySendCodec, (int channel, + webrtc::CodecInst& codec)); + WEBRTC_STUB(GetRecCodec, (int channel, webrtc::CodecInst& codec)); + WEBRTC_STUB(SetAMREncFormat, (int channel, webrtc::AmrMode mode)); + WEBRTC_STUB(SetAMRDecFormat, (int channel, webrtc::AmrMode mode)); + WEBRTC_STUB(SetAMRWbEncFormat, (int channel, webrtc::AmrMode mode)); + WEBRTC_STUB(SetAMRWbDecFormat, (int channel, webrtc::AmrMode mode)); + WEBRTC_STUB(SetISACInitTargetRate, (int channel, int rateBps, + bool useFixedFrameSize)); + WEBRTC_STUB(SetISACMaxRate, (int channel, int rateBps)); + WEBRTC_STUB(SetISACMaxPayloadSize, (int channel, int sizeBytes)); + WEBRTC_FUNC(SetRecPayloadType, (int channel, + const webrtc::CodecInst& codec)) { + WEBRTC_CHECK_CHANNEL(channel); + Channel* ch = channels_[channel]; + if (ch->playout) + return -1; // Channel is in use. + // Check if something else already has this slot. + if (codec.pltype != -1) { + for (std::vector::iterator it = + ch->recv_codecs.begin(); it != ch->recv_codecs.end(); ++it) { + if (it->pltype == codec.pltype && + _stricmp(it->plname, codec.plname) != 0) { + return -1; + } + } + } + // Otherwise try to find this codec and update its payload type. + for (std::vector::iterator it = ch->recv_codecs.begin(); + it != ch->recv_codecs.end(); ++it) { + if (strcmp(it->plname, codec.plname) == 0 && + it->plfreq == codec.plfreq) { + it->pltype = codec.pltype; + it->channels = codec.channels; + return 0; + } + } + return -1; // not found + } + WEBRTC_FUNC(SetSendCNPayloadType, (int channel, int type, + webrtc::PayloadFrequencies frequency)) { + WEBRTC_CHECK_CHANNEL(channel); + if (frequency == webrtc::kFreq8000Hz) { + channels_[channel]->cn8_type = type; + } else if (frequency == webrtc::kFreq16000Hz) { + channels_[channel]->cn16_type = type; + } + return 0; + } + WEBRTC_FUNC(GetRecPayloadType, (int channel, webrtc::CodecInst& codec)) { + WEBRTC_CHECK_CHANNEL(channel); + Channel* ch = channels_[channel]; + for (std::vector::iterator it = ch->recv_codecs.begin(); + it != ch->recv_codecs.end(); ++it) { + if (strcmp(it->plname, codec.plname) == 0 && + it->plfreq == codec.plfreq && + it->channels == codec.channels && + it->pltype != -1) { + codec.pltype = it->pltype; + return 0; + } + } + return -1; // not found + } + WEBRTC_FUNC(SetVADStatus, (int channel, bool enable, webrtc::VadModes mode, + bool disableDTX)) { + WEBRTC_CHECK_CHANNEL(channel); + if (channels_[channel]->send_codec.channels == 2) { + // Replicating VoE behavior; VAD cannot be enabled for stereo. + return -1; + } + channels_[channel]->vad = enable; + return 0; + } + WEBRTC_STUB(GetVADStatus, (int channel, bool& enabled, + webrtc::VadModes& mode, bool& disabledDTX)); + + // webrtc::VoEDtmf + WEBRTC_FUNC(SendTelephoneEvent, (int channel, int event_code, + bool out_of_band = true, int length_ms = 160, int attenuation_db = 10)) { + channels_[channel]->dtmf_info.dtmf_event_code = event_code; + channels_[channel]->dtmf_info.dtmf_out_of_band = out_of_band; + channels_[channel]->dtmf_info.dtmf_length_ms = length_ms; + return 0; + } + + WEBRTC_FUNC(SetSendTelephoneEventPayloadType, + (int channel, unsigned char type)) { + channels_[channel]->dtmf_type = type; + return 0; + }; + WEBRTC_STUB(GetSendTelephoneEventPayloadType, + (int channel, unsigned char& type)); + + WEBRTC_STUB(SetDtmfFeedbackStatus, (bool enable, bool directFeedback)); + WEBRTC_STUB(GetDtmfFeedbackStatus, (bool& enabled, bool& directFeedback)); + 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; + dtmf_info_.dtmf_length_ms = length_ms; + return 0; + } + WEBRTC_STUB(StartPlayingDtmfTone, + (int eventCode, int attenuationDb = 10)); + WEBRTC_STUB(StopPlayingDtmfTone, ()); + + // webrtc::VoEFile + WEBRTC_FUNC(StartPlayingFileLocally, (int channel, const char* fileNameUTF8, + bool loop, webrtc::FileFormats format, + float volumeScaling, int startPointMs, + int stopPointMs)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->file = true; + return 0; + } + WEBRTC_FUNC(StartPlayingFileLocally, (int channel, webrtc::InStream* stream, + webrtc::FileFormats format, + float volumeScaling, int startPointMs, + int stopPointMs)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->file = true; + return 0; + } + WEBRTC_FUNC(StopPlayingFileLocally, (int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->file = false; + return 0; + } + WEBRTC_FUNC(IsPlayingFileLocally, (int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + return (channels_[channel]->file) ? 1 : 0; + } + WEBRTC_STUB(ScaleLocalFilePlayout, (int channel, float scale)); + WEBRTC_STUB(StartPlayingFileAsMicrophone, (int channel, + const char* fileNameUTF8, + bool loop, + bool mixWithMicrophone, + webrtc::FileFormats format, + float volumeScaling)); + WEBRTC_STUB(StartPlayingFileAsMicrophone, (int channel, + webrtc::InStream* stream, + bool mixWithMicrophone, + webrtc::FileFormats format, + float volumeScaling)); + WEBRTC_STUB(StopPlayingFileAsMicrophone, (int channel)); + WEBRTC_STUB(IsPlayingFileAsMicrophone, (int channel)); + WEBRTC_STUB(ScaleFileAsMicrophonePlayout, (int channel, float scale)); + WEBRTC_STUB(StartRecordingPlayout, (int channel, const char* fileNameUTF8, + webrtc::CodecInst* compression, + int maxSizeBytes)); + WEBRTC_STUB(StartRecordingPlayout, (int channel, webrtc::OutStream* stream, + webrtc::CodecInst* compression)); + WEBRTC_STUB(StopRecordingPlayout, (int channel)); + WEBRTC_FUNC(StartRecordingMicrophone, (const char* fileNameUTF8, + webrtc::CodecInst* compression, + int maxSizeBytes)) { + if (fail_start_recording_microphone_) { + return -1; + } + recording_microphone_ = true; + return 0; + } + WEBRTC_FUNC(StartRecordingMicrophone, (webrtc::OutStream* stream, + webrtc::CodecInst* compression)) { + if (fail_start_recording_microphone_) { + return -1; + } + recording_microphone_ = true; + return 0; + } + WEBRTC_FUNC(StopRecordingMicrophone, ()) { + if (!recording_microphone_) { + return -1; + } + recording_microphone_ = false; + return 0; + } + WEBRTC_STUB(ConvertPCMToWAV, (const char* fileNameInUTF8, + const char* fileNameOutUTF8)); + WEBRTC_STUB(ConvertPCMToWAV, (webrtc::InStream* streamIn, + webrtc::OutStream* streamOut)); + WEBRTC_STUB(ConvertWAVToPCM, (const char* fileNameInUTF8, + const char* fileNameOutUTF8)); + WEBRTC_STUB(ConvertWAVToPCM, (webrtc::InStream* streamIn, + webrtc::OutStream* streamOut)); + WEBRTC_STUB(ConvertPCMToCompressed, (const char* fileNameInUTF8, + const char* fileNameOutUTF8, + webrtc::CodecInst* compression)); + WEBRTC_STUB(ConvertPCMToCompressed, (webrtc::InStream* streamIn, + webrtc::OutStream* streamOut, + webrtc::CodecInst* compression)); + WEBRTC_STUB(ConvertCompressedToPCM, (const char* fileNameInUTF8, + const char* fileNameOutUTF8)); + WEBRTC_STUB(ConvertCompressedToPCM, (webrtc::InStream* streamIn, + webrtc::OutStream* streamOut)); + WEBRTC_STUB(GetFileDuration, (const char* fileNameUTF8, int& durationMs, + webrtc::FileFormats format)); + WEBRTC_STUB(GetPlaybackPosition, (int channel, int& positionMs)); + + // webrtc::VoEHardware + WEBRTC_STUB(GetCPULoad, (int&)); + WEBRTC_FUNC(GetNumOfRecordingDevices, (int& num)) { + return GetNumDevices(num); + } + WEBRTC_FUNC(GetNumOfPlayoutDevices, (int& num)) { + return GetNumDevices(num); + } + WEBRTC_FUNC(GetRecordingDeviceName, (int i, char* name, char* guid)) { + return GetDeviceName(i, name, guid); + } + WEBRTC_FUNC(GetPlayoutDeviceName, (int i, char* name, char* guid)) { + return GetDeviceName(i, name, guid); + } + WEBRTC_STUB(SetRecordingDevice, (int, webrtc::StereoChannel)); + WEBRTC_STUB(SetPlayoutDevice, (int)); + WEBRTC_STUB(SetAudioDeviceLayer, (webrtc::AudioLayers)); + WEBRTC_STUB(GetAudioDeviceLayer, (webrtc::AudioLayers&)); + WEBRTC_STUB(GetPlayoutDeviceStatus, (bool&)); + WEBRTC_STUB(GetRecordingDeviceStatus, (bool&)); + WEBRTC_STUB(ResetAudioDevice, ()); + WEBRTC_STUB(AudioDeviceControl, (unsigned int, unsigned int, unsigned int)); + WEBRTC_STUB(SetLoudspeakerStatus, (bool enable)); + WEBRTC_STUB(GetLoudspeakerStatus, (bool& enabled)); + WEBRTC_FUNC(SetRecordingSampleRate, (unsigned int samples_per_sec)) { + recording_sample_rate_ = samples_per_sec; + return 0; + } + WEBRTC_FUNC_CONST(RecordingSampleRate, (unsigned int* samples_per_sec)) { + *samples_per_sec = recording_sample_rate_; + return 0; + } + WEBRTC_FUNC(SetPlayoutSampleRate, (unsigned int samples_per_sec)) { + playout_sample_rate_ = samples_per_sec; + return 0; + } + WEBRTC_FUNC_CONST(PlayoutSampleRate, (unsigned int* samples_per_sec)) { + *samples_per_sec = playout_sample_rate_; + return 0; + } + WEBRTC_STUB(EnableBuiltInAEC, (bool enable)); + virtual bool BuiltInAECIsEnabled() const { return true; } + + // webrtc::VoENetEqStats + WEBRTC_STUB(GetNetworkStatistics, (int, webrtc::NetworkStatistics&)); + WEBRTC_FUNC_CONST(GetDecodingCallStatistics, (int channel, + webrtc::AudioDecodingCallStats*)) { + WEBRTC_CHECK_CHANNEL(channel); + return 0; + } + + // webrtc::VoENetwork + WEBRTC_FUNC(RegisterExternalTransport, (int channel, + webrtc::Transport& transport)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->external_transport = true; + return 0; + } + WEBRTC_FUNC(DeRegisterExternalTransport, (int channel)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->external_transport = false; + return 0; + } + WEBRTC_FUNC(ReceivedRTPPacket, (int channel, const void* data, + unsigned int length)) { + WEBRTC_CHECK_CHANNEL(channel); + if (!channels_[channel]->external_transport) return -1; + channels_[channel]->packets.push_back( + std::string(static_cast(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)); + + // webrtc::VoERTP_RTCP + WEBRTC_STUB(RegisterRTPObserver, (int channel, + webrtc::VoERTPObserver& observer)); + WEBRTC_STUB(DeRegisterRTPObserver, (int channel)); + WEBRTC_STUB(RegisterRTCPObserver, (int channel, + webrtc::VoERTCPObserver& observer)); + WEBRTC_STUB(DeRegisterRTCPObserver, (int channel)); + WEBRTC_FUNC(SetLocalSSRC, (int channel, unsigned int ssrc)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->send_ssrc = ssrc; + return 0; + } + WEBRTC_FUNC(GetLocalSSRC, (int channel, unsigned int& ssrc)) { + WEBRTC_CHECK_CHANNEL(channel); + ssrc = channels_[channel]->send_ssrc; + return 0; + } + WEBRTC_STUB(GetRemoteSSRC, (int channel, unsigned int& ssrc)); + WEBRTC_FUNC(SetSendAudioLevelIndicationStatus, (int channel, bool enable, + unsigned char id)) { + WEBRTC_CHECK_CHANNEL(channel); + 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(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable, + unsigned char id)) { + WEBRTC_CHECK_CHANNEL(channel); + 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)); + WEBRTC_STUB(SetRTCP_CNAME, (int channel, const char cname[256])); + WEBRTC_STUB(GetRTCP_CNAME, (int channel, char cname[256])); + WEBRTC_STUB(GetRemoteRTCP_CNAME, (int channel, char* cname)); + WEBRTC_STUB(GetRemoteRTCPData, (int channel, unsigned int& NTPHigh, + unsigned int& NTPLow, + unsigned int& timestamp, + unsigned int& playoutTimestamp, + unsigned int* jitter, + unsigned short* fractionLost)); + WEBRTC_STUB(GetRemoteRTCPSenderInfo, (int channel, + webrtc::SenderInfo* sender_info)); + WEBRTC_FUNC(GetRemoteRTCPReportBlocks, + (int channel, std::vector* receive_blocks)) { + WEBRTC_CHECK_CHANNEL(channel); + webrtc::ReportBlock block; + block.source_SSRC = channels_[channel]->send_ssrc; + webrtc::CodecInst send_codec = channels_[channel]->send_codec; + if (send_codec.pltype >= 0) { + block.fraction_lost = (unsigned char)(kFractionLostStatValue * 256); + if (send_codec.plfreq / 1000 > 0) { + block.interarrival_jitter = kIntStatValue * (send_codec.plfreq / 1000); + } + block.cumulative_num_packets_lost = kIntStatValue; + block.extended_highest_sequence_number = kIntStatValue; + receive_blocks->push_back(block); + } + return 0; + } + WEBRTC_STUB(SendApplicationDefinedRTCPPacket, (int channel, + unsigned char subType, + unsigned int name, + const char* data, + unsigned short dataLength)); + WEBRTC_STUB(GetRTPStatistics, (int channel, unsigned int& averageJitterMs, + unsigned int& maxJitterMs, + unsigned int& discardedPackets)); + WEBRTC_FUNC(GetRTCPStatistics, (int channel, webrtc::CallStatistics& stats)) { + WEBRTC_CHECK_CHANNEL(channel); + stats.fractionLost = static_cast(kIntStatValue); + stats.cumulativeLost = kIntStatValue; + stats.extendedMax = kIntStatValue; + stats.jitterSamples = kIntStatValue; + stats.rttMs = kIntStatValue; + stats.bytesSent = kIntStatValue; + stats.packetsSent = kIntStatValue; + stats.bytesReceived = kIntStatValue; + stats.packetsReceived = kIntStatValue; + return 0; + } + WEBRTC_FUNC(SetFECStatus, (int channel, bool enable, int redPayloadtype)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->fec = enable; + channels_[channel]->fec_type = redPayloadtype; + return 0; + } + WEBRTC_FUNC(GetFECStatus, (int channel, bool& enable, int& redPayloadtype)) { + WEBRTC_CHECK_CHANNEL(channel); + enable = channels_[channel]->fec; + redPayloadtype = channels_[channel]->fec_type; + return 0; + } + WEBRTC_FUNC(SetNACKStatus, (int channel, bool enable, int maxNoPackets)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->nack = enable; + channels_[channel]->nack_max_packets = maxNoPackets; + return 0; + } + WEBRTC_STUB(StartRTPDump, (int channel, const char* fileNameUTF8, + webrtc::RTPDirections direction)); + WEBRTC_STUB(StopRTPDump, (int channel, webrtc::RTPDirections direction)); + WEBRTC_STUB(RTPDumpIsActive, (int channel, webrtc::RTPDirections direction)); + WEBRTC_STUB(InsertExtraRTPPacket, (int channel, unsigned char payloadType, + bool markerBit, const char* payloadData, + 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)); + WEBRTC_STUB(GetPlayoutTimestamp, (int channel, unsigned int& timestamp)); + WEBRTC_STUB(GetRtpRtcp, (int, webrtc::RtpRtcp**, webrtc::RtpReceiver**)); + WEBRTC_STUB(SetInitTimestamp, (int channel, unsigned int timestamp)); + WEBRTC_STUB(SetInitSequenceNumber, (int channel, short sequenceNumber)); + WEBRTC_STUB(SetMinimumPlayoutDelay, (int channel, int delayMs)); + WEBRTC_STUB(SetInitialPlayoutDelay, (int channel, int delay_ms)); + WEBRTC_STUB(GetDelayEstimate, (int channel, int* jitter_buffer_delay_ms, + int* playout_buffer_delay_ms)); + WEBRTC_STUB_CONST(GetLeastRequiredDelayMs, (int channel)); + + // webrtc::VoEVolumeControl + WEBRTC_STUB(SetSpeakerVolume, (unsigned int)); + WEBRTC_STUB(GetSpeakerVolume, (unsigned int&)); + WEBRTC_STUB(SetSystemOutputMute, (bool)); + WEBRTC_STUB(GetSystemOutputMute, (bool&)); + WEBRTC_STUB(SetMicVolume, (unsigned int)); + WEBRTC_STUB(GetMicVolume, (unsigned int&)); + WEBRTC_STUB(SetInputMute, (int, bool)); + WEBRTC_STUB(GetInputMute, (int, bool&)); + WEBRTC_STUB(SetSystemInputMute, (bool)); + WEBRTC_STUB(GetSystemInputMute, (bool&)); + WEBRTC_STUB(GetSpeechInputLevel, (unsigned int&)); + WEBRTC_STUB(GetSpeechOutputLevel, (int, unsigned int&)); + WEBRTC_STUB(GetSpeechInputLevelFullRange, (unsigned int&)); + WEBRTC_STUB(GetSpeechOutputLevelFullRange, (int, unsigned int&)); + WEBRTC_FUNC(SetChannelOutputVolumeScaling, (int channel, float scale)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->volume_scale= scale; + return 0; + } + WEBRTC_FUNC(GetChannelOutputVolumeScaling, (int channel, float& scale)) { + WEBRTC_CHECK_CHANNEL(channel); + scale = channels_[channel]->volume_scale; + return 0; + } + WEBRTC_FUNC(SetOutputVolumePan, (int channel, float left, float right)) { + WEBRTC_CHECK_CHANNEL(channel); + channels_[channel]->volume_pan_left = left; + channels_[channel]->volume_pan_right = right; + return 0; + } + WEBRTC_FUNC(GetOutputVolumePan, (int channel, float& left, float& right)) { + WEBRTC_CHECK_CHANNEL(channel); + left = channels_[channel]->volume_pan_left; + right = channels_[channel]->volume_pan_right; + return 0; + } + + // webrtc::VoEAudioProcessing + WEBRTC_FUNC(SetNsStatus, (bool enable, webrtc::NsModes mode)) { + ns_enabled_ = enable; + ns_mode_ = mode; + return 0; + } + WEBRTC_FUNC(GetNsStatus, (bool& enabled, webrtc::NsModes& mode)) { + enabled = ns_enabled_; + mode = ns_mode_; + return 0; + } + + WEBRTC_FUNC(SetAgcStatus, (bool enable, webrtc::AgcModes mode)) { + agc_enabled_ = enable; + agc_mode_ = mode; + return 0; + } + WEBRTC_FUNC(GetAgcStatus, (bool& enabled, webrtc::AgcModes& mode)) { + enabled = agc_enabled_; + mode = agc_mode_; + return 0; + } + + WEBRTC_FUNC(SetAgcConfig, (webrtc::AgcConfig config)) { + agc_config_ = config; + return 0; + } + WEBRTC_FUNC(GetAgcConfig, (webrtc::AgcConfig& config)) { + config = agc_config_; + return 0; + } + WEBRTC_FUNC(SetEcStatus, (bool enable, webrtc::EcModes mode)) { + ec_enabled_ = enable; + ec_mode_ = mode; + return 0; + } + WEBRTC_FUNC(GetEcStatus, (bool& enabled, webrtc::EcModes& mode)) { + enabled = ec_enabled_; + mode = ec_mode_; + return 0; + } + WEBRTC_STUB(EnableDriftCompensation, (bool enable)) + WEBRTC_BOOL_STUB(DriftCompensationEnabled, ()) + WEBRTC_VOID_STUB(SetDelayOffsetMs, (int offset)) + WEBRTC_STUB(DelayOffsetMs, ()); + WEBRTC_FUNC(SetAecmMode, (webrtc::AecmModes mode, bool enableCNG)) { + aecm_mode_ = mode; + cng_enabled_ = enableCNG; + return 0; + } + WEBRTC_FUNC(GetAecmMode, (webrtc::AecmModes& mode, bool& enabledCNG)) { + mode = aecm_mode_; + enabledCNG = cng_enabled_; + return 0; + } + WEBRTC_STUB(SetRxNsStatus, (int channel, bool enable, webrtc::NsModes mode)); + WEBRTC_STUB(GetRxNsStatus, (int channel, bool& enabled, + webrtc::NsModes& mode)); + WEBRTC_FUNC(SetRxAgcStatus, (int channel, bool enable, + webrtc::AgcModes mode)) { + channels_[channel]->rx_agc_enabled = enable; + channels_[channel]->rx_agc_mode = mode; + return 0; + } + WEBRTC_FUNC(GetRxAgcStatus, (int channel, bool& enabled, + webrtc::AgcModes& mode)) { + enabled = channels_[channel]->rx_agc_enabled; + mode = channels_[channel]->rx_agc_mode; + return 0; + } + + WEBRTC_FUNC(SetRxAgcConfig, (int channel, webrtc::AgcConfig config)) { + channels_[channel]->rx_agc_config = config; + return 0; + } + WEBRTC_FUNC(GetRxAgcConfig, (int channel, webrtc::AgcConfig& config)) { + config = channels_[channel]->rx_agc_config; + return 0; + } + + WEBRTC_STUB(RegisterRxVadObserver, (int, webrtc::VoERxVadCallback&)); + WEBRTC_STUB(DeRegisterRxVadObserver, (int channel)); + WEBRTC_STUB(VoiceActivityIndicator, (int channel)); + WEBRTC_FUNC(SetEcMetricsStatus, (bool enable)) { + ec_metrics_enabled_ = enable; + return 0; + } + WEBRTC_FUNC(GetEcMetricsStatus, (bool& enabled)) { + enabled = ec_metrics_enabled_; + return 0; + } + WEBRTC_STUB(GetEchoMetrics, (int& ERL, int& ERLE, int& RERL, int& A_NLP)); + WEBRTC_STUB(GetEcDelayMetrics, (int& delay_median, int& delay_std)); + + WEBRTC_STUB(StartDebugRecording, (const char* fileNameUTF8)); + WEBRTC_STUB(StartDebugRecording, (FILE* handle)); + WEBRTC_STUB(StopDebugRecording, ()); + + WEBRTC_FUNC(SetTypingDetectionStatus, (bool enable)) { + typing_detection_enabled_ = enable; + return 0; + } + WEBRTC_FUNC(GetTypingDetectionStatus, (bool& enabled)) { + enabled = typing_detection_enabled_; + return 0; + } + + WEBRTC_STUB(TimeSinceLastTyping, (int& seconds)); + WEBRTC_STUB(SetTypingDetectionParameters, (int timeWindow, + int costPerTyping, + int reportingThreshold, + int penaltyDecay, + int typeEventDelay)); + int EnableHighPassFilter(bool enable) { + highpass_filter_enabled_ = enable; + return 0; + } + bool IsHighPassFilterEnabled() { + return highpass_filter_enabled_; + } + bool IsStereoChannelSwappingEnabled() { + return stereo_swapping_enabled_; + } + void EnableStereoChannelSwapping(bool enable) { + stereo_swapping_enabled_ = enable; + } + bool WasSendTelephoneEventCalled(int channel, int event_code, int length_ms) { + return (channels_[channel]->dtmf_info.dtmf_event_code == event_code && + channels_[channel]->dtmf_info.dtmf_out_of_band == true && + channels_[channel]->dtmf_info.dtmf_length_ms == length_ms); + } + bool WasPlayDtmfToneCalled(int event_code, int length_ms) { + return (dtmf_info_.dtmf_event_code == event_code && + dtmf_info_.dtmf_length_ms == length_ms); + } + // webrtc::VoEExternalMedia + WEBRTC_FUNC(RegisterExternalMediaProcessing, + (int channel, webrtc::ProcessingTypes type, + webrtc::VoEMediaProcess& processObject)) { + WEBRTC_CHECK_CHANNEL(channel); + if (channels_[channel]->media_processor_registered) { + return -1; + } + channels_[channel]->media_processor_registered = true; + media_processor_ = &processObject; + return 0; + } + WEBRTC_FUNC(DeRegisterExternalMediaProcessing, + (int channel, webrtc::ProcessingTypes type)) { + WEBRTC_CHECK_CHANNEL(channel); + if (!channels_[channel]->media_processor_registered) { + return -1; + } + channels_[channel]->media_processor_registered = false; + media_processor_ = NULL; + return 0; + } + WEBRTC_STUB(SetExternalRecordingStatus, (bool enable)); + WEBRTC_STUB(SetExternalPlayoutStatus, (bool enable)); + WEBRTC_STUB(ExternalRecordingInsertData, + (const int16_t speechData10ms[], int lengthSamples, + int samplingFreqHz, int current_delay_ms)); + WEBRTC_STUB(ExternalPlayoutGetData, + (int16_t speechData10ms[], int samplingFreqHz, + int current_delay_ms, int& lengthSamples)); + WEBRTC_STUB(GetAudioFrame, (int channel, int desired_sample_rate_hz, + webrtc::AudioFrame* frame)); + WEBRTC_STUB(SetExternalMixing, (int channel, bool enable)); + + private: + int GetNumDevices(int& num) { +#ifdef WIN32 + num = 1; +#else + // On non-Windows platforms VE adds a special entry for the default device, + // so if there is one physical device then there are two entries in the + // list. + num = 2; +#endif + return 0; + } + + int GetDeviceName(int i, char* name, char* guid) { + const char *s; +#ifdef WIN32 + if (0 == i) { + s = kFakeDeviceName; + } else { + return -1; + } +#else + // See comment above. + if (0 == i) { + s = kFakeDefaultDeviceName; + } else if (1 == i) { + s = kFakeDeviceName; + } else { + return -1; + } +#endif + strcpy(name, s); + guid[0] = '\0'; + return 0; + } + + bool inited_; + int last_channel_; + std::map channels_; + 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_; + bool ns_enabled_; + bool agc_enabled_; + bool highpass_filter_enabled_; + bool stereo_swapping_enabled_; + bool typing_detection_enabled_; + webrtc::EcModes ec_mode_; + webrtc::AecmModes aecm_mode_; + webrtc::NsModes ns_mode_; + webrtc::AgcModes agc_mode_; + webrtc::AgcConfig agc_config_; + webrtc::VoiceEngineObserver* observer_; + int playout_fail_channel_; + int send_fail_channel_; + bool fail_start_recording_microphone_; + bool recording_microphone_; + int recording_sample_rate_; + int playout_sample_rate_; + DtmfInfo dtmf_info_; + webrtc::VoEMediaProcess* media_processor_; +}; + +#undef WEBRTC_CHECK_HEADER_EXTENSION_ID + +} // namespace cricket + +#endif // TALK_SESSION_PHONE_FAKEWEBRTCVOICEENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtccommon.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtccommon.h new file mode 100644 index 0000000..e7e946f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtccommon.h @@ -0,0 +1,76 @@ +/* + * 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_WEBRTCCOMMON_H_ +#define TALK_MEDIA_WEBRTCCOMMON_H_ + +#include "webrtc/common_types.h" + +namespace cricket { + +// Tracing helpers, for easy logging when WebRTC calls fail. +// Example: "LOG_RTCERR1(StartSend, channel);" produces the trace +// "StartSend(1) failed, err=XXXX" +// The method GetLastEngineError must be defined in the calling scope. +#define LOG_RTCERR0(func) \ + LOG_RTCERR0_EX(func, GetLastEngineError()) +#define LOG_RTCERR1(func, a1) \ + LOG_RTCERR1_EX(func, a1, GetLastEngineError()) +#define LOG_RTCERR2(func, a1, a2) \ + LOG_RTCERR2_EX(func, a1, a2, GetLastEngineError()) +#define LOG_RTCERR3(func, a1, a2, a3) \ + LOG_RTCERR3_EX(func, a1, a2, a3, GetLastEngineError()) +#define LOG_RTCERR4(func, a1, a2, a3, a4) \ + LOG_RTCERR4_EX(func, a1, a2, a3, a4, GetLastEngineError()) +#define LOG_RTCERR5(func, a1, a2, a3, a4, a5) \ + LOG_RTCERR5_EX(func, a1, a2, a3, a4, a5, GetLastEngineError()) +#define LOG_RTCERR6(func, a1, a2, a3, a4, a5, a6) \ + LOG_RTCERR6_EX(func, a1, a2, a3, a4, a5, a6, GetLastEngineError()) +#define LOG_RTCERR0_EX(func, err) LOG(LS_WARNING) \ + << "" << #func << "() failed, err=" << err +#define LOG_RTCERR1_EX(func, a1, err) LOG(LS_WARNING) \ + << "" << #func << "(" << a1 << ") failed, err=" << err +#define LOG_RTCERR2_EX(func, a1, a2, err) LOG(LS_WARNING) \ + << "" << #func << "(" << a1 << ", " << a2 << ") failed, err=" \ + << err +#define LOG_RTCERR3_EX(func, a1, a2, a3, err) LOG(LS_WARNING) \ + << "" << #func << "(" << a1 << ", " << a2 << ", " << a3 \ + << ") failed, err=" << err +#define LOG_RTCERR4_EX(func, a1, a2, a3, a4, err) LOG(LS_WARNING) \ + << "" << #func << "(" << a1 << ", " << a2 << ", " << a3 \ + << ", " << a4 << ") failed, err=" << err +#define LOG_RTCERR5_EX(func, a1, a2, a3, a4, a5, err) LOG(LS_WARNING) \ + << "" << #func << "(" << a1 << ", " << a2 << ", " << a3 \ + << ", " << a4 << ", " << a5 << ") failed, err=" << err +#define LOG_RTCERR6_EX(func, a1, a2, a3, a4, a5, a6, err) LOG(LS_WARNING) \ + << "" << #func << "(" << a1 << ", " << a2 << ", " << a3 \ + << ", " << a4 << ", " << a5 << ", " << a6 << ") failed, err=" << err + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTCCOMMON_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcexport.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcexport.h new file mode 100644 index 0000000..3b219b2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcexport.h @@ -0,0 +1,79 @@ +/* + * 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_MEDIA_WEBRTC_WEBRTCEXPORT_H_ +#define TALK_MEDIA_WEBRTC_WEBRTCEXPORT_H_ + +#if !defined(GOOGLE_CHROME_BUILD) && !defined(CHROMIUM_BUILD) +#define LIBPEERCONNECTION_LIB 1 +#endif + +#ifndef NON_EXPORTED_BASE +#ifdef WIN32 + +// MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and +// for the next line of the source file. +#define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n)) + +// Allows exporting a class that inherits from a non-exported base class. +// This uses suppress instead of push/pop because the delimiter after the +// declaration (either "," or "{") has to be placed before the pop macro. +// +// Example usage: +// class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) { +// +// MSVC Compiler warning C4275: +// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'. +// Note that this is intended to be used only when no access to the base class' +// static data is done through derived classes or inline methods. For more info, +// see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx +#define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \ + code + +#else // Not WIN32 +#define NON_EXPORTED_BASE(code) code +#endif // WIN32 +#endif // NON_EXPORTED_BASE + +#if defined (LIBPEERCONNECTION_LIB) + #define WRME_EXPORT +#else + #if defined(WIN32) + #if defined(LIBPEERCONNECTION_IMPLEMENTATION) + #define WRME_EXPORT __declspec(dllexport) + #else + #define WRME_EXPORT __declspec(dllimport) + #endif + #else // defined(WIN32) + #if defined(LIBPEERCONNECTION_IMPLEMENTATION) + #define WRME_EXPORT __attribute__((visibility("default"))) + #else + #define WRME_EXPORT + #endif + #endif +#endif // LIBPEERCONNECTION_LIB + +#endif // TALK_MEDIA_WEBRTC_WEBRTCEXPORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcmediaengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcmediaengine.h new file mode 100644 index 0000000..ded1b54 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcmediaengine.h @@ -0,0 +1,203 @@ +/* + * 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_MEDIA_WEBRTCMEDIAENGINE_H_ +#define TALK_MEDIA_WEBRTCMEDIAENGINE_H_ + +#include "talk/media/base/mediaengine.h" +#include "talk/media/webrtc/webrtcexport.h" + +namespace webrtc { +class AudioDeviceModule; +class VideoCaptureModule; +} +namespace cricket { +class WebRtcVideoDecoderFactory; +class WebRtcVideoEncoderFactory; +} + + +#if !defined(LIBPEERCONNECTION_LIB) && \ + !defined(LIBPEERCONNECTION_IMPLEMENTATION) + +WRME_EXPORT +cricket::MediaEngineInterface* CreateWebRtcMediaEngine( + webrtc::AudioDeviceModule* adm, webrtc::AudioDeviceModule* adm_sc, + cricket::WebRtcVideoEncoderFactory* encoder_factory, + cricket::WebRtcVideoDecoderFactory* decoder_factory); + +WRME_EXPORT +void DestroyWebRtcMediaEngine(cricket::MediaEngineInterface* media_engine); + +namespace cricket { + +class WebRtcMediaEngine : public cricket::MediaEngineInterface { + public: + WebRtcMediaEngine( + webrtc::AudioDeviceModule* adm, + webrtc::AudioDeviceModule* adm_sc, + cricket::WebRtcVideoEncoderFactory* encoder_factory, + cricket::WebRtcVideoDecoderFactory* decoder_factory) + : delegate_(CreateWebRtcMediaEngine( + adm, adm_sc, encoder_factory, decoder_factory)) { + } + virtual ~WebRtcMediaEngine() { + DestroyWebRtcMediaEngine(delegate_); + } + virtual bool Init(talk_base::Thread* worker_thread) OVERRIDE { + return delegate_->Init(worker_thread); + } + virtual void Terminate() OVERRIDE { + delegate_->Terminate(); + } + virtual int GetCapabilities() OVERRIDE { + return delegate_->GetCapabilities(); + } + virtual VoiceMediaChannel* CreateChannel() OVERRIDE { + return delegate_->CreateChannel(); + } + virtual VideoMediaChannel* CreateVideoChannel( + VoiceMediaChannel* voice_media_channel) OVERRIDE { + return delegate_->CreateVideoChannel(voice_media_channel); + } + virtual SoundclipMedia* CreateSoundclip() OVERRIDE { + return delegate_->CreateSoundclip(); + } + virtual AudioOptions GetAudioOptions() const OVERRIDE { + return delegate_->GetAudioOptions(); + } + virtual bool SetAudioOptions(const AudioOptions& options) OVERRIDE { + return delegate_->SetAudioOptions(options); + } + virtual bool SetVideoOptions(const VideoOptions& options) OVERRIDE { + return delegate_->SetVideoOptions(options); + } + virtual bool SetAudioDelayOffset(int offset) OVERRIDE { + return delegate_->SetAudioDelayOffset(offset); + } + virtual bool SetDefaultVideoEncoderConfig( + const VideoEncoderConfig& config) OVERRIDE { + return delegate_->SetDefaultVideoEncoderConfig(config); + } + virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const OVERRIDE { + return delegate_->GetDefaultVideoEncoderConfig(); + } + virtual bool SetSoundDevices( + const Device* in_device, const Device* out_device) OVERRIDE { + return delegate_->SetSoundDevices(in_device, out_device); + } + virtual bool GetOutputVolume(int* level) OVERRIDE { + return delegate_->GetOutputVolume(level); + } + virtual bool SetOutputVolume(int level) OVERRIDE { + return delegate_->SetOutputVolume(level); + } + virtual int GetInputLevel() OVERRIDE { + return delegate_->GetInputLevel(); + } + virtual bool SetLocalMonitor(bool enable) OVERRIDE { + return delegate_->SetLocalMonitor(enable); + } + virtual bool SetLocalRenderer(VideoRenderer* renderer) OVERRIDE { + return delegate_->SetLocalRenderer(renderer); + } + virtual const std::vector& audio_codecs() OVERRIDE { + return delegate_->audio_codecs(); + } + virtual const std::vector& + audio_rtp_header_extensions() OVERRIDE { + return delegate_->audio_rtp_header_extensions(); + } + virtual const std::vector& video_codecs() OVERRIDE { + return delegate_->video_codecs(); + } + virtual const std::vector& + video_rtp_header_extensions() OVERRIDE { + return delegate_->video_rtp_header_extensions(); + } + virtual void SetVoiceLogging(int min_sev, const char* filter) OVERRIDE { + delegate_->SetVoiceLogging(min_sev, filter); + } + 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 { + return delegate_->RegisterVoiceProcessor(ssrc, video_processor, direction); + } + virtual bool UnregisterVoiceProcessor( + uint32 ssrc, VoiceProcessor* video_processor, + MediaProcessorDirection direction) OVERRIDE { + return delegate_->UnregisterVoiceProcessor(ssrc, video_processor, + direction); + } + virtual VideoFormat GetStartCaptureFormat() const OVERRIDE { + return delegate_->GetStartCaptureFormat(); + } + virtual sigslot::repeater2& + SignalVideoCaptureStateChange() { + return delegate_->SignalVideoCaptureStateChange(); + } + + private: + cricket::MediaEngineInterface* delegate_; +}; + +} // namespace cricket +#else + +#include "talk/media/webrtc/webrtcvideoengine.h" +#include "talk/media/webrtc/webrtcvoiceengine.h" + +namespace cricket { +typedef CompositeMediaEngine + WebRtcCompositeMediaEngine; + +class WebRtcMediaEngine : public WebRtcCompositeMediaEngine { + public: + WebRtcMediaEngine(webrtc::AudioDeviceModule* adm, + webrtc::AudioDeviceModule* adm_sc, + WebRtcVideoEncoderFactory* encoder_factory, + WebRtcVideoDecoderFactory* decoder_factory) { + voice_.SetAudioDeviceModule(adm, adm_sc); + video_.SetVoiceEngine(&voice_); + video_.EnableTimedRender(); + video_.SetExternalEncoderFactory(encoder_factory); + video_.SetExternalDecoderFactory(decoder_factory); + } +}; + +} // namespace cricket + +#endif // !defined(LIBPEERCONNECTION_LIB) && + // !defined(LIBPEERCONNECTION_IMPLEMENTATION) + +#endif // TALK_MEDIA_WEBRTCMEDIAENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcpassthroughrender.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcpassthroughrender.h new file mode 100644 index 0000000..cfef467 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcpassthroughrender.h @@ -0,0 +1,211 @@ +/* + * 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_WEBRTCPASSTHROUGHRENDER_H_ +#define TALK_MEDIA_WEBRTCPASSTHROUGHRENDER_H_ + +#include + +#include "talk/base/criticalsection.h" +#include "webrtc/modules/video_render/include/video_render.h" + +namespace cricket { +class PassthroughStream; + +class WebRtcPassthroughRender : public webrtc::VideoRender { + public: + WebRtcPassthroughRender(); + virtual ~WebRtcPassthroughRender(); + + virtual int32_t Version(int8_t* version, + uint32_t& remainingBufferInBytes, + uint32_t& position) const { + return 0; + } + + virtual int32_t ChangeUniqueId(const int32_t id) { + return 0; + } + + virtual int32_t TimeUntilNextProcess() { return 0; } + + virtual int32_t Process() { return 0; } + + virtual void* Window() { + talk_base::CritScope cs(&render_critical_); + return window_; + } + + virtual int32_t ChangeWindow(void* window) { + talk_base::CritScope cs(&render_critical_); + window_ = window; + return 0; + } + + virtual webrtc::VideoRenderCallback* AddIncomingRenderStream( + const uint32_t stream_id, + const uint32_t zOrder, + const float left, const float top, + const float right, const float bottom); + + virtual int32_t DeleteIncomingRenderStream(const uint32_t stream_id); + + virtual int32_t AddExternalRenderCallback( + const uint32_t stream_id, + webrtc::VideoRenderCallback* render_object); + + virtual int32_t GetIncomingRenderStreamProperties( + const uint32_t stream_id, + uint32_t& zOrder, + float& left, float& top, + float& right, float& bottom) const { + return -1; + } + + virtual uint32_t GetIncomingFrameRate( + const uint32_t stream_id) { + return 0; + } + + virtual uint32_t GetNumIncomingRenderStreams() const { + return static_cast(stream_render_map_.size()); + } + + virtual bool HasIncomingRenderStream(const uint32_t stream_id) const; + + virtual int32_t RegisterRawFrameCallback( + const uint32_t stream_id, + webrtc::VideoRenderCallback* callback_obj) { + return -1; + } + + virtual int32_t GetLastRenderedFrame( + const uint32_t stream_id, + webrtc::I420VideoFrame &frame) const { + return -1; + } + + virtual int32_t StartRender( + const uint32_t stream_id); + + virtual int32_t StopRender( + const uint32_t stream_id); + + virtual int32_t ResetRender() { return 0; } + + virtual webrtc::RawVideoType PreferredVideoType() const; + + virtual bool IsFullScreen() { return false; } + + virtual int32_t GetScreenResolution(uint32_t& screenWidth, + uint32_t& screenHeight) const { + return -1; + } + + virtual uint32_t RenderFrameRate( + const uint32_t stream_id) { + return 0; + } + + virtual int32_t SetStreamCropping( + const uint32_t stream_id, + const float left, const float top, + const float right, + const float bottom) { + return -1; + } + + virtual int32_t SetExpectedRenderDelay(uint32_t stream_id, int32_t delay_ms) { + return -1; + } + + virtual int32_t ConfigureRenderer( + const uint32_t stream_id, + const unsigned int zOrder, + const float left, const float top, + const float right, + const float bottom) { + return -1; + } + + virtual int32_t SetTransparentBackground(const bool enable) { + return -1; + } + + virtual int32_t FullScreenRender(void* window, const bool enable) { + return -1; + } + + virtual int32_t SetBitmap(const void* bitMap, + const uint8_t pictureId, const void* colorKey, + const float left, const float top, + const float right, const float bottom) { + return -1; + } + + virtual int32_t SetText(const uint8_t textId, + const uint8_t* text, + const int32_t textLength, + const uint32_t textColorRef, + const uint32_t backgroundColorRef, + const float left, const float top, + const float right, const float bottom) { + return -1; + } + + virtual int32_t SetStartImage( + const uint32_t stream_id, + const webrtc::I420VideoFrame& videoFrame) { + return -1; + } + + virtual int32_t SetTimeoutImage( + const uint32_t stream_id, + const webrtc::I420VideoFrame& videoFrame, + const uint32_t timeout) { + return -1; + } + + virtual int32_t MirrorRenderStream(const int renderId, + const bool enable, + const bool mirrorXAxis, + const bool mirrorYAxis) { + return -1; + } + + private: + typedef std::map StreamMap; + + PassthroughStream* FindStream(const uint32_t stream_id) const; + + void* window_; + StreamMap stream_render_map_; + talk_base::CriticalSection render_critical_; +}; +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTCPASSTHROUGHRENDER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtctexturevideoframe.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtctexturevideoframe.h new file mode 100644 index 0000000..bab1f9f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtctexturevideoframe.h @@ -0,0 +1,113 @@ +/* + * 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_MEDIA_WEBRTC_WEBRTCTEXTUREVIDEOFRAME_H_ +#define TALK_MEDIA_WEBRTC_WEBRTCTEXTUREVIDEOFRAME_H_ + +#include "talk/base/refcount.h" +#include "talk/base/scoped_ref_ptr.h" +#include "talk/media/base/videoframe.h" +#include "webrtc/common_video/interface/native_handle.h" + +namespace cricket { + +// A video frame backed by the texture via a native handle. +class WebRtcTextureVideoFrame : public VideoFrame { + public: + WebRtcTextureVideoFrame(webrtc::NativeHandle* handle, int width, int height, + int64 elapsed_time, int64 time_stamp); + virtual ~WebRtcTextureVideoFrame(); + + // From base class VideoFrame. + virtual bool InitToBlack(int w, int h, size_t pixel_width, + size_t pixel_height, int64 elapsed_time, + int64 time_stamp); + 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); + virtual size_t GetWidth() const { return width_; } + virtual size_t GetHeight() const { return height_; } + virtual const uint8* GetYPlane() const; + virtual const uint8* GetUPlane() const; + virtual const uint8* GetVPlane() const; + virtual uint8* GetYPlane(); + virtual uint8* GetUPlane(); + virtual uint8* GetVPlane(); + virtual int32 GetYPitch() const; + virtual int32 GetUPitch() const; + virtual int32 GetVPitch() const; + virtual size_t GetPixelWidth() const { return 1; } + virtual size_t GetPixelHeight() const { return 1; } + virtual int64 GetElapsedTime() const { return elapsed_time_; } + virtual int64 GetTimeStamp() const { return time_stamp_; } + virtual void SetElapsedTime(int64 elapsed_time) { + elapsed_time_ = elapsed_time; + } + virtual void SetTimeStamp(int64 time_stamp) { time_stamp_ = time_stamp; } + virtual int GetRotation() const { return 0; } + virtual VideoFrame* Copy() const; + virtual bool MakeExclusive(); + virtual size_t CopyToBuffer(uint8* buffer, size_t size) const; + virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8* buffer, + size_t size, int stride_rgb) const; + virtual void* GetNativeHandle() const { return handle_.get(); } + + virtual bool CopyToPlanes( + uint8* dst_y, uint8* dst_u, uint8* dst_v, + int32 dst_pitch_y, int32 dst_pitch_u, int32 dst_pitch_v) const; + virtual void CopyToFrame(VideoFrame* target) const; + virtual talk_base::StreamResult Write(talk_base::StreamInterface* stream, + int* error); + virtual void StretchToPlanes( + uint8* y, uint8* u, uint8* v, int32 pitchY, int32 pitchU, int32 pitchV, + size_t width, size_t height, bool interpolate, bool crop) const; + virtual size_t StretchToBuffer(size_t w, size_t h, uint8* buffer, size_t size, + bool interpolate, bool crop) const; + virtual void StretchToFrame(VideoFrame* target, bool interpolate, + bool crop) const; + virtual VideoFrame* Stretch(size_t w, size_t h, bool interpolate, + bool crop) const; + virtual bool SetToBlack(); + + protected: + virtual VideoFrame* CreateEmptyFrame(int w, int h, size_t pixel_width, + size_t pixel_height, int64 elapsed_time, + int64 time_stamp) const; + + private: + // The handle of the underlying video frame. + talk_base::scoped_refptr handle_; + int width_; + int height_; + int64 elapsed_time_; + int64 time_stamp_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTC_WEBRTCTEXTUREVIDEOFRAME_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideocapturer.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideocapturer.h new file mode 100644 index 0000000..506b853 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideocapturer.h @@ -0,0 +1,107 @@ +// 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_WEBRTCVIDEOCAPTURER_H_ +#define TALK_MEDIA_WEBRTCVIDEOCAPTURER_H_ + +#ifdef HAVE_WEBRTC_VIDEO + +#include +#include + +#include "talk/base/criticalsection.h" +#include "talk/base/messagehandler.h" +#include "talk/media/base/videocapturer.h" +#include "talk/media/webrtc/webrtcvideoframe.h" +#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" +#include "webrtc/modules/video_capture/include/video_capture.h" + +namespace cricket { + +// Factory to allow injection of a VCM impl into WebRtcVideoCapturer. +// DeviceInfos do not have a Release() and therefore need an explicit Destroy(). +class WebRtcVcmFactoryInterface { + public: + virtual ~WebRtcVcmFactoryInterface() {} + virtual webrtc::VideoCaptureModule* Create( + int id, const char* device) = 0; + virtual webrtc::VideoCaptureModule::DeviceInfo* CreateDeviceInfo(int id) = 0; + virtual void DestroyDeviceInfo( + webrtc::VideoCaptureModule::DeviceInfo* info) = 0; +}; + +// WebRTC-based implementation of VideoCapturer. +class WebRtcVideoCapturer : public VideoCapturer, + public webrtc::VideoCaptureDataCallback { + public: + WebRtcVideoCapturer(); + explicit WebRtcVideoCapturer(WebRtcVcmFactoryInterface* factory); + virtual ~WebRtcVideoCapturer(); + + bool Init(const Device& device); + bool Init(webrtc::VideoCaptureModule* module); + + // Override virtual methods of the parent class VideoCapturer. + virtual bool GetBestCaptureFormat(const VideoFormat& desired, + VideoFormat* best_format); + virtual CaptureState Start(const VideoFormat& capture_format); + virtual void Stop(); + virtual bool IsRunning(); + virtual bool IsScreencast() const { return false; } + + protected: + // Override virtual methods of the parent class VideoCapturer. + virtual bool GetPreferredFourccs(std::vector* fourccs); + + private: + // Callback when a frame is captured by camera. + virtual void OnIncomingCapturedFrame(const int32_t id, + webrtc::I420VideoFrame& frame); + virtual void OnIncomingCapturedEncodedFrame(const int32_t id, + webrtc::VideoFrame& frame, + webrtc::VideoCodecType codec_type) { + } + virtual void OnCaptureDelayChanged(const int32_t id, + const int32_t delay); + + talk_base::scoped_ptr factory_; + webrtc::VideoCaptureModule* module_; + int captured_frames_; + std::vector capture_buffer_; + + // Critical section to avoid Stop during an OnIncomingCapturedFrame callback. + talk_base::CriticalSection critical_section_stopping_; +}; + +struct WebRtcCapturedFrame : public CapturedFrame { + public: + WebRtcCapturedFrame(const webrtc::I420VideoFrame& frame, + void* buffer, int length); +}; + +} // namespace cricket + +#endif // HAVE_WEBRTC_VIDEO +#endif // TALK_MEDIA_WEBRTCVIDEOCAPTURER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideochannelfactory.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideochannelfactory.h new file mode 100644 index 0000000..7eb06bd --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/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/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideodecoderfactory.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideodecoderfactory.h new file mode 100644 index 0000000..cb70790 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideodecoderfactory.h @@ -0,0 +1,53 @@ +/* + * 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_MEDIA_WEBRTC_WEBRTCVIDEODECODERFACTORY_H_ +#define TALK_MEDIA_WEBRTC_WEBRTCVIDEODECODERFACTORY_H_ + +#include "talk/base/refcount.h" +#include "webrtc/common_types.h" + +namespace webrtc { +class VideoDecoder; +} + +namespace cricket { + +class WebRtcVideoDecoderFactory { + public: + // Caller takes the ownership of the returned object and it should be released + // by calling DestroyVideoDecoder(). + virtual webrtc::VideoDecoder* CreateVideoDecoder( + webrtc::VideoCodecType type) = 0; + virtual ~WebRtcVideoDecoderFactory() {} + + virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) = 0; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTC_WEBRTCVIDEODECODERFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoencoderfactory.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoencoderfactory.h new file mode 100644 index 0000000..e20a5d6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoencoderfactory.h @@ -0,0 +1,89 @@ +/* + * 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_MEDIA_WEBRTC_WEBRTCVIDEOENCODERFACTORY_H_ +#define TALK_MEDIA_WEBRTC_WEBRTCVIDEOENCODERFACTORY_H_ + +#include "talk/base/refcount.h" +#include "talk/media/base/codec.h" +#include "webrtc/common_types.h" + +namespace webrtc { +class VideoEncoder; +} + +namespace cricket { + +class WebRtcVideoEncoderFactory { + public: + struct VideoCodec { + webrtc::VideoCodecType type; + std::string name; + int max_width; + int max_height; + int max_fps; + + VideoCodec(webrtc::VideoCodecType t, const std::string& nm, int w, int h, + int fr) + : type(t), name(nm), max_width(w), max_height(h), max_fps(fr) { + } + }; + + class Observer { + public: + // Invoked when the list of supported codecs becomes available. + // This will not be invoked if the list of codecs is already available when + // the factory is installed. Otherwise this will be invoked only once if the + // list of codecs is not yet available when the factory is installed. + virtual void OnCodecsAvailable() = 0; + + protected: + virtual ~Observer() {} + }; + + // Caller takes the ownership of the returned object and it should be released + // by calling DestroyVideoEncoder(). + virtual webrtc::VideoEncoder* CreateVideoEncoder( + webrtc::VideoCodecType type) = 0; + virtual ~WebRtcVideoEncoderFactory() {} + + // Adds/removes observer to receive OnCodecsChanged notifications. + // Factory must outlive Observer. Observer is responsible for removing itself + // from the Factory by the time its dtor is done. + virtual void AddObserver(Observer* observer) = 0; + virtual void RemoveObserver(Observer* observer) = 0; + + // Returns a list of supported codecs in order of preference. + // The list is empty if the list of codecs is not yet available. + virtual const std::vector& codecs() const = 0; + + virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) = 0; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTC_WEBRTCVIDEOENCODERFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoengine.h new file mode 100644 index 0000000..8e5f0cc --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoengine.h @@ -0,0 +1,468 @@ +/* + * 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_WEBRTCVIDEOENGINE_H_ +#define TALK_MEDIA_WEBRTCVIDEOENGINE_H_ + +#include +#include + +#include "talk/base/scoped_ptr.h" +#include "talk/media/base/codec.h" +#include "talk/media/base/videocommon.h" +#include "talk/media/webrtc/webrtccommon.h" +#include "talk/media/webrtc/webrtcexport.h" +#include "talk/media/webrtc/webrtcvideoencoderfactory.h" +#include "talk/session/media/channel.h" +#include "webrtc/video_engine/include/vie_base.h" + +#if !defined(LIBPEERCONNECTION_LIB) && \ + !defined(LIBPEERCONNECTION_IMPLEMENTATION) +#error "Bogus include." +#endif + + +namespace webrtc { +class VideoCaptureModule; +class VideoDecoder; +class VideoEncoder; +class VideoRender; +class ViEExternalCapture; +class ViERTP_RTCP; +} + +namespace talk_base { +class CpuMonitor; +} // namespace talk_base + +namespace cricket { + +class CoordinatedVideoAdapter; +class ViETraceWrapper; +class ViEWrapper; +class VideoCapturer; +class VideoFrame; +class VideoProcessor; +class VideoRenderer; +class VoiceMediaChannel; +class WebRtcDecoderObserver; +class WebRtcEncoderObserver; +class WebRtcLocalStreamInfo; +class WebRtcRenderAdapter; +class WebRtcVideoChannelRecvInfo; +class WebRtcVideoChannelSendInfo; +class WebRtcVideoDecoderFactory; +class WebRtcVideoEncoderFactory; +class WebRtcVideoMediaChannel; +class WebRtcVoiceEngine; + +struct CapturedFrame; +struct Device; + +class WebRtcVideoEngine : public sigslot::has_slots<>, + public webrtc::TraceCallback, + public WebRtcVideoEncoderFactory::Observer { + public: + // Creates the WebRtcVideoEngine with internal VideoCaptureModule. + WebRtcVideoEngine(); + // For testing purposes. Allows the WebRtcVoiceEngine, + // ViEWrapper and CpuMonitor to be mocks. + // TODO(juberti): Remove the 3-arg ctor once fake tracing is implemented. + WebRtcVideoEngine(WebRtcVoiceEngine* voice_engine, + ViEWrapper* vie_wrapper, + talk_base::CpuMonitor* cpu_monitor); + WebRtcVideoEngine(WebRtcVoiceEngine* voice_engine, + ViEWrapper* vie_wrapper, + ViETraceWrapper* tracing, + talk_base::CpuMonitor* cpu_monitor); + ~WebRtcVideoEngine(); + + // 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; + + WebRtcVideoMediaChannel* CreateChannel(VoiceMediaChannel* voice_channel); + + const std::vector& codecs() const; + const std::vector& rtp_header_extensions() const; + void SetLogging(int min_sev, const char* filter); + + bool SetLocalRenderer(VideoRenderer* renderer); + sigslot::repeater2 SignalCaptureStateChange; + + // Set the VoiceEngine for A/V sync. This can only be called before Init. + bool SetVoiceEngine(WebRtcVoiceEngine* voice_engine); + // Set a WebRtcVideoDecoderFactory for external decoding. Video engine does + // not take the ownership of |decoder_factory|. The caller needs to make sure + // that |decoder_factory| outlives the video engine. + void SetExternalDecoderFactory(WebRtcVideoDecoderFactory* decoder_factory); + // Set a WebRtcVideoEncoderFactory for external encoding. Video engine does + // not take the ownership of |encoder_factory|. The caller needs to make sure + // that |encoder_factory| outlives the video engine. + void SetExternalEncoderFactory(WebRtcVideoEncoderFactory* encoder_factory); + // Enable the render module with timing control. + bool EnableTimedRender(); + + // Returns an external decoder for the given codec type. The return value + // can be NULL if decoder factory is not given or it does not support the + // codec type. The caller takes the ownership of the returned object. + webrtc::VideoDecoder* CreateExternalDecoder(webrtc::VideoCodecType type); + // Releases the decoder instance created by CreateExternalDecoder(). + void DestroyExternalDecoder(webrtc::VideoDecoder* decoder); + + // Returns an external encoder for the given codec type. The return value + // can be NULL if encoder factory is not given or it does not support the + // codec type. The caller takes the ownership of the returned object. + webrtc::VideoEncoder* CreateExternalEncoder(webrtc::VideoCodecType type); + // Releases the encoder instance created by CreateExternalEncoder(). + void DestroyExternalEncoder(webrtc::VideoEncoder* encoder); + + // Returns true if the codec type is supported by the external encoder. + bool IsExternalEncoderCodecType(webrtc::VideoCodecType type) const; + + // Functions called by WebRtcVideoMediaChannel. + talk_base::Thread* worker_thread() { return worker_thread_; } + ViEWrapper* vie() { return vie_wrapper_.get(); } + const VideoFormat& default_codec_format() const { + return default_codec_format_; + } + int GetLastEngineError(); + bool FindCodec(const VideoCodec& in); + bool CanSendCodec(const VideoCodec& in, const VideoCodec& current, + VideoCodec* out); + void RegisterChannel(WebRtcVideoMediaChannel* channel); + void UnregisterChannel(WebRtcVideoMediaChannel* channel); + bool ConvertFromCricketVideoCodec(const VideoCodec& in_codec, + webrtc::VideoCodec* out_codec); + // Check whether the supplied trace should be ignored. + bool ShouldIgnoreTrace(const std::string& trace); + int GetNumOfChannels(); + + VideoFormat GetStartCaptureFormat() const { return default_codec_format_; } + + talk_base::CpuMonitor* cpu_monitor() { return cpu_monitor_.get(); } + + protected: + // When a video processor registers with the engine. + // SignalMediaFrame will be invoked for every video frame. + // See videoprocessor.h for param reference. + sigslot::signal3 SignalMediaFrame; + + private: + typedef std::vector VideoChannels; + struct VideoCodecPref { + const char* name; + int payload_type; + // For RTX, this field is the payload-type that RTX applies to. + // For other codecs, it should be set to -1. + int associated_payload_type; + int pref; + }; + + static const VideoCodecPref kVideoCodecPrefs[]; + static const VideoFormatPod kVideoFormats[]; + static const VideoFormatPod kDefaultVideoFormat; + + void Construct(ViEWrapper* vie_wrapper, + ViETraceWrapper* tracing, + WebRtcVoiceEngine* voice_engine, + talk_base::CpuMonitor* cpu_monitor); + bool SetDefaultCodec(const VideoCodec& codec); + bool RebuildCodecList(const VideoCodec& max_codec); + 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); + + // WebRtcVideoEncoderFactory::Observer implementation. + virtual void OnCodecsAvailable(); + + talk_base::Thread* worker_thread_; + talk_base::scoped_ptr vie_wrapper_; + bool vie_wrapper_base_initialized_; + talk_base::scoped_ptr tracing_; + WebRtcVoiceEngine* voice_engine_; + talk_base::scoped_ptr render_module_; + WebRtcVideoEncoderFactory* encoder_factory_; + WebRtcVideoDecoderFactory* decoder_factory_; + std::vector video_codecs_; + std::vector rtp_header_extensions_; + VideoFormat default_codec_format_; + + bool initialized_; + talk_base::CriticalSection channels_crit_; + VideoChannels channels_; + + bool capture_started_; + int local_renderer_w_; + int local_renderer_h_; + VideoRenderer* local_renderer_; + + talk_base::scoped_ptr cpu_monitor_; +}; + +class WebRtcVideoMediaChannel : public talk_base::MessageHandler, + public VideoMediaChannel, + public webrtc::Transport { + public: + WebRtcVideoMediaChannel(WebRtcVideoEngine* engine, + VoiceMediaChannel* voice_channel); + ~WebRtcVideoMediaChannel(); + bool Init(); + + WebRtcVideoEngine* engine() { return engine_; } + VoiceMediaChannel* voice_channel() { return voice_channel_; } + 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 &codecs); + virtual bool SetSendCodecs(const std::vector &codecs); + virtual bool GetSendCodec(VideoCodec* send_codec); + virtual bool SetSendStreamFormat(uint32 ssrc, const VideoFormat& format); + virtual bool SetRender(bool render); + virtual bool SetSend(bool send); + + virtual bool AddSendStream(const StreamParams& sp); + virtual bool RemoveSendStream(uint32 ssrc); + virtual bool AddRecvStream(const StreamParams& sp); + virtual bool RemoveRecvStream(uint32 ssrc); + virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer); + virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info); + virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer); + virtual bool SendIntraFrame(); + virtual bool RequestIntraFrame(); + + virtual void OnPacketReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + virtual void OnRtcpReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + virtual void OnReadyToSend(bool ready); + virtual bool MuteStream(uint32 ssrc, bool on); + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions); + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions); + 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_; + return true; + } + virtual void SetInterface(NetworkInterface* iface); + virtual void UpdateAspectRatio(int ratio_w, int ratio_h); + + // 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); + + // Thunk functions for use with HybridVideoEngine + void OnLocalFrame(VideoCapturer* capturer, const VideoFrame* frame) { + SendFrame(0u, frame, capturer->IsScreencast()); + } + void OnLocalFrameFormat(VideoCapturer* capturer, const VideoFormat* format) { + } + + virtual void OnMessage(talk_base::Message* msg); + + protected: + int GetLastEngineError() { return engine()->GetLastEngineError(); } + virtual int SendPacket(int channel, const void* data, int len); + virtual int SendRTCPPacket(int channel, const void* data, int len); + + private: + typedef std::map RecvChannelMap; + typedef std::map SendChannelMap; + typedef std::map SsrcMap; + typedef int (webrtc::ViERTP_RTCP::* ExtensionSetterFunction)(int, bool, int); + + enum MediaDirection { MD_RECV, MD_SEND, MD_SENDRECV }; + + // Creates and initializes a ViE channel. When successful |channel_id| will + // contain the new channel's ID. If |receiving| is true |ssrc| is the + // remote ssrc. If |sending| is true the ssrc is local ssrc. If both + // |receiving| and |sending| is true the ssrc must be 0 and the channel will + // be created as a default channel. The ssrc must be different for receive + // channels and it must be different for send channels. If the same SSRC is + // being used for creating channel more than once, this function will fail + // 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); + bool SetSendCodec(WebRtcVideoChannelSendInfo* send_channel, + 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); + // 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 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(); + bool StartSend(WebRtcVideoChannelSendInfo* send_channel); + // Helper function for stop the sending of media on all channels or + // |channel_id|. Note that these two function do not change |sending_|. + bool StopSend(); + bool StopSend(WebRtcVideoChannelSendInfo* send_channel); + bool SendIntraFrame(int channel_id); + + bool HasReadySendChannels(); + + // Send channel key returns the key corresponding to the provided local SSRC + // in |key|. The return value is true upon success. + // If the local ssrc correspond to that of the default channel the key is 0. + // For all other channels the returned key will be the same as the local ssrc. + bool GetSendChannelKey(uint32 local_ssrc, uint32* key); + WebRtcVideoChannelSendInfo* GetSendChannel(uint32 local_ssrc); + // Creates a new unique key that can be used for inserting a new send channel + // into |send_channels_| + bool CreateSendChannelKey(uint32 local_ssrc, uint32* key); + // Get the number of the send channels |capturer| registered with. + int GetSendChannelNum(VideoCapturer* capturer); + + bool IsDefaultChannel(int channel_id) const { + return channel_id == vie_channel_; + } + + bool DeleteSendChannel(uint32 ssrc_key); + + bool InConferenceMode() const { + return options_.conference_mode.GetWithDefaultIfUnset(false); + } + bool RemoveCapturer(uint32 ssrc); + + + talk_base::MessageQueue* worker_thread() { return engine_->worker_thread(); } + void QueueBlackFrame(uint32 ssrc, int64 timestamp, int framerate); + void FlushBlackFrame(uint32 ssrc, int64 timestamp); + + void SetNetworkTransmissionState(bool is_transmitting); + + bool SetHeaderExtension(ExtensionSetterFunction setter, int channel_id, + const RtpHeaderExtension* extension); + bool SetHeaderExtension(ExtensionSetterFunction setter, int channel_id, + const std::vector& extensions, + const char header_extension_uri[]); + + // Signal when cpu adaptation has no further scope to adapt. + void OnCpuAdaptationUnable(); + + // Set the local (send-side) RTX SSRC corresponding to primary_ssrc. + bool SetLocalRtxSsrc(int channel_id, const StreamParams& send_params, + uint32 primary_ssrc, int stream_idx); + + // Connect |capturer| to WebRtcVideoMediaChannel if it is only registered + // to one send channel, i.e. the first send channel. + void MaybeConnectCapturer(VideoCapturer* capturer); + // Disconnect |capturer| from WebRtcVideoMediaChannel if it is only registered + // 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_; + int vie_channel_; + bool nack_enabled_; + // Receiver Estimated Max Bitrate + bool remb_enabled_; + VideoOptions options_; + + // Global recv side state. + // Note the default channel (vie_channel_), i.e. the send channel + // corresponding to all the receive channels (this must be done for REMB to + // 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 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 associated_payload_types_; + bool render_started_; + uint32 first_receive_ssrc_; + std::vector receive_extensions_; + int num_unsignalled_recv_channels_; + + // Global send side state. + SendChannelMap send_channels_; + talk_base::scoped_ptr send_codec_; + int send_rtx_type_; + int send_red_type_; + int send_fec_type_; + bool sending_; + std::vector send_extensions_; + + // The aspect ratio that the channel desires. 0 means there is no desired + // aspect ratio + int ratio_w_; + int ratio_h_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTCVIDEOENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoengine2.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoengine2.h new file mode 100644 index 0000000..1b1f87b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoengine2.h @@ -0,0 +1,332 @@ +/* + * 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 +#include +#include + +#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 bool CreateEncoderSettings( + webrtc::VideoSendStream::Config::EncoderSettings* encoder_settings, + const VideoOptions& options, + const cricket::VideoCodec& codec, + size_t num_streams) = 0; + virtual bool SupportsCodec(const cricket::VideoCodec& codec) = 0; +}; + +// 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& codecs() const; + const std::vector& 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 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* GetDefaultVideoEncoderFactory() const; + + private: + void Construct(WebRtcVideoChannelFactory* channel_factory, + WebRtcVoiceEngine* voice_engine, + talk_base::CpuMonitor* cpu_monitor); + + talk_base::Thread* worker_thread_; + WebRtcVoiceEngine* voice_engine_; + std::vector video_codecs_; + std::vector 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 cpu_monitor_; + WebRtcVideoChannelFactory* channel_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& codecs) OVERRIDE; + virtual bool SetSendCodecs(const std::vector& 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; + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions) OVERRIDE; + virtual bool SetSendRtpHeaderExtensions( + const std::vector& 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(); + + cricket::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, + 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: + 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_); + webrtc::VideoSendStream::Config config_ 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 MapCodecs( + const std::vector& codecs); + std::vector FilterSupportedCodecs( + const std::vector& mapped_codecs); + + uint32_t rtcp_receiver_report_ssrc_; + bool sending_; + talk_base::scoped_ptr call_; + std::map renderers_; + VideoRenderer* default_renderer_; + uint32_t default_send_ssrc_; + uint32_t default_recv_ssrc_; + + // Using primary-ssrc (first ssrc) as key. + std::map send_streams_; + std::map receive_streams_; + + Settable send_codec_; + WebRtcVideoEncoderFactory2* const encoder_factory_; + std::vector recv_codecs_; + VideoOptions options_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoframe.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoframe.h new file mode 100644 index 0000000..51fb0a4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvideoframe.h @@ -0,0 +1,134 @@ +/* + * 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_MEDIA_WEBRTCVIDEOFRAME_H_ +#define TALK_MEDIA_WEBRTCVIDEOFRAME_H_ + +#include "talk/base/buffer.h" +#include "talk/base/refcount.h" +#include "talk/base/scoped_ref_ptr.h" +#include "talk/media/base/videoframe.h" +#include "webrtc/common_types.h" +#include "webrtc/modules/interface/module_common_types.h" + +namespace cricket { + +struct CapturedFrame; + +class WebRtcVideoFrame : public VideoFrame { + public: + WebRtcVideoFrame(); + ~WebRtcVideoFrame(); + + // Creates a frame from a raw sample with FourCC "format" and size "w" x "h". + // "h" can be negative indicating a vertically flipped image. + // "dh" is destination height if cropping is desired and is always positive. + // Returns "true" if successful. + bool Init(uint32 format, 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); + + bool Init(const CapturedFrame* frame, int dw, int dh); + + // Aliases this WebRtcVideoFrame to a CapturedFrame. |frame| must outlive + // this WebRtcVideoFrame. + bool Alias(const CapturedFrame* frame, int dw, int dh); + + bool InitToBlack(int w, int h, size_t pixel_width, size_t pixel_height, + int64 elapsed_time, int64 time_stamp); + + // Aliases this WebRtcVideoFrame to a memory buffer. |buffer| must outlive + // this WebRtcVideoFrame. + void Alias(uint8* buffer, size_t buffer_size, int w, int h, + size_t pixel_width, size_t pixel_height, int64 elapsed_time, + int64 time_stamp, int rotation); + + webrtc::VideoFrame* frame(); + const webrtc::VideoFrame* frame() const; + + // From base class VideoFrame. + virtual bool Reset(uint32 format, 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); + + virtual size_t GetWidth() const; + virtual size_t GetHeight() const; + virtual const uint8* GetYPlane() const; + virtual const uint8* GetUPlane() const; + virtual const uint8* GetVPlane() const; + virtual uint8* GetYPlane(); + virtual uint8* GetUPlane(); + virtual uint8* GetVPlane(); + virtual int32 GetYPitch() const { return frame()->Width(); } + virtual int32 GetUPitch() const { return (frame()->Width() + 1) / 2; } + virtual int32 GetVPitch() const { return (frame()->Width() + 1) / 2; } + virtual void* GetNativeHandle() const { return NULL; } + + virtual size_t GetPixelWidth() const { return pixel_width_; } + virtual size_t GetPixelHeight() const { return pixel_height_; } + virtual int64 GetElapsedTime() const { return elapsed_time_; } + virtual int64 GetTimeStamp() const { return time_stamp_; } + virtual void SetElapsedTime(int64 elapsed_time) { + elapsed_time_ = elapsed_time; + } + virtual void SetTimeStamp(int64 time_stamp) { time_stamp_ = time_stamp; } + + virtual int GetRotation() const { return rotation_; } + + virtual VideoFrame* Copy() const; + virtual bool MakeExclusive(); + virtual size_t CopyToBuffer(uint8* buffer, size_t size) const; + virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8* buffer, + size_t size, int stride_rgb) const; + + private: + class FrameBuffer; + typedef talk_base::RefCountedObject RefCountedBuffer; + + void Attach(RefCountedBuffer* video_buffer, size_t buffer_size, int w, int h, + size_t pixel_width, size_t pixel_height, int64 elapsed_time, + int64 time_stamp, int rotation); + + virtual VideoFrame* CreateEmptyFrame(int w, int h, size_t pixel_width, + size_t pixel_height, int64 elapsed_time, + int64 time_stamp) const; + void InitToEmptyBuffer(int w, int h, size_t pixel_width, size_t pixel_height, + int64 elapsed_time, int64 time_stamp); + + talk_base::scoped_refptr video_buffer_; + bool is_black_; + size_t pixel_width_; + size_t pixel_height_; + int64 elapsed_time_; + int64 time_stamp_; + int rotation_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTCVIDEOFRAME_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvie.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvie.h new file mode 100644 index 0000000..1b2fe1a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvie.h @@ -0,0 +1,151 @@ +/* + * 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_WEBRTCVIE_H_ +#define TALK_MEDIA_WEBRTCVIE_H_ + +#include "talk/base/common.h" +#include "talk/media/webrtc/webrtccommon.h" +#include "webrtc/common_types.h" +#include "webrtc/modules/interface/module_common_types.h" +#include "webrtc/modules/video_capture/include/video_capture.h" +#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h" +#include "webrtc/modules/video_render/include/video_render.h" +#include "webrtc/video_engine/include/vie_base.h" +#include "webrtc/video_engine/include/vie_capture.h" +#include "webrtc/video_engine/include/vie_codec.h" +#include "webrtc/video_engine/include/vie_errors.h" +#include "webrtc/video_engine/include/vie_external_codec.h" +#include "webrtc/video_engine/include/vie_image_process.h" +#include "webrtc/video_engine/include/vie_network.h" +#include "webrtc/video_engine/include/vie_render.h" +#include "webrtc/video_engine/include/vie_rtp_rtcp.h" + +namespace cricket { + +// all tracing macros should go to a common file + +// automatically handles lifetime of VideoEngine +class scoped_vie_engine { + public: + explicit scoped_vie_engine(webrtc::VideoEngine* e) : ptr(e) {} + // VERIFY, to ensure that there are no leaks at shutdown + ~scoped_vie_engine() { + if (ptr) { + webrtc::VideoEngine::Delete(ptr); + } + } + webrtc::VideoEngine* get() const { return ptr; } + private: + webrtc::VideoEngine* ptr; +}; + +// scoped_ptr class to handle obtaining and releasing VideoEngine +// interface pointers +template class scoped_vie_ptr { + public: + explicit scoped_vie_ptr(const scoped_vie_engine& e) + : ptr(T::GetInterface(e.get())) {} + explicit scoped_vie_ptr(T* p) : ptr(p) {} + ~scoped_vie_ptr() { if (ptr) ptr->Release(); } + T* operator->() const { return ptr; } + T* get() const { return ptr; } + private: + T* ptr; +}; + +// Utility class for aggregating the various WebRTC interface. +// Fake implementations can also be injected for testing. +class ViEWrapper { + public: + ViEWrapper() + : engine_(webrtc::VideoEngine::Create()), + base_(engine_), codec_(engine_), capture_(engine_), + network_(engine_), render_(engine_), rtp_(engine_), + image_(engine_), ext_codec_(engine_) { + } + + ViEWrapper(webrtc::ViEBase* base, webrtc::ViECodec* codec, + webrtc::ViECapture* capture, webrtc::ViENetwork* network, + webrtc::ViERender* render, webrtc::ViERTP_RTCP* rtp, + webrtc::ViEImageProcess* image, + webrtc::ViEExternalCodec* ext_codec) + : engine_(NULL), + base_(base), + codec_(codec), + capture_(capture), + network_(network), + render_(render), + rtp_(rtp), + image_(image), + ext_codec_(ext_codec) { + } + + virtual ~ViEWrapper() {} + webrtc::VideoEngine* engine() { return engine_.get(); } + webrtc::ViEBase* base() { return base_.get(); } + webrtc::ViECodec* codec() { return codec_.get(); } + webrtc::ViECapture* capture() { return capture_.get(); } + webrtc::ViENetwork* network() { return network_.get(); } + webrtc::ViERender* render() { return render_.get(); } + webrtc::ViERTP_RTCP* rtp() { return rtp_.get(); } + webrtc::ViEImageProcess* image() { return image_.get(); } + webrtc::ViEExternalCodec* ext_codec() { return ext_codec_.get(); } + int error() { return base_->LastError(); } + + private: + scoped_vie_engine engine_; + scoped_vie_ptr base_; + scoped_vie_ptr codec_; + scoped_vie_ptr capture_; + scoped_vie_ptr network_; + scoped_vie_ptr render_; + scoped_vie_ptr rtp_; + scoped_vie_ptr image_; + scoped_vie_ptr ext_codec_; +}; + +// Adds indirection to static WebRtc functions, allowing them to be mocked. +class ViETraceWrapper { + public: + virtual ~ViETraceWrapper() {} + + virtual int SetTraceFilter(const unsigned int filter) { + return webrtc::VideoEngine::SetTraceFilter(filter); + } + virtual int SetTraceFile(const char* fileNameUTF8) { + return webrtc::VideoEngine::SetTraceFile(fileNameUTF8); + } + virtual int SetTraceCallback(webrtc::TraceCallback* callback) { + return webrtc::VideoEngine::SetTraceCallback(callback); + } +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTCVIE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvoe.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvoe.h new file mode 100644 index 0000000..c0cb698 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvoe.h @@ -0,0 +1,179 @@ +/* + * 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_WEBRTCVOE_H_ +#define TALK_MEDIA_WEBRTCVOE_H_ + +#include "talk/base/common.h" +#include "talk/media/webrtc/webrtccommon.h" + +#include "webrtc/common_types.h" +#include "webrtc/modules/audio_device/include/audio_device.h" +#include "webrtc/voice_engine/include/voe_audio_processing.h" +#include "webrtc/voice_engine/include/voe_base.h" +#include "webrtc/voice_engine/include/voe_codec.h" +#include "webrtc/voice_engine/include/voe_dtmf.h" +#include "webrtc/voice_engine/include/voe_errors.h" +#include "webrtc/voice_engine/include/voe_external_media.h" +#include "webrtc/voice_engine/include/voe_file.h" +#include "webrtc/voice_engine/include/voe_hardware.h" +#include "webrtc/voice_engine/include/voe_neteq_stats.h" +#include "webrtc/voice_engine/include/voe_network.h" +#include "webrtc/voice_engine/include/voe_rtp_rtcp.h" +#include "webrtc/voice_engine/include/voe_video_sync.h" +#include "webrtc/voice_engine/include/voe_volume_control.h" + +namespace cricket { +// automatically handles lifetime of WebRtc VoiceEngine +class scoped_voe_engine { + public: + explicit scoped_voe_engine(webrtc::VoiceEngine* e) : ptr(e) {} + // VERIFY, to ensure that there are no leaks at shutdown + ~scoped_voe_engine() { if (ptr) VERIFY(webrtc::VoiceEngine::Delete(ptr)); } + // Releases the current pointer. + void reset() { + if (ptr) { + VERIFY(webrtc::VoiceEngine::Delete(ptr)); + ptr = NULL; + } + } + webrtc::VoiceEngine* get() const { return ptr; } + private: + webrtc::VoiceEngine* ptr; +}; + +// scoped_ptr class to handle obtaining and releasing WebRTC interface pointers +template +class scoped_voe_ptr { + public: + explicit scoped_voe_ptr(const scoped_voe_engine& e) + : ptr(T::GetInterface(e.get())) {} + explicit scoped_voe_ptr(T* p) : ptr(p) {} + ~scoped_voe_ptr() { if (ptr) ptr->Release(); } + T* operator->() const { return ptr; } + T* get() const { return ptr; } + + // Releases the current pointer. + void reset() { + if (ptr) { + ptr->Release(); + ptr = NULL; + } + } + + private: + T* ptr; +}; + +// Utility class for aggregating the various WebRTC interface. +// Fake implementations can also be injected for testing. +class VoEWrapper { + public: + VoEWrapper() + : engine_(webrtc::VoiceEngine::Create()), processing_(engine_), + base_(engine_), codec_(engine_), dtmf_(engine_), file_(engine_), + hw_(engine_), media_(engine_), neteq_(engine_), network_(engine_), + rtp_(engine_), sync_(engine_), volume_(engine_) { + } + VoEWrapper(webrtc::VoEAudioProcessing* processing, + webrtc::VoEBase* base, + webrtc::VoECodec* codec, + webrtc::VoEDtmf* dtmf, + webrtc::VoEFile* file, + webrtc::VoEHardware* hw, + webrtc::VoEExternalMedia* media, + webrtc::VoENetEqStats* neteq, + webrtc::VoENetwork* network, + webrtc::VoERTP_RTCP* rtp, + webrtc::VoEVideoSync* sync, + webrtc::VoEVolumeControl* volume) + : engine_(NULL), + processing_(processing), + base_(base), + codec_(codec), + dtmf_(dtmf), + file_(file), + hw_(hw), + media_(media), + neteq_(neteq), + network_(network), + rtp_(rtp), + sync_(sync), + volume_(volume) { + } + ~VoEWrapper() {} + webrtc::VoiceEngine* engine() const { return engine_.get(); } + webrtc::VoEAudioProcessing* processing() const { return processing_.get(); } + webrtc::VoEBase* base() const { return base_.get(); } + webrtc::VoECodec* codec() const { return codec_.get(); } + webrtc::VoEDtmf* dtmf() const { return dtmf_.get(); } + webrtc::VoEFile* file() const { return file_.get(); } + webrtc::VoEHardware* hw() const { return hw_.get(); } + webrtc::VoEExternalMedia* media() const { return media_.get(); } + webrtc::VoENetEqStats* neteq() const { return neteq_.get(); } + webrtc::VoENetwork* network() const { return network_.get(); } + webrtc::VoERTP_RTCP* rtp() const { return rtp_.get(); } + webrtc::VoEVideoSync* sync() const { return sync_.get(); } + webrtc::VoEVolumeControl* volume() const { return volume_.get(); } + int error() { return base_->LastError(); } + + private: + scoped_voe_engine engine_; + scoped_voe_ptr processing_; + scoped_voe_ptr base_; + scoped_voe_ptr codec_; + scoped_voe_ptr dtmf_; + scoped_voe_ptr file_; + scoped_voe_ptr hw_; + scoped_voe_ptr media_; + scoped_voe_ptr neteq_; + scoped_voe_ptr network_; + scoped_voe_ptr rtp_; + scoped_voe_ptr sync_; + scoped_voe_ptr volume_; +}; + +// Adds indirection to static WebRtc functions, allowing them to be mocked. +class VoETraceWrapper { + public: + virtual ~VoETraceWrapper() {} + + virtual int SetTraceFilter(const unsigned int filter) { + return webrtc::VoiceEngine::SetTraceFilter(filter); + } + virtual int SetTraceFile(const char* fileNameUTF8) { + return webrtc::VoiceEngine::SetTraceFile(fileNameUTF8); + } + virtual int SetTraceCallback(webrtc::TraceCallback* callback) { + return webrtc::VoiceEngine::SetTraceCallback(callback); + } +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTCVOE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvoiceengine.h b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvoiceengine.h new file mode 100644 index 0000000..bf27085 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/media/webrtc/webrtcvoiceengine.h @@ -0,0 +1,464 @@ +/* + * 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_WEBRTCVOICEENGINE_H_ +#define TALK_MEDIA_WEBRTCVOICEENGINE_H_ + +#include +#include +#include +#include + +#include "talk/base/buffer.h" +#include "talk/base/byteorder.h" +#include "talk/base/logging.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/stream.h" +#include "talk/media/base/rtputils.h" +#include "talk/media/webrtc/webrtccommon.h" +#include "talk/media/webrtc/webrtcexport.h" +#include "talk/media/webrtc/webrtcvoe.h" +#include "talk/session/media/channel.h" +#include "webrtc/common.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 +// passed into WebRtc, and support looping. +class WebRtcSoundclipStream : public webrtc::InStream { + public: + WebRtcSoundclipStream(const char* buf, size_t len) + : mem_(buf, len), loop_(true) { + } + void set_loop(bool loop) { loop_ = loop; } + virtual int Read(void* buf, int len); + virtual int Rewind(); + + private: + talk_base::MemoryStream mem_; + bool loop_; +}; + +// WebRtcMonitorStream is used to monitor a stream coming from WebRtc. +// For now we just dump the data. +class WebRtcMonitorStream : public webrtc::OutStream { + virtual bool Write(const void *buf, int len) { + return true; + } +}; + +class AudioDeviceModule; +class AudioRenderer; +class VoETraceWrapper; +class VoEWrapper; +class VoiceProcessor; +class WebRtcSoundclipMedia; +class WebRtcVoiceMediaChannel; + +// WebRtcVoiceEngine is a class to be used with CompositeMediaEngine. +// It uses the WebRtc VoiceEngine library for audio handling. +class WebRtcVoiceEngine + : public webrtc::VoiceEngineObserver, + public webrtc::TraceCallback, + public webrtc::VoEMediaProcess { + public: + WebRtcVoiceEngine(); + // Dependency injection for testing. + WebRtcVoiceEngine(VoEWrapper* voe_wrapper, + VoEWrapper* voe_wrapper_sc, + VoETraceWrapper* tracing); + ~WebRtcVoiceEngine(); + bool Init(talk_base::Thread* worker_thread); + void Terminate(); + + int GetCapabilities(); + VoiceMediaChannel* CreateChannel(); + + SoundclipMedia* CreateSoundclip(); + + AudioOptions GetOptions() const { return options_; } + bool SetOptions(const AudioOptions& options); + // Overrides, when set, take precedence over the options on a + // per-option basis. For example, if AGC is set in options and AEC + // is set in overrides, AGC and AEC will be both be set. Overrides + // can also turn off options. For example, if AGC is set to "on" in + // options and AGC is set to "off" in overrides, the result is that + // AGC will be off until different overrides are applied or until + // the overrides are cleared. Only one set of overrides is present + // at a time (they do not "stack"). And when the overrides are + // cleared, the media engine's state reverts back to the options set + // via SetOptions. This allows us to have both "persistent options" + // (the normal options) and "temporary options" (overrides). + bool SetOptionOverrides(const AudioOptions& options); + bool ClearOptionOverrides(); + bool SetDelayOffset(int offset); + bool SetDevices(const Device* in_device, const Device* out_device); + bool GetOutputVolume(int* level); + bool SetOutputVolume(int level); + int GetInputLevel(); + bool SetLocalMonitor(bool enable); + + const std::vector& codecs(); + bool FindCodec(const AudioCodec& codec); + bool FindWebRtcCodec(const AudioCodec& codec, webrtc::CodecInst* gcodec); + + const std::vector& rtp_header_extensions() const; + + void SetLogging(int min_sev, const char* filter); + + bool RegisterProcessor(uint32 ssrc, + VoiceProcessor* voice_processor, + MediaProcessorDirection direction); + bool UnregisterProcessor(uint32 ssrc, + VoiceProcessor* voice_processor, + MediaProcessorDirection direction); + + // Method from webrtc::VoEMediaProcess + virtual void Process(int channel, + webrtc::ProcessingTypes type, + int16_t audio10ms[], + int length, + int sampling_freq, + bool is_stereo); + + // For tracking WebRtc channels. Needed because we have to pause them + // all when switching devices. + // May only be called by WebRtcVoiceMediaChannel. + void RegisterChannel(WebRtcVoiceMediaChannel *channel); + void UnregisterChannel(WebRtcVoiceMediaChannel *channel); + + // May only be called by WebRtcSoundclipMedia. + void RegisterSoundclip(WebRtcSoundclipMedia *channel); + void UnregisterSoundclip(WebRtcSoundclipMedia *channel); + + // Called by WebRtcVoiceMediaChannel to set a gain offset from + // the default AGC target level. + bool AdjustAgcLevel(int delta); + + VoEWrapper* voe() { return voe_wrapper_.get(); } + VoEWrapper* voe_sc() { return voe_wrapper_sc_.get(); } + int GetLastEngineError(); + + // Set the external ADMs. This can only be called before Init. + 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); + + // Create a VoiceEngine Channel. + int CreateMediaVoiceChannel(); + int CreateSoundclipVoiceChannel(); + + private: + typedef std::vector SoundclipList; + typedef std::vector ChannelList; + typedef sigslot:: + signal3 FrameSignal; + + void Construct(); + void ConstructCodecs(); + bool InitInternal(); + bool EnsureSoundclipEngineInit(); + void SetTraceFilter(int filter); + void SetTraceOptions(const std::string& options); + // Applies either options or overrides. Every option that is "set" + // will be applied. Every option not "set" will be ignored. This + // allows us to selectively turn on and off different options easily + // at any time. + bool ApplyOptions(const AudioOptions& options); + 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 + // set the output parameter rtc_id if successful. + bool FindWebRtcAudioDeviceId( + bool is_input, const std::string& dev_name, int dev_id, int* rtc_id); + bool FindChannelAndSsrc(int channel_num, + WebRtcVoiceMediaChannel** channel, + uint32* ssrc) const; + bool FindChannelNumFromSsrc(uint32 ssrc, + MediaProcessorDirection direction, + int* channel_num); + bool ChangeLocalMonitor(bool enable); + bool PauseLocalMonitor(); + bool ResumeLocalMonitor(); + + bool UnregisterProcessorChannel(MediaProcessorDirection channel_direction, + uint32 ssrc, + VoiceProcessor* voice_processor, + MediaProcessorDirection processor_direction); + + void StartAecDump(const std::string& filename); + void StopAecDump(); + int CreateVoiceChannel(VoEWrapper* voe); + + // When a voice processor registers with the engine, it is connected + // to either the Rx or Tx signals, based on the direction parameter. + // SignalXXMediaFrame will be invoked for every audio packet. + FrameSignal SignalRxMediaFrame; + FrameSignal SignalTxMediaFrame; + + static const int kDefaultLogSeverity = talk_base::LS_WARNING; + + // The primary instance of WebRtc VoiceEngine. + talk_base::scoped_ptr voe_wrapper_; + // A secondary instance, for playing out soundclips (on the 'ring' device). + talk_base::scoped_ptr voe_wrapper_sc_; + bool voe_wrapper_sc_initialized_; + talk_base::scoped_ptr tracing_; + // The external audio device manager + webrtc::AudioDeviceModule* adm_; + webrtc::AudioDeviceModule* adm_sc_; + int log_filter_; + std::string log_options_; + bool is_dumping_aec_; + std::vector codecs_; + std::vector rtp_header_extensions_; + bool desired_local_monitor_enable_; + talk_base::scoped_ptr monitor_; + SoundclipList soundclips_; + ChannelList channels_; + // channels_ can be read from WebRtc callback thread. We need a lock on that + // callback as well as the RegisterChannel/UnregisterChannel. + talk_base::CriticalSection channels_cs_; + webrtc::AgcConfig default_agc_config_; + + webrtc::Config voe_config_; + + bool initialized_; + // See SetOptions and SetOptionOverrides for a description of the + // difference between options and overrides. + // options_ are the base options, which combined with the + // option_overrides_, create the current options being used. + // options_ is stored so that when option_overrides_ is cleared, we + // can restore the options_ without the option_overrides. + AudioOptions options_; + AudioOptions option_overrides_; + + // When the media processor registers with the engine, the ssrc is cached + // here so that a look up need not be made when the callback is invoked. + // This is necessary because the lookup results in mux_channels_cs lock being + // held and if a remote participant leaves the hangout at the same time + // we hit a deadlock. + uint32 tx_processor_ssrc_; + uint32 rx_processor_ssrc_; + + talk_base::CriticalSection signal_media_critical_; +}; + +// WebRtcMediaChannel is a class that implements the common WebRtc channel +// functionality. +template +class WebRtcMediaChannel : public T, public webrtc::Transport { + public: + WebRtcMediaChannel(E *engine, int channel) + : engine_(engine), voe_channel_(channel) {} + E *engine() { return engine_; } + int voe_channel() const { return voe_channel_; } + bool valid() const { return voe_channel_ != -1; } + + protected: + // implements Transport interface + virtual int SendPacket(int channel, const void *data, int len) { + talk_base::Buffer packet(data, len, kMaxRtpPacketLen); + if (!T::SendPacket(&packet)) { + return -1; + } + return len; + } + + virtual int SendRTCPPacket(int channel, const void *data, int len) { + talk_base::Buffer packet(data, len, kMaxRtpPacketLen); + return T::SendRtcp(&packet) ? len : -1; + } + + private: + E *engine_; + int voe_channel_; +}; + +// WebRtcVoiceMediaChannel is an implementation of VoiceMediaChannel that uses +// WebRtc Voice Engine. +class WebRtcVoiceMediaChannel + : public WebRtcMediaChannel { + public: + explicit WebRtcVoiceMediaChannel(WebRtcVoiceEngine *engine); + virtual ~WebRtcVoiceMediaChannel(); + virtual bool SetOptions(const AudioOptions& options); + virtual bool GetOptions(AudioOptions* options) const { + *options = options_; + return true; + } + virtual bool SetRecvCodecs(const std::vector &codecs); + virtual bool SetSendCodecs(const std::vector &codecs); + virtual bool SetRecvRtpHeaderExtensions( + const std::vector& extensions); + virtual bool SetSendRtpHeaderExtensions( + const std::vector& extensions); + virtual bool SetPlayout(bool playout); + bool PausePlayout(); + bool ResumePlayout(); + virtual bool SetSend(SendFlags send); + bool PauseSend(); + bool ResumeSend(); + virtual bool AddSendStream(const StreamParams& sp); + virtual bool RemoveSendStream(uint32 ssrc); + virtual bool AddRecvStream(const StreamParams& sp); + virtual bool RemoveRecvStream(uint32 ssrc); + virtual bool SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer); + virtual bool SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer); + virtual bool GetActiveStreams(AudioInfo::StreamList* actives); + virtual int GetOutputLevel(); + virtual int GetTimeSinceLastTyping(); + virtual void SetTypingDetectionParameters(int time_window, + int cost_per_typing, int reporting_threshold, int penalty_decay, + int type_event_delay); + virtual bool SetOutputScaling(uint32 ssrc, double left, double right); + virtual bool GetOutputScaling(uint32 ssrc, double* left, double* right); + + virtual bool SetRingbackTone(const char *buf, int len); + virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop); + virtual bool CanInsertDtmf(); + virtual bool InsertDtmf(uint32 ssrc, int event, int duration, int flags); + + virtual void OnPacketReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + virtual void OnRtcpReceived(talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + virtual void OnReadyToSend(bool ready) {} + virtual bool MuteStream(uint32 ssrc, bool on); + 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. + virtual void GetLastMediaError(uint32* ssrc, + VoiceMediaChannel::Error* error); + bool FindSsrc(int channel_num, uint32* ssrc); + void OnError(uint32 ssrc, int error); + + bool sending() const { return send_ != SEND_NOTHING; } + int GetReceiveChannelNum(uint32 ssrc); + int GetSendChannelNum(uint32 ssrc); + + protected: + int GetLastEngineError() { return engine()->GetLastEngineError(); } + int GetOutputLevel(int channel); + bool GetRedSendCodec(const AudioCodec& red_codec, + const std::vector& all_codecs, + webrtc::CodecInst* send_codec); + bool EnableRtcp(int channel); + bool ResetRecvCodecs(int channel); + bool SetPlayout(int channel, bool playout); + static uint32 ParseSsrc(const void* data, size_t len, bool rtcp); + static Error WebRtcErrorToChannelError(int err_code); + + private: + 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 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); + bool SetSendCodec(const webrtc::CodecInst& send_codec); + bool SetSendCodec(int channel, const webrtc::CodecInst& send_codec); + bool ChangePlayout(bool playout); + bool ChangeSend(SendFlags send); + bool ChangeSend(int channel, SendFlags send); + void ConfigureSendChannel(int channel); + bool ConfigureRecvChannel(int channel); + bool DeleteChannel(int channel); + bool InConferenceMode() const { + return options_.conference_mode.GetWithDefaultIfUnset(false); + } + bool IsDefaultChannel(int channel_id) const { + return channel_id == voe_channel(); + } + bool SetSendCodecs(int channel, const std::vector& codecs); + bool SetSendBandwidthInternal(int bps); + + bool SetHeaderExtension(ExtensionSetterFunction setter, int channel_id, + const RtpHeaderExtension* extension); + + bool SetChannelRecvRtpHeaderExtensions( + int channel_id, + const std::vector& extensions); + bool SetChannelSendRtpHeaderExtensions( + int channel_id, + const std::vector& extensions); + + talk_base::scoped_ptr ringback_tone_; + std::set ringback_channels_; // channels playing ringback + std::vector recv_codecs_; + std::vector send_codecs_; + talk_base::scoped_ptr send_codec_; + bool send_bw_setting_; + int send_bw_bps_; + AudioOptions options_; + bool dtmf_allowed_; + bool desired_playout_; + bool nack_enabled_; + bool playout_; + bool typing_noise_detected_; + SendFlags desired_send_; + SendFlags send_; + + // send_channels_ contains the channels which are being used for sending. + // When the default channel (voe_channel) is used for sending, it is + // contained in send_channels_, otherwise not. + ChannelMap send_channels_; + std::vector 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 + // case it will only be there if a non-zero default_receive_ssrc_ is set. + ChannelMap receive_channels_; // for multiple sources + // receive_channels_ can be read from WebRtc callback thread. Access from + // the WebRtc thread must be synchronized with edits on the worker thread. + // Reads on the worker thread are ok. + // + std::vector receive_extensions_; + // Do not lock this on the VoE media processor thread; potential for deadlock + // exists. + mutable talk_base::CriticalSection receive_channels_cs_; +}; + +} // namespace cricket + +#endif // TALK_MEDIA_WEBRTCVOICEENGINE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/asyncstuntcpsocket.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/asyncstuntcpsocket.h new file mode 100644 index 0000000..fca75e0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/asyncstuntcpsocket.h @@ -0,0 +1,67 @@ +/* + * 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_ASYNCSTUNTCPSOCKET_H_ +#define TALK_BASE_ASYNCSTUNTCPSOCKET_H_ + +#include "talk/base/asynctcpsocket.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/socketfactory.h" + +namespace cricket { + +class AsyncStunTCPSocket : public talk_base::AsyncTCPSocketBase { + public: + // Binds and connects |socket| and creates AsyncTCPSocket for + // it. Takes ownership of |socket|. Returns NULL if bind() or + // connect() fail (|socket| is destroyed in that case). + static AsyncStunTCPSocket* Create( + talk_base::AsyncSocket* socket, + const talk_base::SocketAddress& bind_address, + const talk_base::SocketAddress& remote_address); + + AsyncStunTCPSocket(talk_base::AsyncSocket* socket, bool listen); + virtual ~AsyncStunTCPSocket() {} + + 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(talk_base::AsyncSocket* socket); + + private: + // This method returns the message hdr + length written in the header. + // This method also returns the number of padding bytes needed/added to the + // turn message. |pad_bytes| should be used only when |is_turn| is true. + size_t GetExpectedLength(const void* data, size_t len, + int* pad_bytes); + + DISALLOW_EVIL_CONSTRUCTORS(AsyncStunTCPSocket); +}; + +} // namespace cricket + +#endif // TALK_BASE_ASYNCSTUNTCPSOCKET_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/basicpacketsocketfactory.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/basicpacketsocketfactory.h new file mode 100644 index 0000000..031669b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/basicpacketsocketfactory.h @@ -0,0 +1,68 @@ +/* + * 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_BASE_BASICPACKETSOCKETFACTORY_H_ +#define TALK_BASE_BASICPACKETSOCKETFACTORY_H_ + +#include "talk/p2p/base/packetsocketfactory.h" + +namespace talk_base { + +class AsyncSocket; +class SocketFactory; +class Thread; + +class BasicPacketSocketFactory : public PacketSocketFactory { + public: + BasicPacketSocketFactory(); + explicit BasicPacketSocketFactory(Thread* thread); + explicit BasicPacketSocketFactory(SocketFactory* socket_factory); + virtual ~BasicPacketSocketFactory(); + + virtual AsyncPacketSocket* CreateUdpSocket( + const SocketAddress& local_address, int min_port, int max_port); + virtual AsyncPacketSocket* CreateServerTcpSocket( + const SocketAddress& local_address, int min_port, int max_port, int opts); + virtual AsyncPacketSocket* CreateClientTcpSocket( + const SocketAddress& local_address, const SocketAddress& remote_address, + const ProxyInfo& proxy_info, const std::string& user_agent, int opts); + + virtual AsyncResolverInterface* CreateAsyncResolver(); + + private: + int BindSocket(AsyncSocket* socket, const SocketAddress& local_address, + int min_port, int max_port); + + SocketFactory* socket_factory(); + + Thread* thread_; + SocketFactory* socket_factory_; +}; + +} // namespace talk_base + +#endif // TALK_BASE_BASICPACKETSOCKETFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/candidate.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/candidate.h new file mode 100644 index 0000000..590d5cf --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/candidate.h @@ -0,0 +1,222 @@ +/* + * 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 TALK_P2P_BASE_CANDIDATE_H_ +#define TALK_P2P_BASE_CANDIDATE_H_ + +#include +#include + +#include +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/socketaddress.h" +#include "talk/p2p/base/constants.h" + +namespace cricket { + +// Candidate for ICE based connection discovery. + +class Candidate { + public: + // TODO: Match the ordering and param list as per RFC 5245 + // candidate-attribute syntax. http://tools.ietf.org/html/rfc5245#section-15.1 + Candidate() : component_(0), priority_(0), generation_(0) {} + Candidate(const std::string& id, int component, const std::string& protocol, + const talk_base::SocketAddress& address, uint32 priority, + const std::string& username, const std::string& password, + const std::string& type, const std::string& network_name, + uint32 generation, const std::string& foundation) + : id_(id), component_(component), protocol_(protocol), address_(address), + priority_(priority), username_(username), password_(password), + type_(type), network_name_(network_name), generation_(generation), + foundation_(foundation) { + } + + const std::string & id() const { return id_; } + void set_id(const std::string & id) { id_ = id; } + + int component() const { return component_; } + void set_component(int component) { component_ = component; } + + const std::string & protocol() const { return protocol_; } + void set_protocol(const std::string & protocol) { protocol_ = protocol; } + + const talk_base::SocketAddress & address() const { return address_; } + void set_address(const talk_base::SocketAddress & address) { + address_ = address; + } + + uint32 priority() const { return priority_; } + void set_priority(const uint32 priority) { priority_ = priority; } + +// void set_type_preference(uint32 type_preference) { +// priority_ = GetPriority(type_preference); +// } + + // Maps old preference (which was 0.0-1.0) to match priority (which + // is 0-2^32-1) to to match RFC 5245, section 4.1.2.1. Also see + // https://docs.google.com/a/google.com/document/d/ + // 1iNQDiwDKMh0NQOrCqbj3DKKRT0Dn5_5UJYhmZO-t7Uc/edit + float preference() const { + // The preference value is clamped to two decimal precision. + return static_cast(((priority_ >> 24) * 100 / 127) / 100.0); + } + + void set_preference(float preference) { + // Limiting priority to UINT_MAX when value exceeds uint32 max. + // This can happen for e.g. when preference = 3. + uint64 prio_val = static_cast(preference * 127) << 24; + priority_ = static_cast( + talk_base::_min(prio_val, static_cast(UINT_MAX))); + } + + const std::string & username() const { return username_; } + void set_username(const std::string & username) { username_ = username; } + + const std::string & password() const { return password_; } + void set_password(const std::string & password) { password_ = password; } + + const std::string & type() const { return type_; } + void set_type(const std::string & type) { type_ = type; } + + const std::string & network_name() const { return network_name_; } + void set_network_name(const std::string & network_name) { + network_name_ = network_name; + } + + // Candidates in a new generation replace those in the old generation. + uint32 generation() const { return generation_; } + void set_generation(uint32 generation) { generation_ = generation; } + const std::string generation_str() const { + std::ostringstream ost; + ost << generation_; + return ost.str(); + } + void set_generation_str(const std::string& str) { + std::istringstream ist(str); + ist >> generation_; + } + + const std::string& foundation() const { + return foundation_; + } + + void set_foundation(const std::string& foundation) { + foundation_ = foundation; + } + + const talk_base::SocketAddress & related_address() const { + return related_address_; + } + void set_related_address( + const talk_base::SocketAddress & related_address) { + related_address_ = related_address; + } + + // Determines whether this candidate is equivalent to the given one. + bool IsEquivalent(const Candidate& c) const { + // We ignore the network name, since that is just debug information, and + // the priority, since that should be the same if the rest is (and it's + // a float so equality checking is always worrisome). + return (id_ == c.id_) && + (component_ == c.component_) && + (protocol_ == c.protocol_) && + (address_ == c.address_) && + (username_ == c.username_) && + (password_ == c.password_) && + (type_ == c.type_) && + (generation_ == c.generation_) && + (foundation_ == c.foundation_) && + (related_address_ == c.related_address_); + } + + std::string ToString() const { + return ToStringInternal(false); + } + + std::string ToSensitiveString() const { + return ToStringInternal(true); + } + + 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()); + int local_preference = (network_adapter_preference << 8) | addr_pref; + + return (type_preference << 24) | + (local_preference << 8) | + (256 - component_); + } + + private: + std::string ToStringInternal(bool sensitive) const { + std::ostringstream ost; + std::string address = sensitive ? address_.ToSensitiveString() : + address_.ToString(); + ost << "Cand[" << foundation_ << ":" << component_ << ":" + << protocol_ << ":" << priority_ << ":" + << address << ":" << type_ << ":" << related_address_ << ":" + << username_ << ":" << password_ << "]"; + return ost.str(); + } + + std::string id_; + int component_; + std::string protocol_; + talk_base::SocketAddress address_; + uint32 priority_; + std::string username_; + std::string password_; + std::string type_; + std::string network_name_; + uint32 generation_; + std::string foundation_; + talk_base::SocketAddress related_address_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_CANDIDATE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/common.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/common.h new file mode 100644 index 0000000..0cdcfb6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/common.h @@ -0,0 +1,37 @@ +/* + * 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 TALK_P2P_BASE_COMMON_H_ +#define TALK_P2P_BASE_COMMON_H_ + +#include "talk/base/logging.h" + +// Common log description format for jingle messages +#define LOG_J(sev, obj) LOG(sev) << "Jingle:" << obj->ToString() << ": " +#define LOG_JV(sev, obj) LOG_V(sev) << "Jingle:" << obj->ToString() << ": " + +#endif // TALK_P2P_BASE_COMMON_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/constants.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/constants.h new file mode 100644 index 0000000..74889c3 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/constants.h @@ -0,0 +1,276 @@ +/* + * 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 TALK_P2P_BASE_CONSTANTS_H_ +#define TALK_P2P_BASE_CONSTANTS_H_ + +#include +#include "talk/xmllite/qname.h" + +// This file contains constants related to signaling that are used in various +// classes in this directory. + +namespace cricket { + +// NS_ == namespace +// QN_ == buzz::QName (namespace + name) +// LN_ == "local name" == QName::LocalPart() +// these are useful when you need to find a tag +// that has different namespaces (like or ) + +extern const char NS_EMPTY[]; +extern const char NS_JINGLE[]; +extern const char NS_JINGLE_DRAFT[]; +extern const char NS_GINGLE[]; + +enum SignalingProtocol { + PROTOCOL_JINGLE, + PROTOCOL_GINGLE, + PROTOCOL_HYBRID, +}; + +// actions (aka Gingle or Jingle ) +extern const buzz::StaticQName QN_ACTION; +extern const char LN_INITIATOR[]; +extern const buzz::StaticQName QN_INITIATOR; +extern const buzz::StaticQName QN_CREATOR; + +extern const buzz::StaticQName QN_JINGLE; +extern const buzz::StaticQName QN_JINGLE_CONTENT; +extern const buzz::StaticQName QN_JINGLE_CONTENT_NAME; +extern const buzz::StaticQName QN_JINGLE_CONTENT_MEDIA; +extern const buzz::StaticQName QN_JINGLE_REASON; +extern const buzz::StaticQName QN_JINGLE_DRAFT_GROUP; +extern const buzz::StaticQName QN_JINGLE_DRAFT_GROUP_TYPE; +extern const char JINGLE_CONTENT_MEDIA_AUDIO[]; +extern const char JINGLE_CONTENT_MEDIA_VIDEO[]; +extern const char JINGLE_CONTENT_MEDIA_DATA[]; +extern const char JINGLE_ACTION_SESSION_INITIATE[]; +extern const char JINGLE_ACTION_SESSION_INFO[]; +extern const char JINGLE_ACTION_SESSION_ACCEPT[]; +extern const char JINGLE_ACTION_SESSION_TERMINATE[]; +extern const char JINGLE_ACTION_TRANSPORT_INFO[]; +extern const char JINGLE_ACTION_TRANSPORT_ACCEPT[]; +extern const char JINGLE_ACTION_DESCRIPTION_INFO[]; + +extern const buzz::StaticQName QN_GINGLE_SESSION; +extern const char GINGLE_ACTION_INITIATE[]; +extern const char GINGLE_ACTION_INFO[]; +extern const char GINGLE_ACTION_ACCEPT[]; +extern const char GINGLE_ACTION_REJECT[]; +extern const char GINGLE_ACTION_TERMINATE[]; +extern const char GINGLE_ACTION_CANDIDATES[]; +extern const char GINGLE_ACTION_UPDATE[]; + +extern const char LN_ERROR[]; +extern const buzz::StaticQName QN_GINGLE_REDIRECT; +extern const char STR_REDIRECT_PREFIX[]; + +// Session Contents (aka Gingle +// or Jingle ) +extern const char LN_DESCRIPTION[]; +extern const char LN_PAYLOADTYPE[]; +extern const buzz::StaticQName QN_ID; +extern const buzz::StaticQName QN_SID; +extern const buzz::StaticQName QN_NAME; +extern const buzz::StaticQName QN_CLOCKRATE; +extern const buzz::StaticQName QN_BITRATE; +extern const buzz::StaticQName QN_CHANNELS; +extern const buzz::StaticQName QN_PARAMETER; +extern const char LN_NAME[]; +extern const char LN_VALUE[]; +extern const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_NAME; +extern const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_VALUE; +extern const char PAYLOADTYPE_PARAMETER_BITRATE[]; +extern const char PAYLOADTYPE_PARAMETER_HEIGHT[]; +extern const char PAYLOADTYPE_PARAMETER_WIDTH[]; +extern const char PAYLOADTYPE_PARAMETER_FRAMERATE[]; +extern const char LN_BANDWIDTH[]; + +// CN_ == "content name". When we initiate a session, we choose the +// name, and when we receive a Gingle session, we provide default +// names (since Gingle has no content names). But when we receive a +// Jingle call, the content name can be anything, so don't rely on +// these values being the same as the ones received. +extern const char CN_AUDIO[]; +extern const char CN_VIDEO[]; +extern const char CN_DATA[]; +extern const char CN_OTHER[]; +// other SDP related strings +// GN stands for group name +extern const char GROUP_TYPE_BUNDLE[]; + +extern const char NS_JINGLE_RTP[]; +extern const buzz::StaticQName QN_JINGLE_RTP_CONTENT; +extern const buzz::StaticQName QN_SSRC; +extern const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE; +extern const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH; +extern const buzz::StaticQName QN_JINGLE_RTCP_MUX; +extern const buzz::StaticQName QN_JINGLE_RTCP_FB; +extern const buzz::StaticQName QN_SUBTYPE; +extern const buzz::StaticQName QN_JINGLE_RTP_HDREXT; +extern const buzz::StaticQName QN_URI; + +extern const char NS_JINGLE_DRAFT_SCTP[]; +extern const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_CONTENT; +extern const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_STREAM; + +extern const char NS_GINGLE_AUDIO[]; +extern const buzz::StaticQName QN_GINGLE_AUDIO_CONTENT; +extern const buzz::StaticQName QN_GINGLE_AUDIO_PAYLOADTYPE; +extern const buzz::StaticQName QN_GINGLE_AUDIO_SRCID; +extern const char NS_GINGLE_VIDEO[]; +extern const buzz::StaticQName QN_GINGLE_VIDEO_CONTENT; +extern const buzz::StaticQName QN_GINGLE_VIDEO_PAYLOADTYPE; +extern const buzz::StaticQName QN_GINGLE_VIDEO_SRCID; +extern const buzz::StaticQName QN_GINGLE_VIDEO_BANDWIDTH; + +// Crypto support. +extern const buzz::StaticQName QN_ENCRYPTION; +extern const buzz::StaticQName QN_ENCRYPTION_REQUIRED; +extern const buzz::StaticQName QN_CRYPTO; +extern const buzz::StaticQName QN_GINGLE_AUDIO_CRYPTO_USAGE; +extern const buzz::StaticQName QN_GINGLE_VIDEO_CRYPTO_USAGE; +extern const buzz::StaticQName QN_CRYPTO_SUITE; +extern const buzz::StaticQName QN_CRYPTO_KEY_PARAMS; +extern const buzz::StaticQName QN_CRYPTO_TAG; +extern const buzz::StaticQName QN_CRYPTO_SESSION_PARAMS; + +// Transports and candidates. +extern const char LN_TRANSPORT[]; +extern const char LN_CANDIDATE[]; +extern const buzz::StaticQName QN_JINGLE_P2P_TRANSPORT; +extern const buzz::StaticQName QN_JINGLE_P2P_CANDIDATE; +extern const buzz::StaticQName QN_UFRAG; +extern const buzz::StaticQName QN_COMPONENT; +extern const buzz::StaticQName QN_PWD; +extern const buzz::StaticQName QN_IP; +extern const buzz::StaticQName QN_PORT; +extern const buzz::StaticQName QN_NETWORK; +extern const buzz::StaticQName QN_GENERATION; +extern const buzz::StaticQName QN_PRIORITY; +extern const buzz::StaticQName QN_PROTOCOL; +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; + +extern const buzz::StaticQName QN_FINGERPRINT; +extern const buzz::StaticQName QN_FINGERPRINT_ALGORITHM; +extern const buzz::StaticQName QN_FINGERPRINT_DIGEST; + +extern const char NS_JINGLE_ICE_UDP[]; + +extern const char ICE_OPTION_GICE[]; +extern const char NS_GINGLE_P2P[]; +extern const buzz::StaticQName QN_GINGLE_P2P_TRANSPORT; +extern const buzz::StaticQName QN_GINGLE_P2P_CANDIDATE; +extern const buzz::StaticQName QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME; +extern const buzz::StaticQName QN_GINGLE_CANDIDATE; +extern const buzz::StaticQName QN_ADDRESS; +extern const buzz::StaticQName QN_USERNAME; +extern const buzz::StaticQName QN_PASSWORD; +extern const buzz::StaticQName QN_PREFERENCE; +extern const char GINGLE_CANDIDATE_TYPE_STUN[]; +extern const char GICE_CHANNEL_NAME_RTP[]; +extern const char GICE_CHANNEL_NAME_RTCP[]; +extern const char GICE_CHANNEL_NAME_VIDEO_RTP[]; +extern const char GICE_CHANNEL_NAME_VIDEO_RTCP[]; +extern const char GICE_CHANNEL_NAME_DATA_RTP[]; +extern const char GICE_CHANNEL_NAME_DATA_RTCP[]; + +extern const char NS_GINGLE_RAW[]; +extern const buzz::StaticQName QN_GINGLE_RAW_TRANSPORT; +extern const buzz::StaticQName QN_GINGLE_RAW_CHANNEL; + +// terminate reasons and errors: see http://xmpp.org/extensions/xep-0166.html +extern const char JINGLE_ERROR_BAD_REQUEST[]; // like parse error +// got transport-info before session-initiate, for example +extern const char JINGLE_ERROR_OUT_OF_ORDER[]; +extern const char JINGLE_ERROR_UNKNOWN_SESSION[]; + +// Call terminate reasons from XEP-166 +extern const char STR_TERMINATE_DECLINE[]; // polite reject +extern const char STR_TERMINATE_SUCCESS[]; // polite hangup +extern const char STR_TERMINATE_ERROR[]; // something bad happened +extern const char STR_TERMINATE_INCOMPATIBLE_PARAMETERS[]; // no codecs? + +// Old terminate reasons used by cricket +extern const char STR_TERMINATE_CALL_ENDED[]; +extern const char STR_TERMINATE_RECIPIENT_UNAVAILABLE[]; +extern const char STR_TERMINATE_RECIPIENT_BUSY[]; +extern const char STR_TERMINATE_INSUFFICIENT_FUNDS[]; +extern const char STR_TERMINATE_NUMBER_MALFORMED[]; +extern const char STR_TERMINATE_NUMBER_DISALLOWED[]; +extern const char STR_TERMINATE_PROTOCOL_ERROR[]; +extern const char STR_TERMINATE_INTERNAL_SERVER_ERROR[]; +extern const char STR_TERMINATE_UNKNOWN_ERROR[]; + +// Draft view and notify messages. +extern const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[]; +extern const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[]; +extern const buzz::StaticQName QN_NICK; +extern const buzz::StaticQName QN_TYPE; +extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW; +extern const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[]; +extern const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[]; +extern const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS; +extern const buzz::StaticQName QN_WIDTH; +extern const buzz::StaticQName QN_HEIGHT; +extern const buzz::StaticQName QN_FRAMERATE; +extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAM; +extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS; +extern const buzz::StaticQName QN_DISPLAY; +extern const buzz::StaticQName QN_CNAME; +extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC; +extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP; +extern const buzz::StaticQName QN_SEMANTICS; +extern const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY; +extern const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE; + +// old stuff +#ifdef FEATURE_ENABLE_VOICEMAIL +extern const char NS_VOICEMAIL[]; +extern const buzz::StaticQName QN_VOICEMAIL_REGARDING; +#endif + +// RFC 4145, SDP setup attribute values. +extern const char CONNECTIONROLE_ACTIVE_STR[]; +extern const char CONNECTIONROLE_PASSIVE_STR[]; +extern const char CONNECTIONROLE_ACTPASS_STR[]; +extern const char CONNECTIONROLE_HOLDCONN_STR[]; + +} // namespace cricket + +#endif // TALK_P2P_BASE_CONSTANTS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/dtlstransport.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/dtlstransport.h new file mode 100644 index 0000000..5070713 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/dtlstransport.h @@ -0,0 +1,256 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_DTLSTRANSPORT_H_ +#define TALK_P2P_BASE_DTLSTRANSPORT_H_ + +#include "talk/p2p/base/dtlstransportchannel.h" +#include "talk/p2p/base/transport.h" + +namespace talk_base { +class SSLIdentity; +} + +namespace cricket { + +class PortAllocator; + +// Base should be a descendant of cricket::Transport +template +class DtlsTransport : public Base { + public: + DtlsTransport(talk_base::Thread* signaling_thread, + talk_base::Thread* worker_thread, + const std::string& content_name, + PortAllocator* allocator, + talk_base::SSLIdentity* identity) + : Base(signaling_thread, worker_thread, content_name, allocator), + identity_(identity) { + } + + ~DtlsTransport() { + Base::DestroyAllChannels(); + } + virtual void SetIdentity_w(talk_base::SSLIdentity* identity) { + identity_ = identity; + } + virtual bool GetIdentity_w(talk_base::SSLIdentity** identity) { + if (!identity_) + return false; + + *identity = identity_->GetReference(); + return true; + } + + virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel, + std::string* error_desc) { + talk_base::SSLFingerprint* local_fp = + Base::local_description()->identity_fingerprint.get(); + + if (local_fp) { + // Sanity check local fingerprint. + if (identity_) { + talk_base::scoped_ptr local_fp_tmp( + talk_base::SSLFingerprint::Create(local_fp->algorithm, + identity_)); + ASSERT(local_fp_tmp.get() != NULL); + if (!(*local_fp_tmp == *local_fp)) { + 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 { + return BadTransportDescription( + "Local fingerprint provided but no identity available.", + error_desc); + } + } else { + identity_ = NULL; + } + + 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, error_desc); + } + + virtual bool NegotiateTransportDescription_w(ContentAction local_role, + std::string* error_desc) { + if (!Base::local_description() || !Base::remote_description()) { + 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 = + Base::local_description()->identity_fingerprint.get(); + talk_base::SSLFingerprint* remote_fp = + Base::remote_description()->identity_fingerprint.get(); + + if (remote_fp && local_fp) { + remote_fingerprint_.reset(new talk_base::SSLFingerprint(*remote_fp)); + + // From RFC 4145, section-4.1, The following are the values that the + // 'setup' attribute can take in an offer/answer exchange: + // Offer Answer + // ________________ + // active passive / holdconn + // passive active / holdconn + // actpass active / passive / holdconn + // holdconn holdconn + // + // Set the role that is most conformant with RFC 5763, Section 5, bullet 1 + // The endpoint MUST use the setup attribute defined in [RFC4145]. + // The endpoint that is the offerer MUST use the setup attribute + // value of setup:actpass and be prepared to receive a client_hello + // before it receives the answer. The answerer MUST use either a + // setup attribute value of setup:active or setup:passive. Note that + // if the answerer uses setup:passive, then the DTLS handshake will + // not begin until the answerer is received, which adds additional + // latency. setup:active allows the answer and the DTLS handshake to + // occur in parallel. Thus, setup:active is RECOMMENDED. Whichever + // party is active MUST initiate a DTLS handshake by sending a + // ClientHello over each flow (host/port quartet). + // IOW - actpass and passive modes should be treated as server and + // active as client. + ConnectionRole local_connection_role = + Base::local_description()->connection_role; + ConnectionRole remote_connection_role = + Base::remote_description()->connection_role; + + bool is_remote_server = false; + if (local_role == CA_OFFER) { + if (local_connection_role != CONNECTIONROLE_ACTPASS) { + return BadTransportDescription( + "Offerer must use actpass value for setup attribute.", + error_desc); + } + + if (remote_connection_role == CONNECTIONROLE_ACTIVE || + remote_connection_role == CONNECTIONROLE_PASSIVE || + remote_connection_role == CONNECTIONROLE_NONE) { + is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE); + } else { + 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) { + 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 { + 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. + } + + secure_role_ = is_remote_server ? talk_base::SSL_CLIENT : + talk_base::SSL_SERVER; + + } else if (local_fp && (local_role == CA_ANSWER)) { + 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( + "", NULL, 0)); + } + + // Now run the negotiation for the base class. + return Base::NegotiateTransportDescription_w(local_role, error_desc); + } + + virtual DtlsTransportChannelWrapper* CreateTransportChannel(int component) { + return new DtlsTransportChannelWrapper( + this, Base::CreateTransportChannel(component)); + } + + virtual void DestroyTransportChannel(TransportChannelImpl* channel) { + // Kind of ugly, but this lets us do the exact inverse of the create. + DtlsTransportChannelWrapper* dtls_channel = + static_cast(channel); + TransportChannelImpl* base_channel = dtls_channel->channel(); + delete dtls_channel; + Base::DestroyTransportChannel(base_channel); + } + + virtual bool GetSslRole_w(talk_base::SSLRole* ssl_role) const { + ASSERT(ssl_role != NULL); + *ssl_role = secure_role_; + return true; + } + + private: + virtual bool ApplyNegotiatedTransportDescription_w( + 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_)) { + return BadTransportDescription("Failed to set ssl role for the channel.", + error_desc); + } + // Apply remote fingerprint. + if (!channel->SetRemoteFingerprint( + remote_fingerprint_->algorithm, + reinterpret_cast(remote_fingerprint_-> + digest.data()), + remote_fingerprint_->digest.length())) { + return BadTransportDescription("Failed to apply remote fingerprint.", + error_desc); + } + return Base::ApplyNegotiatedTransportDescription_w(channel, error_desc); + } + + talk_base::SSLIdentity* identity_; + talk_base::SSLRole secure_role_; + talk_base::scoped_ptr remote_fingerprint_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_DTLSTRANSPORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/dtlstransportchannel.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/dtlstransportchannel.h new file mode 100644 index 0000000..54cb567 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/dtlstransportchannel.h @@ -0,0 +1,264 @@ +/* + * libjingle + * Copyright 2011, Google Inc. + * Copyright 2011, 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. + */ + +#ifndef TALK_P2P_BASE_DTLSTRANSPORTCHANNEL_H_ +#define TALK_P2P_BASE_DTLSTRANSPORTCHANNEL_H_ + +#include +#include + +#include "talk/base/buffer.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sslstreamadapter.h" +#include "talk/base/stream.h" +#include "talk/p2p/base/transportchannelimpl.h" + +namespace cricket { + +// A bridge between a packet-oriented/channel-type interface on +// the bottom and a StreamInterface on the top. +class StreamInterfaceChannel : public talk_base::StreamInterface, + public sigslot::has_slots<> { + public: + StreamInterfaceChannel(talk_base::Thread* owner, TransportChannel* channel) + : channel_(channel), + state_(talk_base::SS_OPEN), + fifo_(kFifoSize, owner) { + fifo_.SignalEvent.connect(this, &StreamInterfaceChannel::OnEvent); + } + + // Push in a packet; this gets pulled out from Read(). + bool OnPacketReceived(const char* data, size_t size); + + // Implementations of StreamInterface + virtual talk_base::StreamState GetState() const { return state_; } + virtual void Close() { state_ = talk_base::SS_CLOSED; } + virtual talk_base::StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + virtual talk_base::StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + + private: + static const size_t kFifoSize = 8192; + + // Forward events + virtual void OnEvent(talk_base::StreamInterface* stream, int sig, int err); + + TransportChannel* channel_; // owned by DtlsTransportChannelWrapper + talk_base::StreamState state_; + talk_base::FifoBuffer fifo_; + + DISALLOW_COPY_AND_ASSIGN(StreamInterfaceChannel); +}; + + +// This class provides a DTLS SSLStreamAdapter inside a TransportChannel-style +// packet-based interface, wrapping an existing TransportChannel instance +// (e.g a P2PTransportChannel) +// Here's the way this works: +// +// DtlsTransportChannelWrapper { +// SSLStreamAdapter* dtls_ { +// StreamInterfaceChannel downward_ { +// TransportChannelImpl* channel_; +// } +// } +// } +// +// - Data which comes into DtlsTransportChannelWrapper from the underlying +// channel_ via OnReadPacket() is checked for whether it is DTLS +// or not, and if it is, is passed to DtlsTransportChannelWrapper:: +// HandleDtlsPacket, which pushes it into to downward_. +// dtls_ is listening for events on downward_, so it immediately calls +// downward_->Read(). +// +// - Data written to DtlsTransportChannelWrapper is passed either to +// downward_ or directly to channel_, depending on whether DTLS is +// negotiated and whether the flags include PF_SRTP_BYPASS +// +// - The SSLStreamAdapter writes to downward_->Write() +// which translates it into packet writes on channel_. +class DtlsTransportChannelWrapper : public TransportChannelImpl { + public: + enum State { + STATE_NONE, // No state or rejected. + STATE_OFFERED, // Our identity has been set. + STATE_ACCEPTED, // The other side sent a fingerprint. + STATE_STARTED, // We are negotiating. + STATE_OPEN, // Negotiation complete. + STATE_CLOSED // Connection closed. + }; + + // The parameters here are: + // transport -- the DtlsTransport that created us + // channel -- the TransportChannel we are wrapping + DtlsTransportChannelWrapper(Transport* transport, + TransportChannelImpl* channel); + virtual ~DtlsTransportChannelWrapper(); + + virtual void SetIceRole(IceRole role) { + channel_->SetIceRole(role); + } + 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; + + virtual bool SetRemoteFingerprint(const std::string& digest_alg, + const uint8* digest, + size_t digest_len); + virtual bool IsDtlsActive() const { return dtls_state_ != STATE_NONE; } + + // Called to send a packet (via DTLS, if turned on). + virtual int SendPacket(const char* data, size_t size, + const talk_base::PacketOptions& options, + int flags); + + // TransportChannel calls that we forward to the wrapped transport. + virtual int SetOption(talk_base::Socket::Option opt, int value) { + return channel_->SetOption(opt, value); + } + virtual int GetError() { + return channel_->GetError(); + } + virtual bool GetStats(ConnectionInfos* infos) { + return channel_->GetStats(infos); + } + virtual const std::string SessionId() const { + return channel_->SessionId(); + } + + // Set up the ciphers to use for DTLS-SRTP. If this method is not called + // before DTLS starts, or |ciphers| is empty, SRTP keys won't be negotiated. + // This method should be called before SetupDtls. + virtual bool SetSrtpCiphers(const std::vector& ciphers); + + // Find out which DTLS-SRTP cipher was negotiated + virtual bool GetSrtpCipher(std::string* cipher); + + virtual bool GetSslRole(talk_base::SSLRole* role) const; + virtual bool SetSslRole(talk_base::SSLRole role); + + // Once DTLS has been established, this method retrieves the certificate in + // use by the remote peer, for use in external identity verification. + virtual bool GetRemoteCertificate(talk_base::SSLCertificate** cert) const; + + // Once DTLS has established (i.e., this channel is writable), this method + // extracts the keys negotiated during the DTLS handshake, for use in external + // encryption. DTLS-SRTP uses this to extract the needed SRTP keys. + // See the SSLStreamAdapter documentation for info on the specific parameters. + virtual bool ExportKeyingMaterial(const std::string& label, + const uint8* context, + size_t context_len, + bool use_context, + uint8* result, + size_t result_len) { + return (dtls_.get()) ? dtls_->ExportKeyingMaterial(label, context, + context_len, + use_context, + result, result_len) + : false; + } + + // TransportChannelImpl calls. + virtual Transport* GetTransport() { + return transport_; + } + 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); + } + virtual void SetIceCredentials(const std::string& ice_ufrag, + const std::string& ice_pwd) { + channel_->SetIceCredentials(ice_ufrag, ice_pwd); + } + virtual void SetRemoteIceCredentials(const std::string& ice_ufrag, + const std::string& ice_pwd) { + channel_->SetRemoteIceCredentials(ice_ufrag, ice_pwd); + } + virtual void SetRemoteIceMode(IceMode mode) { + channel_->SetRemoteIceMode(mode); + } + + virtual void Connect(); + virtual void Reset(); + + virtual void OnSignalingReady() { + channel_->OnSignalingReady(); + } + virtual void OnCandidate(const Candidate& candidate) { + channel_->OnCandidate(candidate); + } + + // Needed by DtlsTransport. + TransportChannelImpl* channel() { return channel_; } + + private: + void OnReadableState(TransportChannel* channel); + void OnWritableState(TransportChannel* channel); + void OnReadPacket(TransportChannel* channel, const char* data, size_t size, + const talk_base::PacketTime& packet_time, int flags); + void OnReadyToSend(TransportChannel* channel); + void OnDtlsEvent(talk_base::StreamInterface* stream_, int sig, int err); + bool SetupDtls(); + bool MaybeStartDtls(); + bool HandleDtlsPacket(const char* data, size_t size); + void OnRequestSignaling(TransportChannelImpl* channel); + void OnCandidateReady(TransportChannelImpl* channel, const Candidate& c); + 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. + TransportChannelImpl* channel_; // Underlying channel, owned by transport_. + talk_base::scoped_ptr dtls_; // The DTLS stream + StreamInterfaceChannel* downward_; // Wrapper for channel_, owned by dtls_. + std::vector srtp_ciphers_; // SRTP ciphers to use with DTLS. + State dtls_state_; + talk_base::SSLIdentity* local_identity_; + talk_base::SSLRole ssl_role_; + talk_base::Buffer remote_fingerprint_value_; + std::string remote_fingerprint_algorithm_; + + DISALLOW_COPY_AND_ASSIGN(DtlsTransportChannelWrapper); +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_DTLSTRANSPORTCHANNEL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/fakesession.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/fakesession.h new file mode 100644 index 0000000..115cbdb --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/fakesession.h @@ -0,0 +1,509 @@ +/* + * libjingle + * Copyright 2009, 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_P2P_BASE_FAKESESSION_H_ +#define TALK_P2P_BASE_FAKESESSION_H_ + +#include +#include +#include + +#include "talk/base/buffer.h" +#include "talk/base/fakesslidentity.h" +#include "talk/base/sigslot.h" +#include "talk/base/sslfingerprint.h" +#include "talk/base/messagequeue.h" +#include "talk/p2p/base/session.h" +#include "talk/p2p/base/transport.h" +#include "talk/p2p/base/transportchannel.h" +#include "talk/p2p/base/transportchannelimpl.h" + +namespace cricket { + +class FakeTransport; + +struct PacketMessageData : public talk_base::MessageData { + PacketMessageData(const char* data, size_t len) : packet(data, len) { + } + talk_base::Buffer packet; +}; + +// Fake transport channel class, which can be passed to anything that needs a +// transport channel. Can be informed of another FakeTransportChannel via +// SetDestination. +class FakeTransportChannel : public TransportChannelImpl, + public talk_base::MessageHandler { + public: + explicit FakeTransportChannel(Transport* transport, + const std::string& content_name, + int component) + : TransportChannelImpl(content_name, component), + transport_(transport), + dest_(NULL), + state_(STATE_INIT), + async_(false), + identity_(NULL), + do_dtls_(false), + role_(ICEROLE_UNKNOWN), + tiebreaker_(0), + ice_proto_(ICEPROTO_HYBRID), + remote_ice_mode_(ICEMODE_FULL), + dtls_fingerprint_("", NULL, 0), + ssl_role_(talk_base::SSL_CLIENT), + connection_count_(0) { + } + ~FakeTransportChannel() { + Reset(); + } + + uint64 IceTiebreaker() const { return tiebreaker_; } + TransportProtocol protocol() const { return ice_proto_; } + IceMode remote_ice_mode() const { return remote_ice_mode_; } + const std::string& ice_ufrag() const { return ice_ufrag_; } + const std::string& ice_pwd() const { return ice_pwd_; } + const std::string& remote_ice_ufrag() const { return remote_ice_ufrag_; } + const std::string& remote_ice_pwd() const { return remote_ice_pwd_; } + const talk_base::SSLFingerprint& dtls_fingerprint() const { + return dtls_fingerprint_; + } + + void SetAsync(bool async) { + async_ = async; + } + + virtual Transport* GetTransport() { + return transport_; + } + + 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) { + ice_ufrag_ = ice_ufrag; + ice_pwd_ = ice_pwd; + } + virtual void SetRemoteIceCredentials(const std::string& ice_ufrag, + const std::string& ice_pwd) { + remote_ice_ufrag_ = ice_ufrag; + remote_ice_pwd_ = ice_pwd; + } + + virtual void SetRemoteIceMode(IceMode mode) { remote_ice_mode_ = mode; } + virtual bool SetRemoteFingerprint(const std::string& alg, const uint8* digest, + size_t digest_len) { + dtls_fingerprint_ = talk_base::SSLFingerprint(alg, digest, digest_len); + return true; + } + virtual bool SetSslRole(talk_base::SSLRole role) { + ssl_role_ = role; + return true; + } + virtual bool GetSslRole(talk_base::SSLRole* role) const { + *role = ssl_role_; + return true; + } + + virtual void Connect() { + if (state_ == STATE_INIT) { + state_ = STATE_CONNECTING; + } + } + virtual void Reset() { + if (state_ != STATE_INIT) { + state_ = STATE_INIT; + if (dest_) { + dest_->state_ = STATE_INIT; + dest_->dest_ = NULL; + dest_ = NULL; + } + } + } + + void SetWritable(bool writable) { + set_writable(writable); + } + + void SetDestination(FakeTransportChannel* dest) { + if (state_ == STATE_CONNECTING && dest) { + // This simulates the delivery of candidates. + dest_ = dest; + dest_->dest_ = this; + if (identity_ && dest_->identity_) { + do_dtls_ = true; + dest_->do_dtls_ = true; + NegotiateSrtpCiphers(); + } + state_ = STATE_CONNECTED; + dest_->state_ = STATE_CONNECTED; + set_writable(true); + dest_->set_writable(true); + } else if (state_ == STATE_CONNECTED && !dest) { + // Simulates loss of connectivity, by asymmetrically forgetting dest_. + dest_ = NULL; + state_ = STATE_CONNECTING; + set_writable(false); + } + } + + 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, + const talk_base::PacketOptions& options, int flags) { + if (state_ != STATE_CONNECTED) { + return -1; + } + + if (flags != PF_SRTP_BYPASS && flags != 0) { + return -1; + } + + PacketMessageData* packet = new PacketMessageData(data, len); + if (async_) { + talk_base::Thread::Current()->Post(this, 0, packet); + } else { + talk_base::Thread::Current()->Send(this, 0, packet); + } + return static_cast(len); + } + virtual int SetOption(talk_base::Socket::Option opt, int value) { + return true; + } + virtual int GetError() { + return 0; + } + + virtual void OnSignalingReady() { + } + virtual void OnCandidate(const Candidate& candidate) { + } + + virtual void OnMessage(talk_base::Message* msg) { + PacketMessageData* data = static_cast( + msg->pdata); + dest_->SignalReadPacket(dest_, data->packet.data(), + data->packet.length(), + talk_base::CreatePacketTime(0), 0); + delete data; + } + + bool SetLocalIdentity(talk_base::SSLIdentity* identity) { + identity_ = identity; + return true; + } + + + void SetRemoteCertificate(talk_base::FakeSSLCertificate* cert) { + remote_cert_ = cert; + } + + virtual bool IsDtlsActive() const { + return do_dtls_; + } + + virtual bool SetSrtpCiphers(const std::vector& ciphers) { + srtp_ciphers_ = ciphers; + return true; + } + + virtual bool GetSrtpCipher(std::string* cipher) { + if (!chosen_srtp_cipher_.empty()) { + *cipher = chosen_srtp_cipher_; + return true; + } + return false; + } + + virtual bool GetLocalIdentity(talk_base::SSLIdentity** identity) const { + if (!identity_) + return false; + + *identity = identity_->GetReference(); + return true; + } + + virtual bool GetRemoteCertificate(talk_base::SSLCertificate** cert) const { + if (!remote_cert_) + return false; + + *cert = remote_cert_->GetReference(); + return true; + } + + virtual bool ExportKeyingMaterial(const std::string& label, + const uint8* context, + size_t context_len, + bool use_context, + uint8* result, + size_t result_len) { + if (!chosen_srtp_cipher_.empty()) { + memset(result, 0xff, result_len); + return true; + } + + return false; + } + + virtual void NegotiateSrtpCiphers() { + for (std::vector::const_iterator it1 = srtp_ciphers_.begin(); + it1 != srtp_ciphers_.end(); ++it1) { + for (std::vector::const_iterator it2 = + dest_->srtp_ciphers_.begin(); + it2 != dest_->srtp_ciphers_.end(); ++it2) { + if (*it1 == *it2) { + chosen_srtp_cipher_ = *it1; + dest_->chosen_srtp_cipher_ = *it2; + return; + } + } + } + } + + virtual bool GetStats(ConnectionInfos* infos) OVERRIDE { + ConnectionInfo info; + infos->clear(); + infos->push_back(info); + return true; + } + + private: + enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED }; + Transport* transport_; + FakeTransportChannel* dest_; + State state_; + bool async_; + talk_base::SSLIdentity* identity_; + talk_base::FakeSSLCertificate* remote_cert_; + bool do_dtls_; + std::vector srtp_ciphers_; + std::string chosen_srtp_cipher_; + IceRole role_; + uint64 tiebreaker_; + IceProtocolType ice_proto_; + std::string ice_ufrag_; + std::string ice_pwd_; + std::string remote_ice_ufrag_; + std::string remote_ice_pwd_; + 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. +// Can be informed of another FakeTransport via SetDestination (low-tech way +// of doing candidates) +class FakeTransport : public Transport { + public: + typedef std::map ChannelMap; + FakeTransport(talk_base::Thread* signaling_thread, + talk_base::Thread* worker_thread, + const std::string& content_name, + PortAllocator* alllocator = NULL) + : Transport(signaling_thread, worker_thread, + content_name, "test_type", NULL), + dest_(NULL), + async_(false), + identity_(NULL) { + } + ~FakeTransport() { + DestroyAllChannels(); + } + + const ChannelMap& channels() const { return channels_; } + + void SetAsync(bool async) { async_ = async; } + void SetDestination(FakeTransport* dest) { + dest_ = dest; + for (ChannelMap::iterator it = channels_.begin(); it != channels_.end(); + ++it) { + it->second->SetLocalIdentity(identity_); + SetChannelDestination(it->first, it->second); + } + } + + void SetWritable(bool writable) { + for (ChannelMap::iterator it = channels_.begin(); it != channels_.end(); + ++it) { + it->second->SetWritable(writable); + } + } + + void set_identity(talk_base::SSLIdentity* identity) { + identity_ = identity; + } + + using Transport::local_description; + using Transport::remote_description; + + protected: + virtual TransportChannelImpl* CreateTransportChannel(int component) { + if (channels_.find(component) != channels_.end()) { + return NULL; + } + FakeTransportChannel* channel = + new FakeTransportChannel(this, content_name(), component); + channel->SetAsync(async_); + SetChannelDestination(component, channel); + channels_[component] = channel; + return channel; + } + virtual void DestroyTransportChannel(TransportChannelImpl* channel) { + channels_.erase(channel->component()); + delete channel; + } + virtual void SetIdentity_w(talk_base::SSLIdentity* identity) { + identity_ = identity; + } + virtual bool GetIdentity_w(talk_base::SSLIdentity** identity) { + if (!identity_) + return false; + + *identity = identity_->GetReference(); + return true; + } + + private: + FakeTransportChannel* GetFakeChannel(int component) { + ChannelMap::iterator it = channels_.find(component); + return (it != channels_.end()) ? it->second : NULL; + } + void SetChannelDestination(int component, + FakeTransportChannel* channel) { + FakeTransportChannel* dest_channel = NULL; + if (dest_) { + dest_channel = dest_->GetFakeChannel(component); + if (dest_channel) { + dest_channel->SetLocalIdentity(dest_->identity_); + } + } + channel->SetDestination(dest_channel); + } + + // Note, this is distinct from the Channel map owned by Transport. + // This map just tracks the FakeTransportChannels created by this class. + ChannelMap channels_; + FakeTransport* dest_; + bool async_; + talk_base::SSLIdentity* identity_; +}; + +// Fake session class, which can be passed into a BaseChannel object for +// test purposes. Can be connected to other FakeSessions via Connect(). +class FakeSession : public BaseSession { + public: + explicit FakeSession() + : BaseSession(talk_base::Thread::Current(), + talk_base::Thread::Current(), + NULL, "", "", true), + fail_create_channel_(false) { + } + explicit FakeSession(bool initiator) + : BaseSession(talk_base::Thread::Current(), + talk_base::Thread::Current(), + NULL, "", "", initiator), + fail_create_channel_(false) { + } + FakeSession(talk_base::Thread* worker_thread, bool initiator) + : BaseSession(talk_base::Thread::Current(), + worker_thread, + NULL, "", "", initiator), + fail_create_channel_(false) { + } + + FakeTransport* GetTransport(const std::string& content_name) { + return static_cast( + BaseSession::GetTransport(content_name)); + } + + void Connect(FakeSession* dest) { + // Simulate the exchange of candidates. + CompleteNegotiation(); + dest->CompleteNegotiation(); + for (TransportMap::const_iterator it = transport_proxies().begin(); + it != transport_proxies().end(); ++it) { + static_cast(it->second->impl())->SetDestination( + dest->GetTransport(it->first)); + } + } + + virtual TransportChannel* CreateChannel( + const std::string& content_name, + const std::string& channel_name, + int component) { + if (fail_create_channel_) { + return NULL; + } + return BaseSession::CreateChannel(content_name, channel_name, component); + } + + void set_fail_channel_creation(bool fail_channel_creation) { + fail_create_channel_ = fail_channel_creation; + } + + // TODO: Hoist this into Session when we re-work the Session code. + void set_ssl_identity(talk_base::SSLIdentity* identity) { + for (TransportMap::const_iterator it = transport_proxies().begin(); + it != transport_proxies().end(); ++it) { + // We know that we have a FakeTransport* + + static_cast(it->second->impl())->set_identity + (identity); + } + } + + protected: + virtual Transport* CreateTransport(const std::string& content_name) { + return new FakeTransport(signaling_thread(), worker_thread(), content_name); + } + + void CompleteNegotiation() { + for (TransportMap::const_iterator it = transport_proxies().begin(); + it != transport_proxies().end(); ++it) { + it->second->CompleteNegotiation(); + it->second->ConnectChannels(); + } + } + + private: + bool fail_create_channel_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_FAKESESSION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/p2ptransport.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/p2ptransport.h new file mode 100644 index 0000000..72240b5 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/p2ptransport.h @@ -0,0 +1,103 @@ +/* + * 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 TALK_P2P_BASE_P2PTRANSPORT_H_ +#define TALK_P2P_BASE_P2PTRANSPORT_H_ + +#include +#include +#include "talk/p2p/base/transport.h" + +namespace cricket { + +class P2PTransport : public Transport { + public: + P2PTransport(talk_base::Thread* signaling_thread, + talk_base::Thread* worker_thread, + const std::string& content_name, + PortAllocator* allocator); + virtual ~P2PTransport(); + + protected: + // Creates and destroys P2PTransportChannel. + virtual TransportChannelImpl* CreateTransportChannel(int component); + virtual void DestroyTransportChannel(TransportChannelImpl* channel); + + friend class P2PTransportChannel; + + DISALLOW_EVIL_CONSTRUCTORS(P2PTransport); +}; + +class P2PTransportParser : public TransportParser { + public: + P2PTransportParser() {} + // Translator may be null, in which case ParseCandidates should + // return false if there are candidates to parse. We can't not call + // ParseCandidates because there's no way to know ahead of time if + // there are candidates or not. + + // Jingle-specific functions; can be used with either ICE, GICE, or HYBRID. + virtual bool ParseTransportDescription(const buzz::XmlElement* elem, + const CandidateTranslator* translator, + TransportDescription* desc, + ParseError* error); + virtual bool WriteTransportDescription(const TransportDescription& desc, + const CandidateTranslator* translator, + buzz::XmlElement** elem, + WriteError* error); + + // Legacy Gingle functions; only can be used with GICE. + virtual bool ParseGingleCandidate(const buzz::XmlElement* elem, + const CandidateTranslator* translator, + Candidate* candidate, + ParseError* error); + virtual bool WriteGingleCandidate(const Candidate& candidate, + const CandidateTranslator* translator, + buzz::XmlElement** elem, + WriteError* error); + + private: + bool ParseCandidate(TransportProtocol proto, + const buzz::XmlElement* elem, + const CandidateTranslator* translator, + Candidate* candidate, + ParseError* error); + bool WriteCandidate(TransportProtocol proto, + const Candidate& candidate, + const CandidateTranslator* translator, + buzz::XmlElement* elem, + WriteError* error); + bool VerifyUsernameFormat(TransportProtocol proto, + const std::string& username, + ParseError* error); + + DISALLOW_EVIL_CONSTRUCTORS(P2PTransportParser); +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_P2PTRANSPORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/p2ptransportchannel.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/p2ptransportchannel.h new file mode 100644 index 0000000..607dd5f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/p2ptransportchannel.h @@ -0,0 +1,259 @@ +/* + * 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. + */ + +// P2PTransportChannel wraps up the state management of the connection between +// two P2P clients. Clients have candidate ports for connecting, and +// connections which are combinations of candidates from each end (Alice and +// Bob each have candidates, one candidate from Alice and one candidate from +// Bob are used to make a connection, repeat to make many connections). +// +// When all of the available connections become invalid (non-writable), we +// kick off a process of determining more candidates and more connections. +// +#ifndef TALK_P2P_BASE_P2PTRANSPORTCHANNEL_H_ +#define TALK_P2P_BASE_P2PTRANSPORTCHANNEL_H_ + +#include +#include +#include +#include "talk/base/asyncpacketsocket.h" +#include "talk/base/sigslot.h" +#include "talk/p2p/base/candidate.h" +#include "talk/p2p/base/portinterface.h" +#include "talk/p2p/base/portallocator.h" +#include "talk/p2p/base/transport.h" +#include "talk/p2p/base/transportchannelimpl.h" +#include "talk/p2p/base/p2ptransport.h" + +namespace cricket { + +// Adds the port on which the candidate originated. +class RemoteCandidate : public Candidate { + public: + RemoteCandidate(const Candidate& c, PortInterface* origin_port) + : Candidate(c), origin_port_(origin_port) {} + + PortInterface* origin_port() { return origin_port_; } + + private: + PortInterface* origin_port_; +}; + +// P2PTransportChannel manages the candidates and connection process to keep +// two P2P clients connected to each other. +class P2PTransportChannel : public TransportChannelImpl, + public talk_base::MessageHandler { + public: + P2PTransportChannel(const std::string& content_name, + int component, + P2PTransport* transport, + PortAllocator *allocator); + virtual ~P2PTransportChannel(); + + // From TransportChannelImpl: + virtual Transport* GetTransport() { return transport_; } + 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); + virtual void SetRemoteIceCredentials(const std::string& ice_ufrag, + const std::string& ice_pwd); + virtual void SetRemoteIceMode(IceMode mode); + virtual void Connect(); + virtual void Reset(); + virtual void OnSignalingReady(); + virtual void OnCandidate(const Candidate& candidate); + + // From TransportChannel: + virtual int SendPacket(const char *data, size_t len, + 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* stats); + + const Connection* best_connection() const { return best_connection_; } + void set_incoming_only(bool value) { incoming_only_ = value; } + + // Note: This is only for testing purpose. + // |ports_| should not be changed from outside. + const std::vector& ports() { return ports_; } + + IceMode remote_ice_mode() const { return remote_ice_mode_; } + + // DTLS methods. + virtual bool IsDtlsActive() const { return false; } + + // Default implementation. + virtual bool GetSslRole(talk_base::SSLRole* role) const { + return false; + } + + virtual bool SetSslRole(talk_base::SSLRole role) { + return false; + } + + // Set up the ciphers to use for DTLS-SRTP. + virtual bool SetSrtpCiphers(const std::vector& ciphers) { + return false; + } + + // Find out which DTLS-SRTP cipher was negotiated + virtual bool GetSrtpCipher(std::string* cipher) { + return false; + } + + // Returns false because the channel is not encrypted by default. + virtual bool GetLocalIdentity(talk_base::SSLIdentity** identity) const { + return false; + } + + virtual bool GetRemoteCertificate(talk_base::SSLCertificate** cert) const { + return false; + } + + // Allows key material to be extracted for external encryption. + virtual bool ExportKeyingMaterial( + const std::string& label, + const uint8* context, + size_t context_len, + bool use_context, + uint8* result, + size_t result_len) { + return false; + } + + virtual bool SetLocalIdentity(talk_base::SSLIdentity* identity) { + return false; + } + + // Set DTLS Remote fingerprint. Must be after local identity set. + virtual bool SetRemoteFingerprint( + const std::string& digest_alg, + const uint8* digest, + size_t digest_len) { + return false; + } + + // Helper method used only in unittest. + talk_base::DiffServCodePoint DefaultDscpValue() const; + + private: + talk_base::Thread* thread() { return worker_thread_; } + PortAllocatorSession* allocator_session() { + return allocator_sessions_.back(); + } + + void Allocate(); + void UpdateConnectionStates(); + void RequestSort(); + void SortConnections(); + void SwitchBestConnectionTo(Connection* conn); + void UpdateChannelState(); + void HandleWritable(); + void HandleNotWritable(); + void HandleAllTimedOut(); + + Connection* GetBestConnectionOnNetwork(talk_base::Network* network); + bool CreateConnections(const Candidate &remote_candidate, + PortInterface* origin_port, bool readable); + bool CreateConnection(PortInterface* port, const Candidate& remote_candidate, + PortInterface* origin_port, bool readable); + 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); + Connection* FindNextPingableConnection(); + void PingConnection(Connection* conn); + void AddAllocatorSession(PortAllocatorSession* session); + void AddConnection(Connection* connection); + + void OnPortReady(PortAllocatorSession *session, PortInterface* port); + void OnCandidatesReady(PortAllocatorSession *session, + const std::vector& candidates); + void OnCandidatesAllocationDone(PortAllocatorSession* session); + void OnUnknownAddress(PortInterface* port, + const talk_base::SocketAddress& addr, + ProtocolType proto, + IceMessage* stun_msg, + const std::string& remote_username, + bool port_muxed); + void OnPortDestroyed(PortInterface* port); + void OnRoleConflict(PortInterface* port); + + void OnConnectionStateChange(Connection* connection); + void OnReadPacket(Connection *connection, const char *data, size_t len, + const talk_base::PacketTime& packet_time); + void OnReadyToSend(Connection* connection); + void OnConnectionDestroyed(Connection *connection); + + void OnUseCandidate(Connection* conn); + + virtual void OnMessage(talk_base::Message *pmsg); + void OnSort(); + void OnPing(); + + P2PTransport* transport_; + PortAllocator *allocator_; + talk_base::Thread *worker_thread_; + bool incoming_only_; + bool waiting_for_signaling_; + int error_; + std::vector allocator_sessions_; + std::vector ports_; + std::vector connections_; + Connection* best_connection_; + // Connection selected by the controlling agent. This should be used only + // at controlled side when protocol type is RFC5245. + Connection* pending_best_connection_; + std::vector remote_candidates_; + bool sort_dirty_; // indicates whether another sort is needed right now + bool was_writable_; + typedef std::map OptionMap; + OptionMap options_; + std::string ice_ufrag_; + std::string ice_pwd_; + std::string remote_ice_ufrag_; + std::string remote_ice_pwd_; + IceProtocolType protocol_type_; + IceMode remote_ice_mode_; + IceRole ice_role_; + uint64 tiebreaker_; + uint32 remote_candidate_generation_; + + DISALLOW_EVIL_CONSTRUCTORS(P2PTransportChannel); +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_P2PTRANSPORTCHANNEL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/packetsocketfactory.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/packetsocketfactory.h new file mode 100644 index 0000000..ba8574e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/packetsocketfactory.h @@ -0,0 +1,69 @@ +/* + * 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_BASE_PACKETSOCKETFACTORY_H_ +#define TALK_BASE_PACKETSOCKETFACTORY_H_ + +#include "talk/base/proxyinfo.h" + +namespace talk_base { + +class AsyncPacketSocket; +class AsyncResolverInterface; + +class PacketSocketFactory { + public: + enum Options { + OPT_SSLTCP = 0x01, // Pseudo-TLS. + OPT_TLS = 0x02, + OPT_STUN = 0x04, + }; + + PacketSocketFactory() { } + virtual ~PacketSocketFactory() { } + + virtual AsyncPacketSocket* CreateUdpSocket( + const SocketAddress& address, int min_port, int max_port) = 0; + virtual AsyncPacketSocket* CreateServerTcpSocket( + const SocketAddress& local_address, int min_port, int max_port, + int opts) = 0; + + // TODO: |proxy_info| and |user_agent| should be set + // per-factory and not when socket is created. + virtual AsyncPacketSocket* CreateClientTcpSocket( + const SocketAddress& local_address, const SocketAddress& remote_address, + const ProxyInfo& proxy_info, const std::string& user_agent, int opts) = 0; + + virtual AsyncResolverInterface* CreateAsyncResolver() = 0; + + private: + DISALLOW_EVIL_CONSTRUCTORS(PacketSocketFactory); +}; + +} // namespace talk_base + +#endif // TALK_BASE_PACKETSOCKETFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/parsing.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/parsing.h new file mode 100644 index 0000000..e15525f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/parsing.h @@ -0,0 +1,157 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_PARSING_H_ +#define TALK_P2P_BASE_PARSING_H_ + +#include +#include +#include "talk/base/basictypes.h" +#include "talk/base/stringencode.h" +#include "talk/xmllite/xmlelement.h" // Needed to delete ParseError.extra. + +namespace cricket { + +typedef std::vector XmlElements; + +// We decided "bool Parse(in, out*, error*)" is generally the best +// parse signature. "out Parse(in)" doesn't allow for errors. +// "error* Parse(in, out*)" doesn't allow flexible memory management. + +// The error type for parsing. +struct ParseError { + public: + // explains the error + std::string text; + // provide details about what wasn't parsable + const buzz::XmlElement* extra; + + ParseError() : extra(NULL) {} + + ~ParseError() { + delete extra; + } + + void SetText(const std::string& text) { + this->text = text; + } +}; + +// The error type for writing. +struct WriteError { + std::string text; + + void SetText(const std::string& text) { + this->text = text; + } +}; + +// Convenience method for returning a message when parsing fails. +bool BadParse(const std::string& text, ParseError* err); + +// Convenience method for returning a message when writing fails. +bool BadWrite(const std::string& text, WriteError* error); + +// helper XML functions +std::string GetXmlAttr(const buzz::XmlElement* elem, + const buzz::QName& name, + const std::string& def); +std::string GetXmlAttr(const buzz::XmlElement* elem, + const buzz::QName& name, + const char* def); +// Return true if the value is "true" or "1". +bool GetXmlAttr(const buzz::XmlElement* elem, + const buzz::QName& name, bool def); +int GetXmlAttr(const buzz::XmlElement* elem, + const buzz::QName& name, int def); + +template +bool GetXmlAttr(const buzz::XmlElement* elem, + const buzz::QName& name, + T* val_out) { + if (!elem->HasAttr(name)) { + return false; + } + std::string unparsed = elem->Attr(name); + return talk_base::FromString(unparsed, val_out); +} + +template +bool GetXmlAttr(const buzz::XmlElement* elem, + const buzz::QName& name, + const T& def, + T* val_out) { + if (!elem->HasAttr(name)) { + *val_out = def; + return true; + } + return GetXmlAttr(elem, name, val_out); +} + +template +bool AddXmlAttr(buzz::XmlElement* elem, + const buzz::QName& name, const T& val) { + std::string buf; + if (!talk_base::ToString(val, &buf)) { + return false; + } + elem->AddAttr(name, buf); + return true; +} + +template +bool SetXmlBody(buzz::XmlElement* elem, const T& val) { + std::string buf; + if (!talk_base::ToString(val, &buf)) { + return false; + } + elem->SetBodyText(buf); + return true; +} + +const buzz::XmlElement* GetXmlChild(const buzz::XmlElement* parent, + const std::string& name); + +bool RequireXmlChild(const buzz::XmlElement* parent, + const std::string& name, + const buzz::XmlElement** child, + ParseError* error); +bool RequireXmlAttr(const buzz::XmlElement* elem, + const buzz::QName& name, + std::string* value, + ParseError* error); +void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem, + const buzz::QName name, + const std::string& value); +void AddXmlChildren(buzz::XmlElement* parent, + const std::vector& children); +void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest); +std::vector CopyOfXmlChildren(const buzz::XmlElement* elem); + +} // namespace cricket + +#endif // TALK_P2P_BASE_PARSING_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/port.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/port.h new file mode 100644 index 0000000..d5f368b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/port.h @@ -0,0 +1,596 @@ +/* + * 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 TALK_P2P_BASE_PORT_H_ +#define TALK_P2P_BASE_PORT_H_ + +#include +#include +#include + +#include "talk/base/asyncpacketsocket.h" +#include "talk/base/network.h" +#include "talk/base/proxyinfo.h" +#include "talk/base/ratetracker.h" +#include "talk/base/sigslot.h" +#include "talk/base/socketaddress.h" +#include "talk/base/thread.h" +#include "talk/p2p/base/candidate.h" +#include "talk/p2p/base/packetsocketfactory.h" +#include "talk/p2p/base/portinterface.h" +#include "talk/p2p/base/stun.h" +#include "talk/p2p/base/stunrequest.h" +#include "talk/p2p/base/transport.h" + +namespace cricket { + +class Connection; +class ConnectionRequest; + +extern const char LOCAL_PORT_TYPE[]; +extern const char STUN_PORT_TYPE[]; +extern const char PRFLX_PORT_TYPE[]; +extern const char RELAY_PORT_TYPE[]; + +extern const char UDP_PROTOCOL_NAME[]; +extern const char TCP_PROTOCOL_NAME[]; +extern const char SSLTCP_PROTOCOL_NAME[]; + +// The length of time we wait before timing out readability on a connection. +const uint32 CONNECTION_READ_TIMEOUT = 30 * 1000; // 30 seconds + +// The length of time we wait before timing out writability on a connection. +const uint32 CONNECTION_WRITE_TIMEOUT = 15 * 1000; // 15 seconds + +// The length of time we wait before we become unwritable. +const uint32 CONNECTION_WRITE_CONNECT_TIMEOUT = 5 * 1000; // 5 seconds + +// The number of pings that must fail to respond before we become unwritable. +const uint32 CONNECTION_WRITE_CONNECT_FAILURES = 5; + +// This is the length of time that we wait for a ping response to come back. +const int CONNECTION_RESPONSE_TIMEOUT = 5 * 1000; // 5 seconds + +enum RelayType { + RELAY_GTURN, // Legacy google relay service. + RELAY_TURN // Standard (TURN) relay service. +}; + +enum IcePriorityValue { + // The reason we are choosing Relay preference 2 is because, we can run + // Relay from client to server on UDP/TCP/TLS. To distinguish the transport + // protocol, we prefer UDP over TCP over TLS. + // For UDP ICE_TYPE_PREFERENCE_RELAY will be 2. + // For TCP ICE_TYPE_PREFERENCE_RELAY will be 1. + // For TLS ICE_TYPE_PREFERENCE_RELAY will be 0. + // Check turnport.cc for setting these values. + ICE_TYPE_PREFERENCE_RELAY = 2, + ICE_TYPE_PREFERENCE_HOST_TCP = 90, + ICE_TYPE_PREFERENCE_SRFLX = 100, + ICE_TYPE_PREFERENCE_PRFLX = 110, + ICE_TYPE_PREFERENCE_HOST = 126 +}; + +const char* ProtoToString(ProtocolType proto); +bool StringToProto(const char* value, ProtocolType* proto); + +struct ProtocolAddress { + talk_base::SocketAddress address; + ProtocolType proto; + bool secure; + + ProtocolAddress(const talk_base::SocketAddress& a, ProtocolType p) + : address(a), proto(p), secure(false) { } + ProtocolAddress(const talk_base::SocketAddress& a, ProtocolType p, bool sec) + : address(a), proto(p), secure(sec) { } +}; + +// Represents a local communication mechanism that can be used to create +// connections to similar mechanisms of the other client. Subclasses of this +// one add support for specific mechanisms like local UDP ports. +class Port : public PortInterface, public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + Port(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory, + talk_base::Network* network, const talk_base::IPAddress& ip, + const std::string& username_fragment, const std::string& password); + Port(talk_base::Thread* thread, const std::string& type, + talk_base::PacketSocketFactory* factory, + talk_base::Network* network, const talk_base::IPAddress& ip, + int min_port, int max_port, const std::string& username_fragment, + const std::string& password); + virtual ~Port(); + + virtual const std::string& Type() const { return type_; } + virtual talk_base::Network* Network() const { return network_; } + + // This method will set the flag which enables standard ICE/STUN procedures + // in STUN connectivity checks. Currently this method does + // 1. Add / Verify MI attribute in STUN binding requests. + // 2. Username attribute in STUN binding request will be RFRAF:LFRAG, + // as opposed to RFRAGLFRAG. + virtual void SetIceProtocolType(IceProtocolType protocol) { + ice_protocol_ = protocol; + } + virtual IceProtocolType IceProtocol() const { return ice_protocol_; } + + // Methods to set/get ICE role and tiebreaker values. + IceRole GetIceRole() const { return ice_role_; } + void SetIceRole(IceRole role) { ice_role_ = role; } + + void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; } + uint64 IceTiebreaker() const { return tiebreaker_; } + + virtual bool SharedSocket() const { return shared_socket_; } + + // The thread on which this port performs its I/O. + talk_base::Thread* thread() { return thread_; } + + // The factory used to create the sockets of this port. + talk_base::PacketSocketFactory* socket_factory() const { return factory_; } + void set_socket_factory(talk_base::PacketSocketFactory* factory) { + factory_ = factory; + } + + // For debugging purposes. + const std::string& content_name() const { return content_name_; } + void set_content_name(const std::string& content_name) { + content_name_ = content_name; + } + + int component() const { return component_; } + void set_component(int component) { component_ = component; } + + bool send_retransmit_count_attribute() const { + return send_retransmit_count_attribute_; + } + void set_send_retransmit_count_attribute(bool enable) { + send_retransmit_count_attribute_ = enable; + } + + // Identifies the generation that this port was created in. + uint32 generation() { return generation_; } + void set_generation(uint32 generation) { generation_ = generation; } + + // ICE requires a single username/password per content/media line. So the + // |ice_username_fragment_| of the ports that belongs to the same content will + // be the same. However this causes a small complication with our relay + // server, which expects different username for RTP and RTCP. + // + // To resolve this problem, we implemented the username_fragment(), + // which returns a different username (calculated from + // |ice_username_fragment_|) for RTCP in the case of ICEPROTO_GOOGLE. And the + // username_fragment() simply returns |ice_username_fragment_| when running + // in ICEPROTO_RFC5245. + // + // As a result the ICEPROTO_GOOGLE will use different usernames for RTP and + // RTCP. And the ICEPROTO_RFC5245 will use same username for both RTP and + // RTCP. + const std::string username_fragment() const; + const std::string& password() const { return password_; } + + // Fired when candidates are discovered by the port. When all candidates + // are discovered that belong to port SignalAddressReady is fired. + sigslot::signal2 SignalCandidateReady; + + // Provides all of the above information in one handy object. + virtual const std::vector& Candidates() const { + return candidates_; + } + + // SignalPortComplete is sent when port completes the task of candidates + // allocation. + sigslot::signal1 SignalPortComplete; + // This signal sent when port fails to allocate candidates and this port + // can't be used in establishing the connections. When port is in shared mode + // and port fails to allocate one of the candidates, port shouldn't send + // this signal as other candidates might be usefull in establishing the + // connection. + sigslot::signal1 SignalPortError; + + // Returns a map containing all of the connections of this port, keyed by the + // remote address. + typedef std::map AddressMap; + const AddressMap& connections() { return connections_; } + + // Returns the connection to the given address or NULL if none exists. + virtual Connection* GetConnection( + const talk_base::SocketAddress& remote_addr); + + // Called each time a connection is created. + sigslot::signal2 SignalConnectionCreated; + + // In a shared socket mode each port which shares the socket will decide + // to accept the packet based on the |remote_addr|. Currently only UDP + // port implemented this method. + // TODO(mallinath) - Make it pure virtual. + 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) { + ASSERT(false); + return false; + } + + // Sends a response message (normal or error) to the given request. One of + // these methods should be called as a response to SignalUnknownAddress. + // NOTE: You MUST call CreateConnection BEFORE SendBindingResponse. + virtual void SendBindingResponse(StunMessage* request, + const talk_base::SocketAddress& addr); + virtual void SendBindingErrorResponse( + StunMessage* request, const talk_base::SocketAddress& addr, + int error_code, const std::string& reason); + + void set_proxy(const std::string& user_agent, + const talk_base::ProxyInfo& proxy) { + user_agent_ = user_agent; + proxy_ = proxy; + } + const std::string& user_agent() { return user_agent_; } + const talk_base::ProxyInfo& proxy() { return proxy_; } + + virtual void EnablePortPackets(); + + // Called if the port has no connections and is no longer useful. + void Destroy(); + + virtual void OnMessage(talk_base::Message *pmsg); + + // Debugging description of this port + virtual std::string ToString() const; + talk_base::IPAddress& ip() { return ip_; } + 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, + IceProtocolType* remote_protocol_type) const; + void CreateStunUsername(const std::string& remote_username, + std::string* stun_username_attr_str) const; + + bool MaybeIceRoleConflict(const talk_base::SocketAddress& addr, + IceMessage* stun_msg, + const std::string& remote_ufrag); + + // Called when the socket is currently able to send. + void OnReadyToSend(); + + // Called when the Connection discovers a local peer reflexive candidate. + // Returns the index of the new local candidate. + size_t AddPrflxCandidate(const Candidate& local); + + // Returns if RFC 5245 ICE protocol is used. + bool IsStandardIce() const; + + // Returns if Google ICE protocol is used. + bool IsGoogleIce() const; + + // Returns if Hybrid ICE protocol is used. + bool IsHybridIce() const; + + protected: + enum { + MSG_CHECKTIMEOUT = 0, + MSG_FIRST_AVAILABLE + }; + + void set_type(const std::string& type) { type_ = type; } + // 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); + + // Adds the given connection to the list. (Deleting removes them.) + void AddConnection(Connection* conn); + + // Called when a packet is received from an unknown address that is not + // currently a connection. If this is an authenticated STUN binding request, + // then we will signal the client. + void OnReadPacket(const char* data, size_t size, + const talk_base::SocketAddress& addr, + ProtocolType proto); + + // If the given data comprises a complete and correct STUN message then the + // return value is true, otherwise false. If the message username corresponds + // with this port's username fragment, msg will contain the parsed STUN + // message. Otherwise, the function may send a STUN response internally. + // remote_username contains the remote fragment of the STUN username. + bool GetStunMessage(const char* data, size_t size, + const talk_base::SocketAddress& addr, + IceMessage** out_msg, std::string* out_username); + + // Checks if the address in addr is compatible with the port's ip. + bool IsCompatibleAddress(const talk_base::SocketAddress& addr); + + // Returns default DSCP value. + talk_base::DiffServCodePoint DefaultDscpValue() const { + // No change from what MediaChannel set. + return talk_base::DSCP_NO_CHANGE; + } + + private: + void Construct(); + // Called when one of our connections deletes itself. + void OnConnectionDestroyed(Connection* conn); + + // Checks if this port is useless, and hence, should be destroyed. + void CheckTimeout(); + + talk_base::Thread* thread_; + talk_base::PacketSocketFactory* factory_; + std::string type_; + bool send_retransmit_count_attribute_; + talk_base::Network* network_; + talk_base::IPAddress ip_; + int min_port_; + int max_port_; + std::string content_name_; + int component_; + uint32 generation_; + // 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. + // PortAllocatorSession will provide these username_fragment and password. + // + // Note: we should always use username_fragment() instead of using + // |ice_username_fragment_| directly. For the details see the comment on + // username_fragment(). + std::string ice_username_fragment_; + std::string password_; + std::vector candidates_; + AddressMap connections_; + int timeout_delay_; + bool enable_port_packets_; + IceProtocolType ice_protocol_; + IceRole ice_role_; + uint64 tiebreaker_; + bool shared_socket_; + // Information to use when going through a proxy. + std::string user_agent_; + talk_base::ProxyInfo proxy_; + + friend class Connection; +}; + +// Represents a communication link between a port on the local client and a +// port on the remote client. +class Connection : public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + // States are from RFC 5245. http://tools.ietf.org/html/rfc5245#section-5.7.4 + enum State { + STATE_WAITING = 0, // Check has not been performed, Waiting pair on CL. + STATE_INPROGRESS, // Check has been sent, transaction is in progress. + STATE_SUCCEEDED, // Check already done, produced a successful result. + STATE_FAILED // Check for this connection failed. + }; + + virtual ~Connection(); + + // The local port where this connection sends and receives packets. + Port* port() { return port_; } + const Port* port() const { return port_; } + + // Returns the description of the local port + virtual const Candidate& local_candidate() const; + + // Returns the description of the remote port to which we communicate. + const Candidate& remote_candidate() const { return remote_candidate_; } + + // Returns the pair priority. + uint64 priority() const; + + enum ReadState { + STATE_READ_INIT = 0, // we have yet to receive a ping + STATE_READABLE = 1, // we have received pings recently + STATE_READ_TIMEOUT = 2, // we haven't received pings in a while + }; + + ReadState read_state() const { return read_state_; } + bool readable() const { return read_state_ == STATE_READABLE; } + + enum WriteState { + STATE_WRITABLE = 0, // we have received ping responses recently + STATE_WRITE_UNRELIABLE = 1, // we have had a few ping failures + STATE_WRITE_INIT = 2, // we have yet to receive a ping response + STATE_WRITE_TIMEOUT = 3, // we have had a large number of ping failures + }; + + WriteState write_state() const { return write_state_; } + bool writable() const { return write_state_ == STATE_WRITABLE; } + + // Determines whether the connection has finished connecting. This can only + // be false for TCP connections. + bool connected() const { return connected_; } + + // Estimate of the round-trip time over this connection. + uint32 rtt() const { return rtt_; } + + size_t sent_total_bytes(); + size_t sent_bytes_second(); + size_t recv_total_bytes(); + size_t recv_bytes_second(); + sigslot::signal1 SignalStateChange; + + // Sent when the connection has decided that it is no longer of value. It + // will delete itself immediately after this call. + sigslot::signal1 SignalDestroyed; + + // The connection can send and receive packets asynchronously. This matches + // the interface of AsyncPacketSocket, which may use UDP or TCP under the + // covers. + virtual int Send(const void* data, size_t size, + const talk_base::PacketOptions& options) = 0; + + // Error if Send() returns < 0 + virtual int GetError() = 0; + + sigslot::signal4 SignalReadPacket; + + sigslot::signal1 SignalReadyToSend; + + // Called when a packet is received on this connection. + void OnReadPacket(const char* data, size_t size, + const talk_base::PacketTime& packet_time); + + // Called when the socket is currently able to send. + void OnReadyToSend(); + + // Called when a connection is determined to be no longer useful to us. We + // still keep it around in case the other side wants to use it. But we can + // safely stop pinging on it and we can allow it to time out if the other + // side stops using it as well. + bool pruned() const { return pruned_; } + void Prune(); + + bool use_candidate_attr() const { return use_candidate_attr_; } + void set_use_candidate_attr(bool enable); + + void set_remote_ice_mode(IceMode mode) { + remote_ice_mode_ = mode; + } + + // Makes the connection go away. + void Destroy(); + + // Checks that the state of this connection is up-to-date. The argument is + // the current time, which is compared against various timeouts. + void UpdateState(uint32 now); + + // Called when this connection should try checking writability again. + uint32 last_ping_sent() const { return last_ping_sent_; } + void Ping(uint32 now); + + // Called whenever a valid ping is received on this connection. This is + // public because the connection intercepts the first ping for us. + uint32 last_ping_received() const { return last_ping_received_; } + void ReceivedPing(); + + // Debugging description of this connection + std::string ToString() const; + std::string ToSensitiveString() const; + + bool reported() const { return reported_; } + void set_reported(bool reported) { reported_ = reported;} + + // This flag will be set if this connection is the chosen one for media + // transmission. This connection will send STUN ping with USE-CANDIDATE + // attribute. + sigslot::signal1 SignalUseCandidate; + // Invoked when Connection receives STUN error response with 487 code. + void HandleRoleConflictFromPeer(); + + State state() const { return state_; } + + IceMode remote_ice_mode() const { return remote_ice_mode_; } + + protected: + // Constructs a new connection to the given remote port. + Connection(Port* port, size_t index, const Candidate& candidate); + + // Called back when StunRequestManager has a stun packet to send + void OnSendStunPacket(const void* data, size_t size, StunRequest* req); + + // Callbacks from ConnectionRequest + void OnConnectionRequestResponse(ConnectionRequest* req, + StunMessage* response); + void OnConnectionRequestErrorResponse(ConnectionRequest* req, + StunMessage* response); + void OnConnectionRequestTimeout(ConnectionRequest* req); + + // Changes the state and signals if necessary. + void set_read_state(ReadState value); + void set_write_state(WriteState value); + void set_state(State state); + void set_connected(bool value); + + // Checks if this connection is useless, and hence, should be destroyed. + void CheckTimeout(); + + void OnMessage(talk_base::Message *pmsg); + + Port* port_; + size_t local_candidate_index_; + Candidate remote_candidate_; + ReadState read_state_; + WriteState write_state_; + bool connected_; + bool pruned_; + // By default |use_candidate_attr_| flag will be true, + // as we will be using agrressive nomination. + // But when peer is ice-lite, this flag "must" be initialized to false and + // turn on when connection becomes "best connection". + bool use_candidate_attr_; + IceMode remote_ice_mode_; + StunRequestManager requests_; + uint32 rtt_; + uint32 last_ping_sent_; // last time we sent a ping to the other side + uint32 last_ping_received_; // last time we received a ping from the other + // side + uint32 last_data_received_; + uint32 last_ping_response_received_; + std::vector pings_since_last_response_; + + talk_base::RateTracker recv_rate_tracker_; + talk_base::RateTracker send_rate_tracker_; + + private: + void MaybeAddPrflxCandidate(ConnectionRequest* request, + StunMessage* response); + + bool reported_; + State state_; + + friend class Port; + friend class ConnectionRequest; +}; + +// ProxyConnection defers all the interesting work to the port +class ProxyConnection : public Connection { + public: + ProxyConnection(Port* port, size_t index, const Candidate& candidate); + + virtual int Send(const void* data, size_t size, + const talk_base::PacketOptions& options); + virtual int GetError() { return error_; } + + private: + int error_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_PORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portallocator.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portallocator.h new file mode 100644 index 0000000..afce017 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portallocator.h @@ -0,0 +1,190 @@ +/* + * 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 TALK_P2P_BASE_PORTALLOCATOR_H_ +#define TALK_P2P_BASE_PORTALLOCATOR_H_ + +#include +#include + +#include "talk/base/helpers.h" +#include "talk/base/proxyinfo.h" +#include "talk/base/sigslot.h" +#include "talk/p2p/base/portinterface.h" + +namespace cricket { + +// PortAllocator is responsible for allocating Port types for a given +// P2PSocket. It also handles port freeing. +// +// Clients can override this class to control port allocation, including +// what kinds of ports are allocated. + +const uint32 PORTALLOCATOR_DISABLE_UDP = 0x01; +const uint32 PORTALLOCATOR_DISABLE_STUN = 0x02; +const uint32 PORTALLOCATOR_DISABLE_RELAY = 0x04; +const uint32 PORTALLOCATOR_DISABLE_TCP = 0x08; +const uint32 PORTALLOCATOR_ENABLE_SHAKER = 0x10; +const uint32 PORTALLOCATOR_ENABLE_BUNDLE = 0x20; +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 kDefaultPortAllocatorFlags = 0; + +const uint32 kDefaultStepDelay = 1000; // 1 sec step delay. +// As per RFC 5245 Appendix B.1, STUN transactions need to be paced at certain +// internal. Less than 20ms is not acceptable. We choose 50ms as our default. +const uint32 kMinimumStepDelay = 50; + +class PortAllocatorSessionMuxer; + +class PortAllocatorSession : public sigslot::has_slots<> { + public: + // Content name passed in mostly for logging and debugging. + // TODO(mallinath) - Change username and password to ice_ufrag and ice_pwd. + PortAllocatorSession(const std::string& content_name, + int component, + const std::string& username, + const std::string& password, + uint32 flags); + + // Subclasses should clean up any ports created. + virtual ~PortAllocatorSession() {} + + uint32 flags() const { return flags_; } + void set_flags(uint32 flags) { flags_ = flags; } + std::string content_name() const { return content_name_; } + int component() const { return component_; } + + // Starts gathering STUN and Relay configurations. + virtual void StartGettingPorts() = 0; + virtual void StopGettingPorts() = 0; + virtual bool IsGettingPorts() = 0; + + sigslot::signal2 SignalPortReady; + sigslot::signal2&> SignalCandidatesReady; + sigslot::signal1 SignalCandidatesAllocationDone; + + virtual uint32 generation() { return generation_; } + virtual void set_generation(uint32 generation) { generation_ = generation; } + sigslot::signal1 SignalDestroyed; + + protected: + const std::string& username() const { return username_; } + const std::string& password() const { return password_; } + + std::string content_name_; + int component_; + + private: + uint32 flags_; + uint32 generation_; + std::string username_; + std::string password_; +}; + +class PortAllocator : public sigslot::has_slots<> { + public: + PortAllocator() : + flags_(kDefaultPortAllocatorFlags), + min_port_(0), + max_port_(0), + step_delay_(kDefaultStepDelay), + allow_tcp_listen_(true) { + // This will allow us to have old behavior on non webrtc clients. + } + virtual ~PortAllocator(); + + PortAllocatorSession* CreateSession( + const std::string& sid, + const std::string& content_name, + int component, + const std::string& ice_ufrag, + const std::string& ice_pwd); + + PortAllocatorSessionMuxer* GetSessionMuxer(const std::string& key) const; + void OnSessionMuxerDestroyed(PortAllocatorSessionMuxer* session); + + uint32 flags() const { return flags_; } + void set_flags(uint32 flags) { flags_ = flags; } + + const std::string& user_agent() const { return agent_; } + const talk_base::ProxyInfo& proxy() const { return proxy_; } + void set_proxy(const std::string& agent, const talk_base::ProxyInfo& proxy) { + agent_ = agent; + proxy_ = proxy; + } + + // Gets/Sets the port range to use when choosing client ports. + int min_port() const { return min_port_; } + int max_port() const { return max_port_; } + bool SetPortRange(int min_port, int max_port) { + if (min_port > max_port) { + return false; + } + + min_port_ = min_port; + max_port_ = max_port; + return true; + } + + uint32 step_delay() const { return step_delay_; } + void set_step_delay(uint32 delay) { + ASSERT(delay >= kMinimumStepDelay); + step_delay_ = delay; + } + + bool allow_tcp_listen() const { return allow_tcp_listen_; } + void set_allow_tcp_listen(bool allow_tcp_listen) { + allow_tcp_listen_ = allow_tcp_listen; + } + + protected: + virtual PortAllocatorSession* CreateSessionInternal( + const std::string& content_name, + int component, + const std::string& ice_ufrag, + const std::string& ice_pwd) = 0; + + typedef std::map SessionMuxerMap; + + uint32 flags_; + std::string agent_; + talk_base::ProxyInfo proxy_; + int min_port_; + int max_port_; + uint32 step_delay_; + SessionMuxerMap muxers_; + bool allow_tcp_listen_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_PORTALLOCATOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portallocatorsessionproxy.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portallocatorsessionproxy.h new file mode 100644 index 0000000..4f57821 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portallocatorsessionproxy.h @@ -0,0 +1,123 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_PORTALLOCATORSESSIONPROXY_H_ +#define TALK_P2P_BASE_PORTALLOCATORSESSIONPROXY_H_ + +#include + +#include "talk/p2p/base/candidate.h" +#include "talk/p2p/base/portallocator.h" + +namespace cricket { +class PortAllocator; +class PortAllocatorSessionProxy; +class PortProxy; + +// This class maintains the list of cricket::Port* objects. Ports will be +// deleted upon receiving SignalDestroyed signal. This class is used when +// PORTALLOCATOR_ENABLE_BUNDLE flag is set. + +class PortAllocatorSessionMuxer : public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + explicit PortAllocatorSessionMuxer(PortAllocatorSession* session); + virtual ~PortAllocatorSessionMuxer(); + + void RegisterSessionProxy(PortAllocatorSessionProxy* session_proxy); + + void OnPortReady(PortAllocatorSession* session, PortInterface* port); + void OnPortDestroyed(PortInterface* port); + void OnCandidatesAllocationDone(PortAllocatorSession* session); + + const std::vector& ports() { return ports_; } + + sigslot::signal1 SignalDestroyed; + + private: + virtual void OnMessage(talk_base::Message *pmsg); + void OnSessionProxyDestroyed(PortAllocatorSession* proxy); + void SendAllocationDone_w(PortAllocatorSessionProxy* proxy); + void SendAllocatedPorts_w(PortAllocatorSessionProxy* proxy); + + // Port will be deleted when SignalDestroyed received, otherwise delete + // happens when PortAllocatorSession dtor is called. + talk_base::Thread* worker_thread_; + std::vector ports_; + talk_base::scoped_ptr session_; + std::vector session_proxies_; + bool candidate_done_signal_received_; +}; + +class PortAllocatorSessionProxy : public PortAllocatorSession { + public: + PortAllocatorSessionProxy(const std::string& content_name, + int component, + uint32 flags) + // Use empty string as the ufrag and pwd because the proxy always uses + // the ufrag and pwd from the underlying implementation. + : PortAllocatorSession(content_name, component, "", "", flags), + impl_(NULL) { + } + + virtual ~PortAllocatorSessionProxy(); + + PortAllocatorSession* impl() { return impl_; } + void set_impl(PortAllocatorSession* session); + + // Forwards call to the actual PortAllocatorSession. + virtual void StartGettingPorts(); + virtual void StopGettingPorts(); + virtual bool IsGettingPorts(); + + virtual void set_generation(uint32 generation) { + ASSERT(impl_ != NULL); + impl_->set_generation(generation); + } + + virtual uint32 generation() { + ASSERT(impl_ != NULL); + return impl_->generation(); + } + + private: + void OnPortReady(PortAllocatorSession* session, PortInterface* port); + void OnCandidatesReady(PortAllocatorSession* session, + const std::vector& candidates); + void OnPortDestroyed(PortInterface* port); + void OnCandidatesAllocationDone(PortAllocatorSession* session); + + // This is the actual PortAllocatorSession, owned by PortAllocator. + PortAllocatorSession* impl_; + std::map proxy_ports_; + + friend class PortAllocatorSessionMuxer; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_PORTALLOCATORSESSIONPROXY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portinterface.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portinterface.h new file mode 100644 index 0000000..cc793b6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portinterface.h @@ -0,0 +1,143 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_PORTINTERFACE_H_ +#define TALK_P2P_BASE_PORTINTERFACE_H_ + +#include + +#include "talk/base/socketaddress.h" +#include "talk/p2p/base/transport.h" + +namespace talk_base { +class Network; +struct PacketOptions; +} + +namespace cricket { +class Connection; +class IceMessage; +class StunMessage; + +enum ProtocolType { + PROTO_UDP, + PROTO_TCP, + PROTO_SSLTCP, + PROTO_LAST = PROTO_SSLTCP +}; + +// Defines the interface for a port, which represents a local communication +// mechanism that can be used to create connections to similar mechanisms of +// the other client. Various types of ports will implement this interface. +class PortInterface { + public: + virtual ~PortInterface() {} + + virtual const std::string& Type() const = 0; + virtual talk_base::Network* Network() const = 0; + + virtual void SetIceProtocolType(IceProtocolType protocol) = 0; + virtual IceProtocolType IceProtocol() const = 0; + + // Methods to set/get ICE role and tiebreaker values. + virtual void SetIceRole(IceRole role) = 0; + virtual IceRole GetIceRole() const = 0; + + virtual void SetIceTiebreaker(uint64 tiebreaker) = 0; + virtual uint64 IceTiebreaker() const = 0; + + virtual bool SharedSocket() const = 0; + + // PrepareAddress will attempt to get an address for this port that other + // clients can send to. It may take some time before the address is ready. + // Once it is ready, we will send SignalAddressReady. If errors are + // preventing the port from getting an address, it may send + // SignalAddressError. + virtual void PrepareAddress() = 0; + + // Returns the connection to the given address or NULL if none exists. + virtual Connection* GetConnection( + const talk_base::SocketAddress& remote_addr) = 0; + + // Creates a new connection to the given address. + enum CandidateOrigin { ORIGIN_THIS_PORT, ORIGIN_OTHER_PORT, ORIGIN_MESSAGE }; + virtual Connection* CreateConnection( + const Candidate& remote_candidate, CandidateOrigin origin) = 0; + + // Functions on the underlying socket(s). + virtual int SetOption(talk_base::Socket::Option opt, int value) = 0; + virtual int GetOption(talk_base::Socket::Option opt, int* value) = 0; + virtual int GetError() = 0; + + virtual const std::vector& Candidates() const = 0; + + // Sends the given packet to the given address, provided that the address is + // 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, + 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 + // into a real connection, call CreateConnection. + sigslot::signal6 SignalUnknownAddress; + + // Sends a response message (normal or error) to the given request. One of + // these methods should be called as a response to SignalUnknownAddress. + // NOTE: You MUST call CreateConnection BEFORE SendBindingResponse. + virtual void SendBindingResponse(StunMessage* request, + const talk_base::SocketAddress& addr) = 0; + virtual void SendBindingErrorResponse( + StunMessage* request, const talk_base::SocketAddress& addr, + int error_code, const std::string& reason) = 0; + + // Signaled when this port decides to delete itself because it no longer has + // any usefulness. + sigslot::signal1 SignalDestroyed; + + // Signaled when Port discovers ice role conflict with the peer. + sigslot::signal1 SignalRoleConflict; + + // Normally, packets arrive through a connection (or they result signaling of + // unknown address). Calling this method turns off delivery of packets + // through their respective connection and instead delivers every packet + // through this port. + virtual void EnablePortPackets() = 0; + sigslot::signal4 SignalReadPacket; + + virtual std::string ToString() const = 0; + + protected: + PortInterface() {} +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_PORTINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portproxy.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portproxy.h new file mode 100644 index 0000000..0db3ab7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/portproxy.h @@ -0,0 +1,104 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_PORTPROXY_H_ +#define TALK_P2P_BASE_PORTPROXY_H_ + +#include "talk/base/sigslot.h" +#include "talk/p2p/base/portinterface.h" + +namespace talk_base { +class Network; +} + +namespace cricket { + +class PortProxy : public PortInterface, public sigslot::has_slots<> { + public: + PortProxy() {} + virtual ~PortProxy() {} + + PortInterface* impl() { return impl_; } + void set_impl(PortInterface* port); + + virtual const std::string& Type() const; + virtual talk_base::Network* Network() const; + + virtual void SetIceProtocolType(IceProtocolType protocol); + virtual IceProtocolType IceProtocol() const; + + // Methods to set/get ICE role and tiebreaker values. + virtual void SetIceRole(IceRole role); + virtual IceRole GetIceRole() const; + + virtual void SetIceTiebreaker(uint64 tiebreaker); + virtual uint64 IceTiebreaker() const; + + virtual bool SharedSocket() const; + + // Forwards call to the actual Port. + virtual void PrepareAddress(); + virtual Connection* CreateConnection(const Candidate& remote_candidate, + CandidateOrigin origin); + virtual Connection* GetConnection( + const talk_base::SocketAddress& remote_addr); + + virtual int SendTo(const void* data, size_t size, + const talk_base::SocketAddress& addr, + 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 const std::vector& Candidates() const; + + virtual void SendBindingResponse(StunMessage* request, + const talk_base::SocketAddress& addr); + virtual void SendBindingErrorResponse( + StunMessage* request, const talk_base::SocketAddress& addr, + int error_code, const std::string& reason); + + virtual void EnablePortPackets(); + virtual std::string ToString() const; + + private: + void OnUnknownAddress(PortInterface *port, + const talk_base::SocketAddress &addr, + ProtocolType proto, + IceMessage *stun_msg, + const std::string &remote_username, + bool port_muxed); + void OnRoleConflict(PortInterface* port); + void OnPortDestroyed(PortInterface* port); + + PortInterface* impl_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_PORTPROXY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/pseudotcp.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/pseudotcp.h new file mode 100644 index 0000000..8778b52 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/pseudotcp.h @@ -0,0 +1,258 @@ +/* + * 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 TALK_P2P_BASE_PSEUDOTCP_H_ +#define TALK_P2P_BASE_PSEUDOTCP_H_ + +#include + +#include "talk/base/basictypes.h" +#include "talk/base/stream.h" + +namespace cricket { + +////////////////////////////////////////////////////////////////////// +// IPseudoTcpNotify +////////////////////////////////////////////////////////////////////// + +class PseudoTcp; + +class IPseudoTcpNotify { + public: + // Notification of tcp events + virtual void OnTcpOpen(PseudoTcp* tcp) = 0; + virtual void OnTcpReadable(PseudoTcp* tcp) = 0; + virtual void OnTcpWriteable(PseudoTcp* tcp) = 0; + virtual void OnTcpClosed(PseudoTcp* tcp, uint32 error) = 0; + + // Write the packet onto the network + enum WriteResult { WR_SUCCESS, WR_TOO_LARGE, WR_FAIL }; + virtual WriteResult TcpWritePacket(PseudoTcp* tcp, + const char* buffer, size_t len) = 0; + + protected: + virtual ~IPseudoTcpNotify() {} +}; + +////////////////////////////////////////////////////////////////////// +// PseudoTcp +////////////////////////////////////////////////////////////////////// + +class PseudoTcp { + public: + static uint32 Now(); + + PseudoTcp(IPseudoTcpNotify* notify, uint32 conv); + virtual ~PseudoTcp(); + + int Connect(); + int Recv(char* buffer, size_t len); + int Send(const char* buffer, size_t len); + void Close(bool force); + int GetError(); + + enum TcpState { + TCP_LISTEN, TCP_SYN_SENT, TCP_SYN_RECEIVED, TCP_ESTABLISHED, TCP_CLOSED + }; + TcpState State() const { return m_state; } + + // Call this when the PMTU changes. + void NotifyMTU(uint16 mtu); + + // Call this based on timeout value returned from GetNextClock. + // It's ok to call this too frequently. + void NotifyClock(uint32 now); + + // Call this whenever a packet arrives. + // Returns true if the packet was processed successfully. + bool NotifyPacket(const char * buffer, size_t len); + + // Call this to determine the next time NotifyClock should be called. + // Returns false if the socket is ready to be destroyed. + bool GetNextClock(uint32 now, long& timeout); + + // Call these to get/set option values to tailor this PseudoTcp + // instance's behaviour for the kind of data it will carry. + // If an unrecognized option is set or got, an assertion will fire. + // + // Setting options for OPT_RCVBUF or OPT_SNDBUF after Connect() is called + // will result in an assertion. + enum Option { + OPT_NODELAY, // Whether to enable Nagle's algorithm (0 == off) + OPT_ACKDELAY, // The Delayed ACK timeout (0 == off). + OPT_RCVBUF, // Set the receive buffer size, in bytes. + OPT_SNDBUF, // Set the send buffer size, in bytes. + }; + void GetOption(Option opt, int* value); + void SetOption(Option opt, int value); + + // Returns current congestion window in bytes. + uint32 GetCongestionWindow() const; + + // Returns amount of data in bytes that has been sent, but haven't + // been acknowledged. + uint32 GetBytesInFlight() const; + + // Returns number of bytes that were written in buffer and haven't + // been sent. + uint32 GetBytesBufferedNotSent() const; + + // Returns current round-trip time estimate in milliseconds. + uint32 GetRoundTripTimeEstimateMs() const; + + protected: + enum SendFlags { sfNone, sfDelayedAck, sfImmediateAck }; + + struct Segment { + uint32 conv, seq, ack; + uint8 flags; + uint16 wnd; + const char * data; + uint32 len; + uint32 tsval, tsecr; + }; + + struct SSegment { + SSegment(uint32 s, uint32 l, bool c) + : seq(s), len(l), /*tstamp(0),*/ xmit(0), bCtrl(c) { + } + uint32 seq, len; + //uint32 tstamp; + uint8 xmit; + bool bCtrl; + }; + typedef std::list SList; + + struct RSegment { + uint32 seq, len; + }; + + uint32 queue(const char* data, uint32 len, bool bCtrl); + + // Creates a packet and submits it to the network. This method can either + // send payload or just an ACK packet. + // + // |seq| is the sequence number of this packet. + // |flags| is the flags for sending this packet. + // |offset| is the offset to read from |m_sbuf|. + // |len| is the number of bytes to read from |m_sbuf| as payload. If this + // value is 0 then this is an ACK packet, otherwise this packet has payload. + IPseudoTcpNotify::WriteResult packet(uint32 seq, uint8 flags, + uint32 offset, uint32 len); + bool parse(const uint8* buffer, uint32 size); + + void attemptSend(SendFlags sflags = sfNone); + + void closedown(uint32 err = 0); + + bool clock_check(uint32 now, long& nTimeout); + + bool process(Segment& seg); + bool transmit(const SList::iterator& seg, uint32 now); + + void adjustMTU(); + + protected: + // This method is used in test only to query receive buffer state. + bool isReceiveBufferFull() const; + + // This method is only used in tests, to disable window scaling + // support for testing backward compatibility. + void disableWindowScale(); + + private: + // Queue the connect message with TCP options. + void queueConnectMessage(); + + // Parse TCP options in the header. + void parseOptions(const char* data, uint32 len); + + // Apply a TCP option that has been read from the header. + void applyOption(char kind, const char* data, uint32 len); + + // Apply window scale option. + void applyWindowScaleOption(uint8 scale_factor); + + // Resize the send buffer with |new_size| in bytes. + void resizeSendBuffer(uint32 new_size); + + // Resize the receive buffer with |new_size| in bytes. This call adjusts + // window scale factor |m_swnd_scale| accordingly. + void resizeReceiveBuffer(uint32 new_size); + + IPseudoTcpNotify* m_notify; + enum Shutdown { SD_NONE, SD_GRACEFUL, SD_FORCEFUL } m_shutdown; + int m_error; + + // TCB data + TcpState m_state; + uint32 m_conv; + bool m_bReadEnable, m_bWriteEnable, m_bOutgoing; + uint32 m_lasttraffic; + + // Incoming data + typedef std::list RList; + RList m_rlist; + uint32 m_rbuf_len, m_rcv_nxt, m_rcv_wnd, m_lastrecv; + uint8 m_rwnd_scale; // Window scale factor. + talk_base::FifoBuffer m_rbuf; + + // Outgoing data + SList m_slist; + uint32 m_sbuf_len, m_snd_nxt, m_snd_wnd, m_lastsend, m_snd_una; + uint8 m_swnd_scale; // Window scale factor. + talk_base::FifoBuffer m_sbuf; + + // Maximum segment size, estimated protocol level, largest segment sent + uint32 m_mss, m_msslevel, m_largest, m_mtu_advise; + // Retransmit timer + uint32 m_rto_base; + + // Timestamp tracking + uint32 m_ts_recent, m_ts_lastack; + + // Round-trip calculation + uint32 m_rx_rttvar, m_rx_srtt, m_rx_rto; + + // Congestion avoidance, Fast retransmit/recovery, Delayed ACKs + uint32 m_ssthresh, m_cwnd; + uint8 m_dup_acks; + uint32 m_recover; + uint32 m_t_ack; + + // Configuration options + bool m_use_nagling; + uint32 m_ack_delay; + + // This is used by unit tests to test backward compatibility of + // PseudoTcp implementations that don't support window scaling. + bool m_support_wnd_scale; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_PSEUDOTCP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/rawtransport.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/rawtransport.h new file mode 100644 index 0000000..30ba010 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/rawtransport.h @@ -0,0 +1,81 @@ +/* + * 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 TALK_P2P_BASE_RAWTRANSPORT_H_ +#define TALK_P2P_BASE_RAWTRANSPORT_H_ + +#include +#include "talk/p2p/base/transport.h" + +#if defined(FEATURE_ENABLE_PSTN) +namespace cricket { + +// Implements a transport that only sends raw packets, no STUN. As a result, +// it cannot do pings to determine connectivity, so it only uses a single port +// that it thinks will work. +class RawTransport : public Transport, public TransportParser { + public: + RawTransport(talk_base::Thread* signaling_thread, + talk_base::Thread* worker_thread, + const std::string& content_name, + PortAllocator* allocator); + virtual ~RawTransport(); + + virtual bool ParseCandidates(SignalingProtocol protocol, + const buzz::XmlElement* elem, + const CandidateTranslator* translator, + Candidates* candidates, + ParseError* error); + virtual bool WriteCandidates(SignalingProtocol protocol, + const Candidates& candidates, + const CandidateTranslator* translator, + XmlElements* candidate_elems, + WriteError* error); + + protected: + // Creates and destroys raw channels. + virtual TransportChannelImpl* CreateTransportChannel(int component); + virtual void DestroyTransportChannel(TransportChannelImpl* channel); + + private: + // Parses the given element, which should describe the address to use for a + // given channel. This will return false and signal an error if the address + // or channel name is bad. + bool ParseRawAddress(const buzz::XmlElement* elem, + talk_base::SocketAddress* addr, + ParseError* error); + + friend class RawTransportChannel; // For ParseAddress. + + DISALLOW_EVIL_CONSTRUCTORS(RawTransport); +}; + +} // namespace cricket + +#endif // defined(FEATURE_ENABLE_PSTN) + +#endif // TALK_P2P_BASE_RAWTRANSPORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/rawtransportchannel.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/rawtransportchannel.h new file mode 100644 index 0000000..db5265e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/rawtransportchannel.h @@ -0,0 +1,206 @@ +/* + * 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 TALK_P2P_BASE_RAWTRANSPORTCHANNEL_H_ +#define TALK_P2P_BASE_RAWTRANSPORTCHANNEL_H_ + +#include +#include +#include "talk/base/messagequeue.h" +#include "talk/p2p/base/transportchannelimpl.h" +#include "talk/p2p/base/rawtransport.h" +#include "talk/p2p/base/candidate.h" + +#if defined(FEATURE_ENABLE_PSTN) + +namespace talk_base { +class Thread; +} + +namespace cricket { + +class Connection; +class PortAllocator; +class PortAllocatorSession; +class PortInterface; +class RelayPort; +class StunPort; + +// Implements a channel that just sends bare packets once we have received the +// address of the other side. We pick a single address to send them based on +// a simple investigation of NAT type. +class RawTransportChannel : public TransportChannelImpl, + public talk_base::MessageHandler { + public: + RawTransportChannel(const std::string& content_name, + int component, + RawTransport* transport, + talk_base::Thread *worker_thread, + PortAllocator *allocator); + virtual ~RawTransportChannel(); + + // Implementation of normal channel packet sending. + virtual int SendPacket(const char *data, size_t len, + const talk_base::PacketOptions& options, int flags); + virtual int SetOption(talk_base::Socket::Option opt, int value); + virtual int GetError(); + + // Implements TransportChannelImpl. + virtual Transport* GetTransport() { return raw_transport_; } + virtual void SetIceCredentials(const std::string& ice_ufrag, + const std::string& ice_pwd) {} + virtual void SetRemoteIceCredentials(const std::string& ice_ufrag, + const std::string& ice_pwd) {} + + // Creates an allocator session to start figuring out which type of + // port we should send to the other client. This will send + // SignalAvailableCandidate once we have decided. + virtual void Connect(); + + // Resets state back to unconnected. + virtual void Reset(); + + // We don't actually worry about signaling since we can't send new candidates. + virtual void OnSignalingReady() {} + + // Handles a message setting the remote address. We are writable once we + // have this since we now know where to send. + virtual void OnCandidate(const Candidate& candidate); + + void OnRemoteAddress(const talk_base::SocketAddress& remote_address); + + // Below ICE specific virtual methods not implemented. + 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; + } + + // DTLS methods. + virtual bool IsDtlsActive() const { return false; } + + // Default implementation. + virtual bool GetSslRole(talk_base::SSLRole* role) const { + return false; + } + + virtual bool SetSslRole(talk_base::SSLRole role) { + return false; + } + + // Set up the ciphers to use for DTLS-SRTP. + virtual bool SetSrtpCiphers(const std::vector& ciphers) { + return false; + } + + // Find out which DTLS-SRTP cipher was negotiated + virtual bool GetSrtpCipher(std::string* cipher) { + return false; + } + + // Returns false because the channel is not DTLS. + virtual bool GetLocalIdentity(talk_base::SSLIdentity** identity) const { + return false; + } + + virtual bool GetRemoteCertificate(talk_base::SSLCertificate** cert) const { + return false; + } + + // Allows key material to be extracted for external encryption. + virtual bool ExportKeyingMaterial( + const std::string& label, + const uint8* context, + size_t context_len, + bool use_context, + uint8* result, + size_t result_len) { + return false; + } + + virtual bool SetLocalIdentity(talk_base::SSLIdentity* identity) { + return false; + } + + // Set DTLS Remote fingerprint. Must be after local identity set. + virtual bool SetRemoteFingerprint( + const std::string& digest_alg, + const uint8* digest, + size_t digest_len) { + return false; + } + + private: + RawTransport* raw_transport_; + talk_base::Thread *worker_thread_; + PortAllocator* allocator_; + PortAllocatorSession* allocator_session_; + StunPort* stun_port_; + RelayPort* relay_port_; + PortInterface* port_; + bool use_relay_; + talk_base::SocketAddress remote_address_; + + // Called when the allocator creates another port. + void OnPortReady(PortAllocatorSession* session, PortInterface* port); + + // Called when one of the ports we are using has determined its address. + void OnCandidatesReady(PortAllocatorSession *session, + const std::vector& candidates); + + // Called once we have chosen the port to use for communication with the + // other client. This will send its address and prepare the port for use. + void SetPort(PortInterface* port); + + // Called once we have a port and a remote address. This will set mark the + // channel as writable and signal the route to the client. + void SetWritable(); + + // Called when we receive a packet from the other client. + void OnReadPacket(PortInterface* port, const char* data, size_t size, + const talk_base::SocketAddress& addr); + + // Handles a message to destroy unused ports. + virtual void OnMessage(talk_base::Message *msg); + + DISALLOW_EVIL_CONSTRUCTORS(RawTransportChannel); +}; + +} // namespace cricket + +#endif // defined(FEATURE_ENABLE_PSTN) +#endif // TALK_P2P_BASE_RAWTRANSPORTCHANNEL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/relayport.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/relayport.h new file mode 100644 index 0000000..b56bf26 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/relayport.h @@ -0,0 +1,118 @@ +/* + * 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 TALK_P2P_BASE_RELAYPORT_H_ +#define TALK_P2P_BASE_RELAYPORT_H_ + +#include +#include +#include +#include + +#include "talk/p2p/base/port.h" +#include "talk/p2p/base/stunrequest.h" + +namespace cricket { + +class RelayEntry; +class RelayConnection; + +// Communicates using an allocated port on the relay server. For each +// remote candidate that we try to send data to a RelayEntry instance +// is created. The RelayEntry will try to reach the remote destination +// by connecting to all available server addresses in a pre defined +// order with a small delay in between. When a connection is +// successful all other connection attemts are aborted. +class RelayPort : public Port { + public: + typedef std::pair OptionValue; + + // RelayPort doesn't yet do anything fancy in the ctor. + static RelayPort* 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, + const std::string& password) { + return new RelayPort(thread, factory, network, ip, min_port, max_port, + username, password); + } + virtual ~RelayPort(); + + void AddServerAddress(const ProtocolAddress& addr); + void AddExternalAddress(const ProtocolAddress& addr); + + const std::vector& options() const { return options_; } + bool HasMagicCookie(const char* data, size_t size); + + virtual void PrepareAddress(); + virtual Connection* CreateConnection(const Candidate& address, + CandidateOrigin origin); + virtual int SetOption(talk_base::Socket::Option opt, int value); + virtual int GetOption(talk_base::Socket::Option opt, int* value); + virtual int GetError(); + + const ProtocolAddress * ServerAddress(size_t index) const; + bool IsReady() { return ready_; } + + // Used for testing. + sigslot::signal1 SignalConnectFailure; + sigslot::signal1 SignalSoftTimeout; + + protected: + RelayPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory, + talk_base::Network*, const talk_base::IPAddress& ip, + int min_port, int max_port, const std::string& username, + const std::string& password); + bool Init(); + + void SetReady(); + + virtual int SendTo(const void* data, size_t size, + const talk_base::SocketAddress& addr, + const talk_base::PacketOptions& options, + bool payload); + + // Dispatches the given packet to the port or connection as appropriate. + void OnReadPacket(const char* data, size_t size, + const talk_base::SocketAddress& remote_addr, + ProtocolType proto, + const talk_base::PacketTime& packet_time); + + private: + friend class RelayEntry; + + std::deque server_addr_; + std::vector external_addr_; + bool ready_; + std::vector entries_; + std::vector options_; + int error_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_RELAYPORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/relayserver.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/relayserver.h new file mode 100644 index 0000000..ad33adc --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/relayserver.h @@ -0,0 +1,252 @@ +/* + * 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 TALK_P2P_BASE_RELAYSERVER_H_ +#define TALK_P2P_BASE_RELAYSERVER_H_ + +#include +#include +#include + +#include "talk/base/asyncudpsocket.h" +#include "talk/base/socketaddresspair.h" +#include "talk/base/thread.h" +#include "talk/base/timeutils.h" +#include "talk/p2p/base/port.h" +#include "talk/p2p/base/stun.h" + +namespace cricket { + +class RelayServerBinding; +class RelayServerConnection; + +// Relays traffic between connections to the server that are "bound" together. +// All connections created with the same username/password are bound together. +class RelayServer : public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + // Creates a server, which will use this thread to post messages to itself. + explicit RelayServer(talk_base::Thread* thread); + ~RelayServer(); + + talk_base::Thread* thread() { return thread_; } + + // Indicates whether we will print updates of the number of bindings. + bool log_bindings() const { return log_bindings_; } + void set_log_bindings(bool log_bindings) { log_bindings_ = log_bindings; } + + // Updates the set of sockets that the server uses to talk to "internal" + // clients. These are clients that do the "port allocations". + void AddInternalSocket(talk_base::AsyncPacketSocket* socket); + void RemoveInternalSocket(talk_base::AsyncPacketSocket* socket); + + // Updates the set of sockets that the server uses to talk to "external" + // clients. These are the clients that do not do allocations. They do not + // know that these addresses represent a relay server. + void AddExternalSocket(talk_base::AsyncPacketSocket* socket); + void RemoveExternalSocket(talk_base::AsyncPacketSocket* socket); + + // Starts listening for connections on this sockets. When someone + // tries to connect, the connection will be accepted and a new + // internal socket will be added. + void AddInternalServerSocket(talk_base::AsyncSocket* socket, + cricket::ProtocolType proto); + + // Removes this server socket from the list. + void RemoveInternalServerSocket(talk_base::AsyncSocket* socket); + + // Methods for testing and debuging. + int GetConnectionCount() const; + talk_base::SocketAddressPair GetConnection(int connection) const; + bool HasConnection(const talk_base::SocketAddress& address) const; + + private: + typedef std::vector SocketList; + typedef std::map ServerSocketMap; + typedef std::map BindingMap; + typedef std::map ConnectionMap; + + talk_base::Thread* thread_; + bool log_bindings_; + SocketList internal_sockets_; + SocketList external_sockets_; + SocketList removed_sockets_; + ServerSocketMap server_sockets_; + BindingMap bindings_; + ConnectionMap connections_; + + // Called when a packet is received by the server on one of its sockets. + void OnInternalPacket(talk_base::AsyncPacketSocket* socket, + const char* bytes, size_t size, + const talk_base::SocketAddress& remote_addr, + const talk_base::PacketTime& packet_time); + void OnExternalPacket(talk_base::AsyncPacketSocket* socket, + const char* bytes, size_t size, + const talk_base::SocketAddress& remote_addr, + const talk_base::PacketTime& packet_time); + + void OnReadEvent(talk_base::AsyncSocket* socket); + + // Processes the relevant STUN request types from the client. + bool HandleStun(const char* bytes, size_t size, + const talk_base::SocketAddress& remote_addr, + talk_base::AsyncPacketSocket* socket, + std::string* username, StunMessage* msg); + void HandleStunAllocate(const char* bytes, size_t size, + const talk_base::SocketAddressPair& ap, + talk_base::AsyncPacketSocket* socket); + void HandleStun(RelayServerConnection* int_conn, const char* bytes, + size_t size); + void HandleStunAllocate(RelayServerConnection* int_conn, + const StunMessage& msg); + void HandleStunSend(RelayServerConnection* int_conn, const StunMessage& msg); + + // Adds/Removes the a connection or binding. + void AddConnection(RelayServerConnection* conn); + void RemoveConnection(RelayServerConnection* conn); + void RemoveBinding(RelayServerBinding* binding); + + // Handle messages in our worker thread. + void OnMessage(talk_base::Message *pmsg); + + // Called when the timer for checking lifetime times out. + void OnTimeout(RelayServerBinding* binding); + + // Accept connections on this server socket. + void AcceptConnection(talk_base::AsyncSocket* server_socket); + + friend class RelayServerConnection; + friend class RelayServerBinding; +}; + +// Maintains information about a connection to the server. Each connection is +// part of one and only one binding. +class RelayServerConnection { + public: + RelayServerConnection(RelayServerBinding* binding, + const talk_base::SocketAddressPair& addrs, + talk_base::AsyncPacketSocket* socket); + ~RelayServerConnection(); + + RelayServerBinding* binding() { return binding_; } + talk_base::AsyncPacketSocket* socket() { return socket_; } + + // Returns a pair where the source is the remote address and the destination + // is the local address. + const talk_base::SocketAddressPair& addr_pair() { return addr_pair_; } + + // Sends a packet to the connected client. If an address is provided, then + // we make sure the internal client receives it, wrapping if necessary. + void Send(const char* data, size_t size); + void Send(const char* data, size_t size, + const talk_base::SocketAddress& ext_addr); + + // Sends a STUN message to the connected client with no wrapping. + void SendStun(const StunMessage& msg); + void SendStunError(const StunMessage& request, int code, const char* desc); + + // A locked connection is one for which we know the intended destination of + // any raw packet received. + bool locked() const { return locked_; } + void Lock(); + void Unlock(); + + // Records the address that raw packets should be forwarded to (for internal + // packets only; for external, we already know where they go). + const talk_base::SocketAddress& default_destination() const { + return default_dest_; + } + void set_default_destination(const talk_base::SocketAddress& addr) { + default_dest_ = addr; + } + + private: + RelayServerBinding* binding_; + talk_base::SocketAddressPair addr_pair_; + talk_base::AsyncPacketSocket* socket_; + bool locked_; + talk_base::SocketAddress default_dest_; +}; + +// Records a set of internal and external connections that we relay between, +// or in other words, that are "bound" together. +class RelayServerBinding : public talk_base::MessageHandler { + public: + RelayServerBinding( + RelayServer* server, const std::string& username, + const std::string& password, uint32 lifetime); + virtual ~RelayServerBinding(); + + RelayServer* server() { return server_; } + uint32 lifetime() { return lifetime_; } + const std::string& username() { return username_; } + const std::string& password() { return password_; } + const std::string& magic_cookie() { return magic_cookie_; } + + // Adds/Removes a connection into the binding. + void AddInternalConnection(RelayServerConnection* conn); + void AddExternalConnection(RelayServerConnection* conn); + + // We keep track of the use of each binding. If we detect that it was not + // used for longer than the lifetime, then we send a signal. + void NoteUsed(); + sigslot::signal1 SignalTimeout; + + // Determines whether the given packet has the magic cookie present (in the + // right place). + bool HasMagicCookie(const char* bytes, size_t size) const; + + // Determines the connection to use to send packets to or from the given + // external address. + RelayServerConnection* GetInternalConnection( + const talk_base::SocketAddress& ext_addr); + RelayServerConnection* GetExternalConnection( + const talk_base::SocketAddress& ext_addr); + + // MessageHandler: + void OnMessage(talk_base::Message *pmsg); + + private: + RelayServer* server_; + + std::string username_; + std::string password_; + std::string magic_cookie_; + + std::vector internal_connections_; + std::vector external_connections_; + + uint32 lifetime_; + uint32 last_used_; + // TODO: bandwidth +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_RELAYSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/session.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/session.h new file mode 100644 index 0000000..06ff403 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/session.h @@ -0,0 +1,768 @@ +/* + * 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 TALK_P2P_BASE_SESSION_H_ +#define TALK_P2P_BASE_SESSION_H_ + +#include +#include +#include +#include + +#include "talk/base/refcount.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/scoped_ref_ptr.h" +#include "talk/base/socketaddress.h" +#include "talk/p2p/base/parsing.h" +#include "talk/p2p/base/port.h" +#include "talk/p2p/base/sessionclient.h" +#include "talk/p2p/base/sessionmanager.h" +#include "talk/p2p/base/sessionmessages.h" +#include "talk/p2p/base/transport.h" +#include "talk/xmllite/xmlelement.h" +#include "talk/xmpp/constants.h" + +namespace cricket { + +class BaseSession; +class P2PTransportChannel; +class Transport; +class TransportChannel; +class TransportChannelProxy; +class TransportChannelImpl; + +typedef talk_base::RefCountedObject > +TransportWrapper; + +// Used for errors that will send back a specific error message to the +// remote peer. We add "type" to the errors because it's needed for +// SignalErrorMessage. +struct MessageError : ParseError { + buzz::QName type; + + // if unset, assume type is a parse error + MessageError() : ParseError(), type(buzz::QN_STANZA_BAD_REQUEST) {} + + void SetType(const buzz::QName type) { + this->type = type; + } +}; + +// Used for errors that may be returned by public session methods that +// can fail. +// TODO: Use this error in Session::Initiate and +// Session::Accept. +struct SessionError : WriteError { +}; + +// Bundles a Transport and ChannelMap together. ChannelMap is used to +// create transport channels before receiving or sending a session +// initiate, and for speculatively connecting channels. Previously, a +// session had one ChannelMap and transport. Now, with multiple +// transports per session, we need multiple ChannelMaps as well. + +typedef std::map ChannelMap; + +class TransportProxy : public sigslot::has_slots<>, + public CandidateTranslator { + public: + TransportProxy( + talk_base::Thread* worker_thread, + const std::string& sid, + const std::string& content_name, + TransportWrapper* transport) + : worker_thread_(worker_thread), + sid_(sid), + content_name_(content_name), + transport_(transport), + connecting_(false), + negotiated_(false), + sent_candidates_(false), + candidates_allocated_(false), + local_description_set_(false), + remote_description_set_(false) { + transport_->get()->SignalCandidatesReady.connect( + this, &TransportProxy::OnTransportCandidatesReady); + } + ~TransportProxy(); + + std::string content_name() const { return content_name_; } + // TODO(juberti): It's not good form to expose the object you're wrapping, + // since callers can mutate it. Can we make this return a const Transport*? + Transport* impl() const { return transport_->get(); } + + std::string type() const; + bool negotiated() const { return negotiated_; } + const Candidates& sent_candidates() const { return sent_candidates_; } + const Candidates& unsent_candidates() const { return unsent_candidates_; } + bool candidates_allocated() const { return candidates_allocated_; } + void set_candidates_allocated(bool allocated) { + candidates_allocated_ = allocated; + } + + TransportChannel* GetChannel(int component); + TransportChannel* CreateChannel(const std::string& channel_name, + int component); + bool HasChannel(int component); + void DestroyChannel(int component); + + void AddSentCandidates(const Candidates& candidates); + void AddUnsentCandidates(const Candidates& candidates); + void ClearSentCandidates() { sent_candidates_.clear(); } + void ClearUnsentCandidates() { unsent_candidates_.clear(); } + + // Start the connection process for any channels, creating impls if needed. + void ConnectChannels(); + // Hook up impls to the proxy channels. Doesn't change connect state. + void CompleteNegotiation(); + + // Mux this proxy onto the specified proxy's transport. + bool SetupMux(TransportProxy* proxy); + + // Simple functions that thunk down to the same functions on Transport. + void SetIceRole(IceRole role); + void SetIdentity(talk_base::SSLIdentity* identity); + bool SetLocalTransportDescription(const TransportDescription& description, + ContentAction action, + std::string* error_desc); + bool SetRemoteTransportDescription(const TransportDescription& description, + ContentAction action, + std::string* error_desc); + void OnSignalingReady(); + bool OnRemoteCandidates(const Candidates& candidates, std::string* error); + + // CandidateTranslator methods. + virtual bool GetChannelNameFromComponent( + int component, std::string* channel_name) const; + virtual bool GetComponentFromChannelName( + const std::string& channel_name, int* component) const; + + // Called when a transport signals that it has new candidates. + void OnTransportCandidatesReady(cricket::Transport* transport, + const Candidates& candidates) { + 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&> SignalCandidatesReady; + + private: + TransportChannelProxy* GetChannelProxy(int component) const; + TransportChannelProxy* GetChannelProxyByName(const std::string& name) const; + + TransportChannelImpl* GetOrCreateChannelProxyImpl(int component); + TransportChannelImpl* GetOrCreateChannelProxyImpl_w(int component); + + // Manipulators of transportchannelimpl in channel proxy. + void SetupChannelProxy(int component, + TransportChannelProxy* proxy); + void SetupChannelProxy_w(int component, + TransportChannelProxy* proxy); + void ReplaceChannelProxyImpl(TransportChannelProxy* proxy, + TransportChannelImpl* impl); + void ReplaceChannelProxyImpl_w(TransportChannelProxy* proxy, + TransportChannelImpl* impl); + + talk_base::Thread* worker_thread_; + std::string sid_; + std::string content_name_; + talk_base::scoped_refptr transport_; + bool connecting_; + bool negotiated_; + ChannelMap channels_; + Candidates sent_candidates_; + Candidates unsent_candidates_; + bool candidates_allocated_; + bool local_description_set_; + bool remote_description_set_; +}; + +typedef std::map TransportMap; + +// Statistics for all the transports of this session. +typedef std::map TransportStatsMap; +typedef std::map ProxyTransportMap; + +struct SessionStats { + ProxyTransportMap proxy_to_transport; + TransportStatsMap transport_stats; +}; + +// A BaseSession manages general session state. This includes negotiation +// of both the application-level and network-level protocols: the former +// defines what will be sent and the latter defines how it will be sent. Each +// network-level protocol is represented by a Transport object. Each Transport +// participates in the network-level negotiation. The individual streams of +// packets are represented by TransportChannels. The application-level protocol +// is represented by SessionDecription objects. +class BaseSession : public sigslot::has_slots<>, + public talk_base::MessageHandler { + public: + enum { + MSG_TIMEOUT = 0, + MSG_ERROR, + MSG_STATE, + }; + + enum State { + STATE_INIT = 0, + STATE_SENTINITIATE, // sent initiate, waiting for Accept or Reject + STATE_RECEIVEDINITIATE, // received an initiate. Call Accept or Reject + STATE_SENTPRACCEPT, // sent provisional Accept + STATE_SENTACCEPT, // sent accept. begin connecting transport + STATE_RECEIVEDPRACCEPT, // received provisional Accept, waiting for Accept + STATE_RECEIVEDACCEPT, // received accept. begin connecting transport + STATE_SENTMODIFY, // sent modify, waiting for Accept or Reject + STATE_RECEIVEDMODIFY, // received modify, call Accept or Reject + STATE_SENTREJECT, // sent reject after receiving initiate + STATE_RECEIVEDREJECT, // received reject after sending initiate + STATE_SENTREDIRECT, // sent direct after receiving initiate + STATE_SENTTERMINATE, // sent terminate (any time / either side) + STATE_RECEIVEDTERMINATE, // received terminate (any time / either side) + STATE_INPROGRESS, // session accepted and in progress + STATE_DEINIT, // session is being destroyed + }; + + enum Error { + ERROR_NONE = 0, // no error + ERROR_TIME = 1, // no response to signaling + ERROR_RESPONSE = 2, // error during signaling + ERROR_NETWORK = 3, // network error, could not allocate network resources + ERROR_CONTENT = 4, // channel errors in SetLocalContent/SetRemoteContent + ERROR_TRANSPORT = 5, // transport error of some kind + }; + + // Convert State to a readable string. + static std::string StateToString(State state); + + BaseSession(talk_base::Thread* signaling_thread, + talk_base::Thread* worker_thread, + PortAllocator* port_allocator, + const std::string& sid, + const std::string& content_type, + bool initiator); + virtual ~BaseSession(); + + talk_base::Thread* signaling_thread() { return signaling_thread_; } + talk_base::Thread* worker_thread() { return worker_thread_; } + PortAllocator* port_allocator() { return port_allocator_; } + + // The ID of this session. + const std::string& id() const { return sid_; } + + // TODO(juberti): This data is largely redundant, as it can now be obtained + // from local/remote_description(). Remove these functions and members. + // Returns the XML namespace identifying the type of this session. + const std::string& content_type() const { return content_type_; } + // Returns the XML namespace identifying the transport used for this session. + const std::string& transport_type() const { return transport_type_; } + + // Indicates whether we initiated this session. + bool initiator() const { return initiator_; } + + // Returns the application-level description given by our client. + // If we are the recipient, this will be NULL until we send an accept. + const SessionDescription* local_description() const { + return local_description_; + } + // Returns the application-level description given by the other client. + // If we are the initiator, this will be NULL until we receive an accept. + const SessionDescription* remote_description() const { + return remote_description_; + } + SessionDescription* remote_description() { + return remote_description_; + } + + // Takes ownership of SessionDescription* + bool set_local_description(const SessionDescription* sdesc) { + if (sdesc != local_description_) { + delete local_description_; + local_description_ = sdesc; + } + return true; + } + + // Takes ownership of SessionDescription* + bool set_remote_description(SessionDescription* sdesc) { + if (sdesc != remote_description_) { + delete remote_description_; + remote_description_ = sdesc; + } + return true; + } + + const SessionDescription* initiator_description() const { + if (initiator_) { + return local_description_; + } else { + return remote_description_; + } + } + + // Returns the current state of the session. See the enum above for details. + // Each time the state changes, we will fire this signal. + State state() const { return state_; } + sigslot::signal2 SignalState; + + // 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 SignalError; + + // Updates the state, signaling if necessary. + virtual void SetState(State state); + + // Updates the error state, signaling if necessary. + // 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. + sigslot::signal2 + SignalRemoteDescriptionUpdate; + + // Fired when SetState is called (regardless if there's a state change), which + // indicates the session description might have be updated. + sigslot::signal2 SignalNewLocalDescription; + + // Fired when SetState is called (regardless if there's a state change), which + // indicates the session description might have be updated. + sigslot::signal2 SignalNewRemoteDescription; + + // Returns the transport that has been negotiated or NULL if + // negotiation is still in progress. + virtual Transport* GetTransport(const std::string& content_name); + + // Creates a new channel with the given names. This method may be called + // immediately after creating the session. However, the actual + // implementation may not be fixed until transport negotiation completes. + // This will usually be called from the worker thread, but that + // shouldn't be an issue since the main thread will be blocked in + // Send when doing so. + virtual TransportChannel* CreateChannel(const std::string& content_name, + const std::string& channel_name, + int component); + + // Returns the channel with the given names. + virtual TransportChannel* GetChannel(const std::string& content_name, + int component); + + // Destroys the channel with the given names. + // This will usually be called from the worker thread, but that + // shouldn't be an issue since the main thread will be blocked in + // Send when doing so. + virtual void DestroyChannel(const std::string& content_name, + int component); + + // Returns stats for all channels of all transports. + // This avoids exposing the internal structures used to track them. + virtual bool GetStats(SessionStats* stats); + + talk_base::SSLIdentity* identity() { return identity_; } + + protected: + // Specifies the identity to use in this session. + bool SetIdentity(talk_base::SSLIdentity* identity); + + bool PushdownTransportDescription(ContentSource source, + ContentAction action, + std::string* error_desc); + void set_initiator(bool initiator) { initiator_ = initiator; } + + const TransportMap& transport_proxies() const { return transports_; } + // Get a TransportProxy by content_name or transport. NULL if not found. + TransportProxy* GetTransportProxy(const std::string& content_name); + TransportProxy* GetTransportProxy(const Transport* transport); + TransportProxy* GetFirstTransportProxy(); + void DestroyTransportProxy(const std::string& content_name); + // TransportProxy is owned by session. Return proxy just for convenience. + TransportProxy* GetOrCreateTransportProxy(const std::string& content_name); + // Creates the actual transport object. Overridable for testing. + virtual Transport* CreateTransport(const std::string& content_name); + + void OnSignalingReady(); + void SpeculativelyConnectAllTransportChannels(); + // Helper method to provide remote candidates to the transport. + bool OnRemoteCandidates(const std::string& content_name, + const Candidates& candidates, + std::string* error); + + // This method will mux transport channels by content_name. + // First content is used for muxing. + bool MaybeEnableMuxingSupport(); + + // Called when a transport requests signaling. + virtual void OnTransportRequestSignaling(Transport* transport) { + } + + // Called when the first channel of a transport begins connecting. We use + // this to start a timer, to make sure that the connection completes in a + // reasonable amount of time. + virtual void OnTransportConnecting(Transport* transport) { + } + + // Called when a transport changes its writable state. We track this to make + // sure that the transport becomes writable within a reasonable amount of + // time. If this does not occur, we signal an error. + virtual void OnTransportWritable(Transport* transport) { + } + 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) { + } + + // Called when a transport signals that it found an error in an incoming + // message. + virtual void OnTransportSendError(Transport* transport, + const buzz::XmlElement* stanza, + const buzz::QName& name, + const std::string& type, + const std::string& text, + const buzz::XmlElement* extra_info) { + } + + virtual void OnTransportRouteChange( + Transport* transport, + int component, + const cricket::Candidate& remote_candidate) { + } + + virtual void OnTransportCandidatesAllocationDone(Transport* transport); + + // Called when all transport channels allocated required candidates. + // This method should be used as an indication of candidates gathering process + // is completed and application can now send local candidates list to remote. + virtual void OnCandidatesAllocationDone() { + } + + // Handles the ice role change callback from Transport. This must be + // propagated to all the transports. + virtual void OnRoleConflict(); + + // Handles messages posted to us. + virtual void OnMessage(talk_base::Message *pmsg); + + 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, + std::string* error_desc); + bool PushdownRemoteTransportDescription( + const SessionDescription* sdesc, ContentAction action, + std::string* error_desc); + + bool IsCandidateAllocationDone() const; + void MaybeCandidateAllocationDone(); + + // This method will delete the Transport and TransportChannelImpls and + // replace those with the selected Transport objects. Selection is done + // based on the content_name and in this case first MediaContent information + // is used for mux. + bool SetSelectedProxy(const std::string& content_name, + const ContentGroup* muxed_group); + // Log session state. + void LogState(State old_state, State new_state); + + // Returns true and the TransportInfo of the given |content_name| + // from |description|. Returns false if it's not available. + bool GetTransportDescription(const SessionDescription* description, + const std::string& content_name, + TransportDescription* info); + + // Fires the new description signal according to the current state. + void SignalNewDescription(); + + // Gets the ContentAction and ContentSource according to the session state. + bool GetContentAction(ContentAction* action, ContentSource* source); + + talk_base::Thread* signaling_thread_; + talk_base::Thread* worker_thread_; + PortAllocator* port_allocator_; + std::string sid_; + std::string content_type_; + std::string transport_type_; + bool initiator_; + talk_base::SSLIdentity* identity_; + const SessionDescription* local_description_; + SessionDescription* remote_description_; + uint64 ice_tiebreaker_; + // This flag will be set to true after the first role switch. This flag + // will enable us to stop any role switch during the call. + bool role_switch_; + TransportMap transports_; +}; + +// A specific Session created by the SessionManager, using XMPP for protocol. +class Session : public BaseSession { + public: + // Returns the manager that created and owns this session. + SessionManager* session_manager() const { return session_manager_; } + + // Returns the client that is handling the application data of this session. + SessionClient* client() const { return client_; } + + // Returns the JID of this client. + const std::string& local_name() const { return local_name_; } + + // Returns the JID of the other peer in this session. + const std::string& remote_name() const { return remote_name_; } + + // Set the JID of the other peer in this session. + // Typically the remote_name_ is set when the session is initiated. + // However, sometimes (e.g when a proxy is used) the peer name is + // known after the BaseSession has been initiated and it must be updated + // explicitly. + void set_remote_name(const std::string& name) { remote_name_ = name; } + + // Set the JID of the initiator of this session. Allows for the overriding + // of the initiator to be a third-party, eg. the MUC JID when creating p2p + // sessions. + void set_initiator_name(const std::string& name) { initiator_name_ = name; } + + // Indicates the JID of the entity who initiated this session. + // In special cases, may be different than both local_name and remote_name. + const std::string& initiator_name() const { return initiator_name_; } + + SignalingProtocol current_protocol() const { return current_protocol_; } + + void set_current_protocol(SignalingProtocol protocol) { + current_protocol_ = protocol; + } + + // Updates the error state, signaling if necessary. + 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 + // it is ready to send the messages. + // (These are called only by SessionManager.) + sigslot::signal1 SignalRequestSignaling; + void OnSignalingReady() { BaseSession::OnSignalingReady(); } + + // Takes ownership of session description. + // TODO: Add an error argument to pass back to the caller. + bool Initiate(const std::string& to, + const SessionDescription* sdesc); + + // When we receive an initiate, we create a session in the + // RECEIVEDINITIATE state and respond by accepting or rejecting. + // Takes ownership of session description. + // TODO: Add an error argument to pass back to the caller. + bool Accept(const SessionDescription* sdesc); + bool Reject(const std::string& reason); + bool Terminate() { + return TerminateWithReason(STR_TERMINATE_SUCCESS); + } + bool TerminateWithReason(const std::string& reason); + // Fired whenever we receive a terminate message along with a reason + sigslot::signal2 SignalReceivedTerminateReason; + + // The two clients in the session may also send one another + // arbitrary XML messages, which are called "info" messages. Sending + // takes ownership of the given elements. The signal does not; the + // parent element will be deleted after the signal. + bool SendInfoMessage(const XmlElements& elems, + const std::string& remote_name); + bool SendDescriptionInfoMessage(const ContentInfos& contents); + sigslot::signal2 SignalInfoMessage; + + private: + // Creates or destroys a session. (These are called only SessionManager.) + Session(SessionManager *session_manager, + const std::string& local_name, const std::string& initiator_name, + const std::string& sid, const std::string& content_type, + SessionClient* client); + ~Session(); + // For each transport info, create a transport proxy. Can fail for + // incompatible transport types. + bool CreateTransportProxies(const TransportInfos& tinfos, + SessionError* error); + bool OnRemoteCandidates(const TransportInfos& tinfos, + ParseError* error); + // Returns a TransportInfo without candidates for each content name. + // Uses the transport_type_ of the session. + TransportInfos GetEmptyTransportInfos(const ContentInfos& contents) const; + + // Maps passed to serialization functions. + TransportParserMap GetTransportParsers(); + ContentParserMap GetContentParsers(); + CandidateTranslatorMap GetCandidateTranslators(); + + virtual void OnTransportRequestSignaling(Transport* transport); + virtual void OnTransportConnecting(Transport* transport); + virtual void OnTransportWritable(Transport* transport); + virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy, + const Candidates& candidates); + virtual void OnTransportSendError(Transport* transport, + const buzz::XmlElement* stanza, + const buzz::QName& name, + const std::string& type, + const std::string& text, + const buzz::XmlElement* extra_info); + virtual void OnMessage(talk_base::Message *pmsg); + + // Send various kinds of session messages. + bool SendInitiateMessage(const SessionDescription* sdesc, + SessionError* error); + bool SendAcceptMessage(const SessionDescription* sdesc, SessionError* error); + bool SendRejectMessage(const std::string& reason, SessionError* error); + bool SendTerminateMessage(const std::string& reason, SessionError* error); + bool SendTransportInfoMessage(const TransportInfo& tinfo, + SessionError* error); + bool SendTransportInfoMessage(const TransportProxy* transproxy, + const Candidates& candidates, + SessionError* error); + + bool ResendAllTransportInfoMessages(SessionError* error); + bool SendAllUnsentTransportInfoMessages(SessionError* error); + + // All versions of SendMessage send a message of the given type to + // the other client. Can pass either a set of elements or an + // "action", which must have a WriteSessionAction method to go along + // with it. Sending with an action supports sending a "hybrid" + // message. Sending with elements must be sent as Jingle or Gingle. + + // When passing elems, must be either Jingle or Gingle protocol. + // Takes ownership of action_elems. + bool SendMessage(ActionType type, const XmlElements& action_elems, + SessionError* error); + // Sends a messge, but overrides the remote name. + bool SendMessage(ActionType type, const XmlElements& action_elems, + const std::string& remote_name, + SessionError* error); + // When passing an action, may be Hybrid protocol. + template + bool SendMessage(ActionType type, const Action& action, + SessionError* error); + + // Helper methods to write the session message stanza. + template + bool WriteActionMessage(ActionType type, const Action& action, + buzz::XmlElement* stanza, WriteError* error); + template + bool WriteActionMessage(SignalingProtocol protocol, + ActionType type, const Action& action, + buzz::XmlElement* stanza, WriteError* error); + + // Sending messages in hybrid form requires being able to write them + // on a per-protocol basis with a common method signature, which all + // of these have. + bool WriteSessionAction(SignalingProtocol protocol, + const SessionInitiate& init, + XmlElements* elems, WriteError* error); + bool WriteSessionAction(SignalingProtocol protocol, + const TransportInfo& tinfo, + XmlElements* elems, WriteError* error); + bool WriteSessionAction(SignalingProtocol protocol, + const SessionTerminate& term, + XmlElements* elems, WriteError* error); + + // Sends a message back to the other client indicating that we have received + // and accepted their message. + void SendAcknowledgementMessage(const buzz::XmlElement* stanza); + + // Once signaling is ready, the session will use this signal to request the + // sending of each message. When messages are received by the other client, + // they should be handed to OnIncomingMessage. + // (These are called only by SessionManager.) + sigslot::signal2 SignalOutgoingMessage; + void OnIncomingMessage(const SessionMessage& msg); + + void OnIncomingResponse(const buzz::XmlElement* orig_stanza, + const buzz::XmlElement* response_stanza, + const SessionMessage& msg); + void OnInitiateAcked(); + void OnFailedSend(const buzz::XmlElement* orig_stanza, + const buzz::XmlElement* error_stanza); + + // Invoked when an error is found in an incoming message. This is translated + // into the appropriate XMPP response by SessionManager. + sigslot::signal6 SignalErrorMessage; + + // Handlers for the various types of messages. These functions may take + // pointers to the whole stanza or to just the session element. + bool OnInitiateMessage(const SessionMessage& msg, MessageError* error); + bool OnAcceptMessage(const SessionMessage& msg, MessageError* error); + bool OnRejectMessage(const SessionMessage& msg, MessageError* error); + bool OnInfoMessage(const SessionMessage& msg); + bool OnTerminateMessage(const SessionMessage& msg, MessageError* error); + bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error); + bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error); + bool OnDescriptionInfoMessage(const SessionMessage& msg, MessageError* error); + bool OnRedirectError(const SessionRedirect& redirect, SessionError* error); + + // Verifies that we are in the appropriate state to receive this message. + bool CheckState(State state, MessageError* error); + + SessionManager* session_manager_; + bool initiate_acked_; + std::string local_name_; + std::string initiator_name_; + std::string remote_name_; + SessionClient* client_; + TransportParser* transport_parser_; + // Keeps track of what protocol we are speaking. + SignalingProtocol current_protocol_; + + friend class SessionManager; // For access to constructor, destructor, + // and signaling related methods. +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_SESSION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionclient.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionclient.h new file mode 100644 index 0000000..61ea48f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionclient.h @@ -0,0 +1,95 @@ +/* + * 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 TALK_P2P_BASE_SESSIONCLIENT_H_ +#define TALK_P2P_BASE_SESSIONCLIENT_H_ + +#include "talk/p2p/base/constants.h" + +namespace buzz { +class XmlElement; +} + +namespace cricket { + +struct ParseError; +class Session; +class ContentDescription; + +class ContentParser { + public: + virtual bool ParseContent(SignalingProtocol protocol, + const buzz::XmlElement* elem, + ContentDescription** content, + ParseError* error) = 0; + // If not IsWriteable, then a given content should be "skipped" when + // writing in the given protocol, as if it didn't exist. We assume + // most things are writeable. We do this to avoid strange cases + // like data contents in Gingle, which aren't writable. + virtual bool IsWritable(SignalingProtocol protocol, + const ContentDescription* content) { + return true; + } + virtual bool WriteContent(SignalingProtocol protocol, + const ContentDescription* content, + buzz::XmlElement** elem, + WriteError* error) = 0; + virtual ~ContentParser() {} +}; + +// A SessionClient exists in 1-1 relation with each session. The implementor +// of this interface is the one that understands *what* the two sides are +// trying to send to one another. The lower-level layers only know how to send +// data; they do not know what is being sent. +class SessionClient : public ContentParser { + public: + // Notifies the client of the creation / destruction of sessions of this type. + // + // IMPORTANT: The SessionClient, in its handling of OnSessionCreate, must + // create whatever channels are indicate in the description. This is because + // the remote client may already be attempting to connect those channels. If + // we do not create our channel right away, then connection may fail or be + // delayed. + virtual void OnSessionCreate(Session* session, bool received_initiate) = 0; + virtual void OnSessionDestroy(Session* session) = 0; + + virtual bool ParseContent(SignalingProtocol protocol, + const buzz::XmlElement* elem, + ContentDescription** content, + ParseError* error) = 0; + virtual bool WriteContent(SignalingProtocol protocol, + const ContentDescription* content, + buzz::XmlElement** elem, + WriteError* error) = 0; + protected: + // The SessionClient interface explicitly does not include destructor + virtual ~SessionClient() { } +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_SESSIONCLIENT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessiondescription.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessiondescription.h new file mode 100644 index 0000000..d272d06 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessiondescription.h @@ -0,0 +1,202 @@ +/* + * 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 TALK_P2P_BASE_SESSIONDESCRIPTION_H_ +#define TALK_P2P_BASE_SESSIONDESCRIPTION_H_ + +#include +#include + +#include "talk/base/constructormagic.h" +#include "talk/p2p/base/transportinfo.h" + +namespace cricket { + +// Describes a session content. Individual content types inherit from +// this class. Analagous to a or +// . +class ContentDescription { + public: + virtual ~ContentDescription() {} + virtual ContentDescription* Copy() const = 0; +}; + +// Analagous to a or . +// name = name of +// type = xmlns of +struct ContentInfo { + ContentInfo() : description(NULL) {} + ContentInfo(const std::string& name, + const std::string& type, + ContentDescription* description) : + name(name), type(type), rejected(false), description(description) {} + ContentInfo(const std::string& name, + const std::string& type, + bool rejected, + ContentDescription* description) : + name(name), type(type), rejected(rejected), description(description) {} + std::string name; + std::string type; + bool rejected; + ContentDescription* description; +}; + +typedef std::vector ContentNames; + +// This class provides a mechanism to aggregate different media contents into a +// group. This group can also be shared with the peers in a pre-defined format. +// GroupInfo should be populated only with the |content_name| of the +// MediaDescription. +class ContentGroup { + public: + explicit ContentGroup(const std::string& semantics) : + semantics_(semantics) {} + + const std::string& semantics() const { return semantics_; } + const ContentNames& content_names() const { return content_names_; } + + const std::string* FirstContentName() const; + bool HasContentName(const std::string& content_name) const; + void AddContentName(const std::string& content_name); + bool RemoveContentName(const std::string& content_name); + + private: + std::string semantics_; + ContentNames content_names_; +}; + +typedef std::vector ContentInfos; +typedef std::vector ContentGroups; + +const ContentInfo* FindContentInfoByName( + const ContentInfos& contents, const std::string& name); +const ContentInfo* FindContentInfoByType( + const ContentInfos& contents, const std::string& type); + +// Describes a collection of contents, each with its own name and +// type. Analogous to a or stanza. Assumes that +// contents are unique be name, but doesn't enforce that. +class SessionDescription { + public: + SessionDescription() {} + explicit SessionDescription(const ContentInfos& contents) : + contents_(contents) {} + SessionDescription(const ContentInfos& contents, + const ContentGroups& groups) : + contents_(contents), + content_groups_(groups) {} + SessionDescription(const ContentInfos& contents, + const TransportInfos& transports, + const ContentGroups& groups) : + contents_(contents), + transport_infos_(transports), + content_groups_(groups) {} + ~SessionDescription() { + for (ContentInfos::iterator content = contents_.begin(); + content != contents_.end(); ++content) { + delete content->description; + } + } + + SessionDescription* Copy() const; + + // Content accessors. + const ContentInfos& contents() const { return contents_; } + ContentInfos& contents() { return contents_; } + const ContentInfo* GetContentByName(const std::string& name) const; + ContentInfo* GetContentByName(const std::string& name); + const ContentDescription* GetContentDescriptionByName( + const std::string& name) const; + ContentDescription* GetContentDescriptionByName(const std::string& name); + const ContentInfo* FirstContentByType(const std::string& type) const; + const ContentInfo* FirstContent() const; + + // Content mutators. + // Adds a content to this description. Takes ownership of ContentDescription*. + void AddContent(const std::string& name, + const std::string& type, + ContentDescription* description); + void AddContent(const std::string& name, + const std::string& type, + bool rejected, + ContentDescription* description); + bool RemoveContentByName(const std::string& name); + + // Transport accessors. + const TransportInfos& transport_infos() const { return transport_infos_; } + TransportInfos& transport_infos() { return transport_infos_; } + const TransportInfo* GetTransportInfoByName( + const std::string& name) const; + TransportInfo* GetTransportInfoByName(const std::string& name); + const TransportDescription* GetTransportDescriptionByName( + const std::string& name) const { + const TransportInfo* tinfo = GetTransportInfoByName(name); + return tinfo ? &tinfo->description : NULL; + } + + // Transport mutators. + void set_transport_infos(const TransportInfos& transport_infos) { + transport_infos_ = transport_infos; + } + // Adds a TransportInfo to this description. + // Returns false if a TransportInfo with the same name already exists. + bool AddTransportInfo(const TransportInfo& transport_info); + bool RemoveTransportInfoByName(const std::string& name); + + // Group accessors. + const ContentGroups& groups() const { return content_groups_; } + const ContentGroup* GetGroupByName(const std::string& name) const; + bool HasGroup(const std::string& name) const; + + // Group mutators. + void AddGroup(const ContentGroup& group) { content_groups_.push_back(group); } + // Remove the first group with the same semantics specified by |name|. + void RemoveGroupByName(const std::string& name); + + private: + ContentInfos contents_; + TransportInfos transport_infos_; + ContentGroups content_groups_; +}; + +// Indicates whether a ContentDescription was an offer or an answer, as +// described in http://www.ietf.org/rfc/rfc3264.txt. CA_UPDATE +// indicates a jingle update message which contains a subset of a full +// session description +enum ContentAction { + CA_OFFER, CA_PRANSWER, CA_ANSWER, CA_UPDATE +}; + +// Indicates whether a ContentDescription was sent by the local client +// or received from the remote client. +enum ContentSource { + CS_LOCAL, CS_REMOTE +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_SESSIONDESCRIPTION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionid.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionid.h new file mode 100644 index 0000000..c630ad0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionid.h @@ -0,0 +1,37 @@ +/* + * 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 TALK_P2P_BASE_SESSIONID_H_ +#define TALK_P2P_BASE_SESSIONID_H_ + +// TODO: Remove this file. + +namespace cricket { + +} // namespace cricket + +#endif // TALK_P2P_BASE_SESSIONID_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionmanager.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionmanager.h new file mode 100644 index 0000000..268c588 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionmanager.h @@ -0,0 +1,211 @@ +/* + * 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 TALK_P2P_BASE_SESSIONMANAGER_H_ +#define TALK_P2P_BASE_SESSIONMANAGER_H_ + +#include +#include +#include +#include + +#include "talk/base/sigslot.h" +#include "talk/base/thread.h" +#include "talk/p2p/base/portallocator.h" +#include "talk/p2p/base/transportdescriptionfactory.h" + +namespace buzz { +class QName; +class XmlElement; +} + +namespace cricket { + +class Session; +class BaseSession; +class SessionClient; + +// SessionManager manages session instances. +class SessionManager : public sigslot::has_slots<> { + public: + SessionManager(PortAllocator *allocator, + talk_base::Thread *worker_thread = NULL); + virtual ~SessionManager(); + + PortAllocator *port_allocator() const { return allocator_; } + talk_base::Thread *worker_thread() const { return worker_thread_; } + talk_base::Thread *signaling_thread() const { return signaling_thread_; } + + int session_timeout() const { return timeout_; } + void set_session_timeout(int timeout) { timeout_ = timeout; } + + // Set what transport protocol we want to default to. + void set_transport_protocol(TransportProtocol proto) { + transport_desc_factory_.set_protocol(proto); + } + + // Control use of DTLS. An identity must be supplied if DTLS is enabled. + void set_secure(SecurePolicy policy) { + transport_desc_factory_.set_secure(policy); + } + void set_identity(talk_base::SSLIdentity* identity) { + transport_desc_factory_.set_identity(identity); + } + const TransportDescriptionFactory* transport_desc_factory() const { + return &transport_desc_factory_; + } + + // Registers support for the given client. If we receive an initiate + // describing a session of the given type, we will automatically create a + // Session object and notify this client. The client may then accept or + // reject the session. + void AddClient(const std::string& content_type, SessionClient* client); + void RemoveClient(const std::string& content_type); + SessionClient* GetClient(const std::string& content_type); + + // Creates a new session. The given name is the JID of the client on whose + // behalf we initiate the session. + Session *CreateSession(const std::string& local_name, + const std::string& content_type); + + Session *CreateSession(const std::string& id, + const std::string& local_name, + const std::string& content_type); + + // Destroys the given session. + void DestroySession(Session *session); + + // Returns the session with the given ID or NULL if none exists. + Session *GetSession(const std::string& sid); + + // Terminates all of the sessions created by this manager. + void TerminateAll(); + + // These are signaled whenever the set of existing sessions changes. + sigslot::signal2 SignalSessionCreate; + sigslot::signal1 SignalSessionDestroy; + + // Determines whether the given stanza is intended for some session. + bool IsSessionMessage(const buzz::XmlElement* stanza); + + // Given a sid, initiator, and remote_name, this finds the matching Session + Session* FindSession(const std::string& sid, + const std::string& remote_name); + + // Called when we receive a stanza for which IsSessionMessage is true. + void OnIncomingMessage(const buzz::XmlElement* stanza); + + // Called when we get a response to a message that we sent. + void OnIncomingResponse(const buzz::XmlElement* orig_stanza, + const buzz::XmlElement* response_stanza); + + // Called if an attempted to send times out or an error is returned. In the + // timeout case error_stanza will be NULL + void OnFailedSend(const buzz::XmlElement* orig_stanza, + const buzz::XmlElement* error_stanza); + + // Signalled each time a session generates a signaling message to send. + // Also signalled on errors, but with a NULL session. + sigslot::signal2 SignalOutgoingMessage; + + // Signaled before sessions try to send certain signaling messages. The + // client should call OnSignalingReady once it is safe to send them. These + // steps are taken so that we don't send signaling messages trying to + // re-establish the connectivity of a session when the client cannot send + // the messages (and would probably just drop them on the floor). + // + // Note: you can connect this directly to OnSignalingReady(), if a signalling + // check is not supported. + sigslot::signal0<> SignalRequestSignaling; + void OnSignalingReady(); + + // Signaled when this SessionManager is deleted. + sigslot::signal0<> SignalDestroyed; + + private: + typedef std::map SessionMap; + typedef std::map ClientMap; + + // Helper function for CreateSession. This is also invoked when we receive + // a message attempting to initiate a session with this client. + Session *CreateSession(const std::string& local_name, + const std::string& initiator, + const std::string& sid, + const std::string& content_type, + bool received_initiate); + + // Attempts to find a registered session type whose description appears as + // a child of the session element. Such a child should be present indicating + // the application they hope to initiate. + std::string FindClient(const buzz::XmlElement* session); + + // Sends a message back to the other client indicating that we found an error + // in the stanza they sent. name identifies the error, type is one of the + // standard XMPP types (cancel, continue, modify, auth, wait), and text is a + // description for debugging purposes. + void SendErrorMessage(const buzz::XmlElement* stanza, + const buzz::QName& name, + const std::string& type, + const std::string& text, + const buzz::XmlElement* extra_info); + + // Creates and returns an error message from the given components. The + // caller is responsible for deleting this. + buzz::XmlElement* CreateErrorMessage( + const buzz::XmlElement* stanza, + const buzz::QName& name, + const std::string& type, + const std::string& text, + const buzz::XmlElement* extra_info); + + // Called each time a session requests signaling. + void OnRequestSignaling(Session* session); + + // Called each time a session has an outgoing message. + void OnOutgoingMessage(Session* session, const buzz::XmlElement* stanza); + + // Called each time a session has an error to send. + void OnErrorMessage(BaseSession* session, + const buzz::XmlElement* stanza, + const buzz::QName& name, + const std::string& type, + const std::string& text, + const buzz::XmlElement* extra_info); + + PortAllocator *allocator_; + talk_base::Thread *signaling_thread_; + talk_base::Thread *worker_thread_; + int timeout_; + TransportDescriptionFactory transport_desc_factory_; + SessionMap session_map_; + ClientMap client_map_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_SESSIONMANAGER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionmessages.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionmessages.h new file mode 100644 index 0000000..c7dac82 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/sessionmessages.h @@ -0,0 +1,243 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_SESSIONMESSAGES_H_ +#define TALK_P2P_BASE_SESSIONMESSAGES_H_ + +#include +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/p2p/base/constants.h" +#include "talk/p2p/base/parsing.h" +#include "talk/p2p/base/sessiondescription.h" // Needed to delete contents. +#include "talk/p2p/base/transportinfo.h" +#include "talk/xmllite/xmlelement.h" + +namespace cricket { + +struct ParseError; +struct WriteError; +class Candidate; +class ContentParser; +class TransportParser; + +typedef std::vector Candidates; +typedef std::map ContentParserMap; +typedef std::map TransportParserMap; + +enum ActionType { + ACTION_UNKNOWN, + + ACTION_SESSION_INITIATE, + ACTION_SESSION_INFO, + ACTION_SESSION_ACCEPT, + ACTION_SESSION_REJECT, + ACTION_SESSION_TERMINATE, + + ACTION_TRANSPORT_INFO, + ACTION_TRANSPORT_ACCEPT, + + ACTION_DESCRIPTION_INFO, +}; + +// Abstraction of a element within an stanza, per XMPP +// standard XEP-166. Can be serialized into multiple protocols, +// including the standard (Jingle) and the draft standard (Gingle). +// In general, used to communicate actions related to a p2p session, +// such accept, initiate, terminate, etc. + +struct SessionMessage { + SessionMessage() : action_elem(NULL), stanza(NULL) {} + + SessionMessage(SignalingProtocol protocol, ActionType type, + const std::string& sid, const std::string& initiator) : + protocol(protocol), type(type), sid(sid), initiator(initiator), + action_elem(NULL), stanza(NULL) {} + + std::string id; + std::string from; + std::string to; + SignalingProtocol protocol; + ActionType type; + std::string sid; // session id + std::string initiator; + + // Used for further parsing when necessary. + // Represents or . + const buzz::XmlElement* action_elem; + // Mostly used for debugging. + const buzz::XmlElement* stanza; +}; + +// TODO: Break up this class so we don't have to typedef it into +// different classes. +struct ContentMessage { + ContentMessage() : owns_contents(false) {} + + ~ContentMessage() { + if (owns_contents) { + for (ContentInfos::iterator content = contents.begin(); + content != contents.end(); content++) { + delete content->description; + } + } + } + + // Caller takes ownership of contents. + ContentInfos ClearContents() { + ContentInfos out; + contents.swap(out); + owns_contents = false; + return out; + } + + bool owns_contents; + ContentInfos contents; + TransportInfos transports; + ContentGroups groups; +}; + +typedef ContentMessage SessionInitiate; +typedef ContentMessage SessionAccept; +// Note that a DescriptionInfo does not have TransportInfos. +typedef ContentMessage DescriptionInfo; + +struct SessionTerminate { + SessionTerminate() {} + + explicit SessionTerminate(const std::string& reason) : + reason(reason) {} + + std::string reason; + std::string debug_reason; +}; + +struct SessionRedirect { + std::string target; +}; + +// Used during parsing and writing to map component to channel name +// and back. This is primarily for converting old G-ICE candidate +// signalling to new ICE candidate classes. +class CandidateTranslator { + public: + virtual bool GetChannelNameFromComponent( + int component, std::string* channel_name) const = 0; + virtual bool GetComponentFromChannelName( + const std::string& channel_name, int* component) const = 0; +}; + +// Content name => translator +typedef std::map CandidateTranslatorMap; + +bool IsSessionMessage(const buzz::XmlElement* stanza); +bool ParseSessionMessage(const buzz::XmlElement* stanza, + SessionMessage* msg, + ParseError* error); +// Will return an error if there is more than one content type. +bool ParseContentType(SignalingProtocol protocol, + const buzz::XmlElement* action_elem, + std::string* content_type, + ParseError* error); +void WriteSessionMessage(const SessionMessage& msg, + const XmlElements& action_elems, + buzz::XmlElement* stanza); +bool ParseSessionInitiate(SignalingProtocol protocol, + const buzz::XmlElement* action_elem, + const ContentParserMap& content_parsers, + const TransportParserMap& transport_parsers, + const CandidateTranslatorMap& translators, + SessionInitiate* init, + ParseError* error); +bool WriteSessionInitiate(SignalingProtocol protocol, + const ContentInfos& contents, + const TransportInfos& tinfos, + const ContentParserMap& content_parsers, + const TransportParserMap& transport_parsers, + const CandidateTranslatorMap& translators, + const ContentGroups& groups, + XmlElements* elems, + WriteError* error); +bool ParseSessionAccept(SignalingProtocol protocol, + const buzz::XmlElement* action_elem, + const ContentParserMap& content_parsers, + const TransportParserMap& transport_parsers, + const CandidateTranslatorMap& translators, + SessionAccept* accept, + ParseError* error); +bool WriteSessionAccept(SignalingProtocol protocol, + const ContentInfos& contents, + const TransportInfos& tinfos, + const ContentParserMap& content_parsers, + const TransportParserMap& transport_parsers, + const CandidateTranslatorMap& translators, + const ContentGroups& groups, + XmlElements* elems, + WriteError* error); +bool ParseSessionTerminate(SignalingProtocol protocol, + const buzz::XmlElement* action_elem, + SessionTerminate* term, + ParseError* error); +void WriteSessionTerminate(SignalingProtocol protocol, + const SessionTerminate& term, + XmlElements* elems); +bool ParseDescriptionInfo(SignalingProtocol protocol, + const buzz::XmlElement* action_elem, + const ContentParserMap& content_parsers, + const TransportParserMap& transport_parsers, + const CandidateTranslatorMap& translators, + DescriptionInfo* description_info, + ParseError* error); +bool WriteDescriptionInfo(SignalingProtocol protocol, + const ContentInfos& contents, + const ContentParserMap& content_parsers, + XmlElements* elems, + WriteError* error); +// Since a TransportInfo is not a transport-info message, and a +// transport-info message is just a collection of TransportInfos, we +// say Parse/Write TransportInfos for transport-info messages. +bool ParseTransportInfos(SignalingProtocol protocol, + const buzz::XmlElement* action_elem, + const ContentInfos& contents, + const TransportParserMap& trans_parsers, + const CandidateTranslatorMap& translators, + TransportInfos* tinfos, + ParseError* error); +bool WriteTransportInfos(SignalingProtocol protocol, + const TransportInfos& tinfos, + const TransportParserMap& trans_parsers, + const CandidateTranslatorMap& translators, + XmlElements* elems, + WriteError* error); +// Handles both Gingle and Jingle syntax. +bool FindSessionRedirect(const buzz::XmlElement* stanza, + SessionRedirect* redirect); +} // namespace cricket + +#endif // TALK_P2P_BASE_SESSIONMESSAGES_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stun.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stun.h new file mode 100644 index 0000000..887dbf8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stun.h @@ -0,0 +1,648 @@ +/* + * 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 TALK_P2P_BASE_STUN_H_ +#define TALK_P2P_BASE_STUN_H_ + +// This file contains classes for dealing with the STUN protocol, as specified +// in RFC 5389, and its descendants. + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/bytebuffer.h" +#include "talk/base/socketaddress.h" + +namespace cricket { + +// These are the types of STUN messages defined in RFC 5389. +enum StunMessageType { + STUN_BINDING_REQUEST = 0x0001, + STUN_BINDING_INDICATION = 0x0011, + STUN_BINDING_RESPONSE = 0x0101, + STUN_BINDING_ERROR_RESPONSE = 0x0111, +}; + +// These are all known STUN attributes, defined in RFC 5389 and elsewhere. +// Next to each is the name of the class (T is StunTAttribute) that implements +// that type. +// RETRANSMIT_COUNT is the number of outstanding pings without a response at +// the time the packet is generated. +enum StunAttributeType { + STUN_ATTR_MAPPED_ADDRESS = 0x0001, // Address + STUN_ATTR_USERNAME = 0x0006, // ByteString + STUN_ATTR_MESSAGE_INTEGRITY = 0x0008, // ByteString, 20 bytes + STUN_ATTR_ERROR_CODE = 0x0009, // ErrorCode + STUN_ATTR_UNKNOWN_ATTRIBUTES = 0x000a, // UInt16List + STUN_ATTR_REALM = 0x0014, // ByteString + STUN_ATTR_NONCE = 0x0015, // ByteString + STUN_ATTR_XOR_MAPPED_ADDRESS = 0x0020, // XorAddress + STUN_ATTR_SOFTWARE = 0x8022, // ByteString + STUN_ATTR_ALTERNATE_SERVER = 0x8023, // ByteString + STUN_ATTR_FINGERPRINT = 0x8028, // UInt32 + STUN_ATTR_RETRANSMIT_COUNT = 0xFF00 // UInt32 +}; + +// These are the types of the values associated with the attributes above. +// This allows us to perform some basic validation when reading or adding +// attributes. Note that these values are for our own use, and not defined in +// RFC 5389. +enum StunAttributeValueType { + STUN_VALUE_UNKNOWN = 0, + STUN_VALUE_ADDRESS = 1, + STUN_VALUE_XOR_ADDRESS = 2, + STUN_VALUE_UINT32 = 3, + STUN_VALUE_UINT64 = 4, + STUN_VALUE_BYTE_STRING = 5, + STUN_VALUE_ERROR_CODE = 6, + STUN_VALUE_UINT16_LIST = 7 +}; + +// These are the types of STUN addresses defined in RFC 5389. +enum StunAddressFamily { + // NB: UNDEF is not part of the STUN spec. + STUN_ADDRESS_UNDEF = 0, + STUN_ADDRESS_IPV4 = 1, + STUN_ADDRESS_IPV6 = 2 +}; + +// These are the types of STUN error codes defined in RFC 5389. +enum StunErrorCode { + STUN_ERROR_TRY_ALTERNATE = 300, + STUN_ERROR_BAD_REQUEST = 400, + STUN_ERROR_UNAUTHORIZED = 401, + STUN_ERROR_UNKNOWN_ATTRIBUTE = 420, + STUN_ERROR_STALE_CREDENTIALS = 430, // GICE only + STUN_ERROR_STALE_NONCE = 438, + STUN_ERROR_SERVER_ERROR = 500, + STUN_ERROR_GLOBAL_FAILURE = 600 +}; + +// Strings for the error codes above. +extern const char STUN_ERROR_REASON_BAD_REQUEST[]; +extern const char STUN_ERROR_REASON_UNAUTHORIZED[]; +extern const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[]; +extern const char STUN_ERROR_REASON_STALE_CREDENTIALS[]; +extern const char STUN_ERROR_REASON_STALE_NONCE[]; +extern const char STUN_ERROR_REASON_SERVER_ERROR[]; + +// The mask used to determine whether a STUN message is a request/response etc. +const uint32 kStunTypeMask = 0x0110; + +// STUN Attribute header length. +const size_t kStunAttributeHeaderSize = 4; + +// Following values correspond to RFC5389. +const size_t kStunHeaderSize = 20; +const size_t kStunTransactionIdOffset = 8; +const size_t kStunTransactionIdLength = 12; +const uint32 kStunMagicCookie = 0x2112A442; +const size_t kStunMagicCookieLength = sizeof(kStunMagicCookie); + +// Following value corresponds to an earlier version of STUN from +// RFC3489. +const size_t kStunLegacyTransactionIdLength = 16; + +// STUN Message Integrity HMAC length. +const size_t kStunMessageIntegritySize = 20; + +class StunAttribute; +class StunAddressAttribute; +class StunXorAddressAttribute; +class StunUInt32Attribute; +class StunUInt64Attribute; +class StunByteStringAttribute; +class StunErrorCodeAttribute; +class StunUInt16ListAttribute; + +// Records a complete STUN/TURN message. Each message consists of a type and +// any number of attributes. Each attribute is parsed into an instance of an +// appropriate class (see above). The Get* methods will return instances of +// that attribute class. +class StunMessage { + public: + StunMessage(); + virtual ~StunMessage(); + + int type() const { return type_; } + size_t length() const { return length_; } + const std::string& transaction_id() const { return transaction_id_; } + + // Returns true if the message confirms to RFC3489 rather than + // RFC5389. The main difference between two version of the STUN + // protocol is the presence of the magic cookie and different length + // of transaction ID. For outgoing packets version of the protocol + // is determined by the lengths of the transaction ID. + bool IsLegacy() const; + + void SetType(int type) { type_ = static_cast(type); } + bool SetTransactionID(const std::string& str); + + // Gets the desired attribute value, or NULL if no such attribute type exists. + const StunAddressAttribute* GetAddress(int type) const; + const StunUInt32Attribute* GetUInt32(int type) const; + const StunUInt64Attribute* GetUInt64(int type) const; + const StunByteStringAttribute* GetByteString(int type) const; + + // Gets these specific attribute values. + const StunErrorCodeAttribute* GetErrorCode() const; + const StunUInt16ListAttribute* GetUnknownAttributes() const; + + // Takes ownership of the specified attribute, verifies it is of the correct + // type, and adds it to the message. The return value indicates whether this + // was successful. + bool AddAttribute(StunAttribute* attr); + + // Validates that a raw STUN message has a correct MESSAGE-INTEGRITY value. + // This can't currently be done on a StunMessage, since it is affected by + // padding data (which we discard when reading a StunMessage). + static bool ValidateMessageIntegrity(const char* data, size_t size, + const std::string& password); + // Adds a MESSAGE-INTEGRITY attribute that is valid for the current message. + bool AddMessageIntegrity(const std::string& password); + bool AddMessageIntegrity(const char* key, size_t keylen); + + // Verifies that a given buffer is STUN by checking for a correct FINGERPRINT. + static bool ValidateFingerprint(const char* data, size_t size); + + // Adds a FINGERPRINT attribute that is valid for the current message. + bool AddFingerprint(); + + // Parses the STUN packet in the given buffer and records it here. The + // return value indicates whether this was successful. + bool Read(talk_base::ByteBuffer* buf); + + // Writes this object into a STUN packet. The return value indicates whether + // this was successful. + bool Write(talk_base::ByteBuffer* buf) const; + + // Creates an empty message. Overridable by derived classes. + virtual StunMessage* CreateNew() const { return new StunMessage(); } + + protected: + // Verifies that the given attribute is allowed for this message. + virtual StunAttributeValueType GetAttributeValueType(int type) const; + + private: + StunAttribute* CreateAttribute(int type, size_t length) /* const*/; + const StunAttribute* GetAttribute(int type) const; + static bool IsValidTransactionId(const std::string& transaction_id); + + uint16 type_; + uint16 length_; + std::string transaction_id_; + std::vector* attrs_; +}; + +// Base class for all STUN/TURN attributes. +class StunAttribute { + public: + virtual ~StunAttribute() { + } + + int type() const { return type_; } + size_t length() const { return length_; } + + // Return the type of this attribute. + virtual StunAttributeValueType value_type() const = 0; + + // Only XorAddressAttribute needs this so far. + virtual void SetOwner(StunMessage* owner) {} + + // Reads the body (not the type or length) for this type of attribute from + // the given buffer. Return value is true if successful. + virtual bool Read(talk_base::ByteBuffer* buf) = 0; + + // Writes the body (not the type or length) to the given buffer. Return + // value is true if successful. + virtual bool Write(talk_base::ByteBuffer* buf) const = 0; + + // Creates an attribute object with the given type and smallest length. + static StunAttribute* Create(StunAttributeValueType value_type, uint16 type, + uint16 length, StunMessage* owner); + // TODO: Allow these create functions to take parameters, to reduce + // the amount of work callers need to do to initialize attributes. + static StunAddressAttribute* CreateAddress(uint16 type); + static StunXorAddressAttribute* CreateXorAddress(uint16 type); + static StunUInt32Attribute* CreateUInt32(uint16 type); + static StunUInt64Attribute* CreateUInt64(uint16 type); + static StunByteStringAttribute* CreateByteString(uint16 type); + static StunErrorCodeAttribute* CreateErrorCode(); + static StunUInt16ListAttribute* CreateUnknownAttributes(); + + protected: + StunAttribute(uint16 type, uint16 length); + void SetLength(uint16 length) { length_ = length; } + void WritePadding(talk_base::ByteBuffer* buf) const; + void ConsumePadding(talk_base::ByteBuffer* buf) const; + + private: + uint16 type_; + uint16 length_; +}; + +// Implements STUN attributes that record an Internet address. +class StunAddressAttribute : public StunAttribute { + public: + static const uint16 SIZE_UNDEF = 0; + static const uint16 SIZE_IP4 = 8; + static const uint16 SIZE_IP6 = 20; + StunAddressAttribute(uint16 type, const talk_base::SocketAddress& addr); + StunAddressAttribute(uint16 type, uint16 length); + + virtual StunAttributeValueType value_type() const { + return STUN_VALUE_ADDRESS; + } + + StunAddressFamily family() const { + switch (address_.ipaddr().family()) { + case AF_INET: + return STUN_ADDRESS_IPV4; + case AF_INET6: + return STUN_ADDRESS_IPV6; + } + return STUN_ADDRESS_UNDEF; + } + + const talk_base::SocketAddress& GetAddress() const { return address_; } + const talk_base::IPAddress& ipaddr() const { return address_.ipaddr(); } + uint16 port() const { return address_.port(); } + + void SetAddress(const talk_base::SocketAddress& addr) { + address_ = addr; + EnsureAddressLength(); + } + void SetIP(const talk_base::IPAddress& ip) { + address_.SetIP(ip); + EnsureAddressLength(); + } + void SetPort(uint16 port) { address_.SetPort(port); } + + virtual bool Read(talk_base::ByteBuffer* buf); + virtual bool Write(talk_base::ByteBuffer* buf) const; + + private: + void EnsureAddressLength() { + switch (family()) { + case STUN_ADDRESS_IPV4: { + SetLength(SIZE_IP4); + break; + } + case STUN_ADDRESS_IPV6: { + SetLength(SIZE_IP6); + break; + } + default: { + SetLength(SIZE_UNDEF); + break; + } + } + } + talk_base::SocketAddress address_; +}; + +// Implements STUN attributes that record an Internet address. When encoded +// in a STUN message, the address contained in this attribute is XORed with the +// transaction ID of the message. +class StunXorAddressAttribute : public StunAddressAttribute { + public: + StunXorAddressAttribute(uint16 type, const talk_base::SocketAddress& addr); + StunXorAddressAttribute(uint16 type, uint16 length, + StunMessage* owner); + + virtual StunAttributeValueType value_type() const { + return STUN_VALUE_XOR_ADDRESS; + } + virtual void SetOwner(StunMessage* owner) { + owner_ = owner; + } + virtual bool Read(talk_base::ByteBuffer* buf); + virtual bool Write(talk_base::ByteBuffer* buf) const; + + private: + talk_base::IPAddress GetXoredIP() const; + StunMessage* owner_; +}; + +// Implements STUN attributes that record a 32-bit integer. +class StunUInt32Attribute : public StunAttribute { + public: + static const uint16 SIZE = 4; + StunUInt32Attribute(uint16 type, uint32 value); + explicit StunUInt32Attribute(uint16 type); + + virtual StunAttributeValueType value_type() const { + return STUN_VALUE_UINT32; + } + + uint32 value() const { return bits_; } + void SetValue(uint32 bits) { bits_ = bits; } + + bool GetBit(size_t index) const; + void SetBit(size_t index, bool value); + + virtual bool Read(talk_base::ByteBuffer* buf); + virtual bool Write(talk_base::ByteBuffer* buf) const; + + private: + uint32 bits_; +}; + +class StunUInt64Attribute : public StunAttribute { + public: + static const uint16 SIZE = 8; + StunUInt64Attribute(uint16 type, uint64 value); + explicit StunUInt64Attribute(uint16 type); + + virtual StunAttributeValueType value_type() const { + return STUN_VALUE_UINT64; + } + + uint64 value() const { return bits_; } + void SetValue(uint64 bits) { bits_ = bits; } + + virtual bool Read(talk_base::ByteBuffer* buf); + virtual bool Write(talk_base::ByteBuffer* buf) const; + + private: + uint64 bits_; +}; + +// Implements STUN attributes that record an arbitrary byte string. +class StunByteStringAttribute : public StunAttribute { + public: + explicit StunByteStringAttribute(uint16 type); + StunByteStringAttribute(uint16 type, const std::string& str); + StunByteStringAttribute(uint16 type, const void* bytes, size_t length); + StunByteStringAttribute(uint16 type, uint16 length); + ~StunByteStringAttribute(); + + virtual StunAttributeValueType value_type() const { + return STUN_VALUE_BYTE_STRING; + } + + const char* bytes() const { return bytes_; } + std::string GetString() const { return std::string(bytes_, length()); } + + void CopyBytes(const char* bytes); // uses strlen + void CopyBytes(const void* bytes, size_t length); + + uint8 GetByte(size_t index) const; + void SetByte(size_t index, uint8 value); + + virtual bool Read(talk_base::ByteBuffer* buf); + virtual bool Write(talk_base::ByteBuffer* buf) const; + + private: + void SetBytes(char* bytes, size_t length); + + char* bytes_; +}; + +// Implements STUN attributes that record an error code. +class StunErrorCodeAttribute : public StunAttribute { + public: + static const uint16 MIN_SIZE = 4; + StunErrorCodeAttribute(uint16 type, int code, const std::string& reason); + StunErrorCodeAttribute(uint16 type, uint16 length); + ~StunErrorCodeAttribute(); + + virtual StunAttributeValueType value_type() const { + return STUN_VALUE_ERROR_CODE; + } + + // The combined error and class, e.g. 0x400. + int code() const; + void SetCode(int code); + + // The individual error components. + int eclass() const { return class_; } + int number() const { return number_; } + const std::string& reason() const { return reason_; } + void SetClass(uint8 eclass) { class_ = eclass; } + void SetNumber(uint8 number) { number_ = number; } + void SetReason(const std::string& reason); + + bool Read(talk_base::ByteBuffer* buf); + bool Write(talk_base::ByteBuffer* buf) const; + + private: + uint8 class_; + uint8 number_; + std::string reason_; +}; + +// Implements STUN attributes that record a list of attribute names. +class StunUInt16ListAttribute : public StunAttribute { + public: + StunUInt16ListAttribute(uint16 type, uint16 length); + ~StunUInt16ListAttribute(); + + virtual StunAttributeValueType value_type() const { + return STUN_VALUE_UINT16_LIST; + } + + size_t Size() const; + uint16 GetType(int index) const; + void SetType(int index, uint16 value); + void AddType(uint16 value); + + bool Read(talk_base::ByteBuffer* buf); + bool Write(talk_base::ByteBuffer* buf) const; + + private: + std::vector* attr_types_; +}; + +// Returns the (successful) response type for the given request type. +// Returns -1 if |request_type| is not a valid request type. +int GetStunSuccessResponseType(int request_type); + +// Returns the error response type for the given request type. +// Returns -1 if |request_type| is not a valid request type. +int GetStunErrorResponseType(int request_type); + +// Returns whether a given message is a request type. +bool IsStunRequestType(int msg_type); + +// Returns whether a given message is an indication type. +bool IsStunIndicationType(int msg_type); + +// Returns whether a given response is a success type. +bool IsStunSuccessResponseType(int msg_type); + +// Returns whether a given response is an error type. +bool IsStunErrorResponseType(int msg_type); + +// Computes the STUN long-term credential hash. +bool ComputeStunCredentialHash(const std::string& username, + const std::string& realm, const std::string& password, std::string* hash); + +// TODO: Move the TURN/ICE stuff below out to separate files. +extern const char TURN_MAGIC_COOKIE_VALUE[4]; + +// "GTURN" STUN methods. +// TODO: Rename these methods to GTURN_ to make it clear they aren't +// part of standard STUN/TURN. +enum RelayMessageType { + // For now, using the same defs from TurnMessageType below. + // STUN_ALLOCATE_REQUEST = 0x0003, + // STUN_ALLOCATE_RESPONSE = 0x0103, + // STUN_ALLOCATE_ERROR_RESPONSE = 0x0113, + STUN_SEND_REQUEST = 0x0004, + STUN_SEND_RESPONSE = 0x0104, + STUN_SEND_ERROR_RESPONSE = 0x0114, + STUN_DATA_INDICATION = 0x0115, +}; + +// "GTURN"-specific STUN attributes. +// TODO: Rename these attributes to GTURN_ to avoid conflicts. +enum RelayAttributeType { + STUN_ATTR_LIFETIME = 0x000d, // UInt32 + STUN_ATTR_MAGIC_COOKIE = 0x000f, // ByteString, 4 bytes + STUN_ATTR_BANDWIDTH = 0x0010, // UInt32 + STUN_ATTR_DESTINATION_ADDRESS = 0x0011, // Address + STUN_ATTR_SOURCE_ADDRESS2 = 0x0012, // Address + STUN_ATTR_DATA = 0x0013, // ByteString + STUN_ATTR_OPTIONS = 0x8001, // UInt32 +}; + +// A "GTURN" STUN message. +class RelayMessage : public StunMessage { + protected: + virtual StunAttributeValueType GetAttributeValueType(int type) const { + switch (type) { + case STUN_ATTR_LIFETIME: return STUN_VALUE_UINT32; + case STUN_ATTR_MAGIC_COOKIE: return STUN_VALUE_BYTE_STRING; + case STUN_ATTR_BANDWIDTH: return STUN_VALUE_UINT32; + case STUN_ATTR_DESTINATION_ADDRESS: return STUN_VALUE_ADDRESS; + case STUN_ATTR_SOURCE_ADDRESS2: return STUN_VALUE_ADDRESS; + case STUN_ATTR_DATA: return STUN_VALUE_BYTE_STRING; + case STUN_ATTR_OPTIONS: return STUN_VALUE_UINT32; + default: return StunMessage::GetAttributeValueType(type); + } + } + virtual StunMessage* CreateNew() const { return new RelayMessage(); } +}; + +// Defined in TURN RFC 5766. +enum TurnMessageType { + STUN_ALLOCATE_REQUEST = 0x0003, + STUN_ALLOCATE_RESPONSE = 0x0103, + STUN_ALLOCATE_ERROR_RESPONSE = 0x0113, + TURN_REFRESH_REQUEST = 0x0004, + TURN_REFRESH_RESPONSE = 0x0104, + TURN_REFRESH_ERROR_RESPONSE = 0x0114, + TURN_SEND_INDICATION = 0x0016, + TURN_DATA_INDICATION = 0x0017, + TURN_CREATE_PERMISSION_REQUEST = 0x0008, + TURN_CREATE_PERMISSION_RESPONSE = 0x0108, + TURN_CREATE_PERMISSION_ERROR_RESPONSE = 0x0118, + TURN_CHANNEL_BIND_REQUEST = 0x0009, + TURN_CHANNEL_BIND_RESPONSE = 0x0109, + TURN_CHANNEL_BIND_ERROR_RESPONSE = 0x0119, +}; + +enum TurnAttributeType { + STUN_ATTR_CHANNEL_NUMBER = 0x000C, // UInt32 + STUN_ATTR_TURN_LIFETIME = 0x000d, // UInt32 + STUN_ATTR_XOR_PEER_ADDRESS = 0x0012, // XorAddress + // TODO(mallinath) - Uncomment after RelayAttributes are renamed. + // STUN_ATTR_DATA = 0x0013, // ByteString + STUN_ATTR_XOR_RELAYED_ADDRESS = 0x0016, // XorAddress + STUN_ATTR_EVEN_PORT = 0x0018, // ByteString, 1 byte. + STUN_ATTR_REQUESTED_TRANSPORT = 0x0019, // UInt32 + STUN_ATTR_DONT_FRAGMENT = 0x001A, // No content, Length = 0 + STUN_ATTR_RESERVATION_TOKEN = 0x0022, // ByteString, 8 bytes. + // TODO(mallinath) - Rename STUN_ATTR_TURN_LIFETIME to STUN_ATTR_LIFETIME and + // STUN_ATTR_TURN_DATA to STUN_ATTR_DATA. Also rename RelayMessage attributes + // by appending G to attribute name. +}; + +// RFC 5766-defined errors. +enum TurnErrorType { + STUN_ERROR_FORBIDDEN = 403, + STUN_ERROR_ALLOCATION_MISMATCH = 437, + STUN_ERROR_WRONG_CREDENTIALS = 441, + STUN_ERROR_UNSUPPORTED_PROTOCOL = 442 +}; +extern const char STUN_ERROR_REASON_FORBIDDEN[]; +extern const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[]; +extern const char STUN_ERROR_REASON_WRONG_CREDENTIALS[]; +extern const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[]; +class TurnMessage : public StunMessage { + protected: + virtual StunAttributeValueType GetAttributeValueType(int type) const { + switch (type) { + case STUN_ATTR_CHANNEL_NUMBER: return STUN_VALUE_UINT32; + case STUN_ATTR_TURN_LIFETIME: return STUN_VALUE_UINT32; + case STUN_ATTR_XOR_PEER_ADDRESS: return STUN_VALUE_XOR_ADDRESS; + case STUN_ATTR_DATA: return STUN_VALUE_BYTE_STRING; + case STUN_ATTR_XOR_RELAYED_ADDRESS: return STUN_VALUE_XOR_ADDRESS; + case STUN_ATTR_EVEN_PORT: return STUN_VALUE_BYTE_STRING; + case STUN_ATTR_REQUESTED_TRANSPORT: return STUN_VALUE_UINT32; + case STUN_ATTR_DONT_FRAGMENT: return STUN_VALUE_BYTE_STRING; + case STUN_ATTR_RESERVATION_TOKEN: return STUN_VALUE_BYTE_STRING; + default: return StunMessage::GetAttributeValueType(type); + } + } + virtual StunMessage* CreateNew() const { return new TurnMessage(); } +}; + +// RFC 5245 ICE STUN attributes. +enum IceAttributeType { + STUN_ATTR_PRIORITY = 0x0024, // UInt32 + STUN_ATTR_USE_CANDIDATE = 0x0025, // No content, Length = 0 + STUN_ATTR_ICE_CONTROLLED = 0x8029, // UInt64 + STUN_ATTR_ICE_CONTROLLING = 0x802A // UInt64 +}; + +// RFC 5245-defined errors. +enum IceErrorCode { + STUN_ERROR_ROLE_CONFLICT = 487, +}; +extern const char STUN_ERROR_REASON_ROLE_CONFLICT[]; + +// A RFC 5245 ICE STUN message. +class IceMessage : public StunMessage { + protected: + virtual StunAttributeValueType GetAttributeValueType(int type) const { + switch (type) { + case STUN_ATTR_PRIORITY: return STUN_VALUE_UINT32; + case STUN_ATTR_USE_CANDIDATE: return STUN_VALUE_BYTE_STRING; + case STUN_ATTR_ICE_CONTROLLED: return STUN_VALUE_UINT64; + case STUN_ATTR_ICE_CONTROLLING: return STUN_VALUE_UINT64; + default: return StunMessage::GetAttributeValueType(type); + } + } + virtual StunMessage* CreateNew() const { return new IceMessage(); } +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_STUN_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunport.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunport.h new file mode 100644 index 0000000..bd074a4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunport.h @@ -0,0 +1,214 @@ +/* + * 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 TALK_P2P_BASE_STUNPORT_H_ +#define TALK_P2P_BASE_STUNPORT_H_ + +#include + +#include "talk/base/asyncpacketsocket.h" +#include "talk/p2p/base/port.h" +#include "talk/p2p/base/stunrequest.h" + +// TODO(mallinath) - Rename stunport.cc|h to udpport.cc|h. +namespace talk_base { +class AsyncResolver; +class SignalThread; +} + +namespace cricket { + +// Communicates using the address on the outside of a NAT. +class UDPPort : public Port { + public: + static UDPPort* Create(talk_base::Thread* thread, + talk_base::PacketSocketFactory* factory, + talk_base::Network* network, + talk_base::AsyncPacketSocket* socket, + const std::string& username, + const std::string& password) { + UDPPort* port = new UDPPort(thread, factory, network, socket, + username, password); + if (!port->Init()) { + delete port; + port = NULL; + } + return port; + } + + static UDPPort* 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, + const std::string& password) { + UDPPort* port = new UDPPort(thread, factory, network, + ip, min_port, max_port, + username, password); + if (!port->Init()) { + delete port; + port = NULL; + } + return port; + } + virtual ~UDPPort(); + + talk_base::SocketAddress GetLocalAddress() const { + return socket_->GetLocalAddress(); + } + + const talk_base::SocketAddress& server_addr() const { return server_addr_; } + void set_server_addr(const talk_base::SocketAddress& addr) { + server_addr_ = addr; + } + + virtual void PrepareAddress(); + + virtual Connection* CreateConnection(const Candidate& address, + CandidateOrigin origin); + virtual int SetOption(talk_base::Socket::Option opt, int value); + virtual int GetOption(talk_base::Socket::Option opt, int* value); + virtual int GetError(); + + 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) { + // All packets given to UDP port will be consumed. + OnReadPacket(socket, data, size, remote_addr, packet_time); + return true; + } + + void set_stun_keepalive_delay(int delay) { + stun_keepalive_delay_ = delay; + } + int stun_keepalive_delay() const { + return stun_keepalive_delay_; + } + + protected: + UDPPort(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, const std::string& password); + + UDPPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory, + talk_base::Network* network, talk_base::AsyncPacketSocket* socket, + const std::string& username, const std::string& password); + + bool Init(); + + virtual int SendTo(const void* data, size_t size, + const talk_base::SocketAddress& addr, + const talk_base::PacketOptions& options, + bool payload); + + void OnLocalAddressReady(talk_base::AsyncPacketSocket* socket, + const talk_base::SocketAddress& address); + void OnReadPacket(talk_base::AsyncPacketSocket* socket, + const char* data, size_t size, + const talk_base::SocketAddress& remote_addr, + const talk_base::PacketTime& packet_time); + + void OnReadyToSend(talk_base::AsyncPacketSocket* socket); + + // This method will send STUN binding request if STUN server address is set. + void MaybePrepareStunCandidate(); + + void SendStunBindingRequest(); + + private: + // DNS resolution of the STUN server. + void ResolveStunAddress(); + void OnResolveResult(talk_base::AsyncResolverInterface* resolver); + + // Below methods handles binding request responses. + void OnStunBindingRequestSucceeded(const talk_base::SocketAddress& stun_addr); + void OnStunBindingOrResolveRequestFailed(); + + // Sends STUN requests to the server. + void OnSendPacket(const void* data, size_t size, StunRequest* req); + + // TODO(mallinaht) - Move this up to cricket::Port when SignalAddressReady is + // changed to SignalPortReady. + void SetResult(bool success); + + talk_base::SocketAddress server_addr_; + StunRequestManager requests_; + talk_base::AsyncPacketSocket* socket_; + int error_; + talk_base::AsyncResolverInterface* resolver_; + bool ready_; + int stun_keepalive_delay_; + + friend class StunBindingRequest; +}; + +class StunPort : public UDPPort { + public: + static StunPort* 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, + const std::string& password, + const talk_base::SocketAddress& server_addr) { + StunPort* port = new StunPort(thread, factory, network, + ip, min_port, max_port, + username, password, server_addr); + if (!port->Init()) { + delete port; + port = NULL; + } + return port; + } + + virtual ~StunPort() {} + + virtual void PrepareAddress() { + SendStunBindingRequest(); + } + + protected: + StunPort(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, const std::string& password, + const talk_base::SocketAddress& server_address) + : UDPPort(thread, factory, network, ip, min_port, max_port, username, + password) { + // UDPPort will set these to local udp, updating these to STUN. + set_type(STUN_PORT_TYPE); + set_server_addr(server_address); + } +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_STUNPORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunrequest.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunrequest.h new file mode 100644 index 0000000..76f9d1d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunrequest.h @@ -0,0 +1,133 @@ +/* + * 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 TALK_P2P_BASE_STUNREQUEST_H_ +#define TALK_P2P_BASE_STUNREQUEST_H_ + +#include "talk/base/sigslot.h" +#include "talk/base/thread.h" +#include "talk/p2p/base/stun.h" +#include +#include + +namespace cricket { + +class StunRequest; + +// Manages a set of STUN requests, sending and resending until we receive a +// response or determine that the request has timed out. +class StunRequestManager { +public: + StunRequestManager(talk_base::Thread* thread); + ~StunRequestManager(); + + // Starts sending the given request (perhaps after a delay). + void Send(StunRequest* request); + void SendDelayed(StunRequest* request, int delay); + + // Removes a stun request that was added previously. This will happen + // automatically when a request succeeds, fails, or times out. + void Remove(StunRequest* request); + + // Removes all stun requests that were added previously. + void Clear(); + + // Determines whether the given message is a response to one of the + // outstanding requests, and if so, processes it appropriately. + bool CheckResponse(StunMessage* msg); + bool CheckResponse(const char* data, size_t size); + + bool empty() { return requests_.empty(); } + + // Raised when there are bytes to be sent. + sigslot::signal3 SignalSendPacket; + +private: + typedef std::map RequestMap; + + talk_base::Thread* thread_; + RequestMap requests_; + + friend class StunRequest; +}; + +// Represents an individual request to be sent. The STUN message can either be +// constructed beforehand or built on demand. +class StunRequest : public talk_base::MessageHandler { +public: + StunRequest(); + StunRequest(StunMessage* request); + virtual ~StunRequest(); + + // Causes our wrapped StunMessage to be Prepared + void Construct(); + + // The manager handling this request (if it has been scheduled for sending). + StunRequestManager* manager() { return manager_; } + + // Returns the transaction ID of this request. + const std::string& id() { return msg_->transaction_id(); } + + // Returns the STUN type of the request message. + int type(); + + // Returns a const pointer to |msg_|. + const StunMessage* msg() const; + + // Time elapsed since last send (in ms) + uint32 Elapsed() const; + +protected: + int count_; + bool timeout_; + + // Fills in a request object to be sent. Note that request's transaction ID + // will already be set and cannot be changed. + virtual void Prepare(StunMessage* request) {} + + // Called when the message receives a response or times out. + virtual void OnResponse(StunMessage* response) {} + virtual void OnErrorResponse(StunMessage* response) {} + virtual void OnTimeout() {} + virtual int GetNextDelay(); + +private: + void set_manager(StunRequestManager* manager); + + // Handles messages for sending and timeout. + void OnMessage(talk_base::Message* pmsg); + + StunRequestManager* manager_; + StunMessage* msg_; + uint32 tstamp_; + + friend class StunRequestManager; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_STUNREQUEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunserver.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunserver.h new file mode 100644 index 0000000..c2b72ca --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/stunserver.h @@ -0,0 +1,78 @@ +/* + * 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 TALK_P2P_BASE_STUNSERVER_H_ +#define TALK_P2P_BASE_STUNSERVER_H_ + +#include "talk/base/asyncudpsocket.h" +#include "talk/base/scoped_ptr.h" +#include "talk/p2p/base/stun.h" + +namespace cricket { + +const int STUN_SERVER_PORT = 3478; + +class StunServer : public sigslot::has_slots<> { + public: + // Creates a STUN server, which will listen on the given socket. + explicit StunServer(talk_base::AsyncUDPSocket* socket); + // Removes the STUN server from the socket and deletes the socket. + ~StunServer(); + + protected: + // Slot for AsyncSocket.PacketRead: + void OnPacket( + talk_base::AsyncPacketSocket* socket, const char* buf, size_t size, + const talk_base::SocketAddress& remote_addr, + const talk_base::PacketTime& packet_time); + + // Handlers for the different types of STUN/TURN requests: + void OnBindingRequest(StunMessage* msg, + const talk_base::SocketAddress& addr); + void OnAllocateRequest(StunMessage* msg, + const talk_base::SocketAddress& addr); + void OnSharedSecretRequest(StunMessage* msg, + const talk_base::SocketAddress& addr); + void OnSendRequest(StunMessage* msg, + const talk_base::SocketAddress& addr); + + // Sends an error response to the given message back to the user. + void SendErrorResponse( + const StunMessage& msg, const talk_base::SocketAddress& addr, + int error_code, const char* error_desc); + + // Sends the given message to the appropriate destination. + void SendResponse(const StunMessage& msg, + const talk_base::SocketAddress& addr); + + private: + talk_base::scoped_ptr socket_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_STUNSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/tcpport.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/tcpport.h new file mode 100644 index 0000000..f0d7694 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/tcpport.h @@ -0,0 +1,153 @@ +/* + * 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 TALK_P2P_BASE_TCPPORT_H_ +#define TALK_P2P_BASE_TCPPORT_H_ + +#include +#include +#include "talk/base/asyncpacketsocket.h" +#include "talk/p2p/base/port.h" + +namespace cricket { + +class TCPConnection; + +// Communicates using a local TCP port. +// +// This class is designed to allow subclasses to take advantage of the +// connection management provided by this class. A subclass should take of all +// packet sending and preparation, but when a packet is received, it should +// call this TCPPort::OnReadPacket (3 arg) to dispatch to a connection. +class TCPPort : public Port { + public: + static TCPPort* 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, + const std::string& password, + bool allow_listen) { + TCPPort* port = new TCPPort(thread, factory, network, + ip, min_port, max_port, + username, password, allow_listen); + if (!port->Init()) { + delete port; + port = NULL; + } + return port; + } + virtual ~TCPPort(); + + virtual Connection* CreateConnection(const Candidate& address, + CandidateOrigin origin); + + virtual void PrepareAddress(); + + virtual int GetOption(talk_base::Socket::Option opt, int* value); + virtual int SetOption(talk_base::Socket::Option opt, int value); + virtual int GetError(); + + protected: + TCPPort(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, + const std::string& password, bool allow_listen); + bool Init(); + + // Handles sending using the local TCP socket. + virtual int SendTo(const void* data, size_t size, + const talk_base::SocketAddress& addr, + const talk_base::PacketOptions& options, + bool payload); + + // Accepts incoming TCP connection. + void OnNewConnection(talk_base::AsyncPacketSocket* socket, + talk_base::AsyncPacketSocket* new_socket); + + private: + struct Incoming { + talk_base::SocketAddress addr; + talk_base::AsyncPacketSocket* socket; + }; + + talk_base::AsyncPacketSocket* GetIncoming( + const talk_base::SocketAddress& addr, bool remove = false); + + // Receives packet signal from the local TCP Socket. + void OnReadPacket(talk_base::AsyncPacketSocket* socket, + const char* data, size_t size, + const talk_base::SocketAddress& remote_addr, + const talk_base::PacketTime& packet_time); + + void OnReadyToSend(talk_base::AsyncPacketSocket* socket); + + void OnAddressReady(talk_base::AsyncPacketSocket* socket, + const talk_base::SocketAddress& address); + + // TODO: Is this still needed? + bool incoming_only_; + bool allow_listen_; + talk_base::AsyncPacketSocket* socket_; + int error_; + std::list incoming_; + + friend class TCPConnection; +}; + +class TCPConnection : public Connection { + public: + // Connection is outgoing unless socket is specified + TCPConnection(TCPPort* port, const Candidate& candidate, + talk_base::AsyncPacketSocket* socket = 0); + virtual ~TCPConnection(); + + virtual int Send(const void* data, size_t size, + const talk_base::PacketOptions& options); + virtual int GetError(); + + talk_base::AsyncPacketSocket* socket() { return socket_; } + + private: + void OnConnect(talk_base::AsyncPacketSocket* socket); + void OnClose(talk_base::AsyncPacketSocket* socket, int error); + void OnReadPacket(talk_base::AsyncPacketSocket* socket, + const char* data, size_t size, + const talk_base::SocketAddress& remote_addr, + const talk_base::PacketTime& packet_time); + void OnReadyToSend(talk_base::AsyncPacketSocket* socket); + + talk_base::AsyncPacketSocket* socket_; + int error_; + + friend class TCPPort; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TCPPORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/testrelayserver.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/testrelayserver.h new file mode 100644 index 0000000..ca70481 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/testrelayserver.h @@ -0,0 +1,118 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_TESTRELAYSERVER_H_ +#define TALK_P2P_BASE_TESTRELAYSERVER_H_ + +#include "talk/base/asynctcpsocket.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/socketadapters.h" +#include "talk/base/sigslot.h" +#include "talk/base/thread.h" +#include "talk/p2p/base/relayserver.h" + +namespace cricket { + +// A test relay server. Useful for unit tests. +class TestRelayServer : public sigslot::has_slots<> { + public: + TestRelayServer(talk_base::Thread* thread, + const talk_base::SocketAddress& udp_int_addr, + const talk_base::SocketAddress& udp_ext_addr, + const talk_base::SocketAddress& tcp_int_addr, + const talk_base::SocketAddress& tcp_ext_addr, + const talk_base::SocketAddress& ssl_int_addr, + const talk_base::SocketAddress& ssl_ext_addr) + : server_(thread) { + server_.AddInternalSocket(talk_base::AsyncUDPSocket::Create( + thread->socketserver(), udp_int_addr)); + server_.AddExternalSocket(talk_base::AsyncUDPSocket::Create( + thread->socketserver(), udp_ext_addr)); + + tcp_int_socket_.reset(CreateListenSocket(thread, tcp_int_addr)); + tcp_ext_socket_.reset(CreateListenSocket(thread, tcp_ext_addr)); + ssl_int_socket_.reset(CreateListenSocket(thread, ssl_int_addr)); + ssl_ext_socket_.reset(CreateListenSocket(thread, ssl_ext_addr)); + } + int GetConnectionCount() const { + return server_.GetConnectionCount(); + } + talk_base::SocketAddressPair GetConnection(int connection) const { + return server_.GetConnection(connection); + } + bool HasConnection(const talk_base::SocketAddress& address) const { + return server_.HasConnection(address); + } + + private: + talk_base::AsyncSocket* CreateListenSocket(talk_base::Thread* thread, + const talk_base::SocketAddress& addr) { + talk_base::AsyncSocket* socket = + thread->socketserver()->CreateAsyncSocket(addr.family(), SOCK_STREAM); + socket->Bind(addr); + socket->Listen(5); + socket->SignalReadEvent.connect(this, &TestRelayServer::OnAccept); + return socket; + } + void OnAccept(talk_base::AsyncSocket* socket) { + bool external = (socket == tcp_ext_socket_.get() || + socket == ssl_ext_socket_.get()); + bool ssl = (socket == ssl_int_socket_.get() || + socket == ssl_ext_socket_.get()); + talk_base::AsyncSocket* raw_socket = socket->Accept(NULL); + if (raw_socket) { + talk_base::AsyncTCPSocket* packet_socket = new talk_base::AsyncTCPSocket( + (!ssl) ? raw_socket : + new talk_base::AsyncSSLServerSocket(raw_socket), false); + if (!external) { + packet_socket->SignalClose.connect(this, + &TestRelayServer::OnInternalClose); + server_.AddInternalSocket(packet_socket); + } else { + packet_socket->SignalClose.connect(this, + &TestRelayServer::OnExternalClose); + server_.AddExternalSocket(packet_socket); + } + } + } + void OnInternalClose(talk_base::AsyncPacketSocket* socket, int error) { + server_.RemoveInternalSocket(socket); + } + void OnExternalClose(talk_base::AsyncPacketSocket* socket, int error) { + server_.RemoveExternalSocket(socket); + } + private: + cricket::RelayServer server_; + talk_base::scoped_ptr tcp_int_socket_; + talk_base::scoped_ptr tcp_ext_socket_; + talk_base::scoped_ptr ssl_int_socket_; + talk_base::scoped_ptr ssl_ext_socket_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TESTRELAYSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/teststunserver.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/teststunserver.h new file mode 100644 index 0000000..80bf9eb --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/teststunserver.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_TESTSTUNSERVER_H_ +#define TALK_P2P_BASE_TESTSTUNSERVER_H_ + +#include "talk/base/socketaddress.h" +#include "talk/base/thread.h" +#include "talk/p2p/base/stunserver.h" + +namespace cricket { + +// A test STUN server. Useful for unit tests. +class TestStunServer { + public: + TestStunServer(talk_base::Thread* thread, + const talk_base::SocketAddress& addr) + : socket_(thread->socketserver()->CreateAsyncSocket(addr.family(), + SOCK_DGRAM)), + udp_socket_(talk_base::AsyncUDPSocket::Create(socket_, addr)), + server_(udp_socket_) { + } + private: + talk_base::AsyncSocket* socket_; + talk_base::AsyncUDPSocket* udp_socket_; + cricket::StunServer server_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TESTSTUNSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/testturnserver.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/testturnserver.h new file mode 100644 index 0000000..5625090 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/testturnserver.h @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_TESTTURNSERVER_H_ +#define TALK_P2P_BASE_TESTTURNSERVER_H_ + +#include + +#include "talk/base/asyncudpsocket.h" +#include "talk/base/thread.h" +#include "talk/p2p/base/basicpacketsocketfactory.h" +#include "talk/p2p/base/stun.h" +#include "talk/p2p/base/turnserver.h" + +namespace cricket { + +static const char kTestRealm[] = "example.org"; +static const char kTestSoftware[] = "TestTurnServer"; + +class TestTurnServer : public TurnAuthInterface { + public: + TestTurnServer(talk_base::Thread* thread, + const talk_base::SocketAddress& udp_int_addr, + const talk_base::SocketAddress& udp_ext_addr) + : server_(thread) { + AddInternalSocket(udp_int_addr, cricket::PROTO_UDP); + server_.SetExternalSocketFactory(new talk_base::BasicPacketSocketFactory(), + udp_ext_addr); + server_.set_realm(kTestRealm); + server_.set_software(kTestSoftware); + server_.set_auth_hook(this); + } + + void set_enable_otu_nonce(bool enable) { + server_.set_enable_otu_nonce(enable); + } + + TurnServer* server() { return &server_; } + + void AddInternalSocket(const talk_base::SocketAddress& int_addr, + ProtocolType proto) { + talk_base::Thread* thread = talk_base::Thread::Current(); + if (proto == cricket::PROTO_UDP) { + server_.AddInternalSocket(talk_base::AsyncUDPSocket::Create( + thread->socketserver(), int_addr), proto); + } else if (proto == cricket::PROTO_TCP) { + // For TCP we need to create a server socket which can listen for incoming + // new connections. + talk_base::AsyncSocket* socket = + thread->socketserver()->CreateAsyncSocket(SOCK_STREAM); + socket->Bind(int_addr); + socket->Listen(5); + server_.AddInternalServerSocket(socket, proto); + } + } + + private: + // For this test server, succeed if the password is the same as the username. + // Obviously, do not use this in a production environment. + virtual bool GetKey(const std::string& username, const std::string& realm, + std::string* key) { + return ComputeStunCredentialHash(username, realm, username, key); + } + + TurnServer server_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TESTTURNSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transport.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transport.h new file mode 100644 index 0000000..6d85438 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transport.h @@ -0,0 +1,525 @@ +/* + * 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. + */ + +// A Transport manages a set of named channels of the same type. +// +// Subclasses choose the appropriate class to instantiate for each channel; +// however, this base class keeps track of the channels by name, watches their +// state changes (in order to update the manager's state), and forwards +// requests to begin connecting or to reset to each of the channels. +// +// On Threading: Transport performs work on both the signaling and worker +// threads. For subclasses, the rule is that all signaling related calls will +// be made on the signaling thread and all channel related calls (including +// signaling for a channel) will be made on the worker thread. When +// information needs to be sent between the two threads, this class should do +// the work (e.g., OnRemoteCandidate). +// +// Note: Subclasses must call DestroyChannels() in their own constructors. +// It is not possible to do so here because the subclass constructor will +// already have run. + +#ifndef TALK_P2P_BASE_TRANSPORT_H_ +#define TALK_P2P_BASE_TRANSPORT_H_ + +#include +#include +#include +#include "talk/base/criticalsection.h" +#include "talk/base/messagequeue.h" +#include "talk/base/sigslot.h" +#include "talk/base/sslstreamadapter.h" +#include "talk/p2p/base/candidate.h" +#include "talk/p2p/base/constants.h" +#include "talk/p2p/base/sessiondescription.h" +#include "talk/p2p/base/transportinfo.h" + +namespace talk_base { +class Thread; +} + +namespace buzz { +class QName; +class XmlElement; +} + +namespace cricket { + +struct ParseError; +struct WriteError; +class CandidateTranslator; +class PortAllocator; +class SessionManager; +class Session; +class TransportChannel; +class TransportChannelImpl; + +typedef std::vector XmlElements; +typedef std::vector Candidates; + +// Used to parse and serialize (write) transport candidates. For +// convenience of old code, Transports will implement TransportParser. +// Parse/Write seems better than Serialize/Deserialize or +// Create/Translate. +class TransportParser { + public: + // The incoming Translator value may be null, in which case + // ParseCandidates should return false if there are candidates to + // parse (indicating a failure to parse). If the Translator is null + // and there are no candidates to parse, then return true, + // indicating a successful parse of 0 candidates. + + // Parse or write a transport description, including ICE credentials and + // any DTLS fingerprint. Since only Jingle has transport descriptions, these + // functions are only used when serializing to Jingle. + virtual bool ParseTransportDescription(const buzz::XmlElement* elem, + const CandidateTranslator* translator, + TransportDescription* tdesc, + ParseError* error) = 0; + virtual bool WriteTransportDescription(const TransportDescription& tdesc, + const CandidateTranslator* translator, + buzz::XmlElement** tdesc_elem, + WriteError* error) = 0; + + + // Parse a single candidate. This must be used when parsing Gingle + // candidates, since there is no enclosing transport description. + virtual bool ParseGingleCandidate(const buzz::XmlElement* elem, + const CandidateTranslator* translator, + Candidate* candidates, + ParseError* error) = 0; + virtual bool WriteGingleCandidate(const Candidate& candidate, + const CandidateTranslator* translator, + buzz::XmlElement** candidate_elem, + WriteError* error) = 0; + + // Helper function to parse an element describing an address. This + // retrieves the IP and port from the given element and verifies + // that they look like plausible values. + bool ParseAddress(const buzz::XmlElement* elem, + const buzz::QName& address_name, + const buzz::QName& port_name, + talk_base::SocketAddress* address, + ParseError* error); + + virtual ~TransportParser() {} +}; + +// For "writable" and "readable", we need to differentiate between +// none, all, and some. +enum TransportState { + TRANSPORT_STATE_NONE = 0, + TRANSPORT_STATE_SOME, + TRANSPORT_STATE_ALL +}; + +// Stats that we can return about the connections for a transport channel. +// TODO(hta): Rename to ConnectionStats +struct ConnectionInfo { + ConnectionInfo() + : best_connection(false), + writable(false), + readable(false), + timeout(false), + new_connection(false), + rtt(0), + sent_total_bytes(0), + sent_bytes_second(0), + recv_total_bytes(0), + recv_bytes_second(0), + key(NULL) {} + + bool best_connection; // Is this the best connection we have? + bool writable; // Has this connection received a STUN response? + bool readable; // Has this connection received a STUN request? + bool timeout; // Has this connection timed out? + bool new_connection; // Is this a newly created connection? + size_t rtt; // The STUN RTT for this connection. + size_t sent_total_bytes; // Total bytes sent on this connection. + size_t sent_bytes_second; // Bps over the last measurement interval. + size_t recv_total_bytes; // Total bytes received on this connection. + size_t recv_bytes_second; // Bps over the last measurement interval. + Candidate local_candidate; // The local candidate for this connection. + Candidate remote_candidate; // The remote candidate for this connection. + void* key; // A static value that identifies this conn. +}; + +// Information about all the connections of a channel. +typedef std::vector ConnectionInfos; + +// Information about a specific channel +struct TransportChannelStats { + int component; + ConnectionInfos connection_infos; +}; + +// Information about all the channels of a transport. +// TODO(hta): Consider if a simple vector is as good as a map. +typedef std::vector TransportChannelStatsList; + +// Information about the stats of a transport. +struct TransportStats { + std::string content_name; + TransportChannelStatsList channel_stats; +}; + +bool BadTransportDescription(const std::string& desc, std::string* err_desc); + +class Transport : public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + Transport(talk_base::Thread* signaling_thread, + talk_base::Thread* worker_thread, + const std::string& content_name, + const std::string& type, + PortAllocator* allocator); + virtual ~Transport(); + + // Returns the signaling thread. The app talks to Transport on this thread. + talk_base::Thread* signaling_thread() { return signaling_thread_; } + // Returns the worker thread. The actual networking is done on this thread. + talk_base::Thread* worker_thread() { return worker_thread_; } + + // Returns the content_name of this transport. + const std::string& content_name() const { return content_name_; } + // Returns the type of this transport. + const std::string& type() const { return type_; } + + // Returns the port allocator object for this transport. + PortAllocator* port_allocator() { return allocator_; } + + // Returns the readable and states of this manager. These bits are the ORs + // of the corresponding bits on the managed channels. Each time one of these + // states changes, a signal is raised. + // TODO: Replace uses of readable() and writable() with + // any_channels_readable() and any_channels_writable(). + bool readable() const { return any_channels_readable(); } + bool writable() const { return any_channels_writable(); } + bool was_writable() const { return was_writable_; } + bool any_channels_readable() const { + return (readable_ == TRANSPORT_STATE_SOME || + readable_ == TRANSPORT_STATE_ALL); + } + bool any_channels_writable() const { + return (writable_ == TRANSPORT_STATE_SOME || + writable_ == TRANSPORT_STATE_ALL); + } + bool all_channels_readable() const { + return (readable_ == TRANSPORT_STATE_ALL); + } + bool all_channels_writable() const { + return (writable_ == TRANSPORT_STATE_ALL); + } + sigslot::signal1 SignalReadableState; + sigslot::signal1 SignalWritableState; + sigslot::signal1 SignalCompleted; + sigslot::signal1 SignalFailed; + + // Returns whether the client has requested the channels to connect. + bool connect_requested() const { return connect_requested_; } + + void SetIceRole(IceRole role); + IceRole ice_role() const { return ice_role_; } + + void SetIceTiebreaker(uint64 IceTiebreaker) { tiebreaker_ = IceTiebreaker; } + uint64 IceTiebreaker() { return tiebreaker_; } + + // Must be called before applying local session description. + void SetIdentity(talk_base::SSLIdentity* identity); + + // Get a copy of the local identity provided by SetIdentity. + bool GetIdentity(talk_base::SSLIdentity** identity); + + // Get a copy of the remote certificate in use by the specified channel. + bool GetRemoteCertificate(talk_base::SSLCertificate** cert); + + TransportProtocol protocol() const { return protocol_; } + + // Create, destroy, and lookup the channels of this type by their components. + TransportChannelImpl* CreateChannel(int component); + // Note: GetChannel may lead to race conditions, since the mutex is not held + // after the pointer is returned. + TransportChannelImpl* GetChannel(int component); + // Note: HasChannel does not lead to race conditions, unlike GetChannel. + bool HasChannel(int component) { + return (NULL != GetChannel(component)); + } + bool HasChannels(); + void DestroyChannel(int component); + + // Set the local TransportDescription to be used by TransportChannels. + // This should be called before ConnectChannels(). + bool SetLocalTransportDescription(const TransportDescription& description, + ContentAction action, + std::string* error_desc); + + // Set the remote TransportDescription to be used by TransportChannels. + bool SetRemoteTransportDescription(const TransportDescription& description, + 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. + void ConnectChannels(); + sigslot::signal1 SignalConnecting; + + // Resets all of the channels back to their initial state. They are no + // longer connecting. + void ResetChannels(); + + // Destroys every channel created so far. + void DestroyAllChannels(); + + bool GetStats(TransportStats* stats); + + // Before any stanza is sent, the manager will request signaling. Once + // signaling is available, the client should call OnSignalingReady. Once + // this occurs, the transport (or its channels) can send any waiting stanzas. + // OnSignalingReady invokes OnTransportSignalingReady and then forwards this + // signal to each channel. + sigslot::signal1 SignalRequestSignaling; + void OnSignalingReady(); + + // Handles sending of ready candidates and receiving of remote candidates. + sigslot::signal2&> SignalCandidatesReady; + + sigslot::signal1 SignalCandidatesAllocationDone; + void OnRemoteCandidates(const std::vector& candidates); + + // If candidate is not acceptable, returns false and sets error. + // Call this before calling OnRemoteCandidates. + virtual bool VerifyCandidate(const Candidate& candidate, + std::string* error); + + // Signals when the best connection for a channel changes. + sigslot::signal3 SignalRouteChange; + + // A transport message has generated an transport-specific error. The + // stanza that caused the error is available in session_msg. If false is + // returned, the error is considered unrecoverable, and the session is + // terminated. + // TODO(juberti): Remove these obsolete functions once Session no longer + // references them. + virtual void OnTransportError(const buzz::XmlElement* error) {} + sigslot::signal6 + SignalTransportError; + + // Forwards the signal from TransportChannel to BaseSession. + sigslot::signal0<> SignalRoleConflict; + + virtual bool GetSslRole(talk_base::SSLRole* ssl_role) const; + + protected: + // These are called by Create/DestroyChannel above in order to create or + // destroy the appropriate type of channel. + virtual TransportChannelImpl* CreateTransportChannel(int component) = 0; + virtual void DestroyTransportChannel(TransportChannelImpl* channel) = 0; + + // Informs the subclass that we received the signaling ready message. + virtual void OnTransportSignalingReady() {} + + // The current local transport description, for use by derived classes + // when performing transport description negotiation. + const TransportDescription* local_description() const { + return local_description_.get(); + } + + // The current remote transport description, for use by derived classes + // when performing transport description negotiation. + const TransportDescription* remote_description() const { + return remote_description_.get(); + } + + virtual void SetIdentity_w(talk_base::SSLIdentity* identity) {} + + virtual bool GetIdentity_w(talk_base::SSLIdentity** identity) { + return false; + } + + // 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, + std::string* error_desc); + + // Pushes down remote ice credentials from the remote description to the + // transport channel. + 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, + 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, std::string* error_desc); + + virtual bool GetSslRole_w(talk_base::SSLRole* ssl_role) const { + return false; + } + + private: + struct ChannelMapEntry { + ChannelMapEntry() : impl_(NULL), candidates_allocated_(false), ref_(0) {} + explicit ChannelMapEntry(TransportChannelImpl *impl) + : impl_(impl), + candidates_allocated_(false), + ref_(0) { + } + + void AddRef() { ++ref_; } + void DecRef() { + ASSERT(ref_ > 0); + --ref_; + } + int ref() const { return ref_; } + + TransportChannelImpl* get() const { return impl_; } + TransportChannelImpl* operator->() const { return impl_; } + void set_candidates_allocated(bool status) { + candidates_allocated_ = status; + } + bool candidates_allocated() const { return candidates_allocated_; } + + private: + TransportChannelImpl *impl_; + bool candidates_allocated_; + int ref_; + }; + + // Candidate component => ChannelMapEntry + typedef std::map ChannelMap; + + // Called when the state of a channel changes. + void OnChannelReadableState(TransportChannel* channel); + void OnChannelWritableState(TransportChannel* channel); + + // Called when a channel requests signaling. + void OnChannelRequestSignaling(TransportChannelImpl* channel); + + // Called when a candidate is ready from remote peer. + void OnRemoteCandidate(const Candidate& candidate); + // Called when a candidate is ready from channel. + void OnChannelCandidateReady(TransportChannelImpl* channel, + const Candidate& candidate); + void OnChannelRouteChange(TransportChannel* channel, + const Candidate& remote_candidate); + 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); + + // These are versions of the above methods that are called only on a + // particular thread (s = signaling, w = worker). The above methods post or + // send a message to invoke this version. + TransportChannelImpl* CreateChannel_w(int component); + void DestroyChannel_w(int component); + void ConnectChannels_w(); + void ResetChannels_w(); + void DestroyAllChannels_w(); + void OnRemoteCandidate_w(const Candidate& candidate); + void OnChannelReadableState_s(); + void OnChannelWritableState_s(); + void OnChannelRequestSignaling_s(int component); + void OnConnecting_s(); + void OnChannelRouteChange_s(const TransportChannel* channel, + const Candidate& remote_candidate); + void OnChannelCandidatesAllocationDone_s(); + + // Helper function that invokes the given function on every channel. + typedef void (TransportChannelImpl::* TransportChannelFunc)(); + void CallChannels_w(TransportChannelFunc func); + + // Computes the OR of the channel's read or write state (argument picks). + TransportState GetTransportState_s(bool read); + + void OnChannelCandidateReady_s(); + + void SetIceRole_w(IceRole role); + void SetRemoteIceMode_w(IceMode mode); + bool SetLocalTransportDescription_w(const TransportDescription& desc, + ContentAction action, + std::string* error_desc); + bool SetRemoteTransportDescription_w(const TransportDescription& desc, + 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_; + std::string content_name_; + std::string type_; + PortAllocator* allocator_; + bool destroyed_; + TransportState readable_; + TransportState writable_; + bool was_writable_; + bool connect_requested_; + IceRole ice_role_; + uint64 tiebreaker_; + TransportProtocol protocol_; + IceMode remote_ice_mode_; + talk_base::scoped_ptr local_description_; + talk_base::scoped_ptr remote_description_; + + ChannelMap channels_; + // Buffers the ready_candidates so that SignalCanidatesReady can + // provide them in multiples. + std::vector ready_candidates_; + // Protects changes to channels and messages + talk_base::CriticalSection crit_; + + DISALLOW_EVIL_CONSTRUCTORS(Transport); +}; + +// Extract a TransportProtocol from a TransportDescription. +TransportProtocol TransportProtocolFromDescription( + const TransportDescription* desc); + +} // namespace cricket + +#endif // TALK_P2P_BASE_TRANSPORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannel.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannel.h new file mode 100644 index 0000000..b3ee89f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannel.h @@ -0,0 +1,160 @@ +/* + * 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 TALK_P2P_BASE_TRANSPORTCHANNEL_H_ +#define TALK_P2P_BASE_TRANSPORTCHANNEL_H_ + +#include +#include + +#include "talk/base/asyncpacketsocket.h" +#include "talk/base/basictypes.h" +#include "talk/base/dscp.h" +#include "talk/base/sigslot.h" +#include "talk/base/socket.h" +#include "talk/base/sslidentity.h" +#include "talk/base/sslstreamadapter.h" +#include "talk/p2p/base/candidate.h" +#include "talk/p2p/base/transport.h" +#include "talk/p2p/base/transportdescription.h" + +namespace cricket { + +class Candidate; + +// Flags for SendPacket/SignalReadPacket. +enum PacketFlags { + PF_NORMAL = 0x00, // A normal packet. + PF_SRTP_BYPASS = 0x01, // An encrypted SRTP packet; bypass any additional + // crypto provided by the transport (e.g. DTLS) +}; + +// A TransportChannel represents one logical stream of packets that are sent +// between the two sides of a session. +class TransportChannel : public sigslot::has_slots<> { + public: + explicit TransportChannel(const std::string& content_name, int component) + : content_name_(content_name), + component_(component), + readable_(false), writable_(false) {} + virtual ~TransportChannel() {} + + // TODO(mallinath) - Remove this API, as it's no longer useful. + // Returns the session id of this channel. + virtual const std::string SessionId() const { return std::string(); } + + const std::string& content_name() const { return content_name_; } + int component() const { return component_; } + + // Returns the readable and states of this channel. Each time one of these + // states changes, a signal is raised. These states are aggregated by the + // TransportManager. + bool readable() const { return readable_; } + bool writable() const { return writable_; } + sigslot::signal1 SignalReadableState; + sigslot::signal1 SignalWritableState; + // Emitted when the TransportChannel's ability to send has changed. + sigslot::signal1 SignalReadyToSend; + + // 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, + const talk_base::PacketOptions& options, + int flags = 0) = 0; + + // Sets a socket option on this channel. Note that not all options are + // supported by all transport types. + virtual int SetOption(talk_base::Socket::Option opt, int value) = 0; + + // Returns the most recent error that occurred on this channel. + virtual int GetError() = 0; + + // Returns the current stats for this connection. + virtual bool GetStats(ConnectionInfos* infos) = 0; + + // Is DTLS active? + virtual bool IsDtlsActive() const = 0; + + // Default implementation. + virtual bool GetSslRole(talk_base::SSLRole* role) const = 0; + + // Sets up the ciphers to use for DTLS-SRTP. + virtual bool SetSrtpCiphers(const std::vector& ciphers) = 0; + + // Finds out which DTLS-SRTP cipher was negotiated + virtual bool GetSrtpCipher(std::string* cipher) = 0; + + // Gets a copy of the local SSL identity, owned by the caller. + virtual bool GetLocalIdentity(talk_base::SSLIdentity** identity) const = 0; + + // Gets a copy of the remote side's SSL certificate, owned by the caller. + virtual bool GetRemoteCertificate(talk_base::SSLCertificate** cert) const = 0; + + // Allows key material to be extracted for external encryption. + virtual bool ExportKeyingMaterial(const std::string& label, + const uint8* context, + size_t context_len, + bool use_context, + uint8* result, + size_t result_len) = 0; + + // Signalled each time a packet is received on this channel. + sigslot::signal5 SignalReadPacket; + + // This signal occurs when there is a change in the way that packets are + // being routed, i.e. to a different remote location. The candidate + // indicates where and how we are currently sending media. + sigslot::signal2 SignalRouteChange; + + // Invoked when the channel is being destroyed. + sigslot::signal1 SignalDestroyed; + + // Debugging description of this transport channel. + std::string ToString() const; + + protected: + // Sets the readable state, signaling if necessary. + void set_readable(bool readable); + + // Sets the writable state, signaling if necessary. + void set_writable(bool writable); + + + private: + // Used mostly for debugging. + std::string content_name_; + int component_; + bool readable_; + bool writable_; + + DISALLOW_EVIL_CONSTRUCTORS(TransportChannel); +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TRANSPORTCHANNEL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannelimpl.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannelimpl.h new file mode 100644 index 0000000..9802f21 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannelimpl.h @@ -0,0 +1,128 @@ +/* + * 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 TALK_P2P_BASE_TRANSPORTCHANNELIMPL_H_ +#define TALK_P2P_BASE_TRANSPORTCHANNELIMPL_H_ + +#include +#include "talk/p2p/base/transport.h" +#include "talk/p2p/base/transportchannel.h" + +namespace buzz { class XmlElement; } + +namespace cricket { + +class Candidate; + +// Base class for real implementations of TransportChannel. This includes some +// methods called only by Transport, which do not need to be exposed to the +// client. +class TransportChannelImpl : public TransportChannel { + public: + explicit TransportChannelImpl(const std::string& content_name, int component) + : TransportChannel(content_name, component) {} + + // Returns the transport that created this channel. + virtual Transport* GetTransport() = 0; + + // For ICE channels. + 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. + // The ufrag and pwd should be set before the Connect() is called. + virtual void SetIceCredentials(const std::string& ice_ufrag, + const std::string& ice_pwd) = 0; + // SetRemoteIceCredentials only need to be implemented by the ICE + // transport channels. Non-ICE transport channels can just ignore. + virtual void SetRemoteIceCredentials(const std::string& ice_ufrag, + const std::string& ice_pwd) = 0; + + // SetRemoteIceMode must be implemented only by the ICE transport channels. + virtual void SetRemoteIceMode(IceMode mode) = 0; + + // Begins the process of attempting to make a connection to the other client. + virtual void Connect() = 0; + + // Resets this channel back to the initial state (i.e., not connecting). + virtual void Reset() = 0; + + // Allows an individual channel to request signaling and be notified when it + // is ready. This is useful if the individual named channels have need to + // send their own transport-info stanzas. + sigslot::signal1 SignalRequestSignaling; + virtual void OnSignalingReady() = 0; + + // Handles sending and receiving of candidates. The Transport + // receives the candidates and may forward them to the relevant + // channel. + // + // Note: Since candidates are delivered asynchronously to the + // channel, they cannot return an error if the message is invalid. + // It is assumed that the Transport will have checked validity + // before forwarding. + sigslot::signal2 SignalCandidateReady; + virtual void OnCandidate(const Candidate& candidate) = 0; + + // DTLS methods + // Set DTLS local identity. The identity object is not copied, but the caller + // retains ownership and must delete it after this TransportChannelImpl is + // destroyed. + // TODO(bemasc): Fix the ownership semantics of this method. + virtual bool SetLocalIdentity(talk_base::SSLIdentity* identity) = 0; + + // Set DTLS Remote fingerprint. Must be after local identity set. + virtual bool SetRemoteFingerprint(const std::string& digest_alg, + const uint8* digest, + size_t digest_len) = 0; + + virtual bool SetSslRole(talk_base::SSLRole role) = 0; + + // TransportChannel is forwarding this signal from PortAllocatorSession. + sigslot::signal1 SignalCandidatesAllocationDone; + + // Invoked when there is conflict in the ICE role between local and remote + // agents. + sigslot::signal1 SignalRoleConflict; + + // Emitted whenever the number of connections available to the transport + // channel decreases. + sigslot::signal1 SignalConnectionRemoved; + + private: + DISALLOW_EVIL_CONSTRUCTORS(TransportChannelImpl); +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TRANSPORTCHANNELIMPL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannelproxy.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannelproxy.h new file mode 100644 index 0000000..46c6c00 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportchannelproxy.h @@ -0,0 +1,112 @@ +/* + * 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 TALK_P2P_BASE_TRANSPORTCHANNELPROXY_H_ +#define TALK_P2P_BASE_TRANSPORTCHANNELPROXY_H_ + +#include +#include +#include + +#include "talk/base/messagehandler.h" +#include "talk/p2p/base/transportchannel.h" + +namespace talk_base { +class Thread; +} + +namespace cricket { + +class TransportChannelImpl; + +// Proxies calls between the client and the transport channel implementation. +// This is needed because clients are allowed to create channels before the +// network negotiation is complete. Hence, we create a proxy up front, and +// when negotiation completes, connect the proxy to the implementaiton. +class TransportChannelProxy : public TransportChannel, + public talk_base::MessageHandler { + public: + TransportChannelProxy(const std::string& content_name, + const std::string& name, + int component); + virtual ~TransportChannelProxy(); + + const std::string& name() const { return name_; } + TransportChannelImpl* impl() { return impl_; } + + // Sets the implementation to which we will proxy. + void SetImplementation(TransportChannelImpl* impl); + + // Implementation of the TransportChannel interface. These simply forward to + // the implementation. + virtual int SendPacket(const char* data, size_t len, + const talk_base::PacketOptions& options, + int flags); + virtual int SetOption(talk_base::Socket::Option opt, int value); + virtual int GetError(); + virtual IceRole GetIceRole() const; + virtual bool GetStats(ConnectionInfos* infos); + virtual bool IsDtlsActive() const; + virtual bool GetSslRole(talk_base::SSLRole* role) const; + virtual bool SetSslRole(talk_base::SSLRole role); + virtual bool SetSrtpCiphers(const std::vector& ciphers); + virtual bool GetSrtpCipher(std::string* cipher); + virtual bool GetLocalIdentity(talk_base::SSLIdentity** identity) const; + virtual bool GetRemoteCertificate(talk_base::SSLCertificate** cert) const; + virtual bool ExportKeyingMaterial(const std::string& label, + const uint8* context, + size_t context_len, + bool use_context, + uint8* result, + size_t result_len); + + private: + // Catch signals from the implementation channel. These just forward to the + // client (after updating our state to match). + void OnReadableState(TransportChannel* channel); + void OnWritableState(TransportChannel* channel); + void OnReadPacket(TransportChannel* channel, const char* data, size_t size, + const talk_base::PacketTime& packet_time, int flags); + void OnReadyToSend(TransportChannel* channel); + void OnRouteChange(TransportChannel* channel, const Candidate& candidate); + + void OnMessage(talk_base::Message* message); + + typedef std::pair OptionPair; + typedef std::vector OptionList; + std::string name_; + talk_base::Thread* worker_thread_; + TransportChannelImpl* impl_; + OptionList pending_options_; + std::vector pending_srtp_ciphers_; + + DISALLOW_EVIL_CONSTRUCTORS(TransportChannelProxy); +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TRANSPORTCHANNELPROXY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportdescription.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportdescription.h new file mode 100644 index 0000000..7a8ad1f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportdescription.h @@ -0,0 +1,186 @@ +/* + * libjingle + * Copyright 2012, The Libjingle Authors. + * + * 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_P2P_BASE_TRANSPORTDESCRIPTION_H_ +#define TALK_P2P_BASE_TRANSPORTDESCRIPTION_H_ + +#include +#include +#include + +#include "talk/base/scoped_ptr.h" +#include "talk/base/sslfingerprint.h" +#include "talk/p2p/base/candidate.h" +#include "talk/p2p/base/constants.h" + +namespace cricket { + +// SEC_ENABLED and SEC_REQUIRED should only be used if the session +// was negotiated over TLS, to protect the inline crypto material +// exchange. +// SEC_DISABLED: No crypto in outgoing offer, ignore any supplied crypto. +// SEC_ENABLED: Crypto in outgoing offer and answer (if supplied in offer). +// SEC_REQUIRED: Crypto in outgoing offer and answer. Fail any offer with absent +// or unsupported crypto. +enum SecurePolicy { + SEC_DISABLED, + SEC_ENABLED, + SEC_REQUIRED +}; + +// The transport protocol we've elected to use. +enum TransportProtocol { + ICEPROTO_GOOGLE, // Google version of ICE protocol. + ICEPROTO_HYBRID, // ICE, but can fall back to the Google version. + ICEPROTO_RFC5245 // Standard RFC 5245 version of ICE. +}; +// The old name for TransportProtocol. +// TODO(juberti): remove this. +typedef TransportProtocol IceProtocolType; + +// Whether our side of the call is driving the negotiation, or the other side. +enum IceRole { + ICEROLE_CONTROLLING = 0, + ICEROLE_CONTROLLED, + ICEROLE_UNKNOWN +}; + +// ICE RFC 5245 implementation type. +enum IceMode { + ICEMODE_FULL, // As defined in http://tools.ietf.org/html/rfc5245#section-4.1 + ICEMODE_LITE // As defined in http://tools.ietf.org/html/rfc5245#section-4.2 +}; + +// RFC 4145 - http://tools.ietf.org/html/rfc4145#section-4 +// 'active': The endpoint will initiate an outgoing connection. +// 'passive': The endpoint will accept an incoming connection. +// 'actpass': The endpoint is willing to accept an incoming +// connection or to initiate an outgoing connection. +enum ConnectionRole { + CONNECTIONROLE_NONE = 0, + CONNECTIONROLE_ACTIVE, + CONNECTIONROLE_PASSIVE, + CONNECTIONROLE_ACTPASS, + CONNECTIONROLE_HOLDCONN, +}; + +extern const char CONNECTIONROLE_ACTIVE_STR[]; +extern const char CONNECTIONROLE_PASSIVE_STR[]; +extern const char CONNECTIONROLE_ACTPASS_STR[]; +extern const char CONNECTIONROLE_HOLDCONN_STR[]; + +bool StringToConnectionRole(const std::string& role_str, ConnectionRole* role); +bool ConnectionRoleToString(const ConnectionRole& role, std::string* role_str); + +typedef std::vector Candidates; + +struct TransportDescription { + TransportDescription() : ice_mode(ICEMODE_FULL) {} + + TransportDescription(const std::string& transport_type, + const std::vector& transport_options, + const std::string& ice_ufrag, + const std::string& ice_pwd, + IceMode ice_mode, + ConnectionRole role, + const talk_base::SSLFingerprint* identity_fingerprint, + const Candidates& candidates) + : transport_type(transport_type), + transport_options(transport_options), + ice_ufrag(ice_ufrag), + ice_pwd(ice_pwd), + ice_mode(ice_mode), + connection_role(role), + identity_fingerprint(CopyFingerprint(identity_fingerprint)), + candidates(candidates) {} + TransportDescription(const std::string& transport_type, + const std::string& ice_ufrag, + const std::string& ice_pwd) + : transport_type(transport_type), + ice_ufrag(ice_ufrag), + ice_pwd(ice_pwd), + ice_mode(ICEMODE_FULL), + connection_role(CONNECTIONROLE_NONE) {} + TransportDescription(const TransportDescription& from) + : transport_type(from.transport_type), + transport_options(from.transport_options), + ice_ufrag(from.ice_ufrag), + ice_pwd(from.ice_pwd), + ice_mode(from.ice_mode), + connection_role(from.connection_role), + identity_fingerprint(CopyFingerprint(from.identity_fingerprint.get())), + candidates(from.candidates) {} + + TransportDescription& operator=(const TransportDescription& from) { + // Self-assignment + if (this == &from) + return *this; + + transport_type = from.transport_type; + transport_options = from.transport_options; + ice_ufrag = from.ice_ufrag; + ice_pwd = from.ice_pwd; + ice_mode = from.ice_mode; + connection_role = from.connection_role; + + identity_fingerprint.reset(CopyFingerprint( + from.identity_fingerprint.get())); + candidates = from.candidates; + return *this; + } + + bool HasOption(const std::string& option) const { + return (std::find(transport_options.begin(), transport_options.end(), + option) != transport_options.end()); + } + void AddOption(const std::string& option) { + transport_options.push_back(option); + } + bool secure() const { return identity_fingerprint != NULL; } + + static talk_base::SSLFingerprint* CopyFingerprint( + const talk_base::SSLFingerprint* from) { + if (!from) + return NULL; + + return new talk_base::SSLFingerprint(*from); + } + + std::string transport_type; // xmlns of + std::vector transport_options; + std::string ice_ufrag; + std::string ice_pwd; + IceMode ice_mode; + ConnectionRole connection_role; + + talk_base::scoped_ptr identity_fingerprint; + Candidates candidates; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TRANSPORTDESCRIPTION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportdescriptionfactory.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportdescriptionfactory.h new file mode 100644 index 0000000..98ab93a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportdescriptionfactory.h @@ -0,0 +1,83 @@ +/* + * libjingle + * Copyright 2012 Google Inc. All rights reserved. + * + * 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_P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_ +#define TALK_P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_ + +#include "talk/p2p/base/transportdescription.h" + +namespace talk_base { +class SSLIdentity; +} + +namespace cricket { + +struct TransportOptions { + TransportOptions() : ice_restart(false), prefer_passive_role(false) {} + bool ice_restart; + bool prefer_passive_role; +}; + +// Creates transport descriptions according to the supplied configuration. +// When creating answers, performs the appropriate negotiation +// of the various fields to determine the proper result. +class TransportDescriptionFactory { + public: + // Default ctor; use methods below to set configuration. + TransportDescriptionFactory(); + SecurePolicy secure() const { return secure_; } + // The identity to use when setting up DTLS. + talk_base::SSLIdentity* identity() const { return identity_; } + + // Specifies the transport protocol to be use. + void set_protocol(TransportProtocol protocol) { protocol_ = protocol; } + // Specifies the transport security policy to use. + void set_secure(SecurePolicy s) { secure_ = s; } + // Specifies the identity to use (only used when secure is not SEC_DISABLED). + void set_identity(talk_base::SSLIdentity* identity) { identity_ = identity; } + + // Creates a transport description suitable for use in an offer. + TransportDescription* CreateOffer(const TransportOptions& options, + const TransportDescription* current_description) const; + // Create a transport description that is a response to an offer. + TransportDescription* CreateAnswer( + const TransportDescription* offer, + const TransportOptions& options, + const TransportDescription* current_description) const; + + private: + bool SetSecurityInfo(TransportDescription* description, + ConnectionRole role) const; + + TransportProtocol protocol_; + SecurePolicy secure_; + talk_base::SSLIdentity* identity_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportinfo.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportinfo.h new file mode 100644 index 0000000..f72552d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/transportinfo.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_TRANSPORTINFO_H_ +#define TALK_P2P_BASE_TRANSPORTINFO_H_ + +#include +#include + +#include "talk/base/helpers.h" +#include "talk/p2p/base/candidate.h" +#include "talk/p2p/base/constants.h" +#include "talk/p2p/base/transportdescription.h" + +namespace cricket { + +// A TransportInfo is NOT a transport-info message. It is comparable +// to a "ContentInfo". A transport-infos message is basically just a +// collection of TransportInfos. +struct TransportInfo { + TransportInfo() {} + + TransportInfo(const std::string& content_name, + const TransportDescription& description) + : content_name(content_name), + description(description) {} + + std::string content_name; + TransportDescription description; +}; + +typedef std::vector TransportInfos; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TRANSPORTINFO_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/turnport.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/turnport.h new file mode 100644 index 0000000..5ff0e32 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/turnport.h @@ -0,0 +1,225 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_TURNPORT_H_ +#define TALK_P2P_BASE_TURNPORT_H_ + +#include +#include +#include + +#include "talk/base/asyncpacketsocket.h" +#include "talk/p2p/base/port.h" +#include "talk/p2p/client/basicportallocator.h" + +namespace talk_base { +class AsyncResolver; +class SignalThread; +} + +namespace cricket { + +extern const char TURN_PORT_TYPE[]; +class TurnAllocateRequest; +class TurnEntry; + +class TurnPort : public Port { + public: + 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. + const std::string& password, // ice password. + const ProtocolAddress& server_address, + const RelayCredentials& credentials) { + return new TurnPort(thread, factory, network, ip, min_port, max_port, + username, password, server_address, credentials); + } + + virtual ~TurnPort(); + + const ProtocolAddress& server_address() const { return server_address_; } + + bool connected() const { return connected_; } + const RelayCredentials& credentials() const { return credentials_; } + + virtual void PrepareAddress(); + virtual Connection* CreateConnection( + const Candidate& c, PortInterface::CandidateOrigin origin); + virtual int SendTo(const void* data, size_t size, + const talk_base::SocketAddress& addr, + 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 bool HandleIncomingPacket( + talk_base::AsyncPacketSocket* socket, const char* data, size_t size, + const talk_base::SocketAddress& remote_addr, + 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); + void OnSocketClose(talk_base::AsyncPacketSocket* socket, int error); + + + 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 SignalResolvedServerAddress; + + // This signal is only for testing purpose. + sigslot::signal3 + SignalCreatePermissionResult; + + protected: + 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, + const std::string& password, + const ProtocolAddress& server_address, + const RelayCredentials& credentials); + + private: + enum { MSG_ERROR = MSG_FIRST_AVAILABLE }; + + typedef std::list EntryList; + typedef std::map SocketOptionsMap; + + virtual void OnMessage(talk_base::Message* pmsg); + + void set_nonce(const std::string& nonce) { nonce_ = nonce; } + void set_realm(const std::string& realm) { + if (realm != realm_) { + realm_ = realm; + UpdateHash(); + } + } + + void ResolveTurnAddress(const talk_base::SocketAddress& address); + void OnResolveResult(talk_base::AsyncResolverInterface* resolver); + + void AddRequestAuthInfo(StunMessage* msg); + void OnSendStunPacket(const void* data, size_t size, StunRequest* request); + // 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, + const talk_base::SocketAddress& stun_address); + void OnAllocateError(); + void OnAllocateRequestTimeout(); + + void HandleDataIndication(const char* data, size_t size, + const talk_base::PacketTime& packet_time); + void HandleChannelData(int channel_id, const char* data, size_t size, + const talk_base::PacketTime& packet_time); + void DispatchPacket(const char* data, size_t size, + const talk_base::SocketAddress& remote_addr, + ProtocolType proto, const talk_base::PacketTime& packet_time); + + bool ScheduleRefresh(int lifetime); + void SendRequest(StunRequest* request, int delay); + int Send(const void* data, size_t size, + const talk_base::PacketOptions& options); + void UpdateHash(); + bool UpdateNonce(StunMessage* response); + + bool HasPermission(const talk_base::IPAddress& ipaddr) const; + TurnEntry* FindEntry(const talk_base::SocketAddress& address) const; + TurnEntry* FindEntry(int channel_id) const; + TurnEntry* CreateEntry(const talk_base::SocketAddress& address); + void DestroyEntry(const talk_base::SocketAddress& address); + void OnConnectionDestroyed(Connection* conn); + + ProtocolAddress server_address_; + RelayCredentials credentials_; + + talk_base::AsyncPacketSocket* socket_; + SocketOptionsMap socket_options_; + talk_base::AsyncResolverInterface* resolver_; + int error_; + + StunRequestManager request_manager_; + std::string realm_; // From 401/438 response message. + std::string nonce_; // From 401/438 response message. + std::string hash_; // Digest of username:realm:password + + int next_channel_number_; + EntryList entries_; + + bool connected_; + + friend class TurnEntry; + friend class TurnAllocateRequest; + friend class TurnRefreshRequest; + friend class TurnCreatePermissionRequest; + friend class TurnChannelBindRequest; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TURNPORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/turnserver.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/turnserver.h new file mode 100644 index 0000000..74c460f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/turnserver.h @@ -0,0 +1,187 @@ +/* + * 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. + */ + +#ifndef TALK_P2P_BASE_TURNSERVER_H_ +#define TALK_P2P_BASE_TURNSERVER_H_ + +#include +#include +#include +#include + +#include "talk/base/asyncpacketsocket.h" +#include "talk/base/messagequeue.h" +#include "talk/base/sigslot.h" +#include "talk/base/socketaddress.h" +#include "talk/p2p/base/portinterface.h" + +namespace talk_base { +class ByteBuffer; +class PacketSocketFactory; +class Thread; +} + +namespace cricket { + +class StunMessage; +class TurnMessage; + +// The default server port for TURN, as specified in RFC5766. +const int TURN_SERVER_PORT = 3478; + +// An interface through which the MD5 credential hash can be retrieved. +class TurnAuthInterface { + public: + // Gets HA1 for the specified user and realm. + // HA1 = MD5(A1) = MD5(username:realm:password). + // Return true if the given username and realm are valid, or false if not. + virtual bool GetKey(const std::string& username, const std::string& realm, + std::string* key) = 0; +}; + +// The core TURN server class. Give it a socket to listen on via +// AddInternalServerSocket, and a factory to create external sockets via +// SetExternalSocketFactory, and it's ready to go. +// Not yet wired up: TCP support. +class TurnServer : public sigslot::has_slots<> { + public: + explicit TurnServer(talk_base::Thread* thread); + ~TurnServer(); + + // Gets/sets the realm value to use for the server. + const std::string& realm() const { return realm_; } + void set_realm(const std::string& realm) { realm_ = realm; } + + // Gets/sets the value for the SOFTWARE attribute for TURN messages. + const std::string& software() const { return software_; } + void set_software(const std::string& software) { software_ = software; } + + // Sets the authentication callback; does not take ownership. + void set_auth_hook(TurnAuthInterface* auth_hook) { auth_hook_ = auth_hook; } + + void set_enable_otu_nonce(bool enable) { enable_otu_nonce_ = enable; } + + // Starts listening for packets from internal clients. + void AddInternalSocket(talk_base::AsyncPacketSocket* socket, + ProtocolType proto); + // Starts listening for the connections on this socket. When someone tries + // to connect, the connection will be accepted and a new internal socket + // will be added. + void AddInternalServerSocket(talk_base::AsyncSocket* socket, + ProtocolType proto); + // Specifies the factory to use for creating external sockets. + void SetExternalSocketFactory(talk_base::PacketSocketFactory* factory, + const talk_base::SocketAddress& address); + + private: + // Encapsulates the client's connection to the server. + class Connection { + public: + Connection() : proto_(PROTO_UDP), socket_(NULL) {} + Connection(const talk_base::SocketAddress& src, + ProtocolType proto, + talk_base::AsyncPacketSocket* socket); + const talk_base::SocketAddress& src() const { return src_; } + talk_base::AsyncPacketSocket* socket() { return socket_; } + bool operator==(const Connection& t) const; + bool operator<(const Connection& t) const; + std::string ToString() const; + + private: + talk_base::SocketAddress src_; + talk_base::SocketAddress dst_; + cricket::ProtocolType proto_; + talk_base::AsyncPacketSocket* socket_; + }; + class Allocation; + class Permission; + class Channel; + typedef std::map AllocationMap; + + void OnInternalPacket(talk_base::AsyncPacketSocket* socket, const char* data, + size_t size, const talk_base::SocketAddress& address, + const talk_base::PacketTime& packet_time); + + void OnNewInternalConnection(talk_base::AsyncSocket* socket); + + // Accept connections on this server socket. + void AcceptConnection(talk_base::AsyncSocket* server_socket); + void OnInternalSocketClose(talk_base::AsyncPacketSocket* socket, int err); + + void HandleStunMessage(Connection* conn, const char* data, size_t size); + void HandleBindingRequest(Connection* conn, const StunMessage* msg); + void HandleAllocateRequest(Connection* conn, const TurnMessage* msg, + const std::string& key); + + bool GetKey(const StunMessage* msg, std::string* key); + bool CheckAuthorization(Connection* conn, const StunMessage* msg, + const char* data, size_t size, + const std::string& key); + std::string GenerateNonce() const; + bool ValidateNonce(const std::string& nonce) const; + + Allocation* FindAllocation(Connection* conn); + Allocation* CreateAllocation(Connection* conn, int proto, + const std::string& key); + + void SendErrorResponse(Connection* conn, const StunMessage* req, + int code, const std::string& reason); + + void SendErrorResponseWithRealmAndNonce(Connection* conn, + const StunMessage* req, + int code, + const std::string& reason); + void SendStun(Connection* conn, StunMessage* msg); + void Send(Connection* conn, const talk_base::ByteBuffer& buf); + + void OnAllocationDestroyed(Allocation* allocation); + void DestroyInternalSocket(talk_base::AsyncPacketSocket* socket); + + typedef std::map InternalSocketMap; + typedef std::map ServerSocketMap; + + talk_base::Thread* thread_; + std::string nonce_key_; + std::string realm_; + std::string software_; + TurnAuthInterface* auth_hook_; + // otu - one-time-use. Server will respond with 438 if it's + // sees the same nonce in next transaction. + bool enable_otu_nonce_; + InternalSocketMap server_sockets_; + ServerSocketMap server_listen_sockets_; + talk_base::scoped_ptr + external_socket_factory_; + talk_base::SocketAddress external_addr_; + AllocationMap allocations_; +}; + +} // namespace cricket + +#endif // TALK_P2P_BASE_TURNSERVER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/base/udpport.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/udpport.h new file mode 100644 index 0000000..a291a78 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/base/udpport.h @@ -0,0 +1,34 @@ +/* + * 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 TALK_P2P_BASE_UDPPORT_H_ +#define TALK_P2P_BASE_UDPPORT_H_ + +// StunPort will be handling UDPPort functionality. +#include "talk/p2p/base/stunport.h" + +#endif // TALK_P2P_BASE_UDPPORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/client/autoportallocator.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/autoportallocator.h new file mode 100644 index 0000000..4345d1d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/autoportallocator.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#ifndef TALK_EXAMPLES_LOGIN_AUTOPORTALLOCATOR_H_ +#define TALK_EXAMPLES_LOGIN_AUTOPORTALLOCATOR_H_ + +#include +#include + +#include "talk/base/sigslot.h" +#include "talk/p2p/client/httpportallocator.h" +#include "talk/xmpp/jingleinfotask.h" +#include "talk/xmpp/xmppclient.h" + +// This class sets the relay and stun servers using XmppClient. +// It enables the client to traverse Proxy and NAT. +class AutoPortAllocator : public cricket::HttpPortAllocator { + public: + AutoPortAllocator(talk_base::NetworkManager* network_manager, + const std::string& user_agent) + : cricket::HttpPortAllocator(network_manager, user_agent) { + } + + // Creates and initiates a task to get relay token from XmppClient and set + // it appropriately. + void SetXmppClient(buzz::XmppClient* client) { + // The JingleInfoTask is freed by the task-runner. + buzz::JingleInfoTask* jit = new buzz::JingleInfoTask(client); + jit->SignalJingleInfo.connect(this, &AutoPortAllocator::OnJingleInfo); + jit->Start(); + jit->RefreshJingleInfoNow(); + } + + private: + void OnJingleInfo( + const std::string& token, + const std::vector& relay_hosts, + const std::vector& stun_hosts) { + SetRelayToken(token); + SetStunHosts(stun_hosts); + SetRelayHosts(relay_hosts); + } +}; + +#endif // TALK_EXAMPLES_LOGIN_AUTOPORTALLOCATOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/client/basicportallocator.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/basicportallocator.h new file mode 100644 index 0000000..1116936 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/basicportallocator.h @@ -0,0 +1,246 @@ +/* + * 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 TALK_P2P_CLIENT_BASICPORTALLOCATOR_H_ +#define TALK_P2P_CLIENT_BASICPORTALLOCATOR_H_ + +#include +#include + +#include "talk/base/messagequeue.h" +#include "talk/base/network.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/thread.h" +#include "talk/p2p/base/port.h" +#include "talk/p2p/base/portallocator.h" + +namespace cricket { + +struct RelayCredentials { + RelayCredentials() {} + RelayCredentials(const std::string& username, + const std::string& password) + : username(username), + password(password) { + } + + std::string username; + std::string password; +}; + +typedef std::vector PortList; +struct RelayServerConfig { + RelayServerConfig(RelayType type) : type(type) {} + + RelayType type; + PortList ports; + RelayCredentials credentials; +}; + +class BasicPortAllocator : public PortAllocator { + public: + BasicPortAllocator(talk_base::NetworkManager* network_manager, + talk_base::PacketSocketFactory* socket_factory); + explicit BasicPortAllocator(talk_base::NetworkManager* network_manager); + BasicPortAllocator(talk_base::NetworkManager* network_manager, + talk_base::PacketSocketFactory* socket_factory, + const talk_base::SocketAddress& stun_server); + BasicPortAllocator(talk_base::NetworkManager* network_manager, + const talk_base::SocketAddress& stun_server, + const talk_base::SocketAddress& relay_server_udp, + const talk_base::SocketAddress& relay_server_tcp, + const talk_base::SocketAddress& relay_server_ssl); + virtual ~BasicPortAllocator(); + + talk_base::NetworkManager* network_manager() { return network_manager_; } + + // If socket_factory() is set to NULL each PortAllocatorSession + // creates its own socket factory. + talk_base::PacketSocketFactory* socket_factory() { return socket_factory_; } + + const talk_base::SocketAddress& stun_address() const { + return stun_address_; + } + + const std::vector& relays() const { + return relays_; + } + virtual void AddRelay(const RelayServerConfig& relay) { + relays_.push_back(relay); + } + + virtual PortAllocatorSession* CreateSessionInternal( + const std::string& content_name, + int component, + const std::string& ice_ufrag, + const std::string& ice_pwd); + + private: + void Construct(); + + talk_base::NetworkManager* network_manager_; + talk_base::PacketSocketFactory* socket_factory_; + const talk_base::SocketAddress stun_address_; + std::vector relays_; + bool allow_tcp_listen_; +}; + +struct PortConfiguration; +class AllocationSequence; + +class BasicPortAllocatorSession : public PortAllocatorSession, + public talk_base::MessageHandler { + public: + BasicPortAllocatorSession(BasicPortAllocator* allocator, + const std::string& content_name, + int component, + const std::string& ice_ufrag, + const std::string& ice_pwd); + ~BasicPortAllocatorSession(); + + virtual BasicPortAllocator* allocator() { return allocator_; } + talk_base::Thread* network_thread() { return network_thread_; } + talk_base::PacketSocketFactory* socket_factory() { return socket_factory_; } + + virtual void StartGettingPorts(); + virtual void StopGettingPorts(); + virtual bool IsGettingPorts() { return running_; } + + protected: + // Starts the process of getting the port configurations. + virtual void GetPortConfigurations(); + + // Adds a port configuration that is now ready. Once we have one for each + // network (or a timeout occurs), we will start allocating ports. + virtual void ConfigReady(PortConfiguration* config); + + // MessageHandler. Can be overriden if message IDs do not conflict. + virtual void OnMessage(talk_base::Message *message); + + private: + class PortData { + public: + PortData() : port_(NULL), sequence_(NULL), state_(STATE_INIT) {} + PortData(Port* port, AllocationSequence* seq) + : port_(port), sequence_(seq), state_(STATE_INIT) { + } + + Port* port() { return port_; } + AllocationSequence* sequence() { return sequence_; } + bool ready() const { return state_ == STATE_READY; } + bool complete() const { + // Returns true if candidate allocation has completed one way or another. + return ((state_ == STATE_COMPLETE) || (state_ == STATE_ERROR)); + } + + void set_ready() { ASSERT(state_ == STATE_INIT); state_ = STATE_READY; } + void set_complete() { + ASSERT(state_ == STATE_READY); + state_ = STATE_COMPLETE; + } + void set_error() { + ASSERT(state_ == STATE_INIT || state_ == STATE_READY); + state_ = STATE_ERROR; + } + + private: + enum State { + STATE_INIT, // No candidates allocated yet. + STATE_READY, // At least one candidate is ready for process. + STATE_COMPLETE, // All candidates allocated and ready for process. + STATE_ERROR // Error in gathering candidates. + }; + Port* port_; + AllocationSequence* sequence_; + State state_; + }; + + void OnConfigReady(PortConfiguration* config); + void OnConfigStop(); + void AllocatePorts(); + void OnAllocate(); + void DoAllocate(); + void OnNetworksChanged(); + void OnAllocationSequenceObjectsCreated(); + void DisableEquivalentPhases(talk_base::Network* network, + PortConfiguration* config, uint32* flags); + void AddAllocatedPort(Port* port, AllocationSequence* seq, + bool prepare_address); + void OnCandidateReady(Port* port, const Candidate& c); + void OnPortComplete(Port* port); + void OnPortError(Port* port); + void OnProtocolEnabled(AllocationSequence* seq, ProtocolType proto); + void OnPortDestroyed(PortInterface* port); + void OnShake(); + void MaybeSignalCandidatesAllocationDone(); + void OnPortAllocationComplete(AllocationSequence* seq); + PortData* FindPort(Port* port); + + BasicPortAllocator* allocator_; + talk_base::Thread* network_thread_; + talk_base::scoped_ptr owned_socket_factory_; + talk_base::PacketSocketFactory* socket_factory_; + bool allocation_started_; + bool network_manager_started_; + bool running_; // set when StartGetAllPorts is called + bool allocation_sequences_created_; + std::vector configs_; + std::vector sequences_; + std::vector ports_; + + friend class AllocationSequence; +}; + +// Records configuration information useful in creating ports. +struct PortConfiguration : public talk_base::MessageData { + talk_base::SocketAddress stun_address; + std::string username; + std::string password; + + typedef std::vector RelayList; + RelayList relays; + + PortConfiguration(const talk_base::SocketAddress& stun_address, + const std::string& username, + const std::string& password); + + // Adds another relay server, with the given ports and modifier, to the list. + void AddRelay(const RelayServerConfig& config); + + // Determines whether the given relay server supports the given protocol. + 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 + +#endif // TALK_P2P_CLIENT_BASICPORTALLOCATOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/client/connectivitychecker.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/connectivitychecker.h new file mode 100644 index 0000000..c4e8d0d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/connectivitychecker.h @@ -0,0 +1,274 @@ +// Copyright 2011 Google Inc. All Rights Reserved. + + +#ifndef TALK_P2P_CLIENT_CONNECTIVITYCHECKER_H_ +#define TALK_P2P_CLIENT_CONNECTIVITYCHECKER_H_ + +#include +#include + +#include "talk/base/network.h" +#include "talk/base/basictypes.h" +#include "talk/base/messagehandler.h" +#include "talk/base/proxyinfo.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sigslot.h" +#include "talk/base/socketaddress.h" +#include "talk/p2p/base/basicpacketsocketfactory.h" +#include "talk/p2p/client/httpportallocator.h" + +namespace talk_base { +class AsyncHttpRequest; +class AutoDetectProxy; +class BasicPacketSocketFactory; +class NetworkManager; +class PacketSocketFactory; +class SignalThread; +class TestHttpPortAllocatorSession; +class Thread; +} + +namespace cricket { +class HttpPortAllocator; +class Port; +class PortAllocatorSession; +struct PortConfiguration; +class RelayPort; +class StunPort; + +// Contains details about a discovered firewall that are of interest +// when debugging call failures. +struct FirewallInfo { + std::string brand; + std::string model; + + // TODO: List of current port mappings. +}; + +// Contains details about a specific connect attempt. +struct ConnectInfo { + ConnectInfo() + : rtt(-1), error(0) {} + // Time when the connection was initiated. Needed for calculating + // the round trip time. + uint32 start_time_ms; + // Round trip time in milliseconds or -1 for failed connection. + int32 rtt; + // Error code representing low level errors like socket errors. + int error; +}; + +// Identifier for a network interface and proxy address pair. +struct NicId { + NicId(const talk_base::IPAddress& ip, + const talk_base::SocketAddress& proxy_address) + : ip(ip), + proxy_address(proxy_address) { + } + talk_base::IPAddress ip; + talk_base::SocketAddress proxy_address; +}; + +// Comparator implementation identifying unique network interface and +// proxy address pairs. +class NicIdComparator { + public: + int compare(const NicId &first, const NicId &second) const { + if (first.ip == second.ip) { + // Compare proxy address. + if (first.proxy_address == second.proxy_address) { + return 0; + } else { + return first.proxy_address < second.proxy_address? -1 : 1; + } + } + return first.ip < second.ip ? -1 : 1; + } + + bool operator()(const NicId &first, const NicId &second) const { + return (compare(first, second) < 0); + } +}; + +// Contains information of a network interface and proxy address pair. +struct NicInfo { + NicInfo() {} + talk_base::IPAddress ip; + talk_base::ProxyInfo proxy_info; + talk_base::SocketAddress external_address; + talk_base::SocketAddress stun_server_address; + talk_base::SocketAddress media_server_address; + ConnectInfo stun; + ConnectInfo http; + ConnectInfo https; + ConnectInfo udp; + ConnectInfo tcp; + ConnectInfo ssltcp; + FirewallInfo firewall; +}; + +// Holds the result of the connectivity check. +class NicMap : public std::map { +}; + +class TestHttpPortAllocatorSession : public HttpPortAllocatorSession { + public: + TestHttpPortAllocatorSession( + HttpPortAllocator* allocator, + const std::string& content_name, + int component, + const std::string& ice_ufrag, + const std::string& ice_pwd, + const std::vector& stun_hosts, + const std::vector& relay_hosts, + const std::string& relay_token, + const std::string& user_agent) + : HttpPortAllocatorSession( + allocator, content_name, component, ice_ufrag, ice_pwd, stun_hosts, + relay_hosts, relay_token, user_agent) { + } + void set_proxy(const talk_base::ProxyInfo& proxy) { + proxy_ = proxy; + } + + void ConfigReady(PortConfiguration* config); + + void OnRequestDone(talk_base::SignalThread* data); + + sigslot::signal4 SignalConfigReady; + sigslot::signal1 SignalRequestDone; + + private: + talk_base::ProxyInfo proxy_; +}; + +// Runs a request/response check on all network interface and proxy +// address combinations. The check is considered done either when all +// checks has been successful or when the check times out. +class ConnectivityChecker + : public talk_base::MessageHandler, public sigslot::has_slots<> { + public: + ConnectivityChecker(talk_base::Thread* worker, + const std::string& jid, + const std::string& session_id, + const std::string& user_agent, + const std::string& relay_token, + const std::string& connection); + virtual ~ConnectivityChecker(); + + // Virtual for gMock. + virtual bool Initialize(); + virtual void Start(); + + // MessageHandler implementation. + virtual void OnMessage(talk_base::Message *msg); + + // Instruct checker to stop and wait until that's done. + // Virtual for gMock. + virtual void Stop() { + worker_->Stop(); + } + + const NicMap& GetResults() const { + return nics_; + } + + void set_timeout_ms(uint32 timeout) { + timeout_ms_ = timeout; + } + + void set_stun_address(const talk_base::SocketAddress& stun_address) { + stun_address_ = stun_address; + } + + const std::string& connection() const { + return connection_; + } + + const std::string& jid() const { + return jid_; + } + + const std::string& session_id() const { + return session_id_; + } + + // Context: Main Thread. Signalled when the connectivity check is complete. + sigslot::signal1 SignalCheckDone; + + protected: + // Can be overridden for test. + virtual talk_base::NetworkManager* CreateNetworkManager() { + return new talk_base::BasicNetworkManager(); + } + virtual talk_base::BasicPacketSocketFactory* CreateSocketFactory( + talk_base::Thread* thread) { + return new talk_base::BasicPacketSocketFactory(thread); + } + virtual HttpPortAllocator* CreatePortAllocator( + talk_base::NetworkManager* network_manager, + const std::string& user_agent, + const std::string& relay_token); + virtual StunPort* CreateStunPort( + const std::string& username, const std::string& password, + const PortConfiguration* config, talk_base::Network* network); + virtual RelayPort* CreateRelayPort( + const std::string& username, const std::string& password, + const PortConfiguration* config, talk_base::Network* network); + virtual void InitiateProxyDetection(); + virtual void SetProxyInfo(const talk_base::ProxyInfo& info); + virtual talk_base::ProxyInfo GetProxyInfo() const; + + talk_base::Thread* worker() { + return worker_; + } + + private: + bool AddNic(const talk_base::IPAddress& ip, + const talk_base::SocketAddress& proxy_address); + void AllocatePorts(); + void AllocateRelayPorts(); + void CheckNetworks(); + void CreateRelayPorts( + const std::string& username, const std::string& password, + const PortConfiguration* config, const talk_base::ProxyInfo& proxy_info); + + // Must be called by the worker thread. + void CleanUp(); + + void OnRequestDone(talk_base::AsyncHttpRequest* request); + void OnRelayPortComplete(Port* port); + void OnStunPortComplete(Port* port); + void OnRelayPortError(Port* port); + void OnStunPortError(Port* port); + void OnNetworksChanged(); + void OnProxyDetect(talk_base::SignalThread* thread); + void OnConfigReady( + const std::string& username, const std::string& password, + const PortConfiguration* config, const talk_base::ProxyInfo& proxy); + void OnConfigWithProxyReady(const PortConfiguration*); + void RegisterHttpStart(int port); + talk_base::Thread* worker_; + std::string jid_; + std::string session_id_; + std::string user_agent_; + std::string relay_token_; + std::string connection_; + talk_base::AutoDetectProxy* proxy_detect_; + talk_base::scoped_ptr network_manager_; + talk_base::scoped_ptr socket_factory_; + talk_base::scoped_ptr port_allocator_; + NicMap nics_; + std::vector ports_; + std::vector sessions_; + uint32 timeout_ms_; + talk_base::SocketAddress stun_address_; + talk_base::Thread* main_; + bool started_; +}; + +} // namespace cricket + +#endif // TALK_P2P_CLIENT_CONNECTIVITYCHECKER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/client/fakeportallocator.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/fakeportallocator.h new file mode 100644 index 0000000..7a28edb --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/fakeportallocator.h @@ -0,0 +1,107 @@ +// Copyright 2010 Google Inc. All Rights Reserved, +// +// Author: Justin Uberti (juberti@google.com) + +#ifndef TALK_P2P_CLIENT_FAKEPORTALLOCATOR_H_ +#define TALK_P2P_CLIENT_FAKEPORTALLOCATOR_H_ + +#include +#include "talk/base/scoped_ptr.h" +#include "talk/p2p/base/basicpacketsocketfactory.h" +#include "talk/p2p/base/portallocator.h" +#include "talk/p2p/base/udpport.h" + +namespace talk_base { +class SocketFactory; +class Thread; +} + +namespace cricket { + +class FakePortAllocatorSession : public PortAllocatorSession { + public: + FakePortAllocatorSession(talk_base::Thread* worker_thread, + talk_base::PacketSocketFactory* factory, + const std::string& content_name, + int component, + const std::string& ice_ufrag, + const std::string& ice_pwd) + : PortAllocatorSession(content_name, component, ice_ufrag, ice_pwd, + cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG), + worker_thread_(worker_thread), + factory_(factory), + network_("network", "unittest", + talk_base::IPAddress(INADDR_LOOPBACK), 8), + port_(), running_(false), + port_config_count_(0) { + network_.AddIP(talk_base::IPAddress(INADDR_LOOPBACK)); + } + + virtual void StartGettingPorts() { + if (!port_) { + port_.reset(cricket::UDPPort::Create(worker_thread_, factory_, + &network_, network_.ip(), 0, 0, + username(), + password())); + AddPort(port_.get()); + } + ++port_config_count_; + running_ = true; + } + + virtual void StopGettingPorts() { running_ = false; } + virtual bool IsGettingPorts() { return running_; } + int port_config_count() { return port_config_count_; } + + void AddPort(cricket::Port* port) { + port->set_component(component_); + port->set_generation(0); + port->SignalPortComplete.connect( + this, &FakePortAllocatorSession::OnPortComplete); + port->PrepareAddress(); + SignalPortReady(this, port); + } + void OnPortComplete(cricket::Port* port) { + SignalCandidatesReady(this, port->Candidates()); + SignalCandidatesAllocationDone(this); + } + + private: + talk_base::Thread* worker_thread_; + talk_base::PacketSocketFactory* factory_; + talk_base::Network network_; + talk_base::scoped_ptr port_; + bool running_; + int port_config_count_; +}; + +class FakePortAllocator : public cricket::PortAllocator { + public: + FakePortAllocator(talk_base::Thread* worker_thread, + talk_base::PacketSocketFactory* factory) + : worker_thread_(worker_thread), factory_(factory) { + if (factory_ == NULL) { + owned_factory_.reset(new talk_base::BasicPacketSocketFactory( + worker_thread_)); + factory_ = owned_factory_.get(); + } + } + + virtual cricket::PortAllocatorSession* CreateSessionInternal( + const std::string& content_name, + int component, + const std::string& ice_ufrag, + const std::string& ice_pwd) { + return new FakePortAllocatorSession( + worker_thread_, factory_, content_name, component, ice_ufrag, ice_pwd); + } + + private: + talk_base::Thread* worker_thread_; + talk_base::PacketSocketFactory* factory_; + talk_base::scoped_ptr owned_factory_; +}; + +} // namespace cricket + +#endif // TALK_P2P_CLIENT_FAKEPORTALLOCATOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/client/httpportallocator.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/httpportallocator.h new file mode 100644 index 0000000..e1b428f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/httpportallocator.h @@ -0,0 +1,190 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_P2P_CLIENT_HTTPPORTALLOCATOR_H_ +#define TALK_P2P_CLIENT_HTTPPORTALLOCATOR_H_ + +#include +#include +#include + +#include "talk/p2p/client/basicportallocator.h" + +class HttpPortAllocatorTest_TestSessionRequestUrl_Test; + +namespace talk_base { +class AsyncHttpRequest; +class SignalThread; +} + +namespace cricket { + +class HttpPortAllocatorBase : public BasicPortAllocator { + public: + // The number of HTTP requests we should attempt before giving up. + static const int kNumRetries; + + // Records the URL that we will GET in order to create a session. + static const char kCreateSessionURL[]; + + HttpPortAllocatorBase(talk_base::NetworkManager* network_manager, + const std::string& user_agent); + HttpPortAllocatorBase(talk_base::NetworkManager* network_manager, + talk_base::PacketSocketFactory* socket_factory, + const std::string& user_agent); + virtual ~HttpPortAllocatorBase(); + + // CreateSession is defined in BasicPortAllocator but is + // redefined here as pure virtual. + virtual PortAllocatorSession* CreateSessionInternal( + const std::string& content_name, + int component, + const std::string& ice_ufrag, + const std::string& ice_pwd) = 0; + + void SetStunHosts(const std::vector& hosts) { + if (!hosts.empty()) { + stun_hosts_ = hosts; + } + } + void SetRelayHosts(const std::vector& hosts) { + if (!hosts.empty()) { + relay_hosts_ = hosts; + } + } + void SetRelayToken(const std::string& relay) { relay_token_ = relay; } + + const std::vector& stun_hosts() const { + return stun_hosts_; + } + + const std::vector& relay_hosts() const { + return relay_hosts_; + } + + const std::string& relay_token() const { + return relay_token_; + } + + const std::string& user_agent() const { + return agent_; + } + + private: + std::vector stun_hosts_; + std::vector relay_hosts_; + std::string relay_token_; + std::string agent_; +}; + +class RequestData; + +class HttpPortAllocatorSessionBase : public BasicPortAllocatorSession { + public: + HttpPortAllocatorSessionBase( + HttpPortAllocatorBase* allocator, + const std::string& content_name, + int component, + const std::string& ice_ufrag, + const std::string& ice_pwd, + const std::vector& stun_hosts, + const std::vector& relay_hosts, + const std::string& relay, + const std::string& agent); + virtual ~HttpPortAllocatorSessionBase(); + + const std::string& relay_token() const { + return relay_token_; + } + + const std::string& user_agent() const { + return agent_; + } + + virtual void SendSessionRequest(const std::string& host, int port) = 0; + virtual void ReceiveSessionResponse(const std::string& response); + + // Made public for testing. Should be protected. + std::string GetSessionRequestUrl(); + + protected: + virtual void GetPortConfigurations(); + void TryCreateRelaySession(); + virtual HttpPortAllocatorBase* allocator() { + return static_cast( + BasicPortAllocatorSession::allocator()); + } + + private: + std::vector relay_hosts_; + std::vector stun_hosts_; + std::string relay_token_; + std::string agent_; + int attempts_; +}; + +class HttpPortAllocator : public HttpPortAllocatorBase { + public: + HttpPortAllocator(talk_base::NetworkManager* network_manager, + const std::string& user_agent); + HttpPortAllocator(talk_base::NetworkManager* network_manager, + talk_base::PacketSocketFactory* socket_factory, + const std::string& user_agent); + virtual ~HttpPortAllocator(); + virtual PortAllocatorSession* CreateSessionInternal( + const std::string& content_name, + int component, + const std::string& ice_ufrag, const std::string& ice_pwd); +}; + +class HttpPortAllocatorSession : public HttpPortAllocatorSessionBase { + public: + HttpPortAllocatorSession( + HttpPortAllocator* allocator, + const std::string& content_name, + int component, + const std::string& ice_ufrag, + const std::string& ice_pwd, + const std::vector& stun_hosts, + const std::vector& relay_hosts, + const std::string& relay, + const std::string& agent); + virtual ~HttpPortAllocatorSession(); + + virtual void SendSessionRequest(const std::string& host, int port); + + protected: + // Protected for diagnostics. + virtual void OnRequestDone(talk_base::SignalThread* request); + + private: + std::list requests_; +}; + +} // namespace cricket + +#endif // TALK_P2P_CLIENT_HTTPPORTALLOCATOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/client/sessionmanagertask.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/sessionmanagertask.h new file mode 100644 index 0000000..548c695 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/sessionmanagertask.h @@ -0,0 +1,93 @@ +/* + * 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 _SESSIONMANAGERTASK_H_ +#define _SESSIONMANAGERTASK_H_ + +#include "talk/p2p/base/sessionmanager.h" +#include "talk/p2p/client/sessionsendtask.h" +#include "talk/xmpp/xmppengine.h" +#include "talk/xmpp/xmpptask.h" + +namespace cricket { + +// This class handles sending and receiving XMPP messages on behalf of the +// SessionManager. The sending part is handed over to SessionSendTask. + +class SessionManagerTask : public buzz::XmppTask { + public: + SessionManagerTask(buzz::XmppTaskParentInterface* parent, + SessionManager* session_manager) + : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE), + session_manager_(session_manager) { + } + + ~SessionManagerTask() { + } + + // Turns on simple support for sending messages, using SessionSendTask. + void EnableOutgoingMessages() { + session_manager_->SignalOutgoingMessage.connect( + this, &SessionManagerTask::OnOutgoingMessage); + session_manager_->SignalRequestSignaling.connect( + session_manager_, &SessionManager::OnSignalingReady); + } + + virtual int ProcessStart() { + const buzz::XmlElement *stanza = NextStanza(); + if (stanza == NULL) + return STATE_BLOCKED; + session_manager_->OnIncomingMessage(stanza); + return STATE_START; + } + + protected: + virtual bool HandleStanza(const buzz::XmlElement *stanza) { + if (!session_manager_->IsSessionMessage(stanza)) + return false; + // Responses are handled by the SessionSendTask that sent the request. + //if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_SET) + // return false; + QueueStanza(stanza); + return true; + } + + private: + void OnOutgoingMessage(SessionManager* manager, + const buzz::XmlElement* stanza) { + cricket::SessionSendTask* sender = + new cricket::SessionSendTask(parent_, session_manager_); + sender->Send(stanza); + sender->Start(); + } + + SessionManager* session_manager_; +}; + +} // namespace cricket + +#endif // _SESSIONMANAGERTASK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/client/sessionsendtask.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/sessionsendtask.h new file mode 100644 index 0000000..acd1cc0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/sessionsendtask.h @@ -0,0 +1,145 @@ +/* + * 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 TALK_P2P_CLIENT_SESSIONSENDTASK_H_ +#define TALK_P2P_CLIENT_SESSIONSENDTASK_H_ + +#include "talk/base/common.h" +#include "talk/xmpp/constants.h" +#include "talk/xmpp/xmppclient.h" +#include "talk/xmpp/xmppengine.h" +#include "talk/xmpp/xmpptask.h" +#include "talk/p2p/base/sessionmanager.h" + +namespace cricket { + +// The job of this task is to send an IQ stanza out (after stamping it with +// an ID attribute) and then wait for a response. If not response happens +// within 5 seconds, it will signal failure on a SessionManager. If an error +// happens it will also signal failure. If, however, the send succeeds this +// task will quietly go away. + +class SessionSendTask : public buzz::XmppTask { + public: + SessionSendTask(buzz::XmppTaskParentInterface* parent, + SessionManager* session_manager) + : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE), + session_manager_(session_manager) { + set_timeout_seconds(15); + session_manager_->SignalDestroyed.connect( + this, &SessionSendTask::OnSessionManagerDestroyed); + } + + virtual ~SessionSendTask() { + SignalDone(this); + } + + void Send(const buzz::XmlElement* stanza) { + ASSERT(stanza_.get() == NULL); + + // This should be an IQ of type set, result, or error. In the first case, + // we supply an ID. In the others, it should be present. + ASSERT(stanza->Name() == buzz::QN_IQ); + ASSERT(stanza->HasAttr(buzz::QN_TYPE)); + if (stanza->Attr(buzz::QN_TYPE) == "set") { + ASSERT(!stanza->HasAttr(buzz::QN_ID)); + } else { + ASSERT((stanza->Attr(buzz::QN_TYPE) == "result") || + (stanza->Attr(buzz::QN_TYPE) == "error")); + ASSERT(stanza->HasAttr(buzz::QN_ID)); + } + + stanza_.reset(new buzz::XmlElement(*stanza)); + if (stanza_->HasAttr(buzz::QN_ID)) { + set_task_id(stanza_->Attr(buzz::QN_ID)); + } else { + stanza_->SetAttr(buzz::QN_ID, task_id()); + } + } + + void OnSessionManagerDestroyed() { + // If the session manager doesn't exist anymore, we should still try to + // send the message, but avoid calling back into the SessionManager. + session_manager_ = NULL; + } + + sigslot::signal1 SignalDone; + + protected: + virtual int OnTimeout() { + if (session_manager_ != NULL) { + session_manager_->OnFailedSend(stanza_.get(), NULL); + } + + return XmppTask::OnTimeout(); + } + + virtual int ProcessStart() { + SendStanza(stanza_.get()); + if (stanza_->Attr(buzz::QN_TYPE) == buzz::STR_SET) { + return STATE_RESPONSE; + } else { + return STATE_DONE; + } + } + + virtual int ProcessResponse() { + const buzz::XmlElement* next = NextStanza(); + if (next == NULL) + return STATE_BLOCKED; + + if (session_manager_ != NULL) { + if (next->Attr(buzz::QN_TYPE) == buzz::STR_RESULT) { + session_manager_->OnIncomingResponse(stanza_.get(), next); + } else { + session_manager_->OnFailedSend(stanza_.get(), next); + } + } + + return STATE_DONE; + } + + virtual bool HandleStanza(const buzz::XmlElement *stanza) { + if (!MatchResponseIq(stanza, + buzz::Jid(stanza_->Attr(buzz::QN_TO)), task_id())) + return false; + if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_RESULT || + stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) { + QueueStanza(stanza); + return true; + } + return false; + } + + private: + SessionManager *session_manager_; + talk_base::scoped_ptr stanza_; +}; + +} + +#endif // TALK_P2P_CLIENT_SESSIONSENDTASK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/p2p/client/socketmonitor.h b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/socketmonitor.h new file mode 100644 index 0000000..b366b9d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/p2p/client/socketmonitor.h @@ -0,0 +1,71 @@ +/* + * 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 TALK_P2P_CLIENT_SOCKETMONITOR_H_ +#define TALK_P2P_CLIENT_SOCKETMONITOR_H_ + +#include + +#include "talk/base/criticalsection.h" +#include "talk/base/sigslot.h" +#include "talk/base/thread.h" +#include "talk/p2p/base/transportchannel.h" + +namespace cricket { + +class SocketMonitor : public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + SocketMonitor(TransportChannel* channel, + talk_base::Thread* worker_thread, + talk_base::Thread* monitor_thread); + ~SocketMonitor(); + + void Start(int cms); + void Stop(); + + talk_base::Thread* monitor_thread() { return monitoring_thread_; } + + sigslot::signal2&> SignalUpdate; + + protected: + void OnMessage(talk_base::Message* message); + void PollSocket(bool poll); + + std::vector connection_infos_; + TransportChannel* channel_; + talk_base::Thread* channel_thread_; + talk_base::Thread* monitoring_thread_; + talk_base::CriticalSection crit_; + uint32 rate_; + bool monitoring_; +}; + +} // namespace cricket + +#endif // TALK_P2P_CLIENT_SOCKETMONITOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/audiomonitor.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/audiomonitor.h new file mode 100644 index 0000000..5ab6b96 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/audiomonitor.h @@ -0,0 +1,75 @@ +/* + * 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_SESSION_MEDIA_AUDIOMONITOR_H_ +#define TALK_SESSION_MEDIA_AUDIOMONITOR_H_ + +#include "talk/base/sigslot.h" +#include "talk/base/thread.h" +#include "talk/p2p/base/port.h" +#include + +namespace cricket { + +class VoiceChannel; + +struct AudioInfo { + int input_level; + int output_level; + typedef std::vector > StreamList; + StreamList active_streams; // ssrcs contributing to output_level +}; + +class AudioMonitor : public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + AudioMonitor(VoiceChannel* voice_channel, talk_base::Thread *monitor_thread); + ~AudioMonitor(); + + void Start(int cms); + void Stop(); + + VoiceChannel* voice_channel(); + talk_base::Thread *monitor_thread(); + + sigslot::signal2 SignalUpdate; + + protected: + void OnMessage(talk_base::Message *message); + void PollVoiceChannel(); + + AudioInfo audio_info_; + VoiceChannel* voice_channel_; + talk_base::Thread* monitoring_thread_; + talk_base::CriticalSection crit_; + uint32 rate_; + bool monitoring_; +}; + +} + +#endif // TALK_SESSION_MEDIA_AUDIOMONITOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/bundlefilter.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/bundlefilter.h new file mode 100644 index 0000000..6e3d8c4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/bundlefilter.h @@ -0,0 +1,80 @@ +/* + * 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_SESSION_MEDIA_BUNDLEFILTER_H_ +#define TALK_SESSION_MEDIA_BUNDLEFILTER_H_ + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/media/base/streamparams.h" + +namespace cricket { + +// 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. +// +// 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: + BundleFilter(); + ~BundleFilter(); + + // 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 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 payload_types_; + std::vector streams_; +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_BUNDLEFILTER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/call.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/call.h new file mode 100644 index 0000000..ea9f0d2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/call.h @@ -0,0 +1,309 @@ +/* + * 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_SESSION_MEDIA_CALL_H_ +#define TALK_SESSION_MEDIA_CALL_H_ + +#include +#include +#include +#include + +#include "talk/base/messagequeue.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/screencastid.h" +#include "talk/media/base/streamparams.h" +#include "talk/media/base/videocommon.h" +#include "talk/p2p/base/session.h" +#include "talk/p2p/client/socketmonitor.h" +#include "talk/session/media/audiomonitor.h" +#include "talk/session/media/currentspeakermonitor.h" +#include "talk/session/media/mediamessages.h" +#include "talk/session/media/mediasession.h" +#include "talk/xmpp/jid.h" + +namespace cricket { + +struct AudioInfo; +class MediaSessionClient; +class BaseChannel; +class VoiceChannel; +class VideoChannel; +class DataChannel; + +// Can't typedef this easily since it's forward declared as struct elsewhere. +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); + ~Call(); + + // |initiator| can be empty. + Session* InitiateSession(const buzz::Jid& to, const buzz::Jid& initiator, + const CallOptions& options); + Session* InitiateSession(const std::string& id, const buzz::Jid& to, + const CallOptions& options); + void AcceptSession(Session* session, const CallOptions& options); + void RejectSession(Session* session); + void TerminateSession(Session* session); + void Terminate(); + bool SendViewRequest(Session* session, + const ViewRequest& view_request); + void SetLocalRenderer(VideoRenderer* renderer); + void SetVideoRenderer(Session* session, uint32 ssrc, + VideoRenderer* renderer); + void StartConnectionMonitor(Session* session, int cms); + void StopConnectionMonitor(Session* session); + void StartAudioMonitor(Session* session, int cms); + void StopAudioMonitor(Session* session); + bool IsAudioMonitorRunning(Session* session); + void StartSpeakerMonitor(Session* session); + void StopSpeakerMonitor(Session* session); + void Mute(bool mute); + void MuteVideo(bool mute); + bool SendData(Session* session, + const SendDataParams& params, + const talk_base::Buffer& payload, + SendDataResult* result); + void PressDTMF(int event); + bool StartScreencast(Session* session, + const std::string& stream_name, uint32 ssrc, + const ScreencastId& screencastid, int fps); + bool StopScreencast(Session* session, + const std::string& stream_name, uint32 ssrc); + + std::vector sessions(); + uint32 id(); + bool has_video() const { return has_video_; } + bool has_data() const { return has_data_; } + bool muted() const { return muted_; } + bool video() const { return has_video_; } + bool secure() const; + bool video_muted() const { return video_muted_; } + const std::vector* GetDataRecvStreams(Session* session) const { + MediaStreams* recv_streams = GetMediaStreams(session); + return recv_streams ? &recv_streams->data() : NULL; + } + const std::vector* GetVideoRecvStreams(Session* session) const { + MediaStreams* recv_streams = GetMediaStreams(session); + return recv_streams ? &recv_streams->video() : NULL; + } + const std::vector* GetAudioRecvStreams(Session* session) const { + MediaStreams* recv_streams = GetMediaStreams(session); + return recv_streams ? &recv_streams->audio() : NULL; + } + VoiceChannel* GetVoiceChannel(Session* session) const; + VideoChannel* GetVideoChannel(Session* session) const; + DataChannel* GetDataChannel(Session* session) const; + // Public just for unit tests + VideoContentDescription* CreateVideoStreamUpdate(const StreamParams& stream); + // Takes ownership of video. + void SendVideoStreamUpdate(Session* session, VideoContentDescription* video); + + // Setting this to false will cause the call to have a longer timeout and + // for the SignalSetupToCallVoicemail to never fire. + void set_send_to_voicemail(bool send_to_voicemail) { + send_to_voicemail_ = send_to_voicemail; + } + bool send_to_voicemail() { return send_to_voicemail_; } + const VoiceMediaInfo& last_voice_media_info() const { + return last_voice_media_info_; + } + + // Sets a flag on the chatapp that will redirect the call to voicemail once + // the call has been terminated + sigslot::signal0<> SignalSetupToCallVoicemail; + sigslot::signal2 SignalAddSession; + sigslot::signal2 SignalRemoveSession; + sigslot::signal3 + SignalSessionState; + sigslot::signal3 + SignalSessionError; + sigslot::signal3 + SignalReceivedTerminateReason; + sigslot::signal2 &> + SignalConnectionMonitor; + sigslot::signal2 SignalMediaMonitor; + sigslot::signal2 SignalAudioMonitor; + // Empty nick on StreamParams means "unknown". + // No ssrcs in StreamParams means "no current speaker". + sigslot::signal3 SignalSpeakerMonitor; + sigslot::signal2 &> + SignalVideoConnectionMonitor; + sigslot::signal2 SignalVideoMediaMonitor; + // Gives added streams and removed streams, in that order. + sigslot::signal4 SignalMediaStreamsUpdate; + sigslot::signal3 SignalDataReceived; + + AudioSourceProxy* GetAudioSourceProxy(); + + private: + void OnMessage(talk_base::Message* message); + void OnSessionState(BaseSession* base_session, BaseSession::State state); + void OnSessionError(BaseSession* base_session, Session::Error error); + void OnSessionInfoMessage( + Session* session, const buzz::XmlElement* action_elem); + void OnViewRequest( + Session* session, const ViewRequest& view_request); + void OnRemoteDescriptionUpdate( + BaseSession* base_session, const ContentInfos& updated_contents); + void OnReceivedTerminateReason(Session* session, const std::string &reason); + void IncomingSession(Session* session, const SessionDescription* offer); + // Returns true on success. + bool AddSession(Session* session, const SessionDescription* offer); + void RemoveSession(Session* session); + void EnableChannels(bool enable); + void EnableSessionChannels(Session* session, bool enable); + void Join(Call* call, bool enable); + void OnConnectionMonitor(VoiceChannel* channel, + const std::vector &infos); + void OnMediaMonitor(VoiceChannel* channel, const VoiceMediaInfo& info); + void OnAudioMonitor(VoiceChannel* channel, const AudioInfo& info); + void OnSpeakerMonitor(CurrentSpeakerMonitor* monitor, uint32 ssrc); + void OnConnectionMonitor(VideoChannel* channel, + const std::vector &infos); + void OnMediaMonitor(VideoChannel* channel, const VideoMediaInfo& info); + void OnDataReceived(DataChannel* channel, + const ReceiveDataParams& params, + const talk_base::Buffer& payload); + MediaStreams* GetMediaStreams(Session* session) const; + void UpdateRemoteMediaStreams(Session* session, + const ContentInfos& updated_contents, + bool update_channels); + bool UpdateVoiceChannelRemoteContent(Session* session, + const AudioContentDescription* audio); + bool UpdateVideoChannelRemoteContent(Session* session, + const VideoContentDescription* video); + bool UpdateDataChannelRemoteContent(Session* session, + const DataContentDescription* data); + void UpdateRecvStreams(const std::vector& update_streams, + BaseChannel* channel, + std::vector* recv_streams, + std::vector* added_streams, + std::vector* removed_streams); + void AddRecvStreams(const std::vector& added_streams, + BaseChannel* channel, + std::vector* recv_streams); + void AddRecvStream(const StreamParams& stream, + BaseChannel* channel, + std::vector* recv_streams); + void RemoveRecvStreams(const std::vector& removed_streams, + BaseChannel* channel, + std::vector* recv_streams); + void RemoveRecvStream(const StreamParams& stream, + BaseChannel* channel, + std::vector* recv_streams); + void ContinuePlayDTMF(); + bool StopScreencastWithoutSendingUpdate(Session* session, uint32 ssrc); + bool StopAllScreencastsWithoutSendingUpdate(Session* session); + bool SessionDescriptionContainsCrypto(const SessionDescription* sdesc) const; + Session* InternalInitiateSession(const std::string& id, + const buzz::Jid& to, + const std::string& initiator_name, + const CallOptions& options); + + uint32 id_; + MediaSessionClient* session_client_; + + struct StartedCapture { + StartedCapture(cricket::VideoCapturer* capturer, + const cricket::VideoFormat& format) : + capturer(capturer), + format(format) { + } + cricket::VideoCapturer* capturer; + cricket::VideoFormat format; + }; + typedef std::map StartedScreencastMap; + + struct MediaSession { + Session* session; + VoiceChannel* voice_channel; + VideoChannel* video_channel; + DataChannel* data_channel; + MediaStreams* recv_streams; + StartedScreencastMap started_screencasts; + }; + + // Create a map of media sessions, keyed off session->id(). + typedef std::map MediaSessionMap; + MediaSessionMap media_session_map_; + + std::map speaker_monitor_map_; + VideoRenderer* local_renderer_; + bool has_video_; + bool has_data_; + bool muted_; + bool video_muted_; + bool send_to_voicemail_; + + // DTMF tones have to be queued up so that we don't flood the call. We + // keep a deque (doubely ended queue) of them around. While one is playing we + // set the playing_dtmf_ bit and schedule a message in XX msec to clear that + // bit or start the next tone playing. + std::deque queued_dtmf_; + bool playing_dtmf_; + + VoiceMediaInfo last_voice_media_info_; + + talk_base::scoped_ptr audio_source_proxy_; + + friend class MediaSessionClient; +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_CALL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/channel.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/channel.h new file mode 100644 index 0000000..35b3326 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/channel.h @@ -0,0 +1,724 @@ +/* + * 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_SESSION_MEDIA_CHANNEL_H_ +#define TALK_SESSION_MEDIA_CHANNEL_H_ + +#include +#include + +#include "talk/base/asyncudpsocket.h" +#include "talk/base/criticalsection.h" +#include "talk/base/network.h" +#include "talk/base/sigslot.h" +#include "talk/base/window.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/mediaengine.h" +#include "talk/media/base/screencastid.h" +#include "talk/media/base/streamparams.h" +#include "talk/media/base/videocapturer.h" +#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" + +namespace cricket { + +struct CryptoParams; +class MediaContentDescription; +struct TypingMonitorOptions; +class TypingMonitor; +struct ViewRequest; + +enum SinkType { + SINK_PRE_CRYPTO, // Sink packets before encryption or after decryption. + SINK_POST_CRYPTO // Sink packets after encryption or before decryption. +}; + +// BaseChannel contains logic common to voice and video, including +// enable/mute, marshaling calls to a worker thread, and +// connection and media monitors. +// +// WARNING! SUBCLASSES MUST CALL Deinit() IN THEIR DESTRUCTORS! +// This is required to avoid a data race between the destructor modifying the +// vtable, and the media channel's thread using BaseChannel as the +// NetworkInterface. + +class BaseChannel + : public talk_base::MessageHandler, public sigslot::has_slots<>, + public MediaChannel::NetworkInterface { + public: + BaseChannel(talk_base::Thread* thread, MediaEngineInterface* media_engine, + MediaChannel* channel, BaseSession* session, + const std::string& content_name, bool rtcp); + virtual ~BaseChannel(); + bool Init(TransportChannel* transport_channel, + TransportChannel* rtcp_transport_channel); + // Deinit may be called multiple times and is simply ignored if it's alreay + // done. + void Deinit(); + + talk_base::Thread* worker_thread() const { return worker_thread_; } + BaseSession* session() const { return session_; } + const std::string& content_name() { return content_name_; } + TransportChannel* transport_channel() const { + return transport_channel_; + } + TransportChannel* rtcp_transport_channel() const { + return rtcp_transport_channel_; + } + bool enabled() const { return enabled_; } + + // This function returns true if we are using SRTP. + bool secure() const { return srtp_filter_.IsActive(); } + // The following function returns true if we are using + // DTLS-based keying. If you turned off SRTP later, however + // you could have secure() == false and dtls_secure() == true. + bool secure_dtls() const { return dtls_keyed_; } + // This function returns true if we require secure channel for call setup. + bool secure_required() const { return secure_required_; } + + bool writable() const { return writable_; } + bool IsStreamMuted(uint32 ssrc); + + // Channel control + bool SetLocalContent(const MediaContentDescription* content, + ContentAction action, + std::string* error_desc); + bool SetRemoteContent(const MediaContentDescription* content, + ContentAction action, + std::string* error_desc); + + bool Enable(bool enable); + // Mute sending media on the stream with SSRC |ssrc| + // If there is only one sending stream SSRC 0 can be used. + bool MuteStream(uint32 ssrc, bool mute); + + // Multiplexing + bool AddRecvStream(const StreamParams& sp); + bool RemoveRecvStream(uint32 ssrc); + bool AddSendStream(const StreamParams& sp); + bool RemoveSendStream(uint32 ssrc); + + // Monitoring + void StartConnectionMonitor(int cms); + void StopConnectionMonitor(); + + void set_srtp_signal_silent_time(uint32 silent_time) { + srtp_filter_.set_signal_silent_time(silent_time); + } + + void set_content_name(const std::string& content_name) { + ASSERT(signaling_thread()->IsCurrent()); + ASSERT(!writable_); + if (session_->state() != BaseSession::STATE_INIT) { + LOG(LS_ERROR) << "Content name for a channel can be changed only " + << "when BaseSession is in STATE_INIT state."; + return; + } + content_name_ = content_name; + } + + template + void RegisterSendSink(T* sink, + void (T::*OnPacket)(const void*, size_t, bool), + SinkType type) { + talk_base::CritScope cs(&signal_send_packet_cs_); + if (SINK_POST_CRYPTO == type) { + SignalSendPacketPostCrypto.disconnect(sink); + SignalSendPacketPostCrypto.connect(sink, OnPacket); + } else { + SignalSendPacketPreCrypto.disconnect(sink); + SignalSendPacketPreCrypto.connect(sink, OnPacket); + } + } + + void UnregisterSendSink(sigslot::has_slots<>* sink, + SinkType type) { + talk_base::CritScope cs(&signal_send_packet_cs_); + if (SINK_POST_CRYPTO == type) { + SignalSendPacketPostCrypto.disconnect(sink); + } else { + SignalSendPacketPreCrypto.disconnect(sink); + } + } + + bool HasSendSinks(SinkType type) { + talk_base::CritScope cs(&signal_send_packet_cs_); + if (SINK_POST_CRYPTO == type) { + return !SignalSendPacketPostCrypto.is_empty(); + } else { + return !SignalSendPacketPreCrypto.is_empty(); + } + } + + template + void RegisterRecvSink(T* sink, + void (T::*OnPacket)(const void*, size_t, bool), + SinkType type) { + talk_base::CritScope cs(&signal_recv_packet_cs_); + if (SINK_POST_CRYPTO == type) { + SignalRecvPacketPostCrypto.disconnect(sink); + SignalRecvPacketPostCrypto.connect(sink, OnPacket); + } else { + SignalRecvPacketPreCrypto.disconnect(sink); + SignalRecvPacketPreCrypto.connect(sink, OnPacket); + } + } + + void UnregisterRecvSink(sigslot::has_slots<>* sink, + SinkType type) { + talk_base::CritScope cs(&signal_recv_packet_cs_); + if (SINK_POST_CRYPTO == type) { + SignalRecvPacketPostCrypto.disconnect(sink); + } else { + SignalRecvPacketPreCrypto.disconnect(sink); + } + } + + bool HasRecvSinks(SinkType type) { + talk_base::CritScope cs(&signal_recv_packet_cs_); + if (SINK_POST_CRYPTO == type) { + return !SignalRecvPacketPostCrypto.is_empty(); + } else { + return !SignalRecvPacketPreCrypto.is_empty(); + } + } + + BundleFilter* bundle_filter() { return &bundle_filter_; } + + const std::vector& local_streams() const { + return local_streams_; + } + const std::vector& remote_streams() const { + return remote_streams_; + } + + // Used for latency measurements. + sigslot::signal1 SignalFirstPacketReceived; + + // Used to alert UI when the muted status changes, perhaps autonomously. + sigslot::repeater2 SignalAutoMuted; + + // Made public for easier testing. + void SetReadyToSend(TransportChannel* channel, bool ready); + + protected: + MediaEngineInterface* media_engine() const { return media_engine_; } + virtual MediaChannel* media_channel() const { return media_channel_; } + void set_rtcp_transport_channel(TransportChannel* transport); + bool was_ever_writable() const { return was_ever_writable_; } + void set_local_content_direction(MediaContentDirection direction) { + local_content_direction_ = direction; + } + void set_remote_content_direction(MediaContentDirection direction) { + remote_content_direction_ = direction; + } + bool IsReadyToReceive() const; + bool IsReadyToSend() const; + talk_base::Thread* signaling_thread() { return session_->signaling_thread(); } + SrtpFilter* srtp_filter() { return &srtp_filter_; } + bool rtcp() const { return rtcp_; } + + void FlushRtcpMessages(); + + // NetworkInterface implementation, called by MediaEngine + virtual bool SendPacket(talk_base::Buffer* packet, + talk_base::DiffServCodePoint dscp); + virtual bool SendRtcp(talk_base::Buffer* packet, + talk_base::DiffServCodePoint dscp); + virtual int SetOption(SocketType type, talk_base::Socket::Option o, int val); + + // From TransportChannel + void OnWritableState(TransportChannel* channel); + virtual void OnChannelRead(TransportChannel* channel, + const char* data, + size_t len, + const talk_base::PacketTime& packet_time, + int flags); + void OnReadyToSend(TransportChannel* channel); + + bool PacketIsRtcp(const TransportChannel* channel, const char* data, + size_t len); + bool SendPacket(bool rtcp, talk_base::Buffer* packet, + talk_base::DiffServCodePoint dscp); + virtual bool WantsPacket(bool rtcp, talk_base::Buffer* packet); + void HandlePacket(bool rtcp, talk_base::Buffer* packet, + const talk_base::PacketTime& packet_time); + + // Apply the new local/remote session description. + void OnNewLocalDescription(BaseSession* session, ContentAction action); + void OnNewRemoteDescription(BaseSession* session, ContentAction action); + + void EnableMedia_w(); + void DisableMedia_w(); + virtual bool MuteStream_w(uint32 ssrc, bool mute); + bool IsStreamMuted_w(uint32 ssrc); + void ChannelWritable_w(); + void ChannelNotWritable_w(); + bool AddRecvStream_w(const StreamParams& sp); + bool RemoveRecvStream_w(uint32 ssrc); + bool AddSendStream_w(const StreamParams& sp); + bool RemoveSendStream_w(uint32 ssrc); + virtual bool ShouldSetupDtlsSrtp() const; + // Do the DTLS key expansion and impose it on the SRTP/SRTCP filters. + // |rtcp_channel| indicates whether to set up the RTP or RTCP filter. + bool SetupDtlsSrtp(bool rtcp_channel); + // Set the DTLS-SRTP cipher policy on this channel as appropriate. + bool SetDtlsSrtpCiphers(TransportChannel *tc, bool rtcp); + + virtual void ChangeState() = 0; + + // Gets the content info appropriate to the channel (audio or video). + virtual const ContentInfo* GetFirstContent( + const SessionDescription* sdesc) = 0; + bool UpdateLocalStreams_w(const std::vector& streams, + ContentAction action, + std::string* error_desc); + bool UpdateRemoteStreams_w(const std::vector& streams, + ContentAction action, + std::string* error_desc); + bool SetBaseLocalContent_w(const MediaContentDescription* content, + ContentAction action, + std::string* error_desc); + virtual bool SetLocalContent_w(const MediaContentDescription* content, + ContentAction action, + std::string* error_desc) = 0; + bool SetBaseRemoteContent_w(const MediaContentDescription* content, + ContentAction action, + std::string* error_desc); + virtual bool SetRemoteContent_w(const MediaContentDescription* content, + 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& extensions); + + bool CheckSrtpConfig(const std::vector& cryptos, + bool* dtls, + std::string* error_desc); + bool SetSrtp_w(const std::vector& 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); + + // Handled in derived classes + // Get the SRTP ciphers to use for RTP media + virtual void GetSrtpCiphers(std::vector* ciphers) const = 0; + virtual void OnConnectionMonitorUpdate(SocketMonitor* monitor, + const std::vector& infos) = 0; + + // Helper function for invoking bool-returning methods on the worker thread. + template + bool InvokeOnWorker(const FunctorT& functor) { + return worker_thread_->Invoke(functor); + } + + private: + sigslot::signal3 SignalSendPacketPreCrypto; + sigslot::signal3 SignalSendPacketPostCrypto; + sigslot::signal3 SignalRecvPacketPreCrypto; + sigslot::signal3 SignalRecvPacketPostCrypto; + talk_base::CriticalSection signal_send_packet_cs_; + talk_base::CriticalSection signal_recv_packet_cs_; + + talk_base::Thread* worker_thread_; + MediaEngineInterface* media_engine_; + BaseSession* session_; + MediaChannel* media_channel_; + std::vector local_streams_; + std::vector remote_streams_; + + std::string content_name_; + bool rtcp_; + TransportChannel* transport_channel_; + TransportChannel* rtcp_transport_channel_; + SrtpFilter srtp_filter_; + RtcpMuxFilter rtcp_mux_filter_; + BundleFilter bundle_filter_; + talk_base::scoped_ptr socket_monitor_; + bool enabled_; + bool writable_; + bool rtp_ready_to_send_; + bool rtcp_ready_to_send_; + bool was_ever_writable_; + MediaContentDirection local_content_direction_; + MediaContentDirection remote_content_direction_; + std::set muted_streams_; + 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, +// and input/output level monitoring. +class VoiceChannel : public BaseChannel { + public: + VoiceChannel(talk_base::Thread* thread, MediaEngineInterface* media_engine, + VoiceMediaChannel* channel, BaseSession* session, + const std::string& content_name, bool rtcp); + ~VoiceChannel(); + bool Init(); + bool SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer); + bool SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer); + + // downcasts a MediaChannel + virtual VoiceMediaChannel* media_channel() const { + return static_cast(BaseChannel::media_channel()); + } + + bool SetRingbackTone(const void* buf, int len); + void SetEarlyMedia(bool enable); + // This signal is emitted when we have gone a period of time without + // receiving early media. When received, a UI should start playing its + // own ringing sound + sigslot::signal1 SignalEarlyMediaTimeout; + + bool PlayRingbackTone(uint32 ssrc, bool play, bool loop); + // TODO(ronghuawu): Replace PressDTMF with InsertDtmf. + bool PressDTMF(int digit, bool playout); + // Returns if the telephone-event has been negotiated. + bool CanInsertDtmf(); + // Send and/or play a DTMF |event| according to the |flags|. + // The DTMF out-of-band signal will be used on sending. + // The |ssrc| should be either 0 or a valid send stream ssrc. + // The valid value for the |event| are 0 which corresponding to DTMF + // event 0-9, *, #, A-D. + bool InsertDtmf(uint32 ssrc, int event_code, int duration, int flags); + bool SetOutputScaling(uint32 ssrc, double left, double right); + // Get statistics about the current media session. + bool GetStats(VoiceMediaInfo* stats); + + // Monitoring functions + sigslot::signal2&> + SignalConnectionMonitor; + + void StartMediaMonitor(int cms); + void StopMediaMonitor(); + sigslot::signal2 SignalMediaMonitor; + + void StartAudioMonitor(int cms); + void StopAudioMonitor(); + bool IsAudioMonitorRunning() const; + sigslot::signal2 SignalAudioMonitor; + + void StartTypingMonitor(const TypingMonitorOptions& settings); + void StopTypingMonitor(); + bool IsTypingMonitorRunning() const; + + // Overrides BaseChannel::MuteStream_w. + virtual bool MuteStream_w(uint32 ssrc, bool mute); + + int GetInputLevel_w(); + int GetOutputLevel_w(); + void GetActiveStreams_w(AudioInfo::StreamList* actives); + + // Signal errors from VoiceMediaChannel. Arguments are: + // ssrc(uint32), and error(VoiceMediaChannel::Error). + sigslot::signal3 + SignalMediaError; + + // Configuration and setting. + bool SetChannelOptions(const AudioOptions& options); + + private: + // overrides from BaseChannel + virtual void OnChannelRead(TransportChannel* channel, + const char* data, size_t len, + const talk_base::PacketTime& packet_time, + int flags); + virtual void ChangeState(); + virtual const ContentInfo* GetFirstContent(const SessionDescription* sdesc); + virtual bool SetLocalContent_w(const MediaContentDescription* content, + ContentAction action, + std::string* error_desc); + virtual bool SetRemoteContent_w(const MediaContentDescription* content, + 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 InsertDtmf_w(uint32 ssrc, int event, int duration, int flags); + bool SetOutputScaling_w(uint32 ssrc, double left, double right); + bool GetStats_w(VoiceMediaInfo* stats); + + virtual void OnMessage(talk_base::Message* pmsg); + virtual void GetSrtpCiphers(std::vector* ciphers) const; + virtual void OnConnectionMonitorUpdate( + SocketMonitor* monitor, const std::vector& infos); + virtual void OnMediaMonitorUpdate( + VoiceMediaChannel* media_channel, const VoiceMediaInfo& info); + void OnAudioMonitorUpdate(AudioMonitor* monitor, const AudioInfo& info); + void OnVoiceChannelError(uint32 ssrc, VoiceMediaChannel::Error error); + void SendLastMediaError(); + void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error); + + static const int kEarlyMediaTimeout = 1000; + bool received_media_; + talk_base::scoped_ptr media_monitor_; + talk_base::scoped_ptr audio_monitor_; + talk_base::scoped_ptr typing_monitor_; +}; + +// VideoChannel is a specialization for video. +class VideoChannel : public BaseChannel { + public: + // Make screen capturer virtual so that it can be overriden in testing. + // E.g. used to test that window events are triggered correctly. + class ScreenCapturerFactory { + public: + virtual VideoCapturer* CreateScreenCapturer(const ScreencastId& window) = 0; + virtual ~ScreenCapturerFactory() {} + }; + + VideoChannel(talk_base::Thread* thread, MediaEngineInterface* media_engine, + VideoMediaChannel* channel, BaseSession* session, + const std::string& content_name, bool rtcp, + VoiceChannel* voice_channel); + ~VideoChannel(); + bool Init(); + + bool SetRenderer(uint32 ssrc, VideoRenderer* renderer); + bool ApplyViewRequest(const ViewRequest& request); + + // TODO(pthatcher): Refactor to use a "capture id" instead of an + // ssrc here as the "key". + VideoCapturer* AddScreencast(uint32 ssrc, const ScreencastId& id); + bool SetCapturer(uint32 ssrc, VideoCapturer* capturer); + bool RemoveScreencast(uint32 ssrc); + // True if we've added a screencast. Doesn't matter if the capturer + // has been started or not. + bool IsScreencasting(); + int GetScreencastFps(uint32 ssrc); + int GetScreencastMaxPixels(uint32 ssrc); + // Get statistics about the current media session. + bool GetStats(const StatsOptions& options, VideoMediaInfo* stats); + + sigslot::signal2&> + SignalConnectionMonitor; + + void StartMediaMonitor(int cms); + void StopMediaMonitor(); + sigslot::signal2 SignalMediaMonitor; + sigslot::signal2 SignalScreencastWindowEvent; + + bool SendIntraFrame(); + bool RequestIntraFrame(); + sigslot::signal3 + SignalMediaError; + + void SetScreenCaptureFactory( + ScreenCapturerFactory* screencapture_factory); + + // Configuration and setting. + bool SetChannelOptions(const VideoOptions& options); + + protected: + // downcasts a MediaChannel + virtual VideoMediaChannel* media_channel() const { + return static_cast(BaseChannel::media_channel()); + } + + private: + typedef std::map ScreencastMap; + struct ScreencastDetailsData; + + // overrides from BaseChannel + virtual void ChangeState(); + virtual const ContentInfo* GetFirstContent(const SessionDescription* sdesc); + virtual bool SetLocalContent_w(const MediaContentDescription* content, + ContentAction action, + std::string* error_desc); + virtual bool SetRemoteContent_w(const MediaContentDescription* content, + ContentAction action, + std::string* error_desc); + bool ApplyViewRequest_w(const ViewRequest& request); + + VideoCapturer* AddScreencast_w(uint32 ssrc, const ScreencastId& id); + bool RemoveScreencast_w(uint32 ssrc); + void OnScreencastWindowEvent_s(uint32 ssrc, talk_base::WindowEvent we); + bool IsScreencasting_w() const; + void GetScreencastDetails_w(ScreencastDetailsData* d) const; + void SetScreenCaptureFactory_w( + ScreenCapturerFactory* screencapture_factory); + bool GetStats_w(VideoMediaInfo* stats); + + virtual void OnMessage(talk_base::Message* pmsg); + virtual void GetSrtpCiphers(std::vector* ciphers) const; + virtual void OnConnectionMonitorUpdate( + SocketMonitor* monitor, const std::vector& infos); + virtual void OnMediaMonitorUpdate( + VideoMediaChannel* media_channel, const VideoMediaInfo& info); + virtual void OnScreencastWindowEvent(uint32 ssrc, + talk_base::WindowEvent event); + virtual void OnStateChange(VideoCapturer* capturer, CaptureState ev); + bool GetLocalSsrc(const VideoCapturer* capturer, uint32* ssrc); + + void OnVideoChannelError(uint32 ssrc, VideoMediaChannel::Error error); + void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error); + + VoiceChannel* voice_channel_; + VideoRenderer* renderer_; + talk_base::scoped_ptr screencapture_factory_; + ScreencastMap screencast_capturers_; + talk_base::scoped_ptr media_monitor_; + + talk_base::WindowEvent previous_we_; +}; + +// DataChannel is a specialization for data. +class DataChannel : public BaseChannel { + public: + DataChannel(talk_base::Thread* thread, + DataMediaChannel* media_channel, + BaseSession* session, + const std::string& content_name, + bool rtcp); + ~DataChannel(); + bool Init(); + + virtual bool SendData(const SendDataParams& params, + const talk_base::Buffer& payload, + SendDataResult* result); + + void StartMediaMonitor(int cms); + void StopMediaMonitor(); + + // Should be called on the signaling thread only. + bool ready_to_send_data() const { + return ready_to_send_data_; + } + + sigslot::signal2 SignalMediaMonitor; + sigslot::signal2&> + SignalConnectionMonitor; + sigslot::signal3 + SignalMediaError; + sigslot::signal3 + SignalDataReceived; + // Signal for notifying when the channel becomes ready to send data. + // 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 SignalReadyToSendData; + + protected: + // downcasts a MediaChannel. + virtual DataMediaChannel* media_channel() const { + return static_cast(BaseChannel::media_channel()); + } + + private: + struct SendDataMessageData : public talk_base::MessageData { + SendDataMessageData(const SendDataParams& params, + const talk_base::Buffer* payload, + SendDataResult* result) + : params(params), + payload(payload), + result(result), + succeeded(false) { + } + + const SendDataParams& params; + const talk_base::Buffer* payload; + SendDataResult* result; + bool succeeded; + }; + + struct DataReceivedMessageData : public talk_base::MessageData { + // We copy the data because the data will become invalid after we + // handle DataMediaChannel::SignalDataReceived but before we fire + // SignalDataReceived. + DataReceivedMessageData( + const ReceiveDataParams& params, const char* data, size_t len) + : params(params), + payload(data, len) { + } + const ReceiveDataParams params; + const talk_base::Buffer payload; + }; + + typedef talk_base::TypedMessageData DataChannelReadyToSendMessageData; + + // 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, + std::string* error_desc); + // Same as SetDataChannelType, but extracts the type from the + // DataContentDescription. + bool SetDataChannelTypeFromContent(const DataContentDescription* content, + std::string* error_desc); + virtual bool SetLocalContent_w(const MediaContentDescription* content, + ContentAction action, + std::string* error_desc); + virtual bool SetRemoteContent_w(const MediaContentDescription* content, + ContentAction action, + std::string* error_desc); + virtual void ChangeState(); + virtual bool WantsPacket(bool rtcp, talk_base::Buffer* packet); + + virtual void OnMessage(talk_base::Message* pmsg); + virtual void GetSrtpCiphers(std::vector* ciphers) const; + virtual void OnConnectionMonitorUpdate( + SocketMonitor* monitor, const std::vector& infos); + virtual void OnMediaMonitorUpdate( + DataMediaChannel* media_channel, const DataMediaInfo& info); + virtual bool ShouldSetupDtlsSrtp() const; + void OnDataReceived( + const ReceiveDataParams& params, const char* data, size_t len); + void OnDataChannelError(uint32 ssrc, DataMediaChannel::Error error); + void OnDataChannelReadyToSend(bool writable); + void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error); + + talk_base::scoped_ptr media_monitor_; + // TODO(pthatcher): Make a separate SctpDataChannel and + // RtpDataChannel instead of using this. + DataChannelType data_channel_type_; + bool ready_to_send_data_; +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_CHANNEL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/channelmanager.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/channelmanager.h new file mode 100644 index 0000000..8ee1e57 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/channelmanager.h @@ -0,0 +1,316 @@ +/* + * 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_SESSION_MEDIA_CHANNELMANAGER_H_ +#define TALK_SESSION_MEDIA_CHANNELMANAGER_H_ + +#include +#include + +#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" +#include "talk/media/base/mediaengine.h" +#include "talk/p2p/base/session.h" +#include "talk/session/media/voicechannel.h" + +namespace cricket { + +class Soundclip; +class VideoProcessor; +class VoiceChannel; +class VoiceProcessor; + +// ChannelManager allows the MediaEngine to run on a separate thread, and takes +// care of marshalling calls between threads. It also creates and keeps track of +// voice and video channels; by doing so, it can temporarily pause all the +// channels when a new audio or video device is chosen. The voice and video +// channels are stored in separate vectors, to easily allow operations on just +// voice or just video channels. +// ChannelManager also allows the application to discover what devices it has +// using device manager. +class ChannelManager : public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: +#if !defined(DISABLE_MEDIA_ENGINE_FACTORY) + // Creates the channel manager, and specifies the worker thread to use. + explicit ChannelManager(talk_base::Thread* worker); +#endif + + // For testing purposes. Allows the media engine and data media + // engine and dev manager to be mocks. The ChannelManager takes + // ownership of these objects. + ChannelManager(MediaEngineInterface* me, + DataEngineInterface* dme, + DeviceManagerInterface* dm, + CaptureManager* cm, + talk_base::Thread* worker); + // Same as above, but gives an easier default DataEngine. + ChannelManager(MediaEngineInterface* me, + DeviceManagerInterface* dm, + talk_base::Thread* worker); + ~ChannelManager(); + + // Accessors for the worker thread, allowing it to be set after construction, + // but before Init. set_worker_thread will return false if called after Init. + talk_base::Thread* worker_thread() const { return worker_thread_; } + bool set_worker_thread(talk_base::Thread* thread) { + if (initialized_) return false; + worker_thread_ = thread; + return true; + } + + // Gets capabilities. Can be called prior to starting the media engine. + int GetCapabilities(); + + // Retrieves the list of supported audio & video codec types. + // Can be called before starting the media engine. + void GetSupportedAudioCodecs(std::vector* codecs) const; + void GetSupportedAudioRtpHeaderExtensions(RtpHeaderExtensions* ext) const; + void GetSupportedVideoCodecs(std::vector* codecs) const; + void GetSupportedVideoRtpHeaderExtensions(RtpHeaderExtensions* ext) const; + void GetSupportedDataCodecs(std::vector* codecs) const; + + // Indicates whether the media engine is started. + bool initialized() const { return initialized_; } + // Starts up the media engine. + bool Init(); + // Shuts down the media engine. + void Terminate(); + + // The operations below all occur on the worker thread. + + // Creates a voice channel, to be associated with the specified session. + VoiceChannel* CreateVoiceChannel( + BaseSession* session, const std::string& content_name, bool rtcp); + // Destroys a voice channel created with the Create API. + void DestroyVoiceChannel(VoiceChannel* voice_channel); + // Creates a video channel, synced with the specified voice channel, and + // associated with the specified session. + VideoChannel* CreateVideoChannel( + BaseSession* session, const std::string& content_name, bool rtcp, + VoiceChannel* voice_channel); + // Destroys a video channel created with the Create API. + void DestroyVideoChannel(VideoChannel* video_channel); + DataChannel* CreateDataChannel( + BaseSession* session, const std::string& content_name, + bool rtcp, DataChannelType data_channel_type); + // Destroys a data channel created with the Create API. + void DestroyDataChannel(DataChannel* data_channel); + + // Creates a soundclip. + Soundclip* CreateSoundclip(); + // Destroys a soundclip created with the Create API. + void DestroySoundclip(Soundclip* soundclip); + + // Indicates whether any channels exist. + bool has_channels() const { + return (!voice_channels_.empty() || !video_channels_.empty() || + !soundclips_.empty()); + } + + // Configures the audio and video devices. A null pointer can be passed to + // GetAudioOptions() for any parameter of no interest. + bool GetAudioOptions(std::string* wave_in_device, + std::string* wave_out_device, + AudioOptions* options); + bool SetAudioOptions(const std::string& wave_in_device, + const std::string& wave_out_device, + const AudioOptions& options); + bool GetOutputVolume(int* level); + bool SetOutputVolume(int level); + bool IsSameCapturer(const std::string& capturer_name, + VideoCapturer* capturer); + // TODO(noahric): Nearly everything called "device" in this API is actually a + // device name, so this should really be GetCaptureDeviceName, and the + // next method should be GetCaptureDevice. + bool GetCaptureDevice(std::string* cam_device); + // Gets the current capture Device. + bool GetVideoCaptureDevice(Device* device); + // Create capturer based on what has been set in SetCaptureDevice(). + VideoCapturer* CreateVideoCapturer(); + bool SetCaptureDevice(const std::string& cam_device); + bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config); + // RTX will be enabled/disabled in engines that support it. The supporting + // engines will start offering an RTX codec. Must be called before Init(). + bool SetVideoRtxEnabled(bool enable); + + // Starts/stops the local microphone and enables polling of the input level. + bool SetLocalMonitor(bool enable); + bool monitoring() const { return monitoring_; } + // Sets the local renderer where to renderer the local camera. + bool SetLocalRenderer(VideoRenderer* renderer); + bool capturing() const { return capturing_; } + + // Configures the logging output of the mediaengine(s). + void SetVoiceLogging(int level, const char* filter); + void SetVideoLogging(int level, const char* filter); + + // The channel manager handles the Tx side for Video processing, + // as well as Tx and Rx side for Voice processing. + // (The Rx Video processing will go throug the simplerenderingmanager, + // to be implemented). + bool RegisterVideoProcessor(VideoCapturer* capturer, + VideoProcessor* processor); + bool UnregisterVideoProcessor(VideoCapturer* capturer, + VideoProcessor* processor); + bool RegisterVoiceProcessor(uint32 ssrc, + VoiceProcessor* processor, + MediaProcessorDirection direction); + bool UnregisterVoiceProcessor(uint32 ssrc, + VoiceProcessor* processor, + MediaProcessorDirection direction); + // The following are done in the new "CaptureManager" style that + // all local video capturers, processors, and managers should move to. + // TODO(pthatcher): Make methods nicer by having start return a handle that + // can be used for stop and restart, rather than needing to pass around + // formats a a pseudo-handle. + bool StartVideoCapture(VideoCapturer* video_capturer, + const VideoFormat& video_format); + // When muting, produce black frames then pause the camera. + // When unmuting, start the camera. Camera starts unmuted. + bool MuteToBlackThenPause(VideoCapturer* video_capturer, bool muted); + bool StopVideoCapture(VideoCapturer* video_capturer, + const VideoFormat& video_format); + bool RestartVideoCapture(VideoCapturer* video_capturer, + const VideoFormat& previous_format, + const VideoFormat& desired_format, + CaptureManager::RestartOptions options); + + bool AddVideoRenderer(VideoCapturer* capturer, VideoRenderer* renderer); + bool RemoveVideoRenderer(VideoCapturer* capturer, VideoRenderer* renderer); + bool IsScreencastRunning() const; + + // The operations below occur on the main thread. + + bool GetAudioInputDevices(std::vector* names); + bool GetAudioOutputDevices(std::vector* names); + bool GetVideoCaptureDevices(std::vector* names); + 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 SignalVideoCaptureStateChange; + + // Returns the current selected device. Note: Subtly different from + // GetCaptureDevice(). See member video_device_ for more details. + // This API is mainly a hook used by unittests. + const std::string& video_device_name() const { return video_device_name_; } + + // TODO(hellner): Remove this function once the engine capturer has been + // removed. + VideoFormat GetStartCaptureFormat(); + + protected: + // Adds non-transient parameters which can only be changed through the + // options store. + bool SetAudioOptions(const std::string& wave_in_device, + const std::string& wave_out_device, + const AudioOptions& options, + int delay_offset); + int audio_delay_offset() const { return audio_delay_offset_; } + + private: + typedef std::vector VoiceChannels; + typedef std::vector VideoChannels; + typedef std::vector DataChannels; + typedef std::vector Soundclips; + + void Construct(MediaEngineInterface* me, + DataEngineInterface* dme, + DeviceManagerInterface* dm, + CaptureManager* cm, + talk_base::Thread* worker_thread); + void Terminate_w(); + VoiceChannel* CreateVoiceChannel_w( + BaseSession* session, const std::string& content_name, bool rtcp); + void DestroyVoiceChannel_w(VoiceChannel* voice_channel); + VideoChannel* CreateVideoChannel_w( + BaseSession* session, const std::string& content_name, bool rtcp, + VoiceChannel* voice_channel); + void DestroyVideoChannel_w(VideoChannel* video_channel); + DataChannel* CreateDataChannel_w( + BaseSession* session, const std::string& content_name, + bool rtcp, DataChannelType data_channel_type); + void DestroyDataChannel_w(DataChannel* data_channel); + Soundclip* CreateSoundclip_w(); + void DestroySoundclip_w(Soundclip* soundclip); + bool SetAudioOptions_w(const AudioOptions& options, int delay_offset, + const Device* in_dev, const Device* out_dev); + bool SetCaptureDevice_w(const Device* cam_device); + void OnVideoCaptureStateChange(VideoCapturer* capturer, + CaptureState result); + bool RegisterVideoProcessor_w(VideoCapturer* capturer, + VideoProcessor* processor); + bool UnregisterVideoProcessor_w(VideoCapturer* capturer, + VideoProcessor* processor); + bool IsScreencastRunning_w() const; + virtual void OnMessage(talk_base::Message *message); + + talk_base::scoped_ptr media_engine_; + talk_base::scoped_ptr data_media_engine_; + talk_base::scoped_ptr device_manager_; + talk_base::scoped_ptr capture_manager_; + bool initialized_; + talk_base::Thread* main_thread_; + talk_base::Thread* worker_thread_; + + VoiceChannels voice_channels_; + VideoChannels video_channels_; + DataChannels data_channels_; + Soundclips soundclips_; + + std::string audio_in_device_; + std::string audio_out_device_; + AudioOptions audio_options_; + int audio_delay_offset_; + int audio_output_volume_; + std::string camera_device_; + VideoEncoderConfig default_video_encoder_config_; + VideoRenderer* local_renderer_; + bool enable_rtx_; + + bool capturing_; + bool monitoring_; + + // String containing currently set device. Note that this string is subtly + // different from camera_device_. E.g. camera_device_ will list unplugged + // but selected devices while this sting will be empty or contain current + // selected device. + // TODO(hellner): refactor the code such that there is no need to keep two + // strings for video devices that have subtle differences in behavior. + std::string video_device_name_; +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_CHANNELMANAGER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/currentspeakermonitor.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/currentspeakermonitor.h new file mode 100644 index 0000000..1367581 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/currentspeakermonitor.h @@ -0,0 +1,120 @@ +/* + * 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. + */ + +// CurrentSpeakerMonitor monitors the audio levels for a session and determines +// which participant is currently speaking. + +#ifndef TALK_SESSION_MEDIA_CURRENTSPEAKERMONITOR_H_ +#define TALK_SESSION_MEDIA_CURRENTSPEAKERMONITOR_H_ + +#include + +#include "talk/base/basictypes.h" +#include "talk/base/sigslot.h" + +namespace cricket { + +class BaseSession; +class Call; +class Session; +struct AudioInfo; +struct MediaStreams; + +class AudioSourceContext { + public: + sigslot::signal2 + SignalAudioMonitor; + sigslot::signal2 + SignalMediaStreamsReset; + sigslot::signal4 + 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(AudioSourceContext* call, BaseSession* session); + ~CurrentSpeakerMonitor(); + + BaseSession* session() const { return session_; } + + void Start(); + void Stop(); + + // Used by tests. Note that the actual minimum time between switches + // enforced by the monitor will be the given value plus or minus the + // resolution of the system clock. + 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. + sigslot::signal2 SignalUpdate; + + private: + void OnAudioMonitor(AudioSourceContext* call, const AudioInfo& info); + void OnMediaStreamsUpdate(AudioSourceContext* call, + 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 + // "twitchiness". + enum SpeakingState { + SS_NOT_SPEAKING, + SS_MIGHT_BE_SPEAKING, + SS_SPEAKING, + SS_WAS_SPEAKING_RECENTLY1, + SS_WAS_SPEAKING_RECENTLY2 + }; + + bool started_; + AudioSourceContext* audio_source_context_; + BaseSession* session_; + std::map ssrc_to_speaking_state_map_; + uint32 current_speaker_ssrc_; + // To prevent overswitching, switching is disabled for some time after a + // switch is made. This gives us the earliest time a switch is permitted. + uint32 earliest_permitted_switch_time_; + uint32 min_time_between_switches_; +}; + +} + +#endif // TALK_SESSION_MEDIA_CURRENTSPEAKERMONITOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/externalhmac.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/externalhmac.h new file mode 100644 index 0000000..71fab40 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/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/thirdparties/common/include/webrtc-sdk/talk/session/media/mediamessages.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediamessages.h new file mode 100644 index 0000000..63b682d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediamessages.h @@ -0,0 +1,169 @@ +/* + * 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. + */ + +/* + * A collection of functions and types for serializing and + * deserializing Jingle session messages related to media. + * Specificially, the and messages. They are not yet + * standardized, but their current documentation can be found at: + * goto/jinglemuc + */ + +#ifndef TALK_SESSION_MEDIA_MEDIAMESSAGES_H_ +#define TALK_SESSION_MEDIA_MEDIAMESSAGES_H_ + +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/media/base/mediachannel.h" // For RtpHeaderExtension +#include "talk/media/base/streamparams.h" +#include "talk/p2p/base/parsing.h" +#include "talk/p2p/base/sessiondescription.h" + +namespace cricket { + +// A collection of audio and video and data streams. Most of the +// methods are merely for convenience. Many of these methods are keyed +// by ssrc, which is the source identifier in the RTP spec +// (http://tools.ietf.org/html/rfc3550). +struct MediaStreams { + public: + MediaStreams() {} + void CopyFrom(const MediaStreams& sources); + + bool empty() const { + return audio_.empty() && video_.empty() && data_.empty(); + } + + std::vector* mutable_audio() { return &audio_; } + std::vector* mutable_video() { return &video_; } + std::vector* mutable_data() { return &data_; } + const std::vector& audio() const { return audio_; } + const std::vector& video() const { return video_; } + const std::vector& data() const { return data_; } + + // Gets a stream, returning true if found. + bool GetAudioStream( + const StreamSelector& selector, StreamParams* stream); + bool GetVideoStream( + const StreamSelector& selector, StreamParams* stream); + bool GetDataStream( + const StreamSelector& selector, StreamParams* stream); + // Adds a stream. + void AddAudioStream(const StreamParams& stream); + void AddVideoStream(const StreamParams& stream); + void AddDataStream(const StreamParams& stream); + // Removes a stream, returning true if found and removed. + bool RemoveAudioStream(const StreamSelector& selector); + bool RemoveVideoStream(const StreamSelector& selector); + bool RemoveDataStream(const StreamSelector& selector); + + private: + std::vector audio_; + std::vector video_; + std::vector data_; + + DISALLOW_COPY_AND_ASSIGN(MediaStreams); +}; + +// In a message, there are a number of views specified. This +// represents one such view. We currently only support "static" +// views. +struct StaticVideoView { + StaticVideoView(const StreamSelector& selector, + int width, int height, int framerate) + : selector(selector), + width(width), + height(height), + framerate(framerate), + preference(0) { + } + + StreamSelector selector; + int width; + int height; + int framerate; + int preference; +}; + +typedef std::vector StaticVideoViews; + +// Represents a whole view request message, which contains many views. +struct ViewRequest { + StaticVideoViews static_video_views; +}; + +// If the parent element (usually ) is a jingle view. +bool IsJingleViewRequest(const buzz::XmlElement* action_elem); + +// Parses a view request from the parent element (usually +// ). If it fails, it returns false and fills an error +// message. +bool ParseJingleViewRequest(const buzz::XmlElement* action_elem, + ViewRequest* view_request, + ParseError* error); + +// Serializes a view request to XML. If it fails, returns false and +// fills in an error message. +bool WriteJingleViewRequest(const std::string& content_name, + const ViewRequest& view, + XmlElements* elems, + WriteError* error); + +// TODO(pthatcher): Get rid of legacy source notify and replace with +// description-info as soon as reflector is capable of sending it. +bool IsSourcesNotify(const buzz::XmlElement* action_elem); + +// If the given elem has . +bool HasJingleStreams(const buzz::XmlElement* desc_elem); + +// Parses streams from a jingle . If it fails, returns +// false and fills an error message. +bool ParseJingleStreams(const buzz::XmlElement* desc_elem, + std::vector* streams, + ParseError* error); + +// Write a element to the parent_elem. +void WriteJingleStreams(const std::vector& streams, + buzz::XmlElement* parent_elem); + +// Parses rtp header extensions from a jingle . If it +// fails, returns false and fills an error message. +bool ParseJingleRtpHeaderExtensions( + const buzz::XmlElement* desc_elem, + std::vector* hdrexts, + ParseError* error); + +// Writes elements to the parent_elem. +void WriteJingleRtpHeaderExtensions( + const std::vector& hdrexts, + buzz::XmlElement* parent_elem); + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_MEDIAMESSAGES_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/mediamonitor.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediamonitor.h new file mode 100644 index 0000000..1675d76 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediamonitor.h @@ -0,0 +1,98 @@ +/* + * libjingle + * Copyright 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. + */ + +// Class to collect statistics from a media channel + +#ifndef TALK_SESSION_MEDIA_MEDIAMONITOR_H_ +#define TALK_SESSION_MEDIA_MEDIAMONITOR_H_ + +#include "talk/base/criticalsection.h" +#include "talk/base/sigslot.h" +#include "talk/base/thread.h" +#include "talk/media/base/mediachannel.h" + +namespace cricket { + +// The base MediaMonitor class, independent of voice and video. +class MediaMonitor : public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + MediaMonitor(talk_base::Thread* worker_thread, + talk_base::Thread* monitor_thread); + ~MediaMonitor(); + + void Start(uint32 milliseconds); + void Stop(); + + protected: + void OnMessage(talk_base::Message *message); + void PollMediaChannel(); + virtual void GetStats() = 0; + virtual void Update() = 0; + + talk_base::CriticalSection crit_; + talk_base::Thread* worker_thread_; + talk_base::Thread* monitor_thread_; + bool monitoring_; + uint32 rate_; +}; + +// Templatized MediaMonitor that can deal with different kinds of media. +template +class MediaMonitorT : public MediaMonitor { + public: + MediaMonitorT(MC* media_channel, talk_base::Thread* worker_thread, + talk_base::Thread* monitor_thread) + : MediaMonitor(worker_thread, monitor_thread), + media_channel_(media_channel) {} + sigslot::signal2 SignalUpdate; + + protected: + // These routines assume the crit_ lock is held by the calling thread. + virtual void GetStats() { + media_info_.Clear(); + media_channel_->GetStats(&media_info_); + } + virtual void Update() { + MI stats(media_info_); + crit_.Leave(); + SignalUpdate(media_channel_, stats); + crit_.Enter(); + } + + private: + MC* media_channel_; + MI media_info_; +}; + +typedef MediaMonitorT VoiceMediaMonitor; +typedef MediaMonitorT VideoMediaMonitor; +typedef MediaMonitorT DataMediaMonitor; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_MEDIAMONITOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/mediarecorder.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediarecorder.h new file mode 100644 index 0000000..5f08ec4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediarecorder.h @@ -0,0 +1,119 @@ +/* + * 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. + */ + +#ifndef TALK_SESSION_MEDIA_MEDIARECORDER_H_ +#define TALK_SESSION_MEDIA_MEDIARECORDER_H_ + +#include +#include + +#include "talk/base/criticalsection.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sigslot.h" +#include "talk/session/media/channel.h" +#include "talk/session/media/mediasink.h" + +namespace talk_base { +class Pathname; +class FileStream; +} + +namespace cricket { + +class BaseChannel; +class VideoChannel; +class VoiceChannel; +class RtpDumpWriter; + +// RtpDumpSink implements MediaSinkInterface by dumping the RTP/RTCP packets to +// a file. +class RtpDumpSink : public MediaSinkInterface, public sigslot::has_slots<> { + public: + // Takes ownership of stream. + explicit RtpDumpSink(talk_base::StreamInterface* stream); + virtual ~RtpDumpSink(); + + virtual void SetMaxSize(size_t size); + virtual bool Enable(bool enable); + virtual bool IsEnabled() const { return recording_; } + virtual void OnPacket(const void* data, size_t size, bool rtcp); + virtual void set_packet_filter(int filter); + int packet_filter() const { return packet_filter_; } + void Flush(); + + private: + size_t max_size_; + bool recording_; + int packet_filter_; + talk_base::scoped_ptr stream_; + talk_base::scoped_ptr writer_; + talk_base::CriticalSection critical_section_; + + DISALLOW_COPY_AND_ASSIGN(RtpDumpSink); +}; + +class MediaRecorder { + public: + MediaRecorder(); + virtual ~MediaRecorder(); + + bool AddChannel(VoiceChannel* channel, + talk_base::StreamInterface* send_stream, + talk_base::StreamInterface* recv_stream, + int filter); + bool AddChannel(VideoChannel* channel, + talk_base::StreamInterface* send_stream, + talk_base::StreamInterface* recv_stream, + int filter); + void RemoveChannel(BaseChannel* channel, SinkType type); + bool EnableChannel(BaseChannel* channel, bool enable_send, bool enable_recv, + SinkType type); + void FlushSinks(); + + private: + struct SinkPair { + bool video_channel; + int filter; + talk_base::scoped_ptr send_sink; + talk_base::scoped_ptr recv_sink; + }; + + bool InternalAddChannel(BaseChannel* channel, + bool video_channel, + talk_base::StreamInterface* send_stream, + talk_base::StreamInterface* recv_stream, + int filter); + + std::map sinks_; + talk_base::CriticalSection critical_section_; + + DISALLOW_COPY_AND_ASSIGN(MediaRecorder); +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_MEDIARECORDER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/mediasession.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediasession.h new file mode 100644 index 0000000..4b30fea --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediasession.h @@ -0,0 +1,522 @@ +/* + * 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. + */ + +// Types and classes used in media session descriptions. + +#ifndef TALK_SESSION_MEDIA_MEDIASESSION_H_ +#define TALK_SESSION_MEDIA_MEDIASESSION_H_ + +#include +#include +#include + +#include "talk/base/scoped_ptr.h" +#include "talk/media/base/codec.h" +#include "talk/media/base/constants.h" +#include "talk/media/base/cryptoparams.h" +#include "talk/media/base/mediachannel.h" +#include "talk/media/base/mediaengine.h" // For DataChannelType +#include "talk/media/base/streamparams.h" +#include "talk/p2p/base/sessiondescription.h" +#include "talk/p2p/base/transport.h" +#include "talk/p2p/base/transportdescriptionfactory.h" + +namespace cricket { + +class ChannelManager; +typedef std::vector AudioCodecs; +typedef std::vector VideoCodecs; +typedef std::vector DataCodecs; +typedef std::vector CryptoParamsVec; +typedef std::vector RtpHeaderExtensions; + +enum MediaType { + MEDIA_TYPE_AUDIO, + MEDIA_TYPE_VIDEO, + MEDIA_TYPE_DATA +}; + +std::string MediaTypeToString(MediaType type); + +enum MediaContentDirection { + MD_INACTIVE, + MD_SENDONLY, + MD_RECVONLY, + 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 kMediaProtocolRtpPrefix[]; + +extern const char kMediaProtocolSctp[]; +extern const char kMediaProtocolDtlsSctp[]; + +// Options to control how session descriptions are generated. +const int kAutoBandwidth = -1; +const int kBufferedModeDisabled = 0; + +struct MediaSessionOptions { + MediaSessionOptions() : + has_audio(true), // Audio enabled by default. + has_video(false), + data_channel_type(DCT_NONE), + is_muc(false), + vad_enabled(true), // When disabled, removes all CN codecs from SDP. + rtcp_mux_enabled(true), + bundle_enabled(false), + video_bandwidth(kAutoBandwidth), + data_bandwidth(kDataMaxBandwidth) { + } + + bool has_data() const { return data_channel_type != DCT_NONE; } + + // Add a stream with MediaType type and id. + // All streams with the same sync_label will get the same CNAME. + // All ids must be unique. + void AddStream(MediaType type, + const std::string& id, + const std::string& sync_label); + void AddVideoStream(const std::string& id, + const std::string& sync_label, + int num_sim_layers); + void RemoveStream(MediaType type, const std::string& id); + + + // Helper function. + void AddStreamInternal(MediaType type, + const std::string& id, + const std::string& sync_label, + int num_sim_layers); + + bool has_audio; + bool has_video; + DataChannelType data_channel_type; + bool is_muc; + bool vad_enabled; + bool rtcp_mux_enabled; + bool bundle_enabled; + // bps. -1 == auto. + int video_bandwidth; + int data_bandwidth; + TransportOptions transport_options; + + struct Stream { + Stream(MediaType type, + const std::string& id, + const std::string& sync_label, + int num_sim_layers) + : type(type), id(id), sync_label(sync_label), + num_sim_layers(num_sim_layers) { + } + MediaType type; + std::string id; + std::string sync_label; + int num_sim_layers; + }; + + typedef std::vector Streams; + Streams streams; +}; + +// "content" (as used in XEP-0166) descriptions for voice and video. +class MediaContentDescription : public ContentDescription { + public: + MediaContentDescription() + : rtcp_mux_(false), + bandwidth_(kAutoBandwidth), + crypto_required_(CT_NONE), + rtp_header_extensions_set_(false), + multistream_(false), + conference_mode_(false), + partial_(false), + buffered_mode_latency_(kBufferedModeDisabled), + direction_(MD_SENDRECV) { + } + + virtual MediaType type() const = 0; + virtual bool has_codecs() const = 0; + + // |protocol| is the expected media transport protocol, such as RTP/AVPF, + // RTP/SAVPF or SCTP/DTLS. + std::string protocol() const { return protocol_; } + void set_protocol(const std::string& protocol) { protocol_ = protocol; } + + MediaContentDirection direction() const { return direction_; } + void set_direction(MediaContentDirection direction) { + direction_ = direction; + } + + bool rtcp_mux() const { return rtcp_mux_; } + void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; } + + int bandwidth() const { return bandwidth_; } + void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; } + + const std::vector& cryptos() const { return cryptos_; } + void AddCrypto(const CryptoParams& params) { + cryptos_.push_back(params); + } + void set_cryptos(const std::vector& cryptos) { + cryptos_ = cryptos; + } + + CryptoType crypto_required() const { return crypto_required_; } + void set_crypto_required(CryptoType type) { + crypto_required_ = type; + } + + const RtpHeaderExtensions& rtp_header_extensions() const { + return rtp_header_extensions_; + } + void set_rtp_header_extensions(const RtpHeaderExtensions& extensions) { + rtp_header_extensions_ = extensions; + rtp_header_extensions_set_ = true; + } + void AddRtpHeaderExtension(const RtpHeaderExtension& ext) { + rtp_header_extensions_.push_back(ext); + rtp_header_extensions_set_ = true; + } + void ClearRtpHeaderExtensions() { + rtp_header_extensions_.clear(); + rtp_header_extensions_set_ = true; + } + // We can't always tell if an empty list of header extensions is + // because the other side doesn't support them, or just isn't hooked up to + // signal them. For now we assume an empty list means no signaling, but + // provide the ClearRtpHeaderExtensions method to allow "no support" to be + // clearly indicated (i.e. when derived from other information). + bool rtp_header_extensions_set() const { + return rtp_header_extensions_set_; + } + // True iff the client supports multiple streams. + void set_multistream(bool multistream) { multistream_ = multistream; } + bool multistream() const { return multistream_; } + const StreamParamsVec& streams() const { + return streams_; + } + // TODO(pthatcher): Remove this by giving mediamessage.cc access + // to MediaContentDescription + StreamParamsVec& mutable_streams() { + return streams_; + } + void AddStream(const StreamParams& stream) { + streams_.push_back(stream); + } + // Legacy streams have an ssrc, but nothing else. + void AddLegacyStream(uint32 ssrc) { + streams_.push_back(StreamParams::CreateLegacy(ssrc)); + } + void AddLegacyStream(uint32 ssrc, uint32 fid_ssrc) { + StreamParams sp = StreamParams::CreateLegacy(ssrc); + sp.AddFidSsrc(ssrc, fid_ssrc); + streams_.push_back(sp); + } + // Sets the CNAME of all StreamParams if it have not been set. + // This can be used to set the CNAME of legacy streams. + void SetCnameIfEmpty(const std::string& cname) { + for (cricket::StreamParamsVec::iterator it = streams_.begin(); + it != streams_.end(); ++it) { + if (it->cname.empty()) + it->cname = cname; + } + } + uint32 first_ssrc() const { + if (streams_.empty()) { + return 0; + } + return streams_[0].first_ssrc(); + } + bool has_ssrcs() const { + if (streams_.empty()) { + return false; + } + return streams_[0].has_ssrcs(); + } + + void set_conference_mode(bool enable) { conference_mode_ = enable; } + bool conference_mode() const { return conference_mode_; } + + void set_partial(bool partial) { partial_ = partial; } + bool partial() const { return partial_; } + + void set_buffered_mode_latency(int latency) { + buffered_mode_latency_ = latency; + } + int buffered_mode_latency() const { return buffered_mode_latency_; } + + protected: + bool rtcp_mux_; + int bandwidth_; + std::string protocol_; + std::vector cryptos_; + CryptoType crypto_required_; + std::vector rtp_header_extensions_; + bool rtp_header_extensions_set_; + bool multistream_; + StreamParamsVec streams_; + bool conference_mode_; + bool partial_; + int buffered_mode_latency_; + MediaContentDirection direction_; +}; + +template +class MediaContentDescriptionImpl : public MediaContentDescription { + public: + struct PreferenceSort { + bool operator()(C a, C b) { return a.preference > b.preference; } + }; + + const std::vector& codecs() const { return codecs_; } + void set_codecs(const std::vector& codecs) { codecs_ = codecs; } + virtual bool has_codecs() const { return !codecs_.empty(); } + bool HasCodec(int id) { + bool found = false; + for (typename std::vector::iterator iter = codecs_.begin(); + iter != codecs_.end(); ++iter) { + if (iter->id == id) { + found = true; + break; + } + } + return found; + } + void AddCodec(const C& codec) { + codecs_.push_back(codec); + } + void AddOrReplaceCodec(const C& codec) { + for (typename std::vector::iterator iter = codecs_.begin(); + iter != codecs_.end(); ++iter) { + if (iter->id == codec.id) { + *iter = codec; + return; + } + } + AddCodec(codec); + } + void AddCodecs(const std::vector& codecs) { + typename std::vector::const_iterator codec; + for (codec = codecs.begin(); codec != codecs.end(); ++codec) { + AddCodec(*codec); + } + } + void SortCodecs() { + std::sort(codecs_.begin(), codecs_.end(), PreferenceSort()); + } + + private: + std::vector codecs_; +}; + +class AudioContentDescription : public MediaContentDescriptionImpl { + public: + AudioContentDescription() : + agc_minus_10db_(false) {} + + virtual ContentDescription* Copy() const { + return new AudioContentDescription(*this); + } + virtual MediaType type() const { return MEDIA_TYPE_AUDIO; } + + const std::string &lang() const { return lang_; } + void set_lang(const std::string &lang) { lang_ = lang; } + + bool agc_minus_10db() const { return agc_minus_10db_; } + void set_agc_minus_10db(bool enable) { + agc_minus_10db_ = enable; + } + + private: + bool agc_minus_10db_; + + private: + std::string lang_; +}; + +class VideoContentDescription : public MediaContentDescriptionImpl { + public: + virtual ContentDescription* Copy() const { + return new VideoContentDescription(*this); + } + virtual MediaType type() const { return MEDIA_TYPE_VIDEO; } +}; + +class DataContentDescription : public MediaContentDescriptionImpl { + public: + virtual ContentDescription* Copy() const { + return new DataContentDescription(*this); + } + virtual MediaType type() const { return MEDIA_TYPE_DATA; } +}; + +// Creates media session descriptions according to the supplied codecs and +// other fields, as well as the supplied per-call options. +// When creating answers, performs the appropriate negotiation +// of the various fields to determine the proper result. +class MediaSessionDescriptionFactory { + public: + // Default ctor; use methods below to set configuration. + // The TransportDescriptionFactory is not owned by MediaSessionDescFactory, + // so it must be kept alive by the user of this class. + explicit MediaSessionDescriptionFactory( + const TransportDescriptionFactory* factory); + // This helper automatically sets up the factory to get its configuration + // from the specified ChannelManager. + MediaSessionDescriptionFactory(ChannelManager* cmanager, + const TransportDescriptionFactory* factory); + + const AudioCodecs& audio_codecs() const { return audio_codecs_; } + void set_audio_codecs(const AudioCodecs& codecs) { audio_codecs_ = codecs; } + void set_audio_rtp_header_extensions(const RtpHeaderExtensions& extensions) { + audio_rtp_extensions_ = extensions; + } + const RtpHeaderExtensions& audio_rtp_header_extensions() const { + return audio_rtp_extensions_; + } + const VideoCodecs& video_codecs() const { return video_codecs_; } + void set_video_codecs(const VideoCodecs& codecs) { video_codecs_ = codecs; } + void set_video_rtp_header_extensions(const RtpHeaderExtensions& extensions) { + video_rtp_extensions_ = extensions; + } + const RtpHeaderExtensions& video_rtp_header_extensions() const { + return video_rtp_extensions_; + } + const DataCodecs& data_codecs() const { return data_codecs_; } + void set_data_codecs(const DataCodecs& codecs) { data_codecs_ = codecs; } + SecurePolicy secure() const { return secure_; } + void set_secure(SecurePolicy s) { secure_ = s; } + // Decides if a StreamParams shall be added to the audio and video media + // content in SessionDescription when CreateOffer and CreateAnswer is called + // even if |options| don't include a Stream. This is needed to support legacy + // applications. |add_legacy_| is true per default. + void set_add_legacy_streams(bool add_legacy) { add_legacy_ = add_legacy; } + + SessionDescription* CreateOffer( + const MediaSessionOptions& options, + const SessionDescription* current_description) const; + SessionDescription* CreateAnswer( + const SessionDescription* offer, + const MediaSessionOptions& options, + const SessionDescription* current_description) const; + + private: + void GetCodecsToOffer(const SessionDescription* current_description, + AudioCodecs* audio_codecs, + VideoCodecs* video_codecs, + DataCodecs* data_codecs) const; + void GetRtpHdrExtsToOffer(const SessionDescription* current_description, + RtpHeaderExtensions* audio_extensions, + RtpHeaderExtensions* video_extensions) const; + bool AddTransportOffer( + const std::string& content_name, + const TransportOptions& transport_options, + const SessionDescription* current_desc, + SessionDescription* offer) const; + + TransportDescription* CreateTransportAnswer( + const std::string& content_name, + const SessionDescription* offer_desc, + const TransportOptions& transport_options, + const SessionDescription* current_desc) const; + + bool AddTransportAnswer( + const std::string& content_name, + const TransportDescription& transport_desc, + SessionDescription* answer_desc) const; + + AudioCodecs audio_codecs_; + RtpHeaderExtensions audio_rtp_extensions_; + VideoCodecs video_codecs_; + RtpHeaderExtensions video_rtp_extensions_; + DataCodecs data_codecs_; + SecurePolicy secure_; + bool add_legacy_; + std::string lang_; + const TransportDescriptionFactory* transport_desc_factory_; +}; + +// Convenience functions. +bool IsMediaContent(const ContentInfo* content); +bool IsAudioContent(const ContentInfo* content); +bool IsVideoContent(const ContentInfo* content); +bool IsDataContent(const ContentInfo* content); +const ContentInfo* GetFirstAudioContent(const ContentInfos& contents); +const ContentInfo* GetFirstVideoContent(const ContentInfos& contents); +const ContentInfo* GetFirstDataContent(const ContentInfos& contents); +const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc); +const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc); +const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc); +const AudioContentDescription* GetFirstAudioContentDescription( + const SessionDescription* sdesc); +const VideoContentDescription* GetFirstVideoContentDescription( + const SessionDescription* sdesc); +const DataContentDescription* GetFirstDataContentDescription( + const SessionDescription* sdesc); +bool GetStreamBySsrc( + const SessionDescription* sdesc, MediaType media_type, + uint32 ssrc, StreamParams* stream_out); +bool GetStreamByIds( + const SessionDescription* sdesc, MediaType media_type, + const std::string& groupid, const std::string& id, + StreamParams* stream_out); + +// Functions for translating media candidate names. + +// For converting between media ICE component and G-ICE channel +// names. For example: +// "rtp" <=> 1 +// "rtcp" <=> 2 +// "video_rtp" <=> 1 +// "video_rtcp" <=> 2 +// Will not convert in the general case of arbitrary channel names, +// but is useful for cases where we have candidates for media +// channels. +// returns false if there is no mapping. +bool GetMediaChannelNameFromComponent( + int component, cricket::MediaType media_type, std::string* channel_name); +bool GetMediaComponentFromChannelName( + const std::string& channel_name, int* component); +bool GetMediaTypeFromChannelName( + const std::string& channel_name, cricket::MediaType* media_type); + +void GetSupportedAudioCryptoSuites(std::vector* crypto_suites); +void GetSupportedVideoCryptoSuites(std::vector* crypto_suites); +void GetSupportedDataCryptoSuites(std::vector* crypto_suites); +void GetSupportedDefaultCryptoSuites(std::vector* crypto_suites); +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_MEDIASESSION_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/mediasessionclient.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediasessionclient.h new file mode 100644 index 0000000..9727a67 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediasessionclient.h @@ -0,0 +1,175 @@ +/* + * 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_SESSION_MEDIA_MEDIASESSIONCLIENT_H_ +#define TALK_SESSION_MEDIA_MEDIASESSIONCLIENT_H_ + +#include +#include +#include +#include +#include "talk/base/messagequeue.h" +#include "talk/base/sigslot.h" +#include "talk/base/sigslotrepeater.h" +#include "talk/base/thread.h" +#include "talk/media/base/cryptoparams.h" +#include "talk/p2p/base/session.h" +#include "talk/p2p/base/sessionclient.h" +#include "talk/p2p/base/sessiondescription.h" +#include "talk/p2p/base/sessionmanager.h" +#include "talk/session/media/call.h" +#include "talk/session/media/channelmanager.h" +#include "talk/session/media/mediasession.h" + +namespace cricket { + +class Call; + +class MediaSessionClient : public SessionClient, public sigslot::has_slots<> { + public: +#if !defined(DISABLE_MEDIA_ENGINE_FACTORY) + MediaSessionClient(const buzz::Jid& jid, SessionManager *manager); +#endif + // Alternative constructor, allowing injection of media_engine + // and device_manager. + MediaSessionClient(const buzz::Jid& jid, SessionManager *manager, + MediaEngineInterface* media_engine, + DataEngineInterface* data_media_engine, + DeviceManagerInterface* device_manager); + ~MediaSessionClient(); + + const buzz::Jid &jid() const { return jid_; } + SessionManager* session_manager() const { return session_manager_; } + ChannelManager* channel_manager() const { return channel_manager_; } + + // Return mapping of call ids to Calls. + const std::map& calls() const { return calls_; } + + // The settings below combine with the settings on SessionManager to choose + + // whether SDES-SRTP, DTLS-SRTP, or no security should be used. The possible + // combinations are shown in the following table. Note that where either DTLS + // or SDES is possible, DTLS is preferred. Thus to require either SDES or + // DTLS, but not mandate DTLS, set SDES to require and DTLS to enable. + // + // | SDES:Disable | SDES:Enable | SDES:Require | + // ----------------------------------------------------------------| + // DTLS:Disable | No SRTP | SDES Optional | SDES Mandatory | + // DTLS:Enable | DTLS Optional | DTLS/SDES Opt | DTLS/SDES Mand | + // DTLS:Require | DTLS Mandatory | DTLS Mandatory | DTLS Mandatory | + + // Control use of SDES-SRTP. + SecurePolicy secure() const { return desc_factory_.secure(); } + void set_secure(SecurePolicy s) { desc_factory_.set_secure(s); } + + // Control use of multiple sessions in a call. + void set_multisession_enabled(bool multisession_enabled) { + multisession_enabled_ = multisession_enabled; + } + + int GetCapabilities() { return channel_manager_->GetCapabilities(); } + + Call *CreateCall(); + void DestroyCall(Call *call); + + Call *GetFocus(); + void SetFocus(Call *call); + + void JoinCalls(Call *call_to_join, Call *call); + + bool GetAudioInputDevices(std::vector* names) { + return channel_manager_->GetAudioInputDevices(names); + } + bool GetAudioOutputDevices(std::vector* names) { + return channel_manager_->GetAudioOutputDevices(names); + } + bool GetVideoCaptureDevices(std::vector* names) { + return channel_manager_->GetVideoCaptureDevices(names); + } + + bool SetAudioOptions(const std::string& in_name, const std::string& out_name, + const AudioOptions& options) { + return channel_manager_->SetAudioOptions(in_name, out_name, options); + } + bool SetOutputVolume(int level) { + return channel_manager_->SetOutputVolume(level); + } + bool SetCaptureDevice(const std::string& cam_device) { + return channel_manager_->SetCaptureDevice(cam_device); + } + + SessionDescription* CreateOffer(const CallOptions& options) { + return desc_factory_.CreateOffer(options, NULL); + } + SessionDescription* CreateAnswer(const SessionDescription* offer, + const CallOptions& options) { + return desc_factory_.CreateAnswer(offer, options, NULL); + } + + sigslot::signal2 SignalFocus; + sigslot::signal1 SignalCallCreate; + sigslot::signal1 SignalCallDestroy; + sigslot::repeater0<> SignalDevicesChange; + + virtual bool ParseContent(SignalingProtocol protocol, + const buzz::XmlElement* elem, + ContentDescription** content, + ParseError* error); + virtual bool IsWritable(SignalingProtocol protocol, + const ContentDescription* content); + virtual bool WriteContent(SignalingProtocol protocol, + const ContentDescription* content, + buzz::XmlElement** elem, + WriteError* error); + + private: + void Construct(); + void OnSessionCreate(Session *session, bool received_initiate); + void OnSessionState(BaseSession *session, BaseSession::State state); + void OnSessionDestroy(Session *session); + Session *CreateSession(Call *call); + Session *CreateSession(const std::string& id, Call* call); + Call *FindCallByRemoteName(const std::string &remote_name); + + buzz::Jid jid_; + SessionManager* session_manager_; + Call *focus_call_; + ChannelManager *channel_manager_; + MediaSessionDescriptionFactory desc_factory_; + bool multisession_enabled_; + std::map calls_; + + // Maintain a mapping of session id to call. + typedef std::map SessionMap; + SessionMap session_map_; + + friend class Call; +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_MEDIASESSIONCLIENT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/mediasink.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediasink.h new file mode 100644 index 0000000..82b1661 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/mediasink.h @@ -0,0 +1,48 @@ +/* + * 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_SESSION_MEDIA_MEDIASINK_H_ +#define TALK_SESSION_MEDIA_MEDIASINK_H_ + +namespace cricket { + +// MediaSinkInterface is a sink to handle RTP and RTCP packets that are sent or +// received by a channel. +class MediaSinkInterface { + public: + virtual ~MediaSinkInterface() {} + + virtual void SetMaxSize(size_t size) = 0; + virtual bool Enable(bool enable) = 0; + virtual bool IsEnabled() const = 0; + virtual void OnPacket(const void* data, size_t size, bool rtcp) = 0; + virtual void set_packet_filter(int filter) = 0; +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_MEDIASINK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/rtcpmuxfilter.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/rtcpmuxfilter.h new file mode 100644 index 0000000..9fd4d8b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/rtcpmuxfilter.h @@ -0,0 +1,86 @@ +/* + * 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_SESSION_MEDIA_RTCPMUXFILTER_H_ +#define TALK_SESSION_MEDIA_RTCPMUXFILTER_H_ + +#include "talk/base/basictypes.h" +#include "talk/p2p/base/sessiondescription.h" + +namespace cricket { + +// RTCP Muxer, as defined in RFC 5761 (http://tools.ietf.org/html/rfc5761) +class RtcpMuxFilter { + public: + RtcpMuxFilter(); + + // Whether the filter is active, i.e. has RTCP mux been properly negotiated. + bool IsActive() const; + + // Specifies whether the offer indicates the use of RTCP mux. + bool SetOffer(bool offer_enable, ContentSource src); + + // Specifies whether the provisional answer indicates the use of RTCP mux. + bool SetProvisionalAnswer(bool answer_enable, ContentSource src); + + // Specifies whether the answer indicates the use of RTCP mux. + bool SetAnswer(bool answer_enable, ContentSource src); + + // Determines whether the specified packet is RTCP. + bool DemuxRtcp(const char* data, int len); + + private: + bool ExpectOffer(bool offer_enable, ContentSource source); + bool ExpectAnswer(ContentSource source); + enum State { + // RTCP mux filter unused. + ST_INIT, + // Offer with RTCP mux enabled received. + // RTCP mux filter is not active. + ST_RECEIVEDOFFER, + // Offer with RTCP mux enabled sent. + // RTCP mux filter can demux incoming packets but is not active. + ST_SENTOFFER, + // RTCP mux filter is active but the sent answer is only provisional. + // When the final answer is set, the state transitions to ST_ACTIVE or + // ST_INIT. + ST_SENTPRANSWER, + // RTCP mux filter is active but the received answer is only provisional. + // When the final answer is set, the state transitions to ST_ACTIVE or + // ST_INIT. + ST_RECEIVEDPRANSWER, + // Offer and answer set, RTCP mux enabled. It is not possible to de-activate + // the filter. + ST_ACTIVE + }; + State state_; + bool offer_enable_; +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_RTCPMUXFILTER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/soundclip.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/soundclip.h new file mode 100644 index 0000000..1b3bbed --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/soundclip.h @@ -0,0 +1,70 @@ +/* + * 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_SESSION_MEDIA_SOUNDCLIP_H_ +#define TALK_SESSION_MEDIA_SOUNDCLIP_H_ + +#include "talk/base/scoped_ptr.h" +#include "talk/media/base/mediaengine.h" + +namespace talk_base { + +class Thread; + +} + +namespace cricket { + +// Soundclip wraps SoundclipMedia to support marshalling calls to the proper +// thread. +class Soundclip : private talk_base::MessageHandler { + public: + Soundclip(talk_base::Thread* thread, SoundclipMedia* soundclip_media); + + // Plays a sound out to the speakers with the given audio stream. The stream + // must be 16-bit little-endian 16 kHz PCM. If a stream is already playing + // on this Soundclip, it is stopped. If clip is NULL, nothing is played. + // Returns whether it was successful. + bool PlaySound(const void* clip, + int len, + SoundclipMedia::SoundclipFlags flags); + + private: + bool PlaySound_w(const void* clip, + int len, + SoundclipMedia::SoundclipFlags flags); + + // From MessageHandler + virtual void OnMessage(talk_base::Message* message); + + talk_base::Thread* worker_thread_; + talk_base::scoped_ptr soundclip_media_; +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_SOUNDCLIP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/srtpfilter.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/srtpfilter.h new file mode 100644 index 0000000..7318444 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/srtpfilter.h @@ -0,0 +1,327 @@ +/* + * libjingle + * Copyright 2009 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_SRTPFILTER_H_ +#define TALK_SESSION_MEDIA_SRTPFILTER_H_ + +#include +#include +#include +#include + +#include "talk/base/basictypes.h" +#include "talk/base/scoped_ptr.h" +#include "talk/base/sigslotrepeater.h" +#include "talk/media/base/cryptoparams.h" +#include "talk/p2p/base/sessiondescription.h" + +// Forward declaration to avoid pulling in libsrtp headers here +struct srtp_event_data_t; +struct srtp_ctx_t; +typedef srtp_ctx_t* srtp_t; +struct srtp_policy_t; + +namespace cricket { + +// Cipher suite to use for SRTP. Typically a 80-bit HMAC will be used, except +// in applications (voice) where the additional bandwidth may be significant. +// A 80-bit HMAC is always used for SRTCP. +// 128-bit AES with 80-bit SHA-1 HMAC. +extern const char CS_AES_CM_128_HMAC_SHA1_80[]; +// 128-bit AES with 32-bit SHA-1 HMAC. +extern const char CS_AES_CM_128_HMAC_SHA1_32[]; +// Key is 128 bits and salt is 112 bits == 30 bytes. B64 bloat => 40 bytes. +extern const int SRTP_MASTER_KEY_BASE64_LEN; + +// Needed for DTLS-SRTP +extern const int SRTP_MASTER_KEY_KEY_LEN; +extern const int SRTP_MASTER_KEY_SALT_LEN; + +class SrtpSession; +class SrtpStat; + +void EnableSrtpDebugging(); +void ShutdownSrtp(); + +// Class to transform SRTP to/from RTP. +// Initialize by calling SetSend with the local security params, then call +// SetRecv once the remote security params are received. At that point +// Protect/UnprotectRt(c)p can be called to encrypt/decrypt data. +// TODO: Figure out concurrency policy for SrtpFilter. +class SrtpFilter { + public: + enum Mode { + PROTECT, + UNPROTECT + }; + enum Error { + ERROR_NONE, + ERROR_FAIL, + ERROR_AUTH, + ERROR_REPLAY, + }; + + SrtpFilter(); + ~SrtpFilter(); + + // Whether the filter is active (i.e. crypto has been properly negotiated). + bool IsActive() const; + + // Indicates which crypto algorithms and keys were contained in the offer. + // offer_params should contain a list of available parameters to use, or none, + // if crypto is not desired. This must be called before SetAnswer. + bool SetOffer(const std::vector& offer_params, + ContentSource source); + // Same as SetAnwer. But multiple calls are allowed to SetProvisionalAnswer + // after a call to SetOffer. + bool SetProvisionalAnswer(const std::vector& answer_params, + ContentSource source); + // Indicates which crypto algorithms and keys were contained in the answer. + // answer_params should contain the negotiated parameters, which may be none, + // if crypto was not desired or could not be negotiated (and not required). + // This must be called after SetOffer. If crypto negotiation completes + // successfully, this will advance the filter to the active state. + bool SetAnswer(const std::vector& answer_params, + ContentSource source); + + // Just set up both sets of keys directly. + // Used with DTLS-SRTP. + bool SetRtpParams(const std::string& send_cs, + const uint8* send_key, int send_key_len, + const std::string& recv_cs, + const uint8* recv_key, int recv_key_len); + bool SetRtcpParams(const std::string& send_cs, + const uint8* send_key, int send_key_len, + const std::string& recv_cs, + const uint8* recv_key, int recv_key_len); + + // 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); + + sigslot::repeater3 SignalSrtpError; + + protected: + bool ExpectOffer(ContentSource source); + bool StoreParams(const std::vector& params, + ContentSource source); + bool ExpectAnswer(ContentSource source); + bool DoSetAnswer(const std::vector& answer_params, + ContentSource source, + bool final); + void CreateSrtpSessions(); + bool NegotiateParams(const std::vector& answer_params, + CryptoParams* selected_params); + bool ApplyParams(const CryptoParams& send_params, + const CryptoParams& recv_params); + bool ResetParams(); + static bool ParseKeyParams(const std::string& params, uint8* key, int len); + + private: + enum State { + ST_INIT, // SRTP filter unused. + ST_SENTOFFER, // Offer with SRTP parameters sent. + ST_RECEIVEDOFFER, // Offer with SRTP parameters received. + ST_SENTPRANSWER_NO_CRYPTO, // Sent provisional answer without crypto. + // Received provisional answer without crypto. + ST_RECEIVEDPRANSWER_NO_CRYPTO, + ST_ACTIVE, // Offer and answer set. + // SRTP filter is active but new parameters are offered. + // When the answer is set, the state transitions to ST_ACTIVE or ST_INIT. + ST_SENTUPDATEDOFFER, + // SRTP filter is active but new parameters are received. + // When the answer is set, the state transitions back to ST_ACTIVE. + ST_RECEIVEDUPDATEDOFFER, + // SRTP filter is active but the sent answer is only provisional. + // When the final answer is set, the state transitions to ST_ACTIVE or + // ST_INIT. + ST_SENTPRANSWER, + // SRTP filter is active but the received answer is only provisional. + // When the final answer is set, the state transitions to ST_ACTIVE or + // ST_INIT. + ST_RECEIVEDPRANSWER + }; + State state_; + uint32 signal_silent_time_in_ms_; + std::vector offer_params_; + talk_base::scoped_ptr send_session_; + talk_base::scoped_ptr recv_session_; + talk_base::scoped_ptr send_rtcp_session_; + talk_base::scoped_ptr recv_rtcp_session_; + CryptoParams applied_send_params_; + CryptoParams applied_recv_params_; +}; + +// Class that wraps a libSRTP session. +class SrtpSession { + public: + SrtpSession(); + ~SrtpSession(); + + // Configures the session for sending data using the specified + // cipher-suite and key. Receiving must be done by a separate session. + bool SetSend(const std::string& cs, const uint8* key, int len); + // Configures the session for receiving data using the specified + // cipher-suite and key. Sending must be done by a separate session. + bool SetRecv(const std::string& cs, const uint8* key, int len); + + // 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); + + // Calls srtp_shutdown if it's initialized. + static void Terminate(); + + sigslot::repeater3 + SignalSrtpError; + + 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* sessions(); + + srtp_t session_; + int rtp_auth_tag_len_; + int rtcp_auth_tag_len_; + talk_base::scoped_ptr srtp_stat_; + static bool inited_; + int last_send_seq_num_; + DISALLOW_COPY_AND_ASSIGN(SrtpSession); +}; + +// Class that collects failures of SRTP. +class SrtpStat { + public: + SrtpStat(); + + // Report RTP protection results to the handler. + void AddProtectRtpResult(uint32 ssrc, int result); + // Report RTP unprotection results to the handler. + void AddUnprotectRtpResult(uint32 ssrc, int result); + // Report RTCP protection results to the handler. + void AddProtectRtcpResult(int result); + // Report RTCP unprotection results to the handler. + void AddUnprotectRtcpResult(int result); + + // Get silent time (in ms) for SRTP statistics handler. + uint32 signal_silent_time() const { return signal_silent_time_; } + // Set silent time (in ms) for SRTP statistics handler. + void set_signal_silent_time(uint32 signal_silent_time) { + signal_silent_time_ = signal_silent_time; + } + + // Sigslot for reporting errors. + sigslot::signal3 + SignalSrtpError; + + private: + // For each different ssrc and error, we collect statistics separately. + struct FailureKey { + FailureKey() + : ssrc(0), + mode(SrtpFilter::PROTECT), + error(SrtpFilter::ERROR_NONE) { + } + FailureKey(uint32 in_ssrc, SrtpFilter::Mode in_mode, + SrtpFilter::Error in_error) + : ssrc(in_ssrc), + mode(in_mode), + error(in_error) { + } + bool operator <(const FailureKey& key) const { + return + (ssrc < key.ssrc) || + (ssrc == key.ssrc && mode < key.mode) || + (ssrc == key.ssrc && mode == key.mode && error < key.error); + } + uint32 ssrc; + SrtpFilter::Mode mode; + SrtpFilter::Error error; + }; + // For tracing conditions for signaling, currently we only use + // last_signal_time. Wrap this as a struct so that later on, if we need any + // other improvements, it will be easier. + struct FailureStat { + FailureStat() + : last_signal_time(0) { + } + explicit FailureStat(uint32 in_last_signal_time) + : last_signal_time(in_last_signal_time) { + } + void Reset() { + last_signal_time = 0; + } + uint32 last_signal_time; + }; + + // Inspect SRTP result and signal error if needed. + void HandleSrtpResult(const FailureKey& key); + + std::map failures_; + // Threshold in ms to silent the signaling errors. + uint32 signal_silent_time_; + + DISALLOW_COPY_AND_ASSIGN(SrtpStat); +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_SRTPFILTER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/typingmonitor.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/typingmonitor.h new file mode 100644 index 0000000..c970094 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/typingmonitor.h @@ -0,0 +1,84 @@ +/* + * 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_SESSION_MEDIA_TYPINGMONITOR_H_ +#define TALK_SESSION_MEDIA_TYPINGMONITOR_H_ + +#include "talk/base/messagehandler.h" +#include "talk/media/base/mediachannel.h" + +namespace talk_base { +class Thread; +} + +namespace cricket { + +class VoiceChannel; +class BaseChannel; + +struct TypingMonitorOptions { + int cost_per_typing; + int mute_period; + int penalty_decay; + int reporting_threshold; + int time_window; + int type_event_delay; + size_t min_participants; +}; + +/** + * An object that observes a channel and listens for typing detection warnings, + * which can be configured to mute audio capture of that channel for some period + * of time. The purpose is to automatically mute someone if they are disturbing + * a conference with loud keystroke audio signals. + */ +class TypingMonitor + : public talk_base::MessageHandler, public sigslot::has_slots<> { + public: + TypingMonitor(VoiceChannel* channel, talk_base::Thread* worker_thread, + const TypingMonitorOptions& params); + ~TypingMonitor(); + + sigslot::signal2 SignalMuted; + + void OnChannelMuted(); + + private: + void OnVoiceChannelError(uint32 ssrc, VoiceMediaChannel::Error error); + void OnMessage(talk_base::Message* msg); + + VoiceChannel* channel_; + talk_base::Thread* worker_thread_; + int mute_period_; + int muted_at_; + bool has_pending_unmute_; +}; + +} // namespace cricket + +#endif // TALK_SESSION_MEDIA_TYPINGMONITOR_H_ + diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/media/voicechannel.h b/thirdparties/common/include/webrtc-sdk/talk/session/media/voicechannel.h new file mode 100644 index 0000000..114ce9d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/media/voicechannel.h @@ -0,0 +1,33 @@ +/* + * 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 _VOICECHANNEL_H_ +#define _VOICECHANNEL_H_ + +#include "talk/session/media/channel.h" + +#endif // _VOICECHANNEL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/tunnel/pseudotcpchannel.h b/thirdparties/common/include/webrtc-sdk/talk/session/tunnel/pseudotcpchannel.h new file mode 100644 index 0000000..a2e1261 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/tunnel/pseudotcpchannel.h @@ -0,0 +1,140 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_ +#define TALK_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_ + +#include "talk/base/criticalsection.h" +#include "talk/base/messagequeue.h" +#include "talk/base/stream.h" +#include "talk/p2p/base/pseudotcp.h" +#include "talk/p2p/base/session.h" + +namespace talk_base { +class Thread; +} + +namespace cricket { + +class Candidate; +class TransportChannel; + +/////////////////////////////////////////////////////////////////////////////// +// PseudoTcpChannel +// Note: The PseudoTcpChannel must persist until both of: +// 1) The StreamInterface provided via GetStream has been closed. +// This is tracked via non-null stream_. +// 2) The PseudoTcp session has completed. +// This is tracked via non-null worker_thread_. When PseudoTcp is done, +// the TransportChannel is signalled to tear-down. Once the channel is +// torn down, the worker thread is purged. +// These indicators are checked by CheckDestroy, invoked whenever one of them +// changes. +/////////////////////////////////////////////////////////////////////////////// +// PseudoTcpChannel::GetStream +// Note: The stream pointer returned by GetStream is owned by the caller. +// They can close & immediately delete the stream while PseudoTcpChannel still +// has cleanup work to do. They can also close the stream but not delete it +// until long after PseudoTcpChannel has finished. We must cope with both. +/////////////////////////////////////////////////////////////////////////////// + +class PseudoTcpChannel + : public IPseudoTcpNotify, + public talk_base::MessageHandler, + public sigslot::has_slots<> { + public: + // Signal thread methods + PseudoTcpChannel(talk_base::Thread* stream_thread, + Session* session); + + bool Connect(const std::string& content_name, + const std::string& channel_name, + int component); + talk_base::StreamInterface* GetStream(); + + sigslot::signal1 SignalChannelClosed; + + // Call this when the Session used to create this channel is being torn + // down, to ensure that things get cleaned up properly. + void OnSessionTerminate(Session* session); + + // See the PseudoTcp class for available options. + void GetOption(PseudoTcp::Option opt, int* value); + void SetOption(PseudoTcp::Option opt, int value); + + private: + class InternalStream; + friend class InternalStream; + + virtual ~PseudoTcpChannel(); + + // Stream thread methods + talk_base::StreamState GetState() const; + talk_base::StreamResult Read(void* buffer, size_t buffer_len, + size_t* read, int* error); + talk_base::StreamResult Write(const void* data, size_t data_len, + size_t* written, int* error); + void Close(); + + // Multi-thread methods + void OnMessage(talk_base::Message* pmsg); + void AdjustClock(bool clear = true); + void CheckDestroy(); + + // Signal thread methods + void OnChannelDestroyed(TransportChannel* channel); + + // Worker thread methods + void OnChannelWritableState(TransportChannel* channel); + void OnChannelRead(TransportChannel* channel, const char* data, size_t size, + const talk_base::PacketTime& packet_time, int flags); + void OnChannelConnectionChanged(TransportChannel* channel, + const Candidate& candidate); + + virtual void OnTcpOpen(PseudoTcp* ptcp); + virtual void OnTcpReadable(PseudoTcp* ptcp); + virtual void OnTcpWriteable(PseudoTcp* ptcp); + virtual void OnTcpClosed(PseudoTcp* ptcp, uint32 nError); + virtual IPseudoTcpNotify::WriteResult TcpWritePacket(PseudoTcp* tcp, + const char* buffer, + size_t len); + + talk_base::Thread* signal_thread_, * worker_thread_, * stream_thread_; + Session* session_; + TransportChannel* channel_; + std::string content_name_; + std::string channel_name_; + PseudoTcp* tcp_; + InternalStream* stream_; + bool stream_readable_, pending_read_event_; + bool ready_to_connect_; + mutable talk_base::CriticalSection cs_; +}; + +} // namespace cricket + +#endif // TALK_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/tunnel/securetunnelsessionclient.h b/thirdparties/common/include/webrtc-sdk/talk/session/tunnel/securetunnelsessionclient.h new file mode 100644 index 0000000..ce3bb21 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/tunnel/securetunnelsessionclient.h @@ -0,0 +1,165 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +// SecureTunnelSessionClient and SecureTunnelSession. +// SecureTunnelSessionClient extends TunnelSessionClient to exchange +// certificates as part of the session description. +// SecureTunnelSession is a TunnelSession that wraps the underlying +// tunnel stream into an SSLStreamAdapter. + +#ifndef TALK_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_ +#define TALK_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_ + +#include + +#include "talk/base/sslidentity.h" +#include "talk/base/sslstreamadapter.h" +#include "talk/session/tunnel/tunnelsessionclient.h" + +namespace cricket { + +class SecureTunnelSession; // below + +// SecureTunnelSessionClient + +// This TunnelSessionClient establishes secure tunnels protected by +// SSL/TLS. The PseudoTcpChannel stream is wrapped with an +// SSLStreamAdapter. An SSLIdentity must be set or generated. +// +// The TunnelContentDescription is extended to include the client and +// server certificates. The initiator acts as the client. The session +// initiate stanza carries a description that contains the client's +// certificate, and the session accept response's description has the +// server certificate added to it. + +class SecureTunnelSessionClient : public TunnelSessionClient { + public: + // The jid is used as the name for sessions for outgoing tunnels. + // manager is the SessionManager to which we register this client + // and its sessions. + SecureTunnelSessionClient(const buzz::Jid& jid, SessionManager* manager); + + // Configures this client to use a preexisting SSLIdentity. + // The client takes ownership of the identity object. + // Use either SetIdentity or GenerateIdentity, and only once. + void SetIdentity(talk_base::SSLIdentity* identity); + + // Generates an identity from nothing. + // Returns true if generation was successful. + // Use either SetIdentity or GenerateIdentity, and only once. + bool GenerateIdentity(); + + // Returns our identity for SSL purposes, as either set by + // SetIdentity() or generated by GenerateIdentity(). Call this + // method only after our identity has been successfully established + // by one of those methods. + talk_base::SSLIdentity& GetIdentity() const; + + // Inherited methods + virtual void OnIncomingTunnel(const buzz::Jid& jid, Session *session); + virtual bool ParseContent(SignalingProtocol protocol, + const buzz::XmlElement* elem, + ContentDescription** content, + ParseError* error); + virtual bool WriteContent(SignalingProtocol protocol, + const ContentDescription* content, + buzz::XmlElement** elem, + WriteError* error); + virtual SessionDescription* CreateOffer( + const buzz::Jid &jid, const std::string &description); + virtual SessionDescription* CreateAnswer( + const SessionDescription* offer); + + protected: + virtual TunnelSession* MakeTunnelSession( + Session* session, talk_base::Thread* stream_thread, + TunnelSessionRole role); + + private: + // Our identity (key and certificate) for SSL purposes. The + // certificate part will be communicated within the session + // description. The identity will be passed to the SSLStreamAdapter + // and used for SSL authentication. + talk_base::scoped_ptr identity_; + + DISALLOW_EVIL_CONSTRUCTORS(SecureTunnelSessionClient); +}; + +// SecureTunnelSession: +// A TunnelSession represents one session for one client. It +// provides the actual tunnel stream and handles state changes. +// A SecureTunnelSession is a TunnelSession that wraps the underlying +// tunnel stream into an SSLStreamAdapter. + +class SecureTunnelSession : public TunnelSession { + public: + // This TunnelSession will tie together the given client and session. + // stream_thread is passed to the PseudoTCPChannel: it's the thread + // designated to interact with the tunnel stream. + // role is either INITIATOR or RESPONDER, depending on who is + // initiating the session. + SecureTunnelSession(SecureTunnelSessionClient* client, Session* session, + talk_base::Thread* stream_thread, + TunnelSessionRole role); + + // Returns the stream that implements the actual P2P tunnel. + // This may be called only once. Caller is responsible for freeing + // the returned object. + virtual talk_base::StreamInterface* GetStream(); + + protected: + // Inherited method: callback on accepting a session. + virtual void OnAccept(); + + // Helper method for GetStream() that Instantiates the + // SSLStreamAdapter to wrap the PseudoTcpChannel's stream, and + // configures it with our identity and role. + talk_base::StreamInterface* MakeSecureStream( + talk_base::StreamInterface* stream); + + // Our role in requesting the tunnel: INITIATOR or + // RESPONDER. Translates to our role in SSL negotiation: + // respectively client or server. Also indicates which slot of the + // SecureTunnelContentDescription our cert goes into: client-cert or + // server-cert respectively. + TunnelSessionRole role_; + + // This is the stream representing the usable tunnel endpoint. It's + // a StreamReference wrapping the SSLStreamAdapter instance, which + // further wraps a PseudoTcpChannel::InternalStream. The + // StreamReference is because in the case of CreateTunnel(), the + // stream endpoint is returned early, but we need to keep a handle + // on it so we can setup the peer certificate when we receive it + // later. + talk_base::scoped_ptr ssl_stream_reference_; + + DISALLOW_EVIL_CONSTRUCTORS(SecureTunnelSession); +}; + +} // namespace cricket + +#endif // TALK_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/session/tunnel/tunnelsessionclient.h b/thirdparties/common/include/webrtc-sdk/talk/session/tunnel/tunnelsessionclient.h new file mode 100644 index 0000000..8fec2cc --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/session/tunnel/tunnelsessionclient.h @@ -0,0 +1,182 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef __TUNNELSESSIONCLIENT_H__ +#define __TUNNELSESSIONCLIENT_H__ + +#include + +#include "talk/base/criticalsection.h" +#include "talk/base/stream.h" +#include "talk/p2p/base/constants.h" +#include "talk/p2p/base/pseudotcp.h" +#include "talk/p2p/base/session.h" +#include "talk/p2p/base/sessiondescription.h" +#include "talk/p2p/base/sessionmanager.h" +#include "talk/p2p/base/sessionclient.h" +#include "talk/xmllite/qname.h" +#include "talk/xmpp/constants.h" + +namespace cricket { + +class TunnelSession; +class TunnelStream; + +enum TunnelSessionRole { INITIATOR, RESPONDER }; + +/////////////////////////////////////////////////////////////////////////////// +// TunnelSessionClient +/////////////////////////////////////////////////////////////////////////////// + +// Base class is still abstract +class TunnelSessionClientBase + : public SessionClient, public talk_base::MessageHandler { +public: + TunnelSessionClientBase(const buzz::Jid& jid, SessionManager* manager, + const std::string &ns); + virtual ~TunnelSessionClientBase(); + + const buzz::Jid& jid() const { return jid_; } + SessionManager* session_manager() const { return session_manager_; } + + void OnSessionCreate(Session* session, bool received); + void OnSessionDestroy(Session* session); + + // This can be called on any thread. The stream interface is + // thread-safe, but notifications must be registered on the creating + // thread. + talk_base::StreamInterface* CreateTunnel(const buzz::Jid& to, + const std::string& description); + + talk_base::StreamInterface* AcceptTunnel(Session* session); + void DeclineTunnel(Session* session); + + // Invoked on an incoming tunnel + virtual void OnIncomingTunnel(const buzz::Jid &jid, Session *session) = 0; + + // Invoked on an outgoing session request + virtual SessionDescription* CreateOffer( + const buzz::Jid &jid, const std::string &description) = 0; + // Invoked on a session request accept to create + // the local-side session description + virtual SessionDescription* CreateAnswer( + const SessionDescription* offer) = 0; + +protected: + + void OnMessage(talk_base::Message* pmsg); + + // helper method to instantiate TunnelSession. By overriding this, + // subclasses of TunnelSessionClient are able to instantiate + // subclasses of TunnelSession instead. + virtual TunnelSession* MakeTunnelSession(Session* session, + talk_base::Thread* stream_thread, + TunnelSessionRole role); + + buzz::Jid jid_; + SessionManager* session_manager_; + std::vector sessions_; + std::string namespace_; + bool shutdown_; +}; + +class TunnelSessionClient + : public TunnelSessionClientBase, public sigslot::has_slots<> { +public: + TunnelSessionClient(const buzz::Jid& jid, SessionManager* manager); + TunnelSessionClient(const buzz::Jid& jid, SessionManager* manager, + const std::string &ns); + virtual ~TunnelSessionClient(); + + virtual bool ParseContent(SignalingProtocol protocol, + const buzz::XmlElement* elem, + ContentDescription** content, + ParseError* error); + virtual bool WriteContent(SignalingProtocol protocol, + const ContentDescription* content, + buzz::XmlElement** elem, + WriteError* error); + + // Signal arguments are this, initiator, description, session + sigslot::signal4 + SignalIncomingTunnel; + + virtual void OnIncomingTunnel(const buzz::Jid &jid, + Session *session); + virtual SessionDescription* CreateOffer( + const buzz::Jid &jid, const std::string &description); + virtual SessionDescription* CreateAnswer( + const SessionDescription* offer); +}; + +/////////////////////////////////////////////////////////////////////////////// +// TunnelSession +// Note: The lifetime of TunnelSession is complicated. It needs to survive +// until the following three conditions are true: +// 1) TunnelStream has called Close (tracked via non-null stream_) +// 2) PseudoTcp has completed (tracked via non-null tcp_) +// 3) Session has been destroyed (tracked via non-null session_) +// This is accomplished by calling CheckDestroy after these indicators change. +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// TunnelStream +// Note: Because TunnelStream provides a stream interface, its lifetime is +// controlled by the owner of the stream pointer. As a result, we must support +// both the TunnelSession disappearing before TunnelStream, and vice versa. +/////////////////////////////////////////////////////////////////////////////// + +class PseudoTcpChannel; + +class TunnelSession : public sigslot::has_slots<> { + public: + // Signalling thread methods + TunnelSession(TunnelSessionClientBase* client, Session* session, + talk_base::Thread* stream_thread); + + virtual talk_base::StreamInterface* GetStream(); + bool HasSession(Session* session); + Session* ReleaseSession(bool channel_exists); + + protected: + virtual ~TunnelSession(); + + virtual void OnSessionState(BaseSession* session, BaseSession::State state); + virtual void OnInitiate(); + virtual void OnAccept(); + virtual void OnTerminate(); + virtual void OnChannelClosed(PseudoTcpChannel* channel); + + TunnelSessionClientBase* client_; + Session* session_; + PseudoTcpChannel* channel_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace cricket + +#endif // __TUNNELSESSIONCLIENT_H__ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/alsasoundsystem.h b/thirdparties/common/include/webrtc-sdk/talk/sound/alsasoundsystem.h new file mode 100644 index 0000000..da9f535 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/alsasoundsystem.h @@ -0,0 +1,120 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_ALSASOUNDSYSTEM_H_ +#define TALK_SOUND_ALSASOUNDSYSTEM_H_ + +#include "talk/base/constructormagic.h" +#include "talk/sound/alsasymboltable.h" +#include "talk/sound/soundsysteminterface.h" + +namespace cricket { + +class AlsaStream; +class AlsaInputStream; +class AlsaOutputStream; + +// Sound system implementation for ALSA, the predominant sound device API on +// Linux (but typically not used directly by applications anymore). +class AlsaSoundSystem : public SoundSystemInterface { + friend class AlsaStream; + friend class AlsaInputStream; + friend class AlsaOutputStream; + public: + static SoundSystemInterface *Create() { + return new AlsaSoundSystem(); + } + + AlsaSoundSystem(); + + virtual ~AlsaSoundSystem(); + + virtual bool Init(); + virtual void Terminate(); + + virtual bool EnumeratePlaybackDevices(SoundDeviceLocatorList *devices); + virtual bool EnumerateCaptureDevices(SoundDeviceLocatorList *devices); + + virtual bool GetDefaultPlaybackDevice(SoundDeviceLocator **device); + virtual bool GetDefaultCaptureDevice(SoundDeviceLocator **device); + + virtual SoundOutputStreamInterface *OpenPlaybackDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms); + virtual SoundInputStreamInterface *OpenCaptureDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms); + + virtual const char *GetName() const; + + private: + bool IsInitialized() { return initialized_; } + + bool EnumerateDevices(SoundDeviceLocatorList *devices, + bool capture_not_playback); + + bool GetDefaultDevice(SoundDeviceLocator **device); + + static size_t FrameSize(const OpenParams ¶ms); + + template + StreamInterface *OpenDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms, + snd_pcm_stream_t type, + StreamInterface *(AlsaSoundSystem::*start_fn)( + snd_pcm_t *handle, + size_t frame_size, + int wait_timeout_ms, + int flags, + int freq)); + + SoundOutputStreamInterface *StartOutputStream( + snd_pcm_t *handle, + size_t frame_size, + int wait_timeout_ms, + int flags, + int freq); + + SoundInputStreamInterface *StartInputStream( + snd_pcm_t *handle, + size_t frame_size, + int wait_timeout_ms, + int flags, + int freq); + + const char *GetError(int err); + + bool initialized_; + AlsaSymbolTable symbol_table_; + + DISALLOW_COPY_AND_ASSIGN(AlsaSoundSystem); +}; + +} // namespace cricket + +#endif // TALK_SOUND_ALSASOUNDSYSTEM_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/alsasymboltable.h b/thirdparties/common/include/webrtc-sdk/talk/sound/alsasymboltable.h new file mode 100644 index 0000000..fc6a21f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/alsasymboltable.h @@ -0,0 +1,66 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_ALSASYMBOLTABLE_H_ +#define TALK_SOUND_ALSASYMBOLTABLE_H_ + +#include + +#include "talk/base/latebindingsymboltable.h" + +namespace cricket { + +#define ALSA_SYMBOLS_CLASS_NAME AlsaSymbolTable +// The ALSA symbols we need, as an X-Macro list. +// This list must contain precisely every libasound function that is used in +// alsasoundsystem.cc. +#define ALSA_SYMBOLS_LIST \ + X(snd_device_name_free_hint) \ + X(snd_device_name_get_hint) \ + X(snd_device_name_hint) \ + X(snd_pcm_avail_update) \ + X(snd_pcm_close) \ + X(snd_pcm_delay) \ + X(snd_pcm_drop) \ + X(snd_pcm_open) \ + X(snd_pcm_prepare) \ + X(snd_pcm_readi) \ + X(snd_pcm_recover) \ + X(snd_pcm_set_params) \ + X(snd_pcm_start) \ + X(snd_pcm_stream) \ + X(snd_pcm_wait) \ + X(snd_pcm_writei) \ + X(snd_strerror) + +#define LATE_BINDING_SYMBOL_TABLE_CLASS_NAME ALSA_SYMBOLS_CLASS_NAME +#define LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST ALSA_SYMBOLS_LIST +#include "talk/base/latebindingsymboltable.h.def" + +} // namespace cricket + +#endif // TALK_SOUND_ALSASYMBOLTABLE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/automaticallychosensoundsystem.h b/thirdparties/common/include/webrtc-sdk/talk/sound/automaticallychosensoundsystem.h new file mode 100644 index 0000000..7371e19 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/automaticallychosensoundsystem.h @@ -0,0 +1,105 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_AUTOMATICALLYCHOSENSOUNDSYSTEM_H_ +#define TALK_SOUND_AUTOMATICALLYCHOSENSOUNDSYSTEM_H_ + +#include "talk/base/common.h" +#include "talk/base/logging.h" +#include "talk/base/scoped_ptr.h" +#include "talk/sound/soundsysteminterface.h" +#include "talk/sound/soundsystemproxy.h" + +namespace cricket { + +// A function type that creates an instance of a sound system implementation. +typedef SoundSystemInterface *(*SoundSystemCreator)(); + +// An AutomaticallyChosenSoundSystem is a sound system proxy that defers to +// an instance of the first sound system implementation in a list that +// successfully initializes. +template +class AutomaticallyChosenSoundSystem : public SoundSystemProxy { + public: + // Chooses and initializes the underlying sound system. + virtual bool Init(); + // Terminates the underlying sound system implementation, but caches it for + // future re-use. + virtual void Terminate(); + + virtual const char *GetName() const; + + private: + talk_base::scoped_ptr sound_systems_[kNumSoundSystems]; +}; + +template +bool AutomaticallyChosenSoundSystem::Init() { + if (wrapped_) { + return true; + } + for (int i = 0; i < kNumSoundSystems; ++i) { + if (!sound_systems_[i].get()) { + sound_systems_[i].reset((*kSoundSystemCreators[i])()); + } + if (sound_systems_[i]->Init()) { + // This is the first sound system in the list to successfully + // initialize, so we're done. + wrapped_ = sound_systems_[i].get(); + break; + } + // Else it failed to initialize, so try the remaining ones. + } + if (!wrapped_) { + LOG(LS_ERROR) << "Failed to find a usable sound system"; + return false; + } + LOG(LS_INFO) << "Selected " << wrapped_->GetName() << " sound system"; + return true; +} + +template +void AutomaticallyChosenSoundSystem::Terminate() { + if (!wrapped_) { + return; + } + wrapped_->Terminate(); + wrapped_ = NULL; + // We do not free the scoped_ptrs because we may be re-init'ed soon. +} + +template +const char *AutomaticallyChosenSoundSystem::GetName() const { + return wrapped_ ? wrapped_->GetName() : "automatic"; +} + +} // namespace cricket + +#endif // TALK_SOUND_AUTOMATICALLYCHOSENSOUNDSYSTEM_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/linuxsoundsystem.h b/thirdparties/common/include/webrtc-sdk/talk/sound/linuxsoundsystem.h new file mode 100644 index 0000000..160a671 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/linuxsoundsystem.h @@ -0,0 +1,58 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_LINUXSOUNDSYSTEM_H_ +#define TALK_SOUND_LINUXSOUNDSYSTEM_H_ + +#include "talk/sound/automaticallychosensoundsystem.h" + +namespace cricket { + +extern const SoundSystemCreator kLinuxSoundSystemCreators[ +#ifdef HAVE_LIBPULSE + 2 +#else + 1 +#endif + ]; + +// The vast majority of Linux systems use ALSA for the device-level sound API, +// but an increasing number are using PulseAudio for the application API and +// only using ALSA internally in PulseAudio itself. But like everything on +// Linux this is user-configurable, so we need to support both and choose the +// right one at run-time. +// PulseAudioSoundSystem is designed to only successfully initialize if +// PulseAudio is installed and running, and if it is running then direct device +// access using ALSA typically won't work, so if PulseAudioSoundSystem +// initializes then we choose that. Otherwise we choose ALSA. +typedef AutomaticallyChosenSoundSystem< + kLinuxSoundSystemCreators, + ARRAY_SIZE(kLinuxSoundSystemCreators)> LinuxSoundSystem; + +} // namespace cricket + +#endif // TALK_SOUND_LINUXSOUNDSYSTEM_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/nullsoundsystem.h b/thirdparties/common/include/webrtc-sdk/talk/sound/nullsoundsystem.h new file mode 100644 index 0000000..705012c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/nullsoundsystem.h @@ -0,0 +1,70 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_NULLSOUNDSYSTEM_H_ +#define TALK_SOUND_NULLSOUNDSYSTEM_H_ + +#include "talk/sound/soundsysteminterface.h" + +namespace cricket { + +class SoundDeviceLocator; +class SoundInputStreamInterface; +class SoundOutputStreamInterface; + +// A simple reference sound system that drops output samples and generates +// no input samples. +class NullSoundSystem : public SoundSystemInterface { + public: + static SoundSystemInterface *Create() { + return new NullSoundSystem(); + } + + virtual ~NullSoundSystem(); + + virtual bool Init(); + virtual void Terminate(); + + virtual bool EnumeratePlaybackDevices(SoundDeviceLocatorList *devices); + virtual bool EnumerateCaptureDevices(SoundDeviceLocatorList *devices); + + virtual SoundOutputStreamInterface *OpenPlaybackDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms); + virtual SoundInputStreamInterface *OpenCaptureDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms); + + virtual bool GetDefaultPlaybackDevice(SoundDeviceLocator **device); + virtual bool GetDefaultCaptureDevice(SoundDeviceLocator **device); + + virtual const char *GetName() const; +}; + +} // namespace cricket + +#endif // TALK_SOUND_NULLSOUNDSYSTEM_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/nullsoundsystemfactory.h b/thirdparties/common/include/webrtc-sdk/talk/sound/nullsoundsystemfactory.h new file mode 100644 index 0000000..2a6dd37 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/nullsoundsystemfactory.h @@ -0,0 +1,50 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_NULLSOUNDSYSTEMFACTORY_H_ +#define TALK_SOUND_NULLSOUNDSYSTEMFACTORY_H_ + +#include "talk/sound/soundsystemfactory.h" + +namespace cricket { + +// A SoundSystemFactory that always returns a NullSoundSystem. Intended for +// testing. +class NullSoundSystemFactory : public SoundSystemFactory { + public: + NullSoundSystemFactory(); + virtual ~NullSoundSystemFactory(); + + protected: + // Inherited from SoundSystemFactory. + virtual bool SetupInstance(); + virtual void CleanupInstance(); +}; + +} // namespace cricket + +#endif // TALK_SOUND_NULLSOUNDSYSTEMFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/platformsoundsystem.h b/thirdparties/common/include/webrtc-sdk/talk/sound/platformsoundsystem.h new file mode 100644 index 0000000..80628f1 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/platformsoundsystem.h @@ -0,0 +1,40 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_PLATFORMSOUNDSYSTEM_H_ +#define TALK_SOUND_PLATFORMSOUNDSYSTEM_H_ + +namespace cricket { + +class SoundSystemInterface; + +// Creates the sound system implementation for this platform. +SoundSystemInterface *CreatePlatformSoundSystem(); + +} // namespace cricket + +#endif // TALK_SOUND_PLATFORMSOUNDSYSTEM_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/platformsoundsystemfactory.h b/thirdparties/common/include/webrtc-sdk/talk/sound/platformsoundsystemfactory.h new file mode 100644 index 0000000..9ac117d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/platformsoundsystemfactory.h @@ -0,0 +1,52 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_PLATFORMSOUNDSYSTEMFACTORY_H_ +#define TALK_SOUND_PLATFORMSOUNDSYSTEMFACTORY_H_ + +#include "talk/sound/soundsystemfactory.h" + +namespace cricket { + +// A SoundSystemFactory that returns the platform's native sound system +// implementation. +class PlatformSoundSystemFactory : public SoundSystemFactory { + public: + PlatformSoundSystemFactory(); + virtual ~PlatformSoundSystemFactory(); + + protected: + // Inherited from SoundSystemFactory. + virtual bool SetupInstance(); + virtual void CleanupInstance(); +}; + +} // namespace cricket + +#endif // TALK_SOUND_PLATFORMSOUNDSYSTEMFACTORY_H_ + + diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/pulseaudiosoundsystem.h b/thirdparties/common/include/webrtc-sdk/talk/sound/pulseaudiosoundsystem.h new file mode 100644 index 0000000..775a05d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/pulseaudiosoundsystem.h @@ -0,0 +1,194 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_PULSEAUDIOSOUNDSYSTEM_H_ +#define TALK_SOUND_PULSEAUDIOSOUNDSYSTEM_H_ + +#ifdef HAVE_LIBPULSE + +#include "talk/base/constructormagic.h" +#include "talk/sound/pulseaudiosymboltable.h" +#include "talk/sound/soundsysteminterface.h" + +namespace cricket { + +class PulseAudioInputStream; +class PulseAudioOutputStream; +class PulseAudioStream; + +// Sound system implementation for PulseAudio, a cross-platform sound server +// (but commonly used only on Linux, which is the only platform we support +// it on). +// Init(), Terminate(), and the destructor should never be invoked concurrently, +// but all other methods are thread-safe. +class PulseAudioSoundSystem : public SoundSystemInterface { + friend class PulseAudioInputStream; + friend class PulseAudioOutputStream; + friend class PulseAudioStream; + public: + static SoundSystemInterface *Create() { + return new PulseAudioSoundSystem(); + } + + PulseAudioSoundSystem(); + + virtual ~PulseAudioSoundSystem(); + + virtual bool Init(); + virtual void Terminate(); + + virtual bool EnumeratePlaybackDevices(SoundDeviceLocatorList *devices); + virtual bool EnumerateCaptureDevices(SoundDeviceLocatorList *devices); + + virtual bool GetDefaultPlaybackDevice(SoundDeviceLocator **device); + virtual bool GetDefaultCaptureDevice(SoundDeviceLocator **device); + + virtual SoundOutputStreamInterface *OpenPlaybackDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms); + virtual SoundInputStreamInterface *OpenCaptureDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms); + + virtual const char *GetName() const; + + private: + bool IsInitialized(); + + static void ConnectToPulseCallbackThunk(pa_context *context, void *userdata); + + void OnConnectToPulseCallback(pa_context *context, bool *connect_done); + + bool ConnectToPulse(pa_context *context); + + pa_context *CreateNewConnection(); + + template + bool EnumerateDevices(SoundDeviceLocatorList *devices, + pa_operation *(*enumerate_fn)( + pa_context *c, + void (*callback_fn)( + pa_context *c, + const InfoStruct *i, + int eol, + void *userdata), + void *userdata), + void (*callback_fn)( + pa_context *c, + const InfoStruct *i, + int eol, + void *userdata)); + + static void EnumeratePlaybackDevicesCallbackThunk(pa_context *unused, + const pa_sink_info *info, + int eol, + void *userdata); + + static void EnumerateCaptureDevicesCallbackThunk(pa_context *unused, + const pa_source_info *info, + int eol, + void *userdata); + + void OnEnumeratePlaybackDevicesCallback( + SoundDeviceLocatorList *devices, + const pa_sink_info *info, + int eol); + + void OnEnumerateCaptureDevicesCallback( + SoundDeviceLocatorList *devices, + const pa_source_info *info, + int eol); + + template + static void GetDefaultDeviceCallbackThunk( + pa_context *unused, + const pa_server_info *info, + void *userdata); + + template + void OnGetDefaultDeviceCallback( + const pa_server_info *info, + SoundDeviceLocator **device); + + template + bool GetDefaultDevice(SoundDeviceLocator **device); + + static void StreamStateChangedCallbackThunk(pa_stream *stream, + void *userdata); + + void OnStreamStateChangedCallback(pa_stream *stream); + + template + StreamInterface *OpenDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms, + const char *stream_name, + StreamInterface *(PulseAudioSoundSystem::*connect_fn)( + pa_stream *stream, + const char *dev, + int flags, + pa_stream_flags_t pa_flags, + int latency, + const pa_sample_spec &spec)); + + SoundOutputStreamInterface *ConnectOutputStream( + pa_stream *stream, + const char *dev, + int flags, + pa_stream_flags_t pa_flags, + int latency, + const pa_sample_spec &spec); + + SoundInputStreamInterface *ConnectInputStream( + pa_stream *stream, + const char *dev, + int flags, + pa_stream_flags_t pa_flags, + int latency, + const pa_sample_spec &spec); + + bool FinishOperation(pa_operation *op); + + void Lock(); + void Unlock(); + void Wait(); + void Signal(); + + const char *LastError(); + + pa_threaded_mainloop *mainloop_; + pa_context *context_; + PulseAudioSymbolTable symbol_table_; + + DISALLOW_COPY_AND_ASSIGN(PulseAudioSoundSystem); +}; + +} // namespace cricket + +#endif // HAVE_LIBPULSE + +#endif // TALK_SOUND_PULSEAUDIOSOUNDSYSTEM_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/pulseaudiosymboltable.h b/thirdparties/common/include/webrtc-sdk/talk/sound/pulseaudiosymboltable.h new file mode 100644 index 0000000..7ceca85 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/pulseaudiosymboltable.h @@ -0,0 +1,104 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_PULSEAUDIOSYMBOLTABLE_H_ +#define TALK_SOUND_PULSEAUDIOSYMBOLTABLE_H_ + +#include +#include +#include +#include +#include +#include + +#include "talk/base/latebindingsymboltable.h" + +namespace cricket { + +#define PULSE_AUDIO_SYMBOLS_CLASS_NAME PulseAudioSymbolTable +// The PulseAudio symbols we need, as an X-Macro list. +// This list must contain precisely every libpulse function that is used in +// pulseaudiosoundsystem.cc. +#define PULSE_AUDIO_SYMBOLS_LIST \ + X(pa_bytes_per_second) \ + X(pa_context_connect) \ + X(pa_context_disconnect) \ + X(pa_context_errno) \ + X(pa_context_get_protocol_version) \ + X(pa_context_get_server_info) \ + X(pa_context_get_sink_info_list) \ + X(pa_context_get_sink_input_info) \ + X(pa_context_get_source_info_by_index) \ + X(pa_context_get_source_info_list) \ + X(pa_context_get_state) \ + X(pa_context_new) \ + X(pa_context_set_sink_input_volume) \ + X(pa_context_set_source_volume_by_index) \ + X(pa_context_set_state_callback) \ + X(pa_context_unref) \ + X(pa_cvolume_set) \ + X(pa_operation_get_state) \ + X(pa_operation_unref) \ + X(pa_stream_connect_playback) \ + X(pa_stream_connect_record) \ + X(pa_stream_disconnect) \ + X(pa_stream_drop) \ + X(pa_stream_get_device_index) \ + X(pa_stream_get_index) \ + X(pa_stream_get_latency) \ + X(pa_stream_get_sample_spec) \ + X(pa_stream_get_state) \ + X(pa_stream_new) \ + X(pa_stream_peek) \ + X(pa_stream_readable_size) \ + X(pa_stream_set_buffer_attr) \ + X(pa_stream_set_overflow_callback) \ + X(pa_stream_set_read_callback) \ + X(pa_stream_set_state_callback) \ + X(pa_stream_set_underflow_callback) \ + X(pa_stream_set_write_callback) \ + X(pa_stream_unref) \ + X(pa_stream_writable_size) \ + X(pa_stream_write) \ + X(pa_strerror) \ + X(pa_threaded_mainloop_free) \ + X(pa_threaded_mainloop_get_api) \ + X(pa_threaded_mainloop_lock) \ + X(pa_threaded_mainloop_new) \ + X(pa_threaded_mainloop_signal) \ + X(pa_threaded_mainloop_start) \ + X(pa_threaded_mainloop_stop) \ + X(pa_threaded_mainloop_unlock) \ + X(pa_threaded_mainloop_wait) + +#define LATE_BINDING_SYMBOL_TABLE_CLASS_NAME PULSE_AUDIO_SYMBOLS_CLASS_NAME +#define LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST PULSE_AUDIO_SYMBOLS_LIST +#include "talk/base/latebindingsymboltable.h.def" + +} // namespace cricket + +#endif // TALK_SOUND_PULSEAUDIOSYMBOLTABLE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/sounddevicelocator.h b/thirdparties/common/include/webrtc-sdk/talk/sound/sounddevicelocator.h new file mode 100644 index 0000000..6cc8e84 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/sounddevicelocator.h @@ -0,0 +1,71 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_SOUNDDEVICELOCATOR_H_ +#define TALK_SOUND_SOUNDDEVICELOCATOR_H_ + +#include + +#include "talk/base/constructormagic.h" + +namespace cricket { + +// A simple container for holding the name of a device and any additional id +// information needed to locate and open it. Implementations of +// SoundSystemInterface must subclass this to add any id information that they +// need. +class SoundDeviceLocator { + public: + virtual ~SoundDeviceLocator() {} + + // Human-readable name for the device. + const std::string &name() const { return name_; } + + // Name sound system uses to locate this device. + const std::string &device_name() const { return device_name_; } + + // Makes a duplicate of this locator. + virtual SoundDeviceLocator *Copy() const = 0; + + protected: + SoundDeviceLocator(const std::string &name, + const std::string &device_name) + : name_(name), device_name_(device_name) {} + + explicit SoundDeviceLocator(const SoundDeviceLocator &that) + : name_(that.name_), device_name_(that.device_name_) {} + + std::string name_; + std::string device_name_; + + private: + DISALLOW_ASSIGN(SoundDeviceLocator); +}; + +} // namespace cricket + +#endif // TALK_SOUND_SOUNDDEVICELOCATOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/soundinputstreaminterface.h b/thirdparties/common/include/webrtc-sdk/talk/sound/soundinputstreaminterface.h new file mode 100644 index 0000000..b9c84db --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/soundinputstreaminterface.h @@ -0,0 +1,85 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_SOUNDINPUTSTREAMINTERFACE_H_ +#define TALK_SOUND_SOUNDINPUTSTREAMINTERFACE_H_ + +#include "talk/base/constructormagic.h" +#include "talk/base/sigslot.h" + +namespace cricket { + +// Interface for consuming an input stream from a recording device. +// Semantics and thread-safety of StartReading()/StopReading() are the same as +// for talk_base::Worker. +class SoundInputStreamInterface { + public: + virtual ~SoundInputStreamInterface() {} + + // Starts the reading of samples on the current thread. + virtual bool StartReading() = 0; + // Stops the reading of samples. + virtual bool StopReading() = 0; + + // Retrieves the current input volume for this stream. Nominal range is + // defined by SoundSystemInterface::k(Max|Min)Volume, but values exceeding the + // max may be possible in some implementations. This call retrieves the actual + // volume currently in use by the OS, not a cached value from a previous + // (Get|Set)Volume() call. + virtual bool GetVolume(int *volume) = 0; + + // Changes the input volume for this stream. Nominal range is defined by + // SoundSystemInterface::k(Max|Min)Volume. The effect of exceeding kMaxVolume + // is implementation-defined. + virtual bool SetVolume(int volume) = 0; + + // Closes this stream object. If currently reading then this may only be + // called from the reading thread. + virtual bool Close() = 0; + + // Get the latency of the stream. + virtual int LatencyUsecs() = 0; + + // Notifies the consumer of new data read from the device. + // The first parameter is a pointer to the data read, and is only valid for + // the duration of the call. + // The second parameter is the amount of data read in bytes (i.e., the valid + // length of the memory pointed to). + // The 3rd parameter is the stream that is issuing the callback. + sigslot::signal3 SignalSamplesRead; + + protected: + SoundInputStreamInterface() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SoundInputStreamInterface); +}; + +} // namespace cricket + +#endif // TALK_SOUND_SOUNDOUTPUTSTREAMINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/soundoutputstreaminterface.h b/thirdparties/common/include/webrtc-sdk/talk/sound/soundoutputstreaminterface.h new file mode 100644 index 0000000..25d836a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/soundoutputstreaminterface.h @@ -0,0 +1,89 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_SOUNDOUTPUTSTREAMINTERFACE_H_ +#define TALK_SOUND_SOUNDOUTPUTSTREAMINTERFACE_H_ + +#include "talk/base/constructormagic.h" +#include "talk/base/sigslot.h" + +namespace cricket { + +// Interface for outputting a stream to a playback device. +// Semantics and thread-safety of EnableBufferMonitoring()/ +// DisableBufferMonitoring() are the same as for talk_base::Worker. +class SoundOutputStreamInterface { + public: + virtual ~SoundOutputStreamInterface() {} + + // Enables monitoring the available buffer space on the current thread. + virtual bool EnableBufferMonitoring() = 0; + // Disables the monitoring. + virtual bool DisableBufferMonitoring() = 0; + + // Write the given samples to the devices. If currently monitoring then this + // may only be called from the monitoring thread. + virtual bool WriteSamples(const void *sample_data, + size_t size) = 0; + + // Retrieves the current output volume for this stream. Nominal range is + // defined by SoundSystemInterface::k(Max|Min)Volume, but values exceeding the + // max may be possible in some implementations. This call retrieves the actual + // volume currently in use by the OS, not a cached value from a previous + // (Get|Set)Volume() call. + virtual bool GetVolume(int *volume) = 0; + + // Changes the output volume for this stream. Nominal range is defined by + // SoundSystemInterface::k(Max|Min)Volume. The effect of exceeding kMaxVolume + // is implementation-defined. + virtual bool SetVolume(int volume) = 0; + + // Closes this stream object. If currently monitoring then this may only be + // called from the monitoring thread. + virtual bool Close() = 0; + + // Get the latency of the stream. + virtual int LatencyUsecs() = 0; + + // Notifies the producer of the available buffer space for writes. + // It fires continuously as long as the space is greater than zero. + // The first parameter is the amount of buffer space available for data to + // be written (i.e., the maximum amount of data that can be written right now + // with WriteSamples() without blocking). + // The 2nd parameter is the stream that is issuing the callback. + sigslot::signal2 SignalBufferSpace; + + protected: + SoundOutputStreamInterface() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SoundOutputStreamInterface); +}; + +} // namespace cricket + +#endif // TALK_SOUND_SOUNDOUTPUTSTREAMINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/soundsystemfactory.h b/thirdparties/common/include/webrtc-sdk/talk/sound/soundsystemfactory.h new file mode 100644 index 0000000..0893a24 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/soundsystemfactory.h @@ -0,0 +1,44 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_SOUNDSYSTEMFACTORY_H_ +#define TALK_SOUND_SOUNDSYSTEMFACTORY_H_ + +#include "talk/base/referencecountedsingletonfactory.h" + +namespace cricket { + +class SoundSystemInterface; + +typedef talk_base::ReferenceCountedSingletonFactory + SoundSystemFactory; + +typedef talk_base::rcsf_ptr SoundSystemHandle; + +} // namespace cricket + +#endif // TALK_SOUND_SOUNDSYSTEMFACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/soundsysteminterface.h b/thirdparties/common/include/webrtc-sdk/talk/sound/soundsysteminterface.h new file mode 100644 index 0000000..245b211 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/soundsysteminterface.h @@ -0,0 +1,129 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_SOUNDSYSTEMINTERFACE_H_ +#define TALK_SOUND_SOUNDSYSTEMINTERFACE_H_ + +#include + +#include "talk/base/constructormagic.h" + +namespace cricket { + +class SoundDeviceLocator; +class SoundInputStreamInterface; +class SoundOutputStreamInterface; + +// Interface for a platform's sound system. +// Implementations must guarantee thread-safety for at least the following use +// cases: +// 1) Concurrent enumeration and opening of devices from different threads. +// 2) Concurrent use of different Sound(Input|Output)StreamInterface +// instances from different threads (but concurrent use of the _same_ one from +// different threads need not be supported). +class SoundSystemInterface { + public: + typedef std::vector SoundDeviceLocatorList; + + enum SampleFormat { + // Only one supported sample format at this time. + // The values here may be used in lookup tables, so they shouldn't change. + FORMAT_S16LE = 0, + }; + + enum Flags { + // Enable reporting the current stream latency in + // Sound(Input|Output)StreamInterface. See those classes for more details. + FLAG_REPORT_LATENCY = (1 << 0), + }; + + struct OpenParams { + // Format for the sound stream. + SampleFormat format; + // Sampling frequency in hertz. + unsigned int freq; + // Number of channels in the PCM stream. + unsigned int channels; + // Misc flags. Should be taken from the Flags enum above. + int flags; + // Desired latency, measured as number of bytes of sample data + int latency; + }; + + // Special values for the "latency" field of OpenParams. + // Use this one to say you don't care what the latency is. The sound system + // will optimize for other things instead. + static const int kNoLatencyRequirements = -1; + // Use this one to say that you want the sound system to pick an appropriate + // small latency value. The sound system may pick the minimum allowed one, or + // a slightly higher one in the event that the true minimum requires an + // undesirable trade-off. + static const int kLowLatency = 0; + + // Max value for the volume parameters for Sound(Input|Output)StreamInterface. + static const int kMaxVolume = 255; + // Min value for the volume parameters for Sound(Input|Output)StreamInterface. + static const int kMinVolume = 0; + + // Helper for clearing a locator list and deleting the entries. + static void ClearSoundDeviceLocatorList(SoundDeviceLocatorList *devices); + + virtual ~SoundSystemInterface() {} + + virtual bool Init() = 0; + virtual void Terminate() = 0; + + // Enumerates the available devices. (Any pre-existing locators in the lists + // are deleted.) + virtual bool EnumeratePlaybackDevices(SoundDeviceLocatorList *devices) = 0; + virtual bool EnumerateCaptureDevices(SoundDeviceLocatorList *devices) = 0; + + // Gets a special locator for the default device. + virtual bool GetDefaultPlaybackDevice(SoundDeviceLocator **device) = 0; + virtual bool GetDefaultCaptureDevice(SoundDeviceLocator **device) = 0; + + // Opens the given device, or returns NULL on error. + virtual SoundOutputStreamInterface *OpenPlaybackDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms) = 0; + virtual SoundInputStreamInterface *OpenCaptureDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms) = 0; + + // A human-readable name for this sound system. + virtual const char *GetName() const = 0; + + protected: + SoundSystemInterface() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SoundSystemInterface); +}; + +} // namespace cricket + +#endif // TALK_SOUND_SOUNDSYSTEMINTERFACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/sound/soundsystemproxy.h b/thirdparties/common/include/webrtc-sdk/talk/sound/soundsystemproxy.h new file mode 100644 index 0000000..b164d6d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/sound/soundsystemproxy.h @@ -0,0 +1,64 @@ +/* + * libjingle + * Copyright 2004--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. + */ + +#ifndef TALK_SOUND_SOUNDSYSTEMPROXY_H_ +#define TALK_SOUND_SOUNDSYSTEMPROXY_H_ + +#include "talk/base/basictypes.h" // for NULL +#include "talk/sound/soundsysteminterface.h" + +namespace cricket { + +// A SoundSystemProxy is a sound system that defers to another one. +// Init(), Terminate(), and GetName() are left as pure virtual, so a sub-class +// must define them. +class SoundSystemProxy : public SoundSystemInterface { + public: + SoundSystemProxy() : wrapped_(NULL) {} + + // Each of these methods simply defers to wrapped_ if non-NULL, else fails. + + virtual bool EnumeratePlaybackDevices(SoundDeviceLocatorList *devices); + virtual bool EnumerateCaptureDevices(SoundDeviceLocatorList *devices); + + virtual bool GetDefaultPlaybackDevice(SoundDeviceLocator **device); + virtual bool GetDefaultCaptureDevice(SoundDeviceLocator **device); + + virtual SoundOutputStreamInterface *OpenPlaybackDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms); + virtual SoundInputStreamInterface *OpenCaptureDevice( + const SoundDeviceLocator *device, + const OpenParams ¶ms); + + protected: + SoundSystemInterface *wrapped_; +}; + +} // namespace cricket + +#endif // TALK_SOUND_SOUNDSYSTEMPROXY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/xmllite/qname.h b/thirdparties/common/include/webrtc-sdk/talk/xmllite/qname.h new file mode 100644 index 0000000..92e54d0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/xmllite/qname.h @@ -0,0 +1,100 @@ +/* + * 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 TALK_XMLLITE_QNAME_H_ +#define TALK_XMLLITE_QNAME_H_ + +#include + +namespace buzz { + +class QName; + +// StaticQName is used to represend constant quailified names. They +// can be initialized statically and don't need intializers code, e.g. +// const StaticQName QN_FOO = { "foo_namespace", "foo" }; +// +// Beside this use case, QName should be used everywhere +// else. StaticQName instances are implicitly converted to QName +// objects. +struct StaticQName { + const char* const ns; + const char* const local; + + bool operator==(const QName& other) const; + bool operator!=(const QName& other) const; +}; + +class QName { + public: + QName(); + QName(const QName& qname); + QName(const StaticQName& const_value); + QName(const std::string& ns, const std::string& local); + explicit QName(const std::string& merged_or_local); + ~QName(); + + const std::string& Namespace() const { return namespace_; } + const std::string& LocalPart() const { return local_part_; } + std::string Merged() const; + bool IsEmpty() const; + + int Compare(const StaticQName& other) const; + int Compare(const QName& other) const; + + bool operator==(const StaticQName& other) const { + return Compare(other) == 0; + } + bool operator==(const QName& other) const { + return Compare(other) == 0; + } + bool operator!=(const StaticQName& other) const { + return Compare(other) != 0; + } + bool operator!=(const QName& other) const { + return Compare(other) != 0; + } + bool operator<(const QName& other) const { + return Compare(other) < 0; + } + + private: + std::string namespace_; + std::string local_part_; +}; + +inline bool StaticQName::operator==(const QName& other) const { + return other.Compare(*this) == 0; +} + +inline bool StaticQName::operator!=(const QName& other) const { + return other.Compare(*this) != 0; +} + +} // namespace buzz + +#endif // TALK_XMLLITE_QNAME_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlbuilder.h b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlbuilder.h new file mode 100644 index 0000000..984eee2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlbuilder.h @@ -0,0 +1,78 @@ +/* + * 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 _xmlbuilder_h_ +#define _xmlbuilder_h_ + +#include +#include +#include "talk/base/scoped_ptr.h" +#include "talk/xmllite/xmlparser.h" + +#ifdef EXPAT_RELATIVE_PATH +#include "expat.h" +#else +#include "third_party/expat/v2_0_1/Source/lib/expat.h" +#endif // EXPAT_RELATIVE_PATH + +namespace buzz { + +class XmlElement; +class XmlParseContext; + + +class XmlBuilder : public XmlParseHandler { +public: + XmlBuilder(); + + static XmlElement * BuildElement(XmlParseContext * pctx, + const char * name, const char ** atts); + virtual void StartElement(XmlParseContext * pctx, + const char * name, const char ** atts); + virtual void EndElement(XmlParseContext * pctx, const char * name); + virtual void CharacterData(XmlParseContext * pctx, + const char * text, int len); + virtual void Error(XmlParseContext * pctx, XML_Error); + virtual ~XmlBuilder(); + + void Reset(); + + // Take ownership of the built element; second call returns NULL + XmlElement * CreateElement(); + + // Peek at the built element without taking ownership + XmlElement * BuiltElement(); + +private: + XmlElement * pelCurrent_; + talk_base::scoped_ptr pelRoot_; + talk_base::scoped_ptr > pvParents_; +}; + +} + +#endif diff --git a/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlconstants.h b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlconstants.h new file mode 100644 index 0000000..3e5da98 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlconstants.h @@ -0,0 +1,47 @@ +/* + * 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 TALK_XMLLITE_XMLCONSTANTS_H_ +#define TALK_XMLLITE_XMLCONSTANTS_H_ + +#include "talk/xmllite/qname.h" + +namespace buzz { + +extern const char STR_EMPTY[]; +extern const char NS_XML[]; +extern const char NS_XMLNS[]; +extern const char STR_XMLNS[]; +extern const char STR_XML[]; +extern const char STR_VERSION[]; +extern const char STR_ENCODING[]; + +extern const StaticQName QN_XMLNS; + +} // namespace buzz + +#endif // TALK_XMLLITE_XMLCONSTANTS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlelement.h b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlelement.h new file mode 100644 index 0000000..ffdc333 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlelement.h @@ -0,0 +1,251 @@ +/* + * 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 TALK_XMLLITE_XMLELEMENT_H_ +#define TALK_XMLLITE_XMLELEMENT_H_ + +#include +#include + +#include "talk/base/scoped_ptr.h" +#include "talk/xmllite/qname.h" + +namespace buzz { + +class XmlChild; +class XmlText; +class XmlElement; +class XmlAttr; + +class XmlChild { + public: + XmlChild* NextChild() { return next_child_; } + const XmlChild* NextChild() const { return next_child_; } + + bool IsText() const { return IsTextImpl(); } + + XmlElement* AsElement() { return AsElementImpl(); } + const XmlElement* AsElement() const { return AsElementImpl(); } + + XmlText* AsText() { return AsTextImpl(); } + const XmlText* AsText() const { return AsTextImpl(); } + + + protected: + XmlChild() : + next_child_(NULL) { + } + + virtual bool IsTextImpl() const = 0; + virtual XmlElement* AsElementImpl() const = 0; + virtual XmlText* AsTextImpl() const = 0; + + + virtual ~XmlChild(); + + private: + friend class XmlElement; + + XmlChild(const XmlChild& noimpl); + + XmlChild* next_child_; +}; + +class XmlText : public XmlChild { + public: + explicit XmlText(const std::string& text) : + XmlChild(), + text_(text) { + } + explicit XmlText(const XmlText& t) : + XmlChild(), + text_(t.text_) { + } + explicit XmlText(const char* cstr, size_t len) : + XmlChild(), + text_(cstr, len) { + } + virtual ~XmlText(); + + const std::string& Text() const { return text_; } + void SetText(const std::string& text); + void AddParsedText(const char* buf, int len); + void AddText(const std::string& text); + + protected: + virtual bool IsTextImpl() const; + virtual XmlElement* AsElementImpl() const; + virtual XmlText* AsTextImpl() const; + + private: + std::string text_; +}; + +class XmlAttr { + public: + XmlAttr* NextAttr() const { return next_attr_; } + const QName& Name() const { return name_; } + const std::string& Value() const { return value_; } + + private: + friend class XmlElement; + + explicit XmlAttr(const QName& name, const std::string& value) : + next_attr_(NULL), + name_(name), + value_(value) { + } + explicit XmlAttr(const XmlAttr& att) : + next_attr_(NULL), + name_(att.name_), + value_(att.value_) { + } + + XmlAttr* next_attr_; + QName name_; + std::string value_; +}; + +class XmlElement : public XmlChild { + public: + explicit XmlElement(const QName& name); + explicit XmlElement(const QName& name, bool useDefaultNs); + explicit XmlElement(const XmlElement& elt); + + virtual ~XmlElement(); + + const QName& Name() const { return name_; } + void SetName(const QName& name) { name_ = name; } + + const std::string BodyText() const; + void SetBodyText(const std::string& text); + + const QName FirstElementName() const; + + XmlAttr* FirstAttr(); + const XmlAttr* FirstAttr() const + { return const_cast(this)->FirstAttr(); } + + // Attr will return an empty string if the attribute isn't there: + // use HasAttr to test presence of an attribute. + const std::string Attr(const StaticQName& name) const; + const std::string Attr(const QName& name) const; + bool HasAttr(const StaticQName& name) const; + bool HasAttr(const QName& name) const; + void SetAttr(const QName& name, const std::string& value); + void ClearAttr(const QName& name); + + XmlChild* FirstChild(); + const XmlChild* FirstChild() const { + return const_cast(this)->FirstChild(); + } + + XmlElement* FirstElement(); + const XmlElement* FirstElement() const { + return const_cast(this)->FirstElement(); + } + + XmlElement* NextElement(); + const XmlElement* NextElement() const { + return const_cast(this)->NextElement(); + } + + XmlElement* FirstWithNamespace(const std::string& ns); + const XmlElement* FirstWithNamespace(const std::string& ns) const { + return const_cast(this)->FirstWithNamespace(ns); + } + + XmlElement* NextWithNamespace(const std::string& ns); + const XmlElement* NextWithNamespace(const std::string& ns) const { + return const_cast(this)->NextWithNamespace(ns); + } + + XmlElement* FirstNamed(const StaticQName& name); + const XmlElement* FirstNamed(const StaticQName& name) const { + return const_cast(this)->FirstNamed(name); + } + + XmlElement* FirstNamed(const QName& name); + const XmlElement* FirstNamed(const QName& name) const { + return const_cast(this)->FirstNamed(name); + } + + XmlElement* NextNamed(const StaticQName& name); + const XmlElement* NextNamed(const StaticQName& name) const { + return const_cast(this)->NextNamed(name); + } + + XmlElement* NextNamed(const QName& name); + const XmlElement* NextNamed(const QName& name) const { + return const_cast(this)->NextNamed(name); + } + + // Finds the first element named 'name'. If that element can't be found then + // adds one and returns it. + XmlElement* FindOrAddNamedChild(const QName& name); + + const std::string TextNamed(const QName& name) const; + + void InsertChildAfter(XmlChild* predecessor, XmlChild* new_child); + void RemoveChildAfter(XmlChild* predecessor); + + void AddParsedText(const char* buf, int len); + // Note: CDATA is not supported by XMPP, therefore using this function will + // generate non-XMPP compatible XML. + void AddCDATAText(const char* buf, int len); + void AddText(const std::string& text); + void AddText(const std::string& text, int depth); + void AddElement(XmlElement* child); + void AddElement(XmlElement* child, int depth); + void AddAttr(const QName& name, const std::string& value); + void AddAttr(const QName& name, const std::string& value, int depth); + void ClearNamedChildren(const QName& name); + void ClearAttributes(); + void ClearChildren(); + + static XmlElement* ForStr(const std::string& str); + std::string Str() const; + + bool IsCDATA() const { return cdata_; } + + protected: + virtual bool IsTextImpl() const; + virtual XmlElement* AsElementImpl() const; + virtual XmlText* AsTextImpl() const; + + private: + QName name_; + XmlAttr* first_attr_; + XmlAttr* last_attr_; + XmlChild* first_child_; + XmlChild* last_child_; + bool cdata_; +}; + +} // namespace buzz + +#endif // TALK_XMLLITE_XMLELEMENT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlnsstack.h b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlnsstack.h new file mode 100644 index 0000000..f6b4b81 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlnsstack.h @@ -0,0 +1,62 @@ +/* + * 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 TALK_XMLLITE_XMLNSSTACK_H_ +#define TALK_XMLLITE_XMLNSSTACK_H_ + +#include +#include +#include "talk/base/scoped_ptr.h" +#include "talk/xmllite/qname.h" + +namespace buzz { + +class XmlnsStack { +public: + XmlnsStack(); + ~XmlnsStack(); + + void AddXmlns(const std::string& prefix, const std::string& ns); + void RemoveXmlns(); + void PushFrame(); + void PopFrame(); + void Reset(); + + std::pair NsForPrefix(const std::string& prefix); + bool PrefixMatchesNs(const std::string & prefix, const std::string & ns); + std::pair PrefixForNs(const std::string& ns, bool isAttr); + std::pair AddNewPrefix(const std::string& ns, bool isAttr); + std::string FormatQName(const QName & name, bool isAttr); + +private: + + talk_base::scoped_ptr > pxmlnsStack_; + talk_base::scoped_ptr > pxmlnsDepthStack_; +}; +} + +#endif // TALK_XMLLITE_XMLNSSTACK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlparser.h b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlparser.h new file mode 100644 index 0000000..4a79858 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlparser.h @@ -0,0 +1,120 @@ +/* + * 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 TALK_XMLLITE_XMLPARSER_H_ +#define TALK_XMLLITE_XMLPARSER_H_ + +#include + +#include "talk/xmllite/xmlnsstack.h" +#ifdef EXPAT_RELATIVE_PATH +#include "expat.h" +#else +#include "third_party/expat/v2_0_1/Source/lib/expat.h" +#endif // EXPAT_RELATIVE_PATH + +struct XML_ParserStruct; +typedef struct XML_ParserStruct* XML_Parser; + +namespace buzz { + +class XmlParseHandler; +class XmlParseContext; +class XmlParser; + +class XmlParseContext { +public: + virtual ~XmlParseContext() {} + virtual QName ResolveQName(const char * qname, bool isAttr) = 0; + virtual void RaiseError(XML_Error err) = 0; + virtual void GetPosition(unsigned long * line, unsigned long * column, + unsigned long * byte_index) = 0; +}; + +class XmlParseHandler { +public: + virtual ~XmlParseHandler() {} + virtual void StartElement(XmlParseContext * pctx, + const char * name, const char ** atts) = 0; + virtual void EndElement(XmlParseContext * pctx, + const char * name) = 0; + virtual void CharacterData(XmlParseContext * pctx, + const char * text, int len) = 0; + virtual void Error(XmlParseContext * pctx, + XML_Error errorCode) = 0; +}; + +class XmlParser { +public: + static void ParseXml(XmlParseHandler * pxph, std::string text); + + explicit XmlParser(XmlParseHandler * pxph); + bool Parse(const char * data, size_t len, bool isFinal); + void Reset(); + virtual ~XmlParser(); + + // expat callbacks + void ExpatStartElement(const char * name, const char ** atts); + void ExpatEndElement(const char * name); + void ExpatCharacterData(const char * text, int len); + void ExpatXmlDecl(const char * ver, const char * enc, int standalone); + +private: + + class ParseContext : public XmlParseContext { + public: + ParseContext(); + virtual ~ParseContext(); + virtual QName ResolveQName(const char * qname, bool isAttr); + virtual void RaiseError(XML_Error err) { if (!raised_) raised_ = err; } + virtual void GetPosition(unsigned long * line, unsigned long * column, + unsigned long * byte_index); + XML_Error RaisedError() { return raised_; } + void Reset(); + + void StartElement(); + void EndElement(); + void StartNamespace(const char * prefix, const char * ns); + void SetPosition(int line, int column, long byte_index); + + private: + XmlnsStack xmlnsstack_; + XML_Error raised_; + XML_Size line_number_; + XML_Size column_number_; + XML_Index byte_index_; + }; + + ParseContext context_; + XML_Parser expat_; + XmlParseHandler * pxph_; + bool sentError_; +}; + +} // namespace buzz + +#endif // TALK_XMLLITE_XMLPARSER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlprinter.h b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlprinter.h new file mode 100644 index 0000000..90cc255 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/talk/xmllite/xmlprinter.h @@ -0,0 +1,49 @@ +/* + * 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 TALK_XMLLITE_XMLPRINTER_H_ +#define TALK_XMLLITE_XMLPRINTER_H_ + +#include +#include + +namespace buzz { + +class XmlElement; +class XmlnsStack; + +class XmlPrinter { + public: + static void PrintXml(std::ostream* pout, const XmlElement* pelt); + + static void PrintXml(std::ostream* pout, const XmlElement* pelt, + XmlnsStack* ns_stack); +}; + +} // namespace buzz + +#endif // TALK_XMLLITE_XMLPRINTER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/assertions.h b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/assertions.h new file mode 100644 index 0000000..3d35ac9 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/assertions.h @@ -0,0 +1,31 @@ +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED +# define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include + +#if !defined(JSON_IS_AMALGAMATION) +# include +#endif // if !defined(JSON_IS_AMALGAMATION) + +#if JSON_USE_EXCEPTION +#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw +#define JSON_FAIL_MESSAGE( message ) throw std::runtime_error( message ); +#else // JSON_USE_EXCEPTION +#define JSON_ASSERT( condition ) assert( condition ); + +// The call to assert() will show the failure message in debug builds. In +// release bugs we write to invalid memory in order to crash hard, so that a +// debugger or crash reporter gets the chance to take over. We still call exit() +// afterward in order to tell the compiler that this macro doesn't return. +#define JSON_FAIL_MESSAGE( message ) { assert(false && message); strcpy(reinterpret_cast(666), message); exit(123); } + +#endif + +#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) { JSON_FAIL_MESSAGE( message ) } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED diff --git a/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/autolink.h b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/autolink.h new file mode 100644 index 0000000..c15bf57 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/autolink.h @@ -0,0 +1,24 @@ +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_AUTOLINK_H_INCLUDED +# define JSON_AUTOLINK_H_INCLUDED + +# include "config.h" + +# ifdef JSON_IN_CPPTL +# include +# endif + +# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) +# define CPPTL_AUTOLINK_NAME "json" +# undef CPPTL_AUTOLINK_DLL +# ifdef JSON_DLL +# define CPPTL_AUTOLINK_DLL +# endif +# include "autolink.h" +# endif + +#endif // JSON_AUTOLINK_H_INCLUDED diff --git a/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/config.h b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/config.h new file mode 100644 index 0000000..77e33af --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/config.h @@ -0,0 +1,98 @@ +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +# define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 +/// If defined, indicates that Json specific container should be used +/// (hash table & simple deque container with customizable allocator). +/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332 +//# define JSON_VALUE_USE_INTERNAL_MAP 1 +/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. +/// The memory pools allocator used optimization (initializing Value and ValueInternalLink +/// as if it was a POD) that may cause some validation tool to report errors. +/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. +//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +# ifndef JSON_USE_EXCEPTION +# define JSON_USE_EXCEPTION 1 +# endif + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + + +# ifdef JSON_IN_CPPTL +# include +# ifndef JSON_USE_CPPTL +# define JSON_USE_CPPTL 1 +# endif +# endif + +# ifdef JSON_IN_CPPTL +# define JSON_API CPPTL_API +# elif defined(JSON_DLL_BUILD) +# define JSON_API __declspec(dllexport) +# elif defined(JSON_DLL) +# define JSON_API __declspec(dllimport) +# else +# define JSON_API +# endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 + +#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 +/// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif + +#if !defined(JSONCPP_DEPRECATED) +# define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +namespace Json { + typedef int Int; + typedef unsigned int UInt; +# if defined(JSON_NO_INT64) + typedef int LargestInt; + typedef unsigned int LargestUInt; +# undef JSON_HAS_INT64 +# else // if defined(JSON_NO_INT64) + // For Microsoft Visual use specific types as long long is not supported +# if defined(_MSC_VER) // Microsoft Visual Studio + typedef __int64 Int64; + typedef unsigned __int64 UInt64; +# else // if defined(_MSC_VER) // Other platforms, use long long + typedef long long int Int64; + typedef unsigned long long int UInt64; +# endif // if defined(_MSC_VER) + typedef Int64 LargestInt; + typedef UInt64 LargestUInt; +# define JSON_HAS_INT64 +# endif // if defined(JSON_NO_INT64) +} // end namespace Json + + +#endif // JSON_CONFIG_H_INCLUDED diff --git a/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/features.h b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/features.h new file mode 100644 index 0000000..54fbf5b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/features.h @@ -0,0 +1,49 @@ +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +# define CPPTL_JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + + /** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ + class JSON_API Features + { + public: + /** \brief A configuration that allows all features and assumes all strings are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c false. + bool strictRoot_; + }; + +} // namespace Json + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED diff --git a/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/forwards.h b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/forwards.h new file mode 100644 index 0000000..c1f8d75 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/forwards.h @@ -0,0 +1,44 @@ +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +# define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + + // writer.h + class FastWriter; + class StyledWriter; + + // reader.h + class Reader; + + // features.h + class Features; + + // value.h + typedef unsigned int ArrayIndex; + class StaticString; + class Path; + class PathArgument; + class Value; + class ValueIteratorBase; + class ValueIterator; + class ValueConstIterator; +#ifdef JSON_VALUE_USE_INTERNAL_MAP + class ValueMapAllocator; + class ValueInternalLink; + class ValueInternalArray; + class ValueInternalMap; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + +} // namespace Json + + +#endif // JSON_FORWARDS_H_INCLUDED diff --git a/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/json.h b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/json.h new file mode 100644 index 0000000..fa91ff0 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/json.h @@ -0,0 +1,15 @@ +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_JSON_H_INCLUDED +# define JSON_JSON_H_INCLUDED + +# include "autolink.h" +# include "value.h" +# include "reader.h" +# include "writer.h" +# include "features.h" + +#endif // JSON_JSON_H_INCLUDED diff --git a/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/reader.h b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/reader.h new file mode 100644 index 0000000..4721ac2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/reader.h @@ -0,0 +1,213 @@ +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_READER_H_INCLUDED +# define CPPTL_JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "features.h" +# include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +# include +# include +# include + +namespace Json { + + /** \brief Unserialize a JSON document into a Value. + * + */ + class JSON_API Reader + { + public: + typedef char Char; + typedef const Char *Location; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader( const Features &features ); + + /** \brief Read a Value from a JSON document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const std::string &document, + Value &root, + bool collectComments = true ); + + /** \brief Read a Value from a JSON document. + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read. + \ Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments = true ); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse( std::istream &is, + Value &root, + bool collectComments = true ); + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead") + std::string getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + */ + std::string getFormattedErrorMessages() const; + + private: + enum TokenType + { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token + { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo + { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool expectToken( TokenType type, Token &token, const char *message ); + bool readToken( Token &token ); + void skipSpaces(); + bool match( Location pattern, + int patternLength ); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject( Token &token ); + bool readArray( Token &token ); + bool decodeNumber( Token &token ); + bool decodeString( Token &token ); + bool decodeString( Token &token, std::string &decoded ); + bool decodeDouble( Token &token ); + bool decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool addError( const std::string &message, + Token &token, + Location extra = 0 ); + bool recoverFromError( TokenType skipUntilToken ); + bool addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ); + void skipUntilSpace(); + Value ¤tValue(); + Char getNextChar(); + void getLocationLineAndColumn( Location location, + int &line, + int &column ) const; + std::string getLocationLineAndColumn( Location location ) const; + void addComment( Location begin, + Location end, + CommentPlacement placement ); + void skipCommentTokens( Token &token ); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value *lastValue_; + std::string commentsBefore_; + Features features_; + bool collectComments_; + }; + + /** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() + */ + std::istream& operator>>( std::istream&, Value& ); + +} // namespace Json + +#endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/value.h b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/value.h new file mode 100644 index 0000000..6405ee3 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/value.h @@ -0,0 +1,1109 @@ +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_H_INCLUDED +# define CPPTL_JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +# include +# include + +# ifndef JSON_USE_CPPTL_SMALLMAP +# include +# else +# include +# endif +# ifdef JSON_USE_CPPTL +# include +# endif + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + + /** \brief Type of the value held by a Value object. + */ + enum ValueType + { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). + }; + + enum CommentPlacement + { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for root value) + numberOfCommentPlacement + }; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + + /** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + class JSON_API StaticString + { + public: + explicit StaticString( const char *czstring ) + : str_( czstring ) + { + } + + operator const char *() const + { + return str_; + } + + const char *c_str() const + { + return str_; + } + + private: + const char *str_; + }; + + /** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. + * Non const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resize and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtanis default value in the case the required element + * does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + */ + class JSON_API Value + { + friend class ValueIteratorBase; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + friend class ValueInternalLink; + friend class ValueInternalMap; +# endif + public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; +# if defined(JSON_HAS_INT64) + typedef Json::UInt64 UInt64; + typedef Json::Int64 Int64; +#endif // defined(JSON_HAS_INT64) + typedef Json::LargestInt LargestInt; + typedef Json::LargestUInt LargestUInt; + typedef Json::ArrayIndex ArrayIndex; + + static const Value null; + /// Minimum signed integer value that can be stored in a Json::Value. + static const LargestInt minLargestInt; + /// Maximum signed integer value that can be stored in a Json::Value. + static const LargestInt maxLargestInt; + /// Maximum unsigned integer value that can be stored in a Json::Value. + static const LargestUInt maxLargestUInt; + + /// Minimum signed int value that can be stored in a Json::Value. + static const Int minInt; + /// Maximum signed int value that can be stored in a Json::Value. + static const Int maxInt; + /// Maximum unsigned int value that can be stored in a Json::Value. + static const UInt maxUInt; + +# if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 minInt64; + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 maxInt64; + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static const UInt64 maxUInt64; +#endif // defined(JSON_HAS_INT64) + + private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION +# ifndef JSON_VALUE_USE_INTERNAL_MAP + class CZString + { + public: + enum DuplicationPolicy + { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString( ArrayIndex index ); + CZString( const char *cstr, DuplicationPolicy allocate ); + CZString( const CZString &other ); + ~CZString(); + CZString &operator =( const CZString &other ); + bool operator<( const CZString &other ) const; + bool operator==( const CZString &other ) const; + ArrayIndex index() const; + const char *c_str() const; + bool isStaticString() const; + private: + void swap( CZString &other ); + const char *cstr_; + ArrayIndex index_; + }; + + public: +# ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +# else + typedef CppTL::SmallMap ObjectValues; +# endif // ifndef JSON_USE_CPPTL_SMALLMAP +# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. + This is useful since clear() and resize() will not alter types. + + Examples: + \code + Json::Value null_value; // null + Json::Value arr_value(Json::arrayValue); // [] + Json::Value obj_value(Json::objectValue); // {} + \endcode + */ + Value( ValueType type = nullValue ); + Value( Int value ); + Value( UInt value ); +#if defined(JSON_HAS_INT64) + Value( Int64 value ); + Value( UInt64 value ); +#endif // if defined(JSON_HAS_INT64) + Value( double value ); + Value( const char *value ); + Value( const char *beginValue, const char *endValue ); + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * \endcode + */ + Value( const StaticString &value ); + Value( const std::string &value ); +# ifdef JSON_USE_CPPTL + Value( const CppTL::ConstString &value ); +# endif + Value( bool value ); + Value( const Value &other ); + ~Value(); + + Value &operator=( const Value &other ); + /// Swap values. + /// \note Currently, comments are intentionally not swapped, for + /// both logic and efficiency. + void swap( Value &other ); + + ValueType type() const; + + bool operator <( const Value &other ) const; + bool operator <=( const Value &other ) const; + bool operator >=( const Value &other ) const; + bool operator >( const Value &other ) const; + + bool operator ==( const Value &other ) const; + bool operator !=( const Value &other ) const; + + int compare( const Value &other ) const; + + const char *asCString() const; + std::string asString() const; +# ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +# endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo( ValueType other ) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize( ArrayIndex size ); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value &operator[]( ArrayIndex index ); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value &operator[]( int index ); + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value &operator[]( ArrayIndex index ) const; + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value &operator[]( int index ) const; + + /// If the array contains at least index+1 elements, returns the element value, + /// otherwise returns defaultValue. + Value get( ArrayIndex index, + const Value &defaultValue ) const; + /// Return true if index < size(). + bool isValidIndex( ArrayIndex index ) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value &append( const Value &value ); + + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const char *key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const char *key ) const; + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const std::string &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const std::string &key ) const; + /** \brief Access an object value by name, create a null member if it does not exist. + + * If the object as no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value &operator[]( const StaticString &key ); +# ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const CppTL::ConstString &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const CppTL::ConstString &key ) const; +# endif + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const char *key, + const Value &defaultValue ) const; + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const std::string &key, + const Value &defaultValue ) const; +# ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const CppTL::ConstString &key, + const Value &defaultValue ) const; +# endif + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + Value removeMember( const char* key ); + /// Same as removeMember(const char*) + Value removeMember( const std::string &key ); + + /// Return true if the object has a member named key. + bool isMember( const char *key ) const; + /// Return true if the object has a member named key. + bool isMember( const std::string &key ) const; +# ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember( const CppTL::ConstString &key ) const; +# endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + +//# ifdef JSON_USE_CPPTL +// EnumMemberNames enumMemberNames() const; +// EnumValues enumValues() const; +//# endif + + /// Comments must be //... or /* ... */ + void setComment( const char *comment, + CommentPlacement placement ); + /// Comments must be //... or /* ... */ + void setComment( const std::string &comment, + CommentPlacement placement ); + bool hasComment( CommentPlacement placement ) const; + /// Include delimiters and embedded newlines. + std::string getComment( CommentPlacement placement ) const; + + std::string toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + private: + Value &resolveReference( const char *key, + bool isStatic ); + +# ifdef JSON_VALUE_USE_INTERNAL_MAP + inline bool isItemAvailable() const + { + return itemIsUsed_ == 0; + } + + inline void setItemUsed( bool isUsed = true ) + { + itemIsUsed_ = isUsed ? 1 : 0; + } + + inline bool isMemberNameStatic() const + { + return memberNameIsStatic_ == 0; + } + + inline void setMemberNameIsStatic( bool isStatic ) + { + memberNameIsStatic_ = isStatic ? 1 : 0; + } +# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP + + private: + struct CommentInfo + { + CommentInfo(); + ~CommentInfo(); + + void setComment( const char *text ); + + char *comment_; + }; + + //struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder + { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char *string_; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + ValueInternalArray *array_; + ValueInternalMap *map_; +#else + ObjectValues *map_; +# endif + } value_; + ValueType type_ : 8; + int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. +# ifdef JSON_VALUE_USE_INTERNAL_MAP + unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. + int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. +# endif + CommentInfo *comments_; + }; + + + /** \brief Experimental and untested: represents an element of the "path" to access a node. + */ + class PathArgument + { + public: + friend class Path; + + PathArgument(); + PathArgument( ArrayIndex index ); + PathArgument( const char *key ); + PathArgument( const std::string &key ); + + private: + enum Kind + { + kindNone = 0, + kindIndex, + kindKey + }; + std::string key_; + ArrayIndex index_; + Kind kind_; + }; + + /** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ + class Path + { + public: + Path( const std::string &path, + const PathArgument &a1 = PathArgument(), + const PathArgument &a2 = PathArgument(), + const PathArgument &a3 = PathArgument(), + const PathArgument &a4 = PathArgument(), + const PathArgument &a5 = PathArgument() ); + + const Value &resolve( const Value &root ) const; + Value resolve( const Value &root, + const Value &defaultValue ) const; + /// Creates the "path" to access the specified node and returns a reference on the node. + Value &make( Value &root ) const; + + private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath( const std::string &path, + const InArgs &in ); + void addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ); + void invalidPath( const std::string &path, + int location ); + + Args args_; + }; + + + +#ifdef JSON_VALUE_USE_INTERNAL_MAP + /** \brief Allocator to customize Value internal map. + * Below is an example of a simple implementation (default implementation actually + * use memory pool for speed). + * \code + class DefaultValueMapAllocator : public ValueMapAllocator + { + public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + return new ValueInternalMap(); + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + return new ValueInternalMap( other ); + } + + virtual void destructMap( ValueInternalMap *map ) + { + delete map; + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + return new ValueInternalLink(); + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + delete link; + } + }; + * \endcode + */ + class JSON_API ValueMapAllocator + { + public: + virtual ~ValueMapAllocator(); + virtual ValueInternalMap *newMap() = 0; + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; + virtual void destructMap( ValueInternalMap *map ) = 0; + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; + virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; + virtual ValueInternalLink *allocateMapLink() = 0; + virtual void releaseMapLink( ValueInternalLink *link ) = 0; + }; + + /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). + * \internal previous_ & next_ allows for bidirectional traversal. + */ + class JSON_API ValueInternalLink + { + public: + enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. + enum InternalFlags { + flagAvailable = 0, + flagUsed = 1 + }; + + ValueInternalLink(); + + ~ValueInternalLink(); + + Value items_[itemPerLink]; + char *keys_[itemPerLink]; + ValueInternalLink *previous_; + ValueInternalLink *next_; + }; + + + /** \brief A linked page based hash-table implementation used internally by Value. + * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked + * list in each bucket to handle collision. There is an addional twist in that + * each node of the collision linked list is a page containing a fixed amount of + * value. This provides a better compromise between memory usage and speed. + * + * Each bucket is made up of a chained list of ValueInternalLink. The last + * link of a given bucket can be found in the 'previous_' field of the following bucket. + * The last link of the last bucket is stored in tailLink_ as it has no following bucket. + * Only the last link of a bucket may contains 'available' item. The last link always + * contains at least one element unless is it the bucket one very first link. + */ + class JSON_API ValueInternalMap + { + friend class ValueIteratorBase; + friend class Value; + public: + typedef unsigned int HashKey; + typedef unsigned int BucketIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState + { + IteratorState() + : map_(0) + , link_(0) + , itemIndex_(0) + , bucketIndex_(0) + { + } + ValueInternalMap *map_; + ValueInternalLink *link_; + BucketIndex itemIndex_; + BucketIndex bucketIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalMap(); + ValueInternalMap( const ValueInternalMap &other ); + ValueInternalMap &operator =( const ValueInternalMap &other ); + ~ValueInternalMap(); + + void swap( ValueInternalMap &other ); + + BucketIndex size() const; + + void clear(); + + bool reserveDelta( BucketIndex growth ); + + bool reserve( BucketIndex newItemCount ); + + const Value *find( const char *key ) const; + + Value *find( const char *key ); + + Value &resolveReference( const char *key, + bool isStatic ); + + void remove( const char *key ); + + void doActualRemove( ValueInternalLink *link, + BucketIndex index, + BucketIndex bucketIndex ); + + ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); + + Value &setNewItem( const char *key, + bool isStatic, + ValueInternalLink *link, + BucketIndex index ); + + Value &unsafeAdd( const char *key, + bool isStatic, + HashKey hashedKey ); + + HashKey hash( const char *key ) const; + + int compare( const ValueInternalMap &other ) const; + + private: + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void incrementBucket( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static const char *key( const IteratorState &iterator ); + static const char *key( const IteratorState &iterator, bool &isStatic ); + static Value &value( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + + private: + ValueInternalLink *buckets_; + ValueInternalLink *tailLink_; + BucketIndex bucketsSize_; + BucketIndex itemCount_; + }; + + /** \brief A simplified deque implementation used internally by Value. + * \internal + * It is based on a list of fixed "page", each page contains a fixed number of items. + * Instead of using a linked-list, a array of pointer is used for fast item look-up. + * Look-up for an element is as follow: + * - compute page index: pageIndex = itemIndex / itemsPerPage + * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] + * + * Insertion is amortized constant time (only the array containing the index of pointers + * need to be reallocated when items are appended). + */ + class JSON_API ValueInternalArray + { + friend class Value; + friend class ValueIteratorBase; + public: + enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. + typedef Value::ArrayIndex ArrayIndex; + typedef unsigned int PageIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState // Must be a POD + { + IteratorState() + : array_(0) + , currentPageIndex_(0) + , currentItemIndex_(0) + { + } + ValueInternalArray *array_; + Value **currentPageIndex_; + unsigned int currentItemIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalArray(); + ValueInternalArray( const ValueInternalArray &other ); + ValueInternalArray &operator =( const ValueInternalArray &other ); + ~ValueInternalArray(); + void swap( ValueInternalArray &other ); + + void clear(); + void resize( ArrayIndex newSize ); + + Value &resolveReference( ArrayIndex index ); + + Value *find( ArrayIndex index ) const; + + ArrayIndex size() const; + + int compare( const ValueInternalArray &other ) const; + + private: + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static Value &dereference( const IteratorState &iterator ); + static Value &unsafeDereference( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + static ArrayIndex indexOf( const IteratorState &iterator ); + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + void makeIterator( IteratorState &it, ArrayIndex index ) const; + + void makeIndexValid( ArrayIndex index ); + + Value **pages_; + ArrayIndex size_; + PageIndex pageCount_; + }; + + /** \brief Experimental: do not use. Allocator to customize Value internal array. + * Below is an example of a simple implementation (actual implementation use + * memory pool). + \code +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator + virtual ~DefaultValueArrayAllocator() + { + } + + virtual ValueInternalArray *newArray() + { + return new ValueInternalArray(); + } + + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) + { + return new ValueInternalArray( other ); + } + + virtual void destruct( ValueInternalArray *array ) + { + delete array; + } + + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) + { + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast( newIndexes ); + } + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) + { + if ( indexes ) + free( indexes ); + } + + virtual Value *allocateArrayPage() + { + return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); + } + + virtual void releaseArrayPage( Value *value ) + { + if ( value ) + free( value ); + } +}; + \endcode + */ + class JSON_API ValueArrayAllocator + { + public: + virtual ~ValueArrayAllocator(); + virtual ValueInternalArray *newArray() = 0; + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; + virtual void destructArray( ValueInternalArray *array ) = 0; + /** \brief Reallocate array page index. + * Reallocates an array of pointer on each page. + * \param indexes [input] pointer on the current index. May be \c NULL. + * [output] pointer on the new index of at least + * \a minNewIndexCount pages. + * \param indexCount [input] current number of pages in the index. + * [output] number of page the reallocated index can handle. + * \b MUST be >= \a minNewIndexCount. + * \param minNewIndexCount Minimum number of page the new index must be able to + * handle. + */ + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) = 0; + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) = 0; + virtual Value *allocateArrayPage() = 0; + virtual void releaseArrayPage( Value *value ) = 0; + }; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + + + /** \brief base class for Value iterators. + * + */ + class ValueIteratorBase + { + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + ValueIteratorBase(); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); +#else + ValueIteratorBase( const ValueInternalArray::IteratorState &state ); + ValueIteratorBase( const ValueInternalMap::IteratorState &state ); +#endif + + bool operator ==( const SelfType &other ) const + { + return isEqual( other ); + } + + bool operator !=( const SelfType &other ) const + { + return !isEqual( other ); + } + + difference_type operator -( const SelfType &other ) const + { + return computeDistance( other ); + } + + /// Return either the index or the member name of the referenced value as a Value. + Value key() const; + + /// Return the index of the referenced Value. -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value. "" if it is not an objectValue. + const char *memberName() const; + + protected: + Value &deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance( const SelfType &other ) const; + + bool isEqual( const SelfType &other ) const; + + void copy( const SelfType &other ); + + private: +#ifndef JSON_VALUE_USE_INTERNAL_MAP + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; +#else + union + { + ValueInternalArray::IteratorState array_; + ValueInternalMap::IteratorState map_; + } iterator_; + bool isArray_; +#endif + }; + + /** \brief const iterator for object and array value. + * + */ + class ValueConstIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef const Value &reference; + typedef const Value *pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueConstIterator( const ValueInternalArray::IteratorState &state ); + ValueConstIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + SelfType &operator =( const ValueIteratorBase &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + + /** \brief Iterator for object and array value. + */ + class ValueIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef Value &reference; + typedef Value *pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + ValueIterator( const ValueConstIterator &other ); + ValueIterator( const ValueIterator &other ); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueIterator( const ValueInternalArray::IteratorState &state ); + ValueIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + + SelfType &operator =( const SelfType &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + +} // namespace Json + + +#endif // CPPTL_JSON_H_INCLUDED diff --git a/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/writer.h b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/writer.h new file mode 100644 index 0000000..e222d93 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/jsoncpp/writer.h @@ -0,0 +1,184 @@ +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +# define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +# include +# include + +namespace Json { + + class Value; + + /** \brief Abstract class for writers. + */ + class JSON_API Writer + { + public: + virtual ~Writer(); + + virtual std::string write( const Value &root ) = 0; + }; + + /** \brief Outputs a Value in JSON format without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + */ + class JSON_API FastWriter : public Writer + { + public: + FastWriter(); + virtual ~FastWriter(){} + + void enableYAMLCompatibility(); + + public: // overridden from Writer + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + + std::string document_; + bool yamlCompatiblityEnabled_; + }; + + /** \brief Writes a Value in JSON format in a human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledWriter: public Writer + { + public: + StyledWriter(); + virtual ~StyledWriter(){} + + public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; + }; + + /** \brief Writes a Value in JSON format in a human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledStreamWriter + { + public: + StyledStreamWriter( std::string indentation="\t" ); + ~StyledStreamWriter(){} + + public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not return a value. + */ + void write( std::ostream &out, const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_; + }; + +# if defined(JSON_HAS_INT64) + std::string JSON_API valueToString( Int value ); + std::string JSON_API valueToString( UInt value ); +# endif // if defined(JSON_HAS_INT64) + std::string JSON_API valueToString( LargestInt value ); + std::string JSON_API valueToString( LargestUInt value ); + std::string JSON_API valueToString( double value ); + std::string JSON_API valueToString( bool value ); + std::string JSON_API valueToQuotedString( const char *value ); + + /// \brief Output using the StyledStreamWriter. + /// \see Json::operator>>() + std::ostream& operator<<( std::ostream&, const Value &root ); + +} // namespace Json + + + +#endif // JSON_WRITER_H_INCLUDED diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv.h new file mode 100644 index 0000000..3bebe64 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv.h @@ -0,0 +1,33 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_H_ // NOLINT +#define INCLUDE_LIBYUV_H_ + +#include "libyuv/basic_types.h" +#include "libyuv/compare.h" +#include "libyuv/convert.h" +#include "libyuv/convert_argb.h" +#include "libyuv/convert_from.h" +#include "libyuv/convert_from_argb.h" +#include "libyuv/cpu_id.h" +#include "libyuv/format_conversion.h" +#include "libyuv/mjpeg_decoder.h" +#include "libyuv/planar_functions.h" +#include "libyuv/rotate.h" +#include "libyuv/rotate_argb.h" +#include "libyuv/row.h" +#include "libyuv/scale.h" +#include "libyuv/scale_argb.h" +#include "libyuv/scale_row.h" +#include "libyuv/version.h" +#include "libyuv/video_common.h" + +#endif // INCLUDE_LIBYUV_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/basic_types.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/basic_types.h new file mode 100644 index 0000000..beb750b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/basic_types.h @@ -0,0 +1,118 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_BASIC_TYPES_H_ // NOLINT +#define INCLUDE_LIBYUV_BASIC_TYPES_H_ + +#include // for NULL, size_t + +#if defined(__ANDROID__) || (defined(_MSC_VER) && (_MSC_VER < 1600)) +#include // for uintptr_t on x86 +#else +#include // for uintptr_t +#endif + +#ifndef GG_LONGLONG +#ifndef INT_TYPES_DEFINED +#define INT_TYPES_DEFINED +#ifdef COMPILER_MSVC +typedef unsigned __int64 uint64; +typedef __int64 int64; +#ifndef INT64_C +#define INT64_C(x) x ## I64 +#endif +#ifndef UINT64_C +#define UINT64_C(x) x ## UI64 +#endif +#define INT64_F "I64" +#else // COMPILER_MSVC +#if defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__) +typedef unsigned long uint64; // NOLINT +typedef long int64; // NOLINT +#ifndef INT64_C +#define INT64_C(x) x ## L +#endif +#ifndef UINT64_C +#define UINT64_C(x) x ## UL +#endif +#define INT64_F "l" +#else // defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__) +typedef unsigned long long uint64; // NOLINT +typedef long long int64; // NOLINT +#ifndef INT64_C +#define INT64_C(x) x ## LL +#endif +#ifndef UINT64_C +#define UINT64_C(x) x ## ULL +#endif +#define INT64_F "ll" +#endif // __LP64__ +#endif // COMPILER_MSVC +typedef unsigned int uint32; +typedef int int32; +typedef unsigned short uint16; // NOLINT +typedef short int16; // NOLINT +typedef unsigned char uint8; +typedef signed char int8; +#endif // INT_TYPES_DEFINED +#endif // GG_LONGLONG + +// Detect compiler is for x86 or x64. +#if defined(__x86_64__) || defined(_M_X64) || \ + defined(__i386__) || defined(_M_IX86) +#define CPU_X86 1 +#endif +// Detect compiler is for ARM. +#if defined(__arm__) || defined(_M_ARM) +#define CPU_ARM 1 +#endif + +#ifndef ALIGNP +#ifdef __cplusplus +#define ALIGNP(p, t) \ + (reinterpret_cast(((reinterpret_cast(p) + \ + ((t) - 1)) & ~((t) - 1)))) +#else +#define ALIGNP(p, t) \ + ((uint8*)((((uintptr_t)(p) + ((t) - 1)) & ~((t) - 1)))) /* NOLINT */ +#endif +#endif + +#if !defined(LIBYUV_API) +#if defined(_WIN32) || defined(__CYGWIN__) +#if defined(LIBYUV_BUILDING_SHARED_LIBRARY) +#define LIBYUV_API __declspec(dllexport) +#elif defined(LIBYUV_USING_SHARED_LIBRARY) +#define LIBYUV_API __declspec(dllimport) +#else +#define LIBYUV_API +#endif // LIBYUV_BUILDING_SHARED_LIBRARY +#elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__APPLE__) && \ + (defined(LIBYUV_BUILDING_SHARED_LIBRARY) || \ + defined(LIBYUV_USING_SHARED_LIBRARY)) +#define LIBYUV_API __attribute__ ((visibility ("default"))) +#else +#define LIBYUV_API +#endif // __GNUC__ +#endif // LIBYUV_API + +#define LIBYUV_BOOL int +#define LIBYUV_FALSE 0 +#define LIBYUV_TRUE 1 + +// Visual C x86 or GCC little endian. +#if defined(__x86_64__) || defined(_M_X64) || \ + defined(__i386__) || defined(_M_IX86) || \ + defined(__arm__) || defined(_M_ARM) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define LIBYUV_LITTLE_ENDIAN +#endif + +#endif // INCLUDE_LIBYUV_BASIC_TYPES_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/compare.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/compare.h new file mode 100644 index 0000000..5dfac7c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/compare.h @@ -0,0 +1,73 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_COMPARE_H_ // NOLINT +#define INCLUDE_LIBYUV_COMPARE_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Compute a hash for specified memory. Seed of 5381 recommended. +LIBYUV_API +uint32 HashDjb2(const uint8* src, uint64 count, uint32 seed); + +// Sum Square Error - used to compute Mean Square Error or PSNR. +LIBYUV_API +uint64 ComputeSumSquareError(const uint8* src_a, + const uint8* src_b, int count); + +LIBYUV_API +uint64 ComputeSumSquareErrorPlane(const uint8* src_a, int stride_a, + const uint8* src_b, int stride_b, + int width, int height); + +static const int kMaxPsnr = 128; + +LIBYUV_API +double SumSquareErrorToPsnr(uint64 sse, uint64 count); + +LIBYUV_API +double CalcFramePsnr(const uint8* src_a, int stride_a, + const uint8* src_b, int stride_b, + int width, int height); + +LIBYUV_API +double I420Psnr(const uint8* src_y_a, int stride_y_a, + const uint8* src_u_a, int stride_u_a, + const uint8* src_v_a, int stride_v_a, + const uint8* src_y_b, int stride_y_b, + const uint8* src_u_b, int stride_u_b, + const uint8* src_v_b, int stride_v_b, + int width, int height); + +LIBYUV_API +double CalcFrameSsim(const uint8* src_a, int stride_a, + const uint8* src_b, int stride_b, + int width, int height); + +LIBYUV_API +double I420Ssim(const uint8* src_y_a, int stride_y_a, + const uint8* src_u_a, int stride_u_a, + const uint8* src_v_a, int stride_v_a, + const uint8* src_y_b, int stride_y_b, + const uint8* src_u_b, int stride_u_b, + const uint8* src_v_b, int stride_v_b, + int width, int height); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_COMPARE_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert.h new file mode 100644 index 0000000..1bd45c8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert.h @@ -0,0 +1,254 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_CONVERT_H_ // NOLINT +#define INCLUDE_LIBYUV_CONVERT_H_ + +#include "libyuv/basic_types.h" +// TODO(fbarchard): Remove the following headers includes. +#include "libyuv/convert_from.h" +#include "libyuv/planar_functions.h" +#include "libyuv/rotate.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Convert I444 to I420. +LIBYUV_API +int I444ToI420(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert I422 to I420. +LIBYUV_API +int I422ToI420(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert I411 to I420. +LIBYUV_API +int I411ToI420(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Copy I420 to I420. +#define I420ToI420 I420Copy +LIBYUV_API +int I420Copy(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert I400 (grey) to I420. +LIBYUV_API +int I400ToI420(const uint8* src_y, int src_stride_y, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert NV12 to I420. +LIBYUV_API +int NV12ToI420(const uint8* src_y, int src_stride_y, + const uint8* src_uv, int src_stride_uv, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert NV21 to I420. +LIBYUV_API +int NV21ToI420(const uint8* src_y, int src_stride_y, + const uint8* src_vu, int src_stride_vu, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert YUY2 to I420. +LIBYUV_API +int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert UYVY to I420. +LIBYUV_API +int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert M420 to I420. +LIBYUV_API +int M420ToI420(const uint8* src_m420, int src_stride_m420, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert Q420 to I420. +LIBYUV_API +int Q420ToI420(const uint8* src_y, int src_stride_y, + const uint8* src_yuy2, int src_stride_yuy2, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// ARGB little endian (bgra in memory) to I420. +LIBYUV_API +int ARGBToI420(const uint8* src_frame, int src_stride_frame, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// BGRA little endian (argb in memory) to I420. +LIBYUV_API +int BGRAToI420(const uint8* src_frame, int src_stride_frame, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// ABGR little endian (rgba in memory) to I420. +LIBYUV_API +int ABGRToI420(const uint8* src_frame, int src_stride_frame, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// RGBA little endian (abgr in memory) to I420. +LIBYUV_API +int RGBAToI420(const uint8* src_frame, int src_stride_frame, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// RGB little endian (bgr in memory) to I420. +LIBYUV_API +int RGB24ToI420(const uint8* src_frame, int src_stride_frame, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// RGB big endian (rgb in memory) to I420. +LIBYUV_API +int RAWToI420(const uint8* src_frame, int src_stride_frame, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// RGB16 (RGBP fourcc) little endian to I420. +LIBYUV_API +int RGB565ToI420(const uint8* src_frame, int src_stride_frame, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// RGB15 (RGBO fourcc) little endian to I420. +LIBYUV_API +int ARGB1555ToI420(const uint8* src_frame, int src_stride_frame, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// RGB12 (R444 fourcc) little endian to I420. +LIBYUV_API +int ARGB4444ToI420(const uint8* src_frame, int src_stride_frame, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +#ifdef HAVE_JPEG +// src_width/height provided by capture. +// dst_width/height for clipping determine final size. +LIBYUV_API +int MJPGToI420(const uint8* sample, size_t sample_size, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int src_width, int src_height, + int dst_width, int dst_height); + +// Query size of MJPG in pixels. +LIBYUV_API +int MJPGSize(const uint8* sample, size_t sample_size, + int* width, int* height); +#endif + +// Note Bayer formats (BGGR) To I420 are in format_conversion.h + +// Convert camera sample to I420 with cropping, rotation and vertical flip. +// "src_size" is needed to parse MJPG. +// "dst_stride_y" number of bytes in a row of the dst_y plane. +// Normally this would be the same as dst_width, with recommended alignment +// to 16 bytes for better efficiency. +// If rotation of 90 or 270 is used, stride is affected. The caller should +// allocate the I420 buffer according to rotation. +// "dst_stride_u" number of bytes in a row of the dst_u plane. +// Normally this would be the same as (dst_width + 1) / 2, with +// recommended alignment to 16 bytes for better efficiency. +// If rotation of 90 or 270 is used, stride is affected. +// "crop_x" and "crop_y" are starting position for cropping. +// To center, crop_x = (src_width - dst_width) / 2 +// crop_y = (src_height - dst_height) / 2 +// "src_width" / "src_height" is size of src_frame in pixels. +// "src_height" can be negative indicating a vertically flipped image source. +// "crop_width" / "crop_height" is the size to crop the src to. +// Must be less than or equal to src_width/src_height +// Cropping parameters are pre-rotation. +// "rotation" can be 0, 90, 180 or 270. +// "format" is a fourcc. ie 'I420', 'YUY2' +// Returns 0 for successful; -1 for invalid parameter. Non-zero for failure. +LIBYUV_API +int ConvertToI420(const uint8* src_frame, size_t src_size, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int crop_x, int crop_y, + int src_width, int src_height, + int crop_width, int crop_height, + enum RotationMode rotation, + uint32 format); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_CONVERT_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_argb.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_argb.h new file mode 100644 index 0000000..a18014c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_argb.h @@ -0,0 +1,225 @@ +/* + * Copyright 2012 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_CONVERT_ARGB_H_ // NOLINT +#define INCLUDE_LIBYUV_CONVERT_ARGB_H_ + +#include "libyuv/basic_types.h" +// TODO(fbarchard): Remove the following headers includes +#include "libyuv/convert_from.h" +#include "libyuv/planar_functions.h" +#include "libyuv/rotate.h" + +// TODO(fbarchard): This set of functions should exactly match convert.h +// Add missing Q420. +// TODO(fbarchard): Add tests. Create random content of right size and convert +// with C vs Opt and or to I420 and compare. +// TODO(fbarchard): Some of these functions lack parameter setting. + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Alias. +#define ARGBToARGB ARGBCopy + +// Copy ARGB to ARGB. +LIBYUV_API +int ARGBCopy(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert I420 to ARGB. +LIBYUV_API +int I420ToARGB(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert I422 to ARGB. +LIBYUV_API +int I422ToARGB(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert I444 to ARGB. +LIBYUV_API +int I444ToARGB(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert I411 to ARGB. +LIBYUV_API +int I411ToARGB(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert I400 (grey) to ARGB. +LIBYUV_API +int I400ToARGB(const uint8* src_y, int src_stride_y, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Alias. +#define YToARGB I400ToARGB_Reference + +// Convert I400 to ARGB. Reverse of ARGBToI400. +LIBYUV_API +int I400ToARGB_Reference(const uint8* src_y, int src_stride_y, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert NV12 to ARGB. +LIBYUV_API +int NV12ToARGB(const uint8* src_y, int src_stride_y, + const uint8* src_uv, int src_stride_uv, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert NV21 to ARGB. +LIBYUV_API +int NV21ToARGB(const uint8* src_y, int src_stride_y, + const uint8* src_vu, int src_stride_vu, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert M420 to ARGB. +LIBYUV_API +int M420ToARGB(const uint8* src_m420, int src_stride_m420, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// TODO(fbarchard): Convert Q420 to ARGB. +// LIBYUV_API +// int Q420ToARGB(const uint8* src_y, int src_stride_y, +// const uint8* src_yuy2, int src_stride_yuy2, +// uint8* dst_argb, int dst_stride_argb, +// int width, int height); + +// Convert YUY2 to ARGB. +LIBYUV_API +int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert UYVY to ARGB. +LIBYUV_API +int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// BGRA little endian (argb in memory) to ARGB. +LIBYUV_API +int BGRAToARGB(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// ABGR little endian (rgba in memory) to ARGB. +LIBYUV_API +int ABGRToARGB(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// RGBA little endian (abgr in memory) to ARGB. +LIBYUV_API +int RGBAToARGB(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Deprecated function name. +#define BG24ToARGB RGB24ToARGB + +// RGB little endian (bgr in memory) to ARGB. +LIBYUV_API +int RGB24ToARGB(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// RGB big endian (rgb in memory) to ARGB. +LIBYUV_API +int RAWToARGB(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// RGB16 (RGBP fourcc) little endian to ARGB. +LIBYUV_API +int RGB565ToARGB(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// RGB15 (RGBO fourcc) little endian to ARGB. +LIBYUV_API +int ARGB1555ToARGB(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// RGB12 (R444 fourcc) little endian to ARGB. +LIBYUV_API +int ARGB4444ToARGB(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +#ifdef HAVE_JPEG +// src_width/height provided by capture +// dst_width/height for clipping determine final size. +LIBYUV_API +int MJPGToARGB(const uint8* sample, size_t sample_size, + uint8* dst_argb, int dst_stride_argb, + int src_width, int src_height, + int dst_width, int dst_height); +#endif + +// Note Bayer formats (BGGR) to ARGB are in format_conversion.h. + +// Convert camera sample to ARGB with cropping, rotation and vertical flip. +// "src_size" is needed to parse MJPG. +// "dst_stride_argb" number of bytes in a row of the dst_argb plane. +// Normally this would be the same as dst_width, with recommended alignment +// to 16 bytes for better efficiency. +// If rotation of 90 or 270 is used, stride is affected. The caller should +// allocate the I420 buffer according to rotation. +// "dst_stride_u" number of bytes in a row of the dst_u plane. +// Normally this would be the same as (dst_width + 1) / 2, with +// recommended alignment to 16 bytes for better efficiency. +// If rotation of 90 or 270 is used, stride is affected. +// "crop_x" and "crop_y" are starting position for cropping. +// To center, crop_x = (src_width - dst_width) / 2 +// crop_y = (src_height - dst_height) / 2 +// "src_width" / "src_height" is size of src_frame in pixels. +// "src_height" can be negative indicating a vertically flipped image source. +// "crop_width" / "crop_height" is the size to crop the src to. +// Must be less than or equal to src_width/src_height +// Cropping parameters are pre-rotation. +// "rotation" can be 0, 90, 180 or 270. +// "format" is a fourcc. ie 'I420', 'YUY2' +// Returns 0 for successful; -1 for invalid parameter. Non-zero for failure. +LIBYUV_API +int ConvertToARGB(const uint8* src_frame, size_t src_size, + uint8* dst_argb, int dst_stride_argb, + int crop_x, int crop_y, + int src_width, int src_height, + int crop_width, int crop_height, + enum RotationMode rotation, + uint32 format); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_CONVERT_ARGB_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_from.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_from.h new file mode 100644 index 0000000..b1cf57f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_from.h @@ -0,0 +1,173 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_CONVERT_FROM_H_ // NOLINT +#define INCLUDE_LIBYUV_CONVERT_FROM_H_ + +#include "libyuv/basic_types.h" +#include "libyuv/rotate.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// See Also convert.h for conversions from formats to I420. + +// I420Copy in convert to I420ToI420. + +LIBYUV_API +int I420ToI422(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +LIBYUV_API +int I420ToI444(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +LIBYUV_API +int I420ToI411(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Copy to I400. Source can be I420, I422, I444, I400, NV12 or NV21. +LIBYUV_API +int I400Copy(const uint8* src_y, int src_stride_y, + uint8* dst_y, int dst_stride_y, + int width, int height); + +// TODO(fbarchard): I420ToM420 +// TODO(fbarchard): I420ToQ420 + +LIBYUV_API +int I420ToNV12(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_uv, int dst_stride_uv, + int width, int height); + +LIBYUV_API +int I420ToNV21(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_vu, int dst_stride_vu, + int width, int height); + +LIBYUV_API +int I420ToYUY2(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +LIBYUV_API +int I420ToUYVY(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +LIBYUV_API +int I420ToARGB(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +LIBYUV_API +int I420ToBGRA(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +LIBYUV_API +int I420ToABGR(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +LIBYUV_API +int I420ToRGBA(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_rgba, int dst_stride_rgba, + int width, int height); + +LIBYUV_API +int I420ToRGB24(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +LIBYUV_API +int I420ToRAW(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +LIBYUV_API +int I420ToRGB565(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +LIBYUV_API +int I420ToARGB1555(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +LIBYUV_API +int I420ToARGB4444(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +// Note Bayer formats (BGGR) To I420 are in format_conversion.h. + +// Convert I420 to specified format. +// "dst_sample_stride" is bytes in a row for the destination. Pass 0 if the +// buffer has contiguous rows. Can be negative. A multiple of 16 is optimal. +LIBYUV_API +int ConvertFromI420(const uint8* y, int y_stride, + const uint8* u, int u_stride, + const uint8* v, int v_stride, + uint8* dst_sample, int dst_sample_stride, + int width, int height, + uint32 format); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_CONVERT_FROM_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_from_argb.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_from_argb.h new file mode 100644 index 0000000..f0343a7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/convert_from_argb.h @@ -0,0 +1,168 @@ +/* + * Copyright 2012 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_CONVERT_FROM_ARGB_H_ // NOLINT +#define INCLUDE_LIBYUV_CONVERT_FROM_ARGB_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Copy ARGB to ARGB. +#define ARGBToARGB ARGBCopy +LIBYUV_API +int ARGBCopy(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert ARGB To BGRA. (alias) +#define ARGBToBGRA BGRAToARGB +LIBYUV_API +int BGRAToARGB(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert ARGB To ABGR. (alias) +#define ARGBToABGR ABGRToARGB +LIBYUV_API +int ABGRToARGB(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert ARGB To RGBA. +LIBYUV_API +int ARGBToRGBA(const uint8* src_frame, int src_stride_frame, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert ARGB To RGB24. +LIBYUV_API +int ARGBToRGB24(const uint8* src_argb, int src_stride_argb, + uint8* dst_rgb24, int dst_stride_rgb24, + int width, int height); + +// Convert ARGB To RAW. +LIBYUV_API +int ARGBToRAW(const uint8* src_argb, int src_stride_argb, + uint8* dst_rgb, int dst_stride_rgb, + int width, int height); + +// Convert ARGB To RGB565. +LIBYUV_API +int ARGBToRGB565(const uint8* src_argb, int src_stride_argb, + uint8* dst_rgb565, int dst_stride_rgb565, + int width, int height); + +// Convert ARGB To ARGB1555. +LIBYUV_API +int ARGBToARGB1555(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb1555, int dst_stride_argb1555, + int width, int height); + +// Convert ARGB To ARGB4444. +LIBYUV_API +int ARGBToARGB4444(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb4444, int dst_stride_argb4444, + int width, int height); + +// Convert ARGB To I444. +LIBYUV_API +int ARGBToI444(const uint8* src_argb, int src_stride_argb, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert ARGB To I422. +LIBYUV_API +int ARGBToI422(const uint8* src_argb, int src_stride_argb, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert ARGB To I420. (also in convert.h) +LIBYUV_API +int ARGBToI420(const uint8* src_argb, int src_stride_argb, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert ARGB to J420. (JPeg full range I420). +LIBYUV_API +int ARGBToJ420(const uint8* src_argb, int src_stride_argb, + uint8* dst_yj, int dst_stride_yj, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert ARGB To I411. +LIBYUV_API +int ARGBToI411(const uint8* src_argb, int src_stride_argb, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert ARGB to J400. (JPeg full range). +LIBYUV_API +int ARGBToJ400(const uint8* src_argb, int src_stride_argb, + uint8* dst_yj, int dst_stride_yj, + int width, int height); + +// Convert ARGB to I400. +LIBYUV_API +int ARGBToI400(const uint8* src_argb, int src_stride_argb, + uint8* dst_y, int dst_stride_y, + int width, int height); + +// Convert ARGB To NV12. +LIBYUV_API +int ARGBToNV12(const uint8* src_argb, int src_stride_argb, + uint8* dst_y, int dst_stride_y, + uint8* dst_uv, int dst_stride_uv, + int width, int height); + +// Convert ARGB To NV21. +LIBYUV_API +int ARGBToNV21(const uint8* src_argb, int src_stride_argb, + uint8* dst_y, int dst_stride_y, + uint8* dst_vu, int dst_stride_vu, + int width, int height); + +// Convert ARGB To NV21. +LIBYUV_API +int ARGBToNV21(const uint8* src_argb, int src_stride_argb, + uint8* dst_y, int dst_stride_y, + uint8* dst_vu, int dst_stride_vu, + int width, int height); + +// Convert ARGB To YUY2. +LIBYUV_API +int ARGBToYUY2(const uint8* src_argb, int src_stride_argb, + uint8* dst_yuy2, int dst_stride_yuy2, + int width, int height); + +// Convert ARGB To UYVY. +LIBYUV_API +int ARGBToUYVY(const uint8* src_argb, int src_stride_argb, + uint8* dst_uyvy, int dst_stride_uyvy, + int width, int height); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_CONVERT_FROM_ARGB_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/cpu_id.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/cpu_id.h new file mode 100644 index 0000000..dc858a8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/cpu_id.h @@ -0,0 +1,81 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_CPU_ID_H_ // NOLINT +#define INCLUDE_LIBYUV_CPU_ID_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// TODO(fbarchard): Consider overlapping bits for different architectures. +// Internal flag to indicate cpuid requires initialization. +#define kCpuInit 0x1 + +// These flags are only valid on ARM processors. +static const int kCpuHasARM = 0x2; +static const int kCpuHasNEON = 0x4; +// 0x8 reserved for future ARM flag. + +// These flags are only valid on x86 processors. +static const int kCpuHasX86 = 0x10; +static const int kCpuHasSSE2 = 0x20; +static const int kCpuHasSSSE3 = 0x40; +static const int kCpuHasSSE41 = 0x80; +static const int kCpuHasSSE42 = 0x100; +static const int kCpuHasAVX = 0x200; +static const int kCpuHasAVX2 = 0x400; +static const int kCpuHasERMS = 0x800; +static const int kCpuHasFMA3 = 0x1000; +// 0x2000, 0x4000, 0x8000 reserved for future X86 flags. + +// These flags are only valid on MIPS processors. +static const int kCpuHasMIPS = 0x10000; +static const int kCpuHasMIPS_DSP = 0x20000; +static const int kCpuHasMIPS_DSPR2 = 0x40000; + +// Internal function used to auto-init. +LIBYUV_API +int InitCpuFlags(void); + +// Internal function for parsing /proc/cpuinfo. +LIBYUV_API +int ArmCpuCaps(const char* cpuinfo_name); + +// Detect CPU has SSE2 etc. +// Test_flag parameter should be one of kCpuHas constants above. +// returns non-zero if instruction set is detected +static __inline int TestCpuFlag(int test_flag) { + LIBYUV_API extern int cpu_info_; + return (cpu_info_ == kCpuInit ? InitCpuFlags() : cpu_info_) & test_flag; +} + +// For testing, allow CPU flags to be disabled. +// ie MaskCpuFlags(~kCpuHasSSSE3) to disable SSSE3. +// MaskCpuFlags(-1) to enable all cpu specific optimizations. +// MaskCpuFlags(0) to disable all cpu specific optimizations. +LIBYUV_API +void MaskCpuFlags(int enable_flags); + +// Low level cpuid for X86. Returns zeros on other CPUs. +// eax is the info type that you want. +// ecx is typically the cpu number, and should normally be zero. +LIBYUV_API +void CpuId(uint32 eax, uint32 ecx, uint32* cpu_info); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_CPU_ID_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/format_conversion.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/format_conversion.h new file mode 100644 index 0000000..b18bf05 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/format_conversion.h @@ -0,0 +1,168 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_FORMATCONVERSION_H_ // NOLINT +#define INCLUDE_LIBYUV_FORMATCONVERSION_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Convert Bayer RGB formats to I420. +LIBYUV_API +int BayerBGGRToI420(const uint8* src_bayer, int src_stride_bayer, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +LIBYUV_API +int BayerGBRGToI420(const uint8* src_bayer, int src_stride_bayer, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +LIBYUV_API +int BayerGRBGToI420(const uint8* src_bayer, int src_stride_bayer, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +LIBYUV_API +int BayerRGGBToI420(const uint8* src_bayer, int src_stride_bayer, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Temporary API mapper. +#define BayerRGBToI420(b, bs, f, y, ys, u, us, v, vs, w, h) \ + BayerToI420(b, bs, y, ys, u, us, v, vs, w, h, f) + +LIBYUV_API +int BayerToI420(const uint8* src_bayer, int src_stride_bayer, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height, + uint32 src_fourcc_bayer); + +// Convert I420 to Bayer RGB formats. +LIBYUV_API +int I420ToBayerBGGR(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +LIBYUV_API +int I420ToBayerGBRG(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +LIBYUV_API +int I420ToBayerGRBG(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +LIBYUV_API +int I420ToBayerRGGB(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +// Temporary API mapper. +#define I420ToBayerRGB(y, ys, u, us, v, vs, b, bs, f, w, h) \ + I420ToBayer(y, ys, u, us, v, vs, b, bs, w, h, f) + +LIBYUV_API +int I420ToBayer(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height, + uint32 dst_fourcc_bayer); + +// Convert Bayer RGB formats to ARGB. +LIBYUV_API +int BayerBGGRToARGB(const uint8* src_bayer, int src_stride_bayer, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +LIBYUV_API +int BayerGBRGToARGB(const uint8* src_bayer, int src_stride_bayer, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +LIBYUV_API +int BayerGRBGToARGB(const uint8* src_bayer, int src_stride_bayer, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +LIBYUV_API +int BayerRGGBToARGB(const uint8* src_bayer, int src_stride_bayer, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Temporary API mapper. +#define BayerRGBToARGB(b, bs, f, a, as, w, h) BayerToARGB(b, bs, a, as, w, h, f) + +LIBYUV_API +int BayerToARGB(const uint8* src_bayer, int src_stride_bayer, + uint8* dst_argb, int dst_stride_argb, + int width, int height, + uint32 src_fourcc_bayer); + +// Converts ARGB to Bayer RGB formats. +LIBYUV_API +int ARGBToBayerBGGR(const uint8* src_argb, int src_stride_argb, + uint8* dst_bayer, int dst_stride_bayer, + int width, int height); + +LIBYUV_API +int ARGBToBayerGBRG(const uint8* src_argb, int src_stride_argb, + uint8* dst_bayer, int dst_stride_bayer, + int width, int height); + +LIBYUV_API +int ARGBToBayerGRBG(const uint8* src_argb, int src_stride_argb, + uint8* dst_bayer, int dst_stride_bayer, + int width, int height); + +LIBYUV_API +int ARGBToBayerRGGB(const uint8* src_argb, int src_stride_argb, + uint8* dst_bayer, int dst_stride_bayer, + int width, int height); + +// Temporary API mapper. +#define ARGBToBayerRGB(a, as, b, bs, f, w, h) ARGBToBayer(b, bs, a, as, w, h, f) + +LIBYUV_API +int ARGBToBayer(const uint8* src_argb, int src_stride_argb, + uint8* dst_bayer, int dst_stride_bayer, + int width, int height, + uint32 dst_fourcc_bayer); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_FORMATCONVERSION_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/mjpeg_decoder.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/mjpeg_decoder.h new file mode 100644 index 0000000..faffaea --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/mjpeg_decoder.h @@ -0,0 +1,201 @@ +/* + * Copyright 2012 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_MJPEG_DECODER_H_ // NOLINT +#define INCLUDE_LIBYUV_MJPEG_DECODER_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +// NOTE: For a simplified public API use convert.h MJPGToI420(). + +struct jpeg_common_struct; +struct jpeg_decompress_struct; +struct jpeg_source_mgr; + +namespace libyuv { + +#ifdef __cplusplus +extern "C" { +#endif + +LIBYUV_BOOL ValidateJpeg(const uint8* sample, size_t sample_size); + +#ifdef __cplusplus +} // extern "C" +#endif + +static const uint32 kUnknownDataSize = 0xFFFFFFFF; + +enum JpegSubsamplingType { + kJpegYuv420, + kJpegYuv422, + kJpegYuv411, + kJpegYuv444, + kJpegYuv400, + kJpegUnknown +}; + +struct SetJmpErrorMgr; + +// MJPEG ("Motion JPEG") is a pseudo-standard video codec where the frames are +// simply independent JPEG images with a fixed huffman table (which is omitted). +// It is rarely used in video transmission, but is common as a camera capture +// format, especially in Logitech devices. This class implements a decoder for +// MJPEG frames. +// +// See http://tools.ietf.org/html/rfc2435 +class LIBYUV_API MJpegDecoder { + public: + typedef void (*CallbackFunction)(void* opaque, + const uint8* const* data, + const int* strides, + int rows); + + static const int kColorSpaceUnknown; + static const int kColorSpaceGrayscale; + static const int kColorSpaceRgb; + static const int kColorSpaceYCbCr; + static const int kColorSpaceCMYK; + static const int kColorSpaceYCCK; + + MJpegDecoder(); + ~MJpegDecoder(); + + // Loads a new frame, reads its headers, and determines the uncompressed + // image format. + // Returns LIBYUV_TRUE if image looks valid and format is supported. + // If return value is LIBYUV_TRUE, then the values for all the following + // getters are populated. + // src_len is the size of the compressed mjpeg frame in bytes. + LIBYUV_BOOL LoadFrame(const uint8* src, size_t src_len); + + // Returns width of the last loaded frame in pixels. + int GetWidth(); + + // Returns height of the last loaded frame in pixels. + int GetHeight(); + + // Returns format of the last loaded frame. The return value is one of the + // kColorSpace* constants. + int GetColorSpace(); + + // Number of color components in the color space. + int GetNumComponents(); + + // Sample factors of the n-th component. + int GetHorizSampFactor(int component); + + int GetVertSampFactor(int component); + + int GetHorizSubSampFactor(int component); + + int GetVertSubSampFactor(int component); + + // Public for testability. + int GetImageScanlinesPerImcuRow(); + + // Public for testability. + int GetComponentScanlinesPerImcuRow(int component); + + // Width of a component in bytes. + int GetComponentWidth(int component); + + // Height of a component. + int GetComponentHeight(int component); + + // Width of a component in bytes with padding for DCTSIZE. Public for testing. + int GetComponentStride(int component); + + // Size of a component in bytes. + int GetComponentSize(int component); + + // Call this after LoadFrame() if you decide you don't want to decode it + // after all. + LIBYUV_BOOL UnloadFrame(); + + // Decodes the entire image into a one-buffer-per-color-component format. + // dst_width must match exactly. dst_height must be <= to image height; if + // less, the image is cropped. "planes" must have size equal to at least + // GetNumComponents() and they must point to non-overlapping buffers of size + // at least GetComponentSize(i). The pointers in planes are incremented + // to point to after the end of the written data. + // TODO(fbarchard): Add dst_x, dst_y to allow specific rect to be decoded. + LIBYUV_BOOL DecodeToBuffers(uint8** planes, int dst_width, int dst_height); + + // Decodes the entire image and passes the data via repeated calls to a + // callback function. Each call will get the data for a whole number of + // image scanlines. + // TODO(fbarchard): Add dst_x, dst_y to allow specific rect to be decoded. + LIBYUV_BOOL DecodeToCallback(CallbackFunction fn, void* opaque, + int dst_width, int dst_height); + + // The helper function which recognizes the jpeg sub-sampling type. + static JpegSubsamplingType JpegSubsamplingTypeHelper( + int* subsample_x, int* subsample_y, int number_of_components); + + private: + struct Buffer { + const uint8* data; + int len; + }; + + struct BufferVector { + Buffer* buffers; + int len; + int pos; + }; + + // Methods that are passed to jpeglib. + static int fill_input_buffer(jpeg_decompress_struct* cinfo); + static void init_source(jpeg_decompress_struct* cinfo); + static void skip_input_data(jpeg_decompress_struct* cinfo, + long num_bytes); // NOLINT + static void term_source(jpeg_decompress_struct* cinfo); + + static void ErrorHandler(jpeg_common_struct* cinfo); + + void AllocOutputBuffers(int num_outbufs); + void DestroyOutputBuffers(); + + LIBYUV_BOOL StartDecode(); + LIBYUV_BOOL FinishDecode(); + + void SetScanlinePointers(uint8** data); + LIBYUV_BOOL DecodeImcuRow(); + + int GetComponentScanlinePadding(int component); + + // A buffer holding the input data for a frame. + Buffer buf_; + BufferVector buf_vec_; + + jpeg_decompress_struct* decompress_struct_; + jpeg_source_mgr* source_mgr_; + SetJmpErrorMgr* error_mgr_; + + // LIBYUV_TRUE iff at least one component has scanline padding. (i.e., + // GetComponentScanlinePadding() != 0.) + LIBYUV_BOOL has_scanline_padding_; + + // Temporaries used to point to scanline outputs. + int num_outbufs_; // Outermost size of all arrays below. + uint8*** scanlines_; + int* scanlines_sizes_; + // Temporary buffer used for decoding when we can't decode directly to the + // output buffers. Large enough for just one iMCU row. + uint8** databuf_; + int* databuf_strides_; +}; + +} // namespace libyuv + +#endif // __cplusplus +#endif // INCLUDE_LIBYUV_MJPEG_DECODER_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/planar_functions.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/planar_functions.h new file mode 100644 index 0000000..ac516c5 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/planar_functions.h @@ -0,0 +1,434 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_PLANAR_FUNCTIONS_H_ // NOLINT +#define INCLUDE_LIBYUV_PLANAR_FUNCTIONS_H_ + +#include "libyuv/basic_types.h" + +// TODO(fbarchard): Remove the following headers includes. +#include "libyuv/convert.h" +#include "libyuv/convert_argb.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Copy a plane of data. +LIBYUV_API +void CopyPlane(const uint8* src_y, int src_stride_y, + uint8* dst_y, int dst_stride_y, + int width, int height); + +// Set a plane of data to a 32 bit value. +LIBYUV_API +void SetPlane(uint8* dst_y, int dst_stride_y, + int width, int height, + uint32 value); + +// Copy I400. Supports inverting. +LIBYUV_API +int I400ToI400(const uint8* src_y, int src_stride_y, + uint8* dst_y, int dst_stride_y, + int width, int height); + + +// Copy I422 to I422. +#define I422ToI422 I422Copy +LIBYUV_API +int I422Copy(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Copy I444 to I444. +#define I444ToI444 I444Copy +LIBYUV_API +int I444Copy(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert YUY2 to I422. +LIBYUV_API +int YUY2ToI422(const uint8* src_yuy2, int src_stride_yuy2, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert UYVY to I422. +LIBYUV_API +int UYVYToI422(const uint8* src_uyvy, int src_stride_uyvy, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Convert I420 to I400. (calls CopyPlane ignoring u/v). +LIBYUV_API +int I420ToI400(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + int width, int height); + +// Alias +#define I420ToI420Mirror I420Mirror + +// I420 mirror. +LIBYUV_API +int I420Mirror(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int width, int height); + +// Alias +#define I400ToI400Mirror I400Mirror + +// I400 mirror. A single plane is mirrored horizontally. +// Pass negative height to achieve 180 degree rotation. +LIBYUV_API +int I400Mirror(const uint8* src_y, int src_stride_y, + uint8* dst_y, int dst_stride_y, + int width, int height); + +// Alias +#define ARGBToARGBMirror ARGBMirror + +// ARGB mirror. +LIBYUV_API +int ARGBMirror(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert NV12 to RGB565. +LIBYUV_API +int NV12ToRGB565(const uint8* src_y, int src_stride_y, + const uint8* src_uv, int src_stride_uv, + uint8* dst_rgb565, int dst_stride_rgb565, + int width, int height); + +// Convert NV21 to RGB565. +LIBYUV_API +int NV21ToRGB565(const uint8* src_y, int src_stride_y, + const uint8* src_uv, int src_stride_uv, + uint8* dst_rgb565, int dst_stride_rgb565, + int width, int height); + +// I422ToARGB is in convert_argb.h +// Convert I422 to BGRA. +LIBYUV_API +int I422ToBGRA(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_bgra, int dst_stride_bgra, + int width, int height); + +// Convert I422 to ABGR. +LIBYUV_API +int I422ToABGR(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_abgr, int dst_stride_abgr, + int width, int height); + +// Convert I422 to RGBA. +LIBYUV_API +int I422ToRGBA(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_rgba, int dst_stride_rgba, + int width, int height); + +// Draw a rectangle into I420. +LIBYUV_API +int I420Rect(uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int x, int y, int width, int height, + int value_y, int value_u, int value_v); + +// Draw a rectangle into ARGB. +LIBYUV_API +int ARGBRect(uint8* dst_argb, int dst_stride_argb, + int x, int y, int width, int height, uint32 value); + +// Convert ARGB to gray scale ARGB. +LIBYUV_API +int ARGBGrayTo(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Make a rectangle of ARGB gray scale. +LIBYUV_API +int ARGBGray(uint8* dst_argb, int dst_stride_argb, + int x, int y, int width, int height); + +// Make a rectangle of ARGB Sepia tone. +LIBYUV_API +int ARGBSepia(uint8* dst_argb, int dst_stride_argb, + int x, int y, int width, int height); + +// Apply a matrix rotation to each ARGB pixel. +// matrix_argb is 4 signed ARGB values. -128 to 127 representing -2 to 2. +// The first 4 coefficients apply to B, G, R, A and produce B of the output. +// The next 4 coefficients apply to B, G, R, A and produce G of the output. +// The next 4 coefficients apply to B, G, R, A and produce R of the output. +// The last 4 coefficients apply to B, G, R, A and produce A of the output. +LIBYUV_API +int ARGBColorMatrix(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + const int8* matrix_argb, + int width, int height); + +// Deprecated. Use ARGBColorMatrix instead. +// Apply a matrix rotation to each ARGB pixel. +// matrix_argb is 3 signed ARGB values. -128 to 127 representing -1 to 1. +// The first 4 coefficients apply to B, G, R, A and produce B of the output. +// The next 4 coefficients apply to B, G, R, A and produce G of the output. +// The last 4 coefficients apply to B, G, R, A and produce R of the output. +LIBYUV_API +int RGBColorMatrix(uint8* dst_argb, int dst_stride_argb, + const int8* matrix_rgb, + int x, int y, int width, int height); + +// Apply a color table each ARGB pixel. +// Table contains 256 ARGB values. +LIBYUV_API +int ARGBColorTable(uint8* dst_argb, int dst_stride_argb, + const uint8* table_argb, + int x, int y, int width, int height); + +// Apply a color table each ARGB pixel but preserve destination alpha. +// Table contains 256 ARGB values. +LIBYUV_API +int RGBColorTable(uint8* dst_argb, int dst_stride_argb, + const uint8* table_argb, + int x, int y, int width, int height); + +// Apply a luma/color table each ARGB pixel but preserve destination alpha. +// Table contains 32768 values indexed by [Y][C] where 7 it 7 bit luma from +// RGB (YJ style) and C is an 8 bit color component (R, G or B). +LIBYUV_API +int ARGBLumaColorTable(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + const uint8* luma_rgb_table, + int width, int height); + +// Apply a 3 term polynomial to ARGB values. +// poly points to a 4x4 matrix. The first row is constants. The 2nd row is +// coefficients for b, g, r and a. The 3rd row is coefficients for b squared, +// g squared, r squared and a squared. The 4rd row is coefficients for b to +// the 3, g to the 3, r to the 3 and a to the 3. The values are summed and +// result clamped to 0 to 255. +// A polynomial approximation can be dirived using software such as 'R'. + +LIBYUV_API +int ARGBPolynomial(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + const float* poly, + int width, int height); + +// Quantize a rectangle of ARGB. Alpha unaffected. +// scale is a 16 bit fractional fixed point scaler between 0 and 65535. +// interval_size should be a value between 1 and 255. +// interval_offset should be a value between 0 and 255. +LIBYUV_API +int ARGBQuantize(uint8* dst_argb, int dst_stride_argb, + int scale, int interval_size, int interval_offset, + int x, int y, int width, int height); + +// Copy ARGB to ARGB. +LIBYUV_API +int ARGBCopy(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Copy ARGB to ARGB. +LIBYUV_API +int ARGBCopyAlpha(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Copy ARGB to ARGB. +LIBYUV_API +int ARGBCopyYToAlpha(const uint8* src_y, int src_stride_y, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +typedef void (*ARGBBlendRow)(const uint8* src_argb0, const uint8* src_argb1, + uint8* dst_argb, int width); + +// Get function to Alpha Blend ARGB pixels and store to destination. +LIBYUV_API +ARGBBlendRow GetARGBBlend(); + +// Alpha Blend ARGB images and store to destination. +// Alpha of destination is set to 255. +LIBYUV_API +int ARGBBlend(const uint8* src_argb0, int src_stride_argb0, + const uint8* src_argb1, int src_stride_argb1, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Multiply ARGB image by ARGB image. Shifted down by 8. Saturates to 255. +LIBYUV_API +int ARGBMultiply(const uint8* src_argb0, int src_stride_argb0, + const uint8* src_argb1, int src_stride_argb1, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Add ARGB image with ARGB image. Saturates to 255. +LIBYUV_API +int ARGBAdd(const uint8* src_argb0, int src_stride_argb0, + const uint8* src_argb1, int src_stride_argb1, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Subtract ARGB image (argb1) from ARGB image (argb0). Saturates to 0. +LIBYUV_API +int ARGBSubtract(const uint8* src_argb0, int src_stride_argb0, + const uint8* src_argb1, int src_stride_argb1, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert I422 to YUY2. +LIBYUV_API +int I422ToYUY2(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +// Convert I422 to UYVY. +LIBYUV_API +int I422ToUYVY(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_frame, int dst_stride_frame, + int width, int height); + +// Convert unattentuated ARGB to preattenuated ARGB. +LIBYUV_API +int ARGBAttenuate(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert preattentuated ARGB to unattenuated ARGB. +LIBYUV_API +int ARGBUnattenuate(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Convert MJPG to ARGB. +LIBYUV_API +int MJPGToARGB(const uint8* sample, size_t sample_size, + uint8* argb, int argb_stride, + int w, int h, int dw, int dh); + +// Internal function - do not call directly. +// Computes table of cumulative sum for image where the value is the sum +// of all values above and to the left of the entry. Used by ARGBBlur. +LIBYUV_API +int ARGBComputeCumulativeSum(const uint8* src_argb, int src_stride_argb, + int32* dst_cumsum, int dst_stride32_cumsum, + int width, int height); + +// Blur ARGB image. +// dst_cumsum table of width * (height + 1) * 16 bytes aligned to +// 16 byte boundary. +// dst_stride32_cumsum is number of ints in a row (width * 4). +// radius is number of pixels around the center. e.g. 1 = 3x3. 2=5x5. +// Blur is optimized for radius of 5 (11x11) or less. +LIBYUV_API +int ARGBBlur(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int32* dst_cumsum, int dst_stride32_cumsum, + int width, int height, int radius); + +// Multiply ARGB image by ARGB value. +LIBYUV_API +int ARGBShade(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height, uint32 value); + +// Interpolate between two ARGB images using specified amount of interpolation +// (0 to 255) and store to destination. +// 'interpolation' is specified as 8 bit fraction where 0 means 100% src_argb0 +// and 255 means 1% src_argb0 and 99% src_argb1. +// Internally uses ARGBScale bilinear filtering. +// Caveat: This function will write up to 16 bytes beyond the end of dst_argb. +LIBYUV_API +int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0, + const uint8* src_argb1, int src_stride_argb1, + uint8* dst_argb, int dst_stride_argb, + int width, int height, int interpolation); + +#if defined(__pnacl__) || defined(__CLR_VER) || defined(COVERAGE_ENABLED) || \ + defined(TARGET_IPHONE_SIMULATOR) +#define LIBYUV_DISABLE_X86 +#endif + +// Row functions for copying a pixels from a source with a slope to a row +// of destination. Useful for scaling, rotation, mirror, texture mapping. +LIBYUV_API +void ARGBAffineRow_C(const uint8* src_argb, int src_argb_stride, + uint8* dst_argb, const float* uv_dudv, int width); +// The following are available on all x86 platforms: +#if !defined(LIBYUV_DISABLE_X86) && \ + (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)) +LIBYUV_API +void ARGBAffineRow_SSE2(const uint8* src_argb, int src_argb_stride, + uint8* dst_argb, const float* uv_dudv, int width); +#define HAS_ARGBAFFINEROW_SSE2 +#endif // LIBYUV_DISABLE_X86 + +// Shuffle ARGB channel order. e.g. BGRA to ARGB. +// shuffler is 16 bytes and must be aligned. +LIBYUV_API +int ARGBShuffle(const uint8* src_bgra, int src_stride_bgra, + uint8* dst_argb, int dst_stride_argb, + const uint8* shuffler, int width, int height); + +// Sobel ARGB effect with planar output. +LIBYUV_API +int ARGBSobelToPlane(const uint8* src_argb, int src_stride_argb, + uint8* dst_y, int dst_stride_y, + int width, int height); + +// Sobel ARGB effect. +LIBYUV_API +int ARGBSobel(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +// Sobel ARGB effect w/ Sobel X, Sobel, Sobel Y in ARGB. +LIBYUV_API +int ARGBSobelXY(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_PLANAR_FUNCTIONS_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/rotate.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/rotate.h new file mode 100644 index 0000000..8af60b8 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/rotate.h @@ -0,0 +1,117 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_ROTATE_H_ // NOLINT +#define INCLUDE_LIBYUV_ROTATE_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Supported rotation. +typedef enum RotationMode { + kRotate0 = 0, // No rotation. + kRotate90 = 90, // Rotate 90 degrees clockwise. + kRotate180 = 180, // Rotate 180 degrees. + kRotate270 = 270, // Rotate 270 degrees clockwise. + + // Deprecated. + kRotateNone = 0, + kRotateClockwise = 90, + kRotateCounterClockwise = 270, +} RotationModeEnum; + +// Rotate I420 frame. +LIBYUV_API +int I420Rotate(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int src_width, int src_height, enum RotationMode mode); + +// Rotate NV12 input and store in I420. +LIBYUV_API +int NV12ToI420Rotate(const uint8* src_y, int src_stride_y, + const uint8* src_uv, int src_stride_uv, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int src_width, int src_height, enum RotationMode mode); + +// Rotate a plane by 0, 90, 180, or 270. +LIBYUV_API +int RotatePlane(const uint8* src, int src_stride, + uint8* dst, int dst_stride, + int src_width, int src_height, enum RotationMode mode); + +// Rotate planes by 90, 180, 270. Deprecated. +LIBYUV_API +void RotatePlane90(const uint8* src, int src_stride, + uint8* dst, int dst_stride, + int width, int height); + +LIBYUV_API +void RotatePlane180(const uint8* src, int src_stride, + uint8* dst, int dst_stride, + int width, int height); + +LIBYUV_API +void RotatePlane270(const uint8* src, int src_stride, + uint8* dst, int dst_stride, + int width, int height); + +LIBYUV_API +void RotateUV90(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, + int width, int height); + +// Rotations for when U and V are interleaved. +// These functions take one input pointer and +// split the data into two buffers while +// rotating them. Deprecated. +LIBYUV_API +void RotateUV180(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, + int width, int height); + +LIBYUV_API +void RotateUV270(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, + int width, int height); + +// The 90 and 270 functions are based on transposes. +// Doing a transpose with reversing the read/write +// order will result in a rotation by +- 90 degrees. +// Deprecated. +LIBYUV_API +void TransposePlane(const uint8* src, int src_stride, + uint8* dst, int dst_stride, + int width, int height); + +LIBYUV_API +void TransposeUV(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, + int width, int height); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_ROTATE_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/rotate_argb.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/rotate_argb.h new file mode 100644 index 0000000..660ff55 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/rotate_argb.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_ROTATE_ARGB_H_ // NOLINT +#define INCLUDE_LIBYUV_ROTATE_ARGB_H_ + +#include "libyuv/basic_types.h" +#include "libyuv/rotate.h" // For RotationMode. + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Rotate ARGB frame +LIBYUV_API +int ARGBRotate(const uint8* src_argb, int src_stride_argb, + uint8* dst_argb, int dst_stride_argb, + int src_width, int src_height, enum RotationMode mode); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_ROTATE_ARGB_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/row.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/row.h new file mode 100644 index 0000000..757020d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/row.h @@ -0,0 +1,1694 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_ROW_H_ // NOLINT +#define INCLUDE_LIBYUV_ROW_H_ + +#include // For malloc. + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +#define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1))) + +#ifdef __cplusplus +#define align_buffer_64(var, size) \ + uint8* var##_mem = reinterpret_cast(malloc((size) + 63)); \ + uint8* var = reinterpret_cast \ + ((reinterpret_cast(var##_mem) + 63) & ~63) +#else +#define align_buffer_64(var, size) \ + uint8* var##_mem = (uint8*)(malloc((size) + 63)); /* NOLINT */ \ + uint8* var = (uint8*)(((intptr_t)(var##_mem) + 63) & ~63) /* NOLINT */ +#endif + +#define free_aligned_buffer_64(var) \ + free(var##_mem); \ + var = 0 + +#if defined(__pnacl__) || defined(__CLR_VER) || defined(COVERAGE_ENABLED) || \ + defined(TARGET_IPHONE_SIMULATOR) +#define LIBYUV_DISABLE_X86 +#endif +// True if compiling for SSSE3 as a requirement. +#if defined(__SSSE3__) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 3)) +#define LIBYUV_SSSE3_ONLY +#endif + +// Enable for NaCL pepper 33 for bundle and AVX2 support. +// #define NEW_BINUTILS + +// The following are available on all x86 platforms: +#if !defined(LIBYUV_DISABLE_X86) && \ + (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)) +// Effects: +#define HAS_ARGBADDROW_SSE2 +#define HAS_ARGBAFFINEROW_SSE2 +#define HAS_ARGBATTENUATEROW_SSSE3 +#define HAS_ARGBBLENDROW_SSSE3 +#define HAS_ARGBCOLORMATRIXROW_SSSE3 +#define HAS_ARGBCOLORTABLEROW_X86 +#define HAS_ARGBCOPYALPHAROW_SSE2 +#define HAS_ARGBCOPYYTOALPHAROW_SSE2 +#define HAS_ARGBGRAYROW_SSSE3 +#define HAS_ARGBLUMACOLORTABLEROW_SSSE3 +#define HAS_ARGBMIRRORROW_SSSE3 +#define HAS_ARGBMULTIPLYROW_SSE2 +#define HAS_ARGBPOLYNOMIALROW_SSE2 +#define HAS_ARGBQUANTIZEROW_SSE2 +#define HAS_ARGBSEPIAROW_SSSE3 +#define HAS_ARGBSHADEROW_SSE2 +#define HAS_ARGBSUBTRACTROW_SSE2 +#define HAS_ARGBTOUVROW_SSSE3 +#define HAS_ARGBUNATTENUATEROW_SSE2 +#define HAS_COMPUTECUMULATIVESUMROW_SSE2 +#define HAS_CUMULATIVESUMTOAVERAGEROW_SSE2 +#define HAS_INTERPOLATEROW_SSE2 +#define HAS_INTERPOLATEROW_SSSE3 +#define HAS_RGBCOLORTABLEROW_X86 +#define HAS_SOBELROW_SSE2 +#define HAS_SOBELTOPLANEROW_SSE2 +#define HAS_SOBELXROW_SSE2 +#define HAS_SOBELXYROW_SSE2 +#define HAS_SOBELYROW_SSE2 + +// Conversions: +#define HAS_ABGRTOUVROW_SSSE3 +#define HAS_ABGRTOYROW_SSSE3 +#define HAS_ARGB1555TOARGBROW_SSE2 +#define HAS_ARGB4444TOARGBROW_SSE2 +#define HAS_ARGBSHUFFLEROW_SSE2 +#define HAS_ARGBSHUFFLEROW_SSSE3 +#define HAS_ARGBTOARGB1555ROW_SSE2 +#define HAS_ARGBTOARGB4444ROW_SSE2 +#define HAS_ARGBTOBAYERGGROW_SSE2 +#define HAS_ARGBTOBAYERROW_SSSE3 +#define HAS_ARGBTORAWROW_SSSE3 +#define HAS_ARGBTORGB24ROW_SSSE3 +#define HAS_ARGBTORGB565ROW_SSE2 +#define HAS_ARGBTOUV422ROW_SSSE3 +#define HAS_ARGBTOUV444ROW_SSSE3 +#define HAS_ARGBTOUVJROW_SSSE3 +#define HAS_ARGBTOYJROW_SSSE3 +#define HAS_ARGBTOYROW_SSSE3 +#define HAS_BGRATOUVROW_SSSE3 +#define HAS_BGRATOYROW_SSSE3 +#define HAS_COPYROW_ERMS +#define HAS_COPYROW_SSE2 +#define HAS_COPYROW_X86 +#define HAS_HALFROW_SSE2 +#define HAS_I400TOARGBROW_SSE2 +#define HAS_I411TOARGBROW_SSSE3 +#define HAS_I422TOARGB1555ROW_SSSE3 +#define HAS_I422TOABGRROW_SSSE3 +#define HAS_I422TOARGB1555ROW_SSSE3 +#define HAS_I422TOARGB4444ROW_SSSE3 +#define HAS_I422TOARGBROW_SSSE3 +#define HAS_I422TOBGRAROW_SSSE3 +#define HAS_I422TORAWROW_SSSE3 +#define HAS_I422TORGB24ROW_SSSE3 +#define HAS_I422TORGB565ROW_SSSE3 +#define HAS_I422TORGBAROW_SSSE3 +#define HAS_I422TOUYVYROW_SSE2 +#define HAS_I422TOYUY2ROW_SSE2 +#define HAS_I444TOARGBROW_SSSE3 +#define HAS_MERGEUVROW_SSE2 +#define HAS_MIRRORROW_SSE2 +#define HAS_MIRRORROW_SSSE3 +#define HAS_MIRRORROW_UV_SSSE3 +#define HAS_MIRRORUVROW_SSSE3 +#define HAS_NV12TOARGBROW_SSSE3 +#define HAS_NV12TORGB565ROW_SSSE3 +#define HAS_NV21TOARGBROW_SSSE3 +#define HAS_NV21TORGB565ROW_SSSE3 +#define HAS_RAWTOARGBROW_SSSE3 +#define HAS_RAWTOYROW_SSSE3 +#define HAS_RGB24TOARGBROW_SSSE3 +#define HAS_RGB24TOYROW_SSSE3 +#define HAS_RGB565TOARGBROW_SSE2 +#define HAS_RGBATOUVROW_SSSE3 +#define HAS_RGBATOYROW_SSSE3 +#define HAS_SETROW_X86 +#define HAS_SPLITUVROW_SSE2 +#define HAS_UYVYTOARGBROW_SSSE3 +#define HAS_UYVYTOUV422ROW_SSE2 +#define HAS_UYVYTOUVROW_SSE2 +#define HAS_UYVYTOYROW_SSE2 +#define HAS_YTOARGBROW_SSE2 +#define HAS_YUY2TOARGBROW_SSSE3 +#define HAS_YUY2TOUV422ROW_SSE2 +#define HAS_YUY2TOUVROW_SSE2 +#define HAS_YUY2TOYROW_SSE2 +#endif + +// GCC >= 4.7.0 required for AVX2. +#if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) +#if (__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 7)) +#define GCC_HAS_AVX2 1 +#endif // GNUC >= 4.7 +#endif // __GNUC__ + +// clang >= 3.4.0 required for AVX2. +#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) +#if (__clang_major__ > 3) || (__clang_major__ == 3 && (__clang_minor__ >= 4)) +#define CLANG_HAS_AVX2 1 +#endif // clang >= 3.4 +#endif // __clang__ + +// Visual C 2012 required for AVX2. +#if defined(_M_IX86) && defined(_MSC_VER) && _MSC_VER >= 1700 +#define VISUALC_HAS_AVX2 1 +#endif // VisualStudio >= 2012 + +// The following are available on all x86 platforms, but +// require VS2012, clang 3.4 or gcc 4.7. +// The code supports NaCL but requires a new compiler and validator. +#if !defined(LIBYUV_DISABLE_X86) && (defined(VISUALC_HAS_AVX2) || \ + defined(CLANG_HAS_AVX2) || defined(GCC_HAS_AVX2)) +// Effects: +#define HAS_ARGBPOLYNOMIALROW_AVX2 +#define HAS_ARGBSHUFFLEROW_AVX2 +#define HAS_ARGBCOPYALPHAROW_AVX2 +#define HAS_ARGBCOPYYTOALPHAROW_AVX2 +#endif + +// The following are require VS2012. +// TODO(fbarchard): Port to gcc. +#if !defined(LIBYUV_DISABLE_X86) && defined(VISUALC_HAS_AVX2) +#define HAS_ARGBTOUVROW_AVX2 +#define HAS_ARGBTOYJROW_AVX2 +#define HAS_ARGBTOYROW_AVX2 +#define HAS_HALFROW_AVX2 +#define HAS_I422TOARGBROW_AVX2 +#define HAS_INTERPOLATEROW_AVX2 +#define HAS_MERGEUVROW_AVX2 +#define HAS_MIRRORROW_AVX2 +#define HAS_SPLITUVROW_AVX2 +#define HAS_UYVYTOUV422ROW_AVX2 +#define HAS_UYVYTOUVROW_AVX2 +#define HAS_UYVYTOYROW_AVX2 +#define HAS_YUY2TOUV422ROW_AVX2 +#define HAS_YUY2TOUVROW_AVX2 +#define HAS_YUY2TOYROW_AVX2 + +// Effects: +#define HAS_ARGBADDROW_AVX2 +#define HAS_ARGBATTENUATEROW_AVX2 +#define HAS_ARGBMIRRORROW_AVX2 +#define HAS_ARGBMULTIPLYROW_AVX2 +#define HAS_ARGBSUBTRACTROW_AVX2 +#define HAS_ARGBUNATTENUATEROW_AVX2 +#endif // defined(VISUALC_HAS_AVX2) + +// The following are Yasm x86 only: +// TODO(fbarchard): Port AVX2 to inline. +#if !defined(LIBYUV_DISABLE_X86) && defined(HAVE_YASM) + (defined(_M_IX86) || defined(_M_X64) || \ + defined(__x86_64__) || defined(__i386__)) +#define HAS_MERGEUVROW_AVX2 +#define HAS_MERGEUVROW_MMX +#define HAS_SPLITUVROW_AVX2 +#define HAS_SPLITUVROW_MMX +#define HAS_UYVYTOYROW_AVX2 +#define HAS_UYVYTOYROW_MMX +#define HAS_YUY2TOYROW_AVX2 +#define HAS_YUY2TOYROW_MMX +#endif + +// The following are disabled when SSSE3 is available: +#if !defined(LIBYUV_DISABLE_X86) && \ + (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)) && \ + !defined(LIBYUV_SSSE3_ONLY) +#define HAS_ARGBBLENDROW_SSE2 +#define HAS_ARGBATTENUATEROW_SSE2 +#define HAS_MIRRORROW_SSE2 +#endif + +// The following are available on Neon platforms: +#if !defined(LIBYUV_DISABLE_NEON) && \ + (defined(__ARM_NEON__) || defined(LIBYUV_NEON)) +#define HAS_ABGRTOUVROW_NEON +#define HAS_ABGRTOYROW_NEON +#define HAS_ARGB1555TOARGBROW_NEON +#define HAS_ARGB1555TOUVROW_NEON +#define HAS_ARGB1555TOYROW_NEON +#define HAS_ARGB4444TOARGBROW_NEON +#define HAS_ARGB4444TOUVROW_NEON +#define HAS_ARGB4444TOYROW_NEON +#define HAS_ARGBTOARGB1555ROW_NEON +#define HAS_ARGBTOARGB4444ROW_NEON +#define HAS_ARGBTOBAYERROW_NEON +#define HAS_ARGBTOBAYERGGROW_NEON +#define HAS_ARGBTORAWROW_NEON +#define HAS_ARGBTORGB24ROW_NEON +#define HAS_ARGBTORGB565ROW_NEON +#define HAS_ARGBTOUV411ROW_NEON +#define HAS_ARGBTOUV422ROW_NEON +#define HAS_ARGBTOUV444ROW_NEON +#define HAS_ARGBTOUVROW_NEON +#define HAS_ARGBTOUVJROW_NEON +#define HAS_ARGBTOYROW_NEON +#define HAS_ARGBTOYJROW_NEON +#define HAS_BGRATOUVROW_NEON +#define HAS_BGRATOYROW_NEON +#define HAS_COPYROW_NEON +#define HAS_HALFROW_NEON +#define HAS_I400TOARGBROW_NEON +#define HAS_I411TOARGBROW_NEON +#define HAS_I422TOABGRROW_NEON +#define HAS_I422TOARGB1555ROW_NEON +#define HAS_I422TOARGB4444ROW_NEON +#define HAS_I422TOARGBROW_NEON +#define HAS_I422TOBGRAROW_NEON +#define HAS_I422TORAWROW_NEON +#define HAS_I422TORGB24ROW_NEON +#define HAS_I422TORGB565ROW_NEON +#define HAS_I422TORGBAROW_NEON +#define HAS_I422TOUYVYROW_NEON +#define HAS_I422TOYUY2ROW_NEON +#define HAS_I444TOARGBROW_NEON +#define HAS_MERGEUVROW_NEON +#define HAS_MIRRORROW_NEON +#define HAS_MIRRORUVROW_NEON +#define HAS_NV12TOARGBROW_NEON +#define HAS_NV12TORGB565ROW_NEON +#define HAS_NV21TOARGBROW_NEON +#define HAS_NV21TORGB565ROW_NEON +#define HAS_RAWTOARGBROW_NEON +#define HAS_RAWTOUVROW_NEON +#define HAS_RAWTOYROW_NEON +#define HAS_RGB24TOARGBROW_NEON +#define HAS_RGB24TOUVROW_NEON +#define HAS_RGB24TOYROW_NEON +#define HAS_RGB565TOARGBROW_NEON +#define HAS_RGB565TOUVROW_NEON +#define HAS_RGB565TOYROW_NEON +#define HAS_RGBATOUVROW_NEON +#define HAS_RGBATOYROW_NEON +#define HAS_SETROW_NEON +#define HAS_SPLITUVROW_NEON +#define HAS_UYVYTOARGBROW_NEON +#define HAS_UYVYTOUV422ROW_NEON +#define HAS_UYVYTOUVROW_NEON +#define HAS_UYVYTOYROW_NEON +#define HAS_YTOARGBROW_NEON +#define HAS_YUY2TOARGBROW_NEON +#define HAS_YUY2TOUV422ROW_NEON +#define HAS_YUY2TOUVROW_NEON +#define HAS_YUY2TOYROW_NEON + +// Effects: +#define HAS_ARGBADDROW_NEON +#define HAS_ARGBATTENUATEROW_NEON +#define HAS_ARGBBLENDROW_NEON +#define HAS_ARGBCOLORMATRIXROW_NEON +#define HAS_ARGBGRAYROW_NEON +#define HAS_ARGBMIRRORROW_NEON +#define HAS_ARGBMULTIPLYROW_NEON +#define HAS_ARGBQUANTIZEROW_NEON +#define HAS_ARGBSEPIAROW_NEON +#define HAS_ARGBSHADEROW_NEON +#define HAS_ARGBSUBTRACTROW_NEON +#define HAS_SOBELROW_NEON +#define HAS_SOBELTOPLANEROW_NEON +#define HAS_SOBELXYROW_NEON +#define HAS_SOBELXROW_NEON +#define HAS_SOBELYROW_NEON +#define HAS_INTERPOLATEROW_NEON +#endif + +// The following are available on Mips platforms: +#if !defined(LIBYUV_DISABLE_MIPS) && defined(__mips__) +#define HAS_COPYROW_MIPS +#if defined(__mips_dsp) && (__mips_dsp_rev >= 2) +#define HAS_I422TOABGRROW_MIPS_DSPR2 +#define HAS_I422TOARGBROW_MIPS_DSPR2 +#define HAS_I422TOBGRAROW_MIPS_DSPR2 +#define HAS_INTERPOLATEROWS_MIPS_DSPR2 +#define HAS_MIRRORROW_MIPS_DSPR2 +#define HAS_MIRRORUVROW_MIPS_DSPR2 +#define HAS_SPLITUVROW_MIPS_DSPR2 +#endif +#endif + +#if defined(_MSC_VER) && !defined(__CLR_VER) +#define SIMD_ALIGNED(var) __declspec(align(16)) var +typedef __declspec(align(16)) int16 vec16[8]; +typedef __declspec(align(16)) int32 vec32[4]; +typedef __declspec(align(16)) int8 vec8[16]; +typedef __declspec(align(16)) uint16 uvec16[8]; +typedef __declspec(align(16)) uint32 uvec32[4]; +typedef __declspec(align(16)) uint8 uvec8[16]; +typedef __declspec(align(32)) int16 lvec16[16]; +typedef __declspec(align(32)) int32 lvec32[8]; +typedef __declspec(align(32)) int8 lvec8[32]; +typedef __declspec(align(32)) uint16 ulvec16[16]; +typedef __declspec(align(32)) uint32 ulvec32[8]; +typedef __declspec(align(32)) uint8 ulvec8[32]; + +#elif defined(__GNUC__) +// Caveat GCC 4.2 to 4.7 have a known issue using vectors with const. +#define SIMD_ALIGNED(var) var __attribute__((aligned(16))) +typedef int16 __attribute__((vector_size(16))) vec16; +typedef int32 __attribute__((vector_size(16))) vec32; +typedef int8 __attribute__((vector_size(16))) vec8; +typedef uint16 __attribute__((vector_size(16))) uvec16; +typedef uint32 __attribute__((vector_size(16))) uvec32; +typedef uint8 __attribute__((vector_size(16))) uvec8; +#else +#define SIMD_ALIGNED(var) var +typedef int16 vec16[8]; +typedef int32 vec32[4]; +typedef int8 vec8[16]; +typedef uint16 uvec16[8]; +typedef uint32 uvec32[4]; +typedef uint8 uvec8[16]; +#endif + +#if defined(__APPLE__) || defined(__x86_64__) || defined(__llvm__) +#define OMITFP +#else +#define OMITFP __attribute__((optimize("omit-frame-pointer"))) +#endif + +// NaCL macros for GCC x86 and x64. + +// TODO(nfullagar): When pepper_33 toolchain is distributed, default to +// NEW_BINUTILS and remove all BUNDLEALIGN occurances. +#if defined(__native_client__) +#define LABELALIGN ".p2align 5\n" +#else +#define LABELALIGN ".p2align 2\n" +#endif +#if defined(__native_client__) && defined(__x86_64__) +#if defined(NEW_BINUTILS) +#define BUNDLELOCK ".bundle_lock\n" +#define BUNDLEUNLOCK ".bundle_unlock\n" +#define BUNDLEALIGN "\n" +#else +#define BUNDLELOCK "\n" +#define BUNDLEUNLOCK "\n" +#define BUNDLEALIGN ".p2align 5\n" +#endif +#define MEMACCESS(base) "%%nacl:(%%r15,%q" #base ")" +#define MEMACCESS2(offset, base) "%%nacl:" #offset "(%%r15,%q" #base ")" +#define MEMLEA(offset, base) #offset "(%q" #base ")" +#define MEMLEA3(offset, index, scale) \ + #offset "(,%q" #index "," #scale ")" +#define MEMLEA4(offset, base, index, scale) \ + #offset "(%q" #base ",%q" #index "," #scale ")" +#define MEMMOVESTRING(s, d) "%%nacl:(%q" #s "),%%nacl:(%q" #d "), %%r15" +#define MEMSTORESTRING(reg, d) "%%" #reg ",%%nacl:(%q" #d "), %%r15" +#define MEMOPREG(opcode, offset, base, index, scale, reg) \ + BUNDLELOCK \ + "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" \ + #opcode " (%%r15,%%r14),%%" #reg "\n" \ + BUNDLEUNLOCK +#define MEMOPMEM(opcode, reg, offset, base, index, scale) \ + BUNDLELOCK \ + "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" \ + #opcode " %%" #reg ",(%%r15,%%r14)\n" \ + BUNDLEUNLOCK +#define MEMOPARG(opcode, offset, base, index, scale, arg) \ + BUNDLELOCK \ + "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" \ + #opcode " (%%r15,%%r14),%" #arg "\n" \ + BUNDLEUNLOCK +#else +#define BUNDLEALIGN "\n" +#define MEMACCESS(base) "(%" #base ")" +#define MEMACCESS2(offset, base) #offset "(%" #base ")" +#define MEMLEA(offset, base) #offset "(%" #base ")" +#define MEMLEA3(offset, index, scale) \ + #offset "(,%" #index "," #scale ")" +#define MEMLEA4(offset, base, index, scale) \ + #offset "(%" #base ",%" #index "," #scale ")" +#define MEMMOVESTRING(s, d) +#define MEMSTORESTRING(reg, d) +#define MEMOPREG(opcode, offset, base, index, scale, reg) \ + #opcode " " #offset "(%" #base ",%" #index "," #scale "),%%" #reg "\n" +#define MEMOPMEM(opcode, reg, offset, base, index, scale) \ + #opcode " %%" #reg ","#offset "(%" #base ",%" #index "," #scale ")\n" +#define MEMOPARG(opcode, offset, base, index, scale, arg) \ + #opcode " " #offset "(%" #base ",%" #index "," #scale "),%" #arg "\n" +#endif + +void I444ToARGBRow_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToARGBRow_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I411ToARGBRow_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToBGRARow_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_bgra, + int width); +void I422ToABGRRow_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_abgr, + int width); +void I422ToRGBARow_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgba, + int width); +void I422ToRGB24Row_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgb24, + int width); +void I422ToRAWRow_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_raw, + int width); +void I422ToRGB565Row_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgb565, + int width); +void I422ToARGB1555Row_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb1555, + int width); +void I422ToARGB4444Row_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb4444, + int width); +void NV12ToARGBRow_NEON(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV21ToARGBRow_NEON(const uint8* src_y, + const uint8* src_vu, + uint8* dst_argb, + int width); +void NV12ToRGB565Row_NEON(const uint8* src_y, + const uint8* src_uv, + uint8* dst_rgb565, + int width); +void NV21ToRGB565Row_NEON(const uint8* src_y, + const uint8* src_vu, + uint8* dst_rgb565, + int width); +void YUY2ToARGBRow_NEON(const uint8* src_yuy2, + uint8* dst_argb, + int width); +void UYVYToARGBRow_NEON(const uint8* src_uyvy, + uint8* dst_argb, + int width); + +void ARGBToYRow_AVX2(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToYRow_Any_AVX2(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToYJRow_AVX2(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToYJRow_Any_AVX2(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToYJRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void BGRAToYRow_SSSE3(const uint8* src_bgra, uint8* dst_y, int pix); +void ABGRToYRow_SSSE3(const uint8* src_abgr, uint8* dst_y, int pix); +void RGBAToYRow_SSSE3(const uint8* src_rgba, uint8* dst_y, int pix); +void RGB24ToYRow_SSSE3(const uint8* src_rgb24, uint8* dst_y, int pix); +void RAWToYRow_SSSE3(const uint8* src_raw, uint8* dst_y, int pix); +void ARGBToYRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToYJRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void BGRAToYRow_Unaligned_SSSE3(const uint8* src_bgra, uint8* dst_y, int pix); +void ABGRToYRow_Unaligned_SSSE3(const uint8* src_abgr, uint8* dst_y, int pix); +void RGBAToYRow_Unaligned_SSSE3(const uint8* src_rgba, uint8* dst_y, int pix); +void RGB24ToYRow_Unaligned_SSSE3(const uint8* src_rgb24, uint8* dst_y, int pix); +void RAWToYRow_Unaligned_SSSE3(const uint8* src_raw, uint8* dst_y, int pix); +void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToUV444Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v, + int pix); +void ARGBToUV422Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v, + int pix); +void ARGBToUV411Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v, + int pix); +void ARGBToUVRow_NEON(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int pix); +void ARGBToUVJRow_NEON(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int pix); +void BGRAToUVRow_NEON(const uint8* src_bgra, int src_stride_bgra, + uint8* dst_u, uint8* dst_v, int pix); +void ABGRToUVRow_NEON(const uint8* src_abgr, int src_stride_abgr, + uint8* dst_u, uint8* dst_v, int pix); +void RGBAToUVRow_NEON(const uint8* src_rgba, int src_stride_rgba, + uint8* dst_u, uint8* dst_v, int pix); +void RGB24ToUVRow_NEON(const uint8* src_rgb24, int src_stride_rgb24, + uint8* dst_u, uint8* dst_v, int pix); +void RAWToUVRow_NEON(const uint8* src_raw, int src_stride_raw, + uint8* dst_u, uint8* dst_v, int pix); +void RGB565ToUVRow_NEON(const uint8* src_rgb565, int src_stride_rgb565, + uint8* dst_u, uint8* dst_v, int pix); +void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, int src_stride_argb1555, + uint8* dst_u, uint8* dst_v, int pix); +void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, int src_stride_argb4444, + uint8* dst_u, uint8* dst_v, int pix); +void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int pix); +void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int pix); +void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int pix); +void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int pix); +void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int pix); +void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int pix); +void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int pix); +void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int pix); +void ARGBToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToYJRow_C(const uint8* src_argb, uint8* dst_y, int pix); +void BGRAToYRow_C(const uint8* src_bgra, uint8* dst_y, int pix); +void ABGRToYRow_C(const uint8* src_abgr, uint8* dst_y, int pix); +void RGBAToYRow_C(const uint8* src_rgba, uint8* dst_y, int pix); +void RGB24ToYRow_C(const uint8* src_rgb24, uint8* dst_y, int pix); +void RAWToYRow_C(const uint8* src_raw, uint8* dst_y, int pix); +void RGB565ToYRow_C(const uint8* src_rgb565, uint8* dst_y, int pix); +void ARGB1555ToYRow_C(const uint8* src_argb1555, uint8* dst_y, int pix); +void ARGB4444ToYRow_C(const uint8* src_argb4444, uint8* dst_y, int pix); +void ARGBToYRow_Any_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToYJRow_Any_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); +void BGRAToYRow_Any_SSSE3(const uint8* src_bgra, uint8* dst_y, int pix); +void ABGRToYRow_Any_SSSE3(const uint8* src_abgr, uint8* dst_y, int pix); +void RGBAToYRow_Any_SSSE3(const uint8* src_rgba, uint8* dst_y, int pix); +void RGB24ToYRow_Any_SSSE3(const uint8* src_rgb24, uint8* dst_y, int pix); +void RAWToYRow_Any_SSSE3(const uint8* src_raw, uint8* dst_y, int pix); +void ARGBToYRow_Any_NEON(const uint8* src_argb, uint8* dst_y, int pix); +void ARGBToYJRow_Any_NEON(const uint8* src_argb, uint8* dst_y, int pix); +void BGRAToYRow_Any_NEON(const uint8* src_bgra, uint8* dst_y, int pix); +void ABGRToYRow_Any_NEON(const uint8* src_abgr, uint8* dst_y, int pix); +void RGBAToYRow_Any_NEON(const uint8* src_rgba, uint8* dst_y, int pix); +void RGB24ToYRow_Any_NEON(const uint8* src_rgb24, uint8* dst_y, int pix); +void RAWToYRow_Any_NEON(const uint8* src_raw, uint8* dst_y, int pix); +void RGB565ToYRow_Any_NEON(const uint8* src_rgb565, uint8* dst_y, int pix); +void ARGB1555ToYRow_Any_NEON(const uint8* src_argb1555, uint8* dst_y, int pix); +void ARGB4444ToYRow_Any_NEON(const uint8* src_argb4444, uint8* dst_y, int pix); + +void ARGBToUVRow_AVX2(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUVRow_Any_AVX2(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUVRow_SSSE3(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUVJRow_SSSE3(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void BGRAToUVRow_SSSE3(const uint8* src_bgra, int src_stride_bgra, + uint8* dst_u, uint8* dst_v, int width); +void ABGRToUVRow_SSSE3(const uint8* src_abgr, int src_stride_abgr, + uint8* dst_u, uint8* dst_v, int width); +void RGBAToUVRow_SSSE3(const uint8* src_rgba, int src_stride_rgba, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUVRow_Unaligned_SSSE3(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUVJRow_Unaligned_SSSE3(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void BGRAToUVRow_Unaligned_SSSE3(const uint8* src_bgra, int src_stride_bgra, + uint8* dst_u, uint8* dst_v, int width); +void ABGRToUVRow_Unaligned_SSSE3(const uint8* src_abgr, int src_stride_abgr, + uint8* dst_u, uint8* dst_v, int width); +void RGBAToUVRow_Unaligned_SSSE3(const uint8* src_rgba, int src_stride_rgba, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUVRow_Any_SSSE3(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUVJRow_Any_SSSE3(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void BGRAToUVRow_Any_SSSE3(const uint8* src_bgra, int src_stride_bgra, + uint8* dst_u, uint8* dst_v, int width); +void ABGRToUVRow_Any_SSSE3(const uint8* src_abgr, int src_stride_abgr, + uint8* dst_u, uint8* dst_v, int width); +void RGBAToUVRow_Any_SSSE3(const uint8* src_rgba, int src_stride_rgba, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUV444Row_Any_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v, + int pix); +void ARGBToUV422Row_Any_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v, + int pix); +void ARGBToUV411Row_Any_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v, + int pix); +void ARGBToUVRow_Any_NEON(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int pix); +void ARGBToUVJRow_Any_NEON(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int pix); +void BGRAToUVRow_Any_NEON(const uint8* src_bgra, int src_stride_bgra, + uint8* dst_u, uint8* dst_v, int pix); +void ABGRToUVRow_Any_NEON(const uint8* src_abgr, int src_stride_abgr, + uint8* dst_u, uint8* dst_v, int pix); +void RGBAToUVRow_Any_NEON(const uint8* src_rgba, int src_stride_rgba, + uint8* dst_u, uint8* dst_v, int pix); +void RGB24ToUVRow_Any_NEON(const uint8* src_rgb24, int src_stride_rgb24, + uint8* dst_u, uint8* dst_v, int pix); +void RAWToUVRow_Any_NEON(const uint8* src_raw, int src_stride_raw, + uint8* dst_u, uint8* dst_v, int pix); +void RGB565ToUVRow_Any_NEON(const uint8* src_rgb565, int src_stride_rgb565, + uint8* dst_u, uint8* dst_v, int pix); +void ARGB1555ToUVRow_Any_NEON(const uint8* src_argb1555, + int src_stride_argb1555, + uint8* dst_u, uint8* dst_v, int pix); +void ARGB4444ToUVRow_Any_NEON(const uint8* src_argb4444, + int src_stride_argb4444, + uint8* dst_u, uint8* dst_v, int pix); +void ARGBToUVRow_C(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUVJRow_C(const uint8* src_argb, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width); +void BGRAToUVRow_C(const uint8* src_bgra, int src_stride_bgra, + uint8* dst_u, uint8* dst_v, int width); +void ABGRToUVRow_C(const uint8* src_abgr, int src_stride_abgr, + uint8* dst_u, uint8* dst_v, int width); +void RGBAToUVRow_C(const uint8* src_rgba, int src_stride_rgba, + uint8* dst_u, uint8* dst_v, int width); +void RGB24ToUVRow_C(const uint8* src_rgb24, int src_stride_rgb24, + uint8* dst_u, uint8* dst_v, int width); +void RAWToUVRow_C(const uint8* src_raw, int src_stride_raw, + uint8* dst_u, uint8* dst_v, int width); +void RGB565ToUVRow_C(const uint8* src_rgb565, int src_stride_rgb565, + uint8* dst_u, uint8* dst_v, int width); +void ARGB1555ToUVRow_C(const uint8* src_argb1555, int src_stride_argb1555, + uint8* dst_u, uint8* dst_v, int width); +void ARGB4444ToUVRow_C(const uint8* src_argb4444, int src_stride_argb4444, + uint8* dst_u, uint8* dst_v, int width); + +void ARGBToUV444Row_SSSE3(const uint8* src_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUV444Row_Unaligned_SSSE3(const uint8* src_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUV444Row_Any_SSSE3(const uint8* src_argb, + uint8* dst_u, uint8* dst_v, int width); + +void ARGBToUV422Row_SSSE3(const uint8* src_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUV422Row_Unaligned_SSSE3(const uint8* src_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUV422Row_Any_SSSE3(const uint8* src_argb, + uint8* dst_u, uint8* dst_v, int width); + +void ARGBToUV444Row_C(const uint8* src_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUV422Row_C(const uint8* src_argb, + uint8* dst_u, uint8* dst_v, int width); +void ARGBToUV411Row_C(const uint8* src_argb, + uint8* dst_u, uint8* dst_v, int width); + +void MirrorRow_AVX2(const uint8* src, uint8* dst, int width); +void MirrorRow_SSSE3(const uint8* src, uint8* dst, int width); +void MirrorRow_SSE2(const uint8* src, uint8* dst, int width); +void MirrorRow_NEON(const uint8* src, uint8* dst, int width); +void MirrorRow_MIPS_DSPR2(const uint8* src, uint8* dst, int width); +void MirrorRow_C(const uint8* src, uint8* dst, int width); + +void MirrorUVRow_SSSE3(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int width); +void MirrorUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int width); +void MirrorUVRow_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int width); +void MirrorUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int width); + +void ARGBMirrorRow_AVX2(const uint8* src, uint8* dst, int width); +void ARGBMirrorRow_SSSE3(const uint8* src, uint8* dst, int width); +void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width); +void ARGBMirrorRow_C(const uint8* src, uint8* dst, int width); + +void SplitUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix); +void SplitUVRow_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix); +void SplitUVRow_AVX2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix); +void SplitUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix); +void SplitUVRow_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int pix); +void SplitUVRow_Unaligned_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int pix); +void SplitUVRow_Unaligned_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u, + uint8* dst_v, int pix); +void SplitUVRow_Any_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int pix); +void SplitUVRow_Any_AVX2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int pix); +void SplitUVRow_Any_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int pix); +void SplitUVRow_Any_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int pix); + +void MergeUVRow_C(const uint8* src_u, const uint8* src_v, uint8* dst_uv, + int width); +void MergeUVRow_SSE2(const uint8* src_u, const uint8* src_v, uint8* dst_uv, + int width); +void MergeUVRow_AVX2(const uint8* src_u, const uint8* src_v, uint8* dst_uv, + int width); +void MergeUVRow_NEON(const uint8* src_u, const uint8* src_v, uint8* dst_uv, + int width); +void MergeUVRow_Unaligned_SSE2(const uint8* src_u, const uint8* src_v, + uint8* dst_uv, int width); +void MergeUVRow_Any_SSE2(const uint8* src_u, const uint8* src_v, uint8* dst_uv, + int width); +void MergeUVRow_Any_AVX2(const uint8* src_u, const uint8* src_v, uint8* dst_uv, + int width); +void MergeUVRow_Any_NEON(const uint8* src_u, const uint8* src_v, uint8* dst_uv, + int width); + +void CopyRow_SSE2(const uint8* src, uint8* dst, int count); +void CopyRow_ERMS(const uint8* src, uint8* dst, int count); +void CopyRow_X86(const uint8* src, uint8* dst, int count); +void CopyRow_NEON(const uint8* src, uint8* dst, int count); +void CopyRow_MIPS(const uint8* src, uint8* dst, int count); +void CopyRow_C(const uint8* src, uint8* dst, int count); + +void ARGBCopyAlphaRow_C(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBCopyAlphaRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBCopyAlphaRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width); + +void ARGBCopyYToAlphaRow_C(const uint8* src_y, uint8* dst_argb, int width); +void ARGBCopyYToAlphaRow_SSE2(const uint8* src_y, uint8* dst_argb, int width); +void ARGBCopyYToAlphaRow_AVX2(const uint8* src_y, uint8* dst_argb, int width); + +void SetRow_X86(uint8* dst, uint32 v32, int count); +void ARGBSetRows_X86(uint8* dst, uint32 v32, int width, + int dst_stride, int height); +void SetRow_NEON(uint8* dst, uint32 v32, int count); +void ARGBSetRows_NEON(uint8* dst, uint32 v32, int width, + int dst_stride, int height); +void SetRow_C(uint8* dst, uint32 v32, int count); +void ARGBSetRows_C(uint8* dst, uint32 v32, int width, int dst_stride, + int height); + +// ARGBShufflers for BGRAToARGB etc. +void ARGBShuffleRow_C(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int pix); +void ARGBShuffleRow_SSE2(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int pix); +void ARGBShuffleRow_SSSE3(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int pix); +void ARGBShuffleRow_AVX2(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int pix); +void ARGBShuffleRow_NEON(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int pix); +void ARGBShuffleRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int pix); +void ARGBShuffleRow_Any_SSE2(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int pix); +void ARGBShuffleRow_Any_SSSE3(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int pix); +void ARGBShuffleRow_Any_AVX2(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int pix); +void ARGBShuffleRow_Any_NEON(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int pix); + +void RGB24ToARGBRow_SSSE3(const uint8* src_rgb24, uint8* dst_argb, int pix); +void RAWToARGBRow_SSSE3(const uint8* src_raw, uint8* dst_argb, int pix); +void RGB565ToARGBRow_SSE2(const uint8* src_rgb565, uint8* dst_argb, int pix); +void ARGB1555ToARGBRow_SSE2(const uint8* src_argb1555, uint8* dst_argb, + int pix); +void ARGB4444ToARGBRow_SSE2(const uint8* src_argb4444, uint8* dst_argb, + int pix); + +void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int pix); +void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int pix); +void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int pix); +void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, uint8* dst_argb, + int pix); +void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, uint8* dst_argb, + int pix); +void RGB24ToARGBRow_C(const uint8* src_rgb24, uint8* dst_argb, int pix); +void RAWToARGBRow_C(const uint8* src_raw, uint8* dst_argb, int pix); +void RGB565ToARGBRow_C(const uint8* src_rgb, uint8* dst_argb, int pix); +void ARGB1555ToARGBRow_C(const uint8* src_argb, uint8* dst_argb, int pix); +void ARGB4444ToARGBRow_C(const uint8* src_argb, uint8* dst_argb, int pix); +void RGB24ToARGBRow_Any_SSSE3(const uint8* src_rgb24, uint8* dst_argb, int pix); +void RAWToARGBRow_Any_SSSE3(const uint8* src_raw, uint8* dst_argb, int pix); +void RGB565ToARGBRow_Any_SSE2(const uint8* src_rgb565, uint8* dst_argb, + int pix); +void ARGB1555ToARGBRow_Any_SSE2(const uint8* src_argb1555, uint8* dst_argb, + int pix); +void ARGB4444ToARGBRow_Any_SSE2(const uint8* src_argb4444, uint8* dst_argb, + int pix); +void RGB24ToARGBRow_Any_NEON(const uint8* src_rgb24, uint8* dst_argb, int pix); +void RAWToARGBRow_Any_NEON(const uint8* src_raw, uint8* dst_argb, int pix); +void RGB565ToARGBRow_Any_NEON(const uint8* src_rgb565, uint8* dst_argb, + int pix); +void ARGB1555ToARGBRow_Any_NEON(const uint8* src_argb1555, uint8* dst_argb, + int pix); +void ARGB4444ToARGBRow_Any_NEON(const uint8* src_argb4444, uint8* dst_argb, + int pix); + +void ARGBToRGB24Row_SSSE3(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRAWRow_SSSE3(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRGB565Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToARGB1555Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToARGB4444Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix); + +void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToARGB1555Row_NEON(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToARGB4444Row_NEON(const uint8* src_argb, uint8* dst_rgb, int pix); + +void ARGBToRGBARow_C(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRGB24Row_C(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRAWRow_C(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRGB565Row_C(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToARGB1555Row_C(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToARGB4444Row_C(const uint8* src_argb, uint8* dst_rgb, int pix); + +void I400ToARGBRow_SSE2(const uint8* src_y, uint8* dst_argb, int pix); +void I400ToARGBRow_Unaligned_SSE2(const uint8* src_y, uint8* dst_argb, int pix); +void I400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int pix); +void I400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int pix); +void I400ToARGBRow_Any_SSE2(const uint8* src_y, uint8* dst_argb, int pix); +void I400ToARGBRow_Any_NEON(const uint8* src_y, uint8* dst_argb, int pix); + +void I444ToARGBRow_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToARGBRow_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I411ToARGBRow_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void NV12ToARGBRow_C(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV21ToRGB565Row_C(const uint8* src_y, + const uint8* src_vu, + uint8* dst_argb, + int width); +void NV12ToRGB565Row_C(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV21ToARGBRow_C(const uint8* src_y, + const uint8* src_vu, + uint8* dst_argb, + int width); +void YUY2ToARGBRow_C(const uint8* src_yuy2, + uint8* dst_argb, + int width); +void UYVYToARGBRow_C(const uint8* src_uyvy, + uint8* dst_argb, + int width); +void I422ToBGRARow_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_bgra, + int width); +void I422ToABGRRow_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_abgr, + int width); +void I422ToRGBARow_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgba, + int width); +void I422ToRGB24Row_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgb24, + int width); +void I422ToRAWRow_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_raw, + int width); +void I422ToARGB4444Row_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb4444, + int width); +void I422ToARGB1555Row_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb4444, + int width); +void I422ToRGB565Row_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgb565, + int width); +void YToARGBRow_C(const uint8* src_y, + uint8* dst_argb, + int width); +void I422ToARGBRow_AVX2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I444ToARGBRow_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToARGBRow_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I411ToARGBRow_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void NV12ToARGBRow_SSSE3(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV21ToARGBRow_SSSE3(const uint8* src_y, + const uint8* src_vu, + uint8* dst_argb, + int width); +void NV12ToRGB565Row_SSSE3(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV21ToRGB565Row_SSSE3(const uint8* src_y, + const uint8* src_vu, + uint8* dst_argb, + int width); +void YUY2ToARGBRow_SSSE3(const uint8* src_yuy2, + uint8* dst_argb, + int width); +void UYVYToARGBRow_SSSE3(const uint8* src_uyvy, + uint8* dst_argb, + int width); +void I422ToBGRARow_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_bgra, + int width); +void I422ToABGRRow_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_abgr, + int width); +void I422ToRGBARow_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgba, + int width); +void I422ToARGB4444Row_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToARGB1555Row_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToRGB565Row_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +// RGB24/RAW are unaligned. +void I422ToRGB24Row_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgb24, + int width); +void I422ToRAWRow_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_raw, + int width); + +void I444ToARGBRow_Unaligned_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToARGBRow_Unaligned_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I411ToARGBRow_Unaligned_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void NV12ToARGBRow_Unaligned_SSSE3(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV21ToARGBRow_Unaligned_SSSE3(const uint8* src_y, + const uint8* src_vu, + uint8* dst_argb, + int width); +void YUY2ToARGBRow_Unaligned_SSSE3(const uint8* src_yuy2, + uint8* dst_argb, + int width); +void UYVYToARGBRow_Unaligned_SSSE3(const uint8* src_uyvy, + uint8* dst_argb, + int width); +void I422ToBGRARow_Unaligned_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_bgra, + int width); +void I422ToABGRRow_Unaligned_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_abgr, + int width); +void I422ToRGBARow_Unaligned_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgba, + int width); +void I422ToARGBRow_Any_AVX2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I444ToARGBRow_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToARGBRow_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I411ToARGBRow_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void NV12ToARGBRow_Any_SSSE3(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV21ToARGBRow_Any_SSSE3(const uint8* src_y, + const uint8* src_vu, + uint8* dst_argb, + int width); +void NV12ToRGB565Row_Any_SSSE3(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV21ToRGB565Row_Any_SSSE3(const uint8* src_y, + const uint8* src_vu, + uint8* dst_argb, + int width); +void YUY2ToARGBRow_Any_SSSE3(const uint8* src_yuy2, + uint8* dst_argb, + int width); +void UYVYToARGBRow_Any_SSSE3(const uint8* src_uyvy, + uint8* dst_argb, + int width); +void I422ToBGRARow_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_bgra, + int width); +void I422ToABGRRow_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_abgr, + int width); +void I422ToRGBARow_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgba, + int width); +void I422ToARGB4444Row_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgba, + int width); +void I422ToARGB1555Row_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgba, + int width); +void I422ToRGB565Row_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_rgba, + int width); +// RGB24/RAW are unaligned. +void I422ToRGB24Row_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToRAWRow_Any_SSSE3(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void YToARGBRow_SSE2(const uint8* src_y, + uint8* dst_argb, + int width); +void YToARGBRow_NEON(const uint8* src_y, + uint8* dst_argb, + int width); +void YToARGBRow_Any_SSE2(const uint8* src_y, + uint8* dst_argb, + int width); +void YToARGBRow_Any_NEON(const uint8* src_y, + uint8* dst_argb, + int width); + +// ARGB preattenuated alpha blend. +void ARGBBlendRow_SSSE3(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBBlendRow_SSE2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBBlendRow_NEON(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBBlendRow_C(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); + +// ARGB multiply images. Same API as Blend, but these require +// pointer and width alignment for SSE2. +void ARGBMultiplyRow_C(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBMultiplyRow_SSE2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBMultiplyRow_Any_SSE2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBMultiplyRow_AVX2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBMultiplyRow_Any_AVX2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBMultiplyRow_NEON(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBMultiplyRow_Any_NEON(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); + +// ARGB add images. +void ARGBAddRow_C(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBAddRow_SSE2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBAddRow_Any_SSE2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBAddRow_AVX2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBAddRow_Any_AVX2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBAddRow_NEON(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBAddRow_Any_NEON(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); + +// ARGB subtract images. Same API as Blend, but these require +// pointer and width alignment for SSE2. +void ARGBSubtractRow_C(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBSubtractRow_SSE2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBSubtractRow_Any_SSE2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBSubtractRow_AVX2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBSubtractRow_Any_AVX2(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBSubtractRow_NEON(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); +void ARGBSubtractRow_Any_NEON(const uint8* src_argb, const uint8* src_argb1, + uint8* dst_argb, int width); + +void ARGBToRGB24Row_Any_SSSE3(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRAWRow_Any_SSSE3(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRGB565Row_Any_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToARGB1555Row_Any_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToARGB4444Row_Any_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix); + +void ARGBToRGB24Row_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRAWRow_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToRGB565Row_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToARGB1555Row_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int pix); +void ARGBToARGB4444Row_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int pix); + +void I444ToARGBRow_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToARGBRow_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I411ToARGBRow_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToBGRARow_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToABGRRow_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToRGBARow_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToRGB24Row_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToRAWRow_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToARGB4444Row_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToARGB1555Row_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToRGB565Row_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void NV12ToARGBRow_Any_NEON(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV21ToARGBRow_Any_NEON(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV12ToRGB565Row_Any_NEON(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void NV21ToRGB565Row_Any_NEON(const uint8* src_y, + const uint8* src_uv, + uint8* dst_argb, + int width); +void YUY2ToARGBRow_Any_NEON(const uint8* src_yuy2, + uint8* dst_argb, + int width); +void UYVYToARGBRow_Any_NEON(const uint8* src_uyvy, + uint8* dst_argb, + int width); +void I422ToARGBRow_MIPS_DSPR2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToBGRARow_MIPS_DSPR2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToABGRRow_MIPS_DSPR2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToARGBRow_MIPS_DSPR2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToBGRARow_MIPS_DSPR2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); +void I422ToABGRRow_MIPS_DSPR2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_argb, + int width); + +void YUY2ToYRow_AVX2(const uint8* src_yuy2, uint8* dst_y, int pix); +void YUY2ToUVRow_AVX2(const uint8* src_yuy2, int stride_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToUV422Row_AVX2(const uint8* src_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToYRow_SSE2(const uint8* src_yuy2, uint8* dst_y, int pix); +void YUY2ToUVRow_SSE2(const uint8* src_yuy2, int stride_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToUV422Row_SSE2(const uint8* src_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToYRow_Unaligned_SSE2(const uint8* src_yuy2, + uint8* dst_y, int pix); +void YUY2ToUVRow_Unaligned_SSE2(const uint8* src_yuy2, int stride_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToUV422Row_Unaligned_SSE2(const uint8* src_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int pix); +void YUY2ToUVRow_NEON(const uint8* src_yuy2, int stride_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToUV422Row_NEON(const uint8* src_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToYRow_C(const uint8* src_yuy2, uint8* dst_y, int pix); +void YUY2ToUVRow_C(const uint8* src_yuy2, int stride_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToUV422Row_C(const uint8* src_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToYRow_Any_AVX2(const uint8* src_yuy2, uint8* dst_y, int pix); +void YUY2ToUVRow_Any_AVX2(const uint8* src_yuy2, int stride_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToUV422Row_Any_AVX2(const uint8* src_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToYRow_Any_SSE2(const uint8* src_yuy2, uint8* dst_y, int pix); +void YUY2ToUVRow_Any_SSE2(const uint8* src_yuy2, int stride_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToUV422Row_Any_SSE2(const uint8* src_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToYRow_Any_NEON(const uint8* src_yuy2, uint8* dst_y, int pix); +void YUY2ToUVRow_Any_NEON(const uint8* src_yuy2, int stride_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void YUY2ToUV422Row_Any_NEON(const uint8* src_yuy2, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToYRow_AVX2(const uint8* src_uyvy, uint8* dst_y, int pix); +void UYVYToUVRow_AVX2(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToUV422Row_AVX2(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToYRow_SSE2(const uint8* src_uyvy, uint8* dst_y, int pix); +void UYVYToUVRow_SSE2(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToUV422Row_SSE2(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToYRow_Unaligned_SSE2(const uint8* src_uyvy, + uint8* dst_y, int pix); +void UYVYToUVRow_Unaligned_SSE2(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToUV422Row_Unaligned_SSE2(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToYRow_AVX2(const uint8* src_uyvy, uint8* dst_y, int pix); +void UYVYToUVRow_AVX2(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToUV422Row_AVX2(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int pix); +void UYVYToUVRow_NEON(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToUV422Row_NEON(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int pix); + +void UYVYToYRow_C(const uint8* src_uyvy, uint8* dst_y, int pix); +void UYVYToUVRow_C(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToUV422Row_C(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToYRow_Any_AVX2(const uint8* src_uyvy, uint8* dst_y, int pix); +void UYVYToUVRow_Any_AVX2(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToUV422Row_Any_AVX2(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToYRow_Any_SSE2(const uint8* src_uyvy, uint8* dst_y, int pix); +void UYVYToUVRow_Any_SSE2(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToUV422Row_Any_SSE2(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToYRow_Any_NEON(const uint8* src_uyvy, uint8* dst_y, int pix); +void UYVYToUVRow_Any_NEON(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int pix); +void UYVYToUV422Row_Any_NEON(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int pix); + +void HalfRow_C(const uint8* src_uv, int src_uv_stride, + uint8* dst_uv, int pix); +void HalfRow_SSE2(const uint8* src_uv, int src_uv_stride, + uint8* dst_uv, int pix); +void HalfRow_AVX2(const uint8* src_uv, int src_uv_stride, + uint8* dst_uv, int pix); +void HalfRow_NEON(const uint8* src_uv, int src_uv_stride, + uint8* dst_uv, int pix); + +void ARGBToBayerRow_C(const uint8* src_argb, uint8* dst_bayer, + uint32 selector, int pix); +void ARGBToBayerRow_SSSE3(const uint8* src_argb, uint8* dst_bayer, + uint32 selector, int pix); +void ARGBToBayerRow_NEON(const uint8* src_argb, uint8* dst_bayer, + uint32 selector, int pix); +void ARGBToBayerRow_Any_SSSE3(const uint8* src_argb, uint8* dst_bayer, + uint32 selector, int pix); +void ARGBToBayerRow_Any_NEON(const uint8* src_argb, uint8* dst_bayer, + uint32 selector, int pix); +void ARGBToBayerGGRow_C(const uint8* src_argb, uint8* dst_bayer, + uint32 /* selector */, int pix); +void ARGBToBayerGGRow_SSE2(const uint8* src_argb, uint8* dst_bayer, + uint32 /* selector */, int pix); +void ARGBToBayerGGRow_NEON(const uint8* src_argb, uint8* dst_bayer, + uint32 /* selector */, int pix); +void ARGBToBayerGGRow_Any_SSE2(const uint8* src_argb, uint8* dst_bayer, + uint32 /* selector */, int pix); +void ARGBToBayerGGRow_Any_NEON(const uint8* src_argb, uint8* dst_bayer, + uint32 /* selector */, int pix); + +void I422ToYUY2Row_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_yuy2, int width); +void I422ToUYVYRow_C(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_uyvy, int width); +void I422ToYUY2Row_SSE2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_yuy2, int width); +void I422ToUYVYRow_SSE2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_uyvy, int width); +void I422ToYUY2Row_Any_SSE2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_yuy2, int width); +void I422ToUYVYRow_Any_SSE2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_uyvy, int width); +void I422ToYUY2Row_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_yuy2, int width); +void I422ToUYVYRow_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_uyvy, int width); +void I422ToYUY2Row_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_yuy2, int width); +void I422ToUYVYRow_Any_NEON(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_uyvy, int width); + +// Effects related row functions. +void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBAttenuateRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBAttenuateRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBAttenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBAttenuateRow_Any_SSE2(const uint8* src_argb, uint8* dst_argb, + int width); +void ARGBAttenuateRow_Any_SSSE3(const uint8* src_argb, uint8* dst_argb, + int width); +void ARGBAttenuateRow_Any_AVX2(const uint8* src_argb, uint8* dst_argb, + int width); +void ARGBAttenuateRow_Any_NEON(const uint8* src_argb, uint8* dst_argb, + int width); + +// Inverse table for unattenuate, shared by C and SSE2. +extern const uint32 fixed_invtbl8[256]; +void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBUnattenuateRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBUnattenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBUnattenuateRow_Any_SSE2(const uint8* src_argb, uint8* dst_argb, + int width); +void ARGBUnattenuateRow_Any_AVX2(const uint8* src_argb, uint8* dst_argb, + int width); + +void ARGBGrayRow_C(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBGrayRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width); +void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width); + +void ARGBSepiaRow_C(uint8* dst_argb, int width); +void ARGBSepiaRow_SSSE3(uint8* dst_argb, int width); +void ARGBSepiaRow_NEON(uint8* dst_argb, int width); + +void ARGBColorMatrixRow_C(const uint8* src_argb, uint8* dst_argb, + const int8* matrix_argb, int width); +void ARGBColorMatrixRow_SSSE3(const uint8* src_argb, uint8* dst_argb, + const int8* matrix_argb, int width); +void ARGBColorMatrixRow_NEON(const uint8* src_argb, uint8* dst_argb, + const int8* matrix_argb, int width); + +void ARGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width); +void ARGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, int width); + +void RGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width); +void RGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, int width); + +void ARGBQuantizeRow_C(uint8* dst_argb, int scale, int interval_size, + int interval_offset, int width); +void ARGBQuantizeRow_SSE2(uint8* dst_argb, int scale, int interval_size, + int interval_offset, int width); +void ARGBQuantizeRow_NEON(uint8* dst_argb, int scale, int interval_size, + int interval_offset, int width); + +void ARGBShadeRow_C(const uint8* src_argb, uint8* dst_argb, int width, + uint32 value); +void ARGBShadeRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width, + uint32 value); +void ARGBShadeRow_NEON(const uint8* src_argb, uint8* dst_argb, int width, + uint32 value); + +// Used for blur. +void CumulativeSumToAverageRow_SSE2(const int32* topleft, const int32* botleft, + int width, int area, uint8* dst, int count); +void ComputeCumulativeSumRow_SSE2(const uint8* row, int32* cumsum, + const int32* previous_cumsum, int width); + +void CumulativeSumToAverageRow_C(const int32* topleft, const int32* botleft, + int width, int area, uint8* dst, int count); +void ComputeCumulativeSumRow_C(const uint8* row, int32* cumsum, + const int32* previous_cumsum, int width); + +LIBYUV_API +void ARGBAffineRow_C(const uint8* src_argb, int src_argb_stride, + uint8* dst_argb, const float* uv_dudv, int width); +LIBYUV_API +void ARGBAffineRow_SSE2(const uint8* src_argb, int src_argb_stride, + uint8* dst_argb, const float* uv_dudv, int width); + +// Used for I420Scale, ARGBScale, and ARGBInterpolate. +void InterpolateRow_C(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, + int width, int source_y_fraction); +void InterpolateRow_SSE2(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRow_SSSE3(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRow_AVX2(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRow_NEON(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRows_MIPS_DSPR2(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRow_Unaligned_SSE2(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRow_Unaligned_SSSE3(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRow_Any_NEON(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRow_Any_SSE2(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRow_Any_SSSE3(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRow_Any_AVX2(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); +void InterpolateRows_Any_MIPS_DSPR2(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride_ptr, int width, + int source_y_fraction); + +// Sobel images. +void SobelXRow_C(const uint8* src_y0, const uint8* src_y1, const uint8* src_y2, + uint8* dst_sobelx, int width); +void SobelXRow_SSE2(const uint8* src_y0, const uint8* src_y1, + const uint8* src_y2, uint8* dst_sobelx, int width); +void SobelXRow_NEON(const uint8* src_y0, const uint8* src_y1, + const uint8* src_y2, uint8* dst_sobelx, int width); +void SobelYRow_C(const uint8* src_y0, const uint8* src_y1, + uint8* dst_sobely, int width); +void SobelYRow_SSE2(const uint8* src_y0, const uint8* src_y1, + uint8* dst_sobely, int width); +void SobelYRow_NEON(const uint8* src_y0, const uint8* src_y1, + uint8* dst_sobely, int width); +void SobelRow_C(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_argb, int width); +void SobelRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_argb, int width); +void SobelRow_NEON(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_argb, int width); +void SobelToPlaneRow_C(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_y, int width); +void SobelToPlaneRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_y, int width); +void SobelToPlaneRow_NEON(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_y, int width); +void SobelXYRow_C(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_argb, int width); +void SobelXYRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_argb, int width); +void SobelXYRow_NEON(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_argb, int width); + +void ARGBPolynomialRow_C(const uint8* src_argb, + uint8* dst_argb, const float* poly, + int width); +void ARGBPolynomialRow_SSE2(const uint8* src_argb, + uint8* dst_argb, const float* poly, + int width); +void ARGBPolynomialRow_AVX2(const uint8* src_argb, + uint8* dst_argb, const float* poly, + int width); + +void ARGBLumaColorTableRow_C(const uint8* src_argb, uint8* dst_argb, int width, + const uint8* luma, uint32 lumacoeff); +void ARGBLumaColorTableRow_SSSE3(const uint8* src_argb, uint8* dst_argb, + int width, + const uint8* luma, uint32 lumacoeff); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_ROW_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale.h new file mode 100644 index 0000000..592b8ed --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale.h @@ -0,0 +1,85 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_SCALE_H_ // NOLINT +#define INCLUDE_LIBYUV_SCALE_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Supported filtering. +typedef enum FilterMode { + kFilterNone = 0, // Point sample; Fastest. + kFilterLinear = 1, // Filter horizontally only. + kFilterBilinear = 2, // Faster than box, but lower quality scaling down. + kFilterBox = 3 // Highest quality. +} FilterModeEnum; + +// Scale a YUV plane. +LIBYUV_API +void ScalePlane(const uint8* src, int src_stride, + int src_width, int src_height, + uint8* dst, int dst_stride, + int dst_width, int dst_height, + enum FilterMode filtering); + +// Scales a YUV 4:2:0 image from the src width and height to the +// dst width and height. +// If filtering is kFilterNone, a simple nearest-neighbor algorithm is +// used. This produces basic (blocky) quality at the fastest speed. +// If filtering is kFilterBilinear, interpolation is used to produce a better +// quality image, at the expense of speed. +// If filtering is kFilterBox, averaging is used to produce ever better +// quality image, at further expense of speed. +// Returns 0 if successful. + +LIBYUV_API +int I420Scale(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + int src_width, int src_height, + uint8* dst_y, int dst_stride_y, + uint8* dst_u, int dst_stride_u, + uint8* dst_v, int dst_stride_v, + int dst_width, int dst_height, + enum FilterMode filtering); + +#ifdef __cplusplus +// Legacy API. Deprecated. +LIBYUV_API +int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v, + int src_stride_y, int src_stride_u, int src_stride_v, + int src_width, int src_height, + uint8* dst_y, uint8* dst_u, uint8* dst_v, + int dst_stride_y, int dst_stride_u, int dst_stride_v, + int dst_width, int dst_height, + LIBYUV_BOOL interpolate); + +// Legacy API. Deprecated. +LIBYUV_API +int ScaleOffset(const uint8* src_i420, int src_width, int src_height, + uint8* dst_i420, int dst_width, int dst_height, int dst_yoffset, + LIBYUV_BOOL interpolate); + +// For testing, allow disabling of specialized scalers. +LIBYUV_API +void SetUseReferenceImpl(LIBYUV_BOOL use); +#endif // __cplusplus + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_SCALE_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale_argb.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale_argb.h new file mode 100644 index 0000000..0c9b362 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale_argb.h @@ -0,0 +1,57 @@ +/* + * Copyright 2012 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_SCALE_ARGB_H_ // NOLINT +#define INCLUDE_LIBYUV_SCALE_ARGB_H_ + +#include "libyuv/basic_types.h" +#include "libyuv/scale.h" // For FilterMode + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +LIBYUV_API +int ARGBScale(const uint8* src_argb, int src_stride_argb, + int src_width, int src_height, + uint8* dst_argb, int dst_stride_argb, + int dst_width, int dst_height, + enum FilterMode filtering); + +// Clipped scale takes destination rectangle coordinates for clip values. +LIBYUV_API +int ARGBScaleClip(const uint8* src_argb, int src_stride_argb, + int src_width, int src_height, + uint8* dst_argb, int dst_stride_argb, + int dst_width, int dst_height, + int clip_x, int clip_y, int clip_width, int clip_height, + enum FilterMode filtering); + +// TODO(fbarchard): Implement this. +// Scale with YUV conversion to ARGB and clipping. +LIBYUV_API +int YUVToARGBScaleClip(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint32 src_fourcc, + int src_width, int src_height, + uint8* dst_argb, int dst_stride_argb, + uint32 dst_fourcc, + int dst_width, int dst_height, + int clip_x, int clip_y, int clip_width, int clip_height, + enum FilterMode filtering); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_SCALE_ARGB_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale_row.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale_row.h new file mode 100644 index 0000000..13eccc4 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/scale_row.h @@ -0,0 +1,301 @@ +/* + * Copyright 2013 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_SCALE_ROW_H_ // NOLINT +#define INCLUDE_LIBYUV_SCALE_ROW_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +#if defined(__pnacl__) || defined(__CLR_VER) || defined(COVERAGE_ENABLED) || \ + defined(TARGET_IPHONE_SIMULATOR) +#define LIBYUV_DISABLE_X86 +#endif + +// The following are available on all x86 platforms: +#if !defined(LIBYUV_DISABLE_X86) && \ + (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)) +#define HAS_SCALEROWDOWN2_SSE2 +#define HAS_SCALEROWDOWN4_SSE2 +#define HAS_SCALEROWDOWN34_SSSE3 +#define HAS_SCALEROWDOWN38_SSSE3 +#define HAS_SCALEADDROWS_SSE2 +#define HAS_SCALEFILTERCOLS_SSSE3 +#define HAS_SCALECOLSUP2_SSE2 +#define HAS_SCALEARGBROWDOWN2_SSE2 +#define HAS_SCALEARGBROWDOWNEVEN_SSE2 +#define HAS_SCALEARGBCOLS_SSE2 +#define HAS_SCALEARGBFILTERCOLS_SSSE3 +#define HAS_SCALEARGBCOLSUP2_SSE2 +#define HAS_FIXEDDIV_X86 +#define HAS_FIXEDDIV1_X86 +#endif + +// The following are available on Neon platforms: +#if !defined(LIBYUV_DISABLE_NEON) && !defined(__native_client__) && \ + (defined(__ARM_NEON__) || defined(LIBYUV_NEON)) +#define HAS_SCALEROWDOWN2_NEON +#define HAS_SCALEROWDOWN4_NEON +#define HAS_SCALEROWDOWN34_NEON +#define HAS_SCALEROWDOWN38_NEON +#define HAS_SCALEARGBROWDOWNEVEN_NEON +#define HAS_SCALEARGBROWDOWN2_NEON +#endif + +// The following are available on Mips platforms: +#if !defined(LIBYUV_DISABLE_MIPS) && !defined(__native_client__) && \ + defined(__mips__) && defined(__mips_dsp) && (__mips_dsp_rev >= 2) +#define HAS_SCALEROWDOWN2_MIPS_DSPR2 +#define HAS_SCALEROWDOWN4_MIPS_DSPR2 +#define HAS_SCALEROWDOWN34_MIPS_DSPR2 +#define HAS_SCALEROWDOWN38_MIPS_DSPR2 +#endif + +// Scale ARGB vertically with bilinear interpolation. +void ScalePlaneVertical(int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8* src_argb, uint8* dst_argb, + int x, int y, int dy, + int bpp, enum FilterMode filtering); + +// Simplify the filtering based on scale factors. +enum FilterMode ScaleFilterReduce(int src_width, int src_height, + int dst_width, int dst_height, + enum FilterMode filtering); + +// Divide num by div and return as 16.16 fixed point result. +int FixedDiv_C(int num, int div); +int FixedDiv_X86(int num, int div); +// Divide num - 1 by div - 1 and return as 16.16 fixed point result. +int FixedDiv1_C(int num, int div); +int FixedDiv1_X86(int num, int div); +#ifdef HAS_FIXEDDIV_X86 +#define FixedDiv FixedDiv_X86 +#define FixedDiv1 FixedDiv1_X86 +#else +#define FixedDiv FixedDiv_C +#define FixedDiv1 FixedDiv1_C +#endif + +// Compute slope values for stepping. +void ScaleSlope(int src_width, int src_height, + int dst_width, int dst_height, + enum FilterMode filtering, + int* x, int* y, int* dx, int* dy); + +void ScaleRowDown2_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown2Linear_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown2Box_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown4_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown4Box_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown34_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown34_0_Box_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* d, int dst_width); +void ScaleRowDown34_1_Box_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* d, int dst_width); +void ScaleCols_C(uint8* dst_ptr, const uint8* src_ptr, + int dst_width, int x, int dx); +void ScaleColsUp2_C(uint8* dst_ptr, const uint8* src_ptr, + int dst_width, int, int); +void ScaleFilterCols_C(uint8* dst_ptr, const uint8* src_ptr, + int dst_width, int x, int dx); +void ScaleFilterCols64_C(uint8* dst_ptr, const uint8* src_ptr, + int dst_width, int x, int dx); +void ScaleRowDown38_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown38_3_Box_C(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown38_2_Box_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleAddRows_C(const uint8* src_ptr, ptrdiff_t src_stride, + uint16* dst_ptr, int src_width, int src_height); +void ScaleARGBRowDown2_C(const uint8* src_argb, + ptrdiff_t src_stride, + uint8* dst_argb, int dst_width); +void ScaleARGBRowDown2Linear_C(const uint8* src_argb, + ptrdiff_t src_stride, + uint8* dst_argb, int dst_width); +void ScaleARGBRowDown2Box_C(const uint8* src_argb, ptrdiff_t src_stride, + uint8* dst_argb, int dst_width); +void ScaleARGBRowDownEven_C(const uint8* src_argb, ptrdiff_t src_stride, + int src_stepx, + uint8* dst_argb, int dst_width); +void ScaleARGBRowDownEvenBox_C(const uint8* src_argb, + ptrdiff_t src_stride, + int src_stepx, + uint8* dst_argb, int dst_width); +void ScaleARGBCols_C(uint8* dst_argb, const uint8* src_argb, + int dst_width, int x, int dx); +void ScaleARGBCols64_C(uint8* dst_argb, const uint8* src_argb, + int dst_width, int x, int dx); +void ScaleARGBColsUp2_C(uint8* dst_argb, const uint8* src_argb, + int dst_width, int, int); +void ScaleARGBFilterCols_C(uint8* dst_argb, const uint8* src_argb, + int dst_width, int x, int dx); +void ScaleARGBFilterCols64_C(uint8* dst_argb, const uint8* src_argb, + int dst_width, int x, int dx); + +void ScaleRowDown2_SSE2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown2Linear_SSE2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown2Box_SSE2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown2_Unaligned_SSE2(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown2Linear_Unaligned_SSE2(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown2Box_Unaligned_SSE2(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown4_SSE2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown4Box_SSE2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown34_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown38_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleAddRows_SSE2(const uint8* src_ptr, ptrdiff_t src_stride, + uint16* dst_ptr, int src_width, + int src_height); +void ScaleFilterCols_SSSE3(uint8* dst_ptr, const uint8* src_ptr, + int dst_width, int x, int dx); +void ScaleColsUp2_SSE2(uint8* dst_ptr, const uint8* src_ptr, + int dst_width, int x, int dx); +void ScaleARGBRowDown2_SSE2(const uint8* src_argb, + ptrdiff_t src_stride, + uint8* dst_argb, int dst_width); +void ScaleARGBRowDown2Linear_SSE2(const uint8* src_argb, + ptrdiff_t src_stride, + uint8* dst_argb, int dst_width); +void ScaleARGBRowDown2Box_SSE2(const uint8* src_argb, + ptrdiff_t src_stride, + uint8* dst_argb, int dst_width); +void ScaleARGBRowDownEven_SSE2(const uint8* src_argb, ptrdiff_t src_stride, + int src_stepx, + uint8* dst_argb, int dst_width); +void ScaleARGBRowDownEvenBox_SSE2(const uint8* src_argb, + ptrdiff_t src_stride, + int src_stepx, + uint8* dst_argb, int dst_width); +void ScaleARGBCols_SSE2(uint8* dst_argb, const uint8* src_argb, + int dst_width, int x, int dx); +void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, const uint8* src_argb, + int dst_width, int x, int dx); +void ScaleARGBColsUp2_SSE2(uint8* dst_argb, const uint8* src_argb, + int dst_width, int x, int dx); +// Row functions. +void ScaleARGBRowDownEven_NEON(const uint8* src_argb, int src_stride, + int src_stepx, + uint8* dst_argb, int dst_width); +void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, int src_stride, + int src_stepx, + uint8* dst_argb, int dst_width); +void ScaleARGBRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); + +// ScaleRowDown2Box also used by planar functions +// NEON downscalers with interpolation. + +// Note - not static due to reuse in convert for 444 to 420. +void ScaleRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); + +void ScaleRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); + +void ScaleRowDown4_NEON(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown4Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); + +// Down scale from 4 to 3 pixels. Use the neon multilane read/write +// to load up the every 4th pixel into a 4 different registers. +// Point samples 32 pixels to 24 pixels. +void ScaleRowDown34_NEON(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown34_0_Box_NEON(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown34_1_Box_NEON(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); + +// 32 -> 12 +void ScaleRowDown38_NEON(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +// 32x3 -> 12x1 +void ScaleRowDown38_3_Box_NEON(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +// 32x2 -> 12x1 +void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); + +void ScaleRowDown2_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown2Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown4_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown4Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown34_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown34_0_Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* d, int dst_width); +void ScaleRowDown34_1_Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* d, int dst_width); +void ScaleRowDown38_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst, int dst_width); +void ScaleRowDown38_2_Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); +void ScaleRowDown38_3_Box_MIPS_DSPR2(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_SCALE_ROW_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/version.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/version.h new file mode 100644 index 0000000..a61c45f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/version.h @@ -0,0 +1,16 @@ +/* + * Copyright 2012 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT +#define INCLUDE_LIBYUV_VERSION_H_ + +#define LIBYUV_VERSION 1000 + +#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/video_common.h b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/video_common.h new file mode 100644 index 0000000..039efb9 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/third_party/libyuv/include/libyuv/video_common.h @@ -0,0 +1,182 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Common definitions for video, including fourcc and VideoFormat. + +#ifndef INCLUDE_LIBYUV_VIDEO_COMMON_H_ // NOLINT +#define INCLUDE_LIBYUV_VIDEO_COMMON_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +////////////////////////////////////////////////////////////////////////////// +// Definition of FourCC codes +////////////////////////////////////////////////////////////////////////////// + +// Convert four characters to a FourCC code. +// Needs to be a macro otherwise the OS X compiler complains when the kFormat* +// constants are used in a switch. +#ifdef __cplusplus +#define FOURCC(a, b, c, d) ( \ + (static_cast(a)) | (static_cast(b) << 8) | \ + (static_cast(c) << 16) | (static_cast(d) << 24)) +#else +#define FOURCC(a, b, c, d) ( \ + ((uint32)(a)) | ((uint32)(b) << 8) | /* NOLINT */ \ + ((uint32)(c) << 16) | ((uint32)(d) << 24)) /* NOLINT */ +#endif + +// Some pages discussing FourCC codes: +// http://www.fourcc.org/yuv.php +// http://v4l2spec.bytesex.org/spec/book1.htm +// http://developer.apple.com/quicktime/icefloe/dispatch020.html +// http://msdn.microsoft.com/library/windows/desktop/dd206750.aspx#nv12 +// http://people.xiph.org/~xiphmont/containers/nut/nut4cc.txt + +// FourCC codes grouped according to implementation efficiency. +// Primary formats should convert in 1 efficient step. +// Secondary formats are converted in 2 steps. +// Auxilliary formats call primary converters. +enum FourCC { + // 9 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. + FOURCC_I420 = FOURCC('I', '4', '2', '0'), + FOURCC_I422 = FOURCC('I', '4', '2', '2'), + FOURCC_I444 = FOURCC('I', '4', '4', '4'), + FOURCC_I411 = FOURCC('I', '4', '1', '1'), + FOURCC_I400 = FOURCC('I', '4', '0', '0'), + FOURCC_NV21 = FOURCC('N', 'V', '2', '1'), + FOURCC_NV12 = FOURCC('N', 'V', '1', '2'), + FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'), + FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'), + + // 2 Secondary YUV formats: row biplanar. + FOURCC_M420 = FOURCC('M', '4', '2', '0'), + FOURCC_Q420 = FOURCC('Q', '4', '2', '0'), + + // 9 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp. + FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'), + FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'), + FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'), + FOURCC_24BG = FOURCC('2', '4', 'B', 'G'), + FOURCC_RAW = FOURCC('r', 'a', 'w', ' '), + FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'), + FOURCC_RGBP = FOURCC('R', 'G', 'B', 'P'), // rgb565 LE. + FOURCC_RGBO = FOURCC('R', 'G', 'B', 'O'), // argb1555 LE. + FOURCC_R444 = FOURCC('R', '4', '4', '4'), // argb4444 LE. + + // 4 Secondary RGB formats: 4 Bayer Patterns. + FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'), + FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'), + FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'), + FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'), + + // 1 Primary Compressed YUV format. + FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'), + + // 5 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias. + FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'), + FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'), + FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'), + FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'), // Linux version of I420. + FOURCC_J420 = FOURCC('J', '4', '2', '0'), + FOURCC_J400 = FOURCC('J', '4', '0', '0'), + + // 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc. + FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420. + FOURCC_YU16 = FOURCC('Y', 'U', '1', '6'), // Alias for I422. + FOURCC_YU24 = FOURCC('Y', 'U', '2', '4'), // Alias for I444. + FOURCC_YUYV = FOURCC('Y', 'U', 'Y', 'V'), // Alias for YUY2. + FOURCC_YUVS = FOURCC('y', 'u', 'v', 's'), // Alias for YUY2 on Mac. + FOURCC_HDYC = FOURCC('H', 'D', 'Y', 'C'), // Alias for UYVY. + FOURCC_2VUY = FOURCC('2', 'v', 'u', 'y'), // Alias for UYVY on Mac. + FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'), // Alias for MJPG. + FOURCC_DMB1 = FOURCC('d', 'm', 'b', '1'), // Alias for MJPG on Mac. + FOURCC_BA81 = FOURCC('B', 'A', '8', '1'), // Alias for BGGR. + FOURCC_RGB3 = FOURCC('R', 'G', 'B', '3'), // Alias for RAW. + FOURCC_BGR3 = FOURCC('B', 'G', 'R', '3'), // Alias for 24BG. + FOURCC_CM32 = FOURCC(0, 0, 0, 32), // Alias for BGRA kCMPixelFormat_32ARGB + FOURCC_CM24 = FOURCC(0, 0, 0, 24), // Alias for RAW kCMPixelFormat_24RGB + FOURCC_L555 = FOURCC('L', '5', '5', '5'), // Alias for RGBO. + FOURCC_L565 = FOURCC('L', '5', '6', '5'), // Alias for RGBP. + FOURCC_5551 = FOURCC('5', '5', '5', '1'), // Alias for RGBO. + + // 1 Auxiliary compressed YUV format set aside for capturer. + FOURCC_H264 = FOURCC('H', '2', '6', '4'), + + // Match any fourcc. + FOURCC_ANY = 0xFFFFFFFF, +}; + +enum FourCCBpp { + // Canonical fourcc codes used in our code. + FOURCC_BPP_I420 = 12, + FOURCC_BPP_I422 = 16, + FOURCC_BPP_I444 = 24, + FOURCC_BPP_I411 = 12, + FOURCC_BPP_I400 = 8, + FOURCC_BPP_NV21 = 12, + FOURCC_BPP_NV12 = 12, + FOURCC_BPP_YUY2 = 16, + FOURCC_BPP_UYVY = 16, + FOURCC_BPP_M420 = 12, + FOURCC_BPP_Q420 = 12, + FOURCC_BPP_ARGB = 32, + FOURCC_BPP_BGRA = 32, + FOURCC_BPP_ABGR = 32, + FOURCC_BPP_RGBA = 32, + FOURCC_BPP_24BG = 24, + FOURCC_BPP_RAW = 24, + FOURCC_BPP_RGBP = 16, + FOURCC_BPP_RGBO = 16, + FOURCC_BPP_R444 = 16, + FOURCC_BPP_RGGB = 8, + FOURCC_BPP_BGGR = 8, + FOURCC_BPP_GRBG = 8, + FOURCC_BPP_GBRG = 8, + FOURCC_BPP_YV12 = 12, + FOURCC_BPP_YV16 = 16, + FOURCC_BPP_YV24 = 24, + FOURCC_BPP_YU12 = 12, + FOURCC_BPP_J420 = 12, + FOURCC_BPP_J400 = 8, + FOURCC_BPP_MJPG = 0, // 0 means unknown. + FOURCC_BPP_H264 = 0, + FOURCC_BPP_IYUV = 12, + FOURCC_BPP_YU16 = 16, + FOURCC_BPP_YU24 = 24, + FOURCC_BPP_YUYV = 16, + FOURCC_BPP_YUVS = 16, + FOURCC_BPP_HDYC = 16, + FOURCC_BPP_2VUY = 16, + FOURCC_BPP_JPEG = 1, + FOURCC_BPP_DMB1 = 1, + FOURCC_BPP_BA81 = 8, + FOURCC_BPP_RGB3 = 24, + FOURCC_BPP_BGR3 = 24, + FOURCC_BPP_CM32 = 32, + FOURCC_BPP_CM24 = 24, + + // Match any fourcc. + FOURCC_BPP_ANY = 0, // 0 means unknown. +}; + +// Converts fourcc aliases into canonical ones. +LIBYUV_API uint32 CanonicalFourCC(uint32 fourcc); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_VIDEO_COMMON_H_ NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/base/constructormagic.h b/thirdparties/common/include/webrtc-sdk/webrtc/base/constructormagic.h new file mode 100644 index 0000000..c20be2b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/base/constructormagic.h @@ -0,0 +1,41 @@ +/* + * Copyright 2004 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_BASE_CONSTRUCTORMAGIC_H_ +#define WEBRTC_BASE_CONSTRUCTORMAGIC_H_ + +#define DISALLOW_ASSIGN(TypeName) \ + void operator=(const TypeName&) + +// A macro to disallow the evil copy constructor and operator= functions +// This should be used in the private: declarations for a class. +// Undefine this, just in case. Some third-party includes have their own +// version. +#undef DISALLOW_COPY_AND_ASSIGN +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + DISALLOW_ASSIGN(TypeName) + +// Alternative, less-accurate legacy name. +#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \ + DISALLOW_COPY_AND_ASSIGN(TypeName) + +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// +// This should be used in the private: declarations for a class +// that wants to prevent anyone from instantiating it. This is +// especially useful for classes containing only static methods. +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName(); \ + DISALLOW_EVIL_CONSTRUCTORS(TypeName) + + +#endif // WEBRTC_BASE_CONSTRUCTORMAGIC_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/common_types.h b/thirdparties/common/include/webrtc-sdk/webrtc/common_types.h new file mode 100644 index 0000000..6892a83 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/common_types.h @@ -0,0 +1,788 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_COMMON_TYPES_H_ +#define WEBRTC_COMMON_TYPES_H_ + +#include +#include + +#include +#include + +#include "webrtc/typedefs.h" + +#if defined(_MSC_VER) +// Disable "new behavior: elements of array will be default initialized" +// warning. Affects OverUseDetectorOptions. +#pragma warning(disable:4351) +#endif + +#ifdef WEBRTC_EXPORT +#define WEBRTC_DLLEXPORT _declspec(dllexport) +#elif WEBRTC_DLL +#define WEBRTC_DLLEXPORT _declspec(dllimport) +#else +#define WEBRTC_DLLEXPORT +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define RTP_PAYLOAD_NAME_SIZE 32 + +#if defined(WEBRTC_WIN) || defined(WIN32) +// Compares two strings without regard to case. +#define STR_CASE_CMP(s1, s2) ::_stricmp(s1, s2) +// Compares characters of two strings without regard to case. +#define STR_NCASE_CMP(s1, s2, n) ::_strnicmp(s1, s2, n) +#else +#define STR_CASE_CMP(s1, s2) ::strcasecmp(s1, s2) +#define STR_NCASE_CMP(s1, s2, n) ::strncasecmp(s1, s2, n) +#endif + +namespace webrtc { + +class Config; + +class InStream +{ +public: + virtual int Read(void *buf,int len) = 0; + virtual int Rewind() {return -1;} + virtual ~InStream() {} +protected: + InStream() {} +}; + +class OutStream +{ +public: + virtual bool Write(const void *buf,int len) = 0; + virtual int Rewind() {return -1;} + virtual ~OutStream() {} +protected: + OutStream() {} +}; + +enum TraceModule +{ + kTraceUndefined = 0, + // not a module, triggered from the engine code + kTraceVoice = 0x0001, + // not a module, triggered from the engine code + kTraceVideo = 0x0002, + // not a module, triggered from the utility code + kTraceUtility = 0x0003, + kTraceRtpRtcp = 0x0004, + kTraceTransport = 0x0005, + kTraceSrtp = 0x0006, + kTraceAudioCoding = 0x0007, + kTraceAudioMixerServer = 0x0008, + kTraceAudioMixerClient = 0x0009, + kTraceFile = 0x000a, + kTraceAudioProcessing = 0x000b, + kTraceVideoCoding = 0x0010, + kTraceVideoMixer = 0x0011, + kTraceAudioDevice = 0x0012, + kTraceVideoRenderer = 0x0014, + kTraceVideoCapture = 0x0015, + kTraceRemoteBitrateEstimator = 0x0017, +}; + +enum TraceLevel +{ + kTraceNone = 0x0000, // no trace + kTraceStateInfo = 0x0001, + kTraceWarning = 0x0002, + kTraceError = 0x0004, + kTraceCritical = 0x0008, + kTraceApiCall = 0x0010, + kTraceDefault = 0x00ff, + + kTraceModuleCall = 0x0020, + kTraceMemory = 0x0100, // memory info + kTraceTimer = 0x0200, // timing info + kTraceStream = 0x0400, // "continuous" stream of data + + // used for debug purposes + kTraceDebug = 0x0800, // debug + kTraceInfo = 0x1000, // debug info + + // Non-verbose level used by LS_INFO of logging.h. Do not use directly. + kTraceTerseInfo = 0x2000, + + kTraceAll = 0xffff +}; + +// External Trace API +class TraceCallback { + public: + virtual void Print(TraceLevel level, const char* message, int length) = 0; + + protected: + virtual ~TraceCallback() {} + TraceCallback() {} +}; + +enum FileFormats +{ + kFileFormatWavFile = 1, + kFileFormatCompressedFile = 2, + kFileFormatAviFile = 3, + kFileFormatPreencodedFile = 4, + kFileFormatPcm16kHzFile = 7, + kFileFormatPcm8kHzFile = 8, + kFileFormatPcm32kHzFile = 9 +}; + +enum ProcessingTypes +{ + kPlaybackPerChannel = 0, + kPlaybackAllChannelsMixed, + kRecordingPerChannel, + kRecordingAllChannelsMixed, + kRecordingPreprocessing +}; + +enum FrameType +{ + kFrameEmpty = 0, + kAudioFrameSpeech = 1, + kAudioFrameCN = 2, + kVideoFrameKey = 3, // independent frame + kVideoFrameDelta = 4, // depends on the previus frame +}; + +// External transport callback interface +class Transport +{ +public: + virtual int SendPacket(int channel, const void *data, int len) = 0; + virtual int SendRTCPPacket(int channel, const void *data, int len) = 0; + +protected: + virtual ~Transport() {} + Transport() {} +}; + +// Statistics for an RTCP channel +struct RtcpStatistics { + RtcpStatistics() + : fraction_lost(0), + cumulative_lost(0), + extended_max_sequence_number(0), + jitter(0) {} + + uint8_t fraction_lost; + uint32_t cumulative_lost; + uint32_t extended_max_sequence_number; + uint32_t jitter; +}; + +// Callback, called whenever a new rtcp report block is transmitted. +class RtcpStatisticsCallback { + public: + virtual ~RtcpStatisticsCallback() {} + + virtual void StatisticsUpdated(const RtcpStatistics& statistics, + uint32_t ssrc) = 0; +}; + +// Statistics for RTCP packet types. +struct RtcpPacketTypeCounter { + RtcpPacketTypeCounter() + : nack_packets(0), + fir_packets(0), + pli_packets(0) {} + + void Add(const RtcpPacketTypeCounter& other) { + nack_packets += other.nack_packets; + fir_packets += other.fir_packets; + pli_packets += other.pli_packets; + } + + uint32_t nack_packets; + uint32_t fir_packets; + uint32_t pli_packets; +}; + +// Data usage statistics for a (rtp) stream +struct StreamDataCounters { + StreamDataCounters() + : bytes(0), + header_bytes(0), + padding_bytes(0), + packets(0), + retransmitted_packets(0), + fec_packets(0) {} + + uint32_t bytes; // Payload bytes, excluding RTP headers and padding. + uint32_t header_bytes; // Number of bytes used by RTP headers. + uint32_t padding_bytes; // Number of padding bytes. + uint32_t packets; // Number of packets. + uint32_t retransmitted_packets; // Number of retransmitted packets. + uint32_t fec_packets; // Number of redundancy packets. +}; + +// Callback, called whenever byte/packet counts have been updated. +class StreamDataCountersCallback { + public: + virtual ~StreamDataCountersCallback() {} + + virtual void DataCountersUpdated(const StreamDataCounters& counters, + uint32_t ssrc) = 0; +}; + +// Rate statistics for a stream +struct BitrateStatistics { + BitrateStatistics() : bitrate_bps(0), packet_rate(0), timestamp_ms(0) {} + + uint32_t bitrate_bps; // Bitrate in bits per second. + uint32_t packet_rate; // Packet rate in packets per second. + uint64_t timestamp_ms; // Ntp timestamp in ms at time of rate estimation. +}; + +// Callback, used to notify an observer whenever new rates have been estimated. +class BitrateStatisticsObserver { + public: + virtual ~BitrateStatisticsObserver() {} + + virtual void Notify(const BitrateStatistics& stats, uint32_t ssrc) = 0; +}; + +// Callback, used to notify an observer whenever frame counts have been updated +class FrameCountObserver { + public: + virtual ~FrameCountObserver() {} + virtual void FrameCountUpdated(FrameType frame_type, + uint32_t frame_count, + const unsigned int ssrc) = 0; +}; + +// ================================================================== +// Voice specific types +// ================================================================== + +// Each codec supported can be described by this structure. +struct CodecInst { + int pltype; + char plname[RTP_PAYLOAD_NAME_SIZE]; + int plfreq; + int pacsize; + int channels; + int rate; // bits/sec unlike {start,min,max}Bitrate elsewhere in this file! + + bool operator==(const CodecInst& other) const { + return pltype == other.pltype && + (STR_CASE_CMP(plname, other.plname) == 0) && + plfreq == other.plfreq && + pacsize == other.pacsize && + channels == other.channels && + rate == other.rate; + } + + bool operator!=(const CodecInst& other) const { + return !(*this == other); + } +}; + +// RTP +enum {kRtpCsrcSize = 15}; // RFC 3550 page 13 + +enum RTPDirections +{ + kRtpIncoming = 0, + kRtpOutgoing +}; + +enum PayloadFrequencies +{ + kFreq8000Hz = 8000, + kFreq16000Hz = 16000, + kFreq32000Hz = 32000 +}; + +enum VadModes // degree of bandwidth reduction +{ + kVadConventional = 0, // lowest reduction + kVadAggressiveLow, + kVadAggressiveMid, + kVadAggressiveHigh // highest reduction +}; + +struct NetworkStatistics // NETEQ statistics +{ + // current jitter buffer size in ms + uint16_t currentBufferSize; + // preferred (optimal) buffer size in ms + uint16_t preferredBufferSize; + // adding extra delay due to "peaky jitter" + bool jitterPeaksFound; + // loss rate (network + late) in percent (in Q14) + uint16_t currentPacketLossRate; + // late loss rate in percent (in Q14) + uint16_t currentDiscardRate; + // fraction (of original stream) of synthesized speech inserted through + // expansion (in Q14) + uint16_t currentExpandRate; + // fraction of synthesized speech inserted through pre-emptive expansion + // (in Q14) + uint16_t currentPreemptiveRate; + // fraction of data removed through acceleration (in Q14) + uint16_t currentAccelerateRate; + // clock-drift in parts-per-million (negative or positive) + int32_t clockDriftPPM; + // average packet waiting time in the jitter buffer (ms) + int meanWaitingTimeMs; + // median packet waiting time in the jitter buffer (ms) + int medianWaitingTimeMs; + // min packet waiting time in the jitter buffer (ms) + int minWaitingTimeMs; + // max packet waiting time in the jitter buffer (ms) + int maxWaitingTimeMs; + // added samples in off mode due to packet loss + int addedSamples; +}; + +// Statistics for calls to AudioCodingModule::PlayoutData10Ms(). +struct AudioDecodingCallStats { + AudioDecodingCallStats() + : calls_to_silence_generator(0), + calls_to_neteq(0), + decoded_normal(0), + decoded_plc(0), + decoded_cng(0), + decoded_plc_cng(0) {} + + int calls_to_silence_generator; // Number of calls where silence generated, + // and NetEq was disengaged from decoding. + int calls_to_neteq; // Number of calls to NetEq. + int decoded_normal; // Number of calls where audio RTP packet decoded. + int decoded_plc; // Number of calls resulted in PLC. + int decoded_cng; // Number of calls where comfort noise generated due to DTX. + int decoded_plc_cng; // Number of calls resulted where PLC faded to CNG. +}; + +typedef struct +{ + int min; // minumum + int max; // maximum + int average; // average +} StatVal; + +typedef struct // All levels are reported in dBm0 +{ + StatVal speech_rx; // long-term speech levels on receiving side + StatVal speech_tx; // long-term speech levels on transmitting side + StatVal noise_rx; // long-term noise/silence levels on receiving side + StatVal noise_tx; // long-term noise/silence levels on transmitting side +} LevelStatistics; + +typedef struct // All levels are reported in dB +{ + StatVal erl; // Echo Return Loss + StatVal erle; // Echo Return Loss Enhancement + StatVal rerl; // RERL = ERL + ERLE + // Echo suppression inside EC at the point just before its NLP + StatVal a_nlp; +} EchoStatistics; + +enum NsModes // type of Noise Suppression +{ + kNsUnchanged = 0, // previously set mode + kNsDefault, // platform default + kNsConference, // conferencing default + kNsLowSuppression, // lowest suppression + kNsModerateSuppression, + kNsHighSuppression, + kNsVeryHighSuppression, // highest suppression +}; + +enum AgcModes // type of Automatic Gain Control +{ + kAgcUnchanged = 0, // previously set mode + kAgcDefault, // platform default + // adaptive mode for use when analog volume control exists (e.g. for + // PC softphone) + kAgcAdaptiveAnalog, + // scaling takes place in the digital domain (e.g. for conference servers + // and embedded devices) + kAgcAdaptiveDigital, + // can be used on embedded devices where the capture signal level + // is predictable + kAgcFixedDigital +}; + +// EC modes +enum EcModes // type of Echo Control +{ + kEcUnchanged = 0, // previously set mode + kEcDefault, // platform default + kEcConference, // conferencing default (aggressive AEC) + kEcAec, // Acoustic Echo Cancellation + kEcAecm, // AEC mobile +}; + +// AECM modes +enum AecmModes // mode of AECM +{ + kAecmQuietEarpieceOrHeadset = 0, + // Quiet earpiece or headset use + kAecmEarpiece, // most earpiece use + kAecmLoudEarpiece, // Loud earpiece or quiet speakerphone use + kAecmSpeakerphone, // most speakerphone use (default) + kAecmLoudSpeakerphone // Loud speakerphone +}; + +// AGC configuration +typedef struct +{ + unsigned short targetLeveldBOv; + unsigned short digitalCompressionGaindB; + bool limiterEnable; +} AgcConfig; // AGC configuration parameters + +enum StereoChannel +{ + kStereoLeft = 0, + kStereoRight, + kStereoBoth +}; + +// Audio device layers +enum AudioLayers +{ + kAudioPlatformDefault = 0, + kAudioWindowsWave = 1, + kAudioWindowsCore = 2, + kAudioLinuxAlsa = 3, + kAudioLinuxPulse = 4 +}; + +// TODO(henrika): to be removed. +enum NetEqModes // NetEQ playout configurations +{ + // Optimized trade-off between low delay and jitter robustness for two-way + // communication. + kNetEqDefault = 0, + // Improved jitter robustness at the cost of increased delay. Can be + // used in one-way communication. + kNetEqStreaming = 1, + // Optimzed for decodability of fax signals rather than for perceived audio + // quality. + kNetEqFax = 2, + // Minimal buffer management. Inserts zeros for lost packets and during + // buffer increases. + kNetEqOff = 3, +}; + +// TODO(henrika): to be removed. +enum OnHoldModes // On Hold direction +{ + kHoldSendAndPlay = 0, // Put both sending and playing in on-hold state. + kHoldSendOnly, // Put only sending in on-hold state. + kHoldPlayOnly // Put only playing in on-hold state. +}; + +// TODO(henrika): to be removed. +enum AmrMode +{ + kRfc3267BwEfficient = 0, + kRfc3267OctetAligned = 1, + kRfc3267FileStorage = 2, +}; + +// ================================================================== +// Video specific types +// ================================================================== + +// Raw video types +enum RawVideoType +{ + kVideoI420 = 0, + kVideoYV12 = 1, + kVideoYUY2 = 2, + kVideoUYVY = 3, + kVideoIYUV = 4, + kVideoARGB = 5, + kVideoRGB24 = 6, + kVideoRGB565 = 7, + kVideoARGB4444 = 8, + kVideoARGB1555 = 9, + kVideoMJPEG = 10, + kVideoNV12 = 11, + kVideoNV21 = 12, + kVideoBGRA = 13, + kVideoUnknown = 99 +}; + +// Video codec +enum { kConfigParameterSize = 128}; +enum { kPayloadNameSize = 32}; +enum { kMaxSimulcastStreams = 4}; +enum { kMaxTemporalStreams = 4}; + +enum VideoCodecComplexity +{ + kComplexityNormal = 0, + kComplexityHigh = 1, + kComplexityHigher = 2, + kComplexityMax = 3 +}; + +enum VideoCodecProfile +{ + kProfileBase = 0x00, + kProfileMain = 0x01 +}; + +enum VP8ResilienceMode { + kResilienceOff, // The stream produced by the encoder requires a + // recovery frame (typically a key frame) to be + // decodable after a packet loss. + kResilientStream, // A stream produced by the encoder is resilient to + // packet losses, but packets within a frame subsequent + // to a loss can't be decoded. + kResilientFrames // Same as kResilientStream but with added resilience + // within a frame. +}; + +// VP8 specific +struct VideoCodecVP8 { + bool pictureLossIndicationOn; + bool feedbackModeOn; + VideoCodecComplexity complexity; + VP8ResilienceMode resilience; + unsigned char numberOfTemporalLayers; + bool denoisingOn; + bool errorConcealmentOn; + bool automaticResizeOn; + bool frameDroppingOn; + int keyFrameInterval; + + bool operator==(const VideoCodecVP8& other) const { + return pictureLossIndicationOn == other.pictureLossIndicationOn && + feedbackModeOn == other.feedbackModeOn && + complexity == other.complexity && + resilience == other.resilience && + numberOfTemporalLayers == other.numberOfTemporalLayers && + denoisingOn == other.denoisingOn && + errorConcealmentOn == other.errorConcealmentOn && + automaticResizeOn == other.automaticResizeOn && + frameDroppingOn == other.frameDroppingOn && + keyFrameInterval == other.keyFrameInterval; + } + + bool operator!=(const VideoCodecVP8& other) const { + return !(*this == other); + } +}; + +// Video codec types +enum VideoCodecType +{ + kVideoCodecVP8, + kVideoCodecI420, + kVideoCodecRED, + kVideoCodecULPFEC, + kVideoCodecGeneric, + kVideoCodecUnknown +}; + +union VideoCodecUnion +{ + VideoCodecVP8 VP8; +}; + + +// Simulcast is when the same stream is encoded multiple times with different +// settings such as resolution. +struct SimulcastStream { + unsigned short width; + unsigned short height; + unsigned char numberOfTemporalLayers; + unsigned int maxBitrate; // kilobits/sec. + unsigned int targetBitrate; // kilobits/sec. + unsigned int minBitrate; // kilobits/sec. + unsigned int qpMax; // minimum quality + + bool operator==(const SimulcastStream& other) const { + return width == other.width && + height == other.height && + numberOfTemporalLayers == other.numberOfTemporalLayers && + maxBitrate == other.maxBitrate && + targetBitrate == other.targetBitrate && + minBitrate == other.minBitrate && + qpMax == other.qpMax; + } + + bool operator!=(const SimulcastStream& other) const { + return !(*this == other); + } +}; + +enum VideoCodecMode { + kRealtimeVideo, + kScreensharing +}; + +// Common video codec properties +struct VideoCodec { + VideoCodecType codecType; + char plName[kPayloadNameSize]; + unsigned char plType; + + unsigned short width; + unsigned short height; + + unsigned int startBitrate; // kilobits/sec. + unsigned int maxBitrate; // kilobits/sec. + unsigned int minBitrate; // kilobits/sec. + unsigned int targetBitrate; // kilobits/sec. + + unsigned char maxFramerate; + + VideoCodecUnion codecSpecific; + + unsigned int qpMax; + unsigned char numberOfSimulcastStreams; + SimulcastStream simulcastStream[kMaxSimulcastStreams]; + + VideoCodecMode mode; + + // When using an external encoder/decoder this allows to pass + // extra options without requiring webrtc to be aware of them. + Config* extra_options; + + bool operator==(const VideoCodec& other) const { + bool ret = codecType == other.codecType && + (STR_CASE_CMP(plName, other.plName) == 0) && + plType == other.plType && + width == other.width && + height == other.height && + startBitrate == other.startBitrate && + maxBitrate == other.maxBitrate && + minBitrate == other.minBitrate && + targetBitrate == other.targetBitrate && + maxFramerate == other.maxFramerate && + qpMax == other.qpMax && + numberOfSimulcastStreams == other.numberOfSimulcastStreams && + mode == other.mode; + if (ret && codecType == kVideoCodecVP8) { + ret &= (codecSpecific.VP8 == other.codecSpecific.VP8); + } + + for (unsigned char i = 0; i < other.numberOfSimulcastStreams && ret; ++i) { + ret &= (simulcastStream[i] == other.simulcastStream[i]); + } + return ret; + } + + bool operator!=(const VideoCodec& other) const { + return !(*this == other); + } +}; + +// Bandwidth over-use detector options. These are used to drive +// experimentation with bandwidth estimation parameters. +// See modules/remote_bitrate_estimator/overuse_detector.h +struct OverUseDetectorOptions { + OverUseDetectorOptions() + : initial_slope(8.0/512.0), + initial_offset(0), + initial_e(), + initial_process_noise(), + initial_avg_noise(0.0), + initial_var_noise(50), + initial_threshold(25.0) { + initial_e[0][0] = 100; + initial_e[1][1] = 1e-1; + initial_e[0][1] = initial_e[1][0] = 0; + initial_process_noise[0] = 1e-10; + initial_process_noise[1] = 1e-2; + } + double initial_slope; + double initial_offset; + double initial_e[2][2]; + double initial_process_noise[2]; + double initial_avg_noise; + double initial_var_noise; + double initial_threshold; +}; + +// This structure will have the information about when packet is actually +// received by socket. +struct PacketTime { + PacketTime() : timestamp(-1), not_before(-1) {} + PacketTime(int64_t timestamp, int64_t not_before) + : timestamp(timestamp), not_before(not_before) { + } + + int64_t timestamp; // Receive time after socket delivers the data. + int64_t not_before; // Earliest possible time the data could have arrived, + // indicating the potential error in the |timestamp| + // value,in case the system is busy. + // For example, the time of the last select() call. + // If unknown, this value will be set to zero. +}; + +struct RTPHeaderExtension { + RTPHeaderExtension() + : hasTransmissionTimeOffset(false), + transmissionTimeOffset(0), + hasAbsoluteSendTime(false), + absoluteSendTime(0), + hasAudioLevel(false), + audioLevel(0) {} + + bool hasTransmissionTimeOffset; + int32_t transmissionTimeOffset; + bool hasAbsoluteSendTime; + uint32_t absoluteSendTime; + + // Audio Level includes both level in dBov and voiced/unvoiced bit. See: + // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/ + bool hasAudioLevel; + uint8_t audioLevel; +}; + +struct RTPHeader { + RTPHeader() + : markerBit(false), + payloadType(0), + sequenceNumber(0), + timestamp(0), + ssrc(0), + numCSRCs(0), + paddingLength(0), + headerLength(0), + payload_type_frequency(0), + extension() { + memset(&arrOfCSRCs, 0, sizeof(arrOfCSRCs)); + } + + bool markerBit; + uint8_t payloadType; + uint16_t sequenceNumber; + uint32_t timestamp; + uint32_t ssrc; + uint8_t numCSRCs; + uint32_t arrOfCSRCs[kRtpCsrcSize]; + uint8_t paddingLength; + uint16_t headerLength; + int payload_type_frequency; + RTPHeaderExtension extension; +}; + +} // namespace webrtc + +#endif // WEBRTC_COMMON_TYPES_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/i420_video_frame.h b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/i420_video_frame.h new file mode 100644 index 0000000..3f90a8e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/i420_video_frame.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef COMMON_VIDEO_INTERFACE_I420_VIDEO_FRAME_H +#define COMMON_VIDEO_INTERFACE_I420_VIDEO_FRAME_H + +// I420VideoFrame class +// +// Storing and handling of YUV (I420) video frames. + +#include + +#include "webrtc/common_video/plane.h" +#include "webrtc/system_wrappers/interface/scoped_refptr.h" +#include "webrtc/typedefs.h" + +/* + * I420VideoFrame includes support for a reference counted impl. + */ + +namespace webrtc { + +enum PlaneType { + kYPlane = 0, + kUPlane = 1, + kVPlane = 2, + kNumOfPlanes = 3 +}; + +class I420VideoFrame { + public: + I420VideoFrame(); + virtual ~I420VideoFrame(); + // Infrastructure for refCount implementation. + // Implements dummy functions for reference counting so that non reference + // counted instantiation can be done. These functions should not be called + // when creating the frame with new I420VideoFrame(). + // Note: do not pass a I420VideoFrame created with new I420VideoFrame() or + // equivalent to a scoped_refptr or memory leak will occur. + virtual int32_t AddRef() {assert(false); return -1;} + virtual int32_t Release() {assert(false); return -1;} + + // CreateEmptyFrame: Sets frame dimensions and allocates buffers based + // on set dimensions - height and plane stride. + // If required size is bigger than the allocated one, new buffers of adequate + // size will be allocated. + // Return value: 0 on success ,-1 on error. + virtual int CreateEmptyFrame(int width, int height, + int stride_y, int stride_u, int stride_v); + + // CreateFrame: Sets the frame's members and buffers. If required size is + // bigger than allocated one, new buffers of adequate size will be allocated. + // Return value: 0 on success ,-1 on error. + virtual int CreateFrame(int size_y, const uint8_t* buffer_y, + int size_u, const uint8_t* buffer_u, + int size_v, const uint8_t* buffer_v, + int width, int height, + int stride_y, int stride_u, int stride_v); + + // Copy frame: If required size is bigger than allocated one, new buffers of + // adequate size will be allocated. + // Return value: 0 on success ,-1 on error. + virtual int CopyFrame(const I420VideoFrame& videoFrame); + + // Swap Frame. + virtual void SwapFrame(I420VideoFrame* videoFrame); + + // Get pointer to buffer per plane. + virtual uint8_t* buffer(PlaneType type); + // Overloading with const. + virtual const uint8_t* buffer(PlaneType type) const; + + // Get allocated size per plane. + virtual int allocated_size(PlaneType type) const; + + // Get allocated stride per plane. + virtual int stride(PlaneType type) const; + + // Set frame width. + virtual int set_width(int width); + + // Set frame height. + virtual int set_height(int height); + + // Get frame width. + virtual int width() const {return width_;} + + // Get frame height. + virtual int height() const {return height_;} + + // Set frame timestamp (90kHz). + virtual void set_timestamp(uint32_t timestamp) {timestamp_ = timestamp;} + + // Get frame timestamp (90kHz). + virtual uint32_t timestamp() const {return timestamp_;} + + // Set capture ntp time in miliseconds. + virtual void set_ntp_time_ms(int64_t ntp_time_ms) { + ntp_time_ms_ = ntp_time_ms; + } + + // Get capture ntp time in miliseconds. + virtual int64_t ntp_time_ms() const {return ntp_time_ms_;} + + // Set render time in miliseconds. + virtual void set_render_time_ms(int64_t render_time_ms) {render_time_ms_ = + render_time_ms;} + + // Get render time in miliseconds. + virtual int64_t render_time_ms() const {return render_time_ms_;} + + // Return true if underlying plane buffers are of zero size, false if not. + virtual bool IsZeroSize() const; + + // Reset underlying plane buffers sizes to 0. This function doesn't + // clear memory. + virtual void ResetSize(); + + // Return the handle of the underlying video frame. This is used when the + // frame is backed by a texture. The object should be destroyed when it is no + // longer in use, so the underlying resource can be freed. + virtual void* native_handle() const; + + protected: + // Verifies legality of parameters. + // Return value: 0 on success, -1 on error. + virtual int CheckDimensions(int width, int height, + int stride_y, int stride_u, int stride_v); + + private: + // Get the pointer to a specific plane. + const Plane* GetPlane(PlaneType type) const; + // Overloading with non-const. + Plane* GetPlane(PlaneType type); + + Plane y_plane_; + Plane u_plane_; + Plane v_plane_; + int width_; + int height_; + uint32_t timestamp_; + int64_t ntp_time_ms_; + int64_t render_time_ms_; +}; // I420VideoFrame + +} // namespace webrtc + +#endif // COMMON_VIDEO_INTERFACE_I420_VIDEO_FRAME_H diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/native_handle.h b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/native_handle.h new file mode 100644 index 0000000..d078d4c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/native_handle.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef COMMON_VIDEO_INTERFACE_NATIVEHANDLE_H_ +#define COMMON_VIDEO_INTERFACE_NATIVEHANDLE_H_ + +#include "webrtc/typedefs.h" + +namespace webrtc { + +// A class to store an opaque handle of the underlying video frame. This is used +// when the frame is backed by a texture. WebRTC carries the handle in +// TextureVideoFrame. This object keeps a reference to the handle. The reference +// is cleared when the object is destroyed. It is important to destroy the +// object as soon as possible so the texture can be recycled. +class NativeHandle { + public: + virtual ~NativeHandle() {} + // For scoped_refptr + virtual int32_t AddRef() = 0; + virtual int32_t Release() = 0; + + // Gets the handle. + virtual void* GetHandle() = 0; +}; + +} // namespace webrtc + +#endif // COMMON_VIDEO_INTERFACE_NATIVEHANDLE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/texture_video_frame.h b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/texture_video_frame.h new file mode 100644 index 0000000..e905ea7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/texture_video_frame.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef COMMON_VIDEO_INTERFACE_TEXTURE_VIDEO_FRAME_H +#define COMMON_VIDEO_INTERFACE_TEXTURE_VIDEO_FRAME_H + +// TextureVideoFrame class +// +// Storing and handling of video frames backed by textures. + +#include "webrtc/common_video/interface/i420_video_frame.h" +#include "webrtc/common_video/interface/native_handle.h" +#include "webrtc/system_wrappers/interface/scoped_refptr.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +class TextureVideoFrame : public I420VideoFrame { + public: + TextureVideoFrame(NativeHandle* handle, + int width, + int height, + uint32_t timestamp, + int64_t render_time_ms); + virtual ~TextureVideoFrame(); + + // I420VideoFrame implementation + virtual int CreateEmptyFrame(int width, + int height, + int stride_y, + int stride_u, + int stride_v) OVERRIDE; + virtual int CreateFrame(int size_y, + const uint8_t* buffer_y, + int size_u, + const uint8_t* buffer_u, + int size_v, + const uint8_t* buffer_v, + int width, + int height, + int stride_y, + int stride_u, + int stride_v) OVERRIDE; + virtual int CopyFrame(const I420VideoFrame& videoFrame) OVERRIDE; + virtual void SwapFrame(I420VideoFrame* videoFrame) OVERRIDE; + virtual uint8_t* buffer(PlaneType type) OVERRIDE; + virtual const uint8_t* buffer(PlaneType type) const OVERRIDE; + virtual int allocated_size(PlaneType type) const OVERRIDE; + virtual int stride(PlaneType type) const OVERRIDE; + virtual bool IsZeroSize() const OVERRIDE; + virtual void ResetSize() OVERRIDE; + virtual void* native_handle() const OVERRIDE; + + protected: + virtual int CheckDimensions( + int width, int height, int stride_y, int stride_u, int stride_v) OVERRIDE; + + private: + // An opaque handle that stores the underlying video frame. + scoped_refptr handle_; +}; + +} // namespace webrtc + +#endif // COMMON_VIDEO_INTERFACE_TEXTURE_VIDEO_FRAME_H diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/video_image.h b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/video_image.h new file mode 100644 index 0000000..c8df436 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/interface/video_image.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef COMMON_VIDEO_INTERFACE_VIDEO_IMAGE_H +#define COMMON_VIDEO_INTERFACE_VIDEO_IMAGE_H + +#include +#include "webrtc/typedefs.h" + +namespace webrtc +{ + +enum VideoFrameType +{ + kKeyFrame = 0, + kDeltaFrame = 1, + kGoldenFrame = 2, + kAltRefFrame = 3, + kSkipFrame = 4 +}; + +class EncodedImage +{ +public: + EncodedImage() + : _encodedWidth(0), + _encodedHeight(0), + _timeStamp(0), + capture_time_ms_(0), + _frameType(kDeltaFrame), + _buffer(NULL), + _length(0), + _size(0), + _completeFrame(false) {} + + EncodedImage(uint8_t* buffer, + uint32_t length, + uint32_t size) + : _encodedWidth(0), + _encodedHeight(0), + _timeStamp(0), + ntp_time_ms_(0), + capture_time_ms_(0), + _frameType(kDeltaFrame), + _buffer(buffer), + _length(length), + _size(size), + _completeFrame(false) {} + + uint32_t _encodedWidth; + uint32_t _encodedHeight; + uint32_t _timeStamp; + // NTP time of the capture time in local timebase in milliseconds. + int64_t ntp_time_ms_; + int64_t capture_time_ms_; + VideoFrameType _frameType; + uint8_t* _buffer; + uint32_t _length; + uint32_t _size; + bool _completeFrame; +}; + +} // namespace webrtc + +#endif // COMMON_VIDEO_INTERFACE_VIDEO_IMAGE_H diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/common_video/libyuv/include/scaler.h b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/libyuv/include/scaler.h new file mode 100644 index 0000000..ce7462c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/libyuv/include/scaler.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * Interface to the LibYuv scaling functionality + */ + +#ifndef WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_SCALER_H_ +#define WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_SCALER_H_ + +#include "webrtc/common_video/interface/i420_video_frame.h" +#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +// Supported scaling types +enum ScaleMethod { + kScalePoint, // no interpolation + kScaleBilinear, + kScaleBox +}; + +class Scaler { + public: + Scaler(); + ~Scaler(); + + // Set interpolation properties: + // + // Return value: 0 - OK + // -1 - parameter error + int Set(int src_width, int src_height, + int dst_width, int dst_height, + VideoType src_video_type, VideoType dst_video_type, + ScaleMethod method); + + // Scale frame + // Memory is allocated by user. If dst_frame is not of sufficient size, + // the frame will be reallocated to the appropriate size. + // Return value: 0 - OK, + // -1 - parameter error + // -2 - scaler not set + int Scale(const I420VideoFrame& src_frame, + I420VideoFrame* dst_frame); + + private: + // Determine if the VideoTypes are currently supported. + bool SupportedVideoType(VideoType src_video_type, + VideoType dst_video_type); + + ScaleMethod method_; + int src_width_; + int src_height_; + int dst_width_; + int dst_height_; + bool set_; +}; + +} // namespace webrtc + +#endif // WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_SCALER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/common_video/libyuv/include/webrtc_libyuv.h b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/libyuv/include/webrtc_libyuv.h new file mode 100644 index 0000000..70d8e2a --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/libyuv/include/webrtc_libyuv.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * WebRTC's wrapper to libyuv. + */ + +#ifndef WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_WEBRTC_LIBYUV_H_ +#define WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_WEBRTC_LIBYUV_H_ + +#include + +#include "webrtc/common_types.h" // RawVideoTypes. +#include "webrtc/common_video/interface/i420_video_frame.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +// Supported video types. +enum VideoType { + kUnknown, + kI420, + kIYUV, + kRGB24, + kABGR, + kARGB, + kARGB4444, + kRGB565, + kARGB1555, + kYUY2, + kYV12, + kUYVY, + kMJPG, + kNV21, + kNV12, + kBGRA, +}; + +// This is the max PSNR value our algorithms can return. +const double kPerfectPSNR = 48.0f; + +// Conversion between the RawVideoType and the LibYuv videoType. +// TODO(wu): Consolidate types into one type throughout WebRtc. +VideoType RawVideoTypeToCommonVideoVideoType(RawVideoType type); + +// Supported rotation +// Direction of rotation - clockwise. +enum VideoRotationMode { + kRotateNone = 0, + kRotate90 = 90, + kRotate180 = 180, + kRotate270 = 270, +}; + +// Align integer values. +// Input: +// - value : Input value to be aligned. +// - alignment : Alignment basis (power of 2). +// Return value: An aligned form of the input value. +int AlignInt(int value, int alignment); + +// Align stride values for I420 Video frames. +// Input: +// - width : Image width. +// - stride_y : Pointer to the stride of the y plane. +// - stride_uv: Pointer to the stride of the u and v planes (setting identical +// values for both). +// Setting 16 byte alignment. +void Calc16ByteAlignedStride(int width, int* stride_y, int* stride_uv); + +// Calculate the required buffer size. +// Input: +// - type :The type of the designated video frame. +// - width :frame width in pixels. +// - height :frame height in pixels. +// Return value: :The required size in bytes to accommodate the specified +// video frame or -1 in case of an error . +int CalcBufferSize(VideoType type, int width, int height); + +// TODO(mikhal): Add unit test for these two functions and determine location. +// Print I420VideoFrame to file +// Input: +// - frame : Reference to video frame. +// - file : pointer to file object. It is assumed that the file is +// already open for writing. +// Return value: 0 if OK, < 0 otherwise. +int PrintI420VideoFrame(const I420VideoFrame& frame, FILE* file); + +// Extract buffer from I420VideoFrame (consecutive planes, no stride) +// Input: +// - frame : Reference to video frame. +// - size : pointer to the size of the allocated buffer. If size is +// insufficient, an error will be returned. +// - buffer : Pointer to buffer +// Return value: length of buffer if OK, < 0 otherwise. +int ExtractBuffer(const I420VideoFrame& input_frame, + int size, uint8_t* buffer); +// Convert To I420 +// Input: +// - src_video_type : Type of input video. +// - src_frame : Pointer to a source frame. +// - crop_x/crop_y : Starting positions for cropping (0 for no crop). +// - src_width : src width in pixels. +// - src_height : src height in pixels. +// - sample_size : Required only for the parsing of MJPG (set to 0 else). +// - rotate : Rotation mode of output image. +// Output: +// - dst_frame : Reference to a destination frame. +// Return value: 0 if OK, < 0 otherwise. + +int ConvertToI420(VideoType src_video_type, + const uint8_t* src_frame, + int crop_x, int crop_y, + int src_width, int src_height, + int sample_size, + VideoRotationMode rotation, + I420VideoFrame* dst_frame); + +// Convert From I420 +// Input: +// - src_frame : Reference to a source frame. +// - dst_video_type : Type of output video. +// - dst_sample_size : Required only for the parsing of MJPG. +// - dst_frame : Pointer to a destination frame. +// Return value: 0 if OK, < 0 otherwise. +// It is assumed that source and destination have equal height. +int ConvertFromI420(const I420VideoFrame& src_frame, + VideoType dst_video_type, int dst_sample_size, + uint8_t* dst_frame); +// ConvertFrom YV12. +// Interface - same as above. +int ConvertFromYV12(const I420VideoFrame& src_frame, + VideoType dst_video_type, int dst_sample_size, + uint8_t* dst_frame); + +// The following list describes designated conversion functions which +// are not covered by the previous general functions. +// Input and output descriptions mostly match the above descriptions, and are +// therefore omitted. +int ConvertRGB24ToARGB(const uint8_t* src_frame, + uint8_t* dst_frame, + int width, int height, + int dst_stride); +int ConvertNV12ToRGB565(const uint8_t* src_frame, + uint8_t* dst_frame, + int width, int height); + +// Mirror functions +// The following 2 functions perform mirroring on a given image +// (LeftRight/UpDown). +// Input: +// - src_frame : Pointer to a source frame. +// - dst_frame : Pointer to a destination frame. +// Return value: 0 if OK, < 0 otherwise. +// It is assumed that src and dst frames have equal dimensions. +int MirrorI420LeftRight(const I420VideoFrame* src_frame, + I420VideoFrame* dst_frame); +int MirrorI420UpDown(const I420VideoFrame* src_frame, + I420VideoFrame* dst_frame); + +// Compute PSNR for an I420 frame (all planes). +// Returns the PSNR in decibel, to a maximum of kInfinitePSNR. +double I420PSNR(const I420VideoFrame* ref_frame, + const I420VideoFrame* test_frame); +// Compute SSIM for an I420 frame (all planes). +double I420SSIM(const I420VideoFrame* ref_frame, + const I420VideoFrame* test_frame); +} + +#endif // WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_WEBRTC_LIBYUV_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/common_video/plane.h b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/plane.h new file mode 100644 index 0000000..4031e03 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/common_video/plane.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef COMMON_VIDEO_PLANE_H +#define COMMON_VIDEO_PLANE_H + +#include "webrtc/system_wrappers/interface/aligned_malloc.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +// Helper class for I420VideoFrame: Store plane data and perform basic plane +// operations. +class Plane { + public: + Plane(); + ~Plane(); + // CreateEmptyPlane - set allocated size, actual plane size and stride: + // If current size is smaller than current size, then a buffer of sufficient + // size will be allocated. + // Return value: 0 on success ,-1 on error. + int CreateEmptyPlane(int allocated_size, int stride, int plane_size); + + // Copy the entire plane data. + // Return value: 0 on success ,-1 on error. + int Copy(const Plane& plane); + + // Copy buffer: If current size is smaller + // than current size, then a buffer of sufficient size will be allocated. + // Return value: 0 on success ,-1 on error. + int Copy(int size, int stride, const uint8_t* buffer); + + // Swap plane data. + void Swap(Plane& plane); + + // Get allocated size. + int allocated_size() const {return allocated_size_;} + + // Set actual size. + void ResetSize() {plane_size_ = 0;} + + // Return true is plane size is zero, false if not. + bool IsZeroSize() const {return plane_size_ == 0;} + + // Get stride value. + int stride() const {return stride_;} + + // Return data pointer. + const uint8_t* buffer() const {return buffer_.get();} + // Overloading with non-const. + uint8_t* buffer() {return buffer_.get();} + + private: + // Resize when needed: If current allocated size is less than new_size, buffer + // will be updated. Old data will be copied to new buffer. + // Return value: 0 on success ,-1 on error. + int MaybeResize(int new_size); + + scoped_ptr buffer_; + int allocated_size_; + int plane_size_; + int stride_; +}; // Plane + +} // namespace webrtc + +#endif // COMMON_VIDEO_PLANE_H diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/modules/interface/module.h b/thirdparties/common/include/webrtc-sdk/webrtc/modules/interface/module.h new file mode 100644 index 0000000..c177fd1 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/modules/interface/module.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_INTERFACE_MODULE_H_ +#define MODULES_INTERFACE_MODULE_H_ + +#include + +#include "webrtc/typedefs.h" + +namespace webrtc { + +class Module { + public: + // TODO(henrika): Remove this when chrome is updated. + // DEPRICATED Change the unique identifier of this object. + virtual int32_t ChangeUniqueId(const int32_t id) { return 0; } + + // Returns the number of milliseconds until the module want a worker + // thread to call Process. + virtual int32_t TimeUntilNextProcess() = 0; + + // Process any pending tasks such as timeouts. + virtual int32_t Process() = 0; + + protected: + virtual ~Module() {} +}; + +// Reference counted version of the module interface. +class RefCountedModule : public Module { + public: + // Increase the reference count by one. + // Returns the incremented reference count. + // TODO(perkj): Make this pure virtual when Chromium have implemented + // reference counting ADM and Video capture module. + virtual int32_t AddRef() { + assert(false && "Not implemented."); + return 1; + } + + // Decrease the reference count by one. + // Returns the decreased reference count. + // Returns 0 if the last reference was just released. + // When the reference count reach 0 the object will self-destruct. + // TODO(perkj): Make this pure virtual when Chromium have implemented + // reference counting ADM and Video capture module. + virtual int32_t Release() { + assert(false && "Not implemented."); + return 1; + } + + protected: + virtual ~RefCountedModule() {} +}; + +} // namespace webrtc + +#endif // MODULES_INTERFACE_MODULE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/modules/interface/module_common_types.h b/thirdparties/common/include/webrtc-sdk/webrtc/modules/interface/module_common_types.h new file mode 100644 index 0000000..14139ad --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/modules/interface/module_common_types.h @@ -0,0 +1,902 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULE_COMMON_TYPES_H +#define MODULE_COMMON_TYPES_H + +#include +#include // memcpy + +#include + +#include "webrtc/base/constructormagic.h" +#include "webrtc/common_types.h" +#include "webrtc/typedefs.h" + +#ifdef _WIN32 +// Remove warning "new behavior: elements of array will be default initialized". +#pragma warning(disable : 4351) +#endif + +namespace webrtc { + +struct RTPAudioHeader { + uint8_t numEnergy; // number of valid entries in arrOfEnergy + uint8_t arrOfEnergy[kRtpCsrcSize]; // one energy byte (0-9) per channel + bool isCNG; // is this CNG + uint8_t channel; // number of channels 2 = stereo +}; + +enum { + kNoPictureId = -1 +}; +enum { + kNoTl0PicIdx = -1 +}; +enum { + kNoTemporalIdx = -1 +}; +enum { + kNoKeyIdx = -1 +}; +enum { + kNoSimulcastIdx = 0 +}; + +struct RTPVideoHeaderVP8 { + void InitRTPVideoHeaderVP8() { + nonReference = false; + pictureId = kNoPictureId; + tl0PicIdx = kNoTl0PicIdx; + temporalIdx = kNoTemporalIdx; + layerSync = false; + keyIdx = kNoKeyIdx; + partitionId = 0; + beginningOfPartition = false; + } + + bool nonReference; // Frame is discardable. + int16_t pictureId; // Picture ID index, 15 bits; + // kNoPictureId if PictureID does not exist. + int16_t tl0PicIdx; // TL0PIC_IDX, 8 bits; + // kNoTl0PicIdx means no value provided. + int8_t temporalIdx; // Temporal layer index, or kNoTemporalIdx. + bool layerSync; // This frame is a layer sync frame. + // Disabled if temporalIdx == kNoTemporalIdx. + int keyIdx; // 5 bits; kNoKeyIdx means not used. + int partitionId; // VP8 partition ID + bool beginningOfPartition; // True if this packet is the first + // in a VP8 partition. Otherwise false +}; +union RTPVideoTypeHeader { + RTPVideoHeaderVP8 VP8; +}; + +enum RtpVideoCodecTypes { + kRtpVideoNone, + kRtpVideoGeneric, + kRtpVideoVp8 +}; +struct RTPVideoHeader { + uint16_t width; // size + uint16_t height; + + bool isFirstPacket; // first packet in frame + uint8_t simulcastIdx; // Index if the simulcast encoder creating + // this frame, 0 if not using simulcast. + RtpVideoCodecTypes codec; + RTPVideoTypeHeader codecHeader; +}; +union RTPTypeHeader { + RTPAudioHeader Audio; + RTPVideoHeader Video; +}; + +struct WebRtcRTPHeader { + RTPHeader header; + FrameType frameType; + RTPTypeHeader type; + // NTP time of the capture time in local timebase in milliseconds. + int64_t ntp_time_ms; +}; + +class RTPFragmentationHeader { + public: + RTPFragmentationHeader() + : fragmentationVectorSize(0), + fragmentationOffset(NULL), + fragmentationLength(NULL), + fragmentationTimeDiff(NULL), + fragmentationPlType(NULL) {}; + + ~RTPFragmentationHeader() { + delete[] fragmentationOffset; + delete[] fragmentationLength; + delete[] fragmentationTimeDiff; + delete[] fragmentationPlType; + } + + void CopyFrom(const RTPFragmentationHeader& src) { + if (this == &src) { + return; + } + + if (src.fragmentationVectorSize != fragmentationVectorSize) { + // new size of vectors + + // delete old + delete[] fragmentationOffset; + fragmentationOffset = NULL; + delete[] fragmentationLength; + fragmentationLength = NULL; + delete[] fragmentationTimeDiff; + fragmentationTimeDiff = NULL; + delete[] fragmentationPlType; + fragmentationPlType = NULL; + + if (src.fragmentationVectorSize > 0) { + // allocate new + if (src.fragmentationOffset) { + fragmentationOffset = new uint32_t[src.fragmentationVectorSize]; + } + if (src.fragmentationLength) { + fragmentationLength = new uint32_t[src.fragmentationVectorSize]; + } + if (src.fragmentationTimeDiff) { + fragmentationTimeDiff = new uint16_t[src.fragmentationVectorSize]; + } + if (src.fragmentationPlType) { + fragmentationPlType = new uint8_t[src.fragmentationVectorSize]; + } + } + // set new size + fragmentationVectorSize = src.fragmentationVectorSize; + } + + if (src.fragmentationVectorSize > 0) { + // copy values + if (src.fragmentationOffset) { + memcpy(fragmentationOffset, src.fragmentationOffset, + src.fragmentationVectorSize * sizeof(uint32_t)); + } + if (src.fragmentationLength) { + memcpy(fragmentationLength, src.fragmentationLength, + src.fragmentationVectorSize * sizeof(uint32_t)); + } + if (src.fragmentationTimeDiff) { + memcpy(fragmentationTimeDiff, src.fragmentationTimeDiff, + src.fragmentationVectorSize * sizeof(uint16_t)); + } + if (src.fragmentationPlType) { + memcpy(fragmentationPlType, src.fragmentationPlType, + src.fragmentationVectorSize * sizeof(uint8_t)); + } + } + } + + void VerifyAndAllocateFragmentationHeader(const uint16_t size) { + if (fragmentationVectorSize < size) { + uint16_t oldVectorSize = fragmentationVectorSize; + { + // offset + uint32_t* oldOffsets = fragmentationOffset; + fragmentationOffset = new uint32_t[size]; + memset(fragmentationOffset + oldVectorSize, 0, + sizeof(uint32_t) * (size - oldVectorSize)); + // copy old values + memcpy(fragmentationOffset, oldOffsets, + sizeof(uint32_t) * oldVectorSize); + delete[] oldOffsets; + } + // length + { + uint32_t* oldLengths = fragmentationLength; + fragmentationLength = new uint32_t[size]; + memset(fragmentationLength + oldVectorSize, 0, + sizeof(uint32_t) * (size - oldVectorSize)); + memcpy(fragmentationLength, oldLengths, + sizeof(uint32_t) * oldVectorSize); + delete[] oldLengths; + } + // time diff + { + uint16_t* oldTimeDiffs = fragmentationTimeDiff; + fragmentationTimeDiff = new uint16_t[size]; + memset(fragmentationTimeDiff + oldVectorSize, 0, + sizeof(uint16_t) * (size - oldVectorSize)); + memcpy(fragmentationTimeDiff, oldTimeDiffs, + sizeof(uint16_t) * oldVectorSize); + delete[] oldTimeDiffs; + } + // payload type + { + uint8_t* oldTimePlTypes = fragmentationPlType; + fragmentationPlType = new uint8_t[size]; + memset(fragmentationPlType + oldVectorSize, 0, + sizeof(uint8_t) * (size - oldVectorSize)); + memcpy(fragmentationPlType, oldTimePlTypes, + sizeof(uint8_t) * oldVectorSize); + delete[] oldTimePlTypes; + } + fragmentationVectorSize = size; + } + } + + uint16_t fragmentationVectorSize; // Number of fragmentations + uint32_t* fragmentationOffset; // Offset of pointer to data for each fragm. + uint32_t* fragmentationLength; // Data size for each fragmentation + uint16_t* fragmentationTimeDiff; // Timestamp difference relative "now" for + // each fragmentation + uint8_t* fragmentationPlType; // Payload type of each fragmentation + + private: + DISALLOW_COPY_AND_ASSIGN(RTPFragmentationHeader); +}; + +struct RTCPVoIPMetric { + // RFC 3611 4.7 + uint8_t lossRate; + uint8_t discardRate; + uint8_t burstDensity; + uint8_t gapDensity; + uint16_t burstDuration; + uint16_t gapDuration; + uint16_t roundTripDelay; + uint16_t endSystemDelay; + uint8_t signalLevel; + uint8_t noiseLevel; + uint8_t RERL; + uint8_t Gmin; + uint8_t Rfactor; + uint8_t extRfactor; + uint8_t MOSLQ; + uint8_t MOSCQ; + uint8_t RXconfig; + uint16_t JBnominal; + uint16_t JBmax; + uint16_t JBabsMax; +}; + +// Types for the FEC packet masks. The type |kFecMaskRandom| is based on a +// random loss model. The type |kFecMaskBursty| is based on a bursty/consecutive +// loss model. The packet masks are defined in +// modules/rtp_rtcp/fec_private_tables_random(bursty).h +enum FecMaskType { + kFecMaskRandom, + kFecMaskBursty, +}; + +// Struct containing forward error correction settings. +struct FecProtectionParams { + int fec_rate; + bool use_uep_protection; + int max_fec_frames; + FecMaskType fec_mask_type; +}; + +// Interface used by the CallStats class to distribute call statistics. +// Callbacks will be triggered as soon as the class has been registered to a +// CallStats object using RegisterStatsObserver. +class CallStatsObserver { + public: + virtual void OnRttUpdate(uint32_t rtt_ms) = 0; + + virtual ~CallStatsObserver() {} +}; + +// class describing a complete, or parts of an encoded frame. +class EncodedVideoData { + public: + EncodedVideoData() + : payloadType(0), + timeStamp(0), + renderTimeMs(0), + encodedWidth(0), + encodedHeight(0), + completeFrame(false), + missingFrame(false), + payloadData(NULL), + payloadSize(0), + bufferSize(0), + fragmentationHeader(), + frameType(kVideoFrameDelta), + codec(kVideoCodecUnknown) {}; + + EncodedVideoData(const EncodedVideoData& data) { + payloadType = data.payloadType; + timeStamp = data.timeStamp; + renderTimeMs = data.renderTimeMs; + encodedWidth = data.encodedWidth; + encodedHeight = data.encodedHeight; + completeFrame = data.completeFrame; + missingFrame = data.missingFrame; + payloadSize = data.payloadSize; + fragmentationHeader.CopyFrom(data.fragmentationHeader); + frameType = data.frameType; + codec = data.codec; + if (data.payloadSize > 0) { + payloadData = new uint8_t[data.payloadSize]; + memcpy(payloadData, data.payloadData, data.payloadSize); + } else { + payloadData = NULL; + } + } + + ~EncodedVideoData() { + delete[] payloadData; + }; + + EncodedVideoData& operator=(const EncodedVideoData& data) { + if (this == &data) { + return *this; + } + payloadType = data.payloadType; + timeStamp = data.timeStamp; + renderTimeMs = data.renderTimeMs; + encodedWidth = data.encodedWidth; + encodedHeight = data.encodedHeight; + completeFrame = data.completeFrame; + missingFrame = data.missingFrame; + payloadSize = data.payloadSize; + fragmentationHeader.CopyFrom(data.fragmentationHeader); + frameType = data.frameType; + codec = data.codec; + if (data.payloadSize > 0) { + delete[] payloadData; + payloadData = new uint8_t[data.payloadSize]; + memcpy(payloadData, data.payloadData, data.payloadSize); + bufferSize = data.payloadSize; + } + return *this; + }; + void VerifyAndAllocate(const uint32_t size) { + if (bufferSize < size) { + uint8_t* oldPayload = payloadData; + payloadData = new uint8_t[size]; + memcpy(payloadData, oldPayload, sizeof(uint8_t) * payloadSize); + + bufferSize = size; + delete[] oldPayload; + } + } + + uint8_t payloadType; + uint32_t timeStamp; + int64_t renderTimeMs; + uint32_t encodedWidth; + uint32_t encodedHeight; + bool completeFrame; + bool missingFrame; + uint8_t* payloadData; + uint32_t payloadSize; + uint32_t bufferSize; + RTPFragmentationHeader fragmentationHeader; + FrameType frameType; + VideoCodecType codec; +}; + +struct VideoContentMetrics { + VideoContentMetrics() + : motion_magnitude(0.0f), + spatial_pred_err(0.0f), + spatial_pred_err_h(0.0f), + spatial_pred_err_v(0.0f) {} + + void Reset() { + motion_magnitude = 0.0f; + spatial_pred_err = 0.0f; + spatial_pred_err_h = 0.0f; + spatial_pred_err_v = 0.0f; + } + float motion_magnitude; + float spatial_pred_err; + float spatial_pred_err_h; + float spatial_pred_err_v; +}; + +/************************************************* + * + * VideoFrame class + * + * The VideoFrame class allows storing and + * handling of video frames. + * + * + *************************************************/ +class VideoFrame { + public: + VideoFrame(); + ~VideoFrame(); + /** + * Verifies that current allocated buffer size is larger than or equal to the + * input size. + * If the current buffer size is smaller, a new allocation is made and the old + * buffer data + * is copied to the new buffer. + * Buffer size is updated to minimumSize. + */ + int32_t VerifyAndAllocate(const uint32_t minimumSize); + /** + * Update length of data buffer in frame. Function verifies that new length + * is less or + * equal to allocated size. + */ + int32_t SetLength(const uint32_t newLength); + /* + * Swap buffer and size data + */ + int32_t Swap(uint8_t*& newMemory, uint32_t& newLength, uint32_t& newSize); + /* + * Swap buffer and size data + */ + int32_t SwapFrame(VideoFrame& videoFrame); + /** + * Copy buffer: If newLength is bigger than allocated size, a new buffer of + * size length + * is allocated. + */ + int32_t CopyFrame(const VideoFrame& videoFrame); + /** + * Copy buffer: If newLength is bigger than allocated size, a new buffer of + * size length + * is allocated. + */ + int32_t CopyFrame(uint32_t length, const uint8_t* sourceBuffer); + /** + * Delete VideoFrame and resets members to zero + */ + void Free(); + /** + * Set frame timestamp (90kHz) + */ + void SetTimeStamp(const uint32_t timeStamp) { _timeStamp = timeStamp; } + /** + * Get pointer to frame buffer + */ + uint8_t* Buffer() const { return _buffer; } + + uint8_t*& Buffer() { return _buffer; } + + /** + * Get allocated buffer size + */ + uint32_t Size() const { return _bufferSize; } + /** + * Get frame length + */ + uint32_t Length() const { return _bufferLength; } + /** + * Get frame timestamp (90kHz) + */ + uint32_t TimeStamp() const { return _timeStamp; } + /** + * Get frame width + */ + uint32_t Width() const { return _width; } + /** + * Get frame height + */ + uint32_t Height() const { return _height; } + /** + * Set frame width + */ + void SetWidth(const uint32_t width) { _width = width; } + /** + * Set frame height + */ + void SetHeight(const uint32_t height) { _height = height; } + /** + * Set render time in miliseconds + */ + void SetRenderTime(const int64_t renderTimeMs) { + _renderTimeMs = renderTimeMs; + } + /** + * Get render time in miliseconds + */ + int64_t RenderTimeMs() const { return _renderTimeMs; } + + private: + void Set(uint8_t* buffer, uint32_t size, uint32_t length, uint32_t timeStamp); + + uint8_t* _buffer; // Pointer to frame buffer + uint32_t _bufferSize; // Allocated buffer size + uint32_t _bufferLength; // Length (in bytes) of buffer + uint32_t _timeStamp; // Timestamp of frame (90kHz) + uint32_t _width; + uint32_t _height; + int64_t _renderTimeMs; +}; // end of VideoFrame class declaration + +// inline implementation of VideoFrame class: +inline VideoFrame::VideoFrame() + : _buffer(0), + _bufferSize(0), + _bufferLength(0), + _timeStamp(0), + _width(0), + _height(0), + _renderTimeMs(0) { + // +} +inline VideoFrame::~VideoFrame() { + if (_buffer) { + delete[] _buffer; + _buffer = NULL; + } +} + +inline int32_t VideoFrame::VerifyAndAllocate(const uint32_t minimumSize) { + if (minimumSize < 1) { + return -1; + } + if (minimumSize > _bufferSize) { + // create buffer of sufficient size + uint8_t* newBufferBuffer = new uint8_t[minimumSize]; + if (_buffer) { + // copy old data + memcpy(newBufferBuffer, _buffer, _bufferSize); + delete[] _buffer; + } else { + memset(newBufferBuffer, 0, minimumSize * sizeof(uint8_t)); + } + _buffer = newBufferBuffer; + _bufferSize = minimumSize; + } + return 0; +} + +inline int32_t VideoFrame::SetLength(const uint32_t newLength) { + if (newLength > _bufferSize) { // can't accomodate new value + return -1; + } + _bufferLength = newLength; + return 0; +} + +inline int32_t VideoFrame::SwapFrame(VideoFrame& videoFrame) { + uint32_t tmpTimeStamp = _timeStamp; + uint32_t tmpWidth = _width; + uint32_t tmpHeight = _height; + int64_t tmpRenderTime = _renderTimeMs; + + _timeStamp = videoFrame._timeStamp; + _width = videoFrame._width; + _height = videoFrame._height; + _renderTimeMs = videoFrame._renderTimeMs; + + videoFrame._timeStamp = tmpTimeStamp; + videoFrame._width = tmpWidth; + videoFrame._height = tmpHeight; + videoFrame._renderTimeMs = tmpRenderTime; + + return Swap(videoFrame._buffer, videoFrame._bufferLength, + videoFrame._bufferSize); +} + +inline int32_t VideoFrame::Swap(uint8_t*& newMemory, uint32_t& newLength, + uint32_t& newSize) { + uint8_t* tmpBuffer = _buffer; + uint32_t tmpLength = _bufferLength; + uint32_t tmpSize = _bufferSize; + _buffer = newMemory; + _bufferLength = newLength; + _bufferSize = newSize; + newMemory = tmpBuffer; + newLength = tmpLength; + newSize = tmpSize; + return 0; +} + +inline int32_t VideoFrame::CopyFrame(uint32_t length, + const uint8_t* sourceBuffer) { + if (length > _bufferSize) { + int32_t ret = VerifyAndAllocate(length); + if (ret < 0) { + return ret; + } + } + memcpy(_buffer, sourceBuffer, length); + _bufferLength = length; + return 0; +} + +inline int32_t VideoFrame::CopyFrame(const VideoFrame& videoFrame) { + if (CopyFrame(videoFrame.Length(), videoFrame.Buffer()) != 0) { + return -1; + } + _timeStamp = videoFrame._timeStamp; + _width = videoFrame._width; + _height = videoFrame._height; + _renderTimeMs = videoFrame._renderTimeMs; + return 0; +} + +inline void VideoFrame::Free() { + _timeStamp = 0; + _bufferLength = 0; + _bufferSize = 0; + _height = 0; + _width = 0; + _renderTimeMs = 0; + + if (_buffer) { + delete[] _buffer; + _buffer = NULL; + } +} + +/* This class holds up to 60 ms of super-wideband (32 kHz) stereo audio. It + * allows for adding and subtracting frames while keeping track of the resulting + * states. + * + * Notes + * - The total number of samples in |data_| is + * samples_per_channel_ * num_channels_ + * + * - Stereo data is interleaved starting with the left channel. + * + * - The +operator assume that you would never add exactly opposite frames when + * deciding the resulting state. To do this use the -operator. + */ +class AudioFrame { + public: + // Stereo, 32 kHz, 60 ms (2 * 32 * 60) + static const int kMaxDataSizeSamples = 3840; + + enum VADActivity { + kVadActive = 0, + kVadPassive = 1, + kVadUnknown = 2 + }; + enum SpeechType { + kNormalSpeech = 0, + kPLC = 1, + kCNG = 2, + kPLCCNG = 3, + kUndefined = 4 + }; + + AudioFrame(); + virtual ~AudioFrame() {} + + // |interleaved_| is not changed by this method. + void UpdateFrame(int id, uint32_t timestamp, const int16_t* data, + int samples_per_channel, int sample_rate_hz, + SpeechType speech_type, VADActivity vad_activity, + int num_channels = 1, uint32_t energy = -1); + + AudioFrame& Append(const AudioFrame& rhs); + + void CopyFrom(const AudioFrame& src); + + void Mute(); + + AudioFrame& operator>>=(const int rhs); + AudioFrame& operator+=(const AudioFrame& rhs); + AudioFrame& operator-=(const AudioFrame& rhs); + + int id_; + // RTP timestamp of the first sample in the AudioFrame. + uint32_t timestamp_; + // NTP time of the estimated capture time in local timebase in milliseconds. + int64_t ntp_time_ms_; + int16_t data_[kMaxDataSizeSamples]; + int samples_per_channel_; + int sample_rate_hz_; + int num_channels_; + SpeechType speech_type_; + VADActivity vad_activity_; + // Note that there is no guarantee that |energy_| is correct. Any user of this + // member must verify that the value is correct. + // TODO(henrike) Remove |energy_|. + // See https://code.google.com/p/webrtc/issues/detail?id=3315. + uint32_t energy_; + bool interleaved_; + + private: + DISALLOW_COPY_AND_ASSIGN(AudioFrame); +}; + +inline AudioFrame::AudioFrame() + : id_(-1), + timestamp_(0), + ntp_time_ms_(0), + data_(), + samples_per_channel_(0), + sample_rate_hz_(0), + num_channels_(1), + speech_type_(kUndefined), + vad_activity_(kVadUnknown), + energy_(0xffffffff), + interleaved_(true) {} + +inline void AudioFrame::UpdateFrame(int id, uint32_t timestamp, + const int16_t* data, + int samples_per_channel, int sample_rate_hz, + SpeechType speech_type, + VADActivity vad_activity, int num_channels, + uint32_t energy) { + id_ = id; + timestamp_ = timestamp; + samples_per_channel_ = samples_per_channel; + sample_rate_hz_ = sample_rate_hz; + speech_type_ = speech_type; + vad_activity_ = vad_activity; + num_channels_ = num_channels; + energy_ = energy; + + const int length = samples_per_channel * num_channels; + assert(length <= kMaxDataSizeSamples && length >= 0); + if (data != NULL) { + memcpy(data_, data, sizeof(int16_t) * length); + } else { + memset(data_, 0, sizeof(int16_t) * length); + } +} + +inline void AudioFrame::CopyFrom(const AudioFrame& src) { + if (this == &src) return; + + id_ = src.id_; + timestamp_ = src.timestamp_; + samples_per_channel_ = src.samples_per_channel_; + sample_rate_hz_ = src.sample_rate_hz_; + speech_type_ = src.speech_type_; + vad_activity_ = src.vad_activity_; + num_channels_ = src.num_channels_; + energy_ = src.energy_; + interleaved_ = src.interleaved_; + + const int length = samples_per_channel_ * num_channels_; + assert(length <= kMaxDataSizeSamples && length >= 0); + memcpy(data_, src.data_, sizeof(int16_t) * length); +} + +inline void AudioFrame::Mute() { + memset(data_, 0, samples_per_channel_ * num_channels_ * sizeof(int16_t)); +} + +inline AudioFrame& AudioFrame::operator>>=(const int rhs) { + assert((num_channels_ > 0) && (num_channels_ < 3)); + if ((num_channels_ > 2) || (num_channels_ < 1)) return *this; + + for (int i = 0; i < samples_per_channel_ * num_channels_; i++) { + data_[i] = static_cast(data_[i] >> rhs); + } + return *this; +} + +inline AudioFrame& AudioFrame::Append(const AudioFrame& rhs) { + // Sanity check + assert((num_channels_ > 0) && (num_channels_ < 3)); + assert(interleaved_ == rhs.interleaved_); + if ((num_channels_ > 2) || (num_channels_ < 1)) return *this; + if (num_channels_ != rhs.num_channels_) return *this; + + if ((vad_activity_ == kVadActive) || rhs.vad_activity_ == kVadActive) { + vad_activity_ = kVadActive; + } else if (vad_activity_ == kVadUnknown || rhs.vad_activity_ == kVadUnknown) { + vad_activity_ = kVadUnknown; + } + if (speech_type_ != rhs.speech_type_) { + speech_type_ = kUndefined; + } + + int offset = samples_per_channel_ * num_channels_; + for (int i = 0; i < rhs.samples_per_channel_ * rhs.num_channels_; i++) { + data_[offset + i] = rhs.data_[i]; + } + samples_per_channel_ += rhs.samples_per_channel_; + return *this; +} + +inline AudioFrame& AudioFrame::operator+=(const AudioFrame& rhs) { + // Sanity check + assert((num_channels_ > 0) && (num_channels_ < 3)); + assert(interleaved_ == rhs.interleaved_); + if ((num_channels_ > 2) || (num_channels_ < 1)) return *this; + if (num_channels_ != rhs.num_channels_) return *this; + + bool noPrevData = false; + if (samples_per_channel_ != rhs.samples_per_channel_) { + if (samples_per_channel_ == 0) { + // special case we have no data to start with + samples_per_channel_ = rhs.samples_per_channel_; + noPrevData = true; + } else { + return *this; + } + } + + if ((vad_activity_ == kVadActive) || rhs.vad_activity_ == kVadActive) { + vad_activity_ = kVadActive; + } else if (vad_activity_ == kVadUnknown || rhs.vad_activity_ == kVadUnknown) { + vad_activity_ = kVadUnknown; + } + + if (speech_type_ != rhs.speech_type_) speech_type_ = kUndefined; + + if (noPrevData) { + memcpy(data_, rhs.data_, + sizeof(int16_t) * rhs.samples_per_channel_ * num_channels_); + } else { + // IMPROVEMENT this can be done very fast in assembly + for (int i = 0; i < samples_per_channel_ * num_channels_; i++) { + int32_t wrapGuard = + static_cast(data_[i]) + static_cast(rhs.data_[i]); + if (wrapGuard < -32768) { + data_[i] = -32768; + } else if (wrapGuard > 32767) { + data_[i] = 32767; + } else { + data_[i] = (int16_t)wrapGuard; + } + } + } + energy_ = 0xffffffff; + return *this; +} + +inline AudioFrame& AudioFrame::operator-=(const AudioFrame& rhs) { + // Sanity check + assert((num_channels_ > 0) && (num_channels_ < 3)); + assert(interleaved_ == rhs.interleaved_); + if ((num_channels_ > 2) || (num_channels_ < 1)) return *this; + + if ((samples_per_channel_ != rhs.samples_per_channel_) || + (num_channels_ != rhs.num_channels_)) { + return *this; + } + if ((vad_activity_ != kVadPassive) || rhs.vad_activity_ != kVadPassive) { + vad_activity_ = kVadUnknown; + } + speech_type_ = kUndefined; + + for (int i = 0; i < samples_per_channel_ * num_channels_; i++) { + int32_t wrapGuard = + static_cast(data_[i]) - static_cast(rhs.data_[i]); + if (wrapGuard < -32768) { + data_[i] = -32768; + } else if (wrapGuard > 32767) { + data_[i] = 32767; + } else { + data_[i] = (int16_t)wrapGuard; + } + } + energy_ = 0xffffffff; + return *this; +} + +inline bool IsNewerSequenceNumber(uint16_t sequence_number, + uint16_t prev_sequence_number) { + return sequence_number != prev_sequence_number && + static_cast(sequence_number - prev_sequence_number) < 0x8000; +} + +inline bool IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) { + return timestamp != prev_timestamp && + static_cast(timestamp - prev_timestamp) < 0x80000000; +} + +inline uint16_t LatestSequenceNumber(uint16_t sequence_number1, + uint16_t sequence_number2) { + return IsNewerSequenceNumber(sequence_number1, sequence_number2) + ? sequence_number1 + : sequence_number2; +} + +inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) { + return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2; +} + +} // namespace webrtc + +#endif // MODULE_COMMON_TYPES_H diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture.h b/thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture.h new file mode 100644 index 0000000..6966c23 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_INCLUDE_VIDEO_CAPTURE_H_ +#define WEBRTC_MODULES_VIDEO_CAPTURE_INCLUDE_VIDEO_CAPTURE_H_ + +#include "webrtc/modules/interface/module.h" +#include "webrtc/modules/video_capture/include/video_capture_defines.h" + +#ifdef ANDROID +#include +#endif + +namespace webrtc { + +#if defined(ANDROID) +int32_t SetCaptureAndroidVM(JavaVM* javaVM); +#endif + +class VideoCaptureModule: public RefCountedModule { + public: + // Interface for receiving information about available camera devices. + class DeviceInfo { + public: + virtual uint32_t NumberOfDevices() = 0; + + // Returns the available capture devices. + // deviceNumber - Index of capture device. + // deviceNameUTF8 - Friendly name of the capture device. + // deviceUniqueIdUTF8 - Unique name of the capture device if it exist. + // Otherwise same as deviceNameUTF8. + // productUniqueIdUTF8 - Unique product id if it exist. + // Null terminated otherwise. + virtual int32_t GetDeviceName( + uint32_t deviceNumber, + char* deviceNameUTF8, + uint32_t deviceNameLength, + char* deviceUniqueIdUTF8, + uint32_t deviceUniqueIdUTF8Length, + char* productUniqueIdUTF8 = 0, + uint32_t productUniqueIdUTF8Length = 0) = 0; + + + // Returns the number of capabilities this device. + virtual int32_t NumberOfCapabilities( + const char* deviceUniqueIdUTF8) = 0; + + // Gets the capabilities of the named device. + virtual int32_t GetCapability( + const char* deviceUniqueIdUTF8, + const uint32_t deviceCapabilityNumber, + VideoCaptureCapability& capability) = 0; + + // Gets clockwise angle the captured frames should be rotated in order + // to be displayed correctly on a normally rotated display. + virtual int32_t GetOrientation( + const char* deviceUniqueIdUTF8, + VideoCaptureRotation& orientation) = 0; + + // Gets the capability that best matches the requested width, height and + // frame rate. + // Returns the deviceCapabilityNumber on success. + virtual int32_t GetBestMatchedCapability( + const char* deviceUniqueIdUTF8, + const VideoCaptureCapability& requested, + VideoCaptureCapability& resulting) = 0; + + // Display OS /capture device specific settings dialog + virtual int32_t DisplayCaptureSettingsDialogBox( + const char* deviceUniqueIdUTF8, + const char* dialogTitleUTF8, + void* parentWindow, + uint32_t positionX, + uint32_t positionY) = 0; + + virtual ~DeviceInfo() {} + }; + + class VideoCaptureEncodeInterface { + public: + virtual int32_t ConfigureEncoder(const VideoCodec& codec, + uint32_t maxPayloadSize) = 0; + // Inform the encoder about the new target bit rate. + // - newBitRate : New target bit rate in Kbit/s. + // - frameRate : The target frame rate. + virtual int32_t SetRates(int32_t newBitRate, int32_t frameRate) = 0; + // Inform the encoder about the packet loss and the round-trip time. + // - packetLoss : Fraction lost + // (loss rate in percent = 100 * packetLoss / 255). + // - rtt : Round-trip time in milliseconds. + virtual int32_t SetChannelParameters(uint32_t packetLoss, int rtt) = 0; + + // Encode the next frame as key frame. + virtual int32_t EncodeFrameType(const FrameType type) = 0; + protected: + virtual ~VideoCaptureEncodeInterface() { + } + }; + + // Register capture data callback + virtual void RegisterCaptureDataCallback( + VideoCaptureDataCallback& dataCallback) = 0; + + // Remove capture data callback + virtual void DeRegisterCaptureDataCallback() = 0; + + // Register capture callback. + virtual void RegisterCaptureCallback(VideoCaptureFeedBack& callBack) = 0; + + // Remove capture callback. + virtual void DeRegisterCaptureCallback() = 0; + + // Start capture device + virtual int32_t StartCapture( + const VideoCaptureCapability& capability) = 0; + + virtual int32_t StopCapture() = 0; + + // Returns the name of the device used by this module. + virtual const char* CurrentDeviceName() const = 0; + + // Returns true if the capture device is running + virtual bool CaptureStarted() = 0; + + // Gets the current configuration. + virtual int32_t CaptureSettings(VideoCaptureCapability& settings) = 0; + + virtual void SetCaptureDelay(int32_t delayMS) = 0; + + // Returns the current CaptureDelay. Only valid when the camera is running. + virtual int32_t CaptureDelay() = 0; + + // Set the rotation of the captured frames. + // If the rotation is set to the same as returned by + // DeviceInfo::GetOrientation the captured frames are + // displayed correctly if rendered. + virtual int32_t SetCaptureRotation(VideoCaptureRotation rotation) = 0; + + // Gets a pointer to an encode interface if the capture device supports the + // requested type and size. NULL otherwise. + virtual VideoCaptureEncodeInterface* GetEncodeInterface( + const VideoCodec& codec) = 0; + + virtual void EnableFrameRateCallback(const bool enable) = 0; + virtual void EnableNoPictureAlarm(const bool enable) = 0; + +protected: + virtual ~VideoCaptureModule() {}; +}; + +} // namespace webrtc +#endif // WEBRTC_MODULES_VIDEO_CAPTURE_INCLUDE_VIDEO_CAPTURE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture_defines.h b/thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture_defines.h new file mode 100644 index 0000000..330bfc7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture_defines.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_INCLUDE_VIDEO_CAPTURE_DEFINES_H_ +#define WEBRTC_MODULES_VIDEO_CAPTURE_INCLUDE_VIDEO_CAPTURE_DEFINES_H_ + +#include "webrtc/common_video/interface/i420_video_frame.h" +#include "webrtc/modules/interface/module_common_types.h" +#include "webrtc/typedefs.h" + +namespace webrtc +{ +// Defines +#ifndef NULL + #define NULL 0 +#endif + +enum {kVideoCaptureUniqueNameLength =1024}; //Max unique capture device name lenght +enum {kVideoCaptureDeviceNameLength =256}; //Max capture device name lenght +enum {kVideoCaptureProductIdLength =128}; //Max product id length + +// Enums +enum VideoCaptureRotation +{ + kCameraRotate0 = 0, + kCameraRotate90 = 5, + kCameraRotate180 = 10, + kCameraRotate270 = 15 +}; + +struct VideoCaptureCapability +{ + int32_t width; + int32_t height; + int32_t maxFPS; + int32_t expectedCaptureDelay; + RawVideoType rawType; + VideoCodecType codecType; + bool interlaced; + + VideoCaptureCapability() + { + width = 0; + height = 0; + maxFPS = 0; + expectedCaptureDelay = 0; + rawType = kVideoUnknown; + codecType = kVideoCodecUnknown; + interlaced = false; + } + ; + bool operator!=(const VideoCaptureCapability &other) const + { + if (width != other.width) + return true; + if (height != other.height) + return true; + if (maxFPS != other.maxFPS) + return true; + if (rawType != other.rawType) + return true; + if (codecType != other.codecType) + return true; + if (interlaced != other.interlaced) + return true; + return false; + } + bool operator==(const VideoCaptureCapability &other) const + { + return !operator!=(other); + } +}; + +enum VideoCaptureAlarm +{ + Raised = 0, + Cleared = 1 +}; + +/* External Capture interface. Returned by Create + and implemented by the capture module. + */ +class VideoCaptureExternal +{ +public: + // |capture_time| must be specified in the NTP time format in milliseconds. + virtual int32_t IncomingFrame(uint8_t* videoFrame, + int32_t videoFrameLength, + const VideoCaptureCapability& frameInfo, + int64_t captureTime = 0) = 0; + virtual int32_t IncomingI420VideoFrame(I420VideoFrame* video_frame, + int64_t captureTime = 0) = 0; + +protected: + ~VideoCaptureExternal() {} +}; + +// Callback class to be implemented by module user +class VideoCaptureDataCallback +{ +public: + virtual void OnIncomingCapturedFrame(const int32_t id, + I420VideoFrame& videoFrame) = 0; + virtual void OnCaptureDelayChanged(const int32_t id, + const int32_t delay) = 0; +protected: + virtual ~VideoCaptureDataCallback(){} +}; + +class VideoCaptureFeedBack +{ +public: + virtual void OnCaptureFrameRate(const int32_t id, + const uint32_t frameRate) = 0; + virtual void OnNoPictureAlarm(const int32_t id, + const VideoCaptureAlarm alarm) = 0; +protected: + virtual ~VideoCaptureFeedBack(){} +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_VIDEO_CAPTURE_INCLUDE_VIDEO_CAPTURE_DEFINES_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture_factory.h b/thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture_factory.h new file mode 100644 index 0000000..ec92d31 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/modules/video_capture/include/video_capture_factory.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains interfaces used for creating the VideoCaptureModule +// and DeviceInfo. + +#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_INCLUDE_VIDEO_CAPTURE_FACTORY_H_ +#define WEBRTC_MODULES_VIDEO_CAPTURE_INCLUDE_VIDEO_CAPTURE_FACTORY_H_ + +#include "webrtc/modules/video_capture/include/video_capture.h" + +namespace webrtc { + +class VideoCaptureFactory { + public: + // Create a video capture module object + // id - unique identifier of this video capture module object. + // deviceUniqueIdUTF8 - name of the device. + // Available names can be found by using GetDeviceName + static VideoCaptureModule* Create(const int32_t id, + const char* deviceUniqueIdUTF8); + + // Create a video capture module object used for external capture. + // id - unique identifier of this video capture module object + // externalCapture - [out] interface to call when a new frame is captured. + static VideoCaptureModule* Create(const int32_t id, + VideoCaptureExternal*& externalCapture); + + static VideoCaptureModule::DeviceInfo* CreateDeviceInfo( + const int32_t id); + +#ifdef WEBRTC_ANDROID + static int32_t SetAndroidObjects(void* javaVM, void* javaContext); +#endif + + private: + ~VideoCaptureFactory(); +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_VIDEO_CAPTURE_INCLUDE_VIDEO_CAPTURE_FACTORY_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/aligned_malloc.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/aligned_malloc.h new file mode 100644 index 0000000..5d343cd --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/aligned_malloc.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_ + +// The functions declared here +// 1) Allocates block of aligned memory. +// 2) Re-calculates a pointer such that it is aligned to a higher or equal +// address. +// Note: alignment must be a power of two. The alignment is in bytes. + +#include + +namespace webrtc { + +// Returns a pointer to the first boundry of |alignment| bytes following the +// address of |ptr|. +// Note that there is no guarantee that the memory in question is available. +// |ptr| has no requirements other than it can't be NULL. +void* GetRightAlign(const void* ptr, size_t alignment); + +// Allocates memory of |size| bytes aligned on an |alignment| boundry. +// The return value is a pointer to the memory. Note that the memory must +// be de-allocated using AlignedFree. +void* AlignedMalloc(size_t size, size_t alignment); +// De-allocates memory created using the AlignedMalloc() API. +void AlignedFree(void* mem_block); + +// Templated versions to facilitate usage of aligned malloc without casting +// to and from void*. +template +T* GetRightAlign(const T* ptr, size_t alignment) { + return reinterpret_cast(GetRightAlign(reinterpret_cast(ptr), + alignment)); +} +template +T* AlignedMalloc(size_t size, size_t alignment) { + return reinterpret_cast(AlignedMalloc(size, alignment)); +} + +// Deleter for use with scoped_ptr. E.g., use as +// scoped_ptr foo; +struct AlignedFreeDeleter { + inline void operator()(void* ptr) const { + AlignedFree(ptr); + } +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/asm_defines.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/asm_defines.h new file mode 100644 index 0000000..4b839a9 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/asm_defines.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ASM_DEFINES_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ASM_DEFINES_H_ + +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif + +// Define the macros used in ARM assembly code, so that for Mac or iOS builds +// we add leading underscores for the function names. +#ifdef __APPLE__ +.macro GLOBAL_FUNCTION name +.global _\name +.endm +.macro DEFINE_FUNCTION name +_\name: +.endm +.macro CALL_FUNCTION name +bl _\name +.endm +.macro GLOBAL_LABEL name +.global _\name +.endm +#else +.macro GLOBAL_FUNCTION name +.global \name +.endm +.macro DEFINE_FUNCTION name +\name: +.endm +.macro CALL_FUNCTION name +bl \name +.endm +.macro GLOBAL_LABEL name +.global \name +.endm +#endif + +// With Apple's clang compiler, for instructions ldrb, strh, etc., +// the condition code is after the width specifier. Here we define +// only the ones that are actually used in the assembly files. +#if (defined __llvm__) && (defined __APPLE__) +.macro streqh reg1, reg2, num +strheq \reg1, \reg2, \num +.endm +#endif + +.text + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ASM_DEFINES_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/atomic32.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/atomic32.h new file mode 100644 index 0000000..8633e26 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/atomic32.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Atomic, system independent 32-bit integer. Unless you know what you're +// doing, use locks instead! :-) +// +// Note: assumes 32-bit (or higher) system +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_ + +#include + +#include "webrtc/base/constructormagic.h" +#include "webrtc/common_types.h" + +namespace webrtc { + +// 32 bit atomic variable. Note that this class relies on the compiler to +// align the 32 bit value correctly (on a 32 bit boundary), so as long as you're +// not doing things like reinterpret_cast over some custom allocated memory +// without being careful with alignment, you should be fine. +class Atomic32 { + public: + Atomic32(int32_t initial_value = 0); + ~Atomic32(); + + // Prefix operator! + int32_t operator++(); + int32_t operator--(); + + int32_t operator+=(int32_t value); + int32_t operator-=(int32_t value); + + // Sets the value atomically to new_value if the value equals compare value. + // The function returns true if the exchange happened. + bool CompareExchange(int32_t new_value, int32_t compare_value); + int32_t Value() { + return *this += 0; + } + + private: + // Disable the + and - operator since it's unclear what these operations + // should do. + Atomic32 operator+(const Atomic32& other); + Atomic32 operator-(const Atomic32& other); + + // Checks if |_value| is 32bit aligned. + inline bool Is32bitAligned() const { + return (reinterpret_cast(&value_) & 3) == 0; + } + + DISALLOW_COPY_AND_ASSIGN(Atomic32); + + int32_t value_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/clock.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/clock.h new file mode 100644 index 0000000..ce32691 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/clock.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CLOCK_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CLOCK_H_ + +#include "webrtc/typedefs.h" + +namespace webrtc { + +// January 1970, in NTP seconds. +const uint32_t kNtpJan1970 = 2208988800UL; + +// Magic NTP fractional unit. +const double kMagicNtpFractionalUnit = 4.294967296E+9; + +// A clock interface that allows reading of absolute and relative timestamps. +class Clock { + public: + virtual ~Clock() {} + + // Return a timestamp in milliseconds relative to some arbitrary source; the + // source is fixed for this clock. + virtual int64_t TimeInMilliseconds() = 0; + + // Return a timestamp in microseconds relative to some arbitrary source; the + // source is fixed for this clock. + virtual int64_t TimeInMicroseconds() = 0; + + // Retrieve an NTP absolute timestamp in seconds and fractions of a second. + virtual void CurrentNtp(uint32_t& seconds, uint32_t& fractions) = 0; + + // Retrieve an NTP absolute timestamp in milliseconds. + virtual int64_t CurrentNtpInMilliseconds() = 0; + + // Converts an NTP timestamp to a millisecond timestamp. + static int64_t NtpToMs(uint32_t seconds, uint32_t fractions); + + // Returns an instance of the real-time system clock implementation. + static Clock* GetRealTimeClock(); +}; + +class SimulatedClock : public Clock { + public: + explicit SimulatedClock(int64_t initial_time_us); + + virtual ~SimulatedClock() {} + + // Return a timestamp in milliseconds relative to some arbitrary source; the + // source is fixed for this clock. + virtual int64_t TimeInMilliseconds() OVERRIDE; + + // Return a timestamp in microseconds relative to some arbitrary source; the + // source is fixed for this clock. + virtual int64_t TimeInMicroseconds() OVERRIDE; + + // Retrieve an NTP absolute timestamp in milliseconds. + virtual void CurrentNtp(uint32_t& seconds, uint32_t& fractions) OVERRIDE; + + // Converts an NTP timestamp to a millisecond timestamp. + virtual int64_t CurrentNtpInMilliseconds() OVERRIDE; + + // Advance the simulated clock with a given number of milliseconds or + // microseconds. + void AdvanceTimeMilliseconds(int64_t milliseconds); + void AdvanceTimeMicroseconds(int64_t microseconds); + + private: + int64_t time_us_; +}; + +}; // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CLOCK_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/compile_assert.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/compile_assert.h new file mode 100644 index 0000000..a075184 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/compile_assert.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Borrowed from Chromium's src/base/macros.h. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ + +// The COMPILE_ASSERT macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and +// libjingle are merged. +#if !defined(COMPILE_ASSERT) +#if __cplusplus >= 201103L +// Under C++11, just use static_assert. +#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg) + +#else +template +struct CompileAssert { +}; + +#define COMPILE_ASSERT(expr, msg) \ + typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] + +#endif // __cplusplus >= 201103L +#endif // !defined(COMPILE_ASSERT) + +// Implementation details of COMPILE_ASSERT: +// +// - COMPILE_ASSERT works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outer parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// COMPILE_ASSERT(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/compile_assert_c.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/compile_assert_c.h new file mode 100644 index 0000000..d9ba866 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/compile_assert_c.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ + +// Only use this for C files. For C++, use compile_assert.h. +// +// Use this macro to verify at compile time that certain restrictions are met. +// The argument is the boolean expression to evaluate. +// Example: +// COMPILE_ASSERT(sizeof(foo) < 128); +#define COMPILE_ASSERT(expression) switch (0) {case 0: case expression:;} + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/condition_variable_wrapper.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/condition_variable_wrapper.h new file mode 100644 index 0000000..151f00e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/condition_variable_wrapper.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONDITION_VARIABLE_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONDITION_VARIABLE_WRAPPER_H_ + +namespace webrtc { + +class CriticalSectionWrapper; + +class ConditionVariableWrapper { + public: + // Factory method, constructor disabled. + static ConditionVariableWrapper* CreateConditionVariable(); + + virtual ~ConditionVariableWrapper() {} + + // Calling thread will atomically release crit_sect and wait until next + // some other thread calls Wake() or WakeAll(). + virtual void SleepCS(CriticalSectionWrapper& crit_sect) = 0; + + // Same as above but with a timeout. + virtual bool SleepCS(CriticalSectionWrapper& crit_sect, + unsigned long max_time_in_ms) = 0; + + // Wakes one thread calling SleepCS(). + virtual void Wake() = 0; + + // Wakes all threads calling SleepCS(). + virtual void WakeAll() = 0; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONDITION_VARIABLE_WRAPPER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/cpu_features_wrapper.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/cpu_features_wrapper.h new file mode 100644 index 0000000..5697c49 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/cpu_features_wrapper.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include "webrtc/typedefs.h" + +// List of features in x86. +typedef enum { + kSSE2, + kSSE3 +} CPUFeature; + +// List of features in ARM. +enum { + kCPUFeatureARMv7 = (1 << 0), + kCPUFeatureVFPv3 = (1 << 1), + kCPUFeatureNEON = (1 << 2), + kCPUFeatureLDREXSTREX = (1 << 3) +}; + +typedef int (*WebRtc_CPUInfo)(CPUFeature feature); + +// Returns true if the CPU supports the feature. +extern WebRtc_CPUInfo WebRtc_GetCPUInfo; + +// No CPU feature is available => straight C path. +extern WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM; + +// Return the features in an ARM device. +// It detects the features in the hardware platform, and returns supported +// values in the above enum definition as a bitmask. +extern uint64_t WebRtc_GetCPUFeaturesARM(void); + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/cpu_info.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/cpu_info.h new file mode 100644 index 0000000..fa8c388 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/cpu_info.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_INFO_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_INFO_H_ + +#include "webrtc/typedefs.h" + +namespace webrtc { + +class CpuInfo { + public: + static uint32_t DetectNumberOfCores(); + + private: + CpuInfo() {} + static uint32_t number_of_cores_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_INFO_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/critical_section_wrapper.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/critical_section_wrapper.h new file mode 100644 index 0000000..4979b5c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/critical_section_wrapper.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_ + +// If the critical section is heavily contended it may be beneficial to use +// read/write locks instead. + +#include "webrtc/common_types.h" +#include "webrtc/system_wrappers/interface/thread_annotations.h" + +namespace webrtc { +class LOCKABLE CriticalSectionWrapper { + public: + // Factory method, constructor disabled + static CriticalSectionWrapper* CreateCriticalSection(); + + virtual ~CriticalSectionWrapper() {} + + // Tries to grab lock, beginning of a critical section. Will wait for the + // lock to become available if the grab failed. + virtual void Enter() EXCLUSIVE_LOCK_FUNCTION() = 0; + + // Returns a grabbed lock, end of critical section. + virtual void Leave() UNLOCK_FUNCTION() = 0; +}; + +// RAII extension of the critical section. Prevents Enter/Leave mismatches and +// provides more compact critical section syntax. +class SCOPED_LOCKABLE CriticalSectionScoped { + public: + explicit CriticalSectionScoped(CriticalSectionWrapper* critsec) + EXCLUSIVE_LOCK_FUNCTION(critsec) + : ptr_crit_sec_(critsec) { + ptr_crit_sec_->Enter(); + } + + ~CriticalSectionScoped() UNLOCK_FUNCTION() { ptr_crit_sec_->Leave(); } + + private: + CriticalSectionWrapper* ptr_crit_sec_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log.h new file mode 100644 index 0000000..9608f2c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This singleton can be used for logging data for offline processing. Data +// logged with it can conveniently be parsed and processed with e.g. Matlab. +// +// Following is an example of the log file format, starting with the header +// row at line 1, and the data rows following. +// col1,col2,col3,multi-value-col4[3],,,col5 +// 123,10.2,-243,1,2,3,100 +// 241,12.3,233,1,2,3,200 +// 13,16.4,-13,1,2,3,300 +// +// As can be seen in the example, a multi-value-column is specified with the +// name followed the number of elements it contains. This followed by +// number of elements - 1 empty columns. +// +// Without multi-value-columns this format can be natively by Matlab. With +// multi-value-columns a small Matlab script is needed, available at +// trunk/tools/matlab/parseLog.m. +// +// Table names and column names are case sensitive. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_H_ + +#include + +#include "webrtc/system_wrappers/interface/data_log_impl.h" + +namespace webrtc { + +class DataLog { + public: + // Creates a log which uses a separate thread (referred to as the file + // writer thread) for writing log rows to file. + // + // Calls to this function after the log object has been created will only + // increment the reference counter. + static int CreateLog(); + + // Decrements the reference counter and deletes the log when the counter + // reaches 0. Should be called equal number of times as successful calls to + // CreateLog or memory leak will occur. + static void ReturnLog(); + + // Combines the string table_name and the integer table_id into a new string + // table_name + _ + table_id. The new string will be lower-case. + static std::string Combine(const std::string& table_name, int table_id); + + // Adds a new table, with the name table_name, and creates the file, with the + // name table_name + ".txt", to which the table will be written. + // table_name is treated in a case sensitive way. + static int AddTable(const std::string& table_name); + + // Adds a new column to a table. The column will be a multi-value-column + // if multi_value_length is greater than 1. + // table_name and column_name are treated in a case sensitive way. + static int AddColumn(const std::string& table_name, + const std::string& column_name, + int multi_value_length); + + // Inserts a single value into a table with name table_name at the column with + // name column_name. + // Note that the ValueContainer makes use of the copy constructor, + // operator= and operator<< of the type T, and that the template type must + // implement a deep copy copy constructor and operator=. + // Copy constructor and operator= must not be disabled for the type T. + // table_name and column_name are treated in a case sensitive way. + template + static int InsertCell(const std::string& table_name, + const std::string& column_name, + T value) { + DataLogImpl* data_log = DataLogImpl::StaticInstance(); + if (data_log == NULL) + return -1; + return data_log->InsertCell( + table_name, + column_name, + new ValueContainer(value)); + } + + // Inserts an array of values into a table with name table_name at the + // column specified by column_name, which must be a multi-value-column. + // Note that the MultiValueContainer makes use of the copy constructor, + // operator= and operator<< of the type T, and that the template type + // must implement a deep copy copy constructor and operator=. + // Copy constructor and operator= must not be disabled for the type T. + // table_name and column_name are treated in a case sensitive way. + template + static int InsertCell(const std::string& table_name, + const std::string& column_name, + const T* array, + int length) { + DataLogImpl* data_log = DataLogImpl::StaticInstance(); + if (data_log == NULL) + return -1; + return data_log->InsertCell( + table_name, + column_name, + new MultiValueContainer(array, length)); + } + + // For the table with name table_name: Writes the current row to file. + // Starts a new empty row. + // table_name is treated in a case-sensitive way. + static int NextRow(const std::string& table_name); +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log_c.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log_c.h new file mode 100644 index 0000000..4ff8329 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log_c.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This is a pure C wrapper of the DataLog class. The functions are directly +// mapped here except for InsertCell as C does not support templates. +// See data_log.h for a description of the functions. + +#ifndef SRC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_C_H_ +#define SRC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_C_H_ + +#include // size_t + +#include "webrtc/typedefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// All char* parameters in this file are expected to be null-terminated +// character sequences. +int WebRtcDataLog_CreateLog(); +void WebRtcDataLog_ReturnLog(); +char* WebRtcDataLog_Combine(char* combined_name, size_t combined_len, + const char* table_name, int table_id); +int WebRtcDataLog_AddTable(const char* table_name); +int WebRtcDataLog_AddColumn(const char* table_name, const char* column_name, + int multi_value_length); + +int WebRtcDataLog_InsertCell_int(const char* table_name, + const char* column_name, + int value); +int WebRtcDataLog_InsertArray_int(const char* table_name, + const char* column_name, + const int* values, + int length); +int WebRtcDataLog_InsertCell_float(const char* table_name, + const char* column_name, + float value); +int WebRtcDataLog_InsertArray_float(const char* table_name, + const char* column_name, + const float* values, + int length); +int WebRtcDataLog_InsertCell_double(const char* table_name, + const char* column_name, + double value); +int WebRtcDataLog_InsertArray_double(const char* table_name, + const char* column_name, + const double* values, + int length); +int WebRtcDataLog_InsertCell_int32(const char* table_name, + const char* column_name, + int32_t value); +int WebRtcDataLog_InsertArray_int32(const char* table_name, + const char* column_name, + const int32_t* values, + int length); +int WebRtcDataLog_InsertCell_uint32(const char* table_name, + const char* column_name, + uint32_t value); +int WebRtcDataLog_InsertArray_uint32(const char* table_name, + const char* column_name, + const uint32_t* values, + int length); +int WebRtcDataLog_InsertCell_int64(const char* table_name, + const char* column_name, + int64_t value); +int WebRtcDataLog_InsertArray_int64(const char* table_name, + const char* column_name, + const int64_t* values, + int length); + +int WebRtcDataLog_NextRow(const char* table_name); + +#ifdef __cplusplus +} // end of extern "C" +#endif + +#endif // SRC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_C_H_ // NOLINT diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log_impl.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log_impl.h new file mode 100644 index 0000000..0e5feef --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/data_log_impl.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains the helper classes for the DataLog APIs. See data_log.h +// for the APIs. +// +// These classes are helper classes used for logging data for offline +// processing. Data logged with these classes can conveniently be parsed and +// processed with e.g. Matlab. +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_IMPL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_IMPL_H_ + +#include +#include +#include +#include + +#include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +class CriticalSectionWrapper; +class EventWrapper; +class LogTable; +class RWLockWrapper; +class ThreadWrapper; + +// All container classes need to implement a ToString-function to be +// writable to file. Enforce this via the Container interface. +class Container { + public: + virtual ~Container() {} + + virtual void ToString(std::string* container_string) const = 0; +}; + +template +class ValueContainer : public Container { + public: + explicit ValueContainer(T data) : data_(data) {} + + virtual void ToString(std::string* container_string) const { + *container_string = ""; + std::stringstream ss; + ss << data_ << ","; + ss >> *container_string; + } + + private: + T data_; +}; + +template +class MultiValueContainer : public Container { + public: + MultiValueContainer(const T* data, int length) + : data_(data, data + length) { + } + + virtual void ToString(std::string* container_string) const { + *container_string = ""; + std::stringstream ss; + for (size_t i = 0; i < data_.size(); ++i) + ss << data_[i] << ","; + *container_string += ss.str(); + } + + private: + std::vector data_; +}; + +class DataLogImpl { + public: + ~DataLogImpl(); + + // The implementation of the CreateLog() method declared in data_log.h. + // See data_log.h for a description. + static int CreateLog(); + + // The implementation of the StaticInstance() method declared in data_log.h. + // See data_log.h for a description. + static DataLogImpl* StaticInstance(); + + // The implementation of the ReturnLog() method declared in data_log.h. See + // data_log.h for a description. + static void ReturnLog(); + + // The implementation of the AddTable() method declared in data_log.h. See + // data_log.h for a description. + int AddTable(const std::string& table_name); + + // The implementation of the AddColumn() method declared in data_log.h. See + // data_log.h for a description. + int AddColumn(const std::string& table_name, + const std::string& column_name, + int multi_value_length); + + // Inserts a Container into a table with name table_name at the column + // with name column_name. + // column_name is treated in a case sensitive way. + int InsertCell(const std::string& table_name, + const std::string& column_name, + const Container* value_container); + + // The implementation of the NextRow() method declared in data_log.h. See + // data_log.h for a description. + int NextRow(const std::string& table_name); + + private: + DataLogImpl(); + + // Initializes the DataLogImpl object, allocates and starts the + // thread file_writer_thread_. + int Init(); + + // Write all complete rows in every table to file. + // This function should only be called by the file_writer_thread_ if that + // thread is running to avoid race conditions. + void Flush(); + + // Run() is called by the thread file_writer_thread_. + static bool Run(void* obj); + + // This function writes data to file. Note, it blocks if there is no data + // that should be written to file availble. Flush is the non-blocking + // version of this function. + void Process(); + + // Stops the continuous calling of Process(). + void StopThread(); + + // Collection of tables indexed by the table name as std::string. + typedef std::map TableMap; + typedef webrtc::scoped_ptr CritSectScopedPtr; + + static CritSectScopedPtr crit_sect_; + static DataLogImpl* instance_; + int counter_; + TableMap tables_; + EventWrapper* flush_event_; + ThreadWrapper* file_writer_thread_; + RWLockWrapper* tables_lock_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_IMPL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/event_tracer.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/event_tracer.h new file mode 100644 index 0000000..80f0fa7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/event_tracer.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file defines the interface for event tracing in WebRTC. +// +// Event log handlers are set through SetupEventTracer(). User of this API will +// provide two function pointers to handle event tracing calls. +// +// * GetCategoryEnabledPtr +// Event tracing system calls this function to determine if a particular +// event category is enabled. +// +// * AddTraceEventPtr +// Adds a tracing event. It is the user's responsibility to log the data +// provided. +// +// Parameters for the above two functions are described in trace_event.h. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_TRACER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_TRACER_H_ + +#include "webrtc/common_types.h" + +namespace webrtc { + +typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name); +typedef void (*AddTraceEventPtr)(char phase, + const unsigned char* category_enabled, + const char* name, + unsigned long long id, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const unsigned long long* arg_values, + unsigned char flags); + +// User of WebRTC can call this method to setup event tracing. +// +// This method must be called before any WebRTC methods. Functions +// provided should be thread-safe. +WEBRTC_DLLEXPORT void SetupEventTracer( + GetCategoryEnabledPtr get_category_enabled_ptr, + AddTraceEventPtr add_trace_event_ptr); + +// This class defines interface for the event tracing system to call +// internally. Do not call these methods directly. +class EventTracer { + public: + static const unsigned char* GetCategoryEnabled( + const char* name); + + static void AddTraceEvent( + char phase, + const unsigned char* category_enabled, + const char* name, + unsigned long long id, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const unsigned long long* arg_values, + unsigned char flags); +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_TRACER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/event_wrapper.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/event_wrapper.h new file mode 100644 index 0000000..7a18232 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/event_wrapper.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_WRAPPER_H_ + +namespace webrtc { +enum EventTypeWrapper { + kEventSignaled = 1, + kEventError = 2, + kEventTimeout = 3 +}; + +#define WEBRTC_EVENT_10_SEC 10000 +#define WEBRTC_EVENT_INFINITE 0xffffffff + +class EventWrapper { + public: + // Factory method. Constructor disabled. + static EventWrapper* Create(); + virtual ~EventWrapper() {} + + // Releases threads who are calling Wait() and has started waiting. Please + // note that a thread calling Wait() will not start waiting immediately. + // assumptions to the contrary is a very common source of issues in + // multithreaded programming. + // Set is sticky in the sense that it will release at least one thread + // either immediately or some time in the future. + virtual bool Set() = 0; + + // Prevents future Wait() calls from finishing without a new Set() call. + virtual bool Reset() = 0; + + // Puts the calling thread into a wait state. The thread may be released + // by a Set() call depending on if other threads are waiting and if so on + // timing. The thread that was released will call Reset() before leaving + // preventing more threads from being released. If multiple threads + // are waiting for the same Set(), only one (random) thread is guaranteed to + // be released. It is possible that multiple (random) threads are released + // Depending on timing. + virtual EventTypeWrapper Wait(unsigned long max_time) = 0; + + // Starts a timer that will call a non-sticky version of Set() either once + // or periodically. If the timer is periodic it ensures that there is no + // drift over time relative to the system clock. + virtual bool StartTimer(bool periodic, unsigned long time) = 0; + + virtual bool StopTimer() = 0; + +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_WRAPPER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/field_trial.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/field_trial.h new file mode 100644 index 0000000..f2cf880 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/field_trial.h @@ -0,0 +1,70 @@ +// +// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FIELD_TRIAL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FIELD_TRIAL_H_ + +#include + +#include "webrtc/common_types.h" + +// Field trials allow webrtc clients (such as Chrome) to turn on feature code +// in binaries out in the field and gather information with that. +// +// WebRTC clients MUST provide an implementation of: +// +// std::string webrtc::field_trial::FindFullName(const std::string& trial). +// +// Or link with a default one provided in: +// +// system_wrappers/source/system_wrappers.gyp:field_trial_default +// +// +// They are designed to wire up directly to chrome field trials and to speed up +// developers by reducing the need to wire APIs to control whether a feature is +// on/off. E.g. to experiment with a new method that could lead to a different +// trade-off between CPU/bandwidth: +// +// 1 - Develop the feature with default behaviour off: +// +// if (FieldTrial::FindFullName("WebRTCExperimenMethod2") == "Enabled") +// method2(); +// else +// method1(); +// +// 2 - Once the changes are rolled to chrome, the new code path can be +// controlled as normal chrome field trials. +// +// 3 - Evaluate the new feature and clean the code paths. +// +// Notes: +// - NOT every feature is a candidate to be controlled by this mechanism as +// it may require negotation between involved parties (e.g. SDP). +// +// TODO(andresp): since chrome --force-fieldtrials does not marks the trial +// as active it does not gets propaged to renderer process. For now one +// needs to push a config with start_active:true or run a local finch +// server. +// +// TODO(andresp): find out how to get bots to run tests with trials enabled. + +namespace webrtc { +namespace field_trial { + +// Returns the group name chosen for the named trial, or the empty string +// if the trial does not exists. +// +// Note: To keep things tidy append all the trial names with WebRTC. +std::string FindFullName(const std::string& name); + +} // namespace field_trial +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FIELD_TRIAL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/file_wrapper.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/file_wrapper.h new file mode 100644 index 0000000..68dc005 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/file_wrapper.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_ + +#include +#include + +#include "webrtc/common_types.h" +#include "webrtc/typedefs.h" + +// Implementation of an InStream and OutStream that can read (exclusive) or +// write from/to a file. + +namespace webrtc { + +class FileWrapper : public InStream, public OutStream { + public: + static const size_t kMaxFileNameSize = 1024; + + // Factory method. Constructor disabled. + static FileWrapper* Create(); + + // Returns true if a file has been opened. + virtual bool Open() const = 0; + + // Opens a file in read or write mode, decided by the read_only parameter. + virtual int OpenFile(const char* file_name_utf8, + bool read_only, + bool loop = false, + bool text = false) = 0; + + // Initializes the wrapper from an existing handle. |read_only| must match in + // the mode the file was opened in. If |manage_file| is true, the wrapper + // takes ownership of |handle| and closes it in CloseFile(). + virtual int OpenFromFileHandle(FILE* handle, + bool manage_file, + bool read_only, + bool loop = false) = 0; + + virtual int CloseFile() = 0; + + // Limits the file size to |bytes|. Writing will fail after the cap + // is hit. Pass zero to use an unlimited size. + virtual int SetMaxFileSize(size_t bytes) = 0; + + // Flush any pending writes. + virtual int Flush() = 0; + + // Returns the opened file's name in |file_name_utf8|. Provide the size of + // the buffer in bytes in |size|. The name will be truncated if |size| is + // too small. + virtual int FileName(char* file_name_utf8, + size_t size) const = 0; + + // Write |format| to the opened file. Arguments are taken in the same manner + // as printf. That is, supply a format string containing text and + // specifiers. Returns the number of characters written or -1 on error. + virtual int WriteText(const char* format, ...) = 0; + + // Inherited from Instream. + // Reads |length| bytes from file to |buf|. Returns the number of bytes read + // or -1 on error. + virtual int Read(void* buf, int length) = 0; + + // Inherited from OutStream. + // Writes |length| bytes from |buf| to file. The actual writing may happen + // some time later. Call Flush() to force a write. + virtual bool Write(const void* buf, int length) = 0; + + // Inherited from both Instream and OutStream. + // Rewinds the file to the start. Only available when OpenFile() has been + // called with |loop| == true or |readOnly| == true. + virtual int Rewind() = 0; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h new file mode 100644 index 0000000..8fb32ef --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Various inline functions and macros to fix compilation of 32 bit target +// on MSVC with /Wp64 flag enabled. + +// The original code can be found here: +// http://src.chromium.org/svn/trunk/src/base/fix_wp64.h + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ + +#include + +// Platform SDK fixes when building with /Wp64 for a 32 bits target. +#if !defined(_WIN64) && defined(_Wp64) + +#ifdef InterlockedExchangePointer +#undef InterlockedExchangePointer +// The problem is that the macro provided for InterlockedExchangePointer() is +// doing a (LONG) C-style cast that triggers invariably the warning C4312 when +// building on 32 bits. +inline void* InterlockedExchangePointer(void* volatile* target, void* value) { + return reinterpret_cast(static_cast(InterlockedExchange( + reinterpret_cast(target), + static_cast(reinterpret_cast(value))))); +} +#endif // #ifdef InterlockedExchangePointer + +#endif // #if !defined(_WIN64) && defined(_Wp64) + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/logcat_trace_context.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/logcat_trace_context.h new file mode 100644 index 0000000..d23e451 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/logcat_trace_context.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGCAT_TRACE_CONTEXT_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGCAT_TRACE_CONTEXT_H_ + +#include "webrtc/system_wrappers/interface/trace.h" + +#ifndef ANDROID +#error This file only makes sense to include on Android! +#endif + +namespace webrtc { + +// Scoped helper class for directing Traces to Android's logcat facility. While +// this object lives, Trace output will be sent to logcat. +class LogcatTraceContext : public webrtc::TraceCallback { + public: + LogcatTraceContext(); + virtual ~LogcatTraceContext(); + + // TraceCallback impl. + virtual void Print(TraceLevel level, const char* message, int length); +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGCAT_TRACE_CONTEXT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/logging.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/logging.h new file mode 100644 index 0000000..41c436b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/logging.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This is a highly stripped-down version of libjingle's talk/base/logging.h. +// It is a thin wrapper around WEBRTC_TRACE, maintaining the libjingle log +// semantics to ease a transition to that format. + +// NOTE: LS_INFO maps to a new trace level which should be reserved for +// infrequent, non-verbose logs. The other levels below kTraceWarning have been +// rendered essentially useless due to their verbosity. Carefully consider the +// impact of adding a new LS_INFO log. If it will be logged at anything +// approaching a frame or packet frequency, use LS_VERBOSE if necessary, or +// preferably, do not log at all. + +// LOG(...) an ostream target that can be used to send formatted +// output to a variety of logging targets, such as debugger console, stderr, +// file, or any StreamInterface. +// The severity level passed as the first argument to the LOGging +// functions is used as a filter, to limit the verbosity of the logging. +// Static members of LogMessage documented below are used to control the +// verbosity and target of the output. +// There are several variations on the LOG macro which facilitate logging +// of common error conditions, detailed below. + +// LOG(sev) logs the given stream at severity "sev", which must be a +// compile-time constant of the LoggingSeverity type, without the namespace +// prefix. +// LOG_V(sev) Like LOG(), but sev is a run-time variable of the LoggingSeverity +// type (basically, it just doesn't prepend the namespace). +// LOG_F(sev) Like LOG(), but includes the name of the current function. + +// Additional helper macros added by WebRTC: +// LOG_API is a shortcut for API call logging. Pass in the input parameters of +// the method. For example: +// Foo(int bar, int baz) { +// LOG_API2(bar, baz); +// } +// +// LOG_FERR is a shortcut for logging a failed function call. For example: +// if (!Foo(bar)) { +// LOG_FERR1(LS_WARNING, Foo, bar); +// } + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGGING_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGGING_H_ + +#include + +namespace webrtc { + +////////////////////////////////////////////////////////////////////// + +// Note that the non-standard LoggingSeverity aliases exist because they are +// still in broad use. The meanings of the levels are: +// LS_SENSITIVE: Information which should only be logged with the consent +// of the user, due to privacy concerns. +// LS_VERBOSE: This level is for data which we do not want to appear in the +// normal debug log, but should appear in diagnostic logs. +// LS_INFO: Chatty level used in debugging for all sorts of things, the default +// in debug builds. +// LS_WARNING: Something that may warrant investigation. +// LS_ERROR: Something that should not have occurred. +enum LoggingSeverity { + LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR +}; + +class LogMessage { + public: + LogMessage(const char* file, int line, LoggingSeverity sev); + ~LogMessage(); + + static bool Loggable(LoggingSeverity sev); + std::ostream& stream() { return print_stream_; } + + private: + // The ostream that buffers the formatted message before output + std::ostringstream print_stream_; + + // The severity level of this message + LoggingSeverity severity_; +}; + +////////////////////////////////////////////////////////////////////// +// Macros which automatically disable logging when WEBRTC_LOGGING == 0 +////////////////////////////////////////////////////////////////////// + +#ifndef LOG +// The following non-obvious technique for implementation of a +// conditional log stream was stolen from google3/base/logging.h. + +// This class is used to explicitly ignore values in the conditional +// logging macros. This avoids compiler warnings like "value computed +// is not used" and "statement has no effect". + +class LogMessageVoidify { + public: + LogMessageVoidify() { } + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream&) { } +}; + +#if defined(WEBRTC_RESTRICT_LOGGING) +// This should compile away logs matching the following condition. +#define RESTRICT_LOGGING_PRECONDITION(sev) \ + sev < webrtc::LS_INFO ? (void) 0 : +#else +#define RESTRICT_LOGGING_PRECONDITION(sev) +#endif + +#define LOG_SEVERITY_PRECONDITION(sev) \ + RESTRICT_LOGGING_PRECONDITION(sev) !(webrtc::LogMessage::Loggable(sev)) \ + ? (void) 0 \ + : webrtc::LogMessageVoidify() & + +#define LOG(sev) \ + LOG_SEVERITY_PRECONDITION(webrtc::sev) \ + webrtc::LogMessage(__FILE__, __LINE__, webrtc::sev).stream() + +// The _V version is for when a variable is passed in. It doesn't do the +// namespace concatination. +#define LOG_V(sev) \ + LOG_SEVERITY_PRECONDITION(sev) \ + webrtc::LogMessage(__FILE__, __LINE__, sev).stream() + +// The _F version prefixes the message with the current function name. +#if (defined(__GNUC__) && defined(_DEBUG)) || defined(WANT_PRETTY_LOG_F) +#define LOG_F(sev) LOG(sev) << __PRETTY_FUNCTION__ << ": " +#else +#define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": " +#endif + +#define LOG_API0() LOG_F(LS_VERBOSE) +#define LOG_API1(v1) LOG_API0() << #v1 << "=" << v1 +#define LOG_API2(v1, v2) LOG_API1(v1) \ + << ", " << #v2 << "=" << v2 +#define LOG_API3(v1, v2, v3) LOG_API2(v1, v2) \ + << ", " << #v3 << "=" << v3 + +#define LOG_FERR0(sev, func) LOG(sev) << #func << " failed" +#define LOG_FERR1(sev, func, v1) LOG_FERR0(sev, func) \ + << ": " << #v1 << "=" << v1 +#define LOG_FERR2(sev, func, v1, v2) LOG_FERR1(sev, func, v1) \ + << ", " << #v2 << "=" << v2 +#define LOG_FERR3(sev, func, v1, v2, v3) LOG_FERR2(sev, func, v1, v2) \ + << ", " << #v3 << "=" << v3 +#define LOG_FERR4(sev, func, v1, v2, v3, v4) LOG_FERR3(sev, func, v1, v2, v3) \ + << ", " << #v4 << "=" << v4 + +#endif // LOG + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGGING_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/ref_count.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/ref_count.h new file mode 100644 index 0000000..6861666 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/ref_count.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef SYSTEM_WRAPPERS_INTERFACE_REF_COUNT_H_ +#define SYSTEM_WRAPPERS_INTERFACE_REF_COUNT_H_ + +#include "webrtc/system_wrappers/interface/atomic32.h" + +namespace webrtc { + +// This class can be used for instantiating +// reference counted objects. +// int32_t AddRef() and int32_t Release(). +// Usage: +// RefCountImpl* implementation = new RefCountImpl(p); +// +// Example: +// class MyInterface { +// public: +// virtual void DoSomething() = 0; +// virtual int32_t AddRef() = 0; +// virtual int32_t Release() = 0: +// private: +// virtual ~MyInterface(){}; +// } +// class MyImplementation : public MyInterface { +// public: +// virtual DoSomething() { printf("hello"); }; +// }; +// MyImplementation* CreateMyImplementation() { +// RefCountImpl* implementation = +// new RefCountImpl(); +// return implementation; +// } + +template +class RefCountImpl : public T { + public: + RefCountImpl() : ref_count_(0) {} + + template + explicit RefCountImpl(P p) : T(p), ref_count_(0) {} + + template + RefCountImpl(P1 p1, P2 p2) : T(p1, p2), ref_count_(0) {} + + template + RefCountImpl(P1 p1, P2 p2, P3 p3) : T(p1, p2, p3), ref_count_(0) {} + + template + RefCountImpl(P1 p1, P2 p2, P3 p3, P4 p4) : T(p1, p2, p3, p4), ref_count_(0) {} + + template + RefCountImpl(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) + : T(p1, p2, p3, p4, p5), ref_count_(0) {} + + virtual int32_t AddRef() { + return ++ref_count_; + } + + virtual int32_t Release() { + int32_t ref_count; + ref_count = --ref_count_; + if (ref_count == 0) + delete this; + return ref_count; + } + + protected: + Atomic32 ref_count_; +}; + +} // namespace webrtc + +#endif // SYSTEM_WRAPPERS_INTERFACE_REF_COUNT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/rtp_to_ntp.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/rtp_to_ntp.h new file mode 100644 index 0000000..dfc25cd --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/rtp_to_ntp.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef SYSTEM_WRAPPERS_INTERFACE_RTP_TO_NTP_H_ +#define SYSTEM_WRAPPERS_INTERFACE_RTP_TO_NTP_H_ + +#include + +#include "webrtc/typedefs.h" + +namespace webrtc { + +struct RtcpMeasurement { + RtcpMeasurement(); + RtcpMeasurement(uint32_t ntp_secs, uint32_t ntp_frac, uint32_t timestamp); + uint32_t ntp_secs; + uint32_t ntp_frac; + uint32_t rtp_timestamp; +}; + +typedef std::list RtcpList; + +// Updates |rtcp_list| with timestamps from the latest RTCP SR. +// |new_rtcp_sr| will be set to true if these are the timestamps which have +// never be added to |rtcp_list|. +bool UpdateRtcpList(uint32_t ntp_secs, + uint32_t ntp_frac, + uint32_t rtp_timestamp, + RtcpList* rtcp_list, + bool* new_rtcp_sr); + +// Converts an RTP timestamp to the NTP domain in milliseconds using two +// (RTP timestamp, NTP timestamp) pairs. +bool RtpToNtpMs(int64_t rtp_timestamp, const RtcpList& rtcp, + int64_t* timestamp_in_ms); + +// Returns 1 there has been a forward wrap around, 0 if there has been no wrap +// around and -1 if there has been a backwards wrap around (i.e. reordering). +int CheckForWrapArounds(uint32_t rtp_timestamp, uint32_t rtcp_rtp_timestamp); + +} // namespace webrtc + +#endif // SYSTEM_WRAPPERS_INTERFACE_RTP_TO_NTP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/rw_lock_wrapper.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/rw_lock_wrapper.h new file mode 100644 index 0000000..91126e5 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/rw_lock_wrapper.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_RW_LOCK_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_RW_LOCK_WRAPPER_H_ + +#include "webrtc/system_wrappers/interface/thread_annotations.h" + +// Note, Windows pre-Vista version of RW locks are not supported natively. For +// these OSs regular critical sections have been used to approximate RW lock +// functionality and will therefore have worse performance. + +namespace webrtc { + +class LOCKABLE RWLockWrapper { + public: + static RWLockWrapper* CreateRWLock(); + virtual ~RWLockWrapper() {} + + virtual void AcquireLockExclusive() EXCLUSIVE_LOCK_FUNCTION() = 0; + virtual void ReleaseLockExclusive() UNLOCK_FUNCTION() = 0; + + virtual void AcquireLockShared() SHARED_LOCK_FUNCTION() = 0; + virtual void ReleaseLockShared() UNLOCK_FUNCTION() = 0; +}; + +// RAII extensions of the RW lock. Prevents Acquire/Release missmatches and +// provides more compact locking syntax. +class SCOPED_LOCKABLE ReadLockScoped { + public: + ReadLockScoped(RWLockWrapper& rw_lock) SHARED_LOCK_FUNCTION(rw_lock) + : rw_lock_(rw_lock) { + rw_lock_.AcquireLockShared(); + } + + ~ReadLockScoped() UNLOCK_FUNCTION() { + rw_lock_.ReleaseLockShared(); + } + + private: + RWLockWrapper& rw_lock_; +}; + +class SCOPED_LOCKABLE WriteLockScoped { + public: + WriteLockScoped(RWLockWrapper& rw_lock) EXCLUSIVE_LOCK_FUNCTION(rw_lock) + : rw_lock_(rw_lock) { + rw_lock_.AcquireLockExclusive(); + } + + ~WriteLockScoped() UNLOCK_FUNCTION() { + rw_lock_.ReleaseLockExclusive(); + } + + private: + RWLockWrapper& rw_lock_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_RW_LOCK_WRAPPER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_ptr.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_ptr.h new file mode 100644 index 0000000..42bb8a6 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_ptr.h @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Borrowed from Chromium's src/base/memory/scoped_ptr.h. + +// Scopers help you manage ownership of a pointer, helping you easily manage the +// a pointer within a scope, and automatically destroying the pointer at the +// end of a scope. There are two main classes you will use, which correspond +// to the operators new/delete and new[]/delete[]. +// +// Example usage (scoped_ptr): +// { +// scoped_ptr foo(new Foo("wee")); +// } // foo goes out of scope, releasing the pointer with it. +// +// { +// scoped_ptr foo; // No pointer managed. +// foo.reset(new Foo("wee")); // Now a pointer is managed. +// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed. +// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed. +// foo->Method(); // Foo::Method() called. +// foo.get()->Method(); // Foo::Method() called. +// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer +// // manages a pointer. +// foo.reset(new Foo("wee4")); // foo manages a pointer again. +// foo.reset(); // Foo("wee4") destroyed, foo no longer +// // manages a pointer. +// } // foo wasn't managing a pointer, so nothing was destroyed. +// +// Example usage (scoped_ptr): +// { +// scoped_ptr foo(new Foo[100]); +// foo.get()->Method(); // Foo::Method on the 0th element. +// foo[10].Method(); // Foo::Method on the 10th element. +// } +// +// These scopers also implement part of the functionality of C++11 unique_ptr +// in that they are "movable but not copyable." You can use the scopers in +// the parameter and return types of functions to signify ownership transfer +// in to and out of a function. When calling a function that has a scoper +// as the argument type, it must be called with the result of an analogous +// scoper's Pass() function or another function that generates a temporary; +// passing by copy will NOT work. Here is an example using scoped_ptr: +// +// void TakesOwnership(scoped_ptr arg) { +// // Do something with arg +// } +// scoped_ptr CreateFoo() { +// // No need for calling Pass() because we are constructing a temporary +// // for the return value. +// return scoped_ptr(new Foo("new")); +// } +// scoped_ptr PassThru(scoped_ptr arg) { +// return arg.Pass(); +// } +// +// { +// scoped_ptr ptr(new Foo("yay")); // ptr manages Foo("yay"). +// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay"). +// scoped_ptr ptr2 = CreateFoo(); // ptr2 owns the return Foo. +// scoped_ptr ptr3 = // ptr3 now owns what was in ptr2. +// PassThru(ptr2.Pass()); // ptr2 is correspondingly NULL. +// } +// +// Notice that if you do not call Pass() when returning from PassThru(), or +// when invoking TakesOwnership(), the code will not compile because scopers +// are not copyable; they only implement move semantics which require calling +// the Pass() function to signify a destructive transfer of state. CreateFoo() +// is different though because we are constructing a temporary on the return +// line and thus can avoid needing to call Pass(). +// +// Pass() properly handles upcast in initialization, i.e. you can use a +// scoped_ptr to initialize a scoped_ptr: +// +// scoped_ptr foo(new Foo()); +// scoped_ptr parent(foo.Pass()); +// +// PassAs<>() should be used to upcast return value in return statement: +// +// scoped_ptr CreateFoo() { +// scoped_ptr result(new FooChild()); +// return result.PassAs(); +// } +// +// Note that PassAs<>() is implemented only for scoped_ptr, but not for +// scoped_ptr. This is because casting array pointers may not be safe. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_PTR_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_PTR_H_ + +// This is an implementation designed to match the anticipated future TR2 +// implementation of the scoped_ptr class. + +#include +#include +#include + +#include // For std::swap(). + +#include "webrtc/base/constructormagic.h" +#include "webrtc/system_wrappers/interface/compile_assert.h" +#include "webrtc/system_wrappers/interface/template_util.h" +#include "webrtc/system_wrappers/source/move.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +// Function object which deletes its parameter, which must be a pointer. +// If C is an array type, invokes 'delete[]' on the parameter; otherwise, +// invokes 'delete'. The default deleter for scoped_ptr. +template +struct DefaultDeleter { + DefaultDeleter() {} + template DefaultDeleter(const DefaultDeleter& other) { + // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor + // if U* is implicitly convertible to T* and U is not an array type. + // + // Correct implementation should use SFINAE to disable this + // constructor. However, since there are no other 1-argument constructors, + // using a COMPILE_ASSERT() based on is_convertible<> and requiring + // complete types is simpler and will cause compile failures for equivalent + // misuses. + // + // Note, the is_convertible check also ensures that U is not an + // array. T is guaranteed to be a non-array, so any U* where U is an array + // cannot convert to T*. + enum { T_must_be_complete = sizeof(T) }; + enum { U_must_be_complete = sizeof(U) }; + COMPILE_ASSERT((webrtc::is_convertible::value), + U_ptr_must_implicitly_convert_to_T_ptr); + } + inline void operator()(T* ptr) const { + enum { type_must_be_complete = sizeof(T) }; + delete ptr; + } +}; + +// Specialization of DefaultDeleter for array types. +template +struct DefaultDeleter { + inline void operator()(T* ptr) const { + enum { type_must_be_complete = sizeof(T) }; + delete[] ptr; + } + + private: + // Disable this operator for any U != T because it is undefined to execute + // an array delete when the static type of the array mismatches the dynamic + // type. + // + // References: + // C++98 [expr.delete]p3 + // http://cplusplus.github.com/LWG/lwg-defects.html#938 + template void operator()(U* array) const; +}; + +template +struct DefaultDeleter { + // Never allow someone to declare something like scoped_ptr. + COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type); +}; + +// Function object which invokes 'free' on its parameter, which must be +// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr: +// +// scoped_ptr foo_ptr( +// static_cast(malloc(sizeof(int)))); +struct FreeDeleter { + inline void operator()(void* ptr) const { + free(ptr); + } +}; + +namespace internal { + +// Minimal implementation of the core logic of scoped_ptr, suitable for +// reuse in both scoped_ptr and its specializations. +template +class scoped_ptr_impl { + public: + explicit scoped_ptr_impl(T* p) : data_(p) { } + + // Initializer for deleters that have data parameters. + scoped_ptr_impl(T* p, const D& d) : data_(p, d) {} + + // Templated constructor that destructively takes the value from another + // scoped_ptr_impl. + template + scoped_ptr_impl(scoped_ptr_impl* other) + : data_(other->release(), other->get_deleter()) { + // We do not support move-only deleters. We could modify our move + // emulation to have webrtc::subtle::move() and webrtc::subtle::forward() + // functions that are imperfect emulations of their C++11 equivalents, + // but until there's a requirement, just assume deleters are copyable. + } + + template + void TakeState(scoped_ptr_impl* other) { + // See comment in templated constructor above regarding lack of support + // for move-only deleters. + reset(other->release()); + get_deleter() = other->get_deleter(); + } + + ~scoped_ptr_impl() { + if (data_.ptr != NULL) { + // Not using get_deleter() saves one function call in non-optimized + // builds. + static_cast(data_)(data_.ptr); + } + } + + void reset(T* p) { + // This is a self-reset, which is no longer allowed: http://crbug.com/162971 + if (p != NULL && p == data_.ptr) + abort(); + + // Note that running data_.ptr = p can lead to undefined behavior if + // get_deleter()(get()) deletes this. In order to pevent this, reset() + // should update the stored pointer before deleting its old value. + // + // However, changing reset() to use that behavior may cause current code to + // break in unexpected ways. If the destruction of the owned object + // dereferences the scoped_ptr when it is destroyed by a call to reset(), + // then it will incorrectly dispatch calls to |p| rather than the original + // value of |data_.ptr|. + // + // During the transition period, set the stored pointer to NULL while + // deleting the object. Eventually, this safety check will be removed to + // prevent the scenario initially described from occuring and + // http://crbug.com/176091 can be closed. + T* old = data_.ptr; + data_.ptr = NULL; + if (old != NULL) + static_cast(data_)(old); + data_.ptr = p; + } + + T* get() const { return data_.ptr; } + + D& get_deleter() { return data_; } + const D& get_deleter() const { return data_; } + + void swap(scoped_ptr_impl& p2) { + // Standard swap idiom: 'using std::swap' ensures that std::swap is + // present in the overload set, but we call swap unqualified so that + // any more-specific overloads can be used, if available. + using std::swap; + swap(static_cast(data_), static_cast(p2.data_)); + swap(data_.ptr, p2.data_.ptr); + } + + T* release() { + T* old_ptr = data_.ptr; + data_.ptr = NULL; + return old_ptr; + } + + private: + // Needed to allow type-converting constructor. + template friend class scoped_ptr_impl; + + // Use the empty base class optimization to allow us to have a D + // member, while avoiding any space overhead for it when D is an + // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good + // discussion of this technique. + struct Data : public D { + explicit Data(T* ptr_in) : ptr(ptr_in) {} + Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {} + T* ptr; + }; + + Data data_; + + DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl); +}; + +} // namespace internal + +// A scoped_ptr is like a T*, except that the destructor of scoped_ptr +// automatically deletes the pointer it holds (if any). +// That is, scoped_ptr owns the T object that it points to. +// Like a T*, a scoped_ptr may hold either NULL or a pointer to a T object. +// Also like T*, scoped_ptr is thread-compatible, and once you +// dereference it, you get the thread safety guarantees of T. +// +// The size of scoped_ptr is small. On most compilers, when using the +// DefaultDeleter, sizeof(scoped_ptr) == sizeof(T*). Custom deleters will +// increase the size proportional to whatever state they need to have. See +// comments inside scoped_ptr_impl<> for details. +// +// Current implementation targets having a strict subset of C++11's +// unique_ptr<> features. Known deficiencies include not supporting move-only +// deleteres, function pointers as deleters, and deleters with reference +// types. +template > +class scoped_ptr { + WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) + + public: + // The element and deleter types. + typedef T element_type; + typedef D deleter_type; + + // Constructor. Defaults to initializing with NULL. + scoped_ptr() : impl_(NULL) { } + + // Constructor. Takes ownership of p. + explicit scoped_ptr(element_type* p) : impl_(p) { } + + // Constructor. Allows initialization of a stateful deleter. + scoped_ptr(element_type* p, const D& d) : impl_(p, d) { } + + // Constructor. Allows construction from a scoped_ptr rvalue for a + // convertible type and deleter. + // + // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct + // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor + // has different post-conditions if D is a reference type. Since this + // implementation does not support deleters with reference type, + // we do not need a separate move constructor allowing us to avoid one + // use of SFINAE. You only need to care about this if you modify the + // implementation of scoped_ptr. + template + scoped_ptr(scoped_ptr other) : impl_(&other.impl_) { + COMPILE_ASSERT(!webrtc::is_array::value, U_cannot_be_an_array); + } + + // Constructor. Move constructor for C++03 move emulation of this type. + scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { } + + // operator=. Allows assignment from a scoped_ptr rvalue for a convertible + // type and deleter. + // + // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from + // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated + // form has different requirements on for move-only Deleters. Since this + // implementation does not support move-only Deleters, we do not need a + // separate move assignment operator allowing us to avoid one use of SFINAE. + // You only need to care about this if you modify the implementation of + // scoped_ptr. + template + scoped_ptr& operator=(scoped_ptr rhs) { + COMPILE_ASSERT(!webrtc::is_array::value, U_cannot_be_an_array); + impl_.TakeState(&rhs.impl_); + return *this; + } + + // Reset. Deletes the currently owned object, if any. + // Then takes ownership of a new object, if given. + void reset(element_type* p = NULL) { impl_.reset(p); } + + // Accessors to get the owned object. + // operator* and operator-> will assert() if there is no current object. + element_type& operator*() const { + assert(impl_.get() != NULL); + return *impl_.get(); + } + element_type* operator->() const { + assert(impl_.get() != NULL); + return impl_.get(); + } + element_type* get() const { return impl_.get(); } + + // Access to the deleter. + deleter_type& get_deleter() { return impl_.get_deleter(); } + const deleter_type& get_deleter() const { return impl_.get_deleter(); } + + // Allow scoped_ptr to be used in boolean expressions, but not + // implicitly convertible to a real bool (which is dangerous). + // + // Note that this trick is only safe when the == and != operators + // are declared explicitly, as otherwise "scoped_ptr1 == + // scoped_ptr2" will compile but do the wrong thing (i.e., convert + // to Testable and then do the comparison). + private: + typedef webrtc::internal::scoped_ptr_impl + scoped_ptr::*Testable; + + public: + operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(const element_type* p) const { return impl_.get() == p; } + bool operator!=(const element_type* p) const { return impl_.get() != p; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + impl_.swap(p2.impl_); + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + element_type* release() WARN_UNUSED_RESULT { + return impl_.release(); + } + + // C++98 doesn't support functions templates with default parameters which + // makes it hard to write a PassAs() that understands converting the deleter + // while preserving simple calling semantics. + // + // Until there is a use case for PassAs() with custom deleters, just ignore + // the custom deleter. + template + scoped_ptr PassAs() { + return scoped_ptr(Pass()); + } + + private: + // Needed to reach into |impl_| in the constructor. + template friend class scoped_ptr; + webrtc::internal::scoped_ptr_impl impl_; + + // Forbidden for API compatibility with std::unique_ptr. + explicit scoped_ptr(int disallow_construction_from_null); + + // Forbid comparison of scoped_ptr types. If U != T, it totally + // doesn't make sense, and if U == T, it still doesn't make sense + // because you should never have the same object owned by two different + // scoped_ptrs. + template bool operator==(scoped_ptr const& p2) const; + template bool operator!=(scoped_ptr const& p2) const; +}; + +template +class scoped_ptr { + WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) + + public: + // The element and deleter types. + typedef T element_type; + typedef D deleter_type; + + // Constructor. Defaults to initializing with NULL. + scoped_ptr() : impl_(NULL) { } + + // Constructor. Stores the given array. Note that the argument's type + // must exactly match T*. In particular: + // - it cannot be a pointer to a type derived from T, because it is + // inherently unsafe in the general case to access an array through a + // pointer whose dynamic type does not match its static type (eg., if + // T and the derived types had different sizes access would be + // incorrectly calculated). Deletion is also always undefined + // (C++98 [expr.delete]p3). If you're doing this, fix your code. + // - it cannot be NULL, because NULL is an integral expression, not a + // pointer to T. Use the no-argument version instead of explicitly + // passing NULL. + // - it cannot be const-qualified differently from T per unique_ptr spec + // (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting + // to work around this may use implicit_cast(). + // However, because of the first bullet in this comment, users MUST + // NOT use implicit_cast() to upcast the static type of the array. + explicit scoped_ptr(element_type* array) : impl_(array) { } + + // Constructor. Move constructor for C++03 move emulation of this type. + scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { } + + // operator=. Move operator= for C++03 move emulation of this type. + scoped_ptr& operator=(RValue rhs) { + impl_.TakeState(&rhs.object->impl_); + return *this; + } + + // Reset. Deletes the currently owned array, if any. + // Then takes ownership of a new object, if given. + void reset(element_type* array = NULL) { impl_.reset(array); } + + // Accessors to get the owned array. + element_type& operator[](size_t i) const { + assert(impl_.get() != NULL); + return impl_.get()[i]; + } + element_type* get() const { return impl_.get(); } + + // Access to the deleter. + deleter_type& get_deleter() { return impl_.get_deleter(); } + const deleter_type& get_deleter() const { return impl_.get_deleter(); } + + // Allow scoped_ptr to be used in boolean expressions, but not + // implicitly convertible to a real bool (which is dangerous). + private: + typedef webrtc::internal::scoped_ptr_impl + scoped_ptr::*Testable; + + public: + operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(element_type* array) const { return impl_.get() == array; } + bool operator!=(element_type* array) const { return impl_.get() != array; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + impl_.swap(p2.impl_); + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + element_type* release() WARN_UNUSED_RESULT { + return impl_.release(); + } + + private: + // Force element_type to be a complete type. + enum { type_must_be_complete = sizeof(element_type) }; + + // Actually hold the data. + webrtc::internal::scoped_ptr_impl impl_; + + // Disable initialization from any type other than element_type*, by + // providing a constructor that matches such an initialization, but is + // private and has no definition. This is disabled because it is not safe to + // call delete[] on an array whose static type does not match its dynamic + // type. + template explicit scoped_ptr(U* array); + explicit scoped_ptr(int disallow_construction_from_null); + + // Disable reset() from any type other than element_type*, for the same + // reasons as the constructor above. + template void reset(U* array); + void reset(int disallow_reset_from_null); + + // Forbid comparison of scoped_ptr types. If U != T, it totally + // doesn't make sense, and if U == T, it still doesn't make sense + // because you should never have the same object owned by two different + // scoped_ptrs. + template bool operator==(scoped_ptr const& p2) const; + template bool operator!=(scoped_ptr const& p2) const; +}; + +} // namespace webrtc + +// Free functions +template +void swap(webrtc::scoped_ptr& p1, webrtc::scoped_ptr& p2) { + p1.swap(p2); +} + +template +bool operator==(T* p1, const webrtc::scoped_ptr& p2) { + return p1 == p2.get(); +} + +template +bool operator!=(T* p1, const webrtc::scoped_ptr& p2) { + return p1 != p2.get(); +} + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_PTR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_refptr.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_refptr.h new file mode 100644 index 0000000..b344d21 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_refptr.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef SYSTEM_WRAPPERS_INTERFACE_SCOPED_REFPTR_H_ +#define SYSTEM_WRAPPERS_INTERFACE_SCOPED_REFPTR_H_ + +#include + +namespace webrtc { + +// Extracted from Chromium's src/base/memory/ref_counted.h. + +// +// A smart pointer class for reference counted objects. Use this class instead +// of calling AddRef and Release manually on a reference counted object to +// avoid common memory leaks caused by forgetting to Release an object +// reference. Sample usage: +// +// class MyFoo : public RefCounted { +// ... +// }; +// +// void some_function() { +// scoped_refptr foo = new MyFoo(); +// foo->Method(param); +// // |foo| is released when this function returns +// } +// +// void some_other_function() { +// scoped_refptr foo = new MyFoo(); +// ... +// foo = NULL; // explicitly releases |foo| +// ... +// if (foo) +// foo->Method(param); +// } +// +// The above examples show how scoped_refptr acts like a pointer to T. +// Given two scoped_refptr classes, it is also possible to exchange +// references between the two objects, like so: +// +// { +// scoped_refptr a = new MyFoo(); +// scoped_refptr b; +// +// b.swap(a); +// // now, |b| references the MyFoo object, and |a| references NULL. +// } +// +// To make both |a| and |b| in the above example reference the same MyFoo +// object, simply use the assignment operator: +// +// { +// scoped_refptr a = new MyFoo(); +// scoped_refptr b; +// +// b = a; +// // now, |a| and |b| each own a reference to the same MyFoo object. +// } +// +template +class scoped_refptr { + public: + scoped_refptr() : ptr_(NULL) { + } + + scoped_refptr(T* p) : ptr_(p) { + if (ptr_) + ptr_->AddRef(); + } + + scoped_refptr(const scoped_refptr& r) : ptr_(r.ptr_) { + if (ptr_) + ptr_->AddRef(); + } + + template + scoped_refptr(const scoped_refptr& r) : ptr_(r.get()) { + if (ptr_) + ptr_->AddRef(); + } + + ~scoped_refptr() { + if (ptr_) + ptr_->Release(); + } + + T* get() const { return ptr_; } + operator T*() const { return ptr_; } + T* operator->() const { return ptr_; } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + T* release() { + T* retVal = ptr_; + ptr_ = NULL; + return retVal; + } + + scoped_refptr& operator=(T* p) { + // AddRef first so that self assignment should work + if (p) + p->AddRef(); + if (ptr_ ) + ptr_->Release(); + ptr_ = p; + return *this; + } + + scoped_refptr& operator=(const scoped_refptr& r) { + return *this = r.ptr_; + } + + template + scoped_refptr& operator=(const scoped_refptr& r) { + return *this = r.get(); + } + + void swap(T** pp) { + T* p = ptr_; + ptr_ = *pp; + *pp = p; + } + + void swap(scoped_refptr& r) { + swap(&r.ptr_); + } + + protected: + T* ptr_; +}; +} // namespace webrtc + +#endif // SYSTEM_WRAPPERS_INTERFACE_SCOPED_REFPTR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_vector.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_vector.h new file mode 100644 index 0000000..68db3a1 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/scoped_vector.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Borrowed from Chromium's src/base/memory/scoped_vector.h. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_VECTOR_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_VECTOR_H_ + +#include +#include +#include + +#include "webrtc/system_wrappers/interface/stl_util.h" +#include "webrtc/system_wrappers/source/move.h" + +namespace webrtc { + +// ScopedVector wraps a vector deleting the elements from its +// destructor. +template +class ScopedVector { + WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue) + + public: + typedef typename std::vector::allocator_type allocator_type; + typedef typename std::vector::size_type size_type; + typedef typename std::vector::difference_type difference_type; + typedef typename std::vector::pointer pointer; + typedef typename std::vector::const_pointer const_pointer; + typedef typename std::vector::reference reference; + typedef typename std::vector::const_reference const_reference; + typedef typename std::vector::value_type value_type; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::reverse_iterator reverse_iterator; + typedef typename std::vector::const_reverse_iterator + const_reverse_iterator; + + ScopedVector() {} + ~ScopedVector() { clear(); } + ScopedVector(RValue other) { swap(*other.object); } + + ScopedVector& operator=(RValue rhs) { + swap(*rhs.object); + return *this; + } + + reference operator[](size_t index) { return v_[index]; } + const_reference operator[](size_t index) const { return v_[index]; } + + bool empty() const { return v_.empty(); } + size_t size() const { return v_.size(); } + + reverse_iterator rbegin() { return v_.rbegin(); } + const_reverse_iterator rbegin() const { return v_.rbegin(); } + reverse_iterator rend() { return v_.rend(); } + const_reverse_iterator rend() const { return v_.rend(); } + + iterator begin() { return v_.begin(); } + const_iterator begin() const { return v_.begin(); } + iterator end() { return v_.end(); } + const_iterator end() const { return v_.end(); } + + const_reference front() const { return v_.front(); } + reference front() { return v_.front(); } + const_reference back() const { return v_.back(); } + reference back() { return v_.back(); } + + void push_back(T* elem) { v_.push_back(elem); } + + void pop_back() { + assert(!empty()); + delete v_.back(); + v_.pop_back(); + } + + std::vector& get() { return v_; } + const std::vector& get() const { return v_; } + void swap(std::vector& other) { v_.swap(other); } + void swap(ScopedVector& other) { v_.swap(other.v_); } + void release(std::vector* out) { + out->swap(v_); + v_.clear(); + } + + void reserve(size_t capacity) { v_.reserve(capacity); } + + // Resize, deleting elements in the disappearing range if we are shrinking. + void resize(size_t new_size) { + if (v_.size() > new_size) + STLDeleteContainerPointers(v_.begin() + new_size, v_.end()); + v_.resize(new_size); + } + + template + void assign(InputIterator begin, InputIterator end) { + v_.assign(begin, end); + } + + void clear() { STLDeleteElements(&v_); } + + // Like |clear()|, but doesn't delete any elements. + void weak_clear() { v_.clear(); } + + // Lets the ScopedVector take ownership of |x|. + iterator insert(iterator position, T* x) { + return v_.insert(position, x); + } + + // Lets the ScopedVector take ownership of elements in [first,last). + template + void insert(iterator position, InputIterator first, InputIterator last) { + v_.insert(position, first, last); + } + + iterator erase(iterator position) { + delete *position; + return v_.erase(position); + } + + iterator erase(iterator first, iterator last) { + STLDeleteContainerPointers(first, last); + return v_.erase(first, last); + } + + // Like |erase()|, but doesn't delete the element at |position|. + iterator weak_erase(iterator position) { + return v_.erase(position); + } + + // Like |erase()|, but doesn't delete the elements in [first, last). + iterator weak_erase(iterator first, iterator last) { + return v_.erase(first, last); + } + + private: + std::vector v_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_VECTOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/sleep.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/sleep.h new file mode 100644 index 0000000..c0205bf --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/sleep.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +// An OS-independent sleep function. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_ + +namespace webrtc { + +// This function sleeps for the specified number of milliseconds. +// It may return early if the thread is woken by some other event, +// such as the delivery of a signal on Unix. +void SleepMs(int msecs); + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/sort.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/sort.h new file mode 100644 index 0000000..da6ff8d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/sort.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Generic unstable sorting routines. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SORT_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SORT_H_ + +#include "webrtc/common_types.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +enum Type { + TYPE_Word8, + TYPE_UWord8, + TYPE_Word16, + TYPE_UWord16, + TYPE_Word32, + TYPE_UWord32, + TYPE_Word64, + TYPE_UWord64, + TYPE_Float32, + TYPE_Float64 +}; + +// Sorts intrinsic data types. +// +// data [in/out] A pointer to an array of intrinsic type. +// Upon return it will be sorted in ascending order. +// num_of_elements The number of elements in the array. +// data_type Enum corresponding to the type of the array. +// +// returns 0 on success, -1 on failure. +int32_t Sort(void* data, uint32_t num_of_elements, Type data_type); + +// Sorts arbitrary data types. This requires an array of intrinsically typed +// key values which will be used to sort the data array. There must be a +// one-to-one correspondence between data elements and key elements, with +// corresponding elements sharing the same position in their respective +// arrays. +// +// data [in/out] A pointer to an array of arbitrary type. +// Upon return it will be sorted in ascending order. +// key [in] A pointer to an array of keys used to sort the +// data array. +// num_of_elements The number of elements in the arrays. +// size_of_element The size, in bytes, of the data array. +// key_type Enum corresponding to the type of the key array. +// +// returns 0 on success, -1 on failure. +// +int32_t KeySort(void* data, void* key, uint32_t num_of_elements, + uint32_t size_of_element, Type key_type); + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SORT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/static_instance.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/static_instance.h new file mode 100644 index 0000000..dad9c52 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/static_instance.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_ + +#include + +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" +#ifdef _WIN32 +#include "webrtc/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h" +#endif + +namespace webrtc { + +enum CountOperation { + kRelease, + kAddRef, + kAddRefNoCreate +}; +enum CreateOperation { + kInstanceExists, + kCreate, + kDestroy +}; + +template +// Construct On First Use idiom. Avoids +// "static initialization order fiasco". +static T* GetStaticInstance(CountOperation count_operation) { + // TODO (hellner): use atomic wrapper instead. + static volatile long instance_count = 0; + static T* volatile instance = NULL; + CreateOperation state = kInstanceExists; +#ifndef _WIN32 + // This memory is staticly allocated once. The application does not try to + // free this memory. This approach is taken to avoid issues with + // destruction order for statically allocated memory. The memory will be + // reclaimed by the OS and memory leak tools will not recognize memory + // reachable from statics leaked so no noise is added by doing this. + static CriticalSectionWrapper* crit_sect( + CriticalSectionWrapper::CreateCriticalSection()); + CriticalSectionScoped lock(crit_sect); + + if (count_operation == + kAddRefNoCreate && instance_count == 0) { + return NULL; + } + if (count_operation == + kAddRef || + count_operation == kAddRefNoCreate) { + instance_count++; + if (instance_count == 1) { + state = kCreate; + } + } else { + instance_count--; + if (instance_count == 0) { + state = kDestroy; + } + } + if (state == kCreate) { + instance = T::CreateInstance(); + } else if (state == kDestroy) { + T* old_instance = instance; + instance = NULL; + // The state will not change past this point. Release the critical + // section while deleting the object in case it would be blocking on + // access back to this object. (This is the case for the tracing class + // since the thread owned by the tracing class also traces). + // TODO(hellner): this is a bit out of place but here goes, de-couple + // thread implementation with trace implementation. + crit_sect->Leave(); + if (old_instance) { + delete old_instance; + } + // Re-acquire the lock since the scoped critical section will release + // it. + crit_sect->Enter(); + return NULL; + } +#else // _WIN32 + if (count_operation == + kAddRefNoCreate && instance_count == 0) { + return NULL; + } + if (count_operation == kAddRefNoCreate) { + if (1 == InterlockedIncrement(&instance_count)) { + // The instance has been destroyed by some other thread. Rollback. + InterlockedDecrement(&instance_count); + assert(false); + return NULL; + } + // Sanity to catch corrupt state. + if (instance == NULL) { + assert(false); + InterlockedDecrement(&instance_count); + return NULL; + } + } else if (count_operation == kAddRef) { + if (instance_count == 0) { + state = kCreate; + } else { + if (1 == InterlockedIncrement(&instance_count)) { + // InterlockedDecrement because reference count should not be + // updated just yet (that's done when the instance is created). + InterlockedDecrement(&instance_count); + state = kCreate; + } + } + } else { + int new_value = InterlockedDecrement(&instance_count); + if (new_value == 0) { + state = kDestroy; + } + } + + if (state == kCreate) { + // Create instance and let whichever thread finishes first assign its + // local copy to the global instance. All other threads reclaim their + // local copy. + T* new_instance = T::CreateInstance(); + if (1 == InterlockedIncrement(&instance_count)) { + InterlockedExchangePointer(reinterpret_cast(&instance), + new_instance); + } else { + InterlockedDecrement(&instance_count); + if (new_instance) { + delete static_cast(new_instance); + } + } + } else if (state == kDestroy) { + T* old_value = static_cast(InterlockedExchangePointer( + reinterpret_cast(&instance), NULL)); + if (old_value) { + delete static_cast(old_value); + } + return NULL; + } +#endif // #ifndef _WIN32 + return instance; +} + +} // namspace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/stl_util.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/stl_util.h new file mode 100644 index 0000000..ebe855f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/stl_util.h @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Borrowed from Chromium's src/base/stl_util.h. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STL_UTIL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STL_UTIL_H_ + +#include +#include +#include +#include +#include +#include + +namespace webrtc { + +// Clears internal memory of an STL object. +// STL clear()/reserve(0) does not always free internal memory allocated +// This function uses swap/destructor to ensure the internal memory is freed. +template +void STLClearObject(T* obj) { + T tmp; + tmp.swap(*obj); + // Sometimes "T tmp" allocates objects with memory (arena implementation?). + // Hence using additional reserve(0) even if it doesn't always work. + obj->reserve(0); +} + +// For a range within a container of pointers, calls delete (non-array version) +// on these pointers. +// NOTE: for these three functions, we could just implement a DeleteObject +// functor and then call for_each() on the range and functor, but this +// requires us to pull in all of algorithm.h, which seems expensive. +// For hash_[multi]set, it is important that this deletes behind the iterator +// because the hash_set may call the hash function on the iterator when it is +// advanced, which could result in the hash function trying to deference a +// stale pointer. +template +void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) { + while (begin != end) { + ForwardIterator temp = begin; + ++begin; + delete *temp; + } +} + +// For a range within a container of pairs, calls delete (non-array version) on +// BOTH items in the pairs. +// NOTE: Like STLDeleteContainerPointers, it is important that this deletes +// behind the iterator because if both the key and value are deleted, the +// container may call the hash function on the iterator when it is advanced, +// which could result in the hash function trying to dereference a stale +// pointer. +template +void STLDeleteContainerPairPointers(ForwardIterator begin, + ForwardIterator end) { + while (begin != end) { + ForwardIterator temp = begin; + ++begin; + delete temp->first; + delete temp->second; + } +} + +// For a range within a container of pairs, calls delete (non-array version) on +// the FIRST item in the pairs. +// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator. +template +void STLDeleteContainerPairFirstPointers(ForwardIterator begin, + ForwardIterator end) { + while (begin != end) { + ForwardIterator temp = begin; + ++begin; + delete temp->first; + } +} + +// For a range within a container of pairs, calls delete. +// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator. +// Deleting the value does not always invalidate the iterator, but it may +// do so if the key is a pointer into the value object. +template +void STLDeleteContainerPairSecondPointers(ForwardIterator begin, + ForwardIterator end) { + while (begin != end) { + ForwardIterator temp = begin; + ++begin; + delete temp->second; + } +} + +// To treat a possibly-empty vector as an array, use these functions. +// If you know the array will never be empty, you can use &*v.begin() +// directly, but that is undefined behaviour if |v| is empty. +template +inline T* vector_as_array(std::vector* v) { + return v->empty() ? NULL : &*v->begin(); +} + +template +inline const T* vector_as_array(const std::vector* v) { + return v->empty() ? NULL : &*v->begin(); +} + +// Return a mutable char* pointing to a string's internal buffer, +// which may not be null-terminated. Writing through this pointer will +// modify the string. +// +// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the +// next call to a string method that invalidates iterators. +// +// As of 2006-04, there is no standard-blessed way of getting a +// mutable reference to a string's internal buffer. However, issue 530 +// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530) +// proposes this as the method. According to Matt Austern, this should +// already work on all current implementations. +inline char* string_as_array(std::string* str) { + // DO NOT USE const_cast(str->data()) + return str->empty() ? NULL : &*str->begin(); +} + +// The following functions are useful for cleaning up STL containers whose +// elements point to allocated memory. + +// STLDeleteElements() deletes all the elements in an STL container and clears +// the container. This function is suitable for use with a vector, set, +// hash_set, or any other STL container which defines sensible begin(), end(), +// and clear() methods. +// +// If container is NULL, this function is a no-op. +// +// As an alternative to calling STLDeleteElements() directly, consider +// STLElementDeleter (defined below), which ensures that your container's +// elements are deleted when the STLElementDeleter goes out of scope. +template +void STLDeleteElements(T* container) { + if (!container) + return; + STLDeleteContainerPointers(container->begin(), container->end()); + container->clear(); +} + +// Given an STL container consisting of (key, value) pairs, STLDeleteValues +// deletes all the "value" components and clears the container. Does nothing +// in the case it's given a NULL pointer. +template +void STLDeleteValues(T* container) { + if (!container) + return; + for (typename T::iterator i(container->begin()); i != container->end(); ++i) + delete i->second; + container->clear(); +} + + +// The following classes provide a convenient way to delete all elements or +// values from STL containers when they goes out of scope. This greatly +// simplifies code that creates temporary objects and has multiple return +// statements. Example: +// +// vector tmp_proto; +// STLElementDeleter > d(&tmp_proto); +// if (...) return false; +// ... +// return success; + +// Given a pointer to an STL container this class will delete all the element +// pointers when it goes out of scope. +template +class STLElementDeleter { + public: + STLElementDeleter(T* container) : container_(container) {} + ~STLElementDeleter() { STLDeleteElements(container_); } + + private: + T* container_; +}; + +// Given a pointer to an STL container this class will delete all the value +// pointers when it goes out of scope. +template +class STLValueDeleter { + public: + STLValueDeleter(T* container) : container_(container) {} + ~STLValueDeleter() { STLDeleteValues(container_); } + + private: + T* container_; +}; + +// Test to see if a set, map, hash_set or hash_map contains a particular key. +// Returns true if the key is in the collection. +template +bool ContainsKey(const Collection& collection, const Key& key) { + return collection.find(key) != collection.end(); +} + +// Returns true if the container is sorted. +template +bool STLIsSorted(const Container& cont) { + // Note: Use reverse iterator on container to ensure we only require + // value_type to implement operator<. + return std::adjacent_find(cont.rbegin(), cont.rend(), + std::less()) + == cont.rend(); +} + +// Returns a new ResultType containing the difference of two sorted containers. +template +ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) { + assert(STLIsSorted(a1)); + assert(STLIsSorted(a2)); + ResultType difference; + std::set_difference(a1.begin(), a1.end(), + a2.begin(), a2.end(), + std::inserter(difference, difference.end())); + return difference; +} + +// Returns a new ResultType containing the union of two sorted containers. +template +ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) { + assert(STLIsSorted(a1)); + assert(STLIsSorted(a2)); + ResultType result; + std::set_union(a1.begin(), a1.end(), + a2.begin(), a2.end(), + std::inserter(result, result.end())); + return result; +} + +// Returns a new ResultType containing the intersection of two sorted +// containers. +template +ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) { + assert(STLIsSorted(a1)); + assert(STLIsSorted(a2)); + ResultType result; + std::set_intersection(a1.begin(), a1.end(), + a2.begin(), a2.end(), + std::inserter(result, result.end())); + return result; +} + +// Returns true if the sorted container |a1| contains all elements of the sorted +// container |a2|. +template +bool STLIncludes(const Arg1& a1, const Arg2& a2) { + assert(STLIsSorted(a1)); + assert(STLIsSorted(a2)); + return std::includes(a1.begin(), a1.end(), + a2.begin(), a2.end()); +} + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STL_UTIL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/stringize_macros.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/stringize_macros.h new file mode 100644 index 0000000..ab8c43d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/stringize_macros.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Modified from the Chromium original: +// src/base/strings/stringize_macros.h + +// This file defines preprocessor macros for stringizing preprocessor +// symbols (or their output) and manipulating preprocessor symbols +// that define strings. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STRINGIZE_MACROS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STRINGIZE_MACROS_H_ + +// This is not very useful as it does not expand defined symbols if +// called directly. Use its counterpart without the _NO_EXPANSION +// suffix, below. +#define STRINGIZE_NO_EXPANSION(x) #x + +// Use this to quote the provided parameter, first expanding it if it +// is a preprocessor symbol. +// +// For example, if: +// #define A FOO +// #define B(x) myobj->FunctionCall(x) +// +// Then: +// STRINGIZE(A) produces "FOO" +// STRINGIZE(B(y)) produces "myobj->FunctionCall(y)" +#define STRINGIZE(x) STRINGIZE_NO_EXPANSION(x) + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STRINGIZE_MACROS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/template_util.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/template_util.h new file mode 100644 index 0000000..410e04c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/template_util.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Borrowed from Chromium's src/base/template_util.h. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TEMPLATE_UTIL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TEMPLATE_UTIL_H_ + +#include // For size_t. + +namespace webrtc { + +// Template definitions from tr1. + +template +struct integral_constant { + static const T value = v; + typedef T value_type; + typedef integral_constant type; +}; + +template const T integral_constant::value; + +typedef integral_constant true_type; +typedef integral_constant false_type; + +template struct is_pointer : false_type {}; +template struct is_pointer : true_type {}; + +template struct is_same : public false_type {}; +template struct is_same : true_type {}; + +template struct is_array : public false_type {}; +template struct is_array : public true_type {}; +template struct is_array : public true_type {}; + +template struct is_non_const_reference : false_type {}; +template struct is_non_const_reference : true_type {}; +template struct is_non_const_reference : false_type {}; + +template struct is_void : false_type {}; +template <> struct is_void : true_type {}; + +namespace internal { + +// Types YesType and NoType are guaranteed such that sizeof(YesType) < +// sizeof(NoType). +typedef char YesType; + +struct NoType { + YesType dummy[2]; +}; + +// This class is an implementation detail for is_convertible, and you +// don't need to know how it works to use is_convertible. For those +// who care: we declare two different functions, one whose argument is +// of type To and one with a variadic argument list. We give them +// return types of different size, so we can use sizeof to trick the +// compiler into telling us which function it would have chosen if we +// had called it with an argument of type From. See Alexandrescu's +// _Modern C++ Design_ for more details on this sort of trick. + +struct ConvertHelper { + template + static YesType Test(To); + + template + static NoType Test(...); + + template + static From& Create(); +}; + +// Used to determine if a type is a struct/union/class. Inspired by Boost's +// is_class type_trait implementation. +struct IsClassHelper { + template + static YesType Test(void(C::*)(void)); + + template + static NoType Test(...); +}; + +} // namespace internal + +// Inherits from true_type if From is convertible to To, false_type otherwise. +// +// Note that if the type is convertible, this will be a true_type REGARDLESS +// of whether or not the conversion would emit a warning. +template +struct is_convertible + : integral_constant( + internal::ConvertHelper::Create())) == + sizeof(internal::YesType)> { +}; + +template +struct is_class + : integral_constant(0)) == + sizeof(internal::YesType)> { +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TEMPLATE_UTIL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/thread_annotations.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/thread_annotations.h new file mode 100644 index 0000000..612242d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/thread_annotations.h @@ -0,0 +1,99 @@ +// +// Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// +// Borrowed from +// https://code.google.com/p/gperftools/source/browse/src/base/thread_annotations.h +// but adapted for clang attributes instead of the gcc. +// +// This header file contains the macro definitions for thread safety +// annotations that allow the developers to document the locking policies +// of their multi-threaded code. The annotations can also help program +// analysis tools to identify potential thread safety issues. + +#ifndef BASE_THREAD_ANNOTATIONS_H_ +#define BASE_THREAD_ANNOTATIONS_H_ + +#if defined(__clang__) && (!defined(SWIG)) +#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +// Document if a shared variable/field needs to be protected by a lock. +// GUARDED_BY allows the user to specify a particular lock that should be +// held when accessing the annotated variable, while GUARDED_VAR only +// indicates a shared variable should be guarded (by any lock). GUARDED_VAR +// is primarily used when the client cannot express the name of the lock. +#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) +#define GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(guarded) + +// Document if the memory location pointed to by a pointer should be guarded +// by a lock when dereferencing the pointer. Similar to GUARDED_VAR, +// PT_GUARDED_VAR is primarily used when the client cannot express the name +// of the lock. Note that a pointer variable to a shared memory location +// could itself be a shared variable. For example, if a shared global pointer +// q, which is guarded by mu1, points to a shared memory location that is +// guarded by mu2, q should be annotated as follows: +// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2); +#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded_by(x)) +#define PT_GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded) + +// Document the acquisition order between locks that can be held +// simultaneously by a thread. For any two locks that need to be annotated +// to establish an acquisition order, only one of them needs the annotation. +// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER +// and ACQUIRED_BEFORE.) +#define ACQUIRED_AFTER(x) THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x)) +#define ACQUIRED_BEFORE(x) THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x)) + +// The following three annotations document the lock requirements for +// functions/methods. + +// Document if a function expects certain locks to be held before it is called +#define EXCLUSIVE_LOCKS_REQUIRED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) + +#define SHARED_LOCKS_REQUIRED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) + +// Document the locks acquired in the body of the function. These locks +// cannot be held when calling this function (as google3's Mutex locks are +// non-reentrant). +#define LOCKS_EXCLUDED(x) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(x)) + +// Document the lock the annotated function returns without acquiring it. +#define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +// Document if a class/type is a lockable type (such as the Mutex class). +#define LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(lockable) + +// Document if a class is a scoped lockable type (such as the MutexLock class). +#define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +// The following annotations specify lock and unlock primitives. +#define EXCLUSIVE_LOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) + +#define SHARED_LOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) + +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) + +#define SHARED_TRYLOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) + +#define UNLOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) + +// An escape hatch for thread safety analysis to ignore the annotated function. +#define NO_THREAD_SAFETY_ANALYSIS \ + THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +#endif // BASE_THREAD_ANNOTATIONS_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/thread_wrapper.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/thread_wrapper.h new file mode 100644 index 0000000..7fbf58c --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/thread_wrapper.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// System independant wrapper for spawning threads +// Note: the spawned thread will loop over the callback function until stopped. +// Note: The callback function is expected to return every 2 seconds or more +// often. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ + +#include "webrtc/common_types.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +// Object that will be passed by the spawned thread when it enters the callback +// function. +#define ThreadObj void* + +// Callback function that the spawned thread will enter once spawned. +// A return value of false is interpreted as that the function has no +// more work to do and that the thread can be released. +typedef bool(*ThreadRunFunction)(ThreadObj); + +enum ThreadPriority { + kLowPriority = 1, + kNormalPriority = 2, + kHighPriority = 3, + kHighestPriority = 4, + kRealtimePriority = 5 +}; + +class ThreadWrapper { + public: + enum {kThreadMaxNameLength = 64}; + + virtual ~ThreadWrapper() {}; + + // Factory method. Constructor disabled. + // + // func Pointer to a, by user, specified callback function. + // obj Object associated with the thread. Passed in the callback + // function. + // prio Thread priority. May require root/admin rights. + // thread_name NULL terminated thread name, will be visable in the Windows + // debugger. + static ThreadWrapper* CreateThread(ThreadRunFunction func, + ThreadObj obj, + ThreadPriority prio = kNormalPriority, + const char* thread_name = 0); + + // Get the current thread's kernel thread ID. + static uint32_t GetThreadId(); + + // Non blocking termination of the spawned thread. Note that it is not safe + // to delete this class until the spawned thread has been reclaimed. + virtual void SetNotAlive() = 0; + + // Tries to spawns a thread and returns true if that was successful. + // Additionally, it tries to set thread priority according to the priority + // from when CreateThread was called. However, failure to set priority will + // not result in a false return value. + // TODO(henrike): add a function for polling whether priority was set or + // not. + virtual bool Start(unsigned int& id) = 0; + + // Sets the threads CPU affinity. CPUs are listed 0 - (number of CPUs - 1). + // The numbers in processor_numbers specify which CPUs are allowed to run the + // thread. processor_numbers should not contain any duplicates and elements + // should be lower than (number of CPUs - 1). amount_of_processors should be + // equal to the number of processors listed in processor_numbers. + virtual bool SetAffinity(const int* processor_numbers, + const unsigned int amount_of_processors); + + // Stops the spawned thread and waits for it to be reclaimed with a timeout + // of two seconds. Will return false if the thread was not reclaimed. + // Multiple tries to Stop are allowed (e.g. to wait longer than 2 seconds). + // It's ok to call Stop() even if the spawned thread has been reclaimed. + virtual bool Stop() = 0; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/tick_util.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/tick_util.h new file mode 100644 index 0000000..0b7890e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/tick_util.h @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// System independant wrapper for polling elapsed time in ms and us. +// The implementation works in the tick domain which can be mapped over to the +// time domain. +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_ + +#if _WIN32 +// Note: The Windows header must always be included before mmsystem.h +#include +#include +#elif WEBRTC_LINUX +#include +#elif WEBRTC_MAC +#include +#include +#else +#include +#include +#endif + +#include "webrtc/typedefs.h" + +namespace webrtc { + +class TickInterval; + +// Class representing the current time. +class TickTime { + public: + TickTime(); + explicit TickTime(int64_t ticks); + + // Current time in the tick domain. + static TickTime Now(); + + // Now in the time domain in ms. + static int64_t MillisecondTimestamp(); + + // Now in the time domain in us. + static int64_t MicrosecondTimestamp(); + + // Returns the number of ticks in the tick domain. + int64_t Ticks() const; + + static int64_t MillisecondsToTicks(const int64_t ms); + + static int64_t TicksToMilliseconds(const int64_t ticks); + + // Returns a TickTime that is ticks later than the passed TickTime. + friend TickTime operator+(const TickTime lhs, const int64_t ticks); + TickTime& operator+=(const int64_t& ticks); + + // Returns a TickInterval that is the difference in ticks beween rhs and lhs. + friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs); + + // Call to engage the fake clock. This is useful for tests since relying on + // a real clock often makes the test flaky. + static void UseFakeClock(int64_t start_millisecond); + + // Advance the fake clock. Must be called after UseFakeClock. + static void AdvanceFakeClock(int64_t milliseconds); + + private: + static int64_t QueryOsForTicks(); + + static bool use_fake_clock_; + static int64_t fake_ticks_; + + int64_t ticks_; +}; + +// Represents a time delta in ticks. +class TickInterval { + public: + TickInterval(); + + int64_t Milliseconds() const; + int64_t Microseconds() const; + + // Returns the sum of two TickIntervals as a TickInterval. + friend TickInterval operator+(const TickInterval& lhs, + const TickInterval& rhs); + TickInterval& operator+=(const TickInterval& rhs); + + // Returns a TickInterval corresponding to rhs - lhs. + friend TickInterval operator-(const TickInterval& lhs, + const TickInterval& rhs); + TickInterval& operator-=(const TickInterval& rhs); + + friend bool operator>(const TickInterval& lhs, const TickInterval& rhs); + friend bool operator<=(const TickInterval& lhs, const TickInterval& rhs); + friend bool operator<(const TickInterval& lhs, const TickInterval& rhs); + friend bool operator>=(const TickInterval& lhs, const TickInterval& rhs); + + private: + explicit TickInterval(int64_t interval); + + friend class TickTime; + friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs); + + private: + int64_t interval_; +}; + +inline TickInterval operator+(const TickInterval& lhs, + const TickInterval& rhs) { + return TickInterval(lhs.interval_ + rhs.interval_); +} + +inline TickInterval operator-(const TickInterval& lhs, + const TickInterval& rhs) { + return TickInterval(lhs.interval_ - rhs.interval_); +} + +inline TickInterval operator-(const TickTime& lhs, const TickTime& rhs) { + return TickInterval(lhs.ticks_ - rhs.ticks_); +} + +inline TickTime operator+(const TickTime lhs, const int64_t ticks) { + TickTime time = lhs; + time.ticks_ += ticks; + return time; +} + +inline bool operator>(const TickInterval& lhs, const TickInterval& rhs) { + return lhs.interval_ > rhs.interval_; +} + +inline bool operator<=(const TickInterval& lhs, const TickInterval& rhs) { + return lhs.interval_ <= rhs.interval_; +} + +inline bool operator<(const TickInterval& lhs, const TickInterval& rhs) { + return lhs.interval_ <= rhs.interval_; +} + +inline bool operator>=(const TickInterval& lhs, const TickInterval& rhs) { + return lhs.interval_ >= rhs.interval_; +} + +inline TickTime::TickTime() + : ticks_(0) { +} + +inline TickTime::TickTime(int64_t ticks) + : ticks_(ticks) { +} + +inline TickTime TickTime::Now() { + if (use_fake_clock_) + return TickTime(fake_ticks_); + else + return TickTime(QueryOsForTicks()); +} + +inline int64_t TickTime::MillisecondTimestamp() { + int64_t ticks = TickTime::Now().Ticks(); +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (ticks * 1000) / qpfreq.QuadPart; +#else + return ticks; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + return ticks / 1000000LL; +#else + return ticks / 1000LL; +#endif +} + +inline int64_t TickTime::MicrosecondTimestamp() { + int64_t ticks = TickTime::Now().Ticks(); +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (ticks * 1000) / (qpfreq.QuadPart / 1000); +#else + return ticks * 1000LL; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + return ticks / 1000LL; +#else + return ticks; +#endif +} + +inline int64_t TickTime::Ticks() const { + return ticks_; +} + +inline int64_t TickTime::MillisecondsToTicks(const int64_t ms) { +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (qpfreq.QuadPart * ms) / 1000; +#else + return ms; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + return ms * 1000000LL; +#else + return ms * 1000LL; +#endif +} + +inline int64_t TickTime::TicksToMilliseconds(const int64_t ticks) { +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (ticks * 1000) / qpfreq.QuadPart; +#else + return ticks; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + return ticks / 1000000LL; +#else + return ticks / 1000LL; +#endif +} + +inline TickTime& TickTime::operator+=(const int64_t& ticks) { + ticks_ += ticks; + return *this; +} + +inline TickInterval::TickInterval() : interval_(0) { +} + +inline TickInterval::TickInterval(const int64_t interval) + : interval_(interval) { +} + +inline int64_t TickInterval::Milliseconds() const { +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (interval_ * 1000) / qpfreq.QuadPart; +#else + // interval_ is in ms + return interval_; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + // interval_ is in ns + return interval_ / 1000000; +#else + // interval_ is usecs + return interval_ / 1000; +#endif +} + +inline int64_t TickInterval::Microseconds() const { +#if _WIN32 +#ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (interval_ * 1000000) / qpfreq.QuadPart; +#else + // interval_ is in ms + return interval_ * 1000LL; +#endif +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) + // interval_ is in ns + return interval_ / 1000; +#else + // interval_ is usecs + return interval_; +#endif +} + +inline TickInterval& TickInterval::operator+=(const TickInterval& rhs) { + interval_ += rhs.interval_; + return *this; +} + +inline TickInterval& TickInterval::operator-=(const TickInterval& rhs) { + interval_ -= rhs.interval_; + return *this; +} + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/timestamp_extrapolator.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/timestamp_extrapolator.h new file mode 100644 index 0000000..d067198 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/timestamp_extrapolator.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef SYSTEM_WRAPPERS_INTERFACE_TIMESTAMP_EXTRAPOLATOR_H_ +#define SYSTEM_WRAPPERS_INTERFACE_TIMESTAMP_EXTRAPOLATOR_H_ + +#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h" +#include "webrtc/typedefs.h" + +namespace webrtc +{ + +class TimestampExtrapolator +{ +public: + explicit TimestampExtrapolator(int64_t start_ms); + ~TimestampExtrapolator(); + void Update(int64_t tMs, uint32_t ts90khz); + int64_t ExtrapolateLocalTime(uint32_t timestamp90khz); + void Reset(int64_t start_ms); + +private: + void CheckForWrapArounds(uint32_t ts90khz); + bool DelayChangeDetection(double error); + RWLockWrapper* _rwLock; + double _w[2]; + double _P[2][2]; + int64_t _startMs; + int64_t _prevMs; + uint32_t _firstTimestamp; + int32_t _wrapArounds; + int64_t _prevUnwrappedTimestamp; + int64_t _prevWrapTimestamp; + const double _lambda; + bool _firstAfterReset; + uint32_t _packetCount; + const uint32_t _startUpFilterDelayInPackets; + + double _detectorAccumulatorPos; + double _detectorAccumulatorNeg; + const double _alarmThreshold; + const double _accDrift; + const double _accMaxError; + const double _P11; +}; + +} // namespace webrtc + +#endif // SYSTEM_WRAPPERS_INTERFACE_TIMESTAMP_EXTRAPOLATOR_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/trace.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/trace.h new file mode 100644 index 0000000..44ea658 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/trace.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + * System independent wrapper for logging runtime information to file. + * Note: All log messages will be written to the same trace file. + * Note: If too many messages are written to file there will be a build up of + * messages. Apply filtering to avoid that. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_ + +#include "webrtc/common_types.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +#if defined(WEBRTC_RESTRICT_LOGGING) +// Disable all TRACE macros. The LOG macro is still functional. +#define WEBRTC_TRACE true ? (void) 0 : Trace::Add +#else +#define WEBRTC_TRACE Trace::Add +#endif + +class Trace { + public: + // The length of the trace text preceeding the log message. + static const int kBoilerplateLength; + // The position of the timestamp text within a trace. + static const int kTimestampPosition; + // The length of the timestamp (without "delta" field). + static const int kTimestampLength; + + // Increments the reference count to the trace. + static void CreateTrace(); + // Decrements the reference count to the trace. + static void ReturnTrace(); + // Note: any instance that writes to the trace file should increment and + // decrement the reference count on construction and destruction, + // respectively. + + // Specifies what type of messages should be written to the trace file. The + // filter parameter is a bitmask where each message type is enumerated by the + // TraceLevel enumerator. TODO(hellner): why is the TraceLevel enumerator not + // defined in this file? + static void set_level_filter(uint32_t filter) { level_filter_ = filter; } + + // Returns what type of messages are written to the trace file. + static uint32_t level_filter() { return level_filter_; } + + // Sets the file name. If add_file_counter is false the same file will be + // reused when it fills up. If it's true a new file with incremented name + // will be used. + static int32_t SetTraceFile(const char* file_name, + const bool add_file_counter = false); + + // Returns the name of the file that the trace is currently writing to. + static int32_t TraceFile(char file_name[1024]); + + // Registers callback to receive trace messages. + // TODO(hellner): Why not use OutStream instead? Why is TraceCallback not + // defined in this file? + static int32_t SetTraceCallback(TraceCallback* callback); + + // Adds a trace message for writing to file. The message is put in a queue + // for writing to file whenever possible for performance reasons. I.e. there + // is a crash it is possible that the last, vital logs are not logged yet. + // level is the type of message to log. If that type of messages is + // filtered it will not be written to file. module is an identifier for what + // part of the code the message is coming. + // id is an identifier that should be unique for that set of classes that + // are associated (e.g. all instances owned by an engine). + // msg and the ellipsis are the same as e.g. sprintf. + // TODO(hellner) Why is TraceModule not defined in this file? + static void Add(const TraceLevel level, + const TraceModule module, + const int32_t id, + const char* msg, ...); + + private: + static uint32_t level_filter_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/trace_event.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/trace_event.h new file mode 100644 index 0000000..23b16c7 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/trace_event.h @@ -0,0 +1,912 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file under third_party_mods/chromium or at: +// http://src.chromium.org/svn/trunk/src/LICENSE + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_EVENT_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_EVENT_H_ + +#include + +#include "webrtc/system_wrappers/interface/event_tracer.h" + +#if defined(TRACE_EVENT0) +#error "Another copy of trace_event.h has already been included." +#endif + +// Extracted from Chromium's src/base/debug/trace_event.h. + +// This header is designed to give you trace_event macros without specifying +// how the events actually get collected and stored. If you need to expose trace +// event to some other universe, you can copy-and-paste this file, +// implement the TRACE_EVENT_API macros, and do any other necessary fixup for +// the target platform. The end result is that multiple libraries can funnel +// events through to a shared trace event collector. + +// Trace events are for tracking application performance and resource usage. +// Macros are provided to track: +// Begin and end of function calls +// Counters +// +// Events are issued against categories. Whereas LOG's +// categories are statically defined, TRACE categories are created +// implicitly with a string. For example: +// TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent") +// +// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope: +// TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly") +// doSomethingCostly() +// TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly") +// Note: our tools can't always determine the correct BEGIN/END pairs unless +// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you +// need them to be in separate scopes. +// +// A common use case is to trace entire function scopes. This +// issues a trace BEGIN and END automatically: +// void doSomethingCostly() { +// TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly"); +// ... +// } +// +// Additional parameters can be associated with an event: +// void doSomethingCostly2(int howMuch) { +// TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly", +// "howMuch", howMuch); +// ... +// } +// +// The trace system will automatically add to this information the +// current process id, thread id, and a timestamp in microseconds. +// +// To trace an asynchronous procedure such as an IPC send/receive, use +// ASYNC_BEGIN and ASYNC_END: +// [single threaded sender code] +// static int send_count = 0; +// ++send_count; +// TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count); +// Send(new MyMessage(send_count)); +// [receive code] +// void OnMyMessage(send_count) { +// TRACE_EVENT_ASYNC_END0("ipc", "message", send_count); +// } +// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs. +// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process. +// Pointers can be used for the ID parameter, and they will be mangled +// internally so that the same pointer on two different processes will not +// match. For example: +// class MyTracedClass { +// public: +// MyTracedClass() { +// TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this); +// } +// ~MyTracedClass() { +// TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this); +// } +// } +// +// Trace event also supports counters, which is a way to track a quantity +// as it varies over time. Counters are created with the following macro: +// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue); +// +// Counters are process-specific. The macro itself can be issued from any +// thread, however. +// +// Sometimes, you want to track two counters at once. You can do this with two +// counter macros: +// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]); +// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]); +// Or you can do it with a combined macro: +// TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter", +// "bytesPinned", g_myCounterValue[0], +// "bytesAllocated", g_myCounterValue[1]); +// This indicates to the tracing UI that these counters should be displayed +// in a single graph, as a summed area chart. +// +// Since counters are in a global namespace, you may want to disembiguate with a +// unique ID, by using the TRACE_COUNTER_ID* variations. +// +// By default, trace collection is compiled in, but turned off at runtime. +// Collecting trace data is the responsibility of the embedding +// application. In Chrome's case, navigating to about:tracing will turn on +// tracing and display data collected across all active processes. +// +// +// Memory scoping note: +// Tracing copies the pointers, not the string content, of the strings passed +// in for category, name, and arg_names. Thus, the following code will +// cause problems: +// char* str = strdup("impprtantName"); +// TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD! +// free(str); // Trace system now has dangling pointer +// +// To avoid this issue with the |name| and |arg_name| parameters, use the +// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead. +// Notes: The category must always be in a long-lived char* (i.e. static const). +// The |arg_values|, when used, are always deep copied with the _COPY +// macros. +// +// When are string argument values copied: +// const char* arg_values are only referenced by default: +// TRACE_EVENT1("category", "name", +// "arg1", "literal string is only referenced"); +// Use TRACE_STR_COPY to force copying of a const char*: +// TRACE_EVENT1("category", "name", +// "arg1", TRACE_STR_COPY("string will be copied")); +// std::string arg_values are always copied: +// TRACE_EVENT1("category", "name", +// "arg1", std::string("string will be copied")); +// +// +// Thread Safety: +// Thread safety is provided by methods defined in event_tracer.h. See the file +// for details. + + +// By default, const char* argument values are assumed to have long-lived scope +// and will not be copied. Use this macro to force a const char* to be copied. +#define TRACE_STR_COPY(str) \ + webrtc::trace_event_internal::TraceStringWithCopy(str) + +// By default, uint64 ID argument values are not mangled with the Process ID in +// TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling. +#define TRACE_ID_MANGLE(id) \ + webrtc::trace_event_internal::TraceID::ForceMangle(id) + +// Records a pair of begin and end events called "name" for the current +// scope, with 0, 1 or 2 associated arguments. If the category is not +// enabled, then this does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_EVENT0(category, name) \ + INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name) +#define TRACE_EVENT1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val) +#define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) + +// Same as TRACE_EVENT except that they are not included in official builds. +#ifdef OFFICIAL_BUILD +#define UNSHIPPED_TRACE_EVENT0(category, name) (void)0 +#define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) (void)0 +#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) (void)0 +#define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) (void)0 +#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ + (void)0 +#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) (void)0 +#else +#define UNSHIPPED_TRACE_EVENT0(category, name) \ + TRACE_EVENT0(category, name) +#define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) \ + TRACE_EVENT1(category, name, arg1_name, arg1_val) +#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) +#define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) \ + TRACE_EVENT_INSTANT0(category, name) +#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ + TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) +#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) +#endif + +// Records a single event called "name" immediately, with 0, 1 or 2 +// associated arguments. If the category is not enabled, then this +// does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_EVENT_INSTANT0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ + arg2_name, arg2_val) +#define TRACE_EVENT_COPY_INSTANT0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) +#define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ + arg2_name, arg2_val) + +// Records a single BEGIN event called "name" immediately, with 0, 1 or 2 +// associated arguments. If the category is not enabled, then this +// does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_EVENT_BEGIN0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ + arg2_name, arg2_val) +#define TRACE_EVENT_COPY_BEGIN0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) +#define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ + arg2_name, arg2_val) + +// Records a single END event for "name" immediately. If the category +// is not enabled, then this does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_EVENT_END0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ + arg2_name, arg2_val) +#define TRACE_EVENT_COPY_END0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) +#define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ + arg2_name, arg2_val) + +// Records the value of a counter called "name" immediately. Value +// must be representable as a 32 bit integer. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_COUNTER1(category, name, value) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ + category, name, TRACE_EVENT_FLAG_NONE, \ + "value", static_cast(value)) +#define TRACE_COPY_COUNTER1(category, name, value) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ + category, name, TRACE_EVENT_FLAG_COPY, \ + "value", static_cast(value)) + +// Records the values of a multi-parted counter called "name" immediately. +// The UI will treat value1 and value2 as parts of a whole, displaying their +// values as a stacked-bar chart. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_COUNTER2(category, name, value1_name, value1_val, \ + value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ + category, name, TRACE_EVENT_FLAG_NONE, \ + value1_name, static_cast(value1_val), \ + value2_name, static_cast(value2_val)) +#define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \ + value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ + category, name, TRACE_EVENT_FLAG_COPY, \ + value1_name, static_cast(value1_val), \ + value2_name, static_cast(value2_val)) + +// Records the value of a counter called "name" immediately. Value +// must be representable as a 32 bit integer. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +// - |id| is used to disambiguate counters with the same name. It must either +// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits +// will be xored with a hash of the process ID so that the same pointer on +// two different processes will not collide. +#define TRACE_COUNTER_ID1(category, name, id, value) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ + category, name, id, TRACE_EVENT_FLAG_NONE, \ + "value", static_cast(value)) +#define TRACE_COPY_COUNTER_ID1(category, name, id, value) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + "value", static_cast(value)) + +// Records the values of a multi-parted counter called "name" immediately. +// The UI will treat value1 and value2 as parts of a whole, displaying their +// values as a stacked-bar chart. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +// - |id| is used to disambiguate counters with the same name. It must either +// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits +// will be xored with a hash of the process ID so that the same pointer on +// two different processes will not collide. +#define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \ + value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ + category, name, id, TRACE_EVENT_FLAG_NONE, \ + value1_name, static_cast(value1_val), \ + value2_name, static_cast(value2_val)) +#define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, \ + value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + value1_name, static_cast(value1_val), \ + value2_name, static_cast(value2_val)) + + +// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2 +// associated arguments. If the category is not enabled, then this +// does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC +// events are considered to match if their category, name and id values all +// match. |id| must either be a pointer or an integer value up to 64 bits. If +// it's a pointer, the bits will be xored with a hash of the process ID so +// that the same pointer on two different processes will not collide. +// An asynchronous operation can consist of multiple phases. The first phase is +// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the +// ASYNC_STEP macros. When the operation completes, call ASYNC_END. +// An ASYNC trace typically occur on a single thread (if not, they will only be +// drawn on the thread defined in the ASYNC_BEGIN event), but all events in that +// operation must use the same |name| and |id|. Each event can have its own +// args. +#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_NONE, \ + arg1_name, arg1_val, arg2_name, arg2_val) +#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val) +#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val, arg2_name, arg2_val) + +// Records a single ASYNC_STEP event for |step| immediately. If the category +// is not enabled, then this does nothing. The |name| and |id| must match the +// ASYNC_BEGIN event above. The |step| param identifies this step within the +// async event. This should be called at the beginning of the next phase of an +// asynchronous operation. +#define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ + category, name, id, TRACE_EVENT_FLAG_NONE, "step", step) +#define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, \ + arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ + category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \ + arg1_name, arg1_val) +#define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ + category, name, id, TRACE_EVENT_FLAG_COPY, "step", step) +#define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, \ + arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ + category, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \ + arg1_name, arg1_val) + +// Records a single ASYNC_END event for "name" immediately. If the category +// is not enabled, then this does nothing. +#define TRACE_EVENT_ASYNC_END0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_NONE, \ + arg1_name, arg1_val, arg2_name, arg2_val) +#define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val) +#define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val, arg2_name, arg2_val) + + +// Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2 +// associated arguments. If the category is not enabled, then this +// does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +// - |id| is used to match the FLOW_BEGIN event with the FLOW_END event. FLOW +// events are considered to match if their category, name and id values all +// match. |id| must either be a pointer or an integer value up to 64 bits. If +// it's a pointer, the bits will be xored with a hash of the process ID so +// that the same pointer on two different processes will not collide. +// FLOW events are different from ASYNC events in how they are drawn by the +// tracing UI. A FLOW defines asynchronous data flow, such as posting a task +// (FLOW_BEGIN) and later executing that task (FLOW_END). Expect FLOWs to be +// drawn as lines or arrows from FLOW_BEGIN scopes to FLOW_END scopes. Similar +// to ASYNC, a FLOW can consist of multiple phases. The first phase is defined +// by the FLOW_BEGIN calls. Additional phases can be defined using the FLOW_STEP +// macros. When the operation completes, call FLOW_END. An async operation can +// span threads and processes, but all events in that operation must use the +// same |name| and |id|. Each event can have its own args. +#define TRACE_EVENT_FLOW_BEGIN0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_NONE, \ + arg1_name, arg1_val, arg2_name, arg2_val) +#define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val) +#define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val, arg2_name, arg2_val) + +// Records a single FLOW_STEP event for |step| immediately. If the category +// is not enabled, then this does nothing. The |name| and |id| must match the +// FLOW_BEGIN event above. The |step| param identifies this step within the +// async event. This should be called at the beginning of the next phase of an +// asynchronous operation. +#define TRACE_EVENT_FLOW_STEP0(category, name, id, step) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ + category, name, id, TRACE_EVENT_FLAG_NONE, "step", step) +#define TRACE_EVENT_FLOW_STEP1(category, name, id, step, \ + arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ + category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \ + arg1_name, arg1_val) +#define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ + category, name, id, TRACE_EVENT_FLAG_COPY, "step", step) +#define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, \ + arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ + category, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \ + arg1_name, arg1_val) + +// Records a single FLOW_END event for "name" immediately. If the category +// is not enabled, then this does nothing. +#define TRACE_EVENT_FLOW_END0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ + category, name, id, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ + category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ + category, name, id, TRACE_EVENT_FLAG_NONE, \ + arg1_name, arg1_val, arg2_name, arg2_val) +#define TRACE_EVENT_COPY_FLOW_END0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ + category, name, id, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val) +#define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val, arg2_name, arg2_val) + + +//////////////////////////////////////////////////////////////////////////////// +// Implementation specific tracing API definitions. + +// Get a pointer to the enabled state of the given trace category. Only +// long-lived literal strings should be given as the category name. The returned +// pointer can be held permanently in a local static for example. If the +// unsigned char is non-zero, tracing is enabled. If tracing is enabled, +// TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled +// between the load of the tracing state and the call to +// TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out +// for best performance when tracing is disabled. +// const unsigned char* +// TRACE_EVENT_API_GET_CATEGORY_ENABLED(const char* category_name) +#define TRACE_EVENT_API_GET_CATEGORY_ENABLED \ + webrtc::EventTracer::GetCategoryEnabled + +// Add a trace event to the platform tracing system. +// void TRACE_EVENT_API_ADD_TRACE_EVENT( +// char phase, +// const unsigned char* category_enabled, +// const char* name, +// unsigned long long id, +// int num_args, +// const char** arg_names, +// const unsigned char* arg_types, +// const unsigned long long* arg_values, +// unsigned char flags) +#define TRACE_EVENT_API_ADD_TRACE_EVENT webrtc::EventTracer::AddTraceEvent + +//////////////////////////////////////////////////////////////////////////////// + +// Implementation detail: trace event macros create temporary variables +// to keep instrumentation overhead low. These macros give each temporary +// variable a unique name based on the line number to prevent name collissions. +#define INTERNAL_TRACE_EVENT_UID3(a,b) \ + trace_event_unique_##a##b +#define INTERNAL_TRACE_EVENT_UID2(a,b) \ + INTERNAL_TRACE_EVENT_UID3(a,b) +#define INTERNAL_TRACE_EVENT_UID(name_prefix) \ + INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__) + +// Implementation detail: internal macro to create static category. +#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category) \ + static const unsigned char* INTERNAL_TRACE_EVENT_UID(catstatic) = 0; \ + if (!INTERNAL_TRACE_EVENT_UID(catstatic)) { \ + INTERNAL_TRACE_EVENT_UID(catstatic) = \ + TRACE_EVENT_API_GET_CATEGORY_ENABLED(category); \ + } + +// Implementation detail: internal macro to create static category and add +// event if the category is enabled. +#define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \ + do { \ + INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ + if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ + webrtc::trace_event_internal::AddTraceEvent( \ + phase, INTERNAL_TRACE_EVENT_UID(catstatic), name, \ + webrtc::trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \ + } \ + } while (0) + +// Implementation detail: internal macro to create static category and add begin +// event if the category is enabled. Also adds the end event when the scope +// ends. +#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \ + INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ + webrtc::trace_event_internal::TraceEndOnScopeClose \ + INTERNAL_TRACE_EVENT_UID(profileScope); \ + if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ + webrtc::trace_event_internal::AddTraceEvent( \ + TRACE_EVENT_PHASE_BEGIN, \ + INTERNAL_TRACE_EVENT_UID(catstatic), \ + name, webrtc::trace_event_internal::kNoEventId, \ + TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \ + INTERNAL_TRACE_EVENT_UID(profileScope).Initialize( \ + INTERNAL_TRACE_EVENT_UID(catstatic), name); \ + } + +// Implementation detail: internal macro to create static category and add +// event if the category is enabled. +#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category, name, id, flags, \ + ...) \ + do { \ + INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ + if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ + unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \ + webrtc::trace_event_internal::TraceID trace_event_trace_id( \ + id, &trace_event_flags); \ + webrtc::trace_event_internal::AddTraceEvent( \ + phase, INTERNAL_TRACE_EVENT_UID(catstatic), \ + name, trace_event_trace_id.data(), trace_event_flags, \ + ##__VA_ARGS__); \ + } \ + } while (0) + +// Notes regarding the following definitions: +// New values can be added and propagated to third party libraries, but existing +// definitions must never be changed, because third party libraries may use old +// definitions. + +// Phase indicates the nature of an event entry. E.g. part of a begin/end pair. +#define TRACE_EVENT_PHASE_BEGIN ('B') +#define TRACE_EVENT_PHASE_END ('E') +#define TRACE_EVENT_PHASE_INSTANT ('I') +#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S') +#define TRACE_EVENT_PHASE_ASYNC_STEP ('T') +#define TRACE_EVENT_PHASE_ASYNC_END ('F') +#define TRACE_EVENT_PHASE_FLOW_BEGIN ('s') +#define TRACE_EVENT_PHASE_FLOW_STEP ('t') +#define TRACE_EVENT_PHASE_FLOW_END ('f') +#define TRACE_EVENT_PHASE_METADATA ('M') +#define TRACE_EVENT_PHASE_COUNTER ('C') + +// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT. +#define TRACE_EVENT_FLAG_NONE (static_cast(0)) +#define TRACE_EVENT_FLAG_COPY (static_cast(1 << 0)) +#define TRACE_EVENT_FLAG_HAS_ID (static_cast(1 << 1)) +#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast(1 << 2)) + +// Type values for identifying types in the TraceValue union. +#define TRACE_VALUE_TYPE_BOOL (static_cast(1)) +#define TRACE_VALUE_TYPE_UINT (static_cast(2)) +#define TRACE_VALUE_TYPE_INT (static_cast(3)) +#define TRACE_VALUE_TYPE_DOUBLE (static_cast(4)) +#define TRACE_VALUE_TYPE_POINTER (static_cast(5)) +#define TRACE_VALUE_TYPE_STRING (static_cast(6)) +#define TRACE_VALUE_TYPE_COPY_STRING (static_cast(7)) + +namespace webrtc { +namespace trace_event_internal { + +// Specify these values when the corresponding argument of AddTraceEvent is not +// used. +const int kZeroNumArgs = 0; +const unsigned long long kNoEventId = 0; + +// TraceID encapsulates an ID that can either be an integer or pointer. Pointers +// are mangled with the Process ID so that they are unlikely to collide when the +// same pointer is used on different processes. +class TraceID { + public: + class ForceMangle { + public: + explicit ForceMangle(unsigned long long id) : data_(id) {} + explicit ForceMangle(unsigned long id) : data_(id) {} + explicit ForceMangle(unsigned int id) : data_(id) {} + explicit ForceMangle(unsigned short id) : data_(id) {} + explicit ForceMangle(unsigned char id) : data_(id) {} + explicit ForceMangle(long long id) + : data_(static_cast(id)) {} + explicit ForceMangle(long id) + : data_(static_cast(id)) {} + explicit ForceMangle(int id) + : data_(static_cast(id)) {} + explicit ForceMangle(short id) + : data_(static_cast(id)) {} + explicit ForceMangle(signed char id) + : data_(static_cast(id)) {} + + unsigned long long data() const { return data_; } + + private: + unsigned long long data_; + }; + + explicit TraceID(const void* id, unsigned char* flags) + : data_(static_cast( + reinterpret_cast(id))) { + *flags |= TRACE_EVENT_FLAG_MANGLE_ID; + } + explicit TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) { + *flags |= TRACE_EVENT_FLAG_MANGLE_ID; + } + explicit TraceID(unsigned long long id, unsigned char* flags) + : data_(id) { (void)flags; } + explicit TraceID(unsigned long id, unsigned char* flags) + : data_(id) { (void)flags; } + explicit TraceID(unsigned int id, unsigned char* flags) + : data_(id) { (void)flags; } + explicit TraceID(unsigned short id, unsigned char* flags) + : data_(id) { (void)flags; } + explicit TraceID(unsigned char id, unsigned char* flags) + : data_(id) { (void)flags; } + explicit TraceID(long long id, unsigned char* flags) + : data_(static_cast(id)) { (void)flags; } + explicit TraceID(long id, unsigned char* flags) + : data_(static_cast(id)) { (void)flags; } + explicit TraceID(int id, unsigned char* flags) + : data_(static_cast(id)) { (void)flags; } + explicit TraceID(short id, unsigned char* flags) + : data_(static_cast(id)) { (void)flags; } + explicit TraceID(signed char id, unsigned char* flags) + : data_(static_cast(id)) { (void)flags; } + + unsigned long long data() const { return data_; } + + private: + unsigned long long data_; +}; + +// Simple union to store various types as unsigned long long. +union TraceValueUnion { + bool as_bool; + unsigned long long as_uint; + long long as_int; + double as_double; + const void* as_pointer; + const char* as_string; +}; + +// Simple container for const char* that should be copied instead of retained. +class TraceStringWithCopy { + public: + explicit TraceStringWithCopy(const char* str) : str_(str) {} + operator const char* () const { return str_; } + private: + const char* str_; +}; + +// Define SetTraceValue for each allowed type. It stores the type and +// value in the return arguments. This allows this API to avoid declaring any +// structures so that it is portable to third_party libraries. +#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \ + union_member, \ + value_type_id) \ + static inline void SetTraceValue(actual_type arg, \ + unsigned char* type, \ + unsigned long long* value) { \ + TraceValueUnion type_value; \ + type_value.union_member = arg; \ + *type = value_type_id; \ + *value = type_value.as_uint; \ + } +// Simpler form for int types that can be safely casted. +#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \ + value_type_id) \ + static inline void SetTraceValue(actual_type arg, \ + unsigned char* type, \ + unsigned long long* value) { \ + *type = value_type_id; \ + *value = static_cast(arg); \ + } + +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long, TRACE_VALUE_TYPE_UINT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT) +INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL) +INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE) +INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer, + TRACE_VALUE_TYPE_POINTER) +INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string, + TRACE_VALUE_TYPE_STRING) +INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string, + TRACE_VALUE_TYPE_COPY_STRING) + +#undef INTERNAL_DECLARE_SET_TRACE_VALUE +#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT + +// std::string version of SetTraceValue so that trace arguments can be strings. +static inline void SetTraceValue(const std::string& arg, + unsigned char* type, + unsigned long long* value) { + TraceValueUnion type_value; + type_value.as_string = arg.c_str(); + *type = TRACE_VALUE_TYPE_COPY_STRING; + *value = type_value.as_uint; +} + +// These AddTraceEvent template functions are defined here instead of in the +// macro, because the arg_values could be temporary objects, such as +// std::string. In order to store pointers to the internal c_str and pass +// through to the tracing API, the arg_values must live throughout +// these procedures. + +static inline void AddTraceEvent(char phase, + const unsigned char* category_enabled, + const char* name, + unsigned long long id, + unsigned char flags) { + TRACE_EVENT_API_ADD_TRACE_EVENT( + phase, category_enabled, name, id, + kZeroNumArgs, NULL, NULL, NULL, + flags); +} + +template +static inline void AddTraceEvent(char phase, + const unsigned char* category_enabled, + const char* name, + unsigned long long id, + unsigned char flags, + const char* arg1_name, + const ARG1_TYPE& arg1_val) { + const int num_args = 1; + unsigned char arg_types[1]; + unsigned long long arg_values[1]; + SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); + TRACE_EVENT_API_ADD_TRACE_EVENT( + phase, category_enabled, name, id, + num_args, &arg1_name, arg_types, arg_values, + flags); +} + +template +static inline void AddTraceEvent(char phase, + const unsigned char* category_enabled, + const char* name, + unsigned long long id, + unsigned char flags, + const char* arg1_name, + const ARG1_TYPE& arg1_val, + const char* arg2_name, + const ARG2_TYPE& arg2_val) { + const int num_args = 2; + const char* arg_names[2] = { arg1_name, arg2_name }; + unsigned char arg_types[2]; + unsigned long long arg_values[2]; + SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); + SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]); + TRACE_EVENT_API_ADD_TRACE_EVENT( + phase, category_enabled, name, id, + num_args, arg_names, arg_types, arg_values, + flags); +} + +// Used by TRACE_EVENTx macro. Do not use directly. +class TraceEndOnScopeClose { + public: + // Note: members of data_ intentionally left uninitialized. See Initialize. + TraceEndOnScopeClose() : p_data_(NULL) {} + ~TraceEndOnScopeClose() { + if (p_data_) + AddEventIfEnabled(); + } + + void Initialize(const unsigned char* category_enabled, + const char* name) { + data_.category_enabled = category_enabled; + data_.name = name; + p_data_ = &data_; + } + + private: + // Add the end event if the category is still enabled. + void AddEventIfEnabled() { + // Only called when p_data_ is non-null. + if (*p_data_->category_enabled) { + TRACE_EVENT_API_ADD_TRACE_EVENT( + TRACE_EVENT_PHASE_END, + p_data_->category_enabled, + p_data_->name, kNoEventId, + kZeroNumArgs, NULL, NULL, NULL, + TRACE_EVENT_FLAG_NONE); + } + } + + // This Data struct workaround is to avoid initializing all the members + // in Data during construction of this object, since this object is always + // constructed, even when tracing is disabled. If the members of Data were + // members of this class instead, compiler warnings occur about potential + // uninitialized accesses. + struct Data { + const unsigned char* category_enabled; + const char* name; + }; + Data* p_data_; + Data data_; +}; + +} // namespace trace_event_internal +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_EVENT_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/utf_util_win.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/utf_util_win.h new file mode 100644 index 0000000..f88f079 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/interface/utf_util_win.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Conversion functions for UTF-8 and UTF-16 strings on Windows. +// Duplicated from talk/base/win32.h. +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_UTF_UTIL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_UTF_UTIL_H_ + +#ifdef WIN32 +#include +#include + +#include "webrtc/system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { + +inline std::wstring ToUtf16(const char* utf8, size_t len) { + int len16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast(len), + NULL, 0); + scoped_ptr ws(new wchar_t[len16]); + ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast(len), ws.get(), + len16); + return std::wstring(ws.get(), len16); +} + +inline std::wstring ToUtf16(const std::string& str) { + return ToUtf16(str.data(), str.length()); +} + +inline std::string ToUtf8(const wchar_t* wide, size_t len) { + int len8 = ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast(len), + NULL, 0, NULL, NULL); + scoped_ptr ns(new char[len8]); + ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast(len), ns.get(), len8, + NULL, NULL); + return std::string(ns.get(), len8); +} + +inline std::string ToUtf8(const wchar_t* wide) { + return ToUtf8(wide, wcslen(wide)); +} + +inline std::string ToUtf8(const std::wstring& wstr) { + return ToUtf8(wstr.data(), wstr.length()); +} + +} // namespace webrtc + +#endif // WIN32 +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_UTF_UTIL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_event_win.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_event_win.h new file mode 100644 index 0000000..fce45d3 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_event_win.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_ + +#include + +#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h" + +namespace webrtc { + +class ConditionVariableEventWin : public ConditionVariableWrapper { + public: + ConditionVariableEventWin(); + virtual ~ConditionVariableEventWin(); + + void SleepCS(CriticalSectionWrapper& crit_sect); + bool SleepCS(CriticalSectionWrapper& crit_sect, unsigned long max_time_inMS); + void Wake(); + void WakeAll(); + + private: + enum EventWakeUpType { + WAKEALL_0 = 0, + WAKEALL_1 = 1, + WAKE = 2, + EVENT_COUNT = 3 + }; + + unsigned int num_waiters_[2]; + EventWakeUpType eventID_; + CRITICAL_SECTION num_waiters_crit_sect_; + HANDLE events_[EVENT_COUNT]; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_native_win.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_native_win.h new file mode 100644 index 0000000..1fbce37 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_native_win.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_ + +#include + +#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h" + +namespace webrtc { + +#if !defined CONDITION_VARIABLE_INIT +typedef struct RTL_CONDITION_VARIABLE_ { + void* Ptr; +} RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; + +typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; +#endif + +typedef void (WINAPI* PInitializeConditionVariable)(PCONDITION_VARIABLE); +typedef BOOL (WINAPI* PSleepConditionVariableCS)(PCONDITION_VARIABLE, + PCRITICAL_SECTION, DWORD); +typedef void (WINAPI* PWakeConditionVariable)(PCONDITION_VARIABLE); +typedef void (WINAPI* PWakeAllConditionVariable)(PCONDITION_VARIABLE); + +class ConditionVariableNativeWin : public ConditionVariableWrapper { + public: + static ConditionVariableWrapper* Create(); + virtual ~ConditionVariableNativeWin(); + + void SleepCS(CriticalSectionWrapper& crit_sect); + bool SleepCS(CriticalSectionWrapper& crit_sect, unsigned long max_time_inMS); + void Wake(); + void WakeAll(); + + private: + ConditionVariableNativeWin(); + + bool Init(); + + CONDITION_VARIABLE condition_variable_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_posix.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_posix.h new file mode 100644 index 0000000..a014a3b --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/condition_variable_posix.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_POSIX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_POSIX_H_ + +#include + +#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +class ConditionVariablePosix : public ConditionVariableWrapper { + public: + static ConditionVariableWrapper* Create(); + virtual ~ConditionVariablePosix(); + + virtual void SleepCS(CriticalSectionWrapper& crit_sect) OVERRIDE; + virtual bool SleepCS(CriticalSectionWrapper& crit_sect, + unsigned long max_time_in_ms) OVERRIDE; + virtual void Wake() OVERRIDE; + virtual void WakeAll() OVERRIDE; + + private: + ConditionVariablePosix(); + int Construct(); + + private: + pthread_cond_t cond_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_POSIX_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/critical_section_posix.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/critical_section_posix.h new file mode 100644 index 0000000..a5ec367 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/critical_section_posix.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_ + +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" + +#include + +namespace webrtc { + +class CriticalSectionPosix : public CriticalSectionWrapper { + public: + CriticalSectionPosix(); + + virtual ~CriticalSectionPosix(); + + virtual void Enter() OVERRIDE; + virtual void Leave() OVERRIDE; + + private: + pthread_mutex_t mutex_; + friend class ConditionVariablePosix; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/critical_section_win.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/critical_section_win.h new file mode 100644 index 0000000..be237ac --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/critical_section_win.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_ + +#include +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +class CriticalSectionWindows : public CriticalSectionWrapper { + public: + CriticalSectionWindows(); + + virtual ~CriticalSectionWindows(); + + virtual void Enter(); + virtual void Leave(); + + private: + CRITICAL_SECTION crit; + + friend class ConditionVariableEventWin; + friend class ConditionVariableNativeWin; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/data_log_c_helpers_unittest.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/data_log_c_helpers_unittest.h new file mode 100644 index 0000000..ef86eae --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/data_log_c_helpers_unittest.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef SRC_SYSTEM_WRAPPERS_SOURCE_DATA_LOG_C_HELPERS_UNITTEST_H_ +#define SRC_SYSTEM_WRAPPERS_SOURCE_DATA_LOG_C_HELPERS_UNITTEST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int WebRtcDataLogCHelper_TestCreateLog(); + +int WebRtcDataLogCHelper_TestReturnLog(); + +int WebRtcDataLogCHelper_TestCombine(); + +int WebRtcDataLogCHelper_TestAddTable(); + +int WebRtcDataLogCHelper_TestAddColumn(); + +int WebRtcDataLogCHelper_TestNextRow(); + +int WebRtcDataLogCHelper_TestInsertCell_int(); + +int WebRtcDataLogCHelper_TestInsertArray_int(); + +int WebRtcDataLogCHelper_TestInsertCell_float(); + +int WebRtcDataLogCHelper_TestInsertArray_float(); + +int WebRtcDataLogCHelper_TestInsertCell_double(); + +int WebRtcDataLogCHelper_TestInsertArray_double(); + +int WebRtcDataLogCHelper_TestInsertCell_int32(); + +int WebRtcDataLogCHelper_TestInsertArray_int32(); + +int WebRtcDataLogCHelper_TestInsertCell_uint32(); + +int WebRtcDataLogCHelper_TestInsertArray_uint32(); + +int WebRtcDataLogCHelper_TestInsertCell_int64(); + +int WebRtcDataLogCHelper_TestInsertArray_int64(); + +#ifdef __cplusplus +} // end of extern "C" +#endif + +#endif // SRC_SYSTEM_WRAPPERS_SOURCE_DATA_LOG_C_HELPERS_UNITTEST_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/event_posix.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/event_posix.h new file mode 100644 index 0000000..5fbe061 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/event_posix.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_ + +#include "webrtc/system_wrappers/interface/event_wrapper.h" + +#include +#include + +#include "webrtc/system_wrappers/interface/thread_wrapper.h" + +namespace webrtc { + +enum State { + kUp = 1, + kDown = 2 +}; + +class EventPosix : public EventWrapper { + public: + static EventWrapper* Create(); + + virtual ~EventPosix(); + + virtual EventTypeWrapper Wait(unsigned long max_time) OVERRIDE; + virtual bool Set() OVERRIDE; + virtual bool Reset() OVERRIDE; + + virtual bool StartTimer(bool periodic, unsigned long time) OVERRIDE; + virtual bool StopTimer() OVERRIDE; + + private: + EventPosix(); + int Construct(); + + static bool Run(ThreadObj obj); + bool Process(); + EventTypeWrapper Wait(timespec& wake_at); + + private: + pthread_cond_t cond_; + pthread_mutex_t mutex_; + + ThreadWrapper* timer_thread_; + EventPosix* timer_event_; + timespec created_at_; + + bool periodic_; + unsigned long time_; // In ms + unsigned long count_; + State state_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/event_win.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/event_win.h new file mode 100644 index 0000000..55ed8eb --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/event_win.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_ + +#include + +#include "webrtc/system_wrappers/interface/event_wrapper.h" + +#include "webrtc/typedefs.h" + +namespace webrtc { + +class EventWindows : public EventWrapper { + public: + EventWindows(); + virtual ~EventWindows(); + + virtual EventTypeWrapper Wait(unsigned long max_time); + virtual bool Set(); + virtual bool Reset(); + + virtual bool StartTimer(bool periodic, unsigned long time); + virtual bool StopTimer(); + + private: + HANDLE event_; + uint32_t timerID_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/file_impl.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/file_impl.h new file mode 100644 index 0000000..1abf010 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/file_impl.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_ + +#include + +#include "webrtc/system_wrappers/interface/file_wrapper.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { + +class RWLockWrapper; + +class FileWrapperImpl : public FileWrapper { + public: + FileWrapperImpl(); + virtual ~FileWrapperImpl(); + + virtual int FileName(char* file_name_utf8, + size_t size) const OVERRIDE; + + virtual bool Open() const OVERRIDE; + + virtual int OpenFile(const char* file_name_utf8, + bool read_only, + bool loop = false, + bool text = false) OVERRIDE; + + virtual int OpenFromFileHandle(FILE* handle, + bool manage_file, + bool read_only, + bool loop = false) OVERRIDE; + + virtual int CloseFile() OVERRIDE; + virtual int SetMaxFileSize(size_t bytes) OVERRIDE; + virtual int Flush() OVERRIDE; + + virtual int Read(void* buf, int length) OVERRIDE; + virtual bool Write(const void* buf, int length) OVERRIDE; + virtual int WriteText(const char* format, ...) OVERRIDE; + virtual int Rewind() OVERRIDE; + + private: + int CloseFileImpl(); + int FlushImpl(); + + scoped_ptr rw_lock_; + + FILE* id_; + bool managed_file_handle_; + bool open_; + bool looping_; + bool read_only_; + size_t max_size_in_bytes_; // -1 indicates file size limitation is off + size_t size_in_bytes_; + char file_name_utf8_[kMaxFileNameSize]; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/move.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/move.h new file mode 100644 index 0000000..2e93641 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/move.h @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Borrowed from Chromium's src/base/move.h. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTEFACE_MOVE_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTEFACE_MOVE_H_ + +// Macro with the boilerplate that makes a type move-only in C++03. +// +// USAGE +// +// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create +// a "move-only" type. Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be +// the first line in a class declaration. +// +// A class using this macro must call .Pass() (or somehow be an r-value already) +// before it can be: +// +// * Passed as a function argument +// * Used as the right-hand side of an assignment +// * Returned from a function +// +// Each class will still need to define their own "move constructor" and "move +// operator=" to make this useful. Here's an example of the macro, the move +// constructor, and the move operator= from the scoped_ptr class: +// +// template +// class scoped_ptr { +// MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) +// public: +// scoped_ptr(RValue& other) : ptr_(other.release()) { } +// scoped_ptr& operator=(RValue& other) { +// swap(other); +// return *this; +// } +// }; +// +// Note that the constructor must NOT be marked explicit. +// +// For consistency, the second parameter to the macro should always be RValue +// unless you have a strong reason to do otherwise. It is only exposed as a +// macro parameter so that the move constructor and move operator= don't look +// like they're using a phantom type. +// +// +// HOW THIS WORKS +// +// For a thorough explanation of this technique, see: +// +// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor +// +// The summary is that we take advantage of 2 properties: +// +// 1) non-const references will not bind to r-values. +// 2) C++ can apply one user-defined conversion when initializing a +// variable. +// +// The first lets us disable the copy constructor and assignment operator +// by declaring private version of them with a non-const reference parameter. +// +// For l-values, direct initialization still fails like in +// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment +// operators are private. +// +// For r-values, the situation is different. The copy constructor and +// assignment operator are not viable due to (1), so we are trying to call +// a non-existent constructor and non-existing operator= rather than a private +// one. Since we have not committed an error quite yet, we can provide an +// alternate conversion sequence and a constructor. We add +// +// * a private struct named "RValue" +// * a user-defined conversion "operator RValue()" +// * a "move constructor" and "move operator=" that take the RValue& as +// their sole parameter. +// +// Only r-values will trigger this sequence and execute our "move constructor" +// or "move operator=." L-values will match the private copy constructor and +// operator= first giving a "private in this context" error. This combination +// gives us a move-only type. +// +// For signaling a destructive transfer of data from an l-value, we provide a +// method named Pass() which creates an r-value for the current instance +// triggering the move constructor or move operator=. +// +// Other ways to get r-values is to use the result of an expression like a +// function call. +// +// Here's an example with comments explaining what gets triggered where: +// +// class Foo { +// MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue); +// +// public: +// ... API ... +// Foo(RValue other); // Move constructor. +// Foo& operator=(RValue rhs); // Move operator= +// }; +// +// Foo MakeFoo(); // Function that returns a Foo. +// +// Foo f; +// Foo f_copy(f); // ERROR: Foo(Foo&) is private in this context. +// Foo f_assign; +// f_assign = f; // ERROR: operator=(Foo&) is private in this context. +// +// +// Foo f(MakeFoo()); // R-value so alternate conversion executed. +// Foo f_copy(f.Pass()); // R-value so alternate conversion executed. +// f = f_copy.Pass(); // R-value so alternate conversion executed. +// +// +// IMPLEMENTATION SUBTLETIES WITH RValue +// +// The RValue struct is just a container for a pointer back to the original +// object. It should only ever be created as a temporary, and no external +// class should ever declare it or use it in a parameter. +// +// It is tempting to want to use the RValue type in function parameters, but +// excluding the limited usage here for the move constructor and move +// operator=, doing so would mean that the function could take both r-values +// and l-values equially which is unexpected. See COMPARED To Boost.Move for +// more details. +// +// An alternate, and incorrect, implementation of the RValue class used by +// Boost.Move makes RValue a fieldless child of the move-only type. RValue& +// is then used in place of RValue in the various operators. The RValue& is +// "created" by doing *reinterpret_cast(this). This has the appeal +// of never creating a temporary RValue struct even with optimizations +// disabled. Also, by virtue of inheritance you can treat the RValue +// reference as if it were the move-only type itself. Unfortunately, +// using the result of this reinterpret_cast<> is actually undefined behavior +// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer +// will generate non-working code. +// +// In optimized builds, both implementations generate the same assembly so we +// choose the one that adheres to the standard. +// +// +// WHY HAVE typedef void MoveOnlyTypeForCPP03 +// +// Callback<>/Bind() needs to understand movable-but-not-copyable semantics +// to call .Pass() appropriately when it is expected to transfer the value. +// The cryptic typedef MoveOnlyTypeForCPP03 is added to make this check +// easy and automatic in helper templates for Callback<>/Bind(). +// See IsMoveOnlyType template and its usage in base/callback_internal.h +// for more details. +// +// +// COMPARED TO C++11 +// +// In C++11, you would implement this functionality using an r-value reference +// and our .Pass() method would be replaced with a call to std::move(). +// +// This emulation also has a deficiency where it uses up the single +// user-defined conversion allowed by C++ during initialization. This can +// cause problems in some API edge cases. For instance, in scoped_ptr, it is +// impossible to make a function "void Foo(scoped_ptr p)" accept a +// value of type scoped_ptr even if you add a constructor to +// scoped_ptr<> that would make it look like it should work. C++11 does not +// have this deficiency. +// +// +// COMPARED TO Boost.Move +// +// Our implementation similar to Boost.Move, but we keep the RValue struct +// private to the move-only type, and we don't use the reinterpret_cast<> hack. +// +// In Boost.Move, RValue is the boost::rv<> template. This type can be used +// when writing APIs like: +// +// void MyFunc(boost::rv& f) +// +// that can take advantage of rv<> to avoid extra copies of a type. However you +// would still be able to call this version of MyFunc with an l-value: +// +// Foo f; +// MyFunc(f); // Uh oh, we probably just destroyed |f| w/o calling Pass(). +// +// unless someone is very careful to also declare a parallel override like: +// +// void MyFunc(const Foo& f) +// +// that would catch the l-values first. This was declared unsafe in C++11 and +// a C++11 compiler will explicitly fail MyFunc(f). Unfortunately, we cannot +// ensure this in C++03. +// +// Since we have no need for writing such APIs yet, our implementation keeps +// RValue private and uses a .Pass() method to do the conversion instead of +// trying to write a version of "std::move()." Writing an API like std::move() +// would require the RValue struct to be public. +// +// +// CAVEATS +// +// If you include a move-only type as a field inside a class that does not +// explicitly declare a copy constructor, the containing class's implicit +// copy constructor will change from Containing(const Containing&) to +// Containing(Containing&). This can cause some unexpected errors. +// +// http://llvm.org/bugs/show_bug.cgi?id=11528 +// +// The workaround is to explicitly declare your copy constructor. +// +#define WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \ + private: \ + struct rvalue_type { \ + explicit rvalue_type(type* object) : object(object) {} \ + type* object; \ + }; \ + type(type&); \ + void operator=(type&); \ + public: \ + operator rvalue_type() { return rvalue_type(this); } \ + type Pass() { return type(rvalue_type(this)); } \ + typedef void MoveOnlyTypeForCPP03; \ + private: + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTEFACE_MOVE_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_generic.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_generic.h new file mode 100644 index 0000000..dd69f52 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_generic.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_ + +#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +class CriticalSectionWrapper; +class ConditionVariableWrapper; + +class RWLockGeneric : public RWLockWrapper { + public: + RWLockGeneric(); + virtual ~RWLockGeneric(); + + virtual void AcquireLockExclusive() OVERRIDE; + virtual void ReleaseLockExclusive() OVERRIDE; + + virtual void AcquireLockShared() OVERRIDE; + virtual void ReleaseLockShared() OVERRIDE; + + private: + CriticalSectionWrapper* critical_section_; + ConditionVariableWrapper* read_condition_; + ConditionVariableWrapper* write_condition_; + + int readers_active_; + bool writer_active_; + int readers_waiting_; + int writers_waiting_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_posix.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_posix.h new file mode 100644 index 0000000..6ce2b2d --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_posix.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_ + +#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h" +#include "webrtc/typedefs.h" + +#include + +namespace webrtc { + +class RWLockPosix : public RWLockWrapper { + public: + static RWLockPosix* Create(); + virtual ~RWLockPosix(); + + virtual void AcquireLockExclusive() OVERRIDE; + virtual void ReleaseLockExclusive() OVERRIDE; + + virtual void AcquireLockShared() OVERRIDE; + virtual void ReleaseLockShared() OVERRIDE; + + private: + RWLockPosix(); + bool Init(); + + pthread_rwlock_t lock_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_win.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_win.h new file mode 100644 index 0000000..6f7cd33 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/rw_lock_win.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_ + +#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h" + +#include + +namespace webrtc { + +class RWLockWin : public RWLockWrapper { + public: + static RWLockWin* Create(); + ~RWLockWin() {} + + virtual void AcquireLockExclusive(); + virtual void ReleaseLockExclusive(); + + virtual void AcquireLockShared(); + virtual void ReleaseLockShared(); + + private: + RWLockWin(); + static bool LoadModule(); + + SRWLOCK lock_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/set_thread_name_win.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/set_thread_name_win.h new file mode 100644 index 0000000..cca126f --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/set_thread_name_win.h @@ -0,0 +1,108 @@ +/* +Source: +http://msdn.microsoft.com/en-us/cc300389.aspx#P + +License: +This license governs use of code marked as “sample” or “example” available on +this web site without a license agreement, as provided under the section above +titled “NOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE.” If you use +such code (the “software”), you accept this license. If you do not accept the +license, do not use the software. + +1. Definitions + +The terms “reproduce,” “reproduction,” “derivative works,” and “distribution” +have the same meaning here as under U.S. copyright law. + +A “contribution” is the original software, or any additions or changes to the +software. + +A “contributor” is any person that distributes its contribution under this +license. + +“Licensed patents” are a contributor’s patent claims that read directly on its +contribution. + +2. Grant of Rights + +(A) Copyright Grant - Subject to the terms of this license, including the +license conditions and limitations in section 3, each contributor grants you a +non-exclusive, worldwide, royalty-free copyright license to reproduce its +contribution, prepare derivative works of its contribution, and distribute its +contribution or any derivative works that you create. + +(B) Patent Grant - Subject to the terms of this license, including the license +conditions and limitations in section 3, each contributor grants you a +non-exclusive, worldwide, royalty-free license under its licensed patents to +make, have made, use, sell, offer for sale, import, and/or otherwise dispose +of its contribution in the software or derivative works of the contribution in +the software. + +3. Conditions and Limitations + +(A) No Trademark License- This license does not grant you rights to use any +contributors’ name, logo, or trademarks. + +(B) If you bring a patent claim against any contributor over patents that you +claim are infringed by the software, your patent license from such contributor +to the software ends automatically. + +(C) If you distribute any portion of the software, you must retain all +copyright, patent, trademark, and attribution notices that are present in the +software. + +(D) If you distribute any portion of the software in source code form, you may +do so only under this license by including a complete copy of this license +with your distribution. If you distribute any portion of the software in +compiled or object code form, you may only do so under a license that complies +with this license. + +(E) The software is licensed “as-is.” You bear the risk of using it. The +contributors give no express warranties, guarantees or conditions. You may +have additional consumer rights under your local laws which this license +cannot change. To the extent permitted under your local laws, the contributors +exclude the implied warranties of merchantability, fitness for a particular +purpose and non-infringement. + +(F) Platform Limitation - The licenses granted in sections 2(A) and 2(B) +extend only to the software or derivative works that you create that run on a +Microsoft Windows operating system product. +*/ + +/* + * The original code can be found here: + * http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.71).aspx + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ + +namespace webrtc { + +struct THREADNAME_INFO +{ + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1 = caller thread) + DWORD dwFlags; // reserved for future use, must be zero +}; + +void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try + { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), + (ULONG_PTR*)&info); + } + __except (EXCEPTION_CONTINUE_EXECUTION) + { + } +} +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/thread_posix.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/thread_posix.h new file mode 100644 index 0000000..c2025fd --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/thread_posix.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_ + +#include "webrtc/system_wrappers/interface/thread_wrapper.h" + +#include + +namespace webrtc { + +class CriticalSectionWrapper; +class EventWrapper; + +int ConvertToSystemPriority(ThreadPriority priority, int min_prio, + int max_prio); + +class ThreadPosix : public ThreadWrapper { + public: + static ThreadWrapper* Create(ThreadRunFunction func, ThreadObj obj, + ThreadPriority prio, const char* thread_name); + + ThreadPosix(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, + const char* thread_name); + virtual ~ThreadPosix(); + + // From ThreadWrapper. + virtual void SetNotAlive() OVERRIDE; + virtual bool Start(unsigned int& id) OVERRIDE; + // Not implemented on Mac. + virtual bool SetAffinity(const int* processor_numbers, + unsigned int amount_of_processors) OVERRIDE; + virtual bool Stop() OVERRIDE; + + void Run(); + + private: + int Construct(); + + private: + ThreadRunFunction run_function_; + ThreadObj obj_; + + // Internal state. + CriticalSectionWrapper* crit_state_; // Protects alive_ and dead_ + bool alive_; + bool dead_; + ThreadPriority prio_; + EventWrapper* event_; + + // Zero-terminated thread name string. + char name_[kThreadMaxNameLength]; + bool set_thread_name_; + + // Handle to thread. +#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) + pid_t pid_; +#endif + pthread_attr_t attr_; + pthread_t thread_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/thread_win.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/thread_win.h new file mode 100644 index 0000000..1122676 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/thread_win.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_ + +#include "webrtc/system_wrappers/interface/thread_wrapper.h" + +#include + +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" +#include "webrtc/system_wrappers/interface/event_wrapper.h" + +namespace webrtc { + +class ThreadWindows : public ThreadWrapper { + public: + ThreadWindows(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, + const char* thread_name); + virtual ~ThreadWindows(); + + virtual bool Start(unsigned int& id); + bool SetAffinity(const int* processor_numbers, + const unsigned int amount_of_processors); + virtual bool Stop(); + virtual void SetNotAlive(); + + static unsigned int WINAPI StartThread(LPVOID lp_parameter); + + protected: + virtual void Run(); + + private: + ThreadRunFunction run_function_; + ThreadObj obj_; + + bool alive_; + bool dead_; + + // TODO(hellner) + // do_not_close_handle_ member seem pretty redundant. Should be able to remove + // it. Basically it should be fine to reclaim the handle when calling stop + // and in the destructor. + bool do_not_close_handle_; + ThreadPriority prio_; + EventWrapper* event_; + CriticalSectionWrapper* critsect_stop_; + + HANDLE thread_; + unsigned int id_; + char name_[kThreadMaxNameLength]; + bool set_thread_name_; + +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_impl.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_impl.h new file mode 100644 index 0000000..9e6e0a2 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_impl.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_ + +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" +#include "webrtc/system_wrappers/interface/event_wrapper.h" +#include "webrtc/system_wrappers/interface/file_wrapper.h" +#include "webrtc/system_wrappers/interface/static_instance.h" +#include "webrtc/system_wrappers/interface/thread_wrapper.h" +#include "webrtc/system_wrappers/interface/trace.h" + +namespace webrtc { + +// TODO(pwestin) WEBRTC_TRACE_MAX_QUEUE needs to be tweaked +// TODO(hellner) the buffer should be close to how much the system can write to +// file. Increasing the buffer will not solve anything. Sooner or +// later the buffer is going to fill up anyways. +#if defined(WEBRTC_IOS) +#define WEBRTC_TRACE_MAX_QUEUE 2000 +#else +#define WEBRTC_TRACE_MAX_QUEUE 8000 +#endif +#define WEBRTC_TRACE_NUM_ARRAY 2 +#define WEBRTC_TRACE_MAX_MESSAGE_SIZE 256 +// Total buffer size is WEBRTC_TRACE_NUM_ARRAY (number of buffer partitions) * +// WEBRTC_TRACE_MAX_QUEUE (number of lines per buffer partition) * +// WEBRTC_TRACE_MAX_MESSAGE_SIZE (number of 1 byte charachters per line) = +// 1 or 4 Mbyte. + +#define WEBRTC_TRACE_MAX_FILE_SIZE 100*1000 +// Number of rows that may be written to file. On average 110 bytes per row (max +// 256 bytes per row). So on average 110*100*1000 = 11 Mbyte, max 256*100*1000 = +// 25.6 Mbyte + +class TraceImpl : public Trace { + public: + virtual ~TraceImpl(); + + static TraceImpl* CreateInstance(); + static TraceImpl* GetTrace(const TraceLevel level = kTraceAll); + + int32_t SetTraceFileImpl(const char* file_name, const bool add_file_counter); + int32_t TraceFileImpl(char file_name[FileWrapper::kMaxFileNameSize]); + + int32_t SetTraceCallbackImpl(TraceCallback* callback); + + void AddImpl(const TraceLevel level, const TraceModule module, + const int32_t id, const char* msg); + + bool StopThread(); + + bool TraceCheck(const TraceLevel level) const; + + protected: + TraceImpl(); + + static TraceImpl* StaticInstance(CountOperation count_operation, + const TraceLevel level = kTraceAll); + + int32_t AddThreadId(char* trace_message) const; + + // OS specific implementations. + virtual int32_t AddTime(char* trace_message, + const TraceLevel level) const = 0; + + virtual int32_t AddBuildInfo(char* trace_message) const = 0; + virtual int32_t AddDateTimeInfo(char* trace_message) const = 0; + + static bool Run(void* obj); + bool Process(); + + private: + friend class Trace; + + int32_t AddLevel(char* sz_message, const TraceLevel level) const; + + int32_t AddModuleAndId(char* trace_message, const TraceModule module, + const int32_t id) const; + + int32_t AddMessage(char* trace_message, + const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE], + const uint16_t written_so_far) const; + + void AddMessageToList( + const char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE], + const uint16_t length, + const TraceLevel level); + + bool UpdateFileName( + const char file_name_utf8[FileWrapper::kMaxFileNameSize], + char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize], + const uint32_t new_count) const; + + bool CreateFileName( + const char file_name_utf8[FileWrapper::kMaxFileNameSize], + char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize], + const uint32_t new_count) const; + + void WriteToFile(); + + CriticalSectionWrapper* critsect_interface_; + TraceCallback* callback_; + uint32_t row_count_text_; + uint32_t file_count_text_; + + FileWrapper& trace_file_; + ThreadWrapper& thread_; + EventWrapper& event_; + + // critsect_array_ protects active_queue_. + CriticalSectionWrapper* critsect_array_; + uint16_t next_free_idx_[WEBRTC_TRACE_NUM_ARRAY]; + TraceLevel level_[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; + uint16_t length_[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; + char* message_queue_[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; + uint8_t active_queue_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_posix.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_posix.h new file mode 100644 index 0000000..2056c70 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_posix.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_ + +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" +#include "webrtc/system_wrappers/source/trace_impl.h" + +namespace webrtc { + +class TracePosix : public TraceImpl { + public: + TracePosix(); + virtual ~TracePosix(); + + // This method can be called on several different threads different from + // the creating thread. + virtual int32_t AddTime(char* trace_message, const TraceLevel level) const + OVERRIDE; + + virtual int32_t AddBuildInfo(char* trace_message) const OVERRIDE; + virtual int32_t AddDateTimeInfo(char* trace_message) const OVERRIDE; + + private: + volatile mutable uint32_t prev_api_tick_count_; + volatile mutable uint32_t prev_tick_count_; + + CriticalSectionWrapper& crit_sect_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_win.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_win.h new file mode 100644 index 0000000..1a87107 --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/trace_win.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_ + +#include +#include + +#include "webrtc/system_wrappers/source/trace_impl.h" + +namespace webrtc { + +class TraceWindows : public TraceImpl { + public: + TraceWindows(); + virtual ~TraceWindows(); + + virtual int32_t AddTime(char* trace_message, const TraceLevel level) const; + + virtual int32_t AddBuildInfo(char* trace_message) const; + virtual int32_t AddDateTimeInfo(char* trace_message) const; + private: + volatile mutable uint32_t prev_api_tick_count_; + volatile mutable uint32_t prev_tick_count_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/unittest_utilities.h b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/unittest_utilities.h new file mode 100644 index 0000000..b32308e --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/system_wrappers/source/unittest_utilities.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_UNITTEST_UTILITIES_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_UNITTEST_UTILITIES_H_ + +// This file contains utilities that make it simpler to write unittests +// that are appropriate for the system_wrappers classes. + +#include +#include + +#include "webrtc/system_wrappers/interface/trace.h" + +namespace webrtc { + +class TestTraceCallback : public TraceCallback { + public: + virtual void Print(TraceLevel level, const char* msg, int length) { + if (msg) { + char* cmd_print = new char[length+1]; + memcpy(cmd_print, msg, length); + cmd_print[length] = '\0'; + printf("%s\n", cmd_print); + fflush(stdout); + delete[] cmd_print; + } + } +}; + +// A class that turns on tracing to stdout at the beginning of the test, +// and turns it off once the test is finished. +// Intended usage: +// class SomeTest : public ::testing::Test { +// protected: +// SomeTest() +// : trace_(false) {} // Change to true to turn on tracing. +// private: +// ScopedTracing trace_; +// } +class ScopedTracing { + public: + explicit ScopedTracing(bool logOn) { + logging_ = logOn; + StartTrace(); + } + + ~ScopedTracing() { + StopTrace(); + } + + private: + void StartTrace() { + if (logging_) { + Trace::CreateTrace(); + Trace::set_level_filter(webrtc::kTraceAll); + Trace::SetTraceCallback(&trace_); + } + } + + void StopTrace() { + if (logging_) { + Trace::SetTraceCallback(NULL); + Trace::ReturnTrace(); + } + } + + private: + bool logging_; + TestTraceCallback trace_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_UNITTEST_UTILITIES_H_ diff --git a/thirdparties/common/include/webrtc-sdk/webrtc/typedefs.h b/thirdparties/common/include/webrtc-sdk/webrtc/typedefs.h new file mode 100644 index 0000000..d8977ff --- /dev/null +++ b/thirdparties/common/include/webrtc-sdk/webrtc/typedefs.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file contains platform-specific typedefs and defines. +// Much of it is derived from Chromium's build/build_config.h. + +#ifndef WEBRTC_TYPEDEFS_H_ +#define WEBRTC_TYPEDEFS_H_ + +// Processor architecture detection. For more info on what's defined, see: +// http://msdn.microsoft.com/en-us/library/b0084kay.aspx +// http://www.agner.org/optimize/calling_conventions.pdf +// or with gcc, run: "echo | gcc -E -dM -" +#if defined(_M_X64) || defined(__x86_64__) +#define WEBRTC_ARCH_X86_FAMILY +#define WEBRTC_ARCH_X86_64 +#define WEBRTC_ARCH_64_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__aarch64__) +#define WEBRTC_ARCH_64_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(_M_IX86) || defined(__i386__) +#define WEBRTC_ARCH_X86_FAMILY +#define WEBRTC_ARCH_X86 +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__ARMEL__) +// TODO(ajm): We'd prefer to control platform defines here, but this is +// currently provided by the Android makefiles. Commented to avoid duplicate +// definition warnings. +//#define WEBRTC_ARCH_ARM +// TODO(ajm): Chromium uses the following two defines. Should we switch? +//#define WEBRTC_ARCH_ARM_FAMILY +//#define WEBRTC_ARCH_ARMEL +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__MIPSEL__) +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__pnacl__) +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#else +#error Please add support for your architecture in typedefs.h +#endif + +#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN)) +#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN +#endif + +#if (defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__)) || \ + (defined(WEBRTC_ARCH_ARM_V7) && !defined(WEBRTC_ARCH_ARM_NEON)) +#define WEBRTC_CPU_DETECTION +#endif + +#if !defined(_MSC_VER) +#include +#else +// Define C99 equivalent types, since pre-2010 MSVC doesn't provide stdint.h. +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef __int64 int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +#endif + +// Borrowed from Chromium's base/compiler_specific.h. +// Annotate a virtual method indicating it must be overriding a virtual +// method in the parent class. +// Use like: +// virtual void foo() OVERRIDE; +#if defined(_MSC_VER) +#define OVERRIDE override +#elif defined(__clang__) +// Clang defaults to C++03 and warns about using override. Squelch that. +// Intentionally no push/pop here so all users of OVERRIDE ignore the warning +// too. This is like passing -Wno-c++11-extensions, except that GCC won't die +// (because it won't see this pragma). +#pragma clang diagnostic ignored "-Wc++11-extensions" +#define OVERRIDE override +#elif defined(__GNUC__) && __cplusplus >= 201103 && \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40700 +// GCC 4.7 supports explicit virtual overrides when C++11 support is enabled. +#define OVERRIDE override +#else +#define OVERRIDE +#endif + +// Annotate a function indicating the caller must examine the return value. +// Use like: +// int foo() WARN_UNUSED_RESULT; +// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and +// libjingle are merged. +#if !defined(WARN_UNUSED_RESULT) +#if defined(__GNUC__) +#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define WARN_UNUSED_RESULT +#endif +#endif // WARN_UNUSED_RESULT + +#endif // WEBRTC_TYPEDEFS_H_ diff --git a/thirdparties/win32/bin/AStyle.exe b/thirdparties/win32/bin/AStyle.exe new file mode 100644 index 0000000000000000000000000000000000000000..a0080494fd67d683ea39209733b3e4be3ceeb0ca GIT binary patch literal 432128 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 >_8;OmG#OneaWTH>PucpC9_ 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 VHKjGB<>gh&E^TPg7yps?{{r^}P$d8W literal 0 HcmV?d00001 diff --git a/thirdparties/win32/include/inttypes.h b/thirdparties/win32/include/inttypes.h new file mode 100644 index 0000000..75716df --- /dev/null +++ b/thirdparties/win32/include/inttypes.h @@ -0,0 +1,305 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006 Alexander Chemeris +// +// 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 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 _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + + +#endif // _MSC_INTTYPES_H_ ] diff --git a/thirdparties/win32/include/stdint.h b/thirdparties/win32/include/stdint.h new file mode 100644 index 0000000..1f4f97e --- /dev/null +++ b/thirdparties/win32/include/stdint.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// 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 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 _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#else +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ +typedef signed __int64 intptr_t; +typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ +typedef _W64 signed int intptr_t; +typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/webrtc-everywhere.sln b/webrtc-everywhere.sln new file mode 100644 index 0000000..9a4921b --- /dev/null +++ b/webrtc-everywhere.sln @@ -0,0 +1,76 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtc-everywhere-ie", "ie\webrtc-everywhere-ie.vcxproj", "{FEF60750-96B0-4124-9007-B90780B6267D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtc-everywhere-common", "common\webrtc-everywhere-common.vcxproj", "{95230956-8581-4F03-A589-C6217119DE9E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtc-everywhere-npapi", "npapi\webrtc-everywhere-npapi.vcxproj", "{332AE24A-F021-4F30-A967-0CB91D94278D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtc-everywhere-console", "common\webrtc-everywhere-console.vcxproj", "{A5BD8595-2B82-42E3-90E8-4405D6425A29}" + ProjectSection(ProjectDependencies) = postProject + {95230956-8581-4F03-A589-C6217119DE9E} = {95230956-8581-4F03-A589-C6217119DE9E} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6E9402F2-5AC4-466A-ACF5-3A137CA85A1C}" + ProjectSection(SolutionItems) = preProject + README.md = README.md + WebRTC.htm = WebRTC.htm + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + CD_ROM|Win32 = CD_ROM|Win32 + Debug|Win32 = Debug|Win32 + DVD-5|Win32 = DVD-5|Win32 + Release|Win32 = Release|Win32 + SingleImage|Win32 = SingleImage|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FEF60750-96B0-4124-9007-B90780B6267D}.CD_ROM|Win32.ActiveCfg = Release|Win32 + {FEF60750-96B0-4124-9007-B90780B6267D}.CD_ROM|Win32.Build.0 = Release|Win32 + {FEF60750-96B0-4124-9007-B90780B6267D}.Debug|Win32.ActiveCfg = Debug|Win32 + {FEF60750-96B0-4124-9007-B90780B6267D}.Debug|Win32.Build.0 = Debug|Win32 + {FEF60750-96B0-4124-9007-B90780B6267D}.DVD-5|Win32.ActiveCfg = Debug|Win32 + {FEF60750-96B0-4124-9007-B90780B6267D}.DVD-5|Win32.Build.0 = Debug|Win32 + {FEF60750-96B0-4124-9007-B90780B6267D}.Release|Win32.ActiveCfg = Release|Win32 + {FEF60750-96B0-4124-9007-B90780B6267D}.Release|Win32.Build.0 = Release|Win32 + {FEF60750-96B0-4124-9007-B90780B6267D}.SingleImage|Win32.ActiveCfg = Release|Win32 + {FEF60750-96B0-4124-9007-B90780B6267D}.SingleImage|Win32.Build.0 = Release|Win32 + {95230956-8581-4F03-A589-C6217119DE9E}.CD_ROM|Win32.ActiveCfg = Release|Win32 + {95230956-8581-4F03-A589-C6217119DE9E}.CD_ROM|Win32.Build.0 = Release|Win32 + {95230956-8581-4F03-A589-C6217119DE9E}.Debug|Win32.ActiveCfg = Debug|Win32 + {95230956-8581-4F03-A589-C6217119DE9E}.Debug|Win32.Build.0 = Debug|Win32 + {95230956-8581-4F03-A589-C6217119DE9E}.DVD-5|Win32.ActiveCfg = Debug|Win32 + {95230956-8581-4F03-A589-C6217119DE9E}.DVD-5|Win32.Build.0 = Debug|Win32 + {95230956-8581-4F03-A589-C6217119DE9E}.Release|Win32.ActiveCfg = Release|Win32 + {95230956-8581-4F03-A589-C6217119DE9E}.Release|Win32.Build.0 = Release|Win32 + {95230956-8581-4F03-A589-C6217119DE9E}.SingleImage|Win32.ActiveCfg = Release|Win32 + {95230956-8581-4F03-A589-C6217119DE9E}.SingleImage|Win32.Build.0 = Release|Win32 + {332AE24A-F021-4F30-A967-0CB91D94278D}.CD_ROM|Win32.ActiveCfg = Release|Win32 + {332AE24A-F021-4F30-A967-0CB91D94278D}.CD_ROM|Win32.Build.0 = Release|Win32 + {332AE24A-F021-4F30-A967-0CB91D94278D}.Debug|Win32.ActiveCfg = Debug|Win32 + {332AE24A-F021-4F30-A967-0CB91D94278D}.Debug|Win32.Build.0 = Debug|Win32 + {332AE24A-F021-4F30-A967-0CB91D94278D}.DVD-5|Win32.ActiveCfg = Debug|Win32 + {332AE24A-F021-4F30-A967-0CB91D94278D}.DVD-5|Win32.Build.0 = Debug|Win32 + {332AE24A-F021-4F30-A967-0CB91D94278D}.Release|Win32.ActiveCfg = Release|Win32 + {332AE24A-F021-4F30-A967-0CB91D94278D}.Release|Win32.Build.0 = Release|Win32 + {332AE24A-F021-4F30-A967-0CB91D94278D}.SingleImage|Win32.ActiveCfg = Release|Win32 + {332AE24A-F021-4F30-A967-0CB91D94278D}.SingleImage|Win32.Build.0 = Release|Win32 + {A5BD8595-2B82-42E3-90E8-4405D6425A29}.CD_ROM|Win32.ActiveCfg = Release|Win32 + {A5BD8595-2B82-42E3-90E8-4405D6425A29}.CD_ROM|Win32.Build.0 = Release|Win32 + {A5BD8595-2B82-42E3-90E8-4405D6425A29}.Debug|Win32.ActiveCfg = Debug|Win32 + {A5BD8595-2B82-42E3-90E8-4405D6425A29}.Debug|Win32.Build.0 = Debug|Win32 + {A5BD8595-2B82-42E3-90E8-4405D6425A29}.DVD-5|Win32.ActiveCfg = Debug|Win32 + {A5BD8595-2B82-42E3-90E8-4405D6425A29}.DVD-5|Win32.Build.0 = Debug|Win32 + {A5BD8595-2B82-42E3-90E8-4405D6425A29}.Release|Win32.ActiveCfg = Release|Win32 + {A5BD8595-2B82-42E3-90E8-4405D6425A29}.Release|Win32.Build.0 = Release|Win32 + {A5BD8595-2B82-42E3-90E8-4405D6425A29}.SingleImage|Win32.ActiveCfg = Release|Win32 + {A5BD8595-2B82-42E3-90E8-4405D6425A29}.SingleImage|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/wininstall/innosetup.iss b/wininstall/innosetup.iss new file mode 100644 index 0000000..edd9627 --- /dev/null +++ b/wininstall/innosetup.iss @@ -0,0 +1,59 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +#define MyAppName "webrtc-everywhere" +#define MyAppVersion "1.0.0.1" +#define MyAppPublisher "Sarandogou" +#define MyAppURL "https://ns313841.ovh.net/webrtc/" + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +; Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{49969875-E6F2-4D13-84C9-BF58B9831869} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +;AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +DefaultDirName={pf}\{#MyAppName} +DefaultGroupName={#MyAppName} +DisableProgramGroupPage=yes +LicenseFile=C:\Projects\webrtc-everywhere\LICENSE-BSD +OutputDir=C:\Projects\webrtc-everywhere\wininstall +OutputBaseFilename=setup +Compression=lzma +SolidCompression=yes +; "ArchitecturesInstallIn64BitMode=x64" requests that the install be +; done in "64-bit mode" on x64, meaning it should use the native +; 64-bit Program Files directory and the 64-bit view of the registry. +; On all other architectures it will install in "32-bit mode". +ArchitecturesInstallIn64BitMode=x64 +; Note: We don't set ProcessorsAllowed because we want this +; installation to run on all architectures (including Itanium, +; since it's capable of running 32-bit code too). + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Files] +Source: "C:\Projects\webrtc-everywhere\Release\npwebrtc-everywhere-npapi.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Projects\webrtc-everywhere\Release\webrtc-everywhere-common.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\Projects\webrtc-everywhere\Release\webrtc-everywhere-ie.dll"; DestDir: "{app}"; Flags: ignoreversion regserver 32bit +Source: "C:\Projects\webrtc-everywhere\wininstall\vcredist_x64.exe"; DestDir: "{tmp}"; DestName: "vcredist.exe"; Check: IsWin64; Flags: ignoreversion; +Source: "C:\Projects\webrtc-everywhere\wininstall\vcredist_x86.exe"; DestDir: "{tmp}"; DestName: "vcredist.exe"; Check: not IsWin64; Flags: ignoreversion solidbreak; + +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Registry] +Root: HKLM64; Subkey: "SOFTWARE\MozillaPlugins\@ns313841.ovh.net/webrtc-everywhere"; ValueType: string; ValueName: "Description"; ValueData: "WebRTC everywhere"; Flags: uninsdeletekey; Check: IsWin64 +Root: HKLM64; Subkey: "SOFTWARE\MozillaPlugins\@ns313841.ovh.net/webrtc-everywhere"; ValueType: string; ValueName: "Path"; ValueData: "{app}\npwebrtc-everywhere-npapi.dll"; Flags: uninsdeletekey; Check: IsWin64 +Root: HKLM64; Subkey: "SOFTWARE\MozillaPlugins\@ns313841.ovh.net/webrtc-everywhere"; ValueType: string; ValueName: "ProductName"; ValueData: "WebRTC everywhere"; Flags: uninsdeletekey; Check: IsWin64 +Root: HKLM32; Subkey: "SOFTWARE\MozillaPlugins\@ns313841.ovh.net/webrtc-everywhere"; ValueType: string; ValueName: "Description"; ValueData: "WebRTC everywhere"; Flags: uninsdeletekey +Root: HKLM32; Subkey: "SOFTWARE\MozillaPlugins\@ns313841.ovh.net/webrtc-everywhere"; ValueType: string; ValueName: "Path"; ValueData: "{app}\npwebrtc-everywhere-npapi.dll"; Flags: uninsdeletekey +Root: HKLM32; Subkey: "SOFTWARE\MozillaPlugins\@ns313841.ovh.net/webrtc-everywhere"; ValueType: string; ValueName: "ProductName"; ValueData: "WebRTC everywhere"; Flags: uninsdeletekey + +[Run] +Filename: "{tmp}\vcredist.exe"; Parameters: "/quiet /norestart"; StatusMsg: Installing Visual Studio 2013 RunTime...; diff --git a/wininstall/webrtc-everywhere-i386-10.4.dmg b/wininstall/webrtc-everywhere-i386-10.4.dmg new file mode 100644 index 0000000000000000000000000000000000000000..cb01ed8d6fbb44a37467ebccd0db28642df4f22d GIT binary patch literal 5815330 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

D3=-H%>$OJJ?5EW(MebxOtv55vM_+SH2GuS_ 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%0Ae<%BKGbKsCGAyu7WovnGJ2p`W_xSFKM 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%0A~V;Ki- zJW`QFqmUVk5OJ~>2KV+0IeLC6G|puV}& z$ZQ7!@2u;>t6N)_p+puUZJ~E^?CaO%EcuobOv-E4(Xlg>FApKvU-0nVsReib6a~LY zD>yW*;Oi{d3(5W(?X-e_V8QaVf{W7%PG-S*X$9X-D>#$|m!%c_KCR$SSn!Lqf|o+$ z8!>S4)WU-~bY@^9s9#*;I9_UZUiADO|2nCD(N zI#VvU`t%3KXii6_m+aEVKyf+TVWoEL9DMITP$LL->@21`qwp+8dHHxyeyZkSSwEx- zY~tjpp3)D{;$A>B>dw9`K!;z1n*%H}VTM^? z4p_VepR4kazj2~Ao`7-3yMQ%e0}o~+Y>YcwR+*T@2Gy~gD13P=*C1PaR2TI!X=9*H z6$b}%Ac0c*z={DgY?XSS=~jYr_Ne?kWxt}%A(au6U6Ny8w#%yiQ7?We9YbU%JX53) zA_+yF06^i-4zpE2LkZ>VD9=m4@~N~TCur`uozJi@Ic!Ptsl_*uO%)XT;4UQ=l)x5G z99xe`o|{SQ6-OD4z2>Z%{-qi(WtA~YNEn9XTC4@H{JN1CV4f_`rk zb$yk@IrT~5tvHbn!p&Na_ySOpWVH^<({C)4fW!)QS02<|C@=RFdG`mc(Sh=@3~qbz zHZFHZR!$DW`g0Axd6mjXywKmtj&aT9a?NPCJHV*5|+DKg$8@MF5oX*M09D6o-L0q2kAcaWXJD!5v zK>IH2|Na8yr|bHF3#iAu0ok}BClui!4{N*rC9`L*qn7ZiqUlz5MkjmruSeN4>c^#L z@}PSrTK1UMvY+hQe`o9;KQsErmW=*25~6(RA9LLP2|Q;17AN~x-^Bh=J0%xvd;O#3 z2W$I@uYYyYKhdNk96y`zMsBL~kNS7%pFHUPjU>=9{>8|(-9LV2^p7nW{c9jZy*hFH znB(?O;K93|>4_arC;RtBg8geS`&ThM)0Io1+2>HtkX)8-KMm94B&7K#k+S^otm=oc zRI262bli6D-Jy9dN;Es}`V-#Tk*52gtd83OSu777E{^5nZ}|}WMN#a3Tiy?jXYj|d zVRBFA)dMFy9aT{~XFfI%N4pD@O6+UTW(9?Cl5SV@#%=YM)Te5*Dz;kR!EpR$nZ&Kb zI$;|AUw52w$^8?Di)91q9|m_eU4q6oUAwo=!K<=QY#pYK`8xvl-LWICE&tH~w`@`T zw)gF++XmPbTiphb^!PG>1GdmHJ^ldh+fkP6<7n_Ro87ks+@gl^0o^xQ4W9qQ|Jwg> z`h9-tJ~g!eTz2GJxX6))$lHJxq|}z*{9HCs1DPHF@qUgZ3jFx#o&i7L-sE7%cgxDE zse{_UhopBEk{BRHngfy^tNbiG^g^8rChr%K^Afo%$`Ywttz3ySCJ~u9S>XYkslQj} zD|V$8(G!2YR~MxJ1?rv=++X^4 z{F1@Je_&vqeOZZpSpY(ktaFLbu}|abya7pxk{_36b>9T)>}kio zGSWLEeK`jaS>O&|7+F6;7CdU^0x=u1;rUq$_E#JmvxW-(qp(Zkn%=+s2;7u2x1vLR zbUrG{wx-Te$B`W7aqz`iPBmBME290cI3nEAPSwXwDIyM9^^Ibz4| zMNu&gvS+bXS0;PCac^t*6{-~4RdjYrAJ@!1aV7Thz}E5l8w5$$8|A{!_O>p`4o{m5 zIZ1?s_7r)YvV}t3Bo!eYT&*I0R+rP8i9-0H2_S*od$Gq8qmuC^w-y>0xbklwj>E+-QC()Oz61~>(JF2#>1@F-;s!X;VFD`$T`#2ba zZomm}c=F_|@?Xl}L>hS_4AQEDE8y2B2yqD~>sa8-V_9(0#6PY9jvba1G_x-F+L7v4 zjz^-eE3*!RHn#gFMIfVdBAY_h$C0iS2LP)GRkv5~By(pOo9E80b(qjP6C-Swtm3=l zLCR7j*>0pkw7s~77K;Gpkh5S3OOw4QzIsWW=Btop5_#aOjL`tTI>1P8M7o%DDZbj* z$Xbdl%~u<;Uqf6QhxL2ys~(3U697ecYA(1@dNr-v~XMOSky zSjvMb6nO+ZQ9*_v01nZIOk6>NhvIuUTop${45?Z}x=2&sP2b|_K*R#}|A2w!M(IuY zjR3j)i140vp$Kn*_H}2!BtMJf=3k$y=GpzO4Wd12uxc#AHA{f>B>4l8-J)lr7i8sVLlM7TqY}6 zsCo-UYb>RZcl6m{l>*?spQ3 zk3#Y64@gspr-)~^^6>hbvcfBw1Bzb=Fi5}i@f)68fRsJJrz$M%^tVjIVB(cxgeVs6SB44^iQ+`ki)EfU|#snU4WX_lXgiyJ(WV$m3(0({guI! z27YN$29TIBTJoK6rCJ7`0XCn@4zDD2gEqPm;L;!`M5y{DBBhecOVjgw1o4x`mo6ku zLD|=w4fJ6Ni`+o&$>m}J3DpU2c^U#ASB#ZZ&{4)HI5vF}SbMCG67LO1#iF_6EQkt6 zitJ}69X4Ym9t#k_j=mt*k4z>AY*F}@6Z^F{?J6~J&mNQBB3a;Sbli4WDmm?{dqOkf zV}7&GLJG8~O>6k;Bv8Dm5s#VplB<7n&`rJv|BT;6`9l!5W0MNi_dq&xuxZI^+RWj0M})?e9Fc!?KEQ~a ze6}m_yCZU6ZaRKsMEYEnVMIoeS37LR7?Fuc#E1+>svmhj*^6?nI#yWG`Vbbm5R&}` z!)XQo#)3B?IR%xlwK34RhzA-6hsL{!#&hNqjV^E2Xza+GBY*~CZqOrU37k(8qjHcE zWVxmtAW6q*L26S2=Yr6kH_(3Q1jPpj-9o}J`$4m96S@h&2BG`g!zdA{Axs#5C$_xM zU1jDl4JGQ1P9IK^`+GwD}6{JkS!Z7+NW=jp=&g?p`*qIcli1yF3s zEm|L{rX6+n*WwY!-FD^Mjl`L!sK6lXwUF#Y*m8HtQ!Pa+E|CjLCp@37)zqKH?%A)CDd*mRt2C?-I* zNsFBc*TK;ugo>=hg>y-1Tl}LouZ23a$c{a1 zGIH&C#r|{(=B2bb##;Ia76rM5N$sek_b*idAP5LWkUy{`DoNoA|8e5sH*bRGPj957 z4?i1*wuK8hZG@*`8#b>txS`@mJ4!kVkL&a?Yk2=rIX<|92O|}?YFB`Y8TP>S|uLCT4$oD&>mk%5TKhu zNde<-?G;dQn>~x4+Yju+U(grTzzU!|IiVAPF1TL-v`ZRN0MXGT={4mCNRJ%6Oc+07tP_!|LkO++;l2>-PD9XeiA=|B%VAl@6rME z{U6d&Dp1SusR@)E9JbAlTw(5g0`4U5IV^%ywDz5YQ z_B247I2)ZIpS$UPs9rb8){#?2wvLI1Fuf9U@y9*ysM`7nKf=GPYZ+(~>R0IfXAJr~ zMrBowRkjEt4b@`xg&fls?2IR%E^A&n*@-BOlbb$JD-m1_GuQ`K{Xpfmob_)e_ zc=}{4>4Y{^Jp*_nH*j#DGL$CoC0<5?=;M@;diZ^?1d^&Vbu;JwuMSHt1nQIRSokVH z!`4P^pMDSVgm4ZN56fz}=;;*N;()oH$R-bfEZ{LK@!%^8S;L4`v^n4d9y$qAI1om5 z9rj<5_Kp;36KPMgh>0|AIWr(_1Ue!}b1#(u-tIw~iMRLsc`Z0~gmXrctPF>zBr)Uv}*2W@c#bpVD5X(H=EsXph$kK<~}==E5>Ww`c8E zcZJxg_zapYE@X>)(8C|I#T1P8;gBl5w#Mja)x#C|vDTYx9kTZ9Z-lYCzWNy0VcFn@ zJDT1nd-atL&AuHqAl^XJFEiFe^=wjzLQRLOn!e9a6ZKk%HXuw&$EXSdGJGgrDV{g?|cxwv19F@!XoxVVkFF-y$CCT>~0PaBO%rWb^A@a#0p7W zj~d(kq;5GGOGI50`M<_UI0Xo>W8b;ei~W=snk8c-*pJzOK3tb$Ef`1cl4g~~)7Q5! z=Mw+kKMBIg%f~9kf|5RhR8A$nKn_KLlF63DUkSGy7K+`69J@L;0IV##rFF9t+i?uU zn!}yg_xP1{)4jft8Y{SlWHpa=V!>lGWFF1T5+`;dGFih}nF`UGsrh6lc7CQzoCjtl z?)@GeP>oVXh0qgYmuCMi3vH^s3qb*I%1Ru^F1g`gietnPLOCFZ7n{f4_9NkBe(?!v z2NJ@yQ(XDAP-=hZ2w&}(`&o&l0?9?dx0LOOXcqe>aYa#kWIJ=9h~)5jk!BQR71x7TP^bs$B^JySTCcMR4a05vhjipevlKWK=-1t`%Ry#*b* z1OMjY-!u5fwRAoHDf=-)Uc8P+=(tlyAE9%fl_SbZ6o&roa~_(8s$&oqpz`K&E7#EL zqn_|%oML*^zTXR;&3Jq!k(x1fAnalbAWNEv*QDcDn*?2q@WFa05`nlAe8yTe6NPvh^E~>z=0r=k-f* z0{#ICKlC`@D%yzy@J;2%vE)rh;{Y7LCjg6b0L}vDiF6VahUE zmP2Xcio-kTAs$D|wi5hS%(-~za0U<}X9(7M*u_{ofCUNv3fq`(&HcG0*Fm79vXo0T zA-WX4)cnu0S3xh?FwI}Yo=79>b1dgL{65ArDS9p _Uw}Tc$TIf$2Q0F$Cit2Bx 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�+W$QLml!rAn;RL@W(mvm&DSbGMPo>B> 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

U&%p?zWO`cfrrq%f%OUV!BXR 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

i1Yy|$4Vp_eOJVH11rL}j>uhn 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%0ADG{TW^6wCtAUzXJL4vE`bxpB*7tcGG0l(1* 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%0AAfR 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 z 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

LBq1>mW7zCRUAf{*cDmm8#gn9>qRFqFBoupeE?3 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

    XF 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
    -d6G#Y{Ei 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:dC3J%}wuGA=EL;{C=11{s=I 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

    SCpwa$T;7p>}L7QdFS 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 z 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�mJw8Pq0cFG86E#^|lS&eKR(E<^_E-v03q`t{qDUMU1!uclSMWtYxm zAZBKN^ zHSqTj{3XuQi*hK)MBW%g_6htq1%4z>O*}ZxluQGSzs&dp&rB`vh zD4&r_gvX|57(!+Jw33wwBqIF4qL>y*AraQZU4!E98_~N8Jktink7NsT^wWx$&)~;? zCBTS$;0CZt$r$USM3v7pP8*aek(G2;ZmPsw=jmx*vell06XDtt-os2gm+uh15alJT zqG^Lo4@$=R5;weSaQuCw1?h7I6DD6jq~bt^ms?*S`TA8beTqZeOevYZ>jn#KNjUlI zhueWo(-Gp<;PiFf%Hw7YxW3B*K;&5Qe}G$kWrlsNEtx8WzWfZh%MmKa&OvDHeRF+OPH8xLk*;8n67Z1p7vKZJ+q>SV3@uxpNeuw#S$Y* z+fXJFspumrVV&J|J{lZN+wn|0-%Oamt-$&KK4oPIDvkkAb%o02Pdi`Iu!53FvcB6A zP9Nk`=XVt16vGOL$OhGpfMMgTTFE+r+H^MMA*Vn|7#dCjN||o)JI{;63KEKY6Ufu+ zwq{gz2}~%AqZ++$+?W-9yBE?=^-}HwkDY)i-$w0@6k;h=IG+C@CwjP|2^a#-)DN!> ztdVAfuttjQa};o3F0Lq2`HSFHnG_0r?2n(%)&o!uDfebAg{ZLJ3#kQo3Omg-PopYeY&><_L0F0-UFz=?hECk zhSFu89=!&Q$I7jB7 z-V2xW zMYkFDwh^v@g6-fDk>R^ohHZB8Wey)kozziqk)%T=K@`+uTwM&T>bE~J$CMk1b7wz? z_#b4j`+}bxMPSa)zEAeni?`?R=8gKc{Mk)>ni!yb^hMq0JQzop%Y*gH;!f-fWWT?t z>7t@-I{G548Ple0YbxM9x-R`Vw_G#_h9gh+Xl)iY>3I{K-9>M6WI31rktEy+A5X8D zegL2G2SsER)A7_^JZ}&qzT^+yC9s9SqqyIK(f2k-q2ur>E8=2pwiD9fG`t7vZ|X|M}HvtPvU1LorXUs>X@RS7M+i%sA8+48k~k^qAIpiV+S0>ioH1IB53b)G~tWO z*J6B}s&b+Uo=Zid@kq4(6DRg{7AmIT-Tkc@b{O(c&bwFqx9nPf=w|pUes1lEj@0^f zXE!n2Ze_D~sW-rFb5B&ir<;Zm9qum8i*a)k*(8&rosr##%@S@zbJyjAT zwbo1ZxU}vCBrc9|$pEja!=G}#NrjaMlL~P1ukUb+n{SW;vlH&VE*0=kH=}bJpyRs0 z2pt()6)K*yVe(J+aCxvF{cH``V~3{~t4|cQfL3_;{2<3YZpYUnv2X~}soZpAcLew| zNE3)7dy8pYCkuw#XY?-cloSR<(TjQ>UceRDQR$LF{!v3K_LJe)8^&q{mFuzfdg{~B zUwn2UZ2O9jb@VAQSs3yN$+qfR;{fWq#h-8I%A!?bj`7vhaeuj=%~qXNw4gyRp7|MAmorAwMcgzMab?b6Y~ds|t|y-6Qt4 zB$Y;L$IbO(cPqf%tnUs$|I*^5_y?_WmSVh@#+*X&VR5bSbvzk~A9hB(0NB05gZ!Q5 zZW002Xvg`+*g^DU%jUOqx|xbhPw649TeyKd*F~OtcD*jJDv^jjfnJEG_I6<7cXq7` zH&G})BAh$I7IU4+-Ecju!9(0^CSZoaG3I8kv=;AHyzel6I1veFe37F@wd!*`QHCus zm^OmbU=*LnwmPDbS!(CrQ5KgP0LF0RwW$4CpE3Kzd|(U4aqMxiBZ^?BHA;tLxG}oj z$~UD~pWQE~gBZOZ-3t8rnK|BXXW^)Rri@?ydd>a1|1-W}_a`P?2a(RX=lg~IQ7={) z3Uy$rp>y6zuUgr`2PRd#b?}P81+CX9Cu%#>IXgS&UaXwm-aCDE{`-G4hay*$gkgk? zXq*#l^{M?1u?KcJ#2!q&ac_;Te|%u9#~+5O0ly z_l`KNEB?;Vf(hOl6~OIW3g7akEPiD0iku*ZS4gf&f|`9Qn%mNvbH@7NVo#b;X}wgW zf-BI&jDnZdmr(%We-C!0Fd-X@72Ih(#L-lUNzhe8~LmJFTdI^2^iIlT+V zP_WYW^jstZif2ZgIn6; zqZoQl7HsFaSbN9D4f6hvlPDQ6it`!k{KWiX;KhiNz3yLr*BZ=TY}#K7-s%jbW|sY# zF@whj=u5FpR|(D0hF!Be#u2-&);up5V&R2Zb)NoK z_?mvZSR+@P={=g7)h5kq@ypk-6k4b5+;} z2|*pQnU7kw`H~y+5L8*V`8Z!xy?W1WuKPCnzFvrKD*!(V&z_ z^{^?aBQold-`Qdw`JE}|w3G43?^KL``8dCDTo{u7zBknVH4^r?BO0&LfzsvR5s%i_ zOY~vW5MEr_%Aht>nep`w;ZtSJ{xVxxyJ_|#_XYLcm#*(V)z^Bv0hg}x0gCauRaIcB z!rnp~^a`~ERT*Epsy2Ta+(|~rR`pa+)l;^r4kzO&Q7qlrAjty(3Hwiw%4X*j#eW6?WI+~dLxysWMzJvVJUMtpuZgwIhq#(K<}81O1o5}BY)T;7HCc?d-0m6ywD1?Kn*H*n`?24D&cdHvHjf0$<`KJW1n*|q zd>a0e-K#1{!QTlBe?e8pyKX`o9JnRCHNUjYBH)@9fSb3Y(bg)9BRHD1&DPgMoG5LC#hWxur@TlQPiv34h8*>6q98jvbC9V#XeKCU$pTc$%dm^5aFAvm^uBCyv-h7e+Kyi%JYF_!2lD1~&9+6O^ka-_Wa2 z#HBCm&LtrYgggf3T;gXg^cFXB-Az*;zT3g$ISx(T#w0pD-&&WUSVUDf27@ zY;Y!JJxUDAEW7BbVU_(71(QSdGq2^A^i-s>uY3iMOp2ZyRyisWI-lkx3NHSa?^Ruy zC>U11U%t^wohTSy`n9Ee3QPZ(GpTh<^kk%RL?SfarvGC9k>f}|Y^qI9c}l;ro)77N zRD?2J5>l4Lu=!-!PXxZiHxmWY%Szy2`x$zIaZ418Ma*hKqTq5HI4%@=v>;JHbqXx7 zpAs84#rhV>SDvV<(wE}O?B^!?xz&DV+0UK!bDRClv!4om$`b_(r36%}wU;SC`n8R| z&^rwgcnioZ+X&wc75g8229x=m{QZ>!jysX>7an&;o^Jh;e(^qDbA4XuxHIR2<4%r= zLOaupO>^d6LEwx{zw2!xPaJp3{_IW4&TpJQ%AK0+PR*^3S26eQ)WL~KribqN~r{%1BbBJQj4w|YA_*E0%nM0GjLIb*ineW8p; zq#8n_g3dwXK!qHh0ggd>&)q$0D%#yBdv{lv6f|RbFj~v+XGonf%UAKSS)H1{A}^zy zIPQ#YwAHF=`Zp(j+?fgQcg*scUnW=0Z)rY5Ih*L5#oPI*#He`AKfTD|Yt*E{R9hcZ z>WnCTjLwj*XT>UxKCj+P?YtGwzL+04vdM4%>XOi_vzgrp$Jm?eoiUA-y?!_c@1%=u zD^PbFU2-dxN2qP~QNF4=vUodv=R3Q8-n8hFve3M5(bfkjeE!75q>F!e`~Blu^UpqP zt)obwRrlFNk`WkkhL=8eRcT~ieqz#4z4Rjer@(U3FktZa#H%R z3Q^2%gLCr^#zrIUjA>rb7X~e(-RulUJZaWmXH3)lf6}9+O@^QiLYP>hMH%VxyxDXlGAF{%^x@8!{Z37U3Y;;=oSJMLlz5xF)xRd}P8u3L{r5}$ zo>3`%$3P@G)*Yk7*4rtJCj3<3&ilHW?Ixd^JG-Uw7c^!xRq6&!BjPr8YtSJzNU?`` z)+q`9!w;Kv(pAMswQgN74ZlabM zukt^CECs6cb-%bpKsuWWa;6g)S@-MNUn5`!ZHfH+Amh#V`>emD_9C=vrgdF65 z&gBFHcsX+}H*_m;m5r!KE>3dKq+vJhkNoP_>5;Vy(iu)O=72=^&d*Zri=E+nN&G82 zGG*_kfJp;{Zk z!nCVYM}|Aik-|}qP4)Y&s8WwZV~PKk8Em^Wm~jCI4NMP+X46=#~SC zLHx^pwC@@L?u_b5ws1C(oPx<-$*sWM_n|8i_kAXL8jTv#N9@KKND)uZe?py$e6RM_new@DLE z6O_6$CUZ?WPgI>rh~Zw#yD1(<#KlPJSo$(&bsG5(qan^|+pp{p%xWQQ^+k*lXJnkY zQR3)O88|dD^hrFd*Rt20o8NK9yzCxW(AT+nU9UN#L+)v3%@Yzm?ECU1xOUyj5^TePAtTw zdE5r^F{TDnI(XG*w$45{0Ufj19!Y?#?TlD04wddh-rp5(sUHlo+8<;KQ zPKyS0P3wxGF3V_KM6S9U~d+ zP0fZ^I?|uk=}ymfZpH{kZ)f$-7_;c&i?f`Epp~JFA}e1gqE&}$2=}IDku0`j-Xg+_ zhw?LBkDVU=<2OV<&Uh8lbpL#a$Qj-ng!s8jotyU@b4Kz%XXi1e%-b?^w9+-Uj)S}= z#HO=}UO6)n1wZ(%Ef@)hF}vqyIKy{d=c)-Rl=L$wVvhGGlV&uO8HTuN9&x)4XAJC z@AgEJ$Dci^hyLNM$}>GPufBEo=O#$>5lS^`$g5BN8TX!h zsix}DZ)=QZRIS-ysw>K+z6p`riy~+3EZG?GS$2?bp=~+WMP_fa>o1{lIi&{Y;wZg~CF|D47*o~e$ zNCdAC8h2Ox1MX%A=beUidfCdKI#gINwK91EC3F!t%h=lLersgQuRi*lynsxZBQ5|c z18TlqsFy-7zXZ80CZ-g&{D5bm=D7pz2Y)3}9fKn)n)c0GpyJE!(guV{DYn#dB z#}4r;=@jKGdMuUt7bf+#yd76hfLwA`J|I6@20W81ykAE4pw0V*cLwFGzWmGN^_x`Y z>TI3^yZ(#D{m&>_bNxo#=Gv-R-q?0UEzbt#+*rMF4>#`TjC+c4*Wz}Tz0VvcVlB7@ znBe4^A50LrloNYO@xyC&2}O^Ht;eU>I=qT~DDZC!{A&Wg(`ZPX*h>86WPg+Ra`G>f zKfNCPSQ5V#+A-ROe)tGYHRHGfRO81YyG%6COU_96i=U?w-a>c<2u*mnJpx z&n}shipjAt$lc}DSD)1T_R2&+kJ$d%Y>@QopDiriKO1^x|HiUd-3GuQ*N;_MXkw0o ze$iL0JN4CzX+f&5Xhzg_lbngVBcP$3&;-y#{s1n!!3b)~()qP&gZ$cilS9aV`!-=> zwlF`l+Vg9bLPp93Q-QLQdBeh?t2Q(f<9{dYn%U){8eV6mOVbaJ`rOs7^_>XTvj9T= z)Oyx>|D5&v?E2I)kg=@KS-%G#P9^*~37xtvJ=X7r|H%4XP?;*~CW;Dogb#GB-z{eS zE@B04FzeU6SUcPLy>UXS5Qjn#S~SDuo;>Rs-eBN1u)V|c(ByYfO7;Kg8vge#Iq7v; zcMpv{G=rxQ*4@MIRWtA^B_nl5X-`Df(gburB%m;^B+qMLfI%qA&8==ZX=-?`RYWLe-o!j+c6iO>SF#@){P}y8W6@^L%D}@ctDbbIJYD#mYY{(cXb-cs1sfV$ zn?Y*^#Rsi4)Xud_nZjp9pHy!XSpru0fR=+iL0Lk3LWZdaqI4cqsnJOO?IoIeWMMn2 z8$^P3(r3n|JUT(Xr|Drw$n_d!SHETNA)&C zXM%af_b||5iq;^aaA?PQ%vntRZw;^aoM3)50d{__yFdLJxa+;jP^49TsPLeSFF`d5 z+W!{=>=zwN1s@24A0k+4Ic47#lcU-vC1g+KvsxL%SpC9zlAVWxt!t`RMlGpur&qY! zM$MV$PMU|-#Ay4l%FNxZyFbX7lbwOF?z*D3+w0GID%7b0{V*aJwK65;XPbzKdRB7P z+YnnER_fO~*Tv~=O2#66yb0v{?McRno$^paicP9Je?TXe4(9TIF}vmJSLhK^(i}n? z4)0Z`H?6sYWzzBH7{ZsoL5QL_Q{CrZmKUlM<-lq1zO{Jn?t9D`&BGbw{GYmaBLSp* z2_h3C%=Cxj9V(e~_%GuKnUjTe#zY@2q{G@SI4j<__6jvC zC!9J$6AVygWbu3WC4Qi6!MrE^W8neuI!6-OjY#-m4y-+3hzK_+Qm+u>n#&c7}5bp50H4;;R7&<$a9q z5wi}u_{~LGi7Lqmbn=&|l1!ui5>*lx&>v^{^!X~aAANFlfX~o>F@CF1O(hSz0M^)8 zeA2O49sQd2sB!Y@fGZ*Q2Oq5n!@Zu@&)F3HXPk&mc+txjqQBWS{=ClCFZGlUy4L1_ zV9b0be2VkovIid{V|6E|wNT|-&pgT}!&9-Ao8ZKZ5s13>L{x$L^Ox5N*T*Vo$<<3a z4$nO|5gUz1k&OW{6_T_6}N=a7F=2$eP*%> zsT?kVi9|=^aq3Kmgc=xj(Ba)|(DYKB#USWsr+a~PZ#+D%TM^QKKmo_rS(Nlmu325v ze#TCNNU4v^*5}FVO|AwvHjlP}GQh^hMeb!Hqqkg6xF6L3`kuj|C@b{+C*CDB%6t5c zWB-H;oJ<(z4TPC}-(ce43DFohZGLp+Us2YZzTc)=l+TZBGcI#tVEcUoUw}wQ(=t0& z8hI}!SYeE+uFcbuiI_69*jdx@ayOQ=(SE!6rh|_J!6EADminko70WWgqw6W)eS+p* z6sI04F5j<$Dr7JRyD#~^shFt&azw?L9nMS=gBlDkm0vhY`&`iIbmO!M^Yn!_RV**CYhJIZLeOf>?F&EU}sr&nzc5HiaapS>o3-%L?*Q zZqJDC`I8mvzs~RdQ!+YM_}AiE;lE@3xF#9@yYgpdtcVrK8#}}=;~3MZF-oz8fnOsk z|6_q)dUxcn3jDVP@lOQ)62z_)zasEI8pPKIehKd@eof$S4&v(r|1eOd;@1cMNKjv+ z^%t#BU=QiUJQG{o9C{cdUdBhw;w!de5F5NrNg zg9>;WC&Zuyo?=1V{6(RKJ5BBt`dwSW=>`gg+yT)?Zi7;K<~9t7^GxpVvg>{}N@;7L zJfV~ZEyxq!Q+?lM3nC1vc&wJAVTDD0Z(LdEfsL6q1Ze1MpuF3k)G`-C$zOK&;M-a8 z91Q}Fn~rnIsZlA!zq|QPO5bS8lyVu%k~0bZh6J8L7M@wp7!9~)Jtd1elcK*^0mDc` z?2|>S=tw9gxo?7S_dWSnOU`@VrPT%zYcieX6`V}$goeGfdn+XF9z5S^Ur0>6tEA`mP=fUvsl5U{1|9W4b#jt4UB5;n02& ze<6*qyFiXXn}n^k3tpE2IR@nT2I+EwxQJiXEuTdUk+l{P*n9zU2-4*QahT%hmd_%L z$l6*PX6g%&MvyKih>Q3ZX=oG6F-95G&iZco0%Q`T%L(El{`zk9Sp*YVYY~cVXMkja zbUCRw40q=Q)15OL#51FX05k9U21sYaqo(kjUkd5u)vtl{HdkoZ!s(Jj0N_mrCkfmHw)|~_SGIsY$r)PyJMK$!}A5Qt|xf+Vw2@I z1lj#DvriNb=(s;-c8J0Oo%h?#A#*@aWEwDw%-(5m8GC2Z55XO*TJJNL>{krGC9Eek39?1bfzchZDq>-k-Uv<`wy9ccZcf4D`>60go?faU#&U2)?MoVtB16U=zMD<-On%9f!NK{W zjDxw34z*ty5wJ|Wnw1!;_LtSH;loyxf}bitBzgbhOG34e(%%e|>gqS?`_eDC#slg1 zJBUZ)macG5gJlH7W1UW|`EHnt3*tsD(()oq?xHo*>1l@7h50 z$XR-$g0Hb>?#x_P)5bVBGgsEM>&uP9Z5$!EtoZ#xzT%mx9hLk18WEp<@fv^a`XekO zv!mCF`J_GhmDHZ@$CTafdby_CBcL;BOHq=JT{BoNA(m?*a)JLM#X>ya%Hk)(uUUU3 zb7D5-+n{n%dm)=K4Yq}5n?mQoV)tWfNaOpaIU;>UZfq%2li;r_FQuEIqHL?$(QwBa zFNg3o^9Ic>vmL86o320ExGhyV1^4|^`anK}u zWJd6rz!9;*HtseX*KXt1Tia&530N{>K9UxWF$a7Y&a^0{;_%zksh_)2xB& z!jHEK!2WPA__1c(I5UJPA|knCF+){T(mj-Q{3M~}UQHQ*Q9i0>5g*qKRcc^f3?Qy7 zs8vI)R^J-<^$b&fby2Ns3H%j-Kg&?QUA-I|_*1P2iW2AC<2`Q~6DS z|IxtT9{5wE7Ho8})F@2`VEpF|Mfx*Cky^Nf7iPgmK<1fshbw*hNih+Bp9O}fDVfNx zpZqfbWe&P(BQAl~r*b@Ka)=65$^Mqdv_{~#0VhXsarA>zu9D0?60DKr8=^#OUi>xZP&iV1)M;Dkd_?%yMSX2a7T41qBJ>69!?8#p~DHrkU^BCbf!_ z|ARDySta9!7c3cJu}Q_!3MIdHr6D*6nQe!sQU+PI{^R=AfAD0W4H*#h_s+d7Rj1Z1{ zYOaXEoZ?1#?)#ec)XQ@(9%lrq&dsY^U1+W|lT-Sfzs}4>X|2D`EWOgF{B>rfl|JFG z%hC{+K7^d9f8$uUbPaabt{>|buk=@&WmmkyUu|Zg_&0$@ku-n*8Es_I#ci3+>a7fj z9mye(v_NQwW=0_tAqYO9;AgY~Yn6a$_Xr!x6c$Amzgmxp7#^ha+-hNy=Bk3%ZoN zRWO8+sP60J)k*`&1lM*C z-b%2z`&+$qxn}UZiQl!)V(*`Lr+58rD+=>F?w|Ni*426c#P7?M>G0AX zfG8M_okT!o!f<(p$;D5kfNd;i0zZ)gwy~TE{6s?hPiDu-xlTV}G__WnDU`#f%B zG(VLn>sUj|3B$djhe%hTf>maYN{^__9F-nXnK>%G%UYl*onEa-73>wQq|eFZ0(xh< z##13-3lHNy79p6${xl1R;E05N$ z3z(ri#gq$XXaUd7a0$~VFZ@v0*$`F!LUBtBD|E%nL9XH_lm)d;8WA&Hxu&iAFVvRN zMJLG)o&kt$W@0VZz@#j>Q#6t(8cPCx%oHuWyroQ)h(=;tdhK7;kvHrnU>GWoi7{v> zTsJnElqr&+MDA4qeS|xpkE~1dkz9s8!okSJs>~M(Ch#u|{8@p&BJhU-|80T4-Hv=r z&7>UvRvYfOned!gGKde#uL*&ERbNnkO*^!a{6YCOZGk^1za|;@&nSOYiwVy$wAH8S zsOou!_ZqY+$Jnh@EkWyI$$%nB^&$cV(ybM-ae+TI3bzLSpch3e{2D{9tTN=v+WHpe z2o{(DrnLrydNRKN{ZMjf2>R^|GEVcEnzJU{{+0sWt{TY5s)CK4z72h>LZn2RXo*z` z48;iZZ+!)q;O_-Pe!vbh?E!2@!UQ`z$uiZHb~cjbauahlLSzUrXAmM<$Z104b?y)0 zd=0jQNRDS#`}wWgU3cUPWxP6nmXQ_&~@m-tB)Q<*4E&^ zGHzE8AkZV(st1SYhO0zgBf{yg#F>aK<5zik#6j0ip6e|CM0X$DyUxx^7=0r^PG`cX zY*M;Jb?W3Pvxq75(rbxE&RJ1UUU>K4%k?gk5e;Wdi&L{o`=MzEF;zGGjK@x6wmUTo z2sXUR90O8!+bYRKE;#-ne2GH{3jzi%qF7mePZNW zp$n$B@pC@30k0e+b)Iu00XajWTZc)-aN?87*U(&J%E@nwB?98cXw+z8|Ik z{V`4gsW$gR2rv{HI^WsBP#ouj(UcvsoD#=!3isI+JF+mEvO|_r8Z)q*GLXFYOW5Ia z^2e2bNB8{bsH70(ccNRd$&rP+_vkkC63zw25Q9)tx5~Pq=?rh>mmQ#MY5LWvTlQ^r z&47)O0^QET2yW7rm8!3bmKl(mz<*-kIcQj;2>$6eLF~;{Er4O*Q{7ivf zXtVH~b3>Ehnwv95pH&HB%t{`(;}RsPG~Q;=$vnyT)EJXFWDM}2`M_pWYm^a_n#o_1 z(T}QK^0N3T*vtv&%_UBfv?fsNkxa=N*nQEfLe7fYXpHA;0kd$b?ZPR_b!z@QD<=`t zbnDOGsM7o`X13R=$^Hg&_pxE2!Z!${-3=AE6S3R)EuagD*sZvR;qrd+<*$GjHcY|q z{bbiga!)qyCyl$%xF0v}0^Ce{_2ZXF&^;$MF7WUA%GZp4EdE-c7j(3YUpgGSi6D2a znb$34a&Mf)uji{e7ih+fp3Rs1%s#&HnO%U5 z#G!HixfZ>6RbQbmt;5ssqC{$x64`~B@C#zP5wgDf>!K^oJxbta8Q*3ZoFd<|Ht7eO*8qfoL!$+no00QY+_O^%A< zGC?lp{Us#bVDZ}Ulq{>7V(6=}rWy?aV17+6F0RZ@MzcIKruZ-ctx~-WW~42RMb)8X z=5ULhFA^qRt1>XDtxvTP4Xic-wNbPD##Sdv=$30rsy1ztKAvg=I!_Q2HJ}4GLsJXG zj`_PP$9>Z?lkBYQ2VHXbanfNQw%UM}nKrN5fR?Gkt2UrzM!>5!pk?am4q6&c`BR{E zD}E|5Ww|lIjbFG45?8L&XrBQyosU~+IiX{XuL2FMe7Og#j21%djt>n;ddn znZZC@r*-RPkj}uwP|^h(!^$GF{+AW4A+1yQ(1MU4grk9wmjPLG&QZ2d@}s{NJS;rt zsw@5ZVQ1wpnKL_h$szxS(=VY6FC{A|V#4x7w){P^g5Ad}#UB~ZVo9pxIeILD(uJRW zWf02?&B<*Ea~u|)N|-~VQYDO@D7g%|2k2)kvThw3@m>rDG!lic2^2Sc1O{VM;6#fs z>GAVezlAj)=(Co0X}kUGKMLmn(QU$X;%tq-STh7%WG7GlE5jja-w2wk$8g4sJ5i5P zoiR0Uu7whbE|KSEUI)(<$Ksj-rP2g75(->H3g5Bo48Y8893*n)R!AKs&V z_@N@1Ofm)Ka^1jg{(oFhI|C*TzM)BCI&d&DAPO@rqVr=)Az1W{8LQSi*Bjc}k3Pzf zcu&8{l%}>wdw$3^C&Vj$L%AB%^ZjToDbJQ>5NZ6VhN60#`eADJP0e~6AfT{33i1R0 z7YY7716XhYxun17e*t0xf-5G0vxWE$O64~SbBS$)IdvE9q(e$z}R!i0#z1P_U4GHYcLEZk}C zIa#YprcQoNG6^ySe5_yd&OF;$i#^f$0&N*-NgnJ4MJNph2n{vnP0irEa$zX+@%E}p z!yWDaYkK6Hei?j_y}o+8dT)p4H@9>XPDPB9@v*NnfQxw9DuX$TBhgNpVQh+ePj}|hjKSrbX+~$n ziS^T#`1ElC4e7_EOoB<4Q`9EcShgS4W=s-B%Cq?SeuSU-gZWu9jGsvh%byR2*7OhnB^bfT8O4tR z4n{ncfNA8N@v?=F92IdLKQsP7fL;));AxaOV_zyoPc213iMxUV#qqNxmbL{MN)%+u zEKUZ6+EgmFv?ZM?t>`Es5DLoGRhwz)WVOsRwX`XfMM1XU##F&3l_|JBohnfc30g@x7?42A_k6)mG(If<6&@b45c2l$Vm-RO zY|bs+-h&$bNVx`}%GmPJ<`9XVN<&lCzp&2%O#*6^^vC)GO$LsAZgwXiL%na!J^jn>>pXre zqw*+S%05n?P?Ca00A?sBv(2gd(7!I6zi-hV6h#-H%{hNJ?OwD@4ME##SN(pr&(?=d zw`8Jlo1qK%YA4lJV;g~v@I$?62USkFG7CME8JK3QY*V#JSF2i6=Qe2-pw6a6FQw~T z^q}dvn%{*#&#YgF!Pd`HOh%w^n}MIR*B|+>uU`Xh>$gx=xQ+Xt&+0!4wf}?tm%`EQ zxt2F=_!V~lh#n2>FNmvMR~(6+%&xpJQS`FL-diy@0^Afo=dHLGhxf!k%3ImgIy`z3 z_}Xle%ugj*Vv>B{CZPn49&;rb>f**c?dny7-ZuAAMfI52TSGwRDHjWzEQCld^O#fG z47(ix_Bpy75#o~c?{(j~B=p8?rgn63GPXloZfGG_6wjemydpo23U6l$55Gw~lK+UV ze2l1*$|`Ged0C&6i#=Z6hdzTP;uBX@zD(jp(N=*`)yQ?1(nN6S8$~TC{r>6oVaMle z*!zo{&FDNon|;=Mx|m<|bXXi-d4>11_;_}v_gLEpU2Jh1D?>}O~lEiB7EK(*QJ zwCK(Jy^G$>(_*(%(*>XZp8cb4;92&MCkZ^u{xMlSP10?<2eil)Q5Yi?nFK}(_K&f0 z(a2yY(Wu(JqE@bPihV+^GPxeZ)noq{M!@$A_?dqzKTERs`Ty66sa_BjE)r*m6|vm04kM z(u_<988z?)HL&=_Md*`c!gJ1S;M(pDOw;S#+gCUcWE(W_J=?&~XdmNecOXX4wyyj5 zX-hQii-ZBj8JQqYwQrl+SM;B1A4KhcW%~yISGNzMsjGb+pxNgt6z2~xyPP%Dl6?5v zXP%cn`#i9&AMoD&Jn%yQf8TkatowPO?B8)7C^0(DmaG z1lm-{|1=>5MJ92JLck=-{*NZ4S=n2Zy_sC% z9-xm!sfO89g(ekP$R0Mxcc}?!R6crlP7w#t%T{^VAIi~84vAS z148MMlrGFzxv$;^ccmU~Qnz(aJu!N!j}yBMK0sbQD#Or!o1%Zln+chL{U*J=D$Vk$ zSM@d1l11%MF0c;&jsP?%)41wE`z;C6v<6@1F)Xl{a7(|mbf;hFizdOnF-5;XVrM=H zr|YX&i1OU~DN}~C^Bdh$6lElGN?R74f1R8Cq}$kf&YDE#lXL+3w|hK;YbhNgK%y#g zk4=hp(6xV}Yp=c^-9FyX5w?F8-U9_s-fy4mW5LaHmmAl}{)`iIQ6?IV-j2LJGYBw( z96DT$yq+JEM$?j`ZEfWBQqiMq*9p$FZH>I1a2v#o`FCAiD+w(Xi{|RSTnHmQZS?4=8X17kETvzEa$4pw4WBx zoSb6S%jzs++Yl67TLKiEPnec=nGW;{%~R+cLd+sg2M;m95e2K!sni)Jm=Lpc)4@k? zP$6^$BtdG!F`(=}nqY=qRKL{rSa`2K`XaC3ELF=x+idS=8Gk_wT85q(viYr(ybwH^ z(7c(hUxv_L*ZzL{&aW+da)AG%JO2K>E2`uCUKv06WpRN98}^P7m3@t@Vdo*Scih;m zWUtlSJ)=13i}SxrQ0pi?_%MaT2J?MoPks{)QX-~krR7ElmuB6oc`uW-2TRDSdE2_o zWrU9r5W_=@7_MCX!=0Va9N;mYu6_3dHeO9DsXcb{=5jB4TDj|gpAx;vnKC%dM1sx>V)!bEKx{qHG(Z4n`(StH775l zDsQdAs!wUuoOK%icuVH6^K!lwdu{1aY}KUcA-A2Y(#jR|z@HS3wlA#wH_uGFlrJNm z;2CJZ#VaL&h+qIg9+GRQCE#Xww`KNLH2MCcL~M=i@yxgxSa4P~(HCw20E%Vr(k3oP zr5k^7t`i%mAznL$((>xLV&KdAsXq5aeN$j%(Xwr9+qP}HW7|f@wr$(#m>rutwv&#X zbetXQ^||ld_r7Y)IjU-YE{z(4f?%G*9{`S&zH+?+IeuV-u!;tI%SxESqSLxVG2L^$U z!t-;RC}>`DVXGjxY9XB3_|;uWMb-OUGBt?4=S{{0)f`C1G-?sRx(AWhkfc9M!(mfC z@bhfb@+MRgsVLJJJXTVHI-W+I+QSh#zeg{;qTUXvH>`k90;X7k)~h6d)AU6I^Y$>0 zK=eBMMS&U)%YV!Yh5ZM-J%DA9F#kfc{?0&D=r$X{YaD-KpfRM@a=cw!ZSUp-}Ob0Y|ZxcZm}i zPwV3a(fhyqd_Uw~;3A5Gf88lMFR;EycLa(s+YE>S&qG7bdmH{+r|TqT{mcP^eEaYeS5w8f6W zzp?ET9Ohc$(lEaLYd8KnB<~%Uy9!&@9FDvvx4&_87hE6ptWeiZ9i*15bvx3xH(-hx z^5{WaUnpLs@~#unJiFWgYJ%b- z2jtCZkgybdVmAA)64J>(y~Ii?&CNH`gG6ZqfC!+0R2S1LLz*_|!_C?KF{S4rwVy(| zj9u&gQ}xbgRB{aGRK7(PWM17rWxk1v!>n__{o#9L?se$Nr!!S;%4@Q8ABvtq6P z32T2AeDBnqMr+p`4_hqgJtcD*o+st z7!d1Ni>9W$#e}z>qi@?APJ3OPr2B=u%Gb(-=ayEyY4%0v(45|7$xgATCe$|sZ~p1i zISyv?w^+*14yqpTeg-;o+mh4+%(b`YeS2Ch)i0immuUPD&>zw~WA0aT?pLduuH|Tk zRiY~zEzMGd9pxMd&rD~WCy{Xl;*VR`VN9%PT}yE{yAoMHv3IbqrYrp*fBBR}c`E-t z_Z*c{V-uq)KSEkF_g>A2l}OEwUlmFVaQwF024_*dalbGGz-YX9wKQuT``#_3wG6f_ zAXqEUp7W^`3?F@xj#~Ch25in-T%|A zg%ZHZD{K$NH|MOEZCZE>f2A67`gPM6nK8<7_!Q$8*}gzgr=mK6cw%DxJmwgW%ZL{G zI1|8QcQ1C`VRTra&*ekELj{l~SQPe|vhnhV1Z6w?6a042>G(Xfcmt@pD=zUm2h>=! zKOMbHo(AC86DmDqT!}DVVrdw7ciQ)z=IC}Gnqm7-Jy0=>;2@l_?JUsyz4~AGg;>A8 zOnTadXZixW2L+pqwRaLW|6rKBC7Zl0^!CS|G1I+LAl>r%D=hf}pOYu(ZiH8ktriXH z33f_r?B0HhD&EJ$Y4}2gniiFErvr$VnDc#iGbb+1Xc|Xj3AbN% zo+WSpA}B9c7GZ($V4Oi1FD=v0guiRg)Ok|K-<64x$g@znyt&{VIK&qAkvQUy4pp;= zQ@n3&!KiGYYP4mBxQUicCah1w*s3eTgO>kR$J6jQ8v4}!A*D*1*q!uG4!PFq2d?hs zcXoiE)WDM8$~K99H<$+7#nsLe2r~!N?fI|O4TrjByyjV-dGhJG`4k7&RIbp^oQ&;& zihX;=&b8K~mw(!H=j3+c^K>}kaRqoruLAD5@%A^g7o#U003_X9A!g+-aZ3A^3_ci1 zV7Lbf#Lu4=H^m7t?dl7I#`aT+ZSv-Gf|afI^kfk4AcA)O@~wCy>vgM%{!5MQ@6XEN zvtZxSkKe*Qy@-D5fKK58M0yDWK`T~(wOSe1O1x?~mY(W7)DIXk726*h){Q_z$H|*j z&3f*d&K(FeE_@dOUKCCh+h`ZPrk0fyI#$tWZ*i`BvVBPy8ocz2QDsDJ(jJ+w-5Yi* zB`%oNoy@?OMk~X@Z10n7s{(J!lWZR@4&6Sl+X%bc<)eWMsja4Hc14Zs-Ldy!;;d3N zB@vjJ!T2*kIWVee!X136t+N99oqFHffs%eCS_o@(TbZ1)tRN6vDG%s}**o^iR-Nc| zB6j*AtB7_@l#Tcupd4-EWs9Lpx+w6&0SyFKVI`8qW|et>Iqgz>Gmz>P_5S?rQb!w8 zsfm&5W*ARd2Zg)#736mU;S*U?xy4Uz+iNM5*#igxUEJww*TKs0&Ap^|Jw%>WDCMNX zh~sW9$UlprHyLFI1oG~dm>Ckf4^*-eh%4FcKT0Ns9}Ij$_JMoQlvTdU@zar%3q;Aj zZGlnx?gEquMa`6-mnL@=qIE=Ik7Fs-);y|+pzmkr#%o|d-7Km!6vf-0dOYzitQ~B5 z!=$E6L&@w5Z+V#hC`#-ZGwF-Kdup4`!Z%ib>s=B5^gzw+of$ma==h29+~6d?TiF++ZSn9+iN1OL1Ke7!k$9?`dk<&#cS18E(!!cRxQ8v`U-4=U z^!b{K5d5Xko6NF;N$%AM^#-wdz9ETAjXq`*s?s6qkgM~-XIWLHBYb+XYBN$~k0S&iQ2WD=kM4@>Q}3+TQj^d%D62+#b-o!Zx-2 z30GtYPuz3FA=IrShn-sQVShNSD|Ln!Kx0E>LKcd*o4phuD&Vdji1yghP4nQ8Wbyg? zV)l26z0%OwW=U_FFvxk3zC3RD5vtNcb<%ir-)P)8I7~%CCO&>c22pVKadw#!^H6yt za!PgH=}!rA9-0mNM~tAlB)0=J!=i;EfIqP-GZlIT?N?op8^DQ1CSctrf2=1;ofddx($sROsR*UK$*2 z+e_dR^0&s@=P~Mzk8rcxbux@%Ov8L>jPEUA@G%(z7^PPPu zOn*IXPQ(53^L`?@3sfU2qcrtw^v5MT9K|R<`%5f#rdw(gUUVI2-I{y0x0J#9Z6*1& zku>OrRU0wRr!JTOx=Xv80s38Wyv8K#o2vIh$AwKVb;eZ2mIL?V+wu5fafqBr8>dm=)P~K?Tt1{#d@jW_gBAzGs1E1 zeo40*sg0|sC!HGKj;B$+7*%b)oCLA%Z&z|q(&pqNWlbEWr-Ho2yM~1)SSIU=1Wirn zLzv1GoY>M2Vlkc8Ms)-c=am-JfQw&sC?;bLpdZKEsU>FhQXQ}J1axX)e{zwx;o5Ds z22tdAhLycXTMERm>IT^Xl?cxB12ooDQwurN(=zYo`>m_}ogo#o{ef-0Ujvq8tNYZ8 zZHzr2so3nsX7g$ooxeQuYPlWR4DrdBb=o^_Cnst6>+;_-TI?lnl!p1wA43*lkLT64 zhZKmg;#M%Y@NU4&)s9$PCla;2ZMde;EgA`OP8lIKKyaI)&=-l5bSTjUCPw2oNjink z+4qtW0eJ`up=CpH`|~axQGf3EiwKslb$(ltx<5QGW0UD`hSsnNyV%V9J%s}*(p0cg zU#(6Sh*62FNC<+Oy-7gq5QKC%=*a(EX~YA8GI=i;8Jk${hnxL&XZZr(JBH@rC&JLl zS8?m9xA)8Z2*7^*bSU%2{s3Ze6_E6wF;VAEX3$C}IV5I(h2qiDuA-C2!hl=!$7kn*wXRzIr?PQm+

    xmo_XtY(Tfqt2Yb?n&?I(E^YYqv396E{JR) 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%0DBK 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

jz`xPRwjZh{ch6GI~L@EwN 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%0A)EOOdaq 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∓NRy@KmP$*R={6X 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�J^D8}-X45}+2ddYvBkZKeg=-dOTy)4(>5+wLHIDU1&$b2T?=Fh7u^&^`M^QZDZhS=hR?QZu6WeLR05n+dc(OB5A>#QN7wX zIlXuyg!f!frCEQ|L=hBJJH9ht6=oZDk9LFJN1Ve(wX^2oDdURlyz|%0tPFnfy;S@2 z#i`)ze0T8Sew;fcg?O^~tVCDPK`3ePJ>>LCgAmio3fVV?HFTVh&MdY;Q19U9D$>=% z>G1Q#Xr{;3vQD?ho}`azhfGusUMbd&B^2Z5anHMp6Ec~q-F3^sk#T6%)AwME(9*IxnU;Vy%M(lPNG{Ql_OJa->2li- z@U*|ff)H=g%082u6~u(GU;HQEWi2vHJ2fqXBy#c!Pz%L~TaSZdT*%&)O+>EUtnEK1OHb-`KkjLA!!)0UjeL#q96~^qC3T(*o72X@Ci= z)e@|NbAff#XFl}6B0>W!&A>u3Y@@`JWC=u(sW%3hQVz;23>%?(NB6!ZD!!z2Lfp{Oll5L|k>AiB3{#>Zrgf6#!bJ+fc1A6w` z{p0I9m)VV0$eb&LZ&Ph|l*i1Id{K*%i_)1Yl8WU&dlp#hh6xPM8x~w2p%-5F_g_z! zH5jtp_9A`V#4{z_{#F|W9nKh>8koI|Jl^(QD~hQj*p!?D--k@h<75~o;3njVJpFpM zG%Qs3^LblL-cm@oh2LE&Mn%#brD4wn5}CS^Yc)(uVQHA-B;lqJbz=E2Z?3-YDASg1 zh@Qix06}w*jRBJUAKe?0r%rvFx5*BbY#v2#GH+RNAuXC)1i6<^l^Yv*XHJzN>Ikix zSUiSAYr6K60>h16g+OqYVmMXys@%0|D)0H|m*cszS7{{QL0Xavutw~i<#x^1vrw$+Jq)Z~2ze>?G#05Ey_mCxZmj7hykhQe+{R*_yA4(8FAYOZ zvWb410k3cKdd9E{FIucnfB#J^^BnU~Ricf-yAu6!^gO4^$Ka7h;(DDpn`Pz36dT`u zXF%|SF8#J{(zVNorD~vEkiL!ROn9qir1oNLcF@-po5J^ao4OCroWs?h*yeQKU}%ms zmN{wzoR`dV*2*RNHk1HZU1Cd@D$nw8|d%LAGNp4LXKGGocs**^~-U{eVr;zG;ka%=j^HHM%FXlwa&7D{1qDY zsz$J1KHCfiepKpJuFr!T(io>oR7jEy_p^lrFz^Fz*8j<(Y-lm}zYU83YbXx$+z7RL z)dfBX3jqerXQD9x1qQ_LoH?sjX=H&>l8-0jTwAE_mTof^an%f7$Hr@iJh=Hsu;sw+ zL~hP=VmI#=)UqS6ZR}6og1guea7cQ_JZu@~8fW)%8+sT*8k!kc<96Q|M{?3-DmYTf zez1%3+l~9uw}uQ^Hnc#ZFD^Wem(rOsk}?OJ;Z_EHBH47*CpaIlG)8kC*Ty$%$F9Sw z!>Pk`!d(YD@L*GaQrUBO;6KZnRbmUI_FVzn~I^bvms1U>U^60cS*U&n|vsts=Jm-_u2!hy4z>sxfa-A z$t9hddKDFZA;1UMNxvqHUc&MD%2sj6@g!S-FyN1HB_!!eNUWs8@=e}Zw(2ey%<*5b z#*{1beD{9u!PAnnY+mG~D^@!7mHIRlPbfrUOPFO|GVY2r@As%Tc`oy?x5fLc)T>v& z@^XIAl1PcKa0S}ooRfFyG}@6gU7Tfu4|b4+`pjK%zk5sgaLTx_!;*)D@mNO!6a~9= z*gLAKp?)ir>90co>dLM|dO8vfDse-l0?6E7ZQ@OK~>%wTt1b4{srCeOq@NHsDu;M z5YE+c3#rlu&S*qZz_o8*5@S86_+#LsJ5CcBl`tiy1bLVc z`t$0%%WgfD8s!szq~bTXm?OA`8~FH=$FkY0HiFHa6uuiKVg}J}_nG7V-1Adk8TP{n zEw}e9?j4->ZDH_^95R6-ckg5-8z>>aFYDtdi;XZLw|F`qDP<;VtB9@iOBu#=j)jS@ z`0Th4k3G@X$%`Kb*Z2v|$HLo#M#jb_^jI`PCYlm* zU&CRBsrs)R4L5x@`M97_w&Z8}1uKTf$J`{Pq%cI?!xEH9vHf>tTBgC-D)}?1doR!% z$O{C-;3`Mdi{%)qRPyo2(7iSb17>0NI^InFmNCdg)SYUjC zhZ@TTWhlF8wZzfR;O`55Gf7Oa?|Q=ckGLQ}6K)SYqq4FRy2khG_nt94ePtzg9w-VU zkry!g5eQADe?%Y*sZ99IA`J-Fz-KK`7#^s>)|h~1 zE;FF1qs{=hWYo6vTG2+qg1Ws;5Uboq=Gi9nMX!&!8Zl*{BPAhp*UyN$jaCotZzipu za4Uilb?X(y<1ua$Pa6HURt0u1T@c4uzX*8Vx%_wHdcRKN-*!*kgFDe`*sw zzSkYK(UmMJ)7WZ%2Wq7Nz@)c~ZzlJig;$)))bDr*cjY+sbVJh|GI!;nfrO&XT_!NQ zVO#4i<^-qDYG!NYS=psvfuSjIE-I8**>!`Fo}-bAP>H`UtHgy7ev#I}ouO_b(_*TUl758W zbegY^uBVUl7tXz@A&S_@r!u4B5FdWp^*0qnc~HT4Wcc6v9w!wclwynZ0T_*pQZPoR)RxA9`t#?jXp|j(7Xoc}s z_uG^Hzr{^`^sNpkq|5L`ySEudiD1dVp=_@vL9nEHg57I?;LqC9y%q}}i+>-mmI4pO64E8bY8R z%A>vmT(2~O5!H1R$Q=E*^H554P2EcXsbXu1ShIoG!tGG}os8FUi`C>SbAsP{h5D%D zz|lK|aP=~iqosT;;_Ti9UtjCwFwh=XNc@B>u$y2>`oyC*2%a~|JC(X6V2uEw8B0jb zfn|LN*}F?|0qhnOD%3^T8^4gI2+Y z6HLKw=%n*hw}J>%#DK5$dYp`tr|>?p)=GP;rX#xVm!!7Ws4pT}bDc8JqrF+jHwoVA z9#NCR{^x;d)bw(Q2hxKF6#R)uwT790oDz%}1U=z8 zloFYFDr%+7X1N^ce{xf8RYMT`6IF~1CE$yy`O?FHtbB6Dg^2aYe1g>{44Z*X-fyqQ zmyh+wFTiKSsTp}wGWjk^OvJ3Ug8Svf8clM$7-de)(gG|Cwi1qZa@_vqDeSe*JJsVJ z$yE6(Y5kc5<|;!REn%^lPVyP!vQMWa*?D`!vCIi&^1@}O>LEg9TBYk=e5YI!xy*C< zx?(fc5np|Mq;ulj%Pl3xz3 z_AE&pU_KOta&5L_E&bSFZ~%7dlHT*vAfaeBfL zl)zgxZRL!91U)hR;=&n~iMhJH#^92sq*}t6xzB8Ji%eM7t zt3__MYJ~n0M6u~z*Rx}t5x2WBe^(3D6>gCY=;uD*Jc?~;_T)uvDf7xPH#pzA=S3A2 z5&0K5DX-DfvaO+ywG8jxNG7*O-s0ZN{!J-}A@HJ(zg<&iynB_`_I^To_3}re%4H+0 zMBV{8Y(yw$H)0QAru)C74(yJ6`(BM;(XFrv-V4``qT+cY=Jtu}FBB|@6GoBxw_Yu3 z@icoM-69-|lNOl1XVF{ipe;`G2r{&)%^Z;KU=+WvYo=NHv)g*k;?4&XEy%xgGjMP} zmStyQ$?M+LrxdSrCun+`E+(AQL3^7lL9`gn|7Xx!`7cLQx2YvKKc(N=g^N(OWq-tYZ}zP@eDCErWn1b;f%gdCO5g5aDgsmeBmfZK!i)R2Kb zIR#55uSa+N-NM(}dxZlvMai@dquOd?=ih17xsTWl$yXFnG|dISi{*kj#~+-$L~<~r z{w=)_j#L{E(Q(t(x-)OxH0+4bRG%uvo@mLb>FO~I_BrY&5=Q2DIiFOM*fSCQ{vKkv zq%<5BwA}b-!tcITIa!%qSyA4)t3OBOg2zYVpW)YQh88VR{ZI-Q&#Hd9__hs_Bv)!1 zX}Qhf&@@Ra263>Ko}ZPZTRh8%RVcQ@x} z1(eGTqrF!&J8$O0h^Li;S7LR?()Hqve!foSM%Xupg&pwS>6NWKq7qastyBE39$ysb zr+(M^#Mntam@=)t)=Ii3qn$~^5s~mgS_tdz#p8((et(-_bK`5>b(^BqD}oUCSXNC| z^ALxLiu>v9Yvh|)Tc=Zp;HU3r+mP@LbZZ>ntSxKs1X(RGJe`zR2NBTxLu2@*= zwi>mgp_41qd2c#NYQICQHYj6 zq=?uLe4OQ@3F}f_IV9~X$$qc8WQ#OipsUJ_bZlT=#vO|u{iOFXo)F%PvakQUpWJs@ z`kSWeRnD@r)sK%cdumBrUsH0zg9uI{MYk8sKH_-LSY&t)bI46-$$Y&uGM^34Q^fYi zyuS8a3EM?6DhZc%L{bh8!E0*w>wTy}`B2g0jCu5;qMR@@_~i&lIm9CNIg&akk6r+y#Q1tb%4U90OFKKDddvELGeS3bCBtmeqS`TGRy z#xR{PpSnNsLyg%sk%qC5=akCeO)8q`3UCT?Mef%5&KLPaFEo(%-8R?LkA}FfH%1e3 zy>Wh#4|Vs5#w!WkzPk72lF#d6H|IBJGw0frmciI0+(awj`<)b`9yA@O51#${3-|CU zzk37CthWknQ(_n|&V~{pde#4ce%?LsUm)7&j)*7k2i2+ytt%7c^ALl+ji5l z59Dl#K1%eDyydjFMr=l0X?KqEB8WA*$|kON8mQ*#mUCR6>nxUX!912Q`q(sV9cm$1 zkbd3B@<#6io@D*@fqvpLUb@}q^HJM{YsW0MjD<{L6FLw0AOu7xANd2l$i`TbrRauf z5$+%qUoYv+IjOM81dCzNd|5%7MpUnwAsqa;Ymwb{da{>V`&6#`Ld9X~k4#tAox>$Y zY&@=~%+QvbOao$GXyzBper~m7(TFZsc40z33IuQTObSWoOeVDWkRJmJPJ#xt=M?{z zIt*Zgn)hLr62CXwd?%>VTaU~N^B<`7cRuLw#SG7S8cvD%K5_h++T_5;pMvycaH2bR zkN2Lvkblah^0hjG*-l1@Aye|La;d^pW2nkQS4ksn6i`>b2@nb%E4h|wuRkJzwwW zzn)_;9Y2gV#Q8pf^xjD9po24(#%+ay=2h+a8;R(wZt;@Zb7ja4hsO84&pZ&*osE*q z!3o}ffpSGL+BTjI5e=)7Ai@WPYHdQ^xcRaDsiqXcDu0C@SbHv|?rpYXf1=+zf8$s7 z!xc_`UN7bQ(aNm132sythpFCUJ1LQ*NdMCnrz^yJzes!0rRidD;04#^A)=`-kS*^D%GZ!rF5<+uYi7u3%!pYSuXpJWbt~)(0J2d4m%awA1sR z%s^qNLyFFVg3-+oh%%Dgjm?7o`RG%7{;5{)j4Rgqz=to7#qAO03jBg*mgeSL&-L~r zvb2Wsp*c(2cc)V5-zO+oN5Naur}^W7&kKMkjbnWvl%WFJ!2;PZz#>Wm;4uNbs0^5Z zZ=?l-6CBU=xxiGoQvqMlvriHDB7|YM-B#j2@*y&}n;#}f&UxlW2qKlA6@OsvN(KH! z2)ElK3GhFy?<<<^?3@GvZ%A-d))frFy3dSg&A`)E$V8BOAZw2wuPw!Aw7^#upTzyb zYC<844s7sG`uekqR>-Gwimi~#Os!Ej+=*(}6VU}HcJ@Q;@gdjkRrbJfup$b%T|rzn zM0SQh>U%nw(AU5GanthH+MFq$@lik1XtZ@O(`?MM|M{Pb_?@GcA8Et<1ujxWOB>+t z>)~&T4g92|{C|_|?Wg3yIFkt9Bn*xWh#oG+lRff#S--uKv6oVYS`#UwHza>vnYXdp zE5G8r!O86B7rZHMSeJwq32hLsoW&NbE}cCya#mHh!6FngTd2>jb%U|A4d9}V{N+Vt zdvbBygQyjDDA&TJP~%uf?`?7!5n{&ay``fqP#UQUucJz!h_&f+`%eLD^B%WX6`tSd zVMiEj)E7U|CbGSYI~Rl`QxDTSzK@{XIj!m1VFH8QPmu`RRmzJxj(pe8UJH6wS(irMId|fFA1Hd}nF6wgLl{;u>n|F}Lby3KPQn;sO zmwyosfK!&~JfOb5w5dj4u!-|p=ynTuJeVHM{=SjgSx0d=evs5h7?swknxJA?O^bzc zQ8)KZ5rh@ahlF`8WPN0s9zE*Gm*_k|LUz3zsSg(L{s5b&!r_etgkZEVd`Zd!%nayc zu7Fvr^WYIID=VW*Wc$EUgo&J7%WXOND2c}^a<*lXE+hL(up?rM(DP{P~N|X zLp)bPPRVh?aAATsa>DQj-Sh&B|8vooVY&5M>@;9F_Y%y3JvGoepG)NfHUsovRE-V7 zLY}$d07eV)&vegzyIhXIOJsF&rhwV2curb;PC5o*g?tp~S)Hokz@e`Mf^}bleDCK; zG=5G<=fKSBj2Ew*F!W4{o3`;$?y$&)*AfV1v&nR-taOUQ{G28;`Fy)7E+?@QAt&B_ zq@9Jy9o44VFfsB&zNmz@8XbWXsf4r_(>%TS?=`YvH{4q`upQ7O9R1KgF9PF<*w^aK zAyy<|AubZ^gQ5d>dUeC*A}SI3r%l_)o@cP8C+Y)#laY9n*rk|XNapA3yEQ+oe~uyr zD4U!z)ER*;T6v1jGN0|o?_UizuPhPn=ml}i*!RSfZR%y;4q0z)>j_f0p0h2W*5#a? z|7iBYKsl>q5ush>w7fd4Oy=trZflq>i_~$Tf;>dGB`t?fLGcNN4$F6iPOWyv1@El1 zK3$P=X(UC?&SY?+N{jzs_ryp%=%`MLAOCI#Lw7E?byTeOKlpmfu&AQ0VVLfaMpC4t z1*A&>DM7ls1f)YcB^3#!qy?nAL0}k4O6jf{KpGrEVCZjiKlk-M-}~qNvG-Yf^`b;-v zzP_|f)xM0AOhBK_Dy6^~nAW)};{^2!db&UJ>h*MkrMwx>o1+c8%Z8jrO^By(nyiV0 z483!7Q!YB&f=S87|o;vs_A%Bd_Z}l$QNE z$|xI(C@K@k`>(zGq1^ZSbn!RZx`sYKhCd7aV3r(ND3S;(8xpTtu!onHabu?c`7A|* zUtCs46Hv~1au|#ir)g(c&Z%u(#+jKb?xSlPs5Wph6C5kz_O0yrNDv+FLJK`l{4tip zrbA^EpX`jZTmc?Dg&NGFQ5Q4NM@7GR00%`%qDC68~`AhO?H@-B_Y;8Q&w9yosULa z_aS2$fD(06`s=*~E`IaCJ$zpL4JQbF>bNa6(Ep&Q@;(Q|3oDw-T2xcl$??Uuxg)CO zew*N*mvc+82h0yqIu50+!wLCYVfK|a`^`moNFVFU z)n*y>-LPtDJ}iorc2F_va%eE-oQ8|)Zg}Y;wCC;%2_i*`wD!-=lgjtcI=*BdiH~yJ z5%qkKx}v#dSM=iiOX0dscN9GQmP-=FewuVkLhE z`=)_Q#5dk@KCVtyRFH3sZ1dM4jlJ#JFRowX{GuOmT%_>ystdBpd|Me3GKx860hHrW(JAQx~Rkm6@TLeV~ZwCy+ z^}$WH@4~zEIE^#O`)3_5fb`c#ahkCZJP4D6pTqld^hH0nokkLrv>e{7@s7yE7aznp z9!5Mqw-PHCq-rH#NR4@yFGNJ1gg$vBve&>}_kvY1o3c1ur*-EWxpY%-{(>5|P=1C& zV+$^;M=d)6ITfV!(Gg zG+CPwjCK6=lR47v(_8nwzO)(Y1m>JmhBNjqr6qqqu0NZSyw3Xdl`W@h7-RA}c0d1K zV>D4To2~c~ZD?_qzDQ{~{pCS(ov%=FrW0#C%3ajuBiBpwy0PW-xaMmV_nXYM1FM=4Q&2ki0WY2Q8s`VOmkK@o!Z3r5zd-KNsCqI^C8sx{$^h`XYQm6nKvMy3` zNB8~kg^;JVB)BE}UUl{^O1(Z(a8NO8g+;C%9psZt7lR@a5gpp&fh<4M`%$D_cuKZ`Fh4Ec@rS2yfztfYt&VIM>+43vuavRK~ObbZxwoS zO{tshKRm<3U$E7S<2UqWxS3);P(n{h*u1$IiWy>J(*oxVB;Phat_^YsOn8*qmgrp^ ziECs!c4$sB(x~w4@%dGa-7gX(H+h#^mF|UjiPWme9qBv!MR2+pVhc+00o1+tXvf{;UiQI4m@iP}9dgW)1F1rzQfZK@o`#AtgBZjWbKsLcSD)32Hvh5hc127)I zgKU<6k)D+ZF`Ct&T1>tQwOV7XqqlUrD3D|f50%Yr)SKhl#544~I{*jHX@9ov% zV8nHCtg+%l*f@0M!mP8>OfMPJc!L!_85d#m{HGj^tgx)N?AeQWS<&Jfezza^mZQRr zOmR#+Ob1M+k2;tT(5PUkpF(1ttoU^p$6`pLMa`N2q;0k>&)t1Ga7~;{^gQfMi8R3} zC3GNgz;z%#I`0c<50DG)KbY#vE@NI$b+2 zT_N&*_djrzqzZH$j-ZAu{^_=Q30oL#z|z{XHp(vbx5%-ZFsP|R4ZHT=q4GzFU*GXx1#ev16? zb!N%b#;E%6cfRT#JTUocSEsAwVVl%SwO0eLt~*{ z`b-ym@#d=KL0L0SmJW+I!HXYwcpLO`Mq67 zBxFUz`hu^?{JHS+ZR{(|Zm}V-0Yok~NBk}Qoyq+_xp=-&g!v?LM{3pYru+5vvr2>n zKP2VMYvp+`NuBVYPx33qGaUK^?*iv)y^bmy^cO_~x%>j<&(XS6|DC=28dz>*+|z8L zIhFf!&~GhB->XlverAhK?lB#wV1EJ(;X5<&db`!KVZ_y|L#}n=j6x5qReH<0Q zOvxztm(?c&x(`Jue$nEoZKDai7{SU{w|I+RW>Ju-;|SJ)BK! zqG#{j{T$J+9Fm2zh%?K`d*=T0*sXssuZg}`e1kxPu+pIA03+C6=1ov$J+;GoLkSJL z0{g4Y@@QWCgkWACn!?;C#%%iX#kjoDoetwpUAh>>IH`janm>&+y_Eh1VGRHIXwTjy z(E4~mqeitVMvsa+i7WpuO(fYib!5w-e9SR(t7CNd~#H^pk_>}O+`El~ansdujjmohzaE-l}6~ryDXJ7mK?pt-IV#Y0QAVg*95N{C6A}RQQ#KBYm0fi8k1fjW|hnRaOjU`WX)>X+;XNa zx&nwJ*Y`>VOTl?PQL8uHgroA7#JvmNw#KV5n(TPSNu1#L>c@H-dErDUWjuAziz%8& zXN5+$-V(CNIC0H6dv3hN8&U%fMU!7xLnNJSI`J*JU@!)s}%zgiH{f} zxq85<82ANvf&~!Z>xvnoSVDJ120Vh1awQx@HR&Po*{QLxH0>keEB)S-V9GmUf%T`ct6u8J!378>#&4JC zqd|ZB9yqNdM&Yj~H)L#gTK!*x@+Fl=udfcXcKq!xG%)C`&%VFa2%xh*ds-IpPn1ci z?V&De|5s%ZTR6Zvnhc$^I=G=}S#^?%KledYdXp4m@F zDd7e!FOlIY=$@DAp7-Xy^V?^FQ`h@w9{?^NEef|!^GPMIfwXx-5Lv z`TXE}5ZC!SFokg*`A-yKeEw;I(D$FRKUPO1m4}7GPH*)K|9wxcZ`eSe?!CU0dwrmy z=--?V2~fhwMm}Lp%nCZi`>0ft0^Al*T-*5=;1JB9qgvI)*{S7v0FZY7p**^$+>`H= zfv?hOqfsDa0zkR9;C&}?Z)W-4OxS(LeLsA5-vtEv0Yy|AT;Ka|KPG<1Zlt)oI~}`) z84~m8jTS6xyB`bkzYbQ|d~&fPL=THL;P&{ZlSt9%@tdzE*I}RO#S;FPZ^XHzq~Eb$ zWn|E2A9;SQe-rWFOjw4Cw^g1QA9C`_HzLGdxlb{e>b=SR`7?4JnPg`(GLz|jz zs?UyICkYK}IwzbnhrBYr9jf>x-?sK)IyvF0h*SV7?~_up0pBN?Hq0D&e`$vxDvwMG zmD<=%*xWko#~&q|QvREho|jJcqZ!FO^gJU>p%)hc9gxEg2&rT$@~mWBmtgG zfilCIS7?0JzFK&~dHZR2F9Z!N{Nn49o>Mxh{m_Jmpt!FwOS;EtZ2lJ5ccaQN*!8Cy z?w`MnmHkwr9Gs!>eLPhIkw2($7WTg}xvR<0CVB zR3l=^5eCA~DYErgR>%r_4?-q8Zdz`&-&U^6ou!43yP759%rffJ^gNF7oED5;zoxE5tPPe!A6ccX9!QzPjm+Fh!c0q~ znDmbytyZI{k6R=_cc(mlnD?$IALygGT6GSiCjA(g{~AhCi>*04`nWVt^3p?-dz^Nt zNQO;$DQPE{?5&}HcZ^i_`I_>MNP4laJlsi^%};(mGUC@o%-rk)0ag|(nDPL@=NPHb zL|kT)HXf!E#mC;RvPDVq`{Q&E>tB6w`Eumpu0pLbZ1I%AT%1BZFJI{H;HOk@(-+SK z!HbPcA_ZlUwR|lsg`Y0HUJ4hI870n*Uk_x184zQsE~Uv~%C@z*w(T5g7u>`Gi!7z$ zF3Lk=ED$2uoz7JYEwOHb?wFuY&Ff4H@78dm6@T*jyhc8R@KT$6p2OvuI1`^!`1v=L zt3@*Tf+j8pUq+qzBGr3~LdPPSaHGCtSa2pWX|(&{m$yTMxXfoA*9x8=##qGP$jx(e zWcRXC$Ubx)=QC4kw=;?6v{K(36#LCr8uJf2y}*1HFm(D><{jt>0U9 zC6$8a{o}(iCVTThVgKy9uO%!yE=YDH=KREX8`JJu@GPfdAWd6WY@MrtkNHrnJ0I;; zE~+GletR~%3`>o4<_*i?TN)<{UyjTmo~P+^V7Vh1!@^MpFx8`SWWUZ2RGQ#S&)OU5@#hxq|sn zq&pTv_yYg8!5oX#D3eWgQcRE-BX6oy*YfvNU5&?Q9^K{`!o^)gVXf{mq8o-wxEQ+zbf(wTAJbA1)rsupF`nTmL1Q%UzJbkXH7shmuCj;@SHtEBWjY2#=*Q z>Xr^oiMTYhA%QS2IJd9Oq9#SHNe*tk+=rF=5z+X*8F)`}Ltv;~!}n~##eh1YoX7dR zHWPy8=%KodNmv zgz@<8pB7BQ&Pi{dxbYG~D3DUCG-0_%7f2loA!$8Eyo#aNEY`!9-KA)w>w-g2g5Z4z z2?Yz{_BTY*_zTd3!twuQ$Ds^@=kH$qX z2&1{3C4PR*6#g|k$&#)fxztS~wAD_|9(lyk;!tn#*k$3d{bBXH$s8`11&K0o8NUk+ z7LUo)@P)0S!XeN&!!lEMQ+(eCx)_y_wK$Z%h8Goz>xv(>I1G0O?f6V;ZQVETNe`K@ z%rof3yNknW>lWml|x{vRsTlLER@wX+(JP z{^zg&Os?q!i}3KoWu_{EHrC>R`@aV%7Pm>Q1J6mV6sX#(cUB??C$(*9e$t;vTO8(v zYctP!3>J%=_Wp-%OtXvOVq|pJk$EO*@KA(@miqr#0mhC=Km8x&O+VFM*)KIjfCIJL zq{lO9k%O{1o^)sdKx~5v!48TxAnuc8iUaFKeFdZXheJ4$PfhDTG=6fAVTS+;3C zw*&7mz!a?%-vO_cK`&CWx6YpgR|C48G>te7FeOgVry&8+lNZ5 zO0Tkdvaiw;ZqCQ<`V&W)_Lvr#?DmGM?;bXFzIZJ+(j}DopY_J0MYaW3g0|Gevqav+ zl|;oyi-*_e&_)>?Kf2>*EcD$CE%Kh@*{xgItGYj^CWr+v1n|D#`jK>>bVeP3Z93n` zjDN+OaQ9eCyGwJPN4#lR#K1*b@4OAJoz zuaTr))Xed?-{ogU_-xer3eN`1hS!GQhSi4IhTVqo&l9l8&%fE5Q>H@4 z&Pm$CC-IN>HYfHDN0*~WE=Ns8mY!Ve>kBW{=5t%7K9%q%=lTGNqCD!^9YR{<-GMHn+I&AI2U7)^V@0`{PcDx6YtURE|nMpH|10 zyGcLJ55h%8xBUNfNP`mJUi6P?D>n#CA1CA$f3YWzXS=rEE@kl#{b8{4#C^?>w$w2x zRS|}tlv?ZwGZp^`@v`wE>diD@myNV1;i8|Wj%J<#Rg>#~+SZffKkAb%{~}?lVtL!= zPfyTEa?Afq;{9US_l@>~IRS@ORIrqC>}@TRe2aQpv~j>R@-?=T#F5KHUDc>6oaF2G zjhTpyhHI3(Yis*Bw&W0kO08|}JD`Hiln_m*hek@L|COQx>$uZD#&Q<%cuFJXe}uA? zEI*PpxIVbBO{wIw<1~KR#{1F#K1Du3`F!y!) zS18NRL{eQ+`mTDAs$$>%{W1E#5RN`>PLW>}%;o3v zDV_TCg*roz)UVusMTBq@PJ<@|>iRFy} z?H|l{)JE3t`puQS663ivl)bd~KWC%jgK($Q1aN*>>FK#5*^SX9{rz2m>w~zAN0oqf z+o8~^y7F7R6=;}%c0KIPdrw_R^fQN6-aIxQc9ORf9_+GeM!|_1NvTP=LJsqfr@n81 zdMt+vP>*GFo27Bf-vA1-CXPWtR)YyB$Wk5#1z8ivpdia=MYTkE7!+hpc(_Zm0cr}+ zk@)}&B>?fS0w5BT0am4Z{gH`x)K(OHAh?$t=Fh-E4KhjjhAsv`35*m5MJ#|RnM>39xN<} z9#ke)CI08D^nP2qVp+y0)rfX?%1rqKx@EcsLk#y_!tHC3!;WB6>%eNnm?-S(5dVhg z6HO!{G#c@cO9U2h8hHP_;}L9eDkZSmDE$#^xHUG5ccwZTk?r@>lY8X6ZjJ=0})Z>&~tC8qQGiKmnqm$$5AQr1@lH`oPz9y z(Kq}KRhf;e@hq<1&)16_<{LrMLq53VxE!#2IZ=3FAX&+=7Q{sdlLMBigUw;?SQeg) zPzGH!(e(AVNy%hBjK{|+P#*Ia_?AYTV=nWc&`8y-z6PW+~=WCDbd!USGM2O;r z7E%5zMshXlDW(SG2HP#`Wa=rJT@FoNda*)DGM{Woay8AR>hlYKt%Ksg$+3`6$7*?z zS`fbom5UiN&W)>d4GweM9CZ$u$Tl zyg<`&xzOWj9oxr4`tR*jVHTl?%%H4_c6F+?3-3cAX*pkNSDZ)mV92 z5H?^&9GKaQe#1W`V&ap095+p07?|{~U;RR1rv>j@AY)gz2E_aAeqJED@0{EPn`S}s z=tZ`tCIkkq{c2^Fhpupx4dZ{}9OkBw=;UJ|pnmo<@R?DzFi@S8b7T0C&d~W|VCozv zY$3{kNH|8VDjL>*59$VU*6Tmb2kgmdE+ zAdAFnaKI!0A{8Kv`>EozAYg59$R{x|*_9VL>VEjO3GR{2bS``OVkGQW6n7|hbRgzD z+71qHe*{;PB@v}|-PgRn2%b$>{%kH<;a`XT)B@yR&@QOE{VbdmR~KSHC8F^NX2G(w zlbA@n=bB1rXSQ>EW~X`;;ovDlXYVNl6Qa*}kom%XmS%C0X+%=Q4p6}szgr!w_vtsk zK6oO{xN`%1qp4xEmrCGSo>7H)=vLGkKHQLRz@YVFrS0W%p!(VSKtwUopMcYkm=`O9 z#)CUnH~vU7ha8z;0;k^<PMvW{S;~2G?gz3@-Cp1^y zVy;gT%5Y%{uG%e+DXD|)r)gCY;eLNZBxK4@Iu7f#+~9j_()uqxC+1eJ#G;!83x|V! ztoIak6LW)3i)%7AI-Mv*>%^~N=r?`{7ig^AHGlt-RvNee>SY?Qp-C*w<+M^z^Zk)L5R^5KHxS+YjY7mpcNPD z2n|3t!ETp=US{>3qB7vnF~Y~8B&a#~bky(%2SsG9k19T$s3g>Q#OjMjrv!9N=y83h zBU79PTE&n^n+@-&Pucgftzx>?D^b_KA+ zM%Vhi9GVP1^d4N>@m)zP{w^A*TSZ`=!nLa^8e6TL4q+oJ6E?ay?K4kH(UGX=$>^yU!tuKPp_p^`YMhx^k!D<#_|#Cr zLWpUqsw#^PuWKnyQ2*;A zyy-JBn8-`LIyERWXJ;Wp{V8$!jVQZQo3AOBPIRL5Wl%$<(PAAICT7896Hj?z-(iz& zC=1v#g5_8_pBOENp*V}Wy zs7H3e<^xofm$MtsvDdIah~(;O;J+soA%R6iHR<6;TC;Nqr?>RayP>M;L_^X0^^8>etfubaYV&GoL7;}J*f`r zv3n-k9?vgZe%sec5iUKK=^w$d+%rq@k)ct#PUouA54}S3!98@0*ARp*G-y!rj-bB{ z0y_db`^ghZ^Q1q?Aqjo|FEGot?@o=(}a!MbEnNPw_y>51+U)Gb#=yTA)w2i@LV|%IQ>;4!W)!&*9ytE1~S*wFz-39k- zxz|{qtM+>bYSx~UEIzjrE;C;=G9r)f;L6&JcWP&Ini@=?nM&<{vHEp-VXn!$g$`|M)t%h~$~0KMmCAUC8Du)u`gR9><+mSw{@kDGS3M8+jYV(0-&b+8=6pNkG3^qu zV5e~!u~fO#o-+}QqFVNhX3lEH5FBPb&lw*J~2zYD4z)g zHaTAWVOhLk>cy{=zY(F1}WVUFTe%B2DqOXq6sMphd)K`8 zcMcG10LTy@Ap~P-sfBFZLbU7>y z!<7&2hboNjP3-n?`69_;v7;yM(AU?bqW?;<{bqw+NNZH!r>@K_2VF=wnwLz2iVSYl z*r~Ieb<%~I6G8LDQ@9VRG^)u%I6gE4QntOhQ*@eRvg$rw1r=Nit%O!2w2(N{1p-EC~k6MYqgSr;e1R-)Y2ao6#t;gljMum=(lQD>-E8b3buW=ZOfOniN z3Xz=A%L;a&1!BxGLuqkErJ+%Qj}FlH@pc?2EE=I9XxH!iALAC;HF*r z7(T0#mk#n7vy#o$NMmc@xeI89pGv(WuBpgWt$5RFEl`_d+h~(tiuq{1V#Q87s_-(-QmlSAN_m z=CuXX28s9Tj^uDE^g^Uq8oRwdhwde9EZS|ho0auR_XIQg*j-!dYM%HleaofwvNzXV zwNE8oxi`Kd;kE1j8B^7uRqI1Z3g@h%&hS$)-M*IzvBIxGGKBy?LatRBuS#NrlWtGZ zjsCGY(ckf|8ynvuDOoS2br&z1^AY$hxeoy89^|uQo!cxG$T4qWoo{qWskjuni+B@C z8ze@tAzyPX3`|zJaVJ=?VjR(HH+*(YpJ@5eVc?ohm-c#HSj%AWt9-TTaJtP7_Qw+K zhH-}_XIU;q`|5vE1{wld4omb6UCnD8S(^!$C|}km9F{~H%k-j)jZHh0DsMaN*J-jp zOtjEyJ1q60BN4m{EjqX0hkwM02^K>@=PetV)SNV1`qwHmvA9fM25Ml~7Ml1|?HZ2& z2*@9-Kl`gt?9RkK*c-US6xVjd(uY20#bSVEa1o3U@ywjNq7Kn|8BA>xABwNeYnS^w?d4Q?4M@~G--gsr*r3JHHeedCuxyEv#XFt`>=>@OD8_nT0$8pYr3XeCbC!>GlfE zD>#R4aD3D=lo28~(Zetlc2oqxVKw;unuX7e>&B$WNDudb!%;%e&hTrnYNasAXw~U- zxoVFFy82nj%*Qhme;!biHXOVY+bZT$E;w&^cUN=HjYb>QVN7sqDsaTK*VrRoIxqiD zwt2!|ytL<_ddg|w=HFE1sCJ97536OFgisq>b_PAaO6h!WrKDjF*@YV0Uvy~(xFGZj z%><>L8LA$}6qkuay*~?;JK9R?Y-cD@&s?lzEC3jf1;91cdoT(`jz+{?>gjiPvJgyw z%_rQV1R~m@Kzf__{=|viv$@>U*7)ziO;jLJ``}*j=)Dbt|8Thk+5p&|2uR2qGceps zhl&8Dc4*4$uh(+B7b;USlXYjAi{qV$=Z%dz)f2XteV#n=H5uNrIk80yrw&1qZ=Oh~ zxyuQ?=X^uX+V=8He_pPx*oJSAa)5G}jpH=gF?YE04cVfH^+~1c7=(E`x@`AVUIoO- zd_JtM$A;ck#$haA=nNB6%J#-4+_u1$wJy+k^U_6ciQdl&@fpE1&plsX=T|3U+j_;9 z?3#5M8dBsGzi&HlT(>l*R(YpgJ8bJ{+c{8H{#(3G%BC}oo_lc$f=n1YTeo3+3vEvF zFb^2Y7&01K7`z-ZFEbez-qB(6aR2?skQ#(O?^Q{)xH~j zK}MCF^ZehsIHM4a0~wA0&9kC?x%r}nq0^9}x#_yoI%lu=Mw`wgq126^o5nIq?$N{I zgFgmGQcqKYzFplt%f7m(8@B1Ov9@tb;2dH&c(SNAqcmeOqcHPgM%TNjqS@)2Q-o9d zzW>AiPSfE4+l0cIlhe}2u=)i=*W`*m2W|3+o_U0o$beYlhUymZ}?uz}3;TRGeQf!9m&s*szZ zAUpe9eA`IEpD~YZHUktYY}8JqhG~np0;I**1Ywh&b$8{r9`A3Qm~V@ z!ub;^OCIUQiAr2;E^VCO>4=@hucawoZJ$e1Na$qho!yk94}OE)alUeme!|N7lCv*{ zAj*A_X%FpUrT6y6cP%!WzQI$uaV+U5Nvof8x>jWb zQfM!ip7S`eaPfYTr1Vn4GRV@QqehRWY5(D2NhmRKO9*reV@VJmizdwv4?`6p_BDVK zqVeLjJcZYy1}L>WvcNKkEX>8;XIfndrNWS@PkTvAP5Rm(-;Z}@=uH$)EZW&OHwh{B z*ddkhPDAKRR7UQsCzIa}xlxNYgt+$$?|KH;2Gs?)vpk|0D2+QRA6BnP{4qFfbF+zx z{6T3=jQhEA&^aP(HOgV3BFyq=q-EP@91Eu%E2x3r)xMO+a1v_tH~|BmN<_LO7RmSZmT*qS*f=ugvzdGbOkE_2WgN3~&- z>cm#F=c>AE9LfIb zWXt*6Ucd~RDXc#H$Ja7MdVbLH)H(OhY-8Bu^AWEg^`H#TpwSo4XV0@xyn;qC0q_a? z2V{$dCLTaP=_?V2<*m&0Jmx{_O2^J+5IdF2Nr&!zZOCQLE}iq_snqr4+16DKTfWt) zln>Y{2Vy5lrhl;;@TS&M%(~>`ZUChe1<}@J&eOQf%bayFlG*crs6QZfkH=1>CPS+b zegxZ>In4kt{43oC*;1@-ffPr*_xf0cn4jiqJ(cQgF^`+RQwkcD*ukInh$qrjTTJRZ zp`$BB7_yo-K#Cb8fWY-#mdfhTUclv^WA`JEXzNpqk*V`fZb9mMVN>Tz{hkA-QtGIt zuoEm`^cApmK?ICCZ-3ki*hK+oY!DzKbTDTd0Ptb~@8|%d&%FdS0J6nIX3tITgYyK? zT>yPc8USV(fRPE%hr@tIRG=|qNxcf;fCpkK0q8#tzqtpEmin5)JoytZbJG2v23NZq zU`w^O4UHt9raCicG6l#A>z@(N%NkN01+&5DqQ%6Dw!hX|qa|EO7M-h5^n8Lv*1f3H ztYf$3b6kQ3&lwxGEa{IQ=awQjjH*&@z^Y1H)&0!?VT(N+pGeO>?7T;Q;Xhbzc5LDDNgC%VS$o$RO z41hHa9(GtNhoCkgzVSVeKosWJU91G-*I$?!#GZ7R1whZ=Jjm!duUevio#rCaeO@KT zR>#wGPGo8$?d|^TQO|jf5~f!?mJM>nr8Kl?Jd_+}oVf5KyNNTs^QeCnlk2Kk0CuHG zRi*_IQGSL3nN^U$gfyF}A)k3(tQ418t4SHLUm0%&Ofn9w1`rQ^PD8xQC?wQ`%;M-L zBX~k&t3+XrFKn_99co@#2wf)ek@GiX^jiVi8zUP5WJeo^9jM4UOxo9h8djU0Ti%>F2qiK@0ZE{e50GSY0mwTb$UuGYw51|q0men+mz=E_GP zZn({p5ki*OCmqLko`!+0$q=@~4ypJtGSQ#s;-_H|Ed!BF{0!EHXAkia91BEf0`6GAASf#GKT|CPg8(3|j{5t21v3M|gPno6 z!FdK-jLIActd<5M8bIU&;Hvi<`-(7)nGHm6!YLu=cR7f{z1H%B`~tggNn11v2owbZU|4)+4b!k$7!z&D@P%ZV|S4vVM5}S@wUb%dX`S43 zD@$V>T;rUZU1?X{??Eul4(;7NKqwd4#>)l%Ui#=FvKUM&BlED zyxb2tuXsLajw(Yt>U~uIazUnVbO!DB=-YC0j^H!wZx{1);EKwv?9Uz^T^LN?v~#wf zzusp7c-!YE_57gifEM!m_g)3plBN6}oA+9=2&G2#%iMhycFK zp!^;!!`&?qlquh%IH`vP^j+^isQzf%cQN31>8r+WAco#Qo)sCZM`Ct92UG)*2fXvkc``|O7vFi!~`{1Ue z%j7k?D`3wE*!uz62u4P(DbX_-F4TGS;2$GU{vv*f==xp}maS-?|@(#O1o=G2h_S@HafG;pJKizdNcZ6x6yE&+u@)Ir$ z()oJj&bqs~k4{wS?XId;n|kS`{PdYvceAI4ImWx0d20% zmHkLv6)Bwiik1wLEu^{fF~YUK&R7-cO%;tKj&vng05MoF9P zZsrrU#)o08HXibzHXJ&Oe2a8F2&IHLTZrJp{Ks8@G~r5!IZ`;y(Qbq~m1zJMCfM*v zE+mCn1KYymGMNI)d+2rZ4xOzoLwQ=gE+SpuO%kW&Wp%y5gH>_rI=$>}c5Qh>36UD? z0$~$5G(zerSW`llf%ZyVVnSelz47pX0vJs|=Lx)`v0pVd_pU#zBpmB*)&|}aZb2y_ zr>I8ArkGnJLMB#o!_5-l>bJd8u+V*1!9kPcbZzZtE?;oIGTZxD-@&&4)Wf)AYe9lO-nJtRl=Q+ zI}qRNnd1M))tkUW-F=VaqNpUPB>R(!N>bLM8G48|rm}@lN%oX%&0=^|wvdF786{*H zQ}$wp5<(iXWt*{Nk0Hhw+x*Y;JfGM9_5HnGy{CKby=T4W&U@~?=Uj_^3Z=OZz1qjl zkedTAfDyIv?aY)IRc6Yd>arYg>)X<+8W1YL-aI1)t)st(-_DQ@K0zP!ZYoBdIOozLxd4#9Kyb6ia`g(@Oug0(KB8Bz&E;G_ehm8>-j10a2V5) z7E<&K2??cwY_rgqOU4I zM(^yvwukq_ymvZ#mg9Ws2-ZElam%X1_X9T_>To%~CRbv{UaKcDJ zYpDw(G5zFB-`FQ3WqS9}*6_Bl!71KxE@WcIQ&g>H7bFp1$pJmjZ~L}s6ek%j}0+P0wC^WjcMm z4G?RND4mdLj3_O2-IE`n{MYfE0O>O~ug+>o`v=z8_7xerFUf9>P^Q-wdI6j=PtAJk zWj@=n&Fbo`rL6ze*^bTr84;y&r3V`#N>BW{Rs;U8Ot<7C1>~NsBn9*cyVUf2gqjch zq=3n$+m;pJ^s|1NZ{<&ihT8_ck0=$JSKN15J)(5S_r#xfOKfI4#GYpal!vhn*Yw=% zAO)Pya4Hb@%JrR`TSSxw7pNYq>G|v!FJq!HTz{jc=OvFa@R|fYr@Yg|y&QurE9^u8 zI0XPofE0j{009!ATTY9wGJQc1m>&g=IZ%TXu$i?K1OrV^{bO07x#5wa+n@`e^#KhQ zbky1nsD@C%25Vxr0w8_zDW$D*_r zd|dvfTOuuw{0*wF4?poazN|Jy>kog|mN_9IS#<1CkI7lmRmbObZ&W)g-%oCl%grXg zb^W4wReC~XN9gmp%2#Jt!QAiftQx3sp3gjU=en&+PSm-kl_}o8k{(_z|i*6&qb z=;2b6BEN?d0&500jT=p$q#kLE>T6rt5HY1HeMDN>pn6`S3sGQv6QAhm=CDHkLXTx# zRvGt99(-{GW4`eCmqnKiE@5BjLagjxd*gf_|I)FRXI0`m?u&@a?UyDF_q4q`FRpH_ zWwB5Y{jrRw!Dk&jJ8@n)qrbZ`I+68+_0%(mbd{SCLAjjp#7?=~!mrdL^RTuSV@all zau{=d0oCQ*Wh0rcqGrFZ>Pu*>++N#`3v8XUDfI>AH$@u=&t|vhXgkR_Amd00vFEyt zmY=#PFh9?pJsq2*a4DXw7ti_P8@rTq__kS3eOm0ry_E~2+_cn9-J?cb=91YIrJMWK zz6dE_?auAzd_o1&R;bd@AZqF+TVlnOUWzL@ceZzCtF70`}4Shf6;==1+=etU~Ls#EA6yAAHe&r;xKc#k6?eH!u9(XoY4v{Y@i@<1>-2)Q^=;`qy~7wAE!0BEVTTK+sWC;g z&DPgL_Rh8Gk*NhMtB)AdPm;ViJ@40uA6E01h*BiHpZNl|F_7&#s|*l4r7ic64f-k#%>oOa0|Vq25A^ zg?u_p=`ryBNg|IM>g=&`Xx-T9R_p3Y>G9q!Kf9E?%dmFRovx^3?_lpgN@l_$spBS>d2Xnxwg)m^S9OGD;h}T6ULbAwInjCf;zHUhfqmX zG|RhqCinh?ySE~ubMT6~;&>uUq6{b}Hzwti zU5y%{^;*uKM#0PpVlaTPJJEUJlPrnc)nMFc<&N<# ztt)Zgj@vlQg{5*P+!fUw;!#Yk7?Jpn&b$L#L(jMCwJw{lsvouBZn@B|Ct${+RsH{9 zISu%5d@bRV{Ca{&d1~uWh-iN zRh`RdWZh1m*Sx;*y|E`ESe>Q0H_v~vO|eaHPUhVI;q!I&|ML8QMED;#nvjG4pXUFM zAplHDIq-iK5KRUx=#+vkM2*VdOO%vCw?^tn8k=zA|MPTyua5vV>UDVdcb(7@m#gP69Of*W-ZcSmpa>f=Je0k1FEg|`}YqZ zA9|g3IH~<8dK6WydZDyC$a3!WfS%MI{07&>Sr03zz}N*;#y}^3>LW5KFys3So=-OpwSyz(Em@(2$>KlXYs*FjOytO21RUm&=V;g*jbde;z2 z%^S8Yz&9i`);35fJENccx?`$W<9 zp*tQu)}EMB^g^-RLF@cN#V=ppm$B+ooWiorLfoG(<3khG(FJr0M*hh%^^G?|66@As z?22TKE#-dK6H_aQtP~|%G!2?%2Wb$OerI|h#XAPEIrWwOW~;ZO=dw%WKW2T8GFogq ztCRnudCB^Q0cyoXOXK|N`SB`#kq5%LmFeJd+$nV?DT&j$acc%~xm!A&|OT{$g!(jCHw9ylmF9a==)bvC?DB)NgBIXxg2&%lQU(s+0L^H~}v~8k} zZUZG)RkB&9hVEFM3&~_#J#)Qi^1(@}NVi$zjqh>pMg2R1%^EIz%^C;RX^12X!c)^? z5;C&RBm~KqEJ#{E@;$9{++?fB(sA6`oUP54t!XKnzP>tzdPg`NV)^#Al=)f(4b8o+ z+qcx5=C3u;B9nfqQX^PUWT^gzl*T$2DIZ|uqSy?!OLJ{r)^ANifeMxUpjWzc=BZ^q zlaQ?f$%4K@$$}#M$%6Z#k@bGdzsf2>FSLM3$RiNuHV6Y-6C%kQG(^ynE>cCiU8LsK zL5C+XUo~7r<>Y|Ypr(k)GDZKNr+2sed?^oJA73iH z=TzOj6~m?Hl8Du~&PR^#iiP<4^TEo5M<)gzdE@tOHT_rJb1?da3c}7hQ(c>SfQcZ)}`j_|+B;6?3O% zbeUSSs`lAEq)~r0uyOKE-RQFYXIUasIzo3F+}1jWLkxdQWlla;b*3`)vDS0A4SAzU z%*L_tWrw^l8N@1~JNM>|vW%fQ9M925mu>Vts>y>##6QK%6VQJIv}XIJ`5}OK`fELv5EBe|c$bx!7Ub0EbF)`8J2c@FN(V z+W|pNpT^d_S-OaIu<8Y|M{z~iIb3@w^uWYCJdH>vpKd=ma z-MJ<D0hhS)n04M9| z!qMfC`!#bo`GEb~$b<3r^{Gru-)ck?+bQ!+?n2AUoQG^%`mg>kScci})1%9l{j*qy ziE$!GYU;4#Ot*X>?Cq*E62G^yf5dU9*H4C?WN5Dg%00mZX3C~{EF%(>p@>332@0#5 zq2M?Fbq==-BKYqHdHSHE^!j%fotgy z6h=Ub$2ZZ|o_!f{zOM3(7BN~)8`+VpKJMS>e&?-Exme&rRri;YovSv30{In|wvG5o zEed{w?Ou7Fb)KKdHL*29@lY2~(N5Ww&$B%ef%;Rb;k+a$@t8)mV7BieyQpZe>5j-ThTLzD8 ziW>g1nCP~9&!7Iwz876EQeW0qyE`<>NoQ)gJBVj4)H0$BRzlU*zA`&I5caSyH^c}<+SYQ9IRn3) zX-+Gcdo3zMdb?dDx$f())K*GCVO76zakBaLg>U6OkT5Qc)< z)Xq-`6+N!p)2y~;5S%c}WX$J`?zJM%G! z^d5USVODPwbUzQB96@+d&_*vdi{iB6%&#)U6osY}&}3n{v*_+d%#{H$+8{=yFo>ZC zfXKKhcz~eS!#@u2?bT$$tm+^J2GR^{gy-REYJ+v=W`J4b^yix^ku#S2hVYLg-FS@G zgVU-56R#$ov!r9SRffExK&5n0LRFzkZS8Mhkq*KV1wnFE0O9~(Yy~lQfEq8c7Kw*? zayD5(Lmf{lo^P1|W0a6hEnd}GCU&+mtWIsM>c+jBD^9)nFxan>><7l&fqbQLkkiWO zZ19y@y>KDGmxVfQfoXA@lOyFUcxiPs!4ts{i-rPJlSi#+FG^sxmxb}#zw<7>xGVZ=Yx`X ztAwYsG1m_!;B_0L>p#~W-amx5H&GbErwp&FH?&QNiVJrH9K6)|`o)x7i7$&iZ}So^ z_;eJ!e!Wt7AaNG|a);8vx498JJ7>=7+k;%^)xfC~@1IF}%zIS$qMviTb9$7PI}kx5`d7<-FN@{O6;pmj(}+w1 zAM6@dtOd5=PPebn>Qi;`NCAg$E1Z4sh8i6$AULm`oLepy{$^$fmBeDJCAqIEdn;n2 zM~Qmi&z|>en$+=Y@kO@cO+?hK@)4Sq3%6~BV>xlbZLMNY^W3OsFhP$<#{K?E?0g+Q zw!#TFM6Xq-+amCRa?pwwM6azFrH#^@1rT_9L*ZG@TX zBC|F#k27bQhgmxr-&PNla%_oNGpzH^9)vd$xfH>iF%MgH6S`~NA=kH8~Ep;{EGxm%&&)+fft7rK^fFip`7|_ilvXzgk~#!kU&Ds~_?W;TlNQ;grJw;6`+hGMzdC~^ z@~SQDqI_1k4lqzdp{;WWOl49MGrP5!YaznmL%asW5Z5NTLVi}y}00c z^9v3Ed~>nVxAPX!JbI%jD$R=>FKSJj)$FovDUGaLAJmWgj!R~#c)A7$koh}9% zM|-ufMYwQ&MZPh%l||2+ZkWcQlX&2_SGM(poyaU(1d z9G+dyc>_@=Jr<0@XrJe-mE!g!^M6A@e0U)m$6RyD2$e{apB?OZa}S7m*rITip}q|Q z9o!+};k`5ztRR@;ee@6rH!>Ive=hfDIs~9>I!iTaXM;6x&y5!M7NU(Z(rZMa2JFuv>?beLS6aLR&7cz>E7>26H3{L41f3$cE(=48Ju&0Eqwu zknkc&grVJf1JDtlhVYj*5I*Y|RO2ClBugC%5)f&kzS#wVe<~CO0Vba&c_eM;SGacQ zHB0vEgAS32YR|~72)s}cPvVIGZR9F$(C;naYOz7dU~Eq*bF?{2YVdQCeO^X)1r{@c+Q0{8BZu8MfC1F$`V zDWZ94idDYyJ@eUleueQRR!K~cn%di9xU!+_Rrq3U*yD+O02v>T0-; z0#)8NHB6OXM+`629KKi=Z2I{RprrD7$E?>twBlgTP=wN8-Ox8;7;TIbDwmlSpg^;ofFV)hS;+AD93UrbVp+%elDr!Z!?A_r7cfRCOO0NDUwfU^81V7eYE z96&Wa5g&!XJs^@709FGJUW5_(eH7O2f)v6*pt+Ea7*`#dQ_D_gwiY^jg4>OE@clG>~!^HfQZGftJ= zuS-hWEsy2U4Qk#@zi=`tzM7R}Ok22lh@pA)dhlh|cT=R#ZR+Gt^U3q}=A(g=ocwyB z2Usg3nqR2Q{W&|5t*e0sqgXxPh3Y;aKO8YyzM!Z^V4?|Q0n|y|-dSv?4}4f<_rB-k z4=j5Bwi_L6Z19);f+p~2XccEDc+Yz%xsacR5BSB5mLKWYm>Vs(dCl^063T5q$;q!A zBJ0ySLZ=%1n=HwfIr*i*9fhO~I*eingKO|NX+hrqZ5MfWbfjGBOVT(0_N)`51XEW^!NFIVY~A|w8LVU)uu>Lik2@Xa5w!G}62k~U{|9+bfe z0bl74gIFtBsDV9ChVO1*92fk}-);*u$pBCe{Sbma)Liw^5p3rM5YT8{D)WQn7`77! zfc<)~-8KNcfr1`iDl?~k^(WTK44^5%^c^@ggzd}@0F2#br)digubn3Y43demtTT^@ zzPS^sRo19U;eQ>C(`8ZTJXZ*@Kh809K0RBM%T_%M3w`_wIGWzFizzQSL)`D!2@I?Y zSsvr7>gW=jj8TSr(5&gyyLwaEtEaMbTC%z4(IuFP3F$Z#ZQ+)u=bH;OzxAg&3O&t? zk7hb!nEt=lM8~?QeI`@Lhx&&X3X3EWwmpAu=zEh^MDRS&cd#~&_6ol|N?-yKBs5WC7G(IsB*WuU4j=|{u72jX~0 zQ(Iwbz4iwXDdnpAWY_J1e&84q0LuUE*ik6Hj^vzc@6e1cIRRBETZ;%&MrkY$FCMFe zzC7n#(INtAKQyZ!f6MYnn&`^;z4(qW zC9Jc%wJ?65?*hVBY0c3*6XXevV|kQr_d@h&f-WUwB~T=kXQb61P3V$c>#xvCw9Bn& zaL9`2xe6kRgwMnoIPlk;kAqw0ABMHEI0Oaq~iXnRZ1M-}O4{I6I zIbn^wR#<4i@U8n+2uF1kK|k~7m)J%W&LNr-t>+_lf512lGgd>r)Ykg z&X0E?o$n_Zi5|{yPWf~hUD5&t%!`aGYtm5Yxx`jLmlV5gNAy_g{Dm$#Z=Fb(I+yUh z(5?x(5G- zo#Nh9FE=7%LSyNJ(H+)dM32#l-xtzRbcg9NjV1B2SFK~DJ2hD?k$3B|TBHY~QR&3T zy2vPdSx5mg%51S>W|a>;eHCTLT2+?mG4m2LryQZaaGig@SdiJG^p4;xg-CZ+cFzoh zy3iutGOxXmVkkO?N_U27<*G^3Sejl`er|-%$S!f0q7cwel8y8>j=9dq1rdxYcS3>H ztwhs6OUoW|mcs3fB^b$nvqYsk2+eCO8R(c#2DJ9kU&XnC!CDh~+7gICd_p#a7$$SyoHd+Ylhc zhn89u2a1(YpahxCXe^lmBl(T<8ffDih$y-&2t|b&hfQBojr1bvKQHif(Jp9j9g7OK zZXK(8N6?HyKJ!JTXFb*FLYHj#z`DP=@(%gw(RZ%%Wcn>BTo11OpR5*t0bnEwgi3jZ zo4`?ZJz5I4t+{pVEC5`7(998pY&XbgXM0lf6>w?o@J`_U}JM zzw*;G%cB;R8F#T8?4*# z!|Pw!Z6}W-8FL@wzmC7|iTcXMYN`~dq&vH#43S9h%}t_ewo!DeUY0u5uwv z@O9?1Tdzy(^GG>koROO%)4Q%RKic`*y*USyOLF2YP3yGo!*_HEw@+C~wv4$O6IYzf zdzw?C{s`g;NKN=}Uz1pIWf0gFT2zjLu*LM3=|#R(0EWt2$2E5DUS&6B>No zkY<^A)eM$)5{upw82YC~3x;|W>m&;SFS0#iu-c?F5BM-p`W3izXvavG4-AW5FYtZnLj<-E*nDMa*@j_SAVgpDsAoByN0J1j3LkEaS z15Xk6c;8lhh1f*IrTKSl_U?XLq3dAjXeX5gv@^r-{ zMvf1Z;WF0)9rezyFh_1cu8GgyDj4W@DXs7hmx-V6(C!M zHom?LFjjqWG;L^n@zDr`MiNC1Q!$b=5kR55UfXRUrXS~|${t1cT9Kf)WC%Q2D@ znEdP6kYnVNYsN4mW=vp4`mJy@jf5QL{g{j^Yn_KJ829+@<}kBK0+$%APk7tjmqXL2 zqr0HT`$Xt(^bS{d^M=BC@a>j=e-e?IuIY_m-=s4?KjF{svOd_~X?%P`udQPiyb)Am z=Tl36%bkAs!b@{%&X&Z?F10Yl(Foo@VMf~-Ov6566mK7~kGGFF{Ye&R{dwb@fHw|m z2c!~9!<>Gm3!9EOUk{f@!xNx@hwT zl9%`eai%PUSL@#u)U2R>5K>r0ilxn(o=p?M}_vmlChC{py&B;k9m}NvFzr}e$U$DW%C`)TVpjhuBfHSV^CTDzHTT@(DZ3P>rw4;l4EEv!OOycR$&DWt&K|^frILsyv(9120{I=s{(<0)ZwQ_KBxW5Nd_oTuK+z zM5i8&NkJ~D@2A-)H~8N=a>`7A^7KfLJ89xULR5p|vES|bOv$Mof@nv zlU&c2pDUqGjT$nEdujSiac}XKV0vHKD*+0Iw?SreZO7)nM%8;qgbqZ^YRty)2B13a5dp92K^kLmUw@I zUH0Wu96@y55cyhKsp;8+g6Pz?kT!kh$uuGKX?@Z8+d}BH&c{V&Z#ugcNz$O}VG)(}}yu5oXn9c@_iMxkI=M!4~#->?C_K)e4!@ex)tL~fp zEjk~42CrC{v?W6LgktN>wP1VlJXPYYmrt7iw){nXvfMO$?43R*gvMDOY7n3t8iY7`q7R;L3FD%Tc5llf2m`6Tcgk9+z;;kGt^)@vUT^EY(rd)0EI^-Rb*bD ztk*0+Sr1PNkL(5@D+#Q*eCRaxL8uksY4_b%bl!&VKRIqdGXs=YzPf)b*xnJKP@agA z0C)jl0A!*zpwqNBfXrrqy$cYRB}7F<=aF@wnBZRmluLs}rRK^9eq^|v`uK0kHM3FA zuu-8)vw#Iuwmy)$O2i4|ntl}T1`BXEJ_0(?PZCcqIn!`IQn;XPT4E08y)VbneiX+z#$Y{T|mLRy41 zVsjLiQ&5`glTotkG>AGIT#%YOU6AdBU4vLRzUc!*o01Fp$BAx#-wZ^?->>vREJV#^ z`*VaL-+D9v=+5wlR>iRNp{dIbL~0`IlW z8pLE_4WiAL77zw11NoCt?SE+{qHw3Zycf+M^=jL^B8`|8Zu~lECSO3P$;#Q`hO}6V z*&B&swUI=LADG{<*onTB0khKIH;)lNh`JzITbi+M>zc6>kl5BHsy~-a8js_&$w6T? zXvEAIm_U9UN@QI!%1#sl4waj+IU=LCkiMItpa-ZjfNBY-j(~9=o`>+zf=A3I;VGYu z1xq8VaJPHz3=smscz~=96si#WpeTp95x*YX|+G zp%Br^4Ox%+Bj&Ot?tll~2M?MM?7fR@-{k)SrJ1Okh-$A(tj^jz<20LHy33vNH?loC zOa{q{!v5zuIr7<|@w3_4@;U7%u@i?OZ#R3wLxMQ*QttI)n?Bga7i=N~_V6r1$ssjm zcs$v`S4Yh5{cuCFw7`JUX&iHlt=Ew4>s^q=2|UkHU5NahJsI|RF8g$u@{k$%@a2my zP$tfdhQ&7VU(!ve;yUqBGZT>4+`l*eclJxBas$@wnC^2FZi5CfNA4T3Q&kBv6SJaW z@KU#E5T*FwF%}*%(}oe91|LRj`Z{b@+LB`OJDUw+v`as)$x?g^E_18!_J1xTKG6}1 zN)0@PM8==_lobszjYwY|koGdDbO0U^P^%Jn$N@PD`2La-H0nZw-+U)F=NJIIUiHvR z6DvmUOfdiHe0-GE#Gv-eOLP2*!@&Pc8q6|%IMnIBM){fi`4X#PwEOm2ITayb{;s*?nreoPZE4@R$d94>chJ6d zJZhM~A++r#<%ek1bNgQzqr(cJ6G6WWCg_$zg?6h@z2q@3U@f zh%s0#pbH@`MVHy<2{lb;-HHo`u!m{!{wry$8+Jh*ks_}js^PZOe_p6!Zs^%H<|uQt>fgxmFmh6wCW``KT9=&z(7UtFiR^~>~ktdpxbU26a9 zCJ3Cn@vVK{HZto5x5}MzMYua^yyn}dW#(j!;$4+IiSj1~S5#puneqdnKUuS|!A7-1 z4uEk0);1Q|=Lt8X-<=<~zM$H%!OIE#?j<%|%S_czlvtNJe8z8`6=s0wJ!~iXDosH^(ln@xj z|JN!IN&Fm{4obe;i{cI8Q6)`7)Tcw#>jtwO&Og;Dpc8wEth zjE$-vf~UdBDUt*v%Tul#1ZY1XFWk3;QV(>U`qbn^x#C{Y5sBCWMm)H#BeE&25+GrK zB#Bhk4PAcFkY`|NKv@FhOg@stvN{0P0NC@{sA`D;Y0QTmt&yq0aK>;$7|s}OOqNkQ zB5^z;O5ElLj)EZI3%<#kUEfomgJJ0r^Ea4q#313`V6v?>(zn(fG{x3-L{h5tJSJ<< z{l)gbu;3GuJfAoL%(8)5J{Z7n9{{1jAR&xLo+tqISPPOw3UK%IEMp|+Z#chuX8#M9kmx#Jbs7CG{BVYZG_O!@9Wks|4TUJEvCUL$i6lAQ*H^o% zb$+~NsQ^&mlp!+pjeVMgZU}r!troSRy4B>qJ73C|$c2~b`j2}Kq1%f5n^NO5DWvq) zBGS$jW7P$Msc|daV5bx1`2vTO>1y>=)V2F|dAz76HFhs5*>6SH+qktzqCXRj@IGvTml>+NOH zQ(3NT(4a?VOk=7A)PdX+lOA9*bq1*KhYIdyVC4#caIk4>ps-JJ$!4XW8dE!=CPpAN z(~i$4+3y6XPlV>_&z^%Co{rE&0+IcIE=CZVt^=9#&`keUUG3UkIp7Nf;W~jIx5iSN z#XaxK&qI0laQ*a7iL71XXRB@(7{TSYS_NAR@(a|RC{6-Sdv6XobvBm8-0u8s-{qL? zi{(boy482CRpU;4!*u(H{}S#J<(|^r@IkPrexgCDVIi?NL3aP7f^=5iaprltU3Q&f z!LEXmf|#H3*~9Gx(l`CTOvkm8?JmybJjT)6fB$>slbW>&r`-L0WCEssA+8vfA<}Q- z*p7_cf}@l1U1jDgzBY8ll>en}mKVf0<=$j8diN}IM{v!u(yvD`(QYY8%=>Onxw(Y) zvk=(@FMLX_$2j~-exL+Ee*s+e{}QfQIVezmey@z`8geY7ES(vGtT%3CBgdZn%w54X4<#8j0DzS7yhj)6 zyR7n=E<}k><-q6Pn$hZ+xl&WB3j20zH`Wa?RGMzgj0r^>;sX?Qgh` zhAns2lXAtjh8=CQms;A-H%FQNa54Tj;(*cOs_4|tMYnP;erZO#v zgle|mv%RW}l(i>Xh8+6tt8lZCnAHoWU5xHG_SR2ulhNo<^c)3UW;_{kBw~hAAXF3L zy-0`izeTz&?`9*74&|SihlW3AD9*#JO#IAn)EtF9b{+0D;tIHFiZXiO;1BE7vfBNP ziGL$>klHB+7yHOHW4-n@W67D_U#rh}-4)$uXApezuH%Qx2N{z-UdLZ>=v(~GuC56kWi88BwK4I0W|iEJn=<}ml*Y05 zugT=tdy(PZpmFgz3LN=0vX9)YJk*czSAMm^){~JLz+@Gk_{6Rq0y4%E+^f47wy(&W zxF$v=-+9*@WwIYIr)uGvBl1DePo)_PsVp2i2W}(!2+s{DPr?7o|J|*$wn>ArEapPB z3N1X!=n-ND^>bZt(Xfk)Y2@O`yBeO^5Q)W z?AxEkhcU3_&!OAFvYU*UKF%nY@qfY8{D`oT_j$$?Z%A!qcW^DJfVR_N7Xt$u{v3M& z1@N|%-*C~90}=j!%40dpTDDPNhUMH0rFzz?if!4OJvE3SwTJ9vKx7hCdz%Y2aeXqg z-74k&B3-iV9*1sTOdP?Og&k#J)`Ni+VOZ2*uzjPQsqB*OFV*bL8>4?yf{`{zs&)>IBK(CX_URxQur&T^L+8gN3%~B?0j>$9JYv9%_`xxC%17F!AZzDPMNf;t= zc#>Z{@B*Nk!XY!B0%NxtgHm}0*E@8vy78e`Bm(?Tu zK5FR)xCLw*L@aRV+#5{0Dv!Kw?U}o~3PK<3+jsU*R>T2smjfquzWjM{C!_}%oN;7o zs^@z4)b4rqY%I;^FY&mowRbPpzr3vTBtkO%%%?ZE*4V2jG0d(||3}PaeB~s!e2qc# z?V~T_=+3hA>cGyzj@5ikJ)uF0#hHDx^eZ=CW^I>cuI@UJi**0ZkYn1ZDIcP{3x+sW zBqBtG6ox2?E)kE}M$J2=nJQT)wCLsWBR>LY%`(!=;+FvCir(|7unI4E6TtkU{`O%F z#=2Ma7~S181}cPpV9kDx?vQ56I*Onqm`*37uF4Kl030brBm@n0P z=#g3XZdQzTe19=W@wnx^6yP;1Q+A>Tb1!M_!XO3n#Na|j=jA9<9>&;CrtffYYb|Ck z@#&xjz30 zW^=r_`}7dx0?6!_t2}3&Dt+CJ!W_RM!cS- zn}B8_itPbRF(AGryB1S;R+DaP2)vD<1@|`;P*7Ms4g5_k?S?3p0Qv3#A+(`$9cX>8 zNw7VDd<-B@K%G1f7#o3B?NhgkL@)^bBmi_J;BXHL)X_+zA&P?wfU4iQk?b{z8qBy- zZ4Kv8z>er^+1d9Z2PrAjo$^&!tgnP5b3?_aA&O|i!#YfX1dJ0RHZ*|T*Yj@H{F&WY^cbIwpD_jk z^~9P>pE39R{-P^C?hH_sm6#}+mD_MHn(28;A)I|nK^PG~7T|RuEpH^R9*?Q$td$mL z`UZVGM(=s(bs>F_;_nK+R{I@%jg-OjwG{9*uU$|5Gto;T#;|gs)O%O31 zESLgAO-}(U7aK^026*u|wan7pD%Xp!W{Zi8!U#DjrYFyu+F;Fwf^AXkBQO|D|DOZf zn3~r-MWi!H(Daw*j<=#7(ww+U~kFm~x$C^zv}#9`N43K-N7V z`DJjN6!0l}Bk)q;>7&l`j{Q&&g~FjisuWWb+>)#gBH+L(x@SN-Yxy^|7#2Y8CV=|K zbph4uF!UJ*I!%D!wF!U}=+a{VUC3B*w+glrNs4JvySiE#AR0L?Q{AAD`gUsF7QRR8 zMAyZvJGo0lU|FMIvOnVn_EqZxrt0Zr3;jE*0jq&tZ@fOfa1dk0U$1a>w%l5SS%`hP zBoH9r&?io!X$Ay-Q9evBBvx#H%oe1vC*_7HA5{Y;wHj)FKDOPq^z+%8$Sh%sdVCwR zKDNO7^#VDJ{ZEEEz18u|&cu5s8dY@?9v{ukV{COgvUuMz>ZH_?uwKd4ssXD&sVmP; z&PxP(Oa)bE#cmxHGr}w`SY@U}BV)TL?WAq~A z8`7Waix(eGB(eY6di+RZ{47@FH8NaJ+A#~kr(~VbxR8#YFSuILa^(uwtkK(PrRtxI z?$o#^3)QAOR`G}4Fy(jWrTNXHNY64Egs zjUWwzbc}?6h)7FIDIp*ON_Pn;EnU(bGL#Jco$LGl*7|+xTi+iZ&)H}1XFvNncUYHm z?-}I#?jO$JtHy@l0hAJ^S2j$%PkY^`^cpL(hiR*MQZmm3zHr-nnJ4$kbUmxsBnPJ7 zZFhC;FH=%hd!7t*D?PvXpd6=WvbNO7lkze?eByQJJn5o~xQRW(@UT2}e9t%2zYMw{ z@3-?pfUB$mk_XU0$?XK^H-H=wl~=uBg0+$A8-Q*NV1csdfj;lxE8v@(nWrUF-kxi2F?8mYrb zE(aszJBM7Xy~TVF(`4>Xnj5R%QtjMqLB@&h)|xP&k#zEXFrpuZn8{Xxq}37@WDv0d z1Rx_7YycP-+=UnrNd5qn>>x_!a`>Q?(cl81IuJ1pHpqj5iU%0#AVaAfG-u(<@C<+? z=qIm!`IUf;?9B) zj5H+p?qeu&{EHFz^mt>GvH^S9GdAGAo$m^n2ugv|F^aJltS}`M^&e3fpe{ZnfoNz8 zAHb#hCy*1wz4;$8U-m>m1{ccFUl0nswaPoEdbK|7K7@P%|D}C<1PS+V;V)l93*pi( zL<*MKJNFUb9ycWA4zBC=Zb+umv}FO#m%>n5*G~{!&gXbBiyUO>mK%~a(_~A@hUFl|xnqOn_JaVbJasGMRICVXB2$b5? z)?1XyVC6@dSu+7^%j%V+{)X9lg~yQ1()`)1|McR#g18asb)fr}_F}#T6Q|9*yiD_f zgOTcb1f>MA$JDQu%`cf`Ss6o&6Rdq+(!h*;-5|JiL+fT>v>TFSyXVe*#Aj4M_zBfj9BQpSF?@nrMzvP0)+=yB*W^W7o z*mzR8=k^|ujXjLieA@l=^f~foHNz#37XKYjfjVYVzeUMB_{~A=)YgK~pSW#57q%U& zGJivzP2r!G?rrk=zmwQ`U)kaJ3#QUvb$^9@a!77l!OA3Vjw?e9MhOolA-n|9w;zz@ z_JO00^PK%La^hNU~2iSAfE*9b3>NSp@d_hJ69E@bmAjmlj6 zr>gKP6)q4@sA2;Mkx(&%{&ZXq$gk`9#)z$N9$e<6{u!W_N6l+Dd>irvF zZg0VKMS=qZAmMofu;6dlMQ9cT`(z>rVkwZo|1lhoVrd4 zSrSzx9}CVXO6nI+NU_b`_Ec|f+w%*pif>y%_V)cG>h?Ow_kX4;=XWP)O$P!wpBk+M&EDIQU>N2QjDHMnPwKInl>%nCFWEZ)Mc{YhyFyKy|7p;?H)>uzmKigRV0F;l(F;pgNNu9lB0UZxqPn; zc_V;*=X3ddJ6;%r%3qGDrf05+nOc7zrC{z9eOs<)D8J(v)#X!Ou}etsG|q|I_|q1cb9gd1-$Lx?m;U;+o&+%Cqp|N}49GW&1fR+2<B&1(B2^oki;vr#W)PcQ)B#U);!l( z@L?OmtR<)=xkD(>yb*oKcw?3bMyQUH)#VzFZMa(AMHNvc-qZPzKPKdb$~)F)^a9Ih znurnc`oA~}xKFP1CiyVLpRDU=k4()eNRnP>4wTg{(?43txtnse9%ua`uyabn%7}Ji z(K)yygBr6RBPM(fLq9S$s^QMIBX9d(4dz=S&@ToXbT($V@N@2TX++pj-|UZ_{Yv97AhU2d3Snqqrm`eXWF zoM6Oa+zQ@+jaX)o3U~Q+)-5gJ<&v^ud#Qf+ra;{jAo6AOC3!OtdcKEM62jY>5}c@| zTHU0Qi2r>8Gk;|BE^21 zJCixAY5tA#9!c5`4d2u#`(sJQ`Q9~b?r55=a|gWchV41aEj>&Jrbm>dH;9(~|o zchP6}v17FCq8;(P(w3C;Lc>FZ)A`w0f04rcwN8=~YXH3G5VyZ10YOWsbd?y*YyIAobO02HHozU*I2j8PvTFQ(EHRASt|& zyvxw$Lvo%UU`L|O?wqqH8*f4H0?E}JyaD8X)VSBXQHQyd#aA9wBdCLs_<1u ztzxc;-+d3^$d>qkyq>WJex7r;)w}vg&X<;#@5kMeO8&T%BXg?mB$eDv>@QHL?GbtR z=put_!UW;0xav4dR`)*7-Rx)k6ft_&6=q#c7}yZ@K00i^dg+m2QVCH}vFZHK!z=VV z-h1$*ZERh59j)Lzz``%RuI~{^n~;Yi19?EhnOE%I&jMUbb*mQxXA<<`$P5+uYJDo` z`~`C)w*6N6$iJ16C8nzi6TbI?bl8ebqvYRCf?uIG{F5=sBiR(@)xdU?8ltdN2a2cC;-3r2}vVW_XelBcPfLvfTq5 z=K$G~pK?GV&0ob_h9t&7r|wsPP8e{g`%+eH`m>R=*gbP0Lk^B~uk8A4dg)g&Ah&w< zDiF}hS8xPh8xvC0Qx#76PN(kgkpFA02{z{kfD(s%an}Re&s-C}XC*zy%phe1sM0^X zx!4`PCZz#KZeh#8SGhDS;B{y5#XZMZz+(oilCd(NA+?snHQ^3%Q7i#wUu^x=X+=05BNvybTJG;Q*3;n0W|aO@9m!BxIC|-Oc1dG=E%ij~63@{%U&n z8OTEg@_6~4fYb{jdPyZBrN!=E0I`Gu*!3WW&^j1`js29_1bKe<T_5_ZM?o)yzb-yGQo5~*g z86-IgyS@QJpm0BP83qB^>3Gq&t!SufOb_iO?i7Q^A@XHhWE}2HUDPPv6^_t6&?0K%c%fjEMp77f6 z9+41}&!#>vh?2HBpXcH<{p8h0&I5B5gOTp)S^SJ`;7lTLsPO;}G9b<@)>wOWYXEqK zOr8n8I=TDVJ+nR1L+%h8@eV(!WWq$dZfg%PeIV)BoE6$u;FJ$%*}1e-FQ@3c$fFi z+`P7F_n*V#r zETg!#POz9@u=N`GZn_=rx~#X$=c~9=LuARW zX_t%m`PnWqU^3k36rO1ryN7?r>Y6>4LHW|SU<+?dG=NUy%L^5k3K565Ix{;0>0)oz zpM8ks=Dn4Kn$Z>R{_OJiar*jOpVVnvG8o3;vj_8RX>X=&Wg{dWyHu3eN9oV(5LHqZ zx%}1n(_QT1EjvcD`F$rOjw!$Tr%y&Mz7X)@|GESoR`cFi^_TXDhR^KGqsen|s`~lX z_Vrt&+Xjic^oT3Q+z5-Sr;_tNR!?O?&F_oahsoxohBM9#wl{ODr*e;OSM`&w=;+LR zLG&;?W@IXr0A_5uIy2xcbikW#f6i+(qsOU^W!JVr9m`_tWpr}*N9%-7NWH{Eq z9__#|COX6Sz8Y^t2?Te?3v_;V5zSZw-i(E(o{kx%B3R}iHvx~%sHjwu{-|g}swW$+ zU_&_6O##h0ei4Ys;$U~oa8U;Yszt!~uM%Lfvzw>mn9&qd6{$btTsFj}x&){?`wic% z>NoGX1TE=8^JkZ~5DA$pOi+5~r@^kGIn2iI)}z&Q%b-5fW+O$Hic_fcialJ)s{U~f z(3q=oIc8`ugWg{j(8wr)VWtYyJOa(jOo&%J)WrS|Id8&24ZxEE@bdmgjvJ73<^x0U zvL`<1YCvOai18Sd><`qOt3Gn6-~>G*Sqnxmo~nF1ZEL}iKP}pXZ@!~|nr>uL!P3PD zd_BbYnSl2@QS^$uGe7<`MrKG>>u#%?CHC+&@#Ttu8{vI?-n)$AO!mZ;I7sYz%xlXJ ze6%kunN0h>+FKM}p2z)V-V&hgA6O2?wZ$65EW_HvII+5TMk1W86=K#Z6KwoTwUu+w z-h{?9v`4NoQ*!0B^--%$Yf@{KT%`r|glC+%M7aL7+a^OlF5637YHN_CdObE%)xo&>C z?!|$2TL=*_@ikgR5F^;J@O(*Z-nDu8Vxh3ea`?R5o>OD<27_jDyyZ-2hR<);cXVKCw?aHE@dTKj z5cA;6V2NT%g)jx1F5J<+QQr6X$FgY-Ci$0+mTyhOo5t4}4n~?BdH;4eFX>KUVZyPP zc&T_W>_!|OTm#IcoG3FKlDD+e+pUC_ByQB&glA7EbEt;MYq5M8H!w@zIN(`I5&Pco zB^GEEwiH8Twf$wYfV!v73>BquWt8P8kW3dnR7+Hvz7nV*C05@ZpQ0b@+7`B>1OOiro>dg zjn-n#Zib_zTi7KX0_Nao9))Uq*et|gyd3-qv0f6xq+V3EUzh8*?I<3JuuIrv;+;>U zlWafBPS``dd{V9-@C1Kl`~LiCGvU~ue(uHFeDi786CD)5>yKgE*1h?(pQV#0$08(2 zCXq%;y*{?o6_lp~#EXg;gzSuTOv2x|X#~)zMaq?#ahhDZPks ztxan7`7|+Ph!<|@z(J;8y3aFFhV~UHkN0Vp0SB37518oc_PM9;rd0RM_$8zpb+Dhkz$moRSwd%_#fdE(9LAk*EDOjjb;$9!e z?xM*ngq>u$V*H-^BLiW;iF%0ZAak>SBJ_vPn$H^dK_-oI3E;&Ej$;&1K@AVoNP~tw zQGZ2BC>%706kupe%xFhFQ&$1MatSw6$o6R`e{|FB3o?x2uw!!Gy<+- zAy(-J>Q#fZNu=!`r6=eUS5)JRnN}F2rI2!q(Vi24cwpK%@3T zMW9AB#3~+YLO~-G3mUzM6fMxoK`M$skps|bK86~RFPfDIJMR(W1jM=%rT?uXyD)gGz|z^5i~T=aC2}=5nROdrECC;pPLiN5Z(OiAahC{fZN^-iUXK35U?54 zWJ3&>p+@a=o8oj}v=9z1-2_mb`oD$5WdPFeLh9gefHI06)lsVxkf(20^DvH z8%A}EL0AaMHwe4uD>M-xy*TgP`O`c*a?bfQT!bkIzfAiC(&IswL?pBTx{WNLr9%7# zbLXdgKs;x#`8vk^2)dvJAz^)Wxo880!oYp4QC^+AEDMl!l;bz&IAdN$SoM;cJak>j zuB}=f9}t-ER0nF>baeSV)+=CHz&CA|j=8rmDF@ZFlyEjbzo=2ejZ!+%f ziAC4O2FeFKZ@Bw$u{v~qHkyZJKJC}6=wZg54g+8qG2HHX0=LMZ$~Ua`!hZ* z`V(s#zQMSmdwI&tTgpF8v;0+7GbnsBzn`){Qs-)TJMlvYfRL=7Ni@Ikh^vF?Iq-vL z3v`U#d4i`y4?$M>K(Cy{p7FS?yl-H)On2&jUSv`o>_FscSl_BdpB5J|J!BtNwaHIS z(&Q>pE>7%0-W^l5!Bzni;p$YZ9)8brCFB9!r$!G1Qwp)9833Qkp)sjn*qXp#M_u9h zz7E!_;9y}jeIu<`D81kgXoJ^4o2YrX2^cK>K>_@vC%l>Z1}XX+NmcQODSnpN5SdST zcRl=wi!`|cLcm0+<)&njGbGu97KH)1Cw+Q z!DLq=05SrmcT5Nz_M}o~;713E_8ed&L*b^4HUJW<83tlID}lF@DyK(u>J<-O#oYHB z)Ur39;5*|sV-{eYSlRD5ZQP2rlDesa|35o(Owy(V{U5R2Zn@D3+`fZ*4?7W)NdSKX zGn0*$=xNZWRBLF{jXS=YcPlRZYlBvBSuj(GLMuUz@D`fS^R@2>e37CqIkg4J9J+<~ zc9o@M7kH9r(omP%aW~X4V6C^AB`?({B|ni?%3{33oo&@;p026AtV5aMxLp~umy=Es zBCs!r>G9sGshx8Mdo2X^3JovV~CL72^D*xbP)t%a?8 zmQ3Wk+m+Yc7n)c$ZZ5@G>zL8Og{axlR=)}SbSy(`hLARN>6fmTvseg%9o&Q9WjRjb zpKwe^Op*}pV5eX{IsV|)`H)@dR@RW0g_23nGJ-uFu5FFiq!=8sam_L3uEY*b$sN9h zFtnb?k)rUmF+PNEFLy1R!R)oGa;}AOkQhiz@3yNu)&IR){6IwF#Ly~i^7RrAO|$Uf ztDc<1q-&=r_S~KMSmuepmC2>t8-VMN_ z4j;cxC};3O^J%AGPcq_OVRE(a(dT3-F!mklPL^RI@$0FVZ<%?c17-8-i0(YFQWP@0 z)W`Wsde|#EK-SN1(!iDHGZi~HR&Xp8_?h}a3(o>&fzMRS8SXJ3((Zo1S0?Og|CnqR z%?+lZhW53T-{MR*liJ`muov%V#H(EE;`vG9wO6lOuw(GPBR?LoeC>VyD{-MFUf!Df znEtIda#U)N%A#n;Yq8rj%g*hog3vgu#_2cJBk>oHO)R^nn_Kg}lqD_y^~XXg8n}ls z^`^0e#@F!P*2)a$+NV#Wf)%7CkG^bgPcYl{ZC!6VI3CIisnUwcT`c5yOqs8PJGp_R zeSrueE%ygqvD>Yxg+=+lWR2Iq)tC`)2R&Zz@r}Y=_aOQCJu0pYc>dxN*4X_t?M66J zw-c#UuDEULz2H|axoPU{&+8o|G_0^X{xtcQWQuevcx`^Vqw%h!#;&PuX2D-+wIK(` z{8R-N^NK(zraI*f)4y(JPd<9_&AcDiioa*N{*B2TW1G-8(~Iw%Yww4%WZ0%@wQyqo zkns;q_b#dn=IQN}n%LGMbJ_Bjv8-^du0?CrM2i8NiQLGOd|O}ic7&r3q+NC!Z>9oBky)z5X^} zLx(cn5U!H-Bs7Ay1daGhY+YlO)}gzE#z6yAk?$)*9DTYeId{dE{2;_YA_5b;Hv<^lKbPK(yG zP1CVX*V+h9-JVZEy!yu1v=n?Ht=}}sQ4!UW*VRh z7e-(TNCDOD+V%r~Q808;03HLYnWGMl9)7Bx>C?S=(25LXc=>1cvhT;FLi0bsd+ZTm5>ok2E9NGz$6TcFg?%4DFxnp|W}*F9{Gx2N6{&mjuF9RVIT^%Ho$iAar&!F#Ogi(bO{;U;+j@CE!L1;mZO> z>EMsYJC>Yo4?8&aLwqSANKr_sm`dORc6>ahZh4Yt_L|EB%}NzObD6Ol2ef%@@T<-l z3*?oG0xJC;5F!PiuRF$`>FJ8=@scTKJ>BraqG(G|01yr+@+Ogj0%={}fC_))D0}h+ zeAtu!Rk!n87r=-}z8SEofas)vEB{=;i~A3y%*`U)Yk7K9i?e6xdFx!q4rt*?Wv!H z(fRRyZt2FK8ABW#Bd1vx35cS1-@*s)Be}<)89(vic1)l4x)4XT_=R`9=vP!XX;-~> zw?G;*^i!%qlm%SztwT5RHK(q+$wR#_sRrqhVhb_KZyks>8Mq5}^Zby$5&blWKTgCG zJL&lfq_OtwAGk2P=vWymPrqGz=eJb1$6QcK$VtLEH1?^p()Qoooy;dN^L)WUGRi?p zzV1)R)!w~={=z1l2c>ke3hEhZRTiCs=>9Rbo0u4D@{0Ar{a>x7>C?5i3rd|y`6)-X%8j`S%s^^m zG2JwwHJV4oR^p#Jw1vM+Sh!l(NyBV zgWHq%)`+Nwth%~X+e^xkmHlpA-A5i>u%`WuihS`}V%O1B32PB=J@vzb-yf}}g#cC) zC}7%AmvY2Ap*Zy~QPEomWgvl6#+c57T?8;A@4+AJ+JcS}NV>)Xf8as|d^G%M^wk?e zfC#w&Bbp8VpkEE(M1cXgWuv4OgTUB;BR&Kcb)wo?c?Rap+EOCkIv9=s*Zw>~J7=n+ zkd)j%L0QQ+xi78VtTS}+%?fjE@CG-Ts0=c|w9;Iz=XJx8tIOtHcA2{HB= z2RxTOrM;t@V+>bp9_X1M%bnIZ!>@|cZZ^mYfA*lqFcS+c!DUf%@scU2%plj@r-Qr% z!E0Mxj1XC-)LGqDvn}bF@W?Ahls+X5_vJj>WgfQ9X`?ascHn$g8Jn!Uf996|``v47 zZ1#U|H;Q)j%9zuRQ&v)aLj3NAUT#DpN^Nd(R$guQ7*@m`B$?wuw@jV)Eh?V)x`?A) z_~%|%gd5!D<@IDQ;%Y$DYV1 zm4$+71`hZtcN*{oPvj6yO2s{fv;bi+zWCtyrV~gntz1%Zki%-b;YnrKAo0tG#XS>KNAT5cRb6;99^jv(2rMwFFFh%2 zz>2f?mCM57K=Si}NHE|UplbcTjIzOh=sE&B40{B4d)bk*X%Ob-8Xe2r)E`M5|Km~8UXB(s2 z%(%D=QCR!j13iUD{FcLqH&-8a=K^_|eBsRoC^Ikv0|?cL#Rnp3K#1R9xebMet?!tf z%q)W4t8Azs0T1w0w!ZQ?g>gDR0k|v<0KxYaY`fPMPJ zyttjC*=~G@y_re8nf5ke68%uUu>(_B;eFxinNjhg+U8j=>-Ksj9pee!i+lSmM%#`a zG4^Jc3dV-`cj&A5PF3#fZu_SU`{s>{Bo{m>b>i)(bL(cULN++WjMdxzf*Ce;R3V=W zYf*XBjz4-JYrI{oVDf&PQrRSR{88P!>Nf4oVK}l-dDMdSoJ4f~eJj|!_DWiv;21ET zxRq;q+V&xFT;$DPib^CQjI`7V!;yTbUMaD7TqIP#3Mr-v-*$`;CN-YGNe3y%E~qrC zkZ@SB@r1YTSbZQXytIUeNV`<6IaIrJ8*E*cc!A>pDy2?%($-Z-GhrzwGY@$~{s#6B zR#nJO_3bZSlnyDX>U2e3ULQFPw(G;zo|Klz_7{%TcZ~(7IGQ!2$yFi2=fMjecbF1s ztpT!csnlzKc?mlH?*SjrwH)IK@P+U7=4|j%?nGhZ?exKEMF%qzg_J`gMtG?cjzjAB z>S|!>cvZrAvDeRKrXsI8)J89Q!nsk$x)RA=QsnjfyHAv(nNM8t_%V5rqZxSf#H;@< zymZ?Jz$Syjk7Y547*AwZ7LUWzPV_60S$A62=Z)$Av$HgW`5D*c zm86D(a~aqUsmEvvmI@9Cj#jxQ5{_bRwUG0(zcUtG-^wP(og?kW+S-y$8Qok?#<}*S zvTWq)QY9lo@}7KlDh`aG4=W4b9D5E|$x_^bx9jXwtgRU@5GxS-0J9MG$;IXcNioK+ zzqI9JxU`rl*rS8uOuW;3c#|=>1N&I-r*LX1Hr$|xk{JsD|9jW#$qmI6y5?)Vm@=ID zMaH^ZHFexItf*kIkTN&^>$V&4M<|bA|JMB0Cpq|AK_-)aBv>u@z5;zz<_6+guLhUp zxa3@f2_{%@Q?X!g>OaJKIQ{q0>f)x_(#r*@JGEqYuwj_KA%(#S!?>}$!SfUg(#%9? z95ms^TRU4;WT*Fn)B=XvZMQ`Ux@f!27p+)AA?v}0AwI#eA^ok?t&9uIC=T+7N}dYA zYLO5k?DIDN51W78^PCP{3v6gIS(D+@=qvF)oBii~by()#cDf(ty`cV#hq9=)Z`$-u z_%s1$wsLLyZs5^b#eyRj5nFJ~_l} zzE7iuS{fR@ES|J5ub#eRRLs`OP=%Yi3iR5r)(hi z00(e#&;UA&L;z1)alp5a6LP0TJIjNjC4fQQ5Hd(XguCKEXdVR8#{$8pK|z#IkQf9X z0o8N0XrcuKpm)s!=F_~L_ae&k+e+WN=*oZNA&7SHhl9J`XqaG4VEzu4!D!j1i=Iq( zVC)|MpHDajGV=UEbw&t3#$%VU#URGO=jzJBg#SKuYna#Glk6BZ7(Q66!M|Gn`##1m zzb3*Nsa6f~vZ$LTg*l{pSYC@~RQwqK-S3w3WSpJH-N6pT)x^@2VVmm7A%$ZWo}Mi3 z>rb@h`W7F4|LD85I4I&=$I8o-MJOJ&R1_)FvCKIY6?KHVR+3%w&0 zE*Sl$Fi<^O+~BrW(^ZlI5BG5H{VZb!w@b3nio`*T9mB|iddo!wu;TquV%_M%IdJULQM#y04XGnbS(hG2ic~|&6pHnm|UF~pli8J7~ z=GXmEl>%uqm>2lnze_LQ{w-j8LF(ZQgD1`vMi)-ghop4r9j3}H7l{Fw9`+;xhBamY z`T`anPGOS?PR!{Ofn@c=hRa1)d9+&Kg}?n#>%3q4qs-$#k1bBdG2h|`4o_fSw@x~i zieAi4_;O9Ug>~v>FaNTGd6~b}gN?1iyY%cBlt^i{GNEWn0Ar>FfGq&4jpre5bacC>A8rO0U9l(Fr(Qx^)X2E-e&hJe$9x#Q^?-XkknY-`m1; z*U|Y7qu7W}JT-5LAAC7mGmrL~m}Lwg=`Uy3fx&D)z14E|rZC_M zT^K?2zjo-aVNCV@F7AuB>8?kujMvc-QS^9tTJ8(CX|5YJ^qen*Qr18fto?=2L8Lno zDP6L^jZC70@ZudWgkk`!AAsdy9YfnO6m`i4sES-k3=E50acY%x$yR}pgFG$6wY~&~ zwf=>kaIGJ9tmDNYWeEe-^@@iq&sAL*lJ*+M;^^tV79r!y$e=FCE?J^G*NuZ>QC+g& z0O!?d7D&+nQoMh1C-WE@9NCBt0%woWb{rt!9Ac;mU?k=Qql319awEwgVh&Pj4O}_d0S>_PF6VN# z^c|DM^vuPxD|*kr=$qSyt+A~v3pm=e%Zk<*R~m{1oPYN2@`Vp}h|4gl;0gv;wc5tC zS*js!c7;|aR0m*P;eWln^`>L6Oi=q)EqN`yJ+>#FKh`h5-=s5c%uMUOWGWe~vECuD zTjfo-wYTnIzQbe0|9H629R89WMUQfPAfvhYs@f-R&3eIeS+%=?x>NRqvQySf2CO&w zyFlI`13cm*y3kqiqC+|Yy>1&BbY%J6cR244#Wjvl^t&JmwkuWVKJ#F@hpI`fA#G3nqg96H(vciu#Wo6q|$ghVy6#CGE-u_bGWskhy1a0h+ zU$@fVx*nop0RI@T-C9=Ac1*C3%S?Il7aev3ELTrEwdk$|3=7fg%9CnugM2^ilMUl9 zGY!jKg!<$D=YL_%eX@R?eKL&@bVMEA5;Uhk`zA;Qe2g5Jubz^U{&yPsA6#I6+kXPs z=@D=xE!?KO9)eiyfPaWH^m>3V?h@0uDEW2V|AWIq@?Dlk8ukhLq&HG#R?zWp8UQ zXZn7m#*s?eca!7LyuU%x_gWHU|HO*>=byYlBtL^O*-!Jc#!{)831N}$wPWf|+@fZ# zEt0;`rXh2kF!bW~+BWrG6G^d2tdb4eaO8x_daM+7`~c3q(`(7$sW+0~nW|W=VDqhJ zW#1UoV7QO+(Kg=`UPL4+zg-MEqn3vvUK}GoZXlX%cM8pTwT2|V^7GVl%k9;5`kT=y z#Ww6dnFaluu7?^zGW*X9F*S>k6u z%W_22s4Gl&`NUt1sL-zPp&4dYasv-HC(8M~sdqY?xsORM_W028uwAcO-<}R)$mBC zRr^@bcZ|r*R9OxuW#Q!zjy%%GbP`B8Dj#Y{>ln=W^XjGUIJGbHg{@?NcBDjjyc)Tc;2oX!^2zYH)pUHqUp`fn zaU0i>%0qdFpesVnOtxK5gZ$ii@RQi%f#1D`vxMKK=}u98uTv!icEso$_;4#YYv+<4 z;47;?Br6__=vNBd~C#C(whytk+6*r->1*Fu>{ihi2LIrIvZ_$r~e! zM>16HwWRZ`GuO7!Vu{ahpGj}x%abMY-7OH*I8?rOpKSMWc-oDP=Efh6l3#%5>{mE zy&OK&&2oZCf(wilEbRRlVU7Hb$a!**sC>~d@2 zan8T@SI9H*Pa@i72vzXdsh5}E^VuJ=^wTq=n!K(}?j_SKseRtiaFw)_{~-Hv!u@4m z4QZ!!*4z{4&A|(jIZa=uE7{VEyH5(d$g`Tm8Y@uIdvQLLbH@q?f7%V5nfKTbJL@Yi z!!|5$jGCw2(N=(l+j8@NsS}JNhfUCcVW`;h;-CJ;txAQrVLFP9)1bhAo7uJiVCDg%X zlykLwr%H<=bcwDvo3YA*_9{!aJZ_zm9&f5$C82JDcM7>%QZDcpSD9GmIWEwNE9c>R z*{XrszT2lOEdD#gOc>e27ll1HE>O)5u0S-wBJKYV!l@jsq_a4%$zs6AUS? z#{9w;;Nh;{<-&c8y%xEV%w?PxNun!WVS}5B=32gI{VOElOf4ymUr{%o9~6LsI9%Bg z1CI|3+DCliYN)QpYF2i`#IC{{Ll5SENO8+PoTHrm!Y}m%sN zNvb~RhkKR}`3|$>@K$Jhj4NN7akGnk>WJ5c<)*gm9p?D{j+7v84x}9Ume6CzD&Ja| zC6#b?mazQbVx~jAmhaEYY0FInt7-iihs(jKK|cfa`flAsM$jmwYqItF=Mv-giCH6x z$*Hc)MPDq^S;;a`O)1nj*&#!lEkC$T5dkr*cJ9Jj&l0L@L}`vdjt3S9V$~) z)u4Y9`&dD%_t!_V*bSB`CqnYH0tF2nrLlgH*a&6QCpw8{7bRf>wKbk$%fUn%Jv-a zWuam8r+64mk1X075Grd;VLY)dW?a0zQkx2f#&lT@gJQnq$8xGi4vjhbra7c@&W2nK zVIj&p9d>Ss-x_gMDSsLD`3341iCav>%!L`&P3-ILXh~=SnAc8dmZi^gGGy> zpAX`4j-;h=zYNurTP`^FTx{t(f)Qy=^JinfgmYSVC z*QjrOSxi>5-u|i4|DIS|s1UW5x4DgLw2}l-qy2_<51U$VXVYNs%I|06+b5e-naJge z&^Xb-gUpfVZ)$8dpuD`y%-X+%_KGrZ@K3#W6J3&{&uGLq-h_d^Bl z9_qWlY+3()c%yhlOoCyvoa)EGhZ=La>E9~#1Mga-`8MTSx~p(Be~9<-udDjAoHP2Z zzW6awgwJKf(lD|Mi>!1_bhR^{UnoNAzfGOWoDA)-jhj7bpH;Rz>YsU~7biGy;8*>M zRcs|Gv(+RDJG8vqj@hPHekEy!s_0^QduhgHZ@fKIe6>>6?XoEdosfM{DE5@?1^A;f z59yL+a!+tB%FT+%ScOl1^Kf%7F?^XOI)pW-+nIMnxH(6oQoU(Io z;j*e06AR+bb@uq%#kESE_7whmK~K;+1j4t%IUeUo7@%bcggI_lg#Dq$l3FDB#jRk; z(Kz`0z_Us%N8-^b%XA@u)`?`JN}ZBz#a>AP8d8BQ^Zc-VfzyYJ9RpV6e=|@r>v2q!bEjAb z%k3wsIew2{N)DUn$o&4PwoJ3HmBATe>$gf_Z$L5Ui1V_T&{aIGu^zRh_rr;hNi?c4 z1~ohwKXEJ26W32+@%-BlI->cn8I46KMdESh@>|UYSp5d=B?@iwpm0wSJeS=trc#Bu zhv;S{@D1L3_DXYb^t98D1|o~Ow8j+F>(HO)H?mLf_ysLy8LeQ4m%WTayg{vI{EQ&r zZ%Rajp=9RcV|9T79X)JA>NqC`KmNEg1g%_!6`o3x^vNENySx`#s%@>Z0g}qtu zDl6j-YYuvcju!3^JUZEP4qL~*m=bkOp>@;z3rC%N&}vy|(;j)Dp>{qgk#HJd;|v%u3@ho;C%7xbea zpok8@wP+vltufe#-#9hsQ;NvsIDa4H-rX9-z22jM=8hYw5?RRiV$rc-n#Q<&H8FB$ zf{bVX#qgIPQ@cbqb^1uyTA>XKyPL+cn`^IpIruJGrK>lX#=``NO+4XBkG8(XRZ^4K-_uGVY%@I}Ia(t1m|5nedeBhHL!BOOG2G)%KfIWi|XJ zMOi$Cv6WTvn}?NE^qaoQ%A#G(SvLWBB96!DV{wYOocFQsGds(SXR|p?`Wlly^!paa zjYpK)a>odXx5`v2Gx~3{rpk@Ue|q~(^(IfpbM&=0VZHz9*Wu@Xvcij~QqN5PlhavJ z&v*S#z9l5f|Kv+TmieE2TgV&!C(jb+7yM6F7Bb)e-XbzIOFri<1EcX2JHktN#}40s}Yy;Tp2$511JdBS-W^<+ZvDJJiy0ss*yy z*A`&F zdD4gBPsCz6CQrwktTT(B+$ngyI!0Wt!R!6+@K)vx4Np7@iT&^Jd1$%0WmaC-mRUYJ z(va60mvd}o+2^g#Ys~ELM)thSgV&F(=zoV#LS9wa{qOJz%6Sn-eLbg2j|$fYR~--b zXMB=yjr?YnGI_8Mj^l%Tb5}G`a_oz+V_R{I5C3%fBs_KPHRyO^_kQfU*Yigz@5||- zf5G+71Mibe2H@`11M#f$-xKXxe(PUZ4|~D!5np*;^+4ygIbvYE8qVp0?&Y-$nCS66 zl0#l;U-^g*M9g?bU3pmy^)2Yo1(NFA&isF6SNxxyaD*kd-Tin+Z@)wSE|t6qIS*vj z=1Zc*!g44s=`q}|x(|F(TVCV1?KtFJmvc8Cg5)FKAM#40H`MQtZ*UH3`M?$|G+tGk z?y9JEycc~Su1;PRj|LCbkd?-(#(Sl3uT-bASL$OX9l@U}XQvfqe}S^i`nq!UqWVK< za?&=Bce(R#LvJ(rlFU)q3|?pQ8;?6*J4u;+(3>gq)Rfn7UWNNI@q3LMye{)X{4lYp z7TD8Gr+78$h6*WNbkk5bEp*dTHxv@#Qe8Iki7TU&cnlR@Rd^vTk1OMR;k|J~T^YO+ z?)=`kcCL&*>Vq6y8C=i8oxeah1xe&7oOj-x|A_D`^+&Z_8QXj!>OLO$VL8Em3y)r!NcqKTF0&So zUxeeCwaLyC&js+zO~P9mkF#W4-eouA@W;dPpXKeSLkOLP~K)@BQk&%f}T(hQZy9?X9Ne8x%{%2nTwb)b=49zHS7u^arntOe{!V+j+b9#aE-tUH-@R8HE*@7M z*Tap=FV_Q09ii#;EicyzomtP@|2!6#cKnHpd^6AD{=kYY3tjc&+Ez}ggoeF#+Y=ZM ztMEW}?NV#K+k73%%8NM@iyXz}9m~X;OL2L>X4d0oKStlae-`02L%8&6I+UAo}$Ymwdw z!Rr{k4W>KYme-iqn#+Pm<8*0xyaCcVA*y}Gcx707k%)F8rKTTWXceZ&o2?vj@ovg( zhmAY`o`}|@7YdOj$I+TJbLZd7_9C?{jPCrA!jo`kg6#;E^vwI&jvN*bZAbpWGw9CO zcBB%19T)(RcBGbYZAUIwF6~G!^+67JbmWr~mrE)OmKPDjki zGA^?eT;D(YX)S6)q~V#2H&gCsav;=(c$nfY9(Wflx(zwYWuy&>qXYluS|%rGgtZ}T zv~oM(zwkDs1-?f8n$AYkD`cN3+B+wTm^G@GZRPOJ7M&@rI|?#HZzrB%X`T0W|NXPD6Bo< z7hb{kB(X>CPuSIFB(HU5Jaao6DKi_8l_6_E#zrf%BiUi`XS;&cyrogW%im?@)8Q66 zYz2#LVp1~WkXi2AOs!4KL!l;SIGUKJC6zQWjf$F>n=+}kLhR1zE8lI-Uncr}q4NuYdi*x&3H<90PH@V@$#yr= z6Ez&*Nr3_N!){tIg_*x%Fk zq8!o(+lvoi#dCF3d_(QU%h)YyFW7p(XRG)WwHK3RKh$1~W|~lY!PZ0D3#N8xFE|u{ z7bLzw)-YV!iw9tgZZFsYacnQ*a3HL`_?_=!>2?I$iwoeO?Zr7{(q5cJChY~I3%~S3 zBHD{3Fl&3kKX(ymFW9rxE{V%{>A(MV6!cEFkB zQ4Q&wP(u5WSrN}z+UArN{jM9RmRKKY|uCXhFze{&M<04lE<2-jhpMF<{3_rY$&jm4XgHe!YVB>eE$S@1Opl^rWkJ-OR2%FeM{}_&YfgVk)Er0UE@BS<>q=QktmZ*Ai zJ8czM7603XJXnCCJdUFH-G8aC%j`v_nYb|+MUn$cF|w5BbLY3>$;)^2nf$;dHxK_I z#Kmw@?kHSF|J(A4Ex<_6^Ek4)jEi-{{aA;+%q;wu`v6YWozHkTB_8Ets0V+<=IyPp z<~7De3D^(QUeo{f9@?wA^Z9N|sfB$G4Hc9f*JZVy_KCy?^V;~|$7i{Prm)7i%Rk1q z)hMwbu^;}N=m#7oalQCgV%fC9#ZmAdJ}S&x-vkIkL$<};C6T@G^O+m$-&|6%Q0z@w_J z{U^ylB1R@+z^D--Mg_r|2$diN17Q*nf`9};2wJtis#e1cq7sr}W`N`I06tLkYDGm$ zeY9Aq4Qe4Fm;vM}A}Rt(w5VsCR3j)5Vl)5WZ|!qtCIP&?_xtmGWX?JJwf5fYwbxpE zZ)rTp=ir}_C%gb3up+WBb71%hd^BErUy!d$Wwx*NQpvl3dACTKLd?|J^OTitEk62M zC$XD>)$&a1zvm)fYdL?<3)57H4D5SAt>9>V_rQ+HczRdx0;DU%zZFjjc*?xSfdpeA?quj89L)eFu&2w)|D_C6k+& zFDzsT1ih`Uz?I-WdPO?C5up+?B1fo%T;CDGe6yn*;_A~BBiF#=`yf;JA@s|po_8dh z;^O<|Sy4~3D$a>rs-{Iz&(HFGBC%yD?X+kDwYir5N}d&E&`N;0$6r@KX_=%9Vwq4y zkaK5uW>*lMsSj=eaDfH*4mVk_&TtYe$D1|y<8p7;P7UtyWa!0CIN(l#`N0Aqs*(q-%Fjw$$CbJqvTulC(O6EWXZkA_7Vwuc3RXzxNFHuw?{g#Iv`h9y*SNZ2M2Ag zSxWd24Z==wF%jJ33S^@=16IJlOf^(&>mFh8c_{Sga2mY~W#8==aJLcyjq*dSW7(bP!STm^cB6Kb(a#1Li z^Asvotf!PTi8m+c(V@*JmGUXFD#T?eqE}UdkS|L_bXT7m{8C@=H)p|fu9q>`p3Zed zi%F$s3w?2$vO4cin2O_n^>Xgh4q-m1{o$T9v{roqPK*U1bYDO`Pv1+mM)g(93s|I znca30w`-}|{Ogcs`mcQLMX1KLRAhfUg{5ohL#nJiFO_G-Mg@V}6&qFc2pdiFwUdo{ z@6|^+LrEMRf1NXOudkih<-H;DdtbXCI`R?Gy_1knpO~(lsu!h2Ci~hc<-EfqV|?x8 z!`@3GBYf>ieCih&j7nH_@5qIygio1~9F*Www@5FPz>}xD|31cU>7&xLB-D*fF!A|I zh|iveNGiQ5E##&sL1=}kep>kBy1LHQ-@Q5H-m5r0@b@EwH!e z{aqYyarps+OVOug+M?s>YNT6okoWp3nb%1UBK!#q42tOhc(57^OJw(MkgZ~WHjC|rrIxq{u1xUL@_ z!!$Me+7xkcbEdCNNz_~9SxHn1m+;m2WB4tt)wN&@zqJB(!yl8VgZb?%`4*F?q?Pao z(nqDR-ir^uHj$@+6nUo73SS2Dgt<8IwJF7QqRL334D6QgO0ou+aSQ$!{+J2tF1)T& zE{}TG0_>fOhUqTywTbK<f>})9mAAe& zcBFb15~QZr<(rbaY6g|m{RYLt10_*W{RTlLl9nqlU%o4unW7Hr}E%#S71D6iq$%-4BcOS;0#7VwK zK8xK?*g2Khoj*-tpk9ksf*`eJO4@?z!7h7{TeO7V#q+uv{P7=|>+Q0x2v6F{{;Iuc zUIemnA0IXGVrQhD$b+3t<~3+BGCK~oQ8VhebGNaSV0*`+90i!U1G`%|Yn~z2Jbmz0 z;yg9*t>ZkYnPuT{5kx~L_$ODPzQNQUoWKI~=eJ#;8rTur$8<@tLv}rU5G*2L{T1Jj zxzvLy>m|Yv#*q|#WTu~cH;=Wy`I`rdsGDK4-k;{8WMe+g$pfQF#Sm8PN9eS*LbC*m zEU_%XLRN1J7BPZZf~BW?SAs>B)Rth8rB|CnNb7RRqlC$gc*ec~@HjlU0w;k^I?I#K z@l9($*dqtho(wnPbvF}jcw>cL)?z7R=AJQ(xpW2BQQBIo(bJKeS<}$7;2tBLW@!*tSjmJN&?!?+2#A4Mi#o01LB zu>hG2L;(KAWJBNr6bJ`Y0!qbYgTz0yDcP__(v@tOhUf4z@;Y=xk?q1=Mq(j&p|Fj!oS7`OuDrmyBen_aQ?2sC|I)> z++!`nFn?;kgf#jxN1Ww9hq~e{zlm=#mY<6z!ajWRwUOmlSNPf#yRXEX#qQI5!tT8l zozSn*8$-Vv&@R}L=H5?A7EUn@-66O>RHVE2hx3ue*QS{9pQS-z##1b2JYFx~uRrkR znPA2XmV6@2c#!68(jWespDO8IPw=nzW_(v;*3kD8d z4C)1d<4t8y-|AYh4E?qY>IiTAGZEo*>9GR|)wxEo7}OUmXF@yvbW~Qub&^-9nxgSr z9AT|=OsSf+@~l+N&GM``!h7nOxV&_~JS$aGaTCQIE&>#o3H)^}y+WRexme1}v*H>* z$g^S@|B~lq<_TU3aIqOkjj>V--;-pe7AovhYGE$BR|6PgYGLKTFat_s#0z6)n;0_# z51@|lLHvmk@$7rWm>DUBzDETxK6-nS`jkn|+W zdn}~GU*pBlMJsHD)!mQRH+gYfKGgf7ar`yrpg99&CRoM7vUOC+=62UC&B*QWRZr!VZ5 z599%!TcPGjP5JUo=s$2CYgPIn>A!j+7zTbl!!4aK$mJs@?BD1YcK|G%jm?`g)aKkzs9zXu&}^vW=X~u@JMXkIA&mzk}?6L#%SoWeWEoU^C6k z*tSBej-PALaASBC^5nyerufiGjEv86^Svg|iVv-mXT^u=d>)#Iw*X(_7USE2r96IOu2Y9QvY#tR0av>cHH7~p zMHNF@k8GCZH#ii};rs9>!P@&fe#?<>v9&3euieQGEyrJ?dfRfW;#Mv} z595~O&jmVSqfxP1`U1WR+YkAvK$c?liDn+dU8lS1zetfCL!fFq&pzBx&VG-RJZq1e z=PfG_?az8?n&#fFm*TvVoia3+tU2+}d^t`H%_|(5<#%u=>?S@wAdj``z}{A+H8GOK z*D6}m1j`s*qI*~Ak1gl{6=~tG-WPlH0R4@He4izu@Bwx+?%(>v)|VQ!7EFPqFAV~i zdd-sWW!(yU6>re(y#3cK5J-bjVGW*v%CeQloQh4!M%k-y5}4KqTLe)6W8pAIUX3p> zRjUIttlqtHJ3A_Ueio0B&nZ0;`T&f2s zUQm6hBKzvm%4Jdw13r0`D@Y4REhSw=gUy3>@)LC;?2@A1VzH3GdVCN69e-@L@iH?~ zZ(&(#64j@{nIhFLV-iV`Nu06jixqAX60)J{LPht4NEDB8m`&vOUQz3|ig9xJiXUl! zufu9-Y~gEPz7DKC&w3@_@Sa^umI1J-!Y~v0k~g)MEUBVF+f18pOdbsvc{ClyUd$uN z7>pqUeUYPw0$uTh<6n+Mz1`N|g|zTb;O~WNSe^A@KR#$>`}HfGI4kHal76rbyLfOA z6-=|#u}#z&*Rd}^(Kqwh3KSCmHl*e62|tgIg`#AiW{ipYTM@PLSCztTz=cYb(PLG3 z9j3#zlmlL<1R3X{P{}dMu0kcoK9NWA^rc_(F|JG(D)Gg!EmUlj3TmO!r0Fp$R5God zk4gB06Ghl%!IHqOfU1yK;tI^dV>q4fL@>{QLZwMBV{=N8{vP?1BE4AbtF6w;g79v9 zM2{&EjKw0xTDw%9Q>bDC{-F{dl|+$et&sXPsPe5W{0V=H^g^oDo=XcQHsHKM2@U8S zrcPW)f#$inkh08ka-mYBZ$rXc0MHSBRaMRvw6Qp*OkaVowleKnpz*B^xn*`}ngFbH z0v9UPnyd_8sPW^c89#+02FDjt{<#9wXbXvKuD}Q;iVO@8uftz3NvYZY#YcX01!!(B zREqW~%tZ~nkTSk{Y@ssAE@A6R8d3=<6k!->!ef{kc%hPizh^EXxxhR8N|ICHM1EID z$yYt1kmQDyvgDLUfrEtOEe+FkgDx>t2|qmu)~Wd8y$Ek)T9_=x4nUti%hsnWXT3>X z8bdWZ6}d#NfDj%!a56aUYk$}*ocChQyH|hh5I;?TCoqAZ4NdZ#QtYo+{y^{ENEd8O zO?pqCl}R%{!O_c_^po;;*!HZUA9_x%8Gfq6n4IJ}7@2K81&h-9JmjMsngtMr1e^6M z)3mY{{dB!76G96X9JL`>9R&sRq2-s$L_yez_L^{5;&+!Nh`&KEU>szXbj?!gI9HGb zM3VFOZ0LtFLQB>Cy9j+B=_*{owaDsx%7Z@G5FODkHq;=iAb%H2lbU1k3$BLsvi-=( z!yu)2^a}(sg}QS3B7GrgLJkgnsEEu2KOjFOR7oCU4UZGJmi)iOsm+2PQ<#?LS{W{? z#kRdm8-BARQbNhq80t#;wMf|r&eBm<1+(767zMIXYMrN zk6rF@Sxh_N8@uWba(e3K$JjF={}BEsX|B=rk{n-;L7pPLb{>Ypn6%Y@)HyqudynUP zTCo%1r)6B<@VKTt@#w-$o5>02u;enTOi26;_}yf0zdi1+_dq8^Hha5ZEu~}kbKb0L zRqF}(kNU;mXsw4Jf4G!dR`NA8j`B5n4-MypEqm#Cs7d7}43IU?;SokicN1Tpv|e_F z+-tAG&MAFlkv?`bAP_ah@NTkp^Cooi3uV1{SXTK;gD-qt~dtADW`tCH!g=I`J*VC&#XNyVi_B zCFwpnjEyO2DXMu+n!_9fx@E{a7}XlxG0ffK?WXOrl}Xe4>zlFVd$hzO2!4$hQklk3 z100lwQ_R+U{m(fLy|-3@Q^z*3{YG~KW<=pf#U`!7#t(lq>gj`tf7A^l`~GRjX;d|+ zB@UZ6s#+o`M%8{}1%ubLip^U2Hluu(R=&OeC-u?fTR(aErI%jP%6Aeg)iFCxz2>Gb zfZhp_5pRq_Ke`VqYw@P}H;otmV*Yh7&cq=73H&oH_^Z^Zb?N$w^9essO;e8eUCJ3R z*+TBkm|*l~C&2}t%lM`m-p!q;6q8BG?J$2WnBqBavp5)!K~W zvg#kB@Ls_@bGyH4zr!<+2NssCB}O@nu}OBebJ3zcAx-nGW=rsP)$jqOE`=P?tJVTN zV?2NPr7-H)SsI-Mjz~V({Wbw_weiHBtp)BBHYZhXT6Y=YKxTRIqg5+RU;6a?AzWvlS z_4~Mj)+eX&{EBj7SNVRURcHz91{zvPNCf~Z_cnH>YUq=KhFG9VY z5Ny&VH#?5OFP@4h^ik8;geu&d$dOv~5&t2Q8Sc$sdg_=>Xc;zs*$d|Py33TEPmSXG z0zotL+Y0#g_JC;;mB4#(zMXfIM5!s{OW}~D;_S>s{OgHxqrr}$pm4!p6^4>PiX?}^ zPwWUQt8vX;Yp#dS(&pogR0wsv;cgbJg^d zsDUW!3NS1PXv^bt7*T{V!^u8z+`Sn{cP#D-_X27m{t3>+wTbG+PM~4}0%tiQMK%Jz z1p{PkxMZv%l~(`N+l}g{0;3q27RP7pV2G3sFy9u8Mlz5(OPfxlo}R8vw-?n9z&NCj z1EH;9?qUh#T1A7#-}V^uy{^8Rk`Y;sXV{C+Vq=p_T;5yzRU z%yJb*Tm@~sC`tWj|3SyqWLrkH5u=d_5lo(Yg~)RCsr?dT89vJ++Jo=oKnA^NFsuFf zL!vCB)Z{y!)A5X>cM51)zY}mp&c&o_U={|8`xnO*s48hVki+BgP2 z0EcUBNTR4>1}o?b0JRWDoS148!tfoyz(y7FaL7~4DeQj+P!?+(KZ#oFiuDk|;#l-K zQ;-=?9~B;o9^Q9GUF1|$B!aUT5J@$D>r#b|@^7Bd<8&JMpI8Va!nt4N(5yu3JFe`Y zq=RNcRS>GYFL{O1>+AS(^l|l4%a;Sz%Nlg_PUsh&TX}RZgAzB3v;?az+eYqMwjBx& zdg3t3UeU_1CfG~dv)TZo;2^!6k98cFLMke|$Wq7D+@y&f^y;rM5*ziZ%rJKkqVIBy zHAPS&4JS?`@=$P@2Tx0q!-}mqodWADTc8`lfFIQ=RzUm0x{&NhojHXHRhvWECWr#P zx*XegK7;S63d^jFNFQbf&_}jgG@w;HrB|#_sfbWw+RXQnR{j*!hilMO&yaf!k0Qc) zhyxMRz|x>fm8}6HswEn51g&QXBeN)TFhf7;JVROM<~${tCr-stlDZm)%ZQbi<3s)- z`}9OCh36^FDfL1eB^&kj;kjFrb(c0WEpjSK$dS-8FxAM0V%<2MuHcQB20%bY zKOK*3c@{E+$K&M~`myn~DvL)D^HlT}Id9BPuh%h35j0!4_6}z~_ z#G7h*v919F2hM=FcfqG8qGhb%UfsW;zAgFIcd10`y^M;dpoYXwNe8!xPM(5kkafXp zzfx#1bP6Vii$PRXwFj26L&7CS5kt;K+IoyPCgM?)lUaIV8$fffuor1@wAp^a%`thN ztyg3+2;7~cm+@$7@fKNzDl_$N=v}hReudq1XXi&(CwcEPmtOp1)R-{PULrV5WRtkT zzaSfcCo`1w`@-vg1gmugU*O=E%!Nj4&c@XldKnLa<8@pyRnPJnm!I3MXd0Oh^e=HD?Y`O(6YP=WV6 z)Fce`04%hT)A2R}pCdfc^b|I*2cL0fB*u2qoF8FO!mNwDdj2!i3MrN?B!}F?nfp~% zvLkjHpV(_;y-4XN#5N2$ROA{MCuLe1bUI^vYBYa`w)ybk{vV(*Fi*h!0dtCi~#1CAwU1Y-H!mvHdBZoyTsL$VCF2=5j{;x2y&p@^k^zvL8W^a#cj}^X3PbLL32K zAbgOQ0nAjYMLiM@e|`oOKkPn)p{T?9oq*Himo12l9gYPg+LL9>2jkG(nWBmGB)y!3 zD|Gn#5G>&vh>Ow?%5FzlLDggqU1cme25f>q1o$Y+ICn;8Qf~n^P=>HC-;p!3FGjh# z7+|JtBjFx7ocVsE@VUOs`z7*nT5lVmz&il{x{ykk7HI8r5&+^K_ISEWrvPsraZN~Q z4)RJkAKLL;sYZ`?$WfArNhaPLo4N;0VTgXs=Grb)&G}J2A}hGzatuKvhb7!7 zA;6HsHj^$!g6Xz^IhX0;L{z z%Vvy2Xafp4G$g`W^l>AKLNRfpQx%8o*%=;iRM3xJ2d$5#0 z6Xb(}4!Eup3(~b_6@;e%26fdha!i8=NtD4htAyeb4j|)*sXo7w5K)^?n`x zGqMtgV`E`nj8+La?pMe|pn*4i{`sscaXlsVndhUnSY20ozh!6oqBAlD;c`@*F#n{7 z9EFRG?!!>J1pf^8VMPr@MpDB@ioySY8s0=cP=g@Phzk@FHX=*{Na%FE;Xdr<cE| zX}``u3?tS?iVxA*V|jQe1E{+yRkL>+d=#+xdPnFLEkh3TJHhr2vPCIM(o;(l7=kI#K4y zauTBxr^LnaeYpyUli}&xKv5yBonz1KFi8E#InY*QDnG-95Xltj&d>vOYWQll7GsUa z>klyhO~?J+9p{#(dDJGg>A**0U5$2!<1Gg!3mKF?5!~%LEq^!ciAmbsPU}Vu9M_HY z(?5MAxIbO50 z!!t|JW*Q7s#)@+R4C9(CU;=morEm14=Wo;pY5Cf{&Pe7mW3VH5z|$-L06*#8%wwR$ z8T#N^5|mK6@fav${yM8&?5VV!b@Igu4uySltiQF(J?D!vHzlwbi&saqiMYJy;WjAI zaC+cGRKOR01Aj0({irfsj-4t9M|}mKXq}w!3+#qb73N>$ngj0~suaAZXnxn4f+YVw zF)1~muB2$>2CE{=iFhpEs$oUyz69?@B>$~{`w0MA%&3ZcXQDU_zBIM|NS}K1Y-3(( zYJD^XHJ_yYVEzh_f{g%o#P9|W%ZgRAjMbErFLsrW8Q_&#J1)n%8VR@@>o9L) zSf!7Z^_*J&J8^B1_HlF>rx2Bn#d4iKO|0UuIU3;gBD*a>@pvoU1X!W!0)Ex2Rx0}- zvz~&)@M@H{e3`sT;uTp_Rjo40c8MH%A7vqdVv>j>6J5r^)7($7z-ksSuw9GGKDDr< z#ER$hSFLh*%HjY%{!Su*x8ewcvKU|P|8e=}NBAlJ3-w(I`ezpLEnfj3&u+tKSgZqfWO@Ol- z$LS_SzeO%r!6j6uI9*Z*LflbAetfj>k9sf<&m`&iD8<6 z`0~_S7*S_#cd$>{cYzfXm>1(f_W}k4gF*nqzBMsTuZFp7FO<~`StxL&LeN0b6^Iqx z9$kjTE5H-DE{enTAR3FqHS1Wol!o$KCZI{g0ga@kt$>)?l&!G+mQm2?0BZ{Zw?vPU zMRE~2ei@Q1)oQp<0P}4|K452a{QeGqa}1yM{zv%q>(4siQ?IvyPc!nj_>Y|GJwv}L z+jn#UdRy6DAD2}#G|9i)QU7I%_JOjlE9;ctoYRp5T-$PzjcYF)2iGF^+qm{6s*DfS zpn42v)vk`{wpV|++s6L`x^+cmf^HVBQ5Dwq0o(q&4z29g+R%(}!$g$(B)SZwPd0q5 zR<#$Hx5tw(v9F_K9NHk>SjXNt!l{XUkPTo?1|ybVPB`Vu1$eQMZUvekrU8jEEKI`+ zsA88s4K5bitTI5I@yH$ACswsrckhfY+l+$8;#)S_i-YwYA_I;K)=x+vBv02SYVN;3 zGp@M{dVP0!C-my%kDfu}?0iUE(k3_)G*kYN6ljPdXNv45CT-VCvQ{T~PFkJpogZF| zR0Lw^v(ofA>9h@ir6uEA2m1g8z{La~av0{D6WRut?*ill>&s$~UOqz+%^-kI=qffx z&Z?<8Xg%Zl#1ihzkOfrUYi&_~wFrGs+eYwA$^|etHikvQn;R@t11st%^w$BAmC!GR z&~E}^u$pubEp8-w0u|xnOLvpz-mF;Q7Ecy4NaV#XPr6oChnN=B;D}`4nWXMUnKemt z=cht#17`suZYP7$aq|;+m?#8F<@bz*Jsy`WiLve?l=D~BIk3MSAjLcL(?6s$sxZVZ zTMy1a7B+SSiQx%&(MNJpPFd}A1(yJtFzq9_z*E0F4K8Q|h1he0$>}gRxZ)&0&oPGk zK{iD5i8V!f`P&%0PF62u7Vh3?Rw29AqE&1HRf${j=hM}61qxy6x>P0#tCosd&xP3i z3(U{JWWnmps0AzHE0bey3pDc;%ppw%jnGqZOAdw)EOe`Wg%j}^`W$Q?*d~>D;v{5` zs3kE_b3uF@U&S}pDU+ba5&gy(u4Mw+gS!(pxH@28PY%aLR(Jk3JVrP( zt>sBfKM?&@@#7gJdLSv5Bc!6^$ajQmW2h*D7`{!{ffyvgCnO!o#52+QL-RT0(smO`cM?ghFrh>NO{G-~2jjI0 z2+o~0k}gI`6)S>=1SFlvb}_iyEv6|*N`A-zz6y!r+~OVuHM@JUEX0tzvn)P|>9r(s z!t{znM(f)w6&5ob10)K;C;~cRhTp}vPC%#`-oXTl%ufsu_(gdyr)kr!&uL zF_B<@hCu7onwriOg2Cy`(vsrzT6LP5%`QV@vpN2_^!opCKBp@X6XtVk?f+puFJU$R z<9s$_>%}k5=ft@}vhI$P`4Nh#$$YBAWIm1WorkxI~)$r|b7{`QWd1CgGyKQi|AY z1f8zNEs>M~vLV8<*o5DKXeEa&-=<%CVpRx&B^P#{L^%tBF^U-K{a1<}qpC=$R@!lS4F$?T-Ac7`9u%)nVMd;jWA ztoQ7KD$^a}3ZVezLu>(75kv(f>0{#x5KTs%<_4usWq7UHAvl)>c_TVBR?Iz=^1Ab`dCjGIqJ~vHLr|VNHVk%51Gvy?TBn?IGGrto=Pn_`@vF8wSN_PiZ_I<>9gP z_vP$F`rD1S|C#=laCgsf>Cdho%GBaHthua(WPK+dg{C2|ig8JGlD7~95BevvwLA|? zC7hx&b2C*mm@Ms;nOvd;=rM)&>IZNQ^IRZ^th;F{Fh9B^)?4LgNw7DGem4*?XIKlM zkmFjt96@T?R26YLP&b)Gu{WhL6`HJ*7I5>qqrgiEqG-YA_%ur{bJOi@jF1R4F%5p# z7&@Pfz+;PIl@9p$^1q&lV&k?-WspfA{Qa+?8b}k`Dp|LzklSFZd>IL_RqjI@W&0I2 zF(|__%1oRKEWSajFlj8pDvT>q78je$G8ByidOce}C8nkAA)71s7>a~7`~gGcic_|h zac-P1$v3gf{1NFy?PjzK6~V+0xOgYj1`JV1mIm}-QXGU+I)JbbI)5h+5cJ?3$Oiw3 zv`AlxIyFDRGrv{CWCR?Cff6qpSr{P_c)S_kY2Z!;8Cbk_@X3mT-_GlV7@h2Ywm&Wr zUw7OU!`H2NJR!aoJ^R1F*V(+Dh0%e6ujh3J>ll26&ZSr6=v8nOW^o%4)>MeYO9-!M z!7Omi+Xov{+O)&k$8g#qq*6NollDICU6$waq(#NZ%6>K=v67yHMS5;O5~to{+jsZV zE8y~iUmbK}%1$QkrHJ`QRQrd}{s-Dd+}YZu&qo}7Gum#@wqwbMW#gPQ-Viw&Y3qsq}9N%d7clDR+eBrIIPOcdeQ$C<&K9SRn( zM%3Z2%5@l0zhSU?Z7YxCT|OL-pA7L^raL8J=v-$l*g-`p|pR zJULpBz>;f;W}x=1(ZOYQzY|QSyOoYGk|o!oa;~lVXipOy;)b#XZvvZ_ptZs{2UHYGp^l&t^qR= zC-RB`&~jwr^7oLPj;T0ahc@;?WXY}QMkvTpMa_8Pu<{8v5d48rDCpLO=oV{9K5i}Z zP>Wx13&i;?N}AnvBR}Qrqjf{uwKi8^HNFPwT)~z2)q{i4f?igDPUq=mgYh#^FU!ME zKXf%$aR5y~vcD2abG(5^;)YpBBsIOlXsDtwTopf-MNk_ktHZqk-KUumnsW-8=XkhVW{jhDe~V@TRbv9Omy%YyER!d|)H_dXO`! z`l3`vg?Vhi#$V}JsR)|vbrcpP>Y=uC|}R}Ho|t1I%Ff4U6?HfrTu`{Q6m;K8S;A6x!N z_xRofDZa&fW&(YiAHPVN*XpgTFkgdlU@Hq42P6w1S`MV4)gFQE1=NW_Le-En*|6Fh z64In>mkcR`r^tXUmHex$-JkiUiO6YC+wA8iKE7*T$jKN~l;BZjL8Grd!L7mR}_V!AGXBa9Jww=u>8 zh(8~Q!A)V9AmEanTykiSK3hU%tmwl|%dPah?< z9EV;cewv#iM2#U~Pks@#l@_e0(H+2GeITc74*~k}pmRD;qEl}dX>cL)k3xQ;-d2a2 z^2z5j298vL2;o@tP5vQKIAin*a?FMg-x=(OW-P8`4nfgKFNt4@r(rn%a-KE5mq`qb zENk`CjLgRks8!0wYAtNjx}m!0#JfPw*+8wN6kN5bwR;|l^h1NW1k=wp7^rBTVFCOs zYez?JMT&$K!VDyVm-NwkSmxRnFccthp1bBBhUGyn9$4g36bbjlOU(bo;9q8a8gS@C zG@R0|)|&`4*r#8M+0{Pvbk*QPyOJ7I#uElPG=!)hUYh%|{#=6jxAnS^1?cNPM5;fg2DUP<{17IS;mEx!t z8uTQ%co_c%^~#BzMweJ8DQIc>Bqsyj5a&CFT}bAlTLlYr!Y{_p6*(DksOslC4jWM8 zVa3-aHYe3N^$hJ)t1T!<_?KUYG92Hj6XBA;APkdOQ_K*e?*5a$PlBnCeb;gs9O2)@ zQ_ExX1WF@ARHjE#j7q0|O&ZpGGxQN$q|htVtfU_qL?5mfslJsnY=-Mpd-((A zZH0g*giSUfyBJa=Z1TX*(lH5}e5?sJhP%wW(RJK>NfkX&i=VM)uR} zfk-z7^Vr-e2~dDLfx$3~7#uvTu6-pD31R7SkRgsn_%ZT&Z3=pbIa?WdECC;EdADZj z^N@7iEpt-IZ>;4xZA&Ap7dh(UQtM?GCJ6zG4s$l~(K?a>ZaT;}=o^dBO!Nj;b-3o`W&i6S#-BZg1H8_(+-H!xVaQt1U?72 zW-pEg$U^an#PYViiTVe5ET$IN8D9Wk63JrBom>^!apA7OW}?kdU_E8*pZOw=YKXZz zKq^cdqLs&r_d!nc*2ih8^uozNT@j$mWPU80C$~p#?9{(w%lAil$^6gA5HxmC z$MHB$rICm$F0Z*o^C-DKWW>JZWU%(IbeJ!jzG3NFJm(o0Ov|>*wnAEe%XaFE=U31s zXQBfn^*MNpooaKZ^#UI`wOA;*J83FoBz-d}Hbm~@;NkrkQd!eEFT&mY%xQS8 zc|HJzLx;;FNCBQ@5fAzlMsdMUViM^ajb-Ybql@J5;Cw3#s}-VYv5xz`N9`bmzKN}) ztuSp$F@3?dkFNRnX^a2ri@%#8bHWMv8jms|$H8az#`JU%_RHW~>;{Btk){Gv6yF6- zq9D(ZBNvkbAHLg(_sVb;c2&H${3peBK0A|y7QxZ{`{hUq6RQv03}m0&p?m@6gN{zn3>a?v1wiGo=Z?W?E)C}3Mj_dG-PP&hu%V)BbJPc9hjpbhG2w)tUDDSX_*DR zUMwFoz^X89{7$^X_tWM37&02}i}6o?`4(Br7;p9D6O6#X+R4}mCYzOswP}X`dMgvt zE|oM8jg?lFkanh|O;Kr1!@uq&REb6xa34(weuoLP0x8)$q(rW2$G8 zYUQa*(d~WIy{*vwWYiU`dp*gM{5no*Rs*-_Mdpg<`5a?}#!_nD#nz_=Le(alR!l!O z*lwpi^B+;Lfgq#?%P1eY#$&M#}Bbi~$L)UXPr3QRJ7R0oF$&+&& zQEX}D!dDSpT>p^u(6kRse^XLLgSGxCnpSTn%LfrZartGZJ3Hiet%qj6)xR~_|HZ%M zh)wratbwfcQG$MREe*~X_a9qsa`@|#X%7Lox4`B|A-|S}C0AfHRvk36mSrl*fC1~O zcrJ_1C_(1Np`Xj%{H8g5;Mq9Xzd>ZGjPqL7c;mlra-`r0nu?~H5wKtV8)C*5K8p@s zf+=zDH5Q#Vh!4ArMHkA$PTX@Q4{sZbCd$KhW6=%rP-`sm$ip^c(F5|Z*;37nMQu`D zT}+>n2rJv3M!SmH`pCBwA?NXM0D!2ZOWNs7`dlSlhP}qODE-Kop9+Nw*~MOSCq~AA zAqR^ma#{AP0j;a~aG5-e1zn?xAmYJ7#y32i-RwGp(WkD~3 zakYTqy~Mb-S3+e!^o%!-fv@aTSwSzUY-d7cr?IkbsDaRvEw= zdYT6}xTHG}i|^ha>Bm3kp;p)q_v0iu%qIYKo{GA0j3IPHvjEcxd8@V4xD@Y754Qf` z!yIfcTJMq2`uQDO|D!vx^&Y>_daczu1&G!9o0L7O^=%2Q_hjqcW3Bg0Xnl2Nhk@+h zq4l1g0n+yif2qeMs?7+8B+>QfiXyq)BCq6U)@a+P8He_SlWo2rx86sdT)(V^f@P6JKTRCSsJAk0$WJD z+rl?FlG-e?3~v9K{*)MSKGoMyNo|iH(QD28M6*(Tm zkn(o~avJlKkjwkEzcIP~>ttBIsXTS*LCS&Q*cG6So4&_dROe8ew7)r(Y}pPLK)CoO zR`$b4lxe7eT`lk>vf>$zSB=sraxwwwxC)jg4!v8A;KQ39&oDYq{VM8fi zGwC2$IBHvf8f3Vktb6xM59axxtb4%(WIld_<^X-jxduQY_+l@XgE(dat}=EI_NSdN z0=lz+>&dv|$Gz5GeRfz6+4?0S%v!Yfl{g}M>5EFti#cgvly^mOdM5F8{I@qb`a`dr z|7)lYy2JICMvLam+zgqlO77fiN#ar?R?ASFh0h;&ba=;I;OdR2&vfI3P%4u zEi?Ew8sD(a6K7um(-nPPB#%wD(vuM12;{Ru5NC1dD$>;g)KWC4NG@E}j=kT&4P)V& zKR{JLE4{%mwG^_uoru53P)3D4T!_&%7Um3~KGAF}93T&-v2chyG$ryYDvK0Zf-m9~ zFhA9WZM)f%c+$z7u=OhG8j^oJiN+c8d6je*(e!bUjzr|$w9J^@&DQ+#F=NWPMxDd_ z>j*#`irg#;U5vhs*}$#+@w4xKKBYsUDimTI6OJfrF-B*d9Jv?`aJ;C-ii+}X#{%P} z0M9p*0^K-js}bC<7->*$eo4?lWBxMbpYZ$|=MHFXk<2(hMfqFM1Q3R2-g&?0;9rdo z_GFJ^V$5R@t52;TXK@{?hLviRGneW^D{qOB-Fn|)-Z1mV!pb%^)2N(E5haZ|6Ld%p zzW^`B!aI(W<1)$N`JJ(_`Z%fCDz(g5cu&VvQ3~6?6640j#=<{8rEn{GMTBZ%FJsBb z{`g{XgO!rcn`)iHptWMdEVjA}{Ilou4mrE4oae`L zo+V!5;7T-2FI3=hJlOh&)>`6k!0ijeycw1}szIs^A^1Zge6R24pm@gtJ{yY5PXNVY zl{F_0MNdNE?F|S#XC&~8c>D7niKJ?+64S>X_c)ncLfC4mJj!VhKX(JJ#t>Bag`8Ia zyaaO_LVrgHdsJieqn92biob(mdg;%6e3OqnT-IEJC*g9t{c;3Q_!)c<@{5T*E|DE4-(^19u$~VkILRk z=>N$2h|_yCvYO%Ws6P{q%8KUjm}Hq_%R>$)7R;f?t9pGg2{~3Zx1>RzY3WeE$@)_y zf&o%xFC*R(`v7it9k!Ihz~6=VUaUKxL5C*7d9M$C0$1sJ{&l>D-JKgg#aa)Ktp5(} zb!Z{-GPkT&G{J^UK6)P*4o`z{1*U)mIgrqAnJ@{ntAZeoV%TVbY!v6v`#9j1v$E$4 zWym{>Un4yg#$v2nEA}^zPEDH;8lCF=?VYm=L(bG3&+mU{j7~iXi(`MoVP4EwwH=)- z%->^p_eXkk!XNTQXCL(VY))YM85ZB5r|^K;2LK{zPvmyXTBD``i8zASrk^uDnu38N%}&B}WvhE}iIrn0l}ovB1U&nT@5 zqi<3Gc={Okl%emmiT#Is&GqL~qvu~sJomPweoaeH%q}2Xh!BLJOoFY-m0Y9!^P2??{k2Gy$ahCqcCFDdBAOcQp1&oMDQ!ni zVI7l@Ca;XAusj*G2lKvixX4G2$7r3Yj~&CgB5VNG<{8oL2;YFAU+ymFfW*er9uGQa z^a&GfZ_99f`gn9C4`)!&HV>`0WTIX)#@1>r1vC1g@<0C_#$;O6al;awC2{dw6qC>6 zG1^6+lYT_`|LAM@FiHmk;@k6gfVP$_;?Q2%Ppg84sx|ok+5RTM-@ref5r|zj?xrhQ zQu4RJ31rI~ed^Et`$i|}z5Jg>`QYCd^*5&Z8``~J0fQL!+MINBC=OT00UnX_^s5I) z5X0M|y=#}puI$X$SrF!|-O-Yvjr0D6h$q7d&j^48vfb|lGO4xS5_}S%)q%-?)wP7z zsN~~JBD+2)_WIaHw6#s>w0` zuJvL-0T-*gQ6L!Lf9?|VAg#^)WR6K8y08&hA3swT- zs9Xb~EQOUSEe7UGuED95`x|q|dH+Z=6TYSc6y4jxfDkAtB@!eJvnM1|$xLornLkCJ zb)7!-Mr@(cOGcyCerPBc4dsC1vVmXV_Ow^gih&=wTm_L3m(qBR$o znW0a})Ta_T&5Yq~!DHX8R*cJO!o0{)BocntnS;yGgYpZrVs zpGcp5xWNh}Y8{UNI)bIg5#4UzG-1&X=rnGx6?^J%@t?IIGc23U>PPg2Sd3Z|KbrGC zq6#5Hr!)x!m&wrCD+3Hi78a}`(d0H-Vg&uICRW~%Umb>U*4I!q;9TRihQi(dI|;bR zdwJFCdU-YN*T2YX%)qk}uXMFNKxD5R8SeQ13-xq!N;0KEf9Ecykq=gHxnoR450Pd&%-*{%bd?!VPh@0Hyqd@KhI_RcHEJ zE341(*GF)9*X%oLx$efjWA(fehhJvYlEdPf8m{Pktxw=@_36eW!+$inve=mP0DtrR ztzOUGNS?3$CV#N#7ttL;-s}&YKqSo}#M8BTreRd5$9z< zK9Pn2HW%n6=j0Ufk1NoMcYAocwPSe1SNsLO0>@*+a~%ebOoH(n)_w7YJ_6U0 zfR+S%kXZ|vPi#R2tr#9xAix^(jgi?veke4305W5!Sjj>rB}5@#MVj`kC#n=$m@>xT z34T`_V;b%R>#W=j&&ut|z8M&Oubq z*;X&`?l8Ya|M2ak^~4^id2;HyQV&(UR{Z|>Y9KOTU0x?Af%2q43;$~|YQSjTT~(cB zJR|@e?OJ)JAa|F_9v}(aoof?9C3H!YwdJR*mjykqVffbkHh;9sJwu^Y*V5;e^5~o2 z;3xVew4pO=5v7EyIQywF$MvpwRT~Rx|A5EX0Wfb&MNogeTsa62VbF&(GAEaOrq|GW zH{bWwAh;KY?nG;8@5JR$k!#ROkJ|r2ezf8luUhbqs(lh)B89b2Ny3ckuBhRn$VL9v z>grT~>rBs?kv_iGIwX3|@U^by@2OVN)Y_-ghroI?3hg_Cm` z+~nob9^^R)U68x!s{06ea+`rop5u{ceHv;Am*UA-yjK`zvddqLOm<%v97X#L78iE~ z&St#{yy`;?g;r00@ZV6#B1c_dF=}3B=Pe(8Fb)3^r)yCZ&$_`m!0mF6W0ay_D6SU#3Mrh5)qhCr zp)0rp-|b#zw{nze@aK%Go-TIv56(q>__;;>Kq0_gVk?lN^GL_KEF0tOUO%=e-s>~` z|6pZM$_&}&#xZ~K`p$iyg3*o)kMp*H>$n~PAFDidU0?MyySw6Oz1Gv)8ga#VUKc?U zt;M&AeGqhAHX8$RJ5dJz?dL>#n}#;eQGQefpaAJo_Y3TO65GQVx@Li zT3t+AquuHwhwX{@6DPmwQ42FhqayQbfTT>)pW;>P1M3wrpSyki_c|fK9%OUaieU>P zVBW*~osRHx{2l|N2MLsSU;5f9_q+v>WaxLmkU5inimvDFk-*Y(`Qf99KdFOrWl#Da z@3;8odc`+?Kp%iIiq9hV5EKVnD(BSdld(PK#!zWGC&}sqAI-k(gX|K>vQS$-4||8L zx&lN>D?8wDn8nB*CX**P=K}x{s0KfvmEb?{>t2aQ=QF)4()F^H)M=S|0ba$!#)Iq0 zBx=t`ozT>^vZoY^Z;oGV0A&$l1THAc##O>LXv{&im*ZGaFhxb80#(&M;6`+V(i(<< zZK?AWNy3tDU>4Q(k$HlLU=Zrm6{R0!=bC4IBrJT4uj)~mgL0!3TU7{pEX$FdlI1+( z%7I$hO5OdGz{I`@B%+|22cMKoiF#K!Bmk|{N?{jS7KedHen=~n>)bLb9fxwnC9i?M{(%N|Vxeujc;JVxR3 z@Ltr9dzr(+uWV|eM+pt|9dd^wa*{lLc_{)BG5oA2<`7=Rnf&h$z!vg5!Yf6-v%piV zRz;Hmwx^L_2XfXaOVCVfO$(8z!VJ8tC|>{m1bg7+^&2uap#zG%JQri_CUuc2IckRL z%~)VVY>v0!8*G*EJhQUc=ZA4gucr$9Jxp+mgq%d_$z$IrA7|VW^qS9s-;EN z+xqS8iXTCY67deL;AGjXVeUb^xmVd{#Q-lU*Ssr#K`i-g6)~3+X5Ird#$e{$jNe9E zRJvChH4k5cIhf*W6HL4?F{PbXgFu2>qD-$^MYz_l7u~UdwLWasx)p78taUPKJ+|xu zl*Q_PF`c0pq#$`H?~DXskI%%=m9159s8d}~V|^~&Fav(zP*6bqfC)jj5!3^+Kf^y4 z=77^!dJDFI7Ycy~-$a&Bv5G@2&g2Y+iaEpB*hTU*X6N$uL|n0AQyY+BS_o$M*)X21 z)o}Tjd!<&KUdzdkTm=SWjP6cuWxjwz{&8F!z4mt)#aYOs;R44sdih%0G{an{pem^+ z18Y~H_FA|^vou8eq0-D+0s<{pn~qILoaGpDOvC)bcH1BG-IW^vHh+)CFv82&XhOa` z#Z3F$rGcnu?uhevcyeoO#ANf7n z&r{%wvH@4{F#fK45nm(c@eXad(_HS0b-Mg}kcP^YbkQGN@ZH70%!*gof1VyAN0T}k zF~ z!Rmq`U%AH`a`UD>K&6UT5^g3^=wRMaf5QEew8vn}5^j;;-U>NgVR?g(rw-J(9t{Qd zy@iRdagE*wUdf#-nL;C2wn7$SiaYiQ$~2bgYSGB$eFyskrnJNQJ+_{VVakwQFduN0 zACI>fF8q({AIm^VKK=b8=y1Kgj!eF%x24#wG0zgfba|W1>#)w_37>F}FR$~psh-yd>T6Zc8%UgL`y9y=Gs})2e@fp$VZna$ zb&=kPg1}{1g?3B0a3v zuIjZPx{Wqs^SpF7q&K2GSq(n|K8JZ58sfTgxUdQE2g^7RU@G}V=XYAT68%rLB&q~^ zg4nxdBM#@vZimB+f96|Irqn)0SKxbmpbC$>T8jjj5VJT!MT++oDb`n{1V@peygmz? zo5hs<+_$Kx7%@ej>DUCz`|m8HJjdfS&>izZg3z^=rk0k!mm=vXa{jSJn(C|~@L6O) zK48!7WN_`_y0qca$HlCst5JJv`!FjPh0rN%X#wBW;IlhsCEn@7Qzp{{ zdzuxmz%8j)0ZGA)hO7PCF5a$X)jpVQmZ~Rm{!7gNPUo>@DO-P)z0A}umbwAFO-@y^}As4T?3N$_Vu@) zJEyOHk5jA6=CO3%7H;LP%!%Y#{3w#{Z$JGW+FE&&p84-@)FddGDCL|iSBdLmasXrw z&a%RfI+K{91jA2Lw9reoH7r?2ZY!M_$180|Wpn@XVmjje9H$6~o^c z*t$+Jd$HO5Mr;FJ?>E9FNwP?*oe6t0*mS6eY6ZxIuZ`R77*#syUh)i@2Ix^x{ ze$SC`&%o7 zOBeWqiMk!rjG7y_&9S^09qHXp5Bv}5YjFpSFpEz7!Y=>g3DOn)ORiZqfpo!qY7HA? zw6OGek$8p4RqVEagK-roTYM!|#Ms^#MCh_`mE4I|WJE1jiT)b$L4o!b00wF)Duj!gl{4jFnKs(%swl#@$k(sv?MP7%?yGB$*P!54Bw8|zwI(ILh5XHLJ+21Ymcdb2tZWzC`MuqM0D6iw_A&f(b$GM!pM>qmD zJ-7mkkVAM~hBk!s<1T&Z>8nLCS%|X zS8$9`KU37tb?WDK^&^(4#G0Qw_YONK0CLV4+Ye|+79ZmRpZpnPgSD>Ly?8y@PiHqJaxnZupY&0O{{9rZXydU zLrh}p#C~5?M zlyn{n7Lv2SRC*TPkt`cPjK4*Z#|XAFXT8h)o;r?99h${VAvsTlmIZ%RHWn(9g=a*m z1MO6nJiNn@jFa8uBrGZ`FbSp`PY*{zV~|bY96Yvx`Uo_n6rKnk9`ICPfuxUh`dgi@ zz$$#jTG=~jT6v)GeX5=Loi}w(E3c@4a_Tqmj?kAXH)Mj&haHdbiFl)ffvEdD4xS1Y%PYCS)zD?f2 z)u~MdM!d~Xah?KWuvR=+A6cLk7YG=`!+!#Fs$+)ut3s(ctPU0`^a5uUp%LaIVrA7M4nOf=SQ0bTp>3DtQEn4ZsQ0bI@^64(EbecZWqm|AyuD#AM z9GG2gSO3lRN0M)C;lYai+jy_>9zG`OKU9RxrBJv+IOg$y5o`gXfFozB^%5^@N;hI> z5GoRlskn8^ke8|pn0hWa$S`hZN{2}icqh@``f^sMd;3{SE-~PvcAKBSe=eeKQmIWw zbwN>7(m~fZRpe|HkEV{N{^dGtD&>ksj z9r$PVp)IC^7W1zP1ST9w2nT?^3;2D_Pcc6W@kkf{{Z4SIw@8fQBDJ-cY8w0`QpXke z2U3q?@rNI41^(ME+nA?B>V_#n@qv&#KwZFEzhHbFW&`VXFDAK7M%9g=IQN50G2F{S z?q#AnxSvu#tJTk1^;4&QwyB?8>SsTHV6)J#;$Yi%I@#w3k(A7b7714i{u3_-e5ohO zObRn^v@*XTnOC1MGilEpVrAAO^V$<;CRLisKVfE4zd6;)yc(IUNt8v%doZvm=LlE61~{uhxnOAD zp9w=Z1Jva_Sv)D{BACJbZ_u*n`HfM`B_bE`_QDLmX|%|gE9NtccSNYz$yrUr8iR(u z;xtr{LyRewL%6hI+UJoRAngh)PR(wgU@3eED-*R?2KWwh4&j7;H^7WNh1poggw z1zBgAIlXY^#lk!1-U}NN4?DB`^>(_xZ~~Ihv|My^6*7n93+jv&i1{0oe}6{EUCU(q z3PaFo8o;>#_GfWw%rwVeBg)ZTTE$a5OO1X)T4G-zX$$E3mEd9YKLwBC9Sp%g7jcqz zka1%CAYNDEems<6fkB+B%OGIFo6sn%`PO%WU@myaS}%tOf!;bL{uYUe1Lnp!%jzZE z6`6Ga=RZ?Aul<0aNI>|WS=ke#^@B{Z|Kq`PLCh-&P)BHx?)_o zLFLBz(+#>$RWFsBrL1}vf&+G`6%=^HztIKa3uc+UgyH$X4N6J*JzudX&=B;(;q$KI zP;l_9yylokl~|w1obDA&=7`wIt)&n%4b~KqSvTT3cDb$nVE+%3KGn)<=?A=lc3k*M zaQN}m4yM-?FT;*nk`_sq_%b;67H20F>E7C*EtLlh9PxpBcr9bq_K#VGi7a|~EhGb7 z97;;i>kFu`Yrbj)ronvdkJhAHEB}?aQ=w{Q$W7fF$V4)P?Y`3-KHEU+)k!5i;J%9zn9G*=bplT(& zA8>j|0PT`jQ8z*c=)2mCbA6I{rca%LQ)GCM%m)z(C&62uwTbM%Sd7oida8yGcT z5}QzfZZE+o;S`uIcH6w{uQd6=KotHN!e7ZVf3u>uS=P0f))0lEh4Ce~ z9I5P1>m<~q;f0m?0s`F6wFH)Pa{Zks-2m?yKwXbowW?L-lBxKO*U0IyZ3_w9XY)AX zACA*Z)f&Pz$YaI4IVKZ>J$I9a;T6EqBe4Fd78!*Xqv%^sK`R?;F+4c5TQ6Is)?hrC zmHtqGr)C{zSg*&d`;WAHuM>yj8qC1|qwQP3qb#n!lMo<6WCKLx5+zF1piu$Q61f-> zl5jCx6cCl0R`Gs=T`odG*3AZ9Utb6nETw9#+Lo&S8oVIhAOV^Mq=;w{getbwzU!h! zuz>`d{eHhQ^X?@C?EibdZ=WaGcW36EIdkUBnKS2{In$mauyzA5h2Yi|Jw4s5|Jw1gePtjB?D>>z%_WcWFKPJXL|CE)#Fv}1r7hsFMmVxnLifgTzG z&y@lu;#iO$Idj^6x&}Hz9LA6x0jQ8T5Gq_t0e?CsJ_RYyYFIil*dEovBPEqj%fRgX z4aPB#jj*~n<7s+Uqj7g1Hf3z##p=}92K@!}QiD5(heD7E z{D7^Bg{t{?v(Wq|(!TFx65@TPIHeJnKE_PA)I@(Hiakd%P~YG$j=d^$3G_cEJT7sx ztT>B@zZ|g!=-EnFEpUmcA7bds#$(g+*J$~Pri7c-TSMmLK_#4lklU{`j z)VpenbHD?Y6N@XO#e8&P@;K567>{m;Gd+a4~FV0!! zOr+BzHca3ZfNl!<)Y<^KS~?~Ah!U|!XS z^Kv5c9e&5f*H!)kW}cwoND+lQaVRKf(-;q(58sx4f!(eQlQ8dD*1>A_d3Y{v(+O=|vgvVNmO`lvF|BzS=Qc_O3)}Is_pq&Qd zAMb{>X96D>_Az2w?atuFBL`L-z@dz~(9Z&S*+dr`#O;k)#>lMtaDI+~`-dLI6$mUs z8?1dEEL-3viH9J#Pxt_H8vZ+}B4f1BuV)w^!{ez)2~;rL%j8VEDGctqIDmW5K9gogA~3| zE2s`lB-lU5Hr#{2@KBo$Gz+pUiAsx$v#OnCjdUU`UuF%)DV5OLmzK%^$tCa88!55_ z2UMPQ;2L_r(wyD-YdAH25&8%Dq3FvpFnbF#6mwyq1`d6U$b@s-T~tpb_>UhA!QM$i zQ3eYreaG~>Z&zv{*(IF=ubJrLHQxA2vBuDhF1*y~-Z`p!xRoQND6W5GNP5>rBeh<^ zF?-34#zAKd+Uvp<1eSZ8QFcfhyU`yU{wn%2DjsZN@@90)T+wC}Oh6qFG$7!o!G#%? zm4hc`c2QOo8GdC1!Q1+R7K;jh1X)xz8&w3O9u^|;UxKGZWe#8#-S*uhja8XQR;B?G zf@QIoVYOxxfanR+&lD*?m6fslGc)mo%XXw5WqQ$d5Fc>3BQm-G8TZwsS_9i)&fZ|i zr7cFI^*;M&)b~9>&2Nodsl%6)zncA*a$?Zamxk7MmVj@{B|654j>&-$9ciLSu-qL} zL+w;eeVchTPXp_rH$;FN7mz9412701adUv7u01KFxDwH;T7qVdx`~^7#6N?IT`Zai z_^=d<3Wl*G_B8DS%A3km7x+l%+K%3>96d#-@2wUU?kIsI^5vy$tB|D zXAoDsa376AhUegEyKIRcGiN4mPXJ$#&R0E+&g*bsJ6S_S1>!4x1BYf_LR$X@trgMo z0^-G}6KA3`h_J9!6jdHx7y^3<+z~f%f`L>aYrP`RzS8PsPm(!^wEq;8A>_ZiF2LLz z@;WBK&osAav0M?_&Gt>uLRbLmM~;r%}80r=L4XXYvUBgz|@QgQ~+WFnStjmwW?;aEsxfC55NxE|Xt0TD*6 zujU)yiH>u+n-$9gs2eD;Mtx2D_L67tX6V8|Q9pw3YfSTW^A39$1nlXAG$zVf=+FX= z2ZB%u{s;Ut{<{Jvz<;{Jf5_!v|5hk01ZK}Ar@(s~;cdc;bR%mE7;)&MsGm>WmJso; zarUQ(uN<>O^I?rZHyh7ee33Q$i0?$woXa^OcXB&)BJJ&m*^#yQhf}CQ3d|d_@z2+I zzB(C6{nhu2ZFAZr%=rO zB~-6blf?B%WFfm*P4slfaOVu-Qyb}bnnM;FeEgY{;W&F9$TN#`8m3&a83IN|DslFH zAWX6%awnOwb`Q)c-_|UdG?D!ou5sjj9~3@mQ?EyVN8mKeG9DC`tKc2}H)73?3Sde! zyw=gqoe$QDTOBbiR@LSnD{Wg)vEB12R43C?Jk#OVi{j!61-%ONclSZ|5?kZXu-?FH zoW@KRAW}tV5)bVC7%4G1+817f7f*yb0VfOuVL$f1ay?ZJuQBuA@jqmLj7dMD=2WYM zUwYI;MzGrm7MuV;vHVEMlavi7!O<`!cVr6On}Hn&<&*tT+ow=ja+X{uBlqrQz6T6L-~Nf27?Hn~uc!Ub<$(mu0@yPOISdESP8gFf#%9>4E+YT_~LP4>U< zF}hQn)bcgAZ*pHFr(zsSLi6eN&oCHjSF37-Mg#y1?`Lc?J5tPm#LMwg65tLC65uKG zDMw!x3l>u%C+WdX3%gr+DTrRx(0@-v-(*fXfoo_y+2;5k{d-&$H2eAnK@rIvTluwc zbKdM)zbDi?Qr>%#Bjo91KKvtO*xP-Bl0DPRYli!3Qga(;zgC?Hg9dJ?l~z4{uzXyv zRb7nhyUQ+{gO2gKW+-kkP*?V^!CYf7i26jaE5s}`AH!kW*c`eU)b$Zy35r>evp+q{ z{1FieuHL+qeQjm>S>}9M3$3-yPZtM>MV$vaf8VEo_X@CyXc5ck>7swyT zofUV_g?7a0p&m&ISXIyuxb0y7eMBr_*vB5m)#m-peDWhlk1DP1wO{TJlNomDpp)uh zsQV~PkxH2ny3o8O3zPSD-=omv<~!P1k`%c5KQQRVQDhe&%S^CFE9p-T#PWy(0x#IY zQxSe(Z@B6R`v|%uAeXT{z01qF4m|K`BIy@FQCg9+gb?RXn0RQQuMBOY`1e{jEUoXd z{cQbvFtiKFU2npxlmx;nghSa&-cqbz7Q`*aw$Kj|dWf#yvKF@DKa&B_;?7aT(K}a3 zOpmZV2O2MD8E#cRfXZo7y00mW!(~I0!0O>2xf15P%#*GWN8d?+W5K3`vmpKyHqm*~ zwJP9RAAs+$m0S)A)W;&yV?4+s`w|KI#rYTk#cmRQmD;c+ksHoryG)wr$(C zZQHKyt}ffQZQJUyZQHhX*;TK;b6?!^B3?vB8FW_-|fu<>mM64)8D^ zf3c;}769CFp?81x7S0k~2A!~*)hqQwS#;Nd`{n=h)OwThMXsaB0q$Q7OI3o%{u%m?B!i07+0Ld7R_e&Tc)4fzyG z*>OI`%KW?vTBGpS|LF1nUW`dZHXZgTq1RNZ$RTpter%XwIy>T)#qp;|dwUp*{K|+V zZvCL!%7h=ixPA~S;IP5puZCaaZv+k}*+Q10JCqe?9GF6z zuKYjItY1+#(V2)#)_JR5gkS?I>dt1coDDSfe*(CDN%+Mpf?betV8w$$o!(&Z`F9y8 zKs~I}b*>j4Jg6_af6A1(9vZ?E{a`qob|)0o=T^i_`nzaDJXm6E>Tlq;SCWGlXOG65b zv1vzC!LFS-N0>+A;Sm$K;#QnORwL<9dau<|jh-^wT`5G^USa!PnU09yohFAZfF0nE z6=1g`?y36JeBnikGm3~SU?lV4~u=C75&qFg@W&h$4l4lfr zzh48Q^T*2$v!B2|uE}T0+V7kMA>7L9+-P0#(^& z8!?h61Hyu%r=r_Q7hbVhWO8$qMkq!tlM)3r$Nac> z4uI=H=8sjDD0FimzrkE%^+q9wGvAf`@4O`NI(b|<;HtTZG%dHYOyo*Er3=_$G?$!h zET`o0ub{V|jVm69*Pstyv3%H>7c*RFHIRO>dw{LivwL5IK}JO`LX;xVfI0^z-!-IA z7o!PWrIZ?D5piff{*mR#J~WGKX6_YgD9AU*4YgUD(SQrL^hpCK{?+#XAHUNB|fYuOaPXl}+OnZ_XA@PW<{;`-Sq7^f|IL?~!qr zcheEM9IM|j(dg1BuzAK`LI|}{hpca?C@s^oI;r*t(~4M7ukka zVwzYkcz03HUR$3xbp4JU(pD;UpnRj=bSOQ2Y1#TbfutU+9y=+xh#{A?QvoY%bAQEI z6I!H;{`o(29ei3u_gFjMqLcTKN`{pu#E=TA$*Oz9aQD<-+8-!nVId-?h|WG!?5XRb zHoAH1sTICXc1Zfc9zqsGg`Nz$*MOTyYy)*x0CPW>3W=Q!h(@^86 z%dP)D)!v8BDiEwl%>%d*g^xQVO}0;A;&#E{OA-oP;JCu`MAEcJCAEcXE=i@L>h>7wVTo=s zKOc!y*xf%(82=-{4nT{P;gL(deg;%oTw9-Q1s(G*pg)|UkqtMLkBVN<*vCHv|I6LDSuc0_ZL7`8oNG@QEeSCIhy zkP+iiN-jEfFuH$#v0j-RHr)=0oYAmz*yG&WK1zZkfv&&V&y>JPTormS$XOf}Vz4wxR>FNMBK2qww=U)yD6Fq2*To_`JLkCqQGQuOS$$Lr8!bJ^5KIq>P5H)~0 z9VM-n`EDs`21uZlzp-lmy>21oa@c&PGJ-qrAd?ckK$e75mve~1T+1kpd4xzd7;tPb zsX4$qi29p2-Iipg=M!h%6RMz#k+BwNk9{;uO+4T7e&AC59O|Uu%O1f+@ope&Vk*3; z-zQ3Rdq8lgbdf{R3CUsJRB7~HI>g~OIOH>Z59M+HmJ{CGZSv}Lh|l1I$(Ex>1?(i^ z6SQi>i?pxe*3DjubJXcjmoiPB7iVz3;rEj`oYPjez4})uoP0qrx|7*&ia;qe_as9) zh1vDwaYd&?Gi+f*(gsksa4b{%6P?g+=6Z@w4GZGC)US1P%?=NU* zU2+DiU!bV-+dAK`cFS`6A>S9Js6Tjrl|Q53WR3V`3r^9>+yFl8ObEW+ zf~l#CQnk5Wb$2n0C+4-6aW%<19X#L>l@hcwwZVv;FeqGt(;BSYez^!d(4xPEZ=D_t zgOTc}!aDO#p6?0SC$f9y-RY9sv{e4GC5i<5wdlN4h1No zJB7}FX6p!Bd7xjEAG@SEVD7;w;THP~qpTwc(`;clsUrY>H@>hDrfSnS@`{2)eMV~S z;e7n81eU)NqHn45!*?-@`gd!YKTIBOPVdn7u>YQ{?!7miB-9>Tg-gc}{T*(0r(Ha= zv8xyL1RT>PxfD;M%0r&t43 z8*5W*g!^Y~7T4S&qC9rpWrh1;#V)kaR?$r_cm(!Yc||yQAW^9SkZBR&nno%<_z2MKQrr-||2BW7$je^6miE#Oo)fvXsMUf4;Z!Fww4N+v z>lIHh(ezn9fR?qIu*%#M2m=ChBw)X9l!Wje9ZHb6ru4c#wC$bQrlbxThA3h{1L8gr zqIk&uC3xe|*#9gp8D{(5AF5Nnbd)JZq;>D4z={9&c*;__vd(YUr;fSCI|`~bxhSH6 zaP7Q`|MnYU0c@kL7rg8)YWu$WlvQwp%EUFQ;GYI0*^$@cEYH}dAbwoN{XS$-Mi|QP z!~_bVAP4-^vAgz;1?*(FFg7HGO^TqKDGp?wxVS|4}Ph0R2p?@4K1b6%Ywh+$l1{^h*&dmZ2Dix zFX-AXq_WSAvUM@TNcZS7dC_(NW;aGE9g1+<-5#ZGnNcH}7eq=E@_fRd zyMSau+z8kgDg^;vh;_!ekP0o6^Dp29oChWAIwR6iw(OjK9o{cSEwbKJMK`k%q^iKQ z{1THoh}h|(^kPaar+FwMhHqT0pg>L{OiZ*Z=4O0byDpvFj)@jrQ_6qpP%{kA+9+;K z(cFSVWsP~6>M?n}4;E#F+}{mc)@#XPRC@ibwRJ!SMq{&bVt+9V`9(?xMO#o2hMI=_ zO(}c>DX{)9MdJMo0xQ7ez{XInSaZcc{F4^!FBV9OWJ!t}3z+oGHKM@E#jbSV8bv?o zg;{L8@y3w$vq+gpwo^BTLmp>3LN}dPQFSf@Kv&w8JGymed5HoiV`y9M<}ndEgD918 zX?2hs%eml#iD&G#obuet7wp}bxoikf2Hl}_eVG6i0VxLMb|+k#`6{9bF`blfv(J}p z%UYa|@8dxC4VM}?r1Y~U#{g3&r;XU|#c&aDeOm!h>a-l=3o#>|9m)BIG(wSF%15-o zVH5z8;-Fx%@#oKY{PIA=(1HyAE$}=P?sfhXqVYr?kxYgo+p34jeGhllJ(Fd5H~Xdz z%UM+Zm1(c0@=Uo#a2N(jc-_FR1cHnATAtCy;R_W?94CTY+uLq&9KacLd7|35;qJE{t)qJ zSyOfRZ^1_R?zCap{04wdTCWPU%Cc9m{aJYLfSv;EXVz5h=euO%y@@)@Rf77y7oF*6-%g1AMwSAO$tU6=(sTgdbSHt*;bx$0U}rL-`)kNGYoeD;o78S}2N`lZcbDqG(K+qc1}{3oy5(_&N5 zv!$Np$E+W0y=g2^`Qi>@Dn$Uq%aK0nJ@_Oj$K5o(iMhbaRWr7YJ%QiVcgJnx3}{<| zb^Pb#%&@|KseiWcLFS=G{E3`ck4lNJAUnZAk+5%67Z5$Q15do{V0QhwWP3d_*1$hM z3HoKSD+^Mjzp8`MI}qw2doAeKzahSTiYWWCZYox%9Tx9^s`Q`g>R*C!^uC;>LXo1N z6MsV|x&5hU=K$B1Qd}s(vN5Uqd%kA&3QZZ>jE$KH3%@ZFU~Vc;V677rwHy!Ib|@Yz z5(wvFq=Wm|*J!q9HT0J_8^j5^&!0#tH_i2JZ-4sWT6f8dnV)-Bl4c_UjQ%Jl`xnY3 z``SAw5UdsUM@F7Rz$CvH5p&qovE56^s8X6wx?A4qg(pxqeLl)6G6|DlScHjDa|fu& zGkqE%kAme?n}H@KhpjbtrISn{~!E&8HIq3)Ni0+tQJM#CG4xYu2bc*(&aQ}!DFPG zlREp10HY|CEPihzYHZFcdM&N7aHim!y(G>SD&-LE&rL2XO18p7zp%USo+3231Su#F z7n+PV%#iUgZNI-7)Y>)ei4urYH(ioGVk_+5TL2MFCc_-bd{1BFWyMuf8|q=abh#N{ zM+QtNXXQezpK_;O2VqbMGF%>*UIEhUsp=Z6Cs!>B(kE<@A|ZW`k@BZ>sLr|>v-IJ5 zhSeI~r18U1q}BunEA}TzICiFm&*zYgnO|kEA2~BRoQs>_xgUex$MOyhp3HRJYedN7 z4174njO8DU?>4!7z-jDHGe};TPz6$G_6Ye*nQv)(U0C`NX?X~hwExMV9 zZBP&v))C3zl<2K!;fQj;w>~wnp?fK(EXYAP3mLj$yr_HV?xYWQa`EV55-~kYKcQrN z$kqNv5=f_ST=Ip{5Lq{Wa}_yT8CLzhc%NIe^ua!eVG-e z?Ljof^2>eD0m6u6WS(pnV55~oREy57HHx4wFMq2w0*ntBA~ktsiVhU=!7?m_nD9Gd--c zc0W@v*Ml11qb}SIGA}>QdirjZEaCnlDz$z3iZw1uQZi|xOG+1zA!j~vZ8W)wrBb7FFZmR3+~R;X>&G~Q3Be=ve`Yk2Hojj6Zq(7<4oxW~4GWlAQUNJsKv z&w+NZTuo(en0C+x1GF?i=HC$drmUN8(CQ`aX9|0XxIvwVr?1?%u6QQ9li)E#_p@Ox zPJ`vE?*dYf2xmfPC=k@HC?AGyi5@96pL-+3ZD{?sdc10LkX1QVdf=tRxioDtXsh!V zl~_i7nFVHqRMOBfdQ+(&4%}cY-)J+XRxct^q(pym0yFk%%XbFHjnW?lQ7%e4JNnRgnx+2T1N6i9N*Q8q+uRwQ#Ot2(Nr{)L7PnN?|N~Nek zpAxBj#tfMXG?;3k5Z21^x^Q(HbK`fD4KpX@!>a`>!za zpCS^22MQ^f0hduBjiH<@nD41nVAXvo3Ng%yXSxs&{HC<-)tfWZZ6eczGd_jzW=hNR z;vrb8yY5{v*Gch&kpAu|ubU&FSgMae7R$wn0Y60w>QX>kTe40K-iV4J6FpjiaJxe= zHoek^5l{Chma_9peS%yMqq!!f9EW>q(V3*qpRw)`B0*=@aDVolGG(%V>yRgi#o?yC zVl0cOH0`*KOzKG$F#o-S4HXPeAkOB7KzMi$jdODAJY3J~+;xxN7Y<|4%Oso)z=dy? zmhr?`N@G>21_A3vsx>O=3S<)l?aPm?WMm}SmNm&>t~?s7y8&w4eiuzXgvq_>}0r-pycX#f6D2 z+W{)4X_2@PBn>9rMz?i(cra@N`lOr2BuGden>cxeMMP+=qxZ)0Il`t6ALM#xZ}`KW zdueJ$PNNs4Q|l|vL>%h4%I0V!aG+}lM_F>z%?( zg7m7R_3$vVm;9MkdG$uvi@lAk3n-)q2;XW9n~`q|WkPuczm_FX)Xm*YxwD}5DHy5t z^K~GWr-cunSh)E_+g837>?OBv`pc&?<1p52|y?du*JncSlnhL1Zq@l|mtL z2U2Gu0_8--vP|ZJdW4J!sWaz#C0-iRU`$%PQ2)cCa`3>c?J7KK`4McSsD?danB`^$ z@*bPX3Zs#@=14fx0s?-2Ffr-wiN zf^Er$n{YA^T{~4^LLZbH^hX$~G5x$*+etwC-JcTz;p9pa);8*qWO~2i^#1$7?_M?w z+Gto-BVj&Mjb~grjFw3jl!_ z+g4YAs&64(nts7L2O6x~7xkQ;umAiL(8xUqS*NTyWMCxqz5F`9 zvziqPTdRleG!L5clVU}xf-RgrgjPJ!G9s5gr0{AhlwoU+Ad+p@&rF8PfRbQjhU}F- zwC2^pdN)P9RFy#h`Ns?A>i&J~Mb0m2aZ0BjTXKsybf7z2-VJG)44oE(g`2jCWcy3V z{Hch^#w4_461I%9Z`$vgNDh{I@ac`@!2-~Uw}R>zkM%)+SINd_u-v>eSw;aOdkY$E zrY+zvgbj76{VQl69^?^=FeoDX1ssRKkd7}9op155Dd+?m4_*xbgaK!+3`XEKh8eJE z1bIt|ZXZn=j@pG7cr`JkO(wm08YF&#T_!FpYJyd%4~7#B4Oeb8H}HM?kO(E> z3P!gxT+zKNduDP$S;R@~ql*T{0?x#aOzU4g%(`Ba7?E-8n?K$04+oe2w z%Hn9&Z0qwUpftLcV@(e27AZ4x)%=`$5u=lkUqruQ;8Y&UN(3q$yRx?LBYuo|h|bWt z+vc#AQ;PH?XFY6^p|oEgwzywO&pX4{2#I;efuf!Sub`K45~Jc{?10%y4}Id6XtQ|x zYl}@T=7eJ3m1vPVrbkZ_hyGw=Xe{p+ONtWQ#~~y3QiRX*#sVW|ohQ|}uqQ(BQ?}Th zvn!nleIVhq_CNZE_cyyfsoB>?GI^vIbw47uAuoHqE&0k!GmIohpOQT)%KAtAW(%AS~BN; z#M1XGcALv9*en8z(dKBRp{LrT&#?BMUj)FQ>>YlIkI+vKpZVU))V0LE(wRj}Ec*OE`{N);>)03#>SDYjO zC}jbf3_FJjYK|Fy)(2shDsIO^=2M~5z2lr-$ne!V7Cg?gyWiL6GB{zCEL<{sP&;9@ zhEkS;Hyo9$K9bC(*Vo-Uj4X#Sd@E~Emh4tVx^q_gk|caZY9C!;-**|c$V<9&S^6Kj zeH9r7cQ~Q!K7E2)U}CE>ily|v6Xk7e0+%kzjWdd-j7d7#v@;5(?EXQ*OIo5^Etvp$ z_(ayAbizv~S&co)J=v{d!iy*6EsM05B#NOUN{6&bHkpkR3M#pMEZOyJI5N8I%cqRv=8dGm4d%(0VRZi#%V9Ehv>kBm=DNNPy%7&n-0d` z-r$Am-pp9OeOE}Du+Wt;?x6p+(NAZfZp#Q^#_nKlF#{SzAh-JvI^_;2l@zF6nJXi; z0BnF5ae}=ocbHBEg`V6X*R&8<#=OYT=TPqdS#EIe9BoK(he}16^aGExZuj?Y7r1-S zvw<2?tRZD79=GN2O+z6}4`wdNO_-LOc0TBh{|ejxS}1M&*^wR0*Z+?2Kd9EC|3mfq z471(l$3W0SYdNx;ip~QtIPU#lXACg-;5!@RCEa+lKxz{cUlRca`Fqu%PPYI8AF}^( zzQZnim=X0AItf+AXY#y_&JD+HB2LoHRv7&D#o2*CVmkd+SEClNafRjvIov-1gYPC- zwhUm2&lTd%KOCv@i2_#yy*U^q?PSakaC6Jf!a2;s-qzotcC!R-cl*%b!wWS0p?G7$ zKQ;UVY#f?g(BhHhKTwLqu>g*)b(EhTL06P}{DuP^1hYc}?_;9>huZhqtSZd^OYX{l zWO);~2f02_19-Su;~gzN1YWB9Z97zVry_#?bG!SU68?Yv*!hpEPt-f88yqzxMMMP! zc86)W8;RlAeh+5s*`b4#Pa`;=ABJruAr1boB(?SbS%LhKX|B{Ew5f3}$aYkvuf7=d4=)!$NyFFE9FN;ThJd9g+C^G6co@MrlWQ&17UhrvOsPIJxu}s2`}oq z_`ky2nEas14Du%0+wzCm-*a|AAU>G{_*l`p(E{u9`51QopWhbm>i-Jw%=;f(*=(Ks zivBBOXU~ZMgayDg_)jo?*}1~~hiXNy^7j7?-rO(;9)s`v{_BBTjc>oRpvYFg5#~eOi>Y2}@Hh3H{?0=^^(;GCM z(X5B*92R11F7$$$1naFSY@?zHmHW7ST1V{oP#rBU%!goxq|;R@(Vqy6a!y@!14kPa z!4?%F(Feedy!@kfG~4Sq?uF44&jm@`RkR*W@#y4jUMXa;P6>POjAM@E?ga`ABhUp6us3mY`w%9v|K5v^XLhf^Nee|g6ESbry%j$#oRP|fX?I&9L^s)*wf zLeOkx2MWS;Tc9w0dGP5Tao;7>)<5r0L-}0Zp>}AzDtzL2H({2(|3QS_#3i@Qot8D- zZrj#@j-1^7l4ziH;<&OdLh0YTdndE)o<7K~k5uh!GE~Cc8rzUMX&KV*YU%*s(ogku zJv?6&F!Z)_O>Lz4*(&C!cWabBFQ5IEn`s`;b;%gAbq#5We}d%keAv_$#gb6Rjj4?f^Sy2x_SQ!onosXjYO>;+oIX%~hJ7VRZ#OKPXH4Ex) zA`WwCo+l;(z>+|+r?0}5z)6hh%v9J^=kInl2vGO-^aOCu2vojBpb4yMJOejaaL-lzC)at=?roVDPWPb!=ckgYbJIPliH>O2XPMvmft}kU+qZR@*U&VnOcLcpiWM44wL@SMu9H9 z#*mEA@uRhOR5L}Ra?RA)K2`UDRz0ZSMWUu@`NoUn2EnYu)N%G|?hg>jU*U&1rVde)qr|EcMa!{}ZVm$XvMxG&Ov zlR%0W>=z9tb;hs2ng=OLEB>jvGvXEvCTy~$y`*w3vn#Z*4#q}yG%Y@*?bE?P_gQqN zT8o$Mbe)=S>Jwy=zVqq z?dHEuq-gG$xisjGQFv{w!5WG>uu)Yq-EmiSj4(6jmbrBJs+O~K`C7_Xd4`%~$?h97 z)|esGHJjI>J(U-Eq%BW8jPS&63d0PMR{PWE2Uh7dgE`m(`lS%s2UA3ca^a`Hcvzn* zNBM83%_H6r&T4i;%6z<6Fe0@`0Pt5?Vq1`h_aVx12Bh{D##lUcaEMo}^fZA6Kr(rt zd?;%v;hx(uMK)%#&SIKL!QHBGvd(TkE3%3`x$2dGnjAIyMlt@G(0rO}EdF&k%Q)d4 z_PFlk$5lF1{N;=sIg3ej+s0YX6C%DyK_O6CpP zwVy7SJV13YR#Rc4q)yrM$mf!5H*W70 z&oyN?3+e-OhU+?BT#%Ww1^xpS@?t%-&_(aiE9Z+FNKo`QkYDKh;HU3#X&LK2 zv}HB+@Z1~LCaHvgzi-wk>$wju-gMvRSQ1YNF!_t|adcjEGoeo(KKS0E#zz4*XOF_V zWpx_C@c^>b5d6<^r!yx^@TUrW>*u($8VbIv>(i;1-S!yJsn;f`s7Ajy+C#S*Qg+v} zs(z9AIqx*sCI%LkBRr2DPpZ%zkBlpu_F2c)Evj2JR9tjuBMyyQn)bEF-UfB-gNyJQ zqEgdT9O4l8kl(A$Q9st}`(J2zs(f7uq%JIpXmA2(RJQwU$!(k#_93`qwLQehY+iPn zlQ?|_Pd|NAIF}oshv*IW3QbZN_mmIe+sDH?Z^QWfw6~)}Rgd6#Cd7{5Z&w(iQ#s%A z#niU*yyhc1`+~V>Y(GL#^Vkfwi8chgI)$efM7CFnq)|jMP;b`R)1)3|@X#LRv!d9p z5dB_NllHGS=EdzvOn{Vy`aaqWd8rKiQbkym=BnH4_^(l`^2R-H6Akl|N%TOiNUxzy z-OCPb<1T5NP~F$$tfo`H*Fr6JUz*P`JlJBTq^JPda;~qwgp37V^2kRH031oNwOX+x zel+E2VGl8}^8B#*5b^`DBtaE1WcR}0Fcop+U{x*yv3y@-@uZe?M+;>0C^T>K)+q5{ zR9+Gp-!W}mCss-YF>Xx<1GsGx_(aeaBxO4|9kC?6S0A2L!kuY-*M1<<`@3?^7>E%|jk)|W^Jb}Z0Dc7b5)UonFPX89# z+V31AUp|uj{%6xH4}EUhd!ul;y^y6v$zNZ zBfLf;O`!>CInxTZaa^O#CkqI2-_SQT$0cu8eZG@oYenhiN& zg*uce>4B=@qf!aUXX+QUq=FHbXp zw25$0R@2~TGggc`_Y>NE135yf& z!-NkoFBC-##co%}w2=Etm7w%-;)^RezTt(Q`iUK-6pLtZ@7hieyy0xJFLsF-%&p2s zC9Do!2cc$k%{hD|tZfUl)~Wt#i9Rob%1^wnWPpwJJ^JCk?kmq;3NkkNyL~0~rEXfd ztl8e%G682Fc}3%%gfN0UBR)1+Ai~<0_&k1u^A7~=H|XbmVX2vp$DpZtLBmb8vy_7Tse~@XK$S zhy@A|@rQqnwy+Mjz)UG&L0qkBlvpqN!}Goagr%085NPaP+j^G$C_rXs3;i~UqcbSk zp_@Pg9!r8AgiZ%pLFNNibHt;uHcY0w$>3KGIM1?jl3-(weJiSx%AAWs(wB+Ww%N@dFKTG)(G5#Be&?wud zx;dx9;(ubN&Jt0N z$-#YG>hi9lutGwqcb*VMt*XXU{_YJ^U+5P;e8-0spbQo~bx%8+F!E&vzgo?hLqms16A~d3m-A6G}8#G-lK5}%%)(GyZ!X1DJ1e8MKuZd$@c8A zX)KH~(n#cpdU-yO2hyxqeZ;cclROoq41cO9;JWya2PO~%Ht}Zs*8<(9@!VnfmB}kN zho-{<8HgOJ8T%)Qx7%AQUJvOlM$T~KgC!4wu>*5O=O0AO!cgEAItdG52n6>%l0f^` zL((OzRLgCy!Pas^qwoQvYV~{5_f>qpCzee?c$Cl+ZwL+2Ao!H^^>|_+0*>in;^vWCr=v_sLDE)tt=qP29kMBOYF7xo^flY&Wuf2m z0}O(2p$9F#w9ARS}9jGCYf_%&~&-Sx53YaHPZy;A3=RHCvvQ|G?0e@=%y;z9f68J=n{b+ZE43gf7XZY(^8}`h2}NV`ySY5j;qn8|r)R zps|hPDqz4ft^&KQXwlvo|2H)R)c1DrbOJ}t18}Z(l{Pw=+`n6#?p@4HrC*fon4~RY zAAj~}styT%zNn5~qKR5ITo#bU6vuZt{DFr-8%rqja(L_*$pzAsP}PD~H#a0Eo=2WR zn(oLwAOfzVAth`_OK!(2-CD)r?wMXr{=i5sJ9`W)4Robd9yL9E;!kfxAvt07Gh9m; z*>U}IY%VraO4{RPW^d5BCz=syA_!yB5pyOTQd! zf1UN7MfXD?@?AcrTqz%sPvSUtA@|{zJ2zsfbSawa$SX!EL2>|}C2i^>cxyPSz8+zt1_YGyw1g#Pk3xS1!ft;rrDLJX0 z|8URUx4D}A5gcKDd*_HfLzR&fg#gm#;)>AYlA`xfS?%A)%rqX8! zizj~L=wFGD7SO{O-ljO)Kqc;$phzVMjrx{$A;#u>p{x%r-iza_u4;!Q*xqh*7T&#X zFkh@#8|s=X$)$E3;p0f3V)-30suQ0j)|4Ujd!dcdW$S~Td8>i2UJ>c~Z*!>dJ zaV7GkCTZFXCu{YZyT4cP_5Zm(_{MykynYs|b>ozKv8%kYs7O@*6fciQ)+s(A>WZ1V zMt*h^)9iyzM^f=VOW(c^u33gmaM=5O~9Uf^Cxl z=a1Ma*Vg8?o*}-LuMAN0doxvVU3t@48IEvS^jL&Y)noj7p&a-X`j(-noEtROQF_Ve z=#8FBoO4p{Ov~w9*x_yeow2Ei=`Be%bRaop2<*`Qx&4YHXT)ju+{|mb2g+d)&b2dA zwRz9jXFyR;%Be9vHXjqLMS=jvsmhW6Lcp`Ky&`MS`LXyIYO+Yv3!&$hxd>k^afW=q zcR5=XCz+e|vBJMJ(ds#p>aukO02B7DY5QL$-LtDVb}hN`*g1o&215 zbfFFVrfvehjgWz7e%$W8C1}7Q3?mgOi9p$f@t<_~T}q_=ufOx|LV-NV7ZqGWVf9kg zI~GZ+4r(@MsS>*fJ-CSosuQuG9S$`%_QG*KR3))?`K1#dALcM-N*4CQqG|`kv_<-w z;EwsVIuG(ts4NZJBe{Yb!S@tc0T-Rd!Wx*3M7)cscw{QuxEOT&F{XuiksN~wJpd*J zRbyxk{Hoh5!=m29zOEer^E^BBTM;7MOgEGxCS*|Z{-poP-VOKDJrSgH@jTOC1|~g{ z-kwy(ah1QN9Ce=b2Ssq+aF>D{3gfhPT6@(E&8mGO;nkx;bOB(?;a$Ql;+@;Nz) zE|RA!dgz3C6T|M~!+0I%>vO;}4M9l|wb|UmY zSZiawl#6uKM9{{;vZxepQJKOA7b-i1t;Y5VhJiitApt2gw551QHXqzi?fqmZMRnj% z6t6)GmPLaxAJGQe?ew*zy}vhoc(Yt~Bl9S5H5(6OT86T8Qkt82W(0>aHC!D?V04^E zirT0?lz(M3cqXTytw3lVSyb7%l4-LCQ8;{6x_LU-r#|Cv51$Ey-W8PUi`v`cpe@YS z8GVR$0;NcL+tX+gAn+U@4%#(B{3TmezX=);ks(cl6bw)uO<$EMPwe{X-k{Y9rvh4n zw#6uWMhVLK?IWiQ#pfE}dnkj1J4B=-6MM{3 z4x3M?4~S(vXTnkRQdiSO(OD}qN-bpNP}Q^2PksmGlv^#*{~)>0+Je@#{g6Dk6s~-q zOfKIBznI2CE=e_Autv;ELy;Qo#XIt-S}AQN=%t_adRu9*+dULDL8$4eoWXgCajCSl z8Gy0N_&-@>0G$vtCcNQpeQC$a2b7QBtSB` zVvwg7b&2i)qBJ6y`2`2-gbITee>Kf5FEJP6SR^8eX3QNeuO;VIgt_$b)nw6? zSUQht6^%U)w{C~&4>m`Tp4E*i=S1yh#EFRN#>iGvcL|*fpS~!BNhDQE%-i8Rz2DW9 zX2Z`)py8}3mHWVHKTU!(JncvCoc=943)u$x3S)0q1!l&WwlcK1`LXonz{{s%>Cl`$ ze{di{SOyJf_4UdX`?)fi6iN-ksN9FZ<|XzQi^TCP5K4xLri4lb*A8_hT^?0vMg7YQ z_nmt^vQF@Ee&(3V9Oh?zQ2OvVwobTq25`((4rgQHoLJ+8mJUhf8%DoJ%qrO~h{~Pq zZ|T90ZLK76+^DR;c375%zPV+dIv$>(Tid?uCOEB_Ci-)FkI-Ho9-g4b1|Y*9@LWNT zI{7P~DU$Nre9~8Qj-2h1&+Pq!(R`V>h1jQprirO@WxilvvnDu*Nh|M}2XU$37T|SC zU!I}i-Z-l4^{ja$Y~!erI~cdRtoX!eIGH2x^zv0aWbfLDkA=tQT5-2{!|`$!4eC{C zpLk%0{Gv!Ys>ltzHtBg;t94Hax8jp55MfJJonXl(RBPbf8H0FbfI^G-nWv}&tA z!4IT#Q;LrDKqbuGO$a9K(|vzI_!4{(b2B_=>6bEL63p>LC5%2i5O4*xd#uq?|N`?A+3Ht*y`piTum(!MU3h%5EYV zyHEsHW-T|5<4U+Zi+=_+~3YM6eDyyPoc)6lH$$6KV)XQ^ArodvU%^O{ed z7c~;f1@<^Qc`L!|H}1?VkI}*{+^1B|5{s8oPO{}GvAaf2{&#|96UxHrsawcXie(dq zDh$fZ?8G6k6|;M)TSyM=uAvNod!*Vtz7hLdcIN{O(`8CH{;8p}7O7UhdUNmhNL>?i-{7Txo4QAd3sL4;m)*=vMvrY2}WZi9Z!>E zGIcXg_^v zKt2U9a=3x4I9p2geluC}+|<%0*r-}%Zl9C4Rb}2lGXVN&WA$i|a!p-q{(4@KEi7BL zqz@z!XKm%HWEL)X3S{NXYr!nieSq>OuNZ?NAHRAjwsG~Hsw9oHCAW0?PVqdR5fkAX zevM>gU&QfB=5-lwQtZW{ohC=PC58`X`qI_w{im z&ih%FxTVAh=+2~$^-Gz9f)LL=DcB-SJ7N_i!stA2s@mPL<;Y&--d6#60PH*Lc`TGh zh!tc5PytubL-4WCF_=Dl8S4Ne^R#2orOsE8qeuCy={c8Ex<|@2@~3A zRb(cLMAh4yQ96(G<{%?H&~Nc(dji%W zibGUNhz<|iGTW@q{{(70$4%oZ$4!Ha77N#+aGc&w+%z^}YJr+u6?9Rer3Fe`1oK8* zGG*V}`!LWTHbHtHK!YG?5ac6ZrPveyfg=5Rose8oU)WJ0|1a8~}|&rgBw0k5UplY5*uy94a1iY7Z@TlBOaF zVu-jJbXQUc-_{h;iTyY;5%p62&^D6N4yqq*otB(_6o``tFF>+;aDtt1q!F9WNa#m= zXfO$S6{Opx1L*5l642n!krc}x9D2<7-;u?i$)4&qp)w4kd$t-vUzrf78lSEYwKjx8 z$y?$I_C&$xKrT8#p~b+QMgmo zl-93kJtP`;r@(ws=WEW~l!+8q@o{l*gGR(E+^vNqX4v^jaBgVsJ+G%V;_BUfkAoT= znOCy!Y%6vQ$3$iKdQkOShnv*KXApB)9_9uv@Pz(|G4hOKaDFxmmqrSOy21oh1WQBRWzDGF8lFV~Ykbgpu|!hEB!huZD;A>*^bo#t7* z3?jveacx&5(uG9ZM@9Jb4#Hd%;j{%lDcqLp%m_cBKPp53dP(>n;3VcfL72hNL3v!D zIVd?2>{oYuO|=wtlVXkD2R@SQdTZVy>@wA=)MyX>A{@?zZ-;iao0KM{CBmHE!NtX2 zM6mXzu;*f>wZhS_ov_I|Rn>nEx;Vvn*GBVq;?l@c4LF$$0H z=C{HlqTt6Rfl$SpC5QXg=6*Ey`5<>|k=7662XMtSRJFzR*0@C*Aju@;?()oy2j;pM zV16C}2Ky5Cw$M=Q>G}bX!4W_XX+RDOAcx}sIV6DmUT}d(W^j|#D6FwYBqTbzECeCP z{B`V6-i`O}QWhkHZ`;bi;r6pg8+H%hzaqX6*YkkHozHT+I7?OTB;X>EE9b|NhLF_xTn-b_gi5D=V6@ z+Ilz69j#K`ok8Lzg_fz8wpek69i7UL6nn$i^daAI<7EZsRp+-r{`eJ8&Ecf=C~0om2D<(;F%Z?W7OF@ccP4>@z>br zxsgBV*&iy%ee3g`^AkKB0!#SKkFSg&Q@QCr7ZENs2tx=~JG={dE}5n5CR`*RUfyjK zX(%GlMDzuqKk*+y$FLAwQe_Tf7;!zm6qB`@o6RHuSI{vxdp={}JlGAD|Ayw&<<%e1 z$a!Y`0qqbh66{skG!x0%Krvzw(y#`_*=)=L!KrySVt5o}>0keYU&eF<8ig}`CE6pB z_G8V(eU;G4d-&y-!JN~17APHt4>aUj;M0s z4$fN-riXNUB`Ye<(!bWTqKzy-TQ#jl%r6GdW2I z!zT`=m`bL)JFt=-kf=i#^GMs>7S{zU$epU6)=O}_FM(g>^kY8%JFRq-S+1~MapreL8qHy%X> zZZ-(HNa2zBV={i|RpvYxh18uvSnpF4B(^VhKQfft?~J915Po49y@QI!4NYt;?7lXp zzPOq;hwmi)ozGT0hjAG1a!{sN%3iz(;$TDQ3jFoZ?c5gEjt{@sMmamgUOe9(Yf0p^ zp0ggt(aQ{T$-e^ZzWW-!F%xf?OOB}&=%-T1{~u1y9Xkk7lS!;cRe6>jfwG~28amuI zrMkZBj@Yi(<5%>JE_efohy-@s1AY}34ZNI0+Y-KFK*RR7wj*peD%fD$0&G$q@PUuD z%^jP8%Nq#ex8@S(o#*flAe61Z9nx9|$FO9KE{X%RSO9fiy9cjDJmCOO47~th>+1wz zW55FlR}SGS%7GE~LTVHzXZLT2rwMk2f{^X(J}QlUu&yCE5MQziUfkK>EmET zaVN@>2cMzf9({3VTfyRIp<1=RI{1Rn$9m7hB$ZP_=i%742$kUDgRlT?vK+1Tj&5YXI{ zD_dENLS-`g3tGxdw^YsGgL>S$n(q9^v7e1w<RCaTk9S2h`2_Gp`v*bc+h6S@b1V6Yh2PHb zZd$fQuTEzH@k>bmlg%Y_kq9nSNCY<}q2q5oh7_X|0o$EBT%Qp{CFv@UTobtDz{3aPg?D5qW*YXX!&Uqt4JtaFb37`WN zB-nl0a$Pn8t_ms)p+mymVxvYnrl3172L6i~K3fW}-wzU@`wEVAsVhrKO7?Ob+~8RA zs2^_dq}$d-P>i4#i12JD;w5bmxfp&#$k02pP&)>ImgkE0Zj zXSPqY`~%J_8fkWhJfghp3brFBMrz#An-``WG34#wzrc{9xIG`&3|dce9Q$uq{L9#8 zc7XhLv~~II3X})5ugl2G2n7vP7*CHe{FwrfSu9uSc0ED-DhMwDgd6Z)IFzo@$6ndv z5s)55u*p{Z*0*?k0xm;)_WWAVnUY5TGYtz`L>lcq9b(xGx<=ZEyF;|mqFhguj}fP~ z^PPw&7s4-NBa0|;>OwvNpC1Dz-Ei<{*KosHPN3q~o10B8Kxa7jSR(~irG8B{#DEN9Usp=CD0 ztOrpwXfA$P>U-X)%TggoMsq>u-2r$P6Y$f}#uofy@_0;Db7Y2+{3~!B2v%7U56Ym*Rm^Fpfv3`m()BJzaJKQ zm$>HIq#~wU32T=+ZJstc5+6RV2upHA%bIIUl zq{30n0mn>o6gjcu3DkgV?JAo{1uXnM!AO#qLTAL+HW0-A2e{%y)(ihU2VQJs;NwFT zngaP3Zwtttv;s597f8+Bvgl*nUIY{L@nZUf0$h-173(b*WCD{P{s<}o%J0JDBg&Oy z;LSJzuf&_{sO5}kS{-{U?>AA>(UqLETT?LSlcsH%7RNm`-tu=0 zf16=0x#m6L2e{!5_a~ghEt*U6ks@cNA%QC6Q4IdgDajCv$K<&RkAg*guiodoKD-;f zAEvNJ{2Y(9FUPbm8(4ZSIvdr$O@W9%BS$W<%h8+HMx@altRQ#eu6IR+QOR$9e2Ybe z0sc90HdGjD>$`w;v#dUTXsxWYK z547P}MObhb3P9b{8#53|-TOCGnaQu?NmML?(S@O!}qFtd3Xmacd!@VQDbvC+LE!cpTwB3!Z2|H8DrXE z$SfuGwO=MVGE4uSkXdjyXMKYE4qlfD&QL9FVz}R=S&B0jhbskBSu0h7I_|9tQ&lhP zloa`>4n=?)4Y0i;2Q3eIohZaG&VJTO4s{$4q@!1><93BFokOAv z(tQv+Oy9O7lxG})5?Tg1sf=kb!wF3<#{1-t$KhUT`q(nNY+!AbE$X{0T~-{&pUtuG zPyQ9{0-nC2>BnH%tI(OZ#+BuM@3}j7NjYBfU}pnGXbxHg7zsG9vIv)c9*MTW^_y!P zG}#>gh2n-Jp%=07ArPO?JgcDm&0=6Q8Oqx#V@3b3JL5Zp$_!NdRe*8@M z?~0+*UT_=5L|4V1&~w-N;``yU>FH3u_<;nqiPbaZ;~U9OFs7c-zHNxNbhl0qNqUBb zrH^JJ6`~0>;WRrvBWOcaQ|%WlIPPvZ-W)oK*BfdR-4~ELA~pRM1vGWotGbdXaLQi2 zTgi6|k6=P)4Xr}0?oWLuCVK9XSw9u60!2TURZHzpNb_U{NY3~UlZ^J_-u$%@9%wO{ z;cuBKX6vnygQtDWJaP^hj^+=400#{Hfg?Qo8{r}nN)KsI;%~Y5TPb}r1#@}lr5l`n zZo|=F^fTFgiG9vY5ydYDN7mCiJf7?Hm8`kDsyPG~yN22%_dwsF|KPa$~R`lIx%PY7GhOwU(|mO^gJPdjWP}uLSe@G*om&FD7xPM6;U`957&z5nDtHI zQT$^HG?KD+?IHDdRqg#J zK&=GogIdw5z&SjiRdrNJsT*b%G@c0N=ii#9bX+>|Y?s)ht zAmswB=KKBEe&ie^a5~0yNcKK^&%M@MbImo^TyxDi7u7g2ZGI!aH0@r^ z)xBUea|iQ-XNN_iA^3H0m^U4`&iwyV#)6vCmVVMfX~OvyFkr5|mm&4?1OmDVI+H#6r(n(zU@I>c7GIWOx|u%?|hDBYsT0TP`%UCTweq?f_>3 z&$p4Xl&Ey|A%}YZfF>d1rNVFTn3_We$T`!U^avv~Hq@zm3vp89_(xuAFdNTJqoG38 z0$H8hzpnqv@5(5jp>UiodTi?Oru%V`U>_RSPNRXmPE5AlCv)Su&wovYrPA9I*!$&t zFNtGYzkQA|vk5Inc!2N~$Qr}zW_Wg-B3Xsrjj{g-d!zgZbDqwTcoE6x~W}#=5IM?jJKJ2GE62)?U*m~ zyU{J>l>1D)k9BIVG|Dd{XOhqQkGQO(~43)-ss zgIG@R!(@M`92OfqXIIApo~N~!&s5C3SwlWB^PSmye4K`AD5?zijTb~|D!n3n=Wcgk zpVs&V?jNBhm3wde2>RfMsg?5@tA|Y1d9J5K5R?6Gkla^MKc<_J7f1;OXue!bz3;aWLdp%HlP;(gfSd{61T z8$_}f7xHKw^CTRyTm8UfQ(fXzmm-OrYMe;gol#|2%bl4+t;8;;x|WgdTvtirrJDXE zT&m_zVNId#_)~Zy|HkC=Yn1-v+7A}m-@(;H=dw$WSAal~Mc7X}4+>d^bJ3FDFpp;( z1ce;;$FJ?D&l1(dV8pLZ&Mwc1a|qwAB=O{B$=RHlI|%CQ*Llg=qsd#%N*+7h4rW{i zql$yF5sP;1NELgk#W$!Scyj?nK>sis3B%1Qq|1JVy~k`Wo2}~6F}O9{60HpFTf>>z zBG~VE`|+@Fz9)5&d8`&zQ?R*ie7f7-&5q&sm@bQ zoo{KV$o?mt2mBwwVZeO7kw)dG74j1mav9JwkNSF+UVqP&LWgg<17x^XQJ<3Y#0Q`R z1oO3BU8rRal|A&={VeZh7R}f#Db;ihRp;vYf505dwk3Qd7Y*)zns>@g-+apJyLP-bZ)lCtJ(tKm|)3X+KEbM+ftMXt(d_a^BZ=`+kIZUwO3mjU6x6 zq}wYQKX&CKjbwQ%3IRQb`t84FN`Vah#{PFU`Pq8PIYRUw?TEY+ZASslw4O2drN{2}!Iam5uk~_O`;6jB*PA0f8 z(lnhX{^AYpl&n|b*4%BRXs8&^-C?qBYTB#ih1IwoIis$#*131q8OP9t`od~##dwPJ zdX=S5u1egjj!mbx2Fl_gAhP;iy&@|daIim;DA$hlr@+r1+-H_kcbNj-($wtCLoOO| zW^5tst_}A1ra)MVe{^+Q`+~w6iP?B52r4n7zo5#1v)*)L3xGUiB{rIlLnB!T$6~kK zKni#?BfGIZIoos=BlZ0`PUuzq+&6?dH zz%v1q;#yC8>Bi3MiDTIzQeLG81b2GY1Ub34MR!Us<5OaKJ$t`3Hw~3BJ}S*u1*jCN zhSmH`UGD9d937$4(h;%%7eYy@QfRYyS9ld_;W_{ZY%;yKCnm~HvdhYQF6LvEny&Q_ zt|Gjw5LBXpHzGW4m#JiZH+VWadtIY7b?5llM3qPbUB2B;IIoy^e zFS`a^zi%7*yVnk<*&1~5Z)j98)#aqh!|{6bak!n`&u|=$(zr&;b^MrSBx8 zIAr#xH^14HX7?DH@Vl`C;}X`H`D$YDJ~N+F2KM+Wa$pLC~0O$!zA6st|q! z@ZHWQ;rY;gL-=@B<$p9kz-L5O@Xv+tMcu<6NssjQhu?2|sN42?_6hk)(bY>UQDn3> zsL>{ncRK{Turr-w>?IFKb}qh>Mur^zvRz8436F_H58Azw8}L9#yzlFqzjIl^g}dm1 zK4I!p$U)awzwlxhtg%4j`=+7X9&3(0tTQ@;IrfJ@cZvQF2f^Yr;&hcE(a$`6RDu73 z$_NDhML;t?2bk_=x;V$oLlPDxD4}Pxl96U(k5oRAz+~Y_2EK+td(!CLvV!j$!pFOZ_xTGoXI_7Ma6Z!BSdkHH-E9SlmQ{l|^(JMb!*UZcr9w-}d4uDZ>`& z&0vH)gW_}_K2%}OHgC(U9YlY!+&av1OVhKL;}oRGud20VO}Ta0_$s(}-H%W;BW(t4 z!0q*|z|QUI1A%_X3eZ@s3OM35bhM4vN*((tkHBS+370A`;w3yjT?~bC0bUBAx45~%6cay%O3gB|7R*zh2xgvN=ytwL znk|0tr}VkFL!X7+q{pmN@tp55E21^~tlqdgonZ1CWvp)uf6Q@3E!juy`3K-CEBZ4N zFJk6n^*EDwj(g6Jgdy??^;i+}^ol*I#HtUwJr;I*ETh}&we;>~E76>0N3(n+(Fo*y+f^TPW6HMvb<%Mb~SiSOR6kWfC)F&utpW>(xpRIb@S>4_RT=J;SQe z`p_<3tdkj-@qc|e7P;tCPIM(T6gyJ)hG1dO0wq@`nMJoa@2gA%@jl7>29mHY*-HLM=^<(M;NMRV#%laZWQAJQUv&KL44%szTq?0soo~&Q zymc?T7R0Mj&xt=dNe`}xBdF4?yuo}Mtj{s^ye4H7v1B~NszyBgS1_eVkb4c)_=_89SZqig{&El~y# z!|020w*$&l988>3F{?P9Yt1UQ4yO9q3my!MKEyOAR7?ZmhqU%h4}rG%Kr-5Qk8f27 zzalI6z9D=Z`0nXPPkV;_zL;UOCXtlvft@1Nv+JXvf4%Yjb@=7oz>9t*VGV>F1~tHP zh5o?GFetcJU;{A|-Nkmazn54^!q}Jv8qDu)Bb%SQVJep=_mX=wbKOW7lEZ8ZlM2H#RPa6|_&zef(Ewlb? z+TUzO3WDqy?U&-^wO!asIQ z_>lY3`FluxfLNwKSZ4dO>92Q>-(L;tCDUI^5b*z-{q^1B^;a5wd&~&vdz+*;Lh0D@ z=I!YLe0f&z%R~6Qtl+1I@Y|RLj*m}O2)`mL_`V^0JS+H*?hV>I;+XJ9<)5(5{XQ9hbezN|aqDyTN*hrw)R(1_}`mBQ8D9nd-nqr z!>NQk{elIh6~hh*s(`&+4TGK0k8YmzcV(YRsjPrjvOo4brcv2+v>e8#E?4yAW@5FSdv+>@*|ZpYEaIiws#? z*?)dQ1RvrXeqXvl3VO!y%h0#d`b+tuG_YEx^&)n{q@?}`vXI>CKzyoMFCWqVvoqRH zL{579@6BvK8fegd-c(bM8vks^gCcz3523K2M^!tUf48c#yvOA%B^no%65-?yQ2rJ&Y`;z6szfSj8U}x9VkGezkB|!Zfwb()8&AlqomYc@u|_ zPf~8Kd8^ge4KG0koJOvgNpg^%d}|e!0K1X4q`#X%pVy zjouas0dMqPo`Lf1pwJ}}jvT*QFOqDW|8Qr#DNl^Vm^fQF-aV1St<6wuO%$}5mx9B- zx@Zc30a%;7g_YhKe%K^Hz0`kVLt{1y`x|W5#o=i<>}yo@rM=zm|)UADf#} zCwUECKkOF(1OKy2;3UVJn=-bJm?MAw!!L~S)fH4<68n$F-#p6_P zUH&F4hcB!r-{1LIy<>K^O)lE++GCV8Y)^cgzq?26W~b6*+Dcsgg$8ArGpg1wK3n7C zDNX}0*;cq5jEJ(9DSv`c0-_;+t% z7tmNMjnP5<=hIgLVh_z?sO{Fpghy@7jHbkYNy(Zk(}B7J}6NPU3Bqw`Pta#oJN zx9`4m3kcv=V4oI0g9wxdpb2XJaLz~mFS+lcn|v!Z0qsY4NL6-+?lKdgb_TD?I8~x8 zW>jcTG0f1W-KL$)#jWu^^G~UqU!TXn{7Ug~5YX^-e620sw)Z}vlUDgFkXowt`#dLI zjWX!#NVrYT@R7;Gxz6a3{UgyglZQFvcU|O#zxRIAI+Wa$pFG@?rxqR=gOiNW#Fy(? zo0E41`<{J`z{A}ix$xzmQ5^bE4-=1D`2l>i&SWKwpXJ1~k}(c^0-W*tsX0#GWgA9Z z)_LU^W)hSs2`eM-C-M#{vSCF3&YZ3je~$DgLGxup>X17~jn}d@v<4`Z1`L0|OGdY( z)pObk*Qefik?_9fOnquJz3c2=Mh&fYCgT{^C12=(v%6?{io%o-Od36xQm$RC)avf- zs-n%#m49VxVzWkU)7tb}yUH{A0*%d2-rtZDFEFur?&&lkoRp3(UnW@-Hv1u3Q&fIl zKZeKT2KlDmiBz#;Wt!?^ z=Vyr1OInOL4Tb5y?v!G>nIe&=t&*p7)WhSb4et9D4YixkzA;#(FZwRO6C3Tu^&J!C z51!cAQ7=UhLjUI0FZ7C3x5M>ha)W&n9>MX(Wht4k4tQ9P7@pbSR}}8|5XbQp$VEyZs!YMjEE9@QHU*kiPqS2SNAw%)vdxe3eSFD z2t5CuCpAZbr%O?{ga z`IP2c!pFC5{q46BFsqD!fyJ!H1&^eH7;|6MszbbI9VCtbFDM3-Z}ci7;kkxKVz^y1 z8s8whW~>z(ZZ|I$bgb5HUTSVe<8s6q9>G^v-lVcQ9_oWg(^}zly7iv>H;oa)oo7gv ze6n4t#%8P8@B$D1^e(i4BmVpWmWR5{9hOS|kV3YCPkf&Jh(-eaN9R?n!Bq2(32#KC zt*qyR>Ol5iJ(g;k&8T^wK4@!}X2SnD_6Y>EtI<+p>5Ko=aF!FxX+r0E(6OEja2W|M zcC=OF=jvDJ<@aP|`MZ@Y=KD5t$_@o`H`*`TdR`;LAVdrPuzX)nF*>AzR%-WI@u~VNKT;jJ*K$3g^PT?rseqloZ@NPRj>ym2GP{0+Ra@Rx zSxTcYEvnUq+ssEw)h{tBy(v`fWISqfZ=tCY0~Z0})DO2X7SxtlW8`I38G3Y9h8~?c zJg=2kpXbr()C{%jN81y}QkQ35U@$T%suwoi#M-^4(yqV3o;c|!@1N0oZ;jzE&3iq; za_bhl)K&IH4VP~vHKFf2f%BW`Umm{WeoeS4|K@~vR_ zVjv0KgC&cEE>)I0+rz$X2l4Tv;a#q8L7U1Y=>CQWP$0NceCCN|4j%b_teMIvN_d-99aM{Xmy1!c~zd&{1% zIWZ=6wW?YJe|l_w1^nRMUBVqy6fHVV>$;Z|TKmF&-1^CX*0>&wqHka<+ZbuuOY>+D ziZ&pxKcrz7X}SRN`a3G4uSaBhTP^2K3C6?I`Uw67iIqIWl*rvy?&#ZZuyDYgp3YvQ9MaasRPi9J14{HbqXRNDXq5 z(Ty4F)C{D9ohfBjqwCC4M5A+kr6vOw3!_U*8IL8HK)ev{Nu_xF?L>tkfLjrI*dFC7 zPru4xT>Wb#a@fyPABFDggzczWngy4&ishv9A}qdnqLAIjDW1ru=x(RBjLZ>E?NE}* zIhCs4t{G^L8Eju)ZqF*Sr|7T}1yFkEjK;YbKXZ&xTtKJYLq{gGd__DIr(@-DUCj!) zoFfGy3r{m$V~BAxXVGfp=;%~>!~ICgk#G)M@%lOukL``IkWlJZ{gXUkGiZl?jEic( z40P%%?Fl=fRH=;rihCbjN_4vRfbec~xfFSU7}{x82vD~~D|-Z@nVb=))j%|+=SS6# zzDl-_smyNNX0s(TYOsA>xjnPYo;{SerPhbp5r>}3=rWHugMK06n3>$Y8;@+*U+j}Q z)910z8d$=gtnOlgy)Bi?ANApNZ%Y&1sB^bG9&k#U~9l?sHVl0iK zkG);Xiz!~ztTv-gcM5ysFh{tk#qzS*Q#j3rK{TdYY%gG_rhu|T=4deH07-sB{_@uSyt!h?rWb!x>WEp#D==k7^e?a{-oDzuAR&{4j{W}@|Gmn#0R^Mow{ z&yt>QMQwTfaXtjvD>F81deID)b%g$6vaZtZI0%0=0uiv6TxRIL2-$H(vRaI!6`1f% zBv)^SdSiZ?d`7KP$U@|yb$-CYSrQb{9scIv$=4yC$gAKVJ=c}*q}bhhjlWY3b4*nB zNwTFg;1~}uxgP=)%+SX6=guc+*%(cV%?Yum;UoO07fLGocjtEL>G97!$>CNk zZ^8`rV?+D9JN}=pzp(nBsDGVEd93=y08{KI-}rP^j{V{m{yNPkxZjuQ*1di?>&@mF z0EimQZ8T3JP@lN(4@ISJKF2z&K~bX^w-MwtDvuKmy{!78U0 ziLI1y*X&yuo0-!*^HUF*mM5oDhUfin&g<~~C2I??H?qyl$`h2^PfT^D3b9MVao&?# zP9g1KH~y?12f#>xH(T|K?(2?+1!Kly?(eEV})ghxNmo(BTx6a|`sYOCq$wp2fN zKqWWEzGsGae2y>dOVw{r>!p^w*K+;>N#Lr@fiu-46X}n)hmbkZJx47$Npa~Hxa0fK zh-zgNIzy+Y5L@iWNh1bg6v&GU;rCMl`TaClcr$%1ob4S%=Gh=Q)`>Xm_~!v+Ev%W^ zl_^h&CnXd;A63F53ko>BdW!Hdaq`F!^JFPxF-bovkd!8$V~Z&k;2|p|xDqpClA)uD zDz?n{*eOsF2CZMkmhJ#m+%F7C(<|5hj%WrcBi2mZM2ei+9u^@`!xtTa%JV&sL}h_c z`3kX=x=uCbwaB@ES}Gv4+$2U7+6B+CCOe{_XpLxP(iXEc7~7o_J=`n}@P*+|rjog_ z-7TUW^ph!Vlc_{$fc2TJm}PRww$%I_+{TvWUO65}x$uFH84fh2O8k{eLtRRU-zXv& zG^+w;nXacy>KWkH)6P^+7NMTlbRgZmc>O|xpE%1b1HQA(@}O~1k)Ksx0kq@w(cqxI z0BG`Pb8yYiMhk(TYYxv#44(P3Ftapoh*6pc zK#}~#8(SEIL1M7To;hF}NQ@kAl;$P_e6Xwkwv^GY$X@jP4pg4eSlydo_*0vtM_khU zFAtalq-e+-K>iya*^63$ybf&X^s~MwZfuR+mFIhpC`PU?P9?&POoqA)M*9!QHG9oB zdKDQT+PBs2NEu%kOYtn>pU*7u^^xP4qoUF1HEWBYWp_D7m$)?_GJ5 zUNOUsXwM^1Od-{l#BMFFHwNTsgb!B;+a*L-1hbuf(w@k!bJ{gi-YNs;AkC^lB5$AM zq>HO3BLZm5L3zbH!R->uANPXhQyYnV(&Z_OVO=`QEwS|MIt5t&FeIAKyULKpMOnVPdr84)m2G9{CVP#}u zaXlK~baLET{z#9K;+=g~O!`mqf~N0d(}KQeC^pUSi?mVMzDwqt{(H=l zAQ~kBmJnb2hf(B5mbSg-v3)THJ~0i5G59C4-bt-pzh9l`>nQ9OVAv*fRf> zl?_Lpw=E^9X6*YR*7tfty1t!5z4di#THiC^+5YO&_AnYWD+BTMs(Io&L$&vznTk`f zzP?Caamwj`VpHGq`>g3X(VemLea7xczBSx$>`u#HNvx008tRYk@-&=LP-H*dPd8c# zRKoOuQ72fzg=R(2x&-V@mp5|E7O};Cm{Txo8}gEY-}T;>N)`aO@b=`9gtitB^t%s{ zgjx0)doMgk{`xU{cpY03#>f74WkbrS*kXijD{SL=BD@jQ`bc(83rOerMs!m=6{_8V zUMUvd$I4uF$KmKAoWC} ze1r2mSdrt+&8Qw_xFMT~F{lS^MhBrEeUPhr<)hZv1 zX*gF`ni|uM73v3Ocmv9(F7Eb@u5hqXxdycGE;%AQQ}IgHi5$AxjjyR{=kv;HRk_~C zVU({TY#0g{_|%v}6l`Z!t~SG)8eS7p1n(y_fGG+9GBj9t>un!)b3-7n#$p(>vm82t zMc`O!WRbBrR<+R=IhAHEzA}0W;3r3C*cUz-=#`&-=x>sRkd^qveNd2g)0vmIx*qCl+RjyeXgvFR;OcggM^%SY0yh6~*cK#c6x=gII-zIIum4eW(ghAwB_#RvA>O z(HtM_vousYPa4$aPwegh>>>I_%H5>}4KyNNdd)k6^R?ev>Zccai+HUC@LH9>;rgpf zp2+f7J8PHhi#^}F-f0z_E%-BVHeKiSUD);v=k*=X2H>^81WI;H-^#{Nyn=1qn#}m4 zP_BIKP#5~I@Mq1EJi4=kJ^nWOX69!z7XpqwswWMa(1LdB1M`APsaN!cjnbesJXgE0 zsY?ru$$m1e6}(%c)X%>?j48RPvOG4Rc+?Jlt~|iaMJSeoSlyDM^o!AGSA_4(?K6~=DIYohw3?X6Sa zMMlLs<3pozmCahl(sivqqi@t_gjbmO(`bn$0`-Ahymvi>U*NhXTCs?AchIO>JIcv-fM&;qmt;Fh8nrm0drJ$)J5?OqP~FccO1j@haX@W%jmWa-WJLYZ`>9-qAZswo2mRnnT!jK=^%Ht z(Hj1-QRe60-p1XzsX=+DJ)%Z#SNB4%eN6hk2AtE(-TX%kad89L>Kks1wxx7lB-YkG z?cVEPFkE}$$Y+6)OC!7mqG^?i0h$)Xom->y7{?zb1BatkF zKF6j9e9_Ke8F+%eQ4#hDh(PoB%+mbW?v_)IHOse{wKX&FBxglxBl$bb?jwKuHu@bq`6R2(M7m7|;z>-eUHIalFAA!1jtQ^+TU?Ji=*wtnk}I z0gd$5tsC?3}dT^Tq8sdBS(lF{`NNR%1vR|*b|`RJEKn-D_kSz z*aPq*wgn;{5J&weYVciOiQ{}Y(+keuj(#stxs-nzet15`;7L|{(jN~30`njKBFiR9 zWqhOzU!pWfj_58Y5`e1speg8|V|4YEgYT8+*p_bWV#+aW4kiXFZVwa~(8@f>9cw~E z6$;qFMFsjQjK^~tU|L{REm*{RyXV9mprl(f^&uLQ2c-cc?S;=m3d6f0_g49CE#ZJ9 z0%pI~85$9WCguTa5C6p9QTlh8SrITV$8dn-gdb5Y95yfqg4EV1-w1bL(7I$xq|g{A znBhDt_!yDX71@Q|*=5pnzRRK&0i$vg0X>8}YoMs~<>FJ+uu#-4-kAt*LDFjvs5sFc zN=J;(QiB2WkXhkx9Vh?SW+h)}k!~c%4yQFV; z(;aPTS?C)?AB*oaqjoeO;~RKfa1g7%DvtWl38MLj)A;YAwNj>F;;d|an{#UO`c`z> zLG=ylFIe&prCqLDUTTc8w&UZ?8+@(DY64`~OzoDjUk)PC5Px_%r5Wu|-#E z75WWcLST+Tj8CgdPGW%4f&n7Z$y{^BHD@|3UtbJPXjM}FnOA?HF^m*yjmg%OJPMCT zW0a;Gb%WLv9Y3mUNWA66_y3u^_c-PMpYr~nGaTk$N#`M3-jzMYc;slXHe<|lK{rY* z8uxHz-HcpxD8^!%WtdpUpGKEs=9nW9FrGEb)gNVFu7I7wkZEVMlRfHWG7pvp=3)h! zQNqvYMPSBQEt}TnPYY~JZ`USTY)*z4_}S1^}W>=Kot zDI^S(@!2LxEXzfqle~}LgxD!(A!JN}tAlK)_r)I)4J900b~G^?5~~WX|fgs-IDTIKpak*bs9Rh98^IZ&>BCoz5br5YAPG_v}BR<3iUFy};P#`nR+e_J=1b z8HgNjbRp_f!J=`>0c}Lng688HV|e-`WZT851Ht3lBt!)iBw^22> zcfg#2*jci|5g5l!{w>G%j1^yOg2w7;Y%<6cxw7J1ydn-rZ$KKV(uqAjf~yf=r$+Sl zC4yZvNcU>YlO!*BMQnE}dZlhOO~l<4M3M3S9J7K#{o)~%H_H$vQ-b&u0vaNh3n|v> z*~biWfcWRYBeX$7ijfe;VHx{}!!F)YdGzm+{ROGGf{G++R#tW`A` z>H3fQ{mV_?YyKfX05?&I*BIpDm_v_*-X`J+#Oza%@obN>msPvm3K9*D>V}%-d2po= z0z0hFhoLgY4BLVaG8{}6nc@5_Pik#f&3ZOQK&k=Q9ugIWoCzf@fCEKbc`D8Ob61kV z42;^^(=ydW$)h ~898ZFa8K{Y%*Pnv39ZB@Tp&W$(iks#JOS7_yv!OO zc>IMcG&2E%!sFPA>#4(vWue+v@gi*yyMHH=;&9shmxt5!Z~}q1qf19%?4jlBB$le& z0?C;`^KtSy-QD9lEk*5zyjcA7&pZ+TkMZ3M(nTIzZ62&n^C`4XcWUc zVDO^kDT0J07n>ogVh4JyfFnRFG2sWAMp2djP0VRS!n~V~)=Cy-^k*E_vqcaSc@TD) zxeT_cOd|e^x9{>6*ABSGmKDnMbkq33O=NkLQB}>tH@+p~b4?jAsE(+;ImX|lAKDAY zU1S}z7L>-9{y@pmKpqE>bT^WokF41;hpmiQ9kkJJl;3BBXIb$(VZcd@RW*}V;Obix z&1p@hxF(2Y`ro~J~`6i>%+sPi6MchZfN2cY{SBVW-2uMU{#xpH_l#6M+Hr6a7 zbt)F(j(^N5&L5dminOYZA`%D-X%qM+$3<-D0>WGS0_sV4`iXD(U>f2`Qf(Q^#`fhL z1-D->g7A)?)%pjox&7`NX-lWBA*f55>&p6kZY-VDXpX!HnL3+8hZOImJTI=t`+mj6 zyG#45owQBbJVQU7_Aem67@6yBjp%JvHcG#wdyFA!?0al%`H)y*h`gDqyrVPZP3RGs z$_UMKLu^g;7r@aZ&|inA+rL)r;aDxOWET8V&GEzj#co^)4@Md3e-6Gud)v{F$izaZ z1;W0e+Ls~H5KX#y47AvH9D~>Fn{TrNsLG&^e;v&`tr0|c&<^l_5S!yN&(kV;qY}3p z`vR$Frr^7%}cf^Ua42Q z!2dx9gW18aBq|z;Gd_hGU<8Tal68;@oY@@vXjVDsVsLRH7Ghw~Vh+u7x~Pxv4ll~h z9so)Ag~EcqX(FoTb(+98!*=vk+#1X6V_~WoV=Borhh6L-KfeeMfhPF)3xrg=LEB&j z6sZVTJ6SDcmGNae4pC8H6$&_hitdjb|5i8YyI;8;t{Sgpz5gKlJ>{u~8c$L?x`8*2 zV>3K|TS}IpaiH*byg*Qgqlhtisvk`|mf$o7us*W|kvtbwD5C){q?I!k~E}YO29)-+{T&W38aiSZfT&va-P9jV&F)3)5Pa2DC|N=mf0P ze3xVIx@V7HKNAgkPs|@eEZ-7&m>}I<^Om^&4F+0`KIh_z_pEa{$0RAH#v`sNk4Kyp78}()QgdLx(X0Eh$q`%5`_ccASB5@U|yi z%Za~;(lu~?320;s{DHIC=W}&UD*Bq%g3=9m1{6TSd!Vy;y&C$xN}AWjmUWkYEMxqu z=1UNN3L?lLlliFImGftz*D4qlnX0Xnh}JFZAzI2HVPtQapEAItrI_OxzLShmWK=V{ z(Z0kgDq&*FPqs-O3z`Ok9i)LC7=EFGY+Y`7o(Tq z3FXusM&p=Pa|w* zLp>+zsxU{5xsXj6^1!ipcmwh8MEpH|(G?(${4ueNqIM4ea2-%9hf~(m4yTN1xtdw< zp+X`?1x5B_v?nmkdcwSF12uTI*n8XYtlp7MR8#wa)Ub)~%8DIAMX?WqXQ87Omi9$gGg((UjGMKXJvt+3S0u`~CAd&WPFr4*m`E;8};#$Lj! zS{JI_z_y-)3haF$hmJbjLP03@Ncrq#)Nic83e^rLCVFj`ti!Uqp$1?T@5M3@7gbCc zQ=W@ryNFe&wu>(43Pbgu9oD3UfgN$l#lj;rKGf2LTSJnQY?bmgbf!FPIvxEQIHU>b zC>^~N+k_TrSb;Ld^$qtBF9_GHyU|1JoOY72*Q4JpIRF>w5&!7tPf{t&77veZrsRE8 z1xr!Y$mI5WQ%YePdI}wq`xcPb&>r`R@Fvtn`ALqU#zpPqaCH?qO%C9jev3rLfGlp# zbZ(L-(h&6mzF516icVz;?wXKsEN&Ea+N%AG7Sfhicf~K#qf51zbhlBpPTs(N82^kV z+<5h6?E7i4Zb;jVAKCdFC%*2cSk=0g(E_+b=sl0*NN{K#g;7h@Fo1`K9;*x#t&_I+ zXW<38`WqN1*c%j{CE5h>54Ffb9#neD5j~=bUwuT zWWpzc!DKGQ`GO}M0W#YgKiP$70Z-?0JV1Cm#A>`wk0*@Jv78C$uYZ)|yU0kUr&Cpy zVknK?WGaE-Svy!8EJ$+tQ(;TLBD;wCfY$|LjL@keeKC7rT%QM+Mm#4r3k?zxMl3PO^k+!(dK#|8RTk+f zZzUgy!fTrlPpP?&+o@(9k7p&#cvydEhZj_rQ^m`o^dUR_n`FKh>XJ|3vSEQvt}j~1 z9FssvvXd;s@zgy>a-|33j=bMQ>wv`(7!Ms`RIE0KA_}<13~;yzdjx;L;qqw!AY2Z3 zCckEM298R4j!u>N?Q#P5X<_98x^;lgm_?DHMMN z&5{|9eCu+t((#Ach#25K#=xW*t~MW$aO5Krg0v(YS-ILkM_sWI!A5roR=OHQN*KXI zaF;pYzY zm;1rr!_TYT{L2n0f3chY;X}%w8v%f!h{y(|-{fC6l?QZ@x!9(HC z05|{Bhm`*aH-F@i@_*gNp?B~h<$ul1pSS<~5>M-w?Kt#gAY?fg1BGfomO&Ra-a9t< zWG4&@MD!FoLatYGI=XxecOBD717JVb5;-_0t)|QA;G$d(%OQ=Pnw`p$H2}Ai7Ax?9 z0$dFg=qetE>aB`KRBx9fsoWXaCRCAUw&vi)$H$c$;-7|Ux3li5b=Gw38ImzW@p^QI z$&<}WyWy{Vhnj!)F{{D?NvxQRJq9Cn$~x>sX?T{epgk9K@aW@6R$;T`kpn36vqh!qv0qPcPyd~A>K`Syt9lv zHV2jP=Ct!9?ADniJunbkPx3PQ8${oYg1M#eU`&5+5t8WpdT4um4%7*2Yqvy;lP792 zZ${Ja`t;fYhYX%1XSKK$ZkC+4@(ccB@TSvdlpDXa7Zg?GIkxFt@&% z{nXdIy=*C=odem++Z%yD=-9&u=K<~Ilzm&9v6r8)T-shfBu0!)wQiXLd@)eSvX{pq zV)K7*FR!OT-oL$Efw|cI*~^~?|9AFsG)0|UdILZYYA=TqF=b8$foK1(?B$e|q}R2V zHq>l?^c6Vt9jd(?W`Z}zh5uTV3L#)}Z}{oBj?C{#i{1^JS5CspS?;m0oQ0aTl5~Tj`^nLij>$}3O??Fst zHCLb4|MfZk*D~~82ltnY-TV*lKfl+nybzs}g&osd z?V)?r3{E>d;RafSu$9{bSH!x@&+YhW`^+w*TM6YC?hyJ}SYu@}NbJ<4?kKz78@>k&?dFLV_);9}n%$M=pKX>S*sfzk9h?(pV- zUk1%;S>U6~Nf%<8(Jsy^HhC+et;1b^=X6rA9+6N8^4BnXoX7x$ zrPzFfUM?L1^{!W{Z1^4GS!sDy{MHLD6JZ$(X{`Y6LzdLo@Z9T7TFLVx7ddp`jbrVZ7cr@P+1`vL1;yXz3@FFrv1&xqY; z{e7F%UtBMP>st22dVQ@k9<2E#q8FoVN^Ly^`5x)!fAf&?AMfU`J*50we|GR0eMtEi zyZMU_DgT3R{vGH(4zABvyZM(LQvPB$|HJ#wujElR0k`=>SJ*O+llfvRUT-&asu zwx+ijs(l0CtO_i}3D~Q#58>~_o~!VcSXtn=0w7|H+<4ZP^aH^dbJ`oWgB?qa$}MWo-C=Bk zmel%C?N+b>w$d8e!>F*Wk-f3x#u_>V5#~gA177(SN=uOb^MIFZA-JDKWbPFav`ut% zVL-*;_oL;^BlS-E+r<@{Z5M++SXp;N1kYAZoVa zo8+^PUx<6K%s`8zdk7KNG<`~59sB(CF2^1YhFL#&yz4bLe;)E5+`iSg`8Vx3l>8&z z{BQ0*KjO#Jz5Q=xL+6ZpkAIcp!ke&vc%J;9>~#3iE1f^R*c2&8{xJWU%O$ed^x7G_ z@MX_@fb%&R<6|RCS*|sV&JR_}&&6n?C${vVeZ=6!cTxBT6&Pg&=Ac5O4CCb@qpZj( z>t+q><`h!yk6nOr)TU)9VwLr>hV{zIu=hHZf#H0stc1%Zb+sD8mpa2elHnq2*hN_x z-jNK^>#VY|*08ZzFXyP2L#(nJtYJ4~y_~LIo@Ne;7-bQw>`rUgompANsVv~j1fy(1 z#=$;LJYM=MXTKnh-B5dkT}P@Bc>ByDf!Lnbkv6eCZ9{RMITKsF&nU-s1iv+;1r|Sr z=HYCNR?*2cHZ*ODlW@Qy*0`>T-v(&A?An}TwsQ=#P- zX!jOtYlXzfD-_MI19=c`GagQkq7`b_R`>`E4(YqZdL+T)`weWFCk<8*OjS8VzO zUo`0C=#Lz*)Xs{|mUG_w4cFuBN_~?ki_qjIKSqLT>hFQ49(-ZmhJ|s?JB8J4tNHk0Vwn%ql`bL#Lh3WAseJazVRQfcg%T&5M z(|uL?bf(W#X&ShO6IA*PraL1|RMgzbzj5BD$Tj3hNUWf6w`03^wCVeq|(PQ{e(&vF#TJVK9=b^l|GK?yH&ai)3>U0 zA=B5Y^zlqzs?uGV9;VVKFnxha7ct#arO#ygWR>p0^f4-3%ydYl&tkfzO1ENq7u;vi z-jnI1O1EbEpDNvp>CaU9Y^D<`%`T$hJ(X_5^s6d;4%1JmG*{s^{7$8@TG7{Fsxdm!03XBd$J#*rDH@))vDgFF;{k#|E&uOYmd2UKwYS+TV zMEq~4xJR$$aq0t4HIZKAt!22guh-dn8~h zYxgg8!5$QMy$&s&5Atibn?zH*5C%fFWjp}#VJYah)goz+y92N3%U^=7)EaaH7e}vk z`Vcym!!Bpw{3dg_-yFjru8L&<=f=|OxO`Mi+#}=b2xDNsEp`ZCS~DN(I!@O00AZg! z81=|{E!Heg&cYKx%R8f<#vg}Y8XxM>%v(dR!^wHi=Y-<_Ci-9EkeR7n)qHYjUi;Xd z9?`teyx}=aw2Lio5v$*aV~M73GL|k*cF9@#$zC`BbgS(rZU-&sa|ZY+A%6lahSJ9d z?mey+QygSXaeeX1jPXTi;b+xLSBK{9jiuU5=@478T8@8A`*Sn#`U!b`*p!a3B`+ik z#o=?~6@0%4r%laUAKQD_l;YTum5Vp}b5`$MoP$}94;FvlCFg@re!`MDbGm<~zjJZ@ zz2n;F45(cnt;4fq3plXu3T5y5hng+41EN3UF^$600p9+s5n9v=(WO{bz7Jb~u>Hpx z=gWzX!L0rz*e8H7g;n?M!?Fk>Xw}X8gQNmhd^KfOMS2R!-nUlq!DCcDEcse%|2~X$ zB-@NHOnGF=>tyTYQqHG~<8&27{82{%L?j>bgC(gP2FfZCjAE?1|EQV+)&f~Zr9{w2 zD*6yUSAd8Y@23&9k3`pJw&Gbv5P8z7ME=SFJj@9HT>dJ5Fq0pcH_9{LUiyQ}kAnU3 zquAxgv%f!7ei(xfg&##`m^Psh{3rlF5L4n*NE5d7-!EIbvYIqoXk+bt@D!S1OIgWv zm|Lnw4%faGIP&2ff`BDn^WXRnSkeW{WDp2=WGQ6Q8h1<%rn&Nfq=X8s>W6--+3=P$ zlUkZ8&GgV9;KPW6Y9=}u_ASJxwQeR>sha8S3!325J&g}eWQgXO^H0b|22!l?5dk7j zoS{Yp)2i;jU$piP%s`7gus?@$<)X!!6Z&p&a&9_Gp#r7B!V9M%|#i4mCt&7^^7}m=$Bk1(HV67fF2Ni%V==`Xo zYjc(DNgiX>^~`>Vp28V;`%8#lE^!`LRDg+oz{$7bQo0$Xy1^m4iLLot2|z%p%sBDV zRu688&wdJyx~p2GPRY!ceqwQ&*qb>X`U^mO62#N^l6aWj6^t?q{r5FT|0B)OpZ%~Y z{Xia*=N0)_bMPsSNYpm{`3D6W_{jo-_4-RA#7%Q5Aaa$$~90A@RP|&khb|Wah<}qHD zqyVND+J{937xh5}<7PQAJl`G8c?v(*+ zurCMGDyJEb1Ss(FApXK^LptEuKvn7-R9!=IvNx+$_f&R<>_)(*=U<%%sHjb0F| zD)8|r+XBb1xTw2pa=O8KI8BXK zcY58XMn*XIrBhoIBXc=wQ;ke+Ya_!zmEEHdjT~o7sAEgv>a!V@YTa>mM*mRY*cY!q z`^`6KddR^z!QE11190&hb@9Iv{e^ zT7rl#Lz>cQ#n-45`i5$*fj}>$40#?QvI1W1g#^eomw2K^**D<{e3EzyalF_9Lc!*^ zZMd->f0R{VSgb*+Nf7}Pf|@bt{Q>eBZ`Gra87Eq*@eWMW-Pe;Ql5;*nq<|0PS3AhR zbtjQmTSS0jCi1s8LHw@!0#Q&YEGd{D08`{YZXB3w#f_Bm$%IbPL>u8|(4MofddY z8r4IJ1?guC3_(6KPE>%zArSG)bq*105VFqVeq6Y}AJN%P@-q-G)`%}dXgIb&bN_7~ zYU*+yXYjB=J)*M)szSscV7|vFI#%pTlIh{UUxfdmyBt(|0#z$EL2{)feuE}@f8z2f z%V!`w3s1=Dj)E}DLtI)3!h*=`n>D|^LUV#f_$vg%y+Wdp{P&#>lC$9lD1NTfh-u>Y z!_RAFpS4#Nw*nT?i=d|10zv_L*GsjUYN%p1KWlp`eqJE?gpBG_v-la*a!e%TjnUuAc+c71uW&64$LJ=za)TM0X#oQEUOB0Nt&)Igk{$*XXX4e2Q~D zy`1xVMaAVm+rj>6pM!i1@qLHyVJWQ@87A>yd>>5~WbnO(Cgf}(MDx8{8o}9Pn&Er6 zSn=JLL2w506c(CLLB79>{Ax^8{5PEM*aYE`fJM&N!koICpMo3Lpfw}!5BE?AkC1$d z^P6AGv>z_NF)m5V`#rxneD4C(9li&=tp>htIf%S(Ae0Qg--{mvUiwAm?rM3%fCjPDZ&C4=uBG$CQ&c9hVv&hLHKIGBIh55&5AA1oUaqxtM$Ga z&Od#+LU=s#y@Q|6{tf=h$pP_;`HXY1_C)ttKRzquvrF7(-H@{HSg=#fy?B$M+C09+ ztjv9QtlMO6*SXLm*ZB&R5Xu(3x8jYCust@D{W+XM)o}#@#b-ai5THFiWw%8;Q?Ugs zlN*XZ>oIaYDKhL2#rKsjTi8pxD*~q>pH!~iN#!H{x|1uf;@5a!oX`x6=^Dm)8iw`Q zY@+Fb^y9ca0x91E=~|MT#s(J9XP>PhHPX6~6&@HP&rmSdc+AI?Ocm$!IjE%56iTDmQDV}nvqG-nxH}A$EnOcNas(l}M9QE%1s%w(LVcnIA8|WJ66AAxs zH#+(?jg}1pdCX0Ck|l&?c&1>OY_Xsvn9$?ZqG(sJlyW=!r3W|v#E2obfcW`B@nb#c zT|@M;n*O{~RkQsFMNhYc{ku$ zCV8ygOWtIbYC@jROWyf{lIjpAXObsUdBrJ;yiP*i&uQ{xsQvdFz2t4f9Gf=i2P7}# zl2?xsB(IWBvdA;=ER#Ie?j`ScEY*a(<1tinTW`Feq{w?Hle|K<&(v;;ymOH+5%*!= z51vv`Wh}At*Ix2E9wK=?xPwB5s$aKNyO+HAEY*a(ffzoy#_#}(G5AiIMJl5_d z?+cdVT4Fb-a6Lwum_m%dh($3DRsYJQs)UV}I7v};5AuaBtq+|N?+v?+OE-1NSC@dg z>_)wKXRFIPby=Y<^KnVUFG5CX_V^Gt^*-LvA3@3IRo>a^GE-gdRF@mnWvsdkQJ3E8 z(oJ3R)g^#SA|AwFg0_A$mQSH@4&NnsIc3gvF`2vBFvN}Er~UQmbH!nGQAWo_ULZu(LRNz=yc%yUqXJg zpB0y!YS=B4vy~?*PCt#@$boRzI&etkWyKhx+YioG5UT~EBR_g9EKoXYC|73YP<^E2 z_@%4rSNgFYgd45+Xx2lUyhtpzRTC9lP&HOl)s!BptB0O?((@d)?y!cFP`+jX%PM-fkjtg#FHPxr?gT~8 ze*nax$Du^m<4_{?oT(|{u`Fr(t$i5b&_DVpO6Dktpk&;BDJel74<(CnYyYDyDT!WH zvw-CY5|L*eI_UpOQwqNAN(!Q!9#EeO(CwgMJJ<{C+s_m()jp4kthlrqr1GUO??hs7 zcQfwZA?Xc&z#s8t8-~KftJDQ<>TEZ4nwvV_O?7rthr6kkZfXyDLL+aC1MuMWkPHk{bB2Y>-m®%gdnxVI(G1yH2^;IVV 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