WebRTC: Implement MediaEndpointPeerConnection::createOffer()
authoradam.bergkvist@ericsson.com <adam.bergkvist@ericsson.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 7 Mar 2016 21:25:03 +0000 (21:25 +0000)
committeradam.bergkvist@ericsson.com <adam.bergkvist@ericsson.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 7 Mar 2016 21:25:03 +0000 (21:25 +0000)
https://bugs.webkit.org/show_bug.cgi?id=154867

Reviewed by Eric Carlson and Jer Noble.

Source/WebCore:

- MediaEndpointPeerConnection: Initial implementation of createOffer()
added. createOffer() is split up into a synchronous part, and a
scheduled task. The task will be deferred until information, requiring
some amount of work, such as the DTLS fingerprint is available. Other
async API functions will also follow this pattern.

- SDPProcessor (added): The SDPProcessors parses SDP to a
MediaEndpointSessionConfiguration object and generates SDP in the
reverse direction. Any SDP string handling is confined to the
SDPProcessor and all configuration of the media session is done via the
MediaEndpointSessionConfiguration object.

The SDP parser and generator logic is implemented in JavaScript and
works with JSON (SDP->JSON, JSON->SDP). The SDPProcessor runs JS in an
isolated scope and converts JSON to a MediaEndpointSessionConfiguration
object and the reverse. Using JSON signaling (nonstandard) can be
helpful during debugging.

- MockMediaEndpoint (added): Mock MediaEndpoint implementation with
support for generating offers. DTLS information, such as fingerprint,
is hard coded to facilitate testing with expected values.

Test: fast/mediastream/RTCPeerConnection-inspect-offer.html

The test is currently skipped on the mac port until support to read the
SDPProcessor JavaScript resource is added.

* CMakeLists.txt:
* Modules/mediastream/MediaEndpointPeerConnection.cpp:
(WebCore::WrappedSessionDescriptionPromise::create):
(WebCore::WrappedSessionDescriptionPromise::promise):
(WebCore::WrappedSessionDescriptionPromise::WrappedSessionDescriptionPromise):
(WebCore::randomString):
(WebCore::MediaEndpointPeerConnection::MediaEndpointPeerConnection):
(WebCore::MediaEndpointPeerConnection::runTask):
(WebCore::MediaEndpointPeerConnection::startRunningTasks):
(WebCore::MediaEndpointPeerConnection::createOffer):
(WebCore::MediaEndpointPeerConnection::createOfferTask):
(WebCore::MediaEndpointPeerConnection::gotDtlsFingerprint):
* Modules/mediastream/MediaEndpointPeerConnection.h:
* Modules/mediastream/SDPProcessor.cpp: Added.
(WebCore::SDPProcessor::SDPProcessor):
(WebCore::createCandidateObject):
(WebCore::createCandidate):
(WebCore::configurationFromJSON):
(WebCore::iceCandidateFromJSON):
(WebCore::configurationToJSON):
(WebCore::iceCandidateToJSON):
(WebCore::SDPProcessor::generate):
(WebCore::SDPProcessor::parse):
(WebCore::SDPProcessor::generateCandidateLine):
(WebCore::SDPProcessor::parseCandidateLine):
(WebCore::SDPProcessor::callScript):
* Modules/mediastream/SDPProcessor.h: Added.
* Modules/mediastream/sdp.js: Added.
(match):
(addDefaults):
(fillTemplate):
(SDP.parse):
(SDP.generate):
(SDP.generateCandidateLine):
(hasAllProperties):
(SDP.verifyObject):
(generate):
(parse):
(generateCandidateLine):
(parseCandidateLine):
* PlatformGTK.cmake:
* WebCore.xcodeproj/project.pbxproj:
* platform/mediastream/MediaEndpoint.cpp:
(WebCore::createMediaEndpoint):
* platform/mediastream/MediaEndpoint.h:
* platform/mediastream/PeerMediaDescription.h:
* platform/mediastream/SDPProcessorScriptResource.cpp: Added.
(WebCore::SDPProcessorScriptResource::scriptString):
* platform/mediastream/SDPProcessorScriptResource.h: Added.
* platform/mediastream/gtk/SDPProcessorScriptResourceGtk.cpp: Added.
(WebCore::SDPProcessorScriptResource::scriptString):
* platform/mock/MockMediaEndpoint.cpp: Added.
(WebCore::MockMediaEndpoint::create):
(WebCore::MockMediaEndpoint::MockMediaEndpoint):
(WebCore::MockMediaEndpoint::~MockMediaEndpoint):
(WebCore::MockMediaEndpoint::setConfiguration):
(WebCore::MockMediaEndpoint::generateDtlsInfo):
(WebCore::MockMediaEndpoint::getDefaultAudioPayloads):
(WebCore::MockMediaEndpoint::getDefaultVideoPayloads):
(WebCore::MockMediaEndpoint::updateReceiveConfiguration):
(WebCore::MockMediaEndpoint::updateSendConfiguration):
(WebCore::MockMediaEndpoint::addRemoteCandidate):
(WebCore::MockMediaEndpoint::replaceSendSource):
(WebCore::MockMediaEndpoint::stop):
* platform/mock/MockMediaEndpoint.h: Added.
* testing/Internals.cpp:
(WebCore::Internals::Internals):
(WebCore::Internals::enableMockMediaEndpoint):
* testing/Internals.h:

LayoutTests:

The output SDP from createOffer() is processed by verifying all variable
identifiers, such as session and user id, and replacing them with
predefined values to make the SDP comparable with an expected result.

The test is currently skipped on the mac port until support to read the
SDPProcessor JavaScript resource is added.

* fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt: Added.
* fast/mediastream/RTCPeerConnection-inspect-offer.html: Added.
* platform/mac/TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@197702 268f45cc-cd09-0410-ab3c-d52691b4dbfc

23 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt [new file with mode: 0644]
LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer.html [new file with mode: 0644]
LayoutTests/platform/mac/TestExpectations
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.cpp
Source/WebCore/Modules/mediastream/MediaEndpointPeerConnection.h
Source/WebCore/Modules/mediastream/SDPProcessor.cpp [new file with mode: 0644]
Source/WebCore/Modules/mediastream/SDPProcessor.h [new file with mode: 0644]
Source/WebCore/Modules/mediastream/sdp.js [new file with mode: 0644]
Source/WebCore/PlatformGTK.cmake
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/mediastream/MediaEndpoint.cpp
Source/WebCore/platform/mediastream/MediaEndpoint.h
Source/WebCore/platform/mediastream/PeerMediaDescription.h
Source/WebCore/platform/mediastream/SDPProcessorScriptResource.cpp [new file with mode: 0644]
Source/WebCore/platform/mediastream/SDPProcessorScriptResource.h [new file with mode: 0644]
Source/WebCore/platform/mediastream/gtk/SDPProcessorScriptResourceGtk.cpp [new file with mode: 0644]
Source/WebCore/platform/mock/MockMediaEndpoint.cpp [new file with mode: 0644]
Source/WebCore/platform/mock/MockMediaEndpoint.h [new file with mode: 0644]
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h

index d684d97..b820927 100644 (file)
@@ -1,3 +1,21 @@
+2016-03-07  Adam Bergkvist  <adam.bergkvist@ericsson.com>
+
+        WebRTC: Implement MediaEndpointPeerConnection::createOffer()
+        https://bugs.webkit.org/show_bug.cgi?id=154867
+
+        Reviewed by Eric Carlson and Jer Noble.
+
+        The output SDP from createOffer() is processed by verifying all variable
+        identifiers, such as session and user id, and replacing them with
+        predefined values to make the SDP comparable with an expected result.
+
+        The test is currently skipped on the mac port until support to read the
+        SDPProcessor JavaScript resource is added.
+
+        * fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt: Added.
+        * fast/mediastream/RTCPeerConnection-inspect-offer.html: Added.
+        * platform/mac/TestExpectations:
+
 2016-03-07  Ryan Haddad  <ryanhaddad@apple.com>
 
         Skip storage/indexeddb/modern/exceed-open-file-limit.html
 2016-03-07  Ryan Haddad  <ryanhaddad@apple.com>
 
         Skip storage/indexeddb/modern/exceed-open-file-limit.html
diff --git a/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt b/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer-expected.txt
new file mode 100644 (file)
index 0000000..03aee36
--- /dev/null
@@ -0,0 +1,76 @@
+Inspect the result of RTCPeerConnection.createOffer()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Got offer
+=== RTCSessionDescription ===
+type: offer, sdp:
+v=0
+o=- {session-id:OK} 0 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=msid-semantic:WMS {media-stream-id:OK}
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+===
+
+PASS Got offer
+=== RTCSessionDescription ===
+type: offer, sdp:
+v=0
+o=- {session-id:OK} 1 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=msid-semantic:WMS {media-stream-id:OK}
+m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=rtpmap:111 OPUS/48000/2
+a=rtpmap:8 PCMA/8000
+a=rtpmap:0 PCMU/8000
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+m=video 9 UDP/TLS/RTP/SAVPF 103 100 120
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendrecv
+a=rtpmap:103 H264/90000
+a=rtpmap:100 VP8/90000
+a=rtpmap:120 RTX/90000
+a=fmtp:103 packetization-mode=1
+a=fmtp:120 apt=100;rtx-time=200
+a=rtcp-fb:100 nack
+a=rtcp-fb:103 nack pli
+a=rtcp-fb:100 nack pli
+a=rtcp-fb:103 ccm fir
+a=rtcp-fb:100 ccm fir
+a=ssrc:{ssrc:OK} cname:{cname:OK}
+a=msid:{media-stream-id:OK} {media-stream-track-id:OK}
+a=ice-ufrag:{ice-ufrag:OK}
+a=ice-pwd:{ice-password:OK}
+a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B
+a=setup:actpass
+===
+
+PASS End of promise chain
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer.html b/LayoutTests/fast/mediastream/RTCPeerConnection-inspect-offer.html
new file mode 100644 (file)
index 0000000..2d1c1a8
--- /dev/null
@@ -0,0 +1,141 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+    <head>
+        <script src="../../resources/js-test-pre.js"></script>
+    </head>
+    <body>
+        <script>
+            var stream;
+            var audioTrack;
+            var videoTrack;
+            var mediaDescriptionVariables = [];
+
+            description("Inspect the result of RTCPeerConnection.createOffer()");
+
+            if (window.testRunner)
+                testRunner.setUserMediaPermission(true);
+            else {
+                debug("This test can not be run without the testRunner");
+                finishJSTest();
+            }
+
+            var pc = new webkitRTCPeerConnection({iceServers:[{urls:'stun:foo.com'}]});
+
+            navigator.mediaDevices.getUserMedia({ "audio": true, "video": true })
+            .then(function (s) {
+                stream = s;
+                audioTrack = stream.getAudioTracks()[0];
+                videoTrack = stream.getVideoTracks()[0];
+
+                pc.addTrack(audioTrack, stream);
+                return pc.createOffer();
+            })
+            .then(function (offer) {
+                testPassed("Got offer");
+                mediaDescriptionVariables.push({ "trackId": audioTrack.id, "streamId": stream.id });
+                printComparableSessionDescription(offer, mediaDescriptionVariables);
+
+                pc.addTrack(videoTrack, stream);
+                return pc.createOffer();
+            })
+            .then(function (offer) {
+                testPassed("Got offer");
+                mediaDescriptionVariables.push({ "trackId": videoTrack.id, "streamId": stream.id });
+                printComparableSessionDescription(offer, mediaDescriptionVariables);
+
+                testPassed("End of promise chain");
+                finishJSTest();
+            })
+            .catch(function (error) {
+                testFailed("Error caught in promise chain: " + error);
+                finishJSTest();
+            });
+
+            // Variable fields (e.g. generated ids) are verified and replaced with predictable
+            // lables. The result can be compared with a predefined expected output.
+            function printComparableSessionDescription(sessionDescription, mdescVariables) {
+                debug("=== RTCSessionDescription ===");
+                debug("type: " + sessionDescription.type + ", sdp:");
+
+                var sdp = sessionDescription.sdp;
+
+                var regexp = {
+                    "oline": "^o=(-) ([\\d]+) .*$",
+                    "msidsemantic": "^a=msid-semantic: *WMS .*$",
+                    "mline": "^m=.*$",
+                    "cname": "^a=ssrc:(\\d+) cname:([\\w+/\\-@\\.\\{\\}]+).*$",
+                    "msid": "^a=(ssrc:\\d+ )?msid:([\\w+/\\-=]+) +([\\w+/\\-=]+).*$",
+                    "iceufrag": "^a=ice-ufrag:([\\w+/]*).*$",
+                    "icepwd": "^a=ice-pwd:([\\w+/]*=*).*$",
+                };
+
+                var mdescIndex = -1;
+                sdp.split("\r\n").forEach(function (line) {
+                    if (match(line, regexp.mline)) {
+                        // Media block ("header" line)
+                        mdescIndex++;
+                    } else if (mdescIndex < 0) {
+                        // Session block
+                        var oline;
+
+                        if (oline = match(line, regexp.oline))
+                            line = line.replace(oline[2], verified("session-id"));
+                        else if (match(line, regexp.msidsemantic)) {
+                            mdescVariables.forEach(function (variables) {
+                                line = line.replace(variables.streamId, verified("media-stream-id"));
+                            });
+                        }
+                    } else {
+                        // Media block (content lines)
+                        var cname;
+                        var msid;
+                        var iceufrag;
+                        var icepwd;
+
+                        if (cname = match(line, regexp.cname)) {
+                            line = line.replace(cname[1], verified("ssrc"));
+                            line = line.replace(cname[2], verified("cname"));
+
+                        } else if (msid = match(line, regexp.msid)) {
+                            if (msid[1])
+                                line = line.replace(msid[1], verified("ssrc"));
+
+                            var variables = mdescVariables[mdescIndex];
+
+                            var mediaStreamId = msid[2];
+                            var streamIdVerified = verified("media-stream-id", mediaStreamId != variables.streamId);
+                            line = line.replace(mediaStreamId, streamIdVerified);
+
+                            var mediaStreamTrackId = msid[3];
+                            var trackIdVerified = verified("media-stream-track-id", mediaStreamTrackId != variables.trackId);
+                            line = line.replace(mediaStreamTrackId, trackIdVerified);
+
+                        } else if (iceufrag = match(line, regexp.iceufrag))
+                            line = line.replace(iceufrag[1], verified("ice-ufrag"));
+                        else if (icepwd = match(line, regexp.icepwd))
+                            line = line.replace(icepwd[1], verified("ice-password"));
+                    }
+
+                    if (line)
+                        debug(line);
+                });
+
+                debug("===");
+                debug("");
+            }
+
+            function verified(name, isFailure) {
+                return "{" + name + ":" + (isFailure ? "FAILED" : "OK") + "}";
+            }
+
+            function match(data, pattern) {
+                return data.match(new RegExp(pattern));
+            }
+
+            window.jsTestIsAsync = true;
+            window.successfullyParsed = true;
+
+        </script>
+        <script src="../../resources/js-test-post.js"></script>
+    </body>
+</html>
index 518d55b..7d0628b 100644 (file)
@@ -178,6 +178,7 @@ fast/mediastream/RTCPeerConnection-stats.html
 fast/mediastream/RTCPeerConnection-statsSelector.html
 fast/mediastream/RTCPeerConnection-stable.html
 fast/mediastream/RTCPeerConnection.html
 fast/mediastream/RTCPeerConnection-statsSelector.html
 fast/mediastream/RTCPeerConnection-stable.html
 fast/mediastream/RTCPeerConnection.html
+fast/mediastream/RTCPeerConnection-inspect-offer.html
 
 # Asserts in debug.
 [ Debug ] fast/images/large-size-image-crash.html [ Skip ]
 
 # Asserts in debug.
 [ Debug ] fast/images/large-size-image-crash.html [ Skip ]
index 4febc49..ffe293d 100644 (file)
@@ -940,6 +940,7 @@ set(WebCore_SOURCES
     Modules/mediastream/RTCStatsReport.cpp
     Modules/mediastream/RTCStatsResponse.cpp
     Modules/mediastream/RTCTrackEvent.cpp
     Modules/mediastream/RTCStatsReport.cpp
     Modules/mediastream/RTCStatsResponse.cpp
     Modules/mediastream/RTCTrackEvent.cpp
+    Modules/mediastream/SDPProcessor.cpp
     Modules/mediastream/SourceInfo.cpp
     Modules/mediastream/UserMediaController.cpp
     Modules/mediastream/UserMediaPermissionCheck.cpp
     Modules/mediastream/SourceInfo.cpp
     Modules/mediastream/UserMediaController.cpp
     Modules/mediastream/UserMediaPermissionCheck.cpp
@@ -2297,6 +2298,7 @@ set(WebCore_SOURCES
     platform/mock/DeviceOrientationClientMock.cpp
     platform/mock/GeolocationClientMock.cpp
     platform/mock/MediaConstraintsMock.cpp
     platform/mock/DeviceOrientationClientMock.cpp
     platform/mock/GeolocationClientMock.cpp
     platform/mock/MediaConstraintsMock.cpp
+    platform/mock/MockMediaEndpoint.cpp
     platform/mock/MockRealtimeAudioSource.cpp
     platform/mock/MockRealtimeMediaSource.cpp
     platform/mock/MockRealtimeMediaSourceCenter.cpp
     platform/mock/MockRealtimeAudioSource.cpp
     platform/mock/MockRealtimeMediaSource.cpp
     platform/mock/MockRealtimeMediaSourceCenter.cpp
@@ -3583,6 +3585,22 @@ if (WebCore_USER_AGENT_SCRIPTS)
     ADD_SOURCE_WEBCORE_DERIVED_DEPENDENCIES(${WebCore_USER_AGENT_SCRIPTS_DEPENDENCIES} UserAgentScriptsData.cpp UserAgentScripts.h)
 endif ()
 
     ADD_SOURCE_WEBCORE_DERIVED_DEPENDENCIES(${WebCore_USER_AGENT_SCRIPTS_DEPENDENCIES} UserAgentScriptsData.cpp UserAgentScripts.h)
 endif ()
 
+if (WebCore_SDP_PROCESSOR_SCRIPTS)
+    # Necessary variables:
+    # WebCore_SDP_PROCESSOR_SCRIPTS containing the JavaScript sources list
+    # WebCore_SDP_PROCESSOR_SCRIPTS_DEPENDENCIES containing the source file that will load the scripts to add the proper
+    #   dependency and having them built at the right moment
+
+    add_custom_command(
+        OUTPUT ${DERIVED_SOURCES_WEBCORE_DIR}/SDPProcessorScriptsData.cpp ${DERIVED_SOURCES_WEBCORE_DIR}/SDPProcessorScripts.h
+        MAIN_DEPENDENCY ${WEBCORE_DIR}/Scripts/make-js-file-arrays.py
+        DEPENDS ${WebCore_SDP_PROCESSOR_SCRIPTS}
+        COMMAND "PYTHONPATH=${JavaScriptCore_SCRIPTS_DIR}" ${PYTHON_EXECUTABLE} ${WEBCORE_DIR}/Scripts/make-js-file-arrays.py ${DERIVED_SOURCES_WEBCORE_DIR}/SDPProcessorScripts.h ${DERIVED_SOURCES_WEBCORE_DIR}/SDPProcessorScriptsData.cpp ${WebCore_SDP_PROCESSOR_SCRIPTS}
+        VERBATIM)
+    list(APPEND WebCore_SOURCES ${DERIVED_SOURCES_WEBCORE_DIR}/SDPProcessorScriptsData.cpp)
+    ADD_SOURCE_WEBCORE_DERIVED_DEPENDENCIES(${WebCore_SDP_PROCESSOR_SCRIPTS_DEPENDENCIES} SDPProcessorScriptsData.cpp SDPProcessorScripts.h)
+endif ()
+
 # Generate plug-in resources
 add_custom_command(
     OUTPUT ${DERIVED_SOURCES_WEBCORE_DIR}/PlugInsResourcesData.cpp ${DERIVED_SOURCES_WEBCORE_DIR}/PlugInsResources.h
 # Generate plug-in resources
 add_custom_command(
     OUTPUT ${DERIVED_SOURCES_WEBCORE_DIR}/PlugInsResourcesData.cpp ${DERIVED_SOURCES_WEBCORE_DIR}/PlugInsResources.h
index c1bcef0..92a821e 100644 (file)
@@ -1,3 +1,107 @@
+2016-03-07  Adam Bergkvist  <adam.bergkvist@ericsson.com>
+
+        WebRTC: Implement MediaEndpointPeerConnection::createOffer()
+        https://bugs.webkit.org/show_bug.cgi?id=154867
+
+        Reviewed by Eric Carlson and Jer Noble.
+
+        - MediaEndpointPeerConnection: Initial implementation of createOffer()
+        added. createOffer() is split up into a synchronous part, and a
+        scheduled task. The task will be deferred until information, requiring
+        some amount of work, such as the DTLS fingerprint is available. Other
+        async API functions will also follow this pattern.
+
+        - SDPProcessor (added): The SDPProcessors parses SDP to a
+        MediaEndpointSessionConfiguration object and generates SDP in the
+        reverse direction. Any SDP string handling is confined to the
+        SDPProcessor and all configuration of the media session is done via the
+        MediaEndpointSessionConfiguration object.
+
+        The SDP parser and generator logic is implemented in JavaScript and
+        works with JSON (SDP->JSON, JSON->SDP). The SDPProcessor runs JS in an
+        isolated scope and converts JSON to a MediaEndpointSessionConfiguration
+        object and the reverse. Using JSON signaling (nonstandard) can be
+        helpful during debugging.
+
+        - MockMediaEndpoint (added): Mock MediaEndpoint implementation with
+        support for generating offers. DTLS information, such as fingerprint,
+        is hard coded to facilitate testing with expected values.
+
+        Test: fast/mediastream/RTCPeerConnection-inspect-offer.html
+
+        The test is currently skipped on the mac port until support to read the
+        SDPProcessor JavaScript resource is added.
+
+        * CMakeLists.txt:
+        * Modules/mediastream/MediaEndpointPeerConnection.cpp:
+        (WebCore::WrappedSessionDescriptionPromise::create):
+        (WebCore::WrappedSessionDescriptionPromise::promise):
+        (WebCore::WrappedSessionDescriptionPromise::WrappedSessionDescriptionPromise):
+        (WebCore::randomString):
+        (WebCore::MediaEndpointPeerConnection::MediaEndpointPeerConnection):
+        (WebCore::MediaEndpointPeerConnection::runTask):
+        (WebCore::MediaEndpointPeerConnection::startRunningTasks):
+        (WebCore::MediaEndpointPeerConnection::createOffer):
+        (WebCore::MediaEndpointPeerConnection::createOfferTask):
+        (WebCore::MediaEndpointPeerConnection::gotDtlsFingerprint):
+        * Modules/mediastream/MediaEndpointPeerConnection.h:
+        * Modules/mediastream/SDPProcessor.cpp: Added.
+        (WebCore::SDPProcessor::SDPProcessor):
+        (WebCore::createCandidateObject):
+        (WebCore::createCandidate):
+        (WebCore::configurationFromJSON):
+        (WebCore::iceCandidateFromJSON):
+        (WebCore::configurationToJSON):
+        (WebCore::iceCandidateToJSON):
+        (WebCore::SDPProcessor::generate):
+        (WebCore::SDPProcessor::parse):
+        (WebCore::SDPProcessor::generateCandidateLine):
+        (WebCore::SDPProcessor::parseCandidateLine):
+        (WebCore::SDPProcessor::callScript):
+        * Modules/mediastream/SDPProcessor.h: Added.
+        * Modules/mediastream/sdp.js: Added.
+        (match):
+        (addDefaults):
+        (fillTemplate):
+        (SDP.parse):
+        (SDP.generate):
+        (SDP.generateCandidateLine):
+        (hasAllProperties):
+        (SDP.verifyObject):
+        (generate):
+        (parse):
+        (generateCandidateLine):
+        (parseCandidateLine):
+        * PlatformGTK.cmake:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/mediastream/MediaEndpoint.cpp:
+        (WebCore::createMediaEndpoint):
+        * platform/mediastream/MediaEndpoint.h:
+        * platform/mediastream/PeerMediaDescription.h:
+        * platform/mediastream/SDPProcessorScriptResource.cpp: Added.
+        (WebCore::SDPProcessorScriptResource::scriptString):
+        * platform/mediastream/SDPProcessorScriptResource.h: Added.
+        * platform/mediastream/gtk/SDPProcessorScriptResourceGtk.cpp: Added.
+        (WebCore::SDPProcessorScriptResource::scriptString):
+        * platform/mock/MockMediaEndpoint.cpp: Added.
+        (WebCore::MockMediaEndpoint::create):
+        (WebCore::MockMediaEndpoint::MockMediaEndpoint):
+        (WebCore::MockMediaEndpoint::~MockMediaEndpoint):
+        (WebCore::MockMediaEndpoint::setConfiguration):
+        (WebCore::MockMediaEndpoint::generateDtlsInfo):
+        (WebCore::MockMediaEndpoint::getDefaultAudioPayloads):
+        (WebCore::MockMediaEndpoint::getDefaultVideoPayloads):
+        (WebCore::MockMediaEndpoint::updateReceiveConfiguration):
+        (WebCore::MockMediaEndpoint::updateSendConfiguration):
+        (WebCore::MockMediaEndpoint::addRemoteCandidate):
+        (WebCore::MockMediaEndpoint::replaceSendSource):
+        (WebCore::MockMediaEndpoint::stop):
+        * platform/mock/MockMediaEndpoint.h: Added.
+        * testing/Internals.cpp:
+        (WebCore::Internals::Internals):
+        (WebCore::Internals::enableMockMediaEndpoint):
+        * testing/Internals.h:
+
 2016-03-07  Daniel Bates  <dabates@apple.com>
 
         CSP: object-src directive should prohibit creation of nested browsing context
 2016-03-07  Daniel Bates  <dabates@apple.com>
 
         CSP: object-src directive should prohibit creation of nested browsing context
index ed683d4..8ee3008 100644 (file)
 
 #include "DOMError.h"
 #include "JSDOMError.h"
 
 #include "DOMError.h"
 #include "JSDOMError.h"
+#include "JSRTCSessionDescription.h"
+#include "MediaEndpointSessionConfiguration.h"
+#include "MediaStreamTrack.h"
+#include "RTCOfferAnswerOptions.h"
+#include "RTCRtpSender.h"
+#include "SDPProcessor.h"
 #include <wtf/MainThread.h>
 #include <wtf/MainThread.h>
+#include <wtf/text/Base64.h>
 
 namespace WebCore {
 
 
 namespace WebCore {
 
@@ -48,18 +55,114 @@ static std::unique_ptr<PeerConnectionBackend> createMediaEndpointPeerConnection(
 
 CreatePeerConnectionBackend PeerConnectionBackend::create = createMediaEndpointPeerConnection;
 
 
 CreatePeerConnectionBackend PeerConnectionBackend::create = createMediaEndpointPeerConnection;
 
+class WrappedSessionDescriptionPromise : public RefCounted<WrappedSessionDescriptionPromise> {
+public:
+    static Ref<WrappedSessionDescriptionPromise> create(SessionDescriptionPromise&& promise)
+    {
+        return *adoptRef(new WrappedSessionDescriptionPromise(WTFMove(promise)));
+    }
+
+    SessionDescriptionPromise& promise() { return m_promise; }
+
+private:
+    WrappedSessionDescriptionPromise(SessionDescriptionPromise&& promise)
+        : m_promise(WTFMove(promise))
+    { }
+
+    SessionDescriptionPromise m_promise;
+};
+
+static String randomString(size_t length)
+{
+    const size_t size = ceil(length * 3 / 4);
+    unsigned char randomValues[size];
+    cryptographicallyRandomValues(randomValues, size);
+    return base64Encode(randomValues, size);
+}
+
 MediaEndpointPeerConnection::MediaEndpointPeerConnection(PeerConnectionBackendClient* client)
 MediaEndpointPeerConnection::MediaEndpointPeerConnection(PeerConnectionBackendClient* client)
+    : m_client(client)
+    , m_sdpProcessor(std::unique_ptr<SDPProcessor>(new SDPProcessor(m_client->scriptExecutionContext())))
+    , m_cname(randomString(16))
+    , m_iceUfrag(randomString(4))
+    , m_icePassword(randomString(22))
+{
+    m_mediaEndpoint = MediaEndpoint::create(*this);
+    ASSERT(m_mediaEndpoint);
+
+    m_defaultAudioPayloads = m_mediaEndpoint->getDefaultAudioPayloads();
+    m_defaultVideoPayloads = m_mediaEndpoint->getDefaultVideoPayloads();
+
+    // Tasks (see runTask()) will be deferred until we get the DTLS fingerprint.
+    m_mediaEndpoint->generateDtlsInfo();
+}
+
+void MediaEndpointPeerConnection::runTask(std::function<void()> task)
+{
+    if (m_dtlsFingerprint.isNull()) {
+        // Only one task needs to be deferred since it will hold off any others until completed.
+        ASSERT(!m_initialDeferredTask);
+        m_initialDeferredTask = task;
+    } else
+        callOnMainThread(task);
+}
+
+void MediaEndpointPeerConnection::startRunningTasks()
 {
 {
-    UNUSED_PARAM(client);
+    if (!m_initialDeferredTask)
+        return;
+
+    m_initialDeferredTask();
+    m_initialDeferredTask = nullptr;
 }
 
 void MediaEndpointPeerConnection::createOffer(RTCOfferOptions& options, SessionDescriptionPromise&& promise)
 {
 }
 
 void MediaEndpointPeerConnection::createOffer(RTCOfferOptions& options, SessionDescriptionPromise&& promise)
 {
-    UNUSED_PARAM(options);
+    const RefPtr<RTCOfferOptions> protectedOptions = &options;
+    RefPtr<WrappedSessionDescriptionPromise> wrappedPromise = WrappedSessionDescriptionPromise::create(WTFMove(promise));
 
 
-    notImplemented();
+    runTask([this, protectedOptions, wrappedPromise]() {
+        createOfferTask(*protectedOptions, wrappedPromise->promise());
+    });
+}
 
 
-    promise.reject(DOMError::create("NotSupportedError"));
+void MediaEndpointPeerConnection::createOfferTask(RTCOfferOptions&, SessionDescriptionPromise& promise)
+{
+    ASSERT(!m_dtlsFingerprint.isEmpty());
+
+    RefPtr<MediaEndpointSessionConfiguration> configurationSnapshot = MediaEndpointSessionConfiguration::create();
+
+    configurationSnapshot->setSessionVersion(m_sdpSessionVersion++);
+
+    RtpSenderVector senders = m_client->getSenders();
+
+    // Add media descriptions for senders.
+    for (auto& sender : senders) {
+        RefPtr<PeerMediaDescription> mediaDescription = PeerMediaDescription::create();
+        MediaStreamTrack* track = sender->track();
+
+        mediaDescription->setMediaStreamId(sender->mediaStreamIds()[0]);
+        mediaDescription->setMediaStreamTrackId(track->id());
+        mediaDescription->setType(track->kind());
+        mediaDescription->setPayloads(track->kind() == "audio" ? m_defaultAudioPayloads : m_defaultVideoPayloads);
+        mediaDescription->setDtlsFingerprintHashFunction(m_dtlsFingerprintFunction);
+        mediaDescription->setDtlsFingerprint(m_dtlsFingerprint);
+        mediaDescription->setCname(m_cname);
+        mediaDescription->addSsrc(cryptographicallyRandomNumber());
+        mediaDescription->setIceUfrag(m_iceUfrag);
+        mediaDescription->setIcePassword(m_icePassword);
+
+        configurationSnapshot->addMediaDescription(WTFMove(mediaDescription));
+    }
+
+    String sdpString;
+    SDPProcessor::Result result = m_sdpProcessor->generate(*configurationSnapshot, sdpString);
+    if (result != SDPProcessor::Result::Success) {
+        LOG_ERROR("SDPProcessor internal error");
+        return;
+    }
+
+    promise.resolve(RTCSessionDescription::create("offer", sdpString));
 }
 
 void MediaEndpointPeerConnection::createAnswer(RTCAnswerOptions& options, SessionDescriptionPromise&& promise)
 }
 
 void MediaEndpointPeerConnection::createAnswer(RTCAnswerOptions& options, SessionDescriptionPromise&& promise)
@@ -179,10 +282,10 @@ void MediaEndpointPeerConnection::gotDtlsFingerprint(const String& fingerprint,
 {
     ASSERT(isMainThread());
 
 {
     ASSERT(isMainThread());
 
-    UNUSED_PARAM(fingerprint);
-    UNUSED_PARAM(fingerprintFunction);
+    m_dtlsFingerprint = fingerprint;
+    m_dtlsFingerprintFunction = fingerprintFunction;
 
 
-    notImplemented();
+    startRunningTasks();
 }
 
 void MediaEndpointPeerConnection::gotIceCandidate(unsigned mdescIndex, RefPtr<IceCandidate>&& candidate)
 }
 
 void MediaEndpointPeerConnection::gotIceCandidate(unsigned mdescIndex, RefPtr<IceCandidate>&& candidate)
index f6d256a..f15e75e 100644 (file)
@@ -42,6 +42,9 @@
 namespace WebCore {
 
 class MediaStreamTrack;
 namespace WebCore {
 
 class MediaStreamTrack;
+class SDPProcessor;
+
+typedef Vector<RefPtr<RTCRtpSender>> RtpSenderVector;
 
 class MediaEndpointPeerConnection : public PeerConnectionBackend, public MediaEndpointClient {
 public:
 
 class MediaEndpointPeerConnection : public PeerConnectionBackend, public MediaEndpointClient {
 public:
@@ -74,11 +77,33 @@ public:
     void clearNegotiationNeededState() override { notImplemented(); };
 
 private:
     void clearNegotiationNeededState() override { notImplemented(); };
 
 private:
+    void runTask(std::function<void()>);
+    void startRunningTasks();
+
+    void createOfferTask(RTCOfferOptions&, PeerConnection::SessionDescriptionPromise&);
+
     // MediaEndpointClient
     void gotDtlsFingerprint(const String& fingerprint, const String& fingerprintFunction) override;
     void gotIceCandidate(unsigned mdescIndex, RefPtr<IceCandidate>&&) override;
     void doneGatheringCandidates(unsigned mdescIndex) override;
     void gotRemoteSource(unsigned mdescIndex, RefPtr<RealtimeMediaSource>&&) override;
     // MediaEndpointClient
     void gotDtlsFingerprint(const String& fingerprint, const String& fingerprintFunction) override;
     void gotIceCandidate(unsigned mdescIndex, RefPtr<IceCandidate>&&) override;
     void doneGatheringCandidates(unsigned mdescIndex) override;
     void gotRemoteSource(unsigned mdescIndex, RefPtr<RealtimeMediaSource>&&) override;
+
+    PeerConnectionBackendClient* m_client;
+    std::unique_ptr<MediaEndpoint> m_mediaEndpoint;
+
+    std::function<void()> m_initialDeferredTask;
+
+    std::unique_ptr<SDPProcessor> m_sdpProcessor;
+
+    Vector<RefPtr<MediaPayload>> m_defaultAudioPayloads;
+    Vector<RefPtr<MediaPayload>> m_defaultVideoPayloads;
+
+    String m_cname;
+    String m_iceUfrag;
+    String m_icePassword;
+    String m_dtlsFingerprint;
+    String m_dtlsFingerprintFunction;
+    unsigned m_sdpSessionVersion { 0 };
 };
 
 } // namespace WebCore
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/Modules/mediastream/SDPProcessor.cpp b/Source/WebCore/Modules/mediastream/SDPProcessor.cpp
new file mode 100644 (file)
index 0000000..44f2294
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2015, 2016 Ericsson AB. 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 name of Ericsson 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
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(MEDIA_STREAM)
+#include "SDPProcessor.h"
+
+#include "Document.h"
+#include "Frame.h"
+#include "SDPProcessorScriptResource.h"
+#include "ScriptController.h"
+#include "ScriptGlobalObject.h"
+#include "ScriptSourceCode.h"
+#include "inspector/InspectorValues.h"
+#include <bindings/ScriptObject.h>
+#include <wtf/NeverDestroyed.h>
+
+using namespace Inspector;
+
+namespace WebCore {
+
+#define STRING_FUNCTION(name) \
+    static const String& name##String() \
+    { \
+        static NeverDestroyed<const String> name { ASCIILiteral(#name) }; \
+        return name; \
+    }
+
+STRING_FUNCTION(address)
+STRING_FUNCTION(apt)
+STRING_FUNCTION(candidates)
+STRING_FUNCTION(ccmfir)
+STRING_FUNCTION(channels)
+STRING_FUNCTION(clockRate)
+STRING_FUNCTION(cname)
+STRING_FUNCTION(componentId)
+STRING_FUNCTION(dtls)
+STRING_FUNCTION(encodingName)
+STRING_FUNCTION(fingerprint)
+STRING_FUNCTION(fingerprintHashFunction)
+STRING_FUNCTION(foundation)
+STRING_FUNCTION(ice)
+STRING_FUNCTION(mediaDescriptions)
+STRING_FUNCTION(mediaStreamId)
+STRING_FUNCTION(mediaStreamTrackId)
+STRING_FUNCTION(mode)
+STRING_FUNCTION(mux)
+STRING_FUNCTION(nack)
+STRING_FUNCTION(nackpli)
+STRING_FUNCTION(originator)
+STRING_FUNCTION(packetizationMode)
+STRING_FUNCTION(parameters)
+STRING_FUNCTION(password)
+STRING_FUNCTION(payloads)
+STRING_FUNCTION(port)
+STRING_FUNCTION(priority)
+STRING_FUNCTION(relatedAddress)
+STRING_FUNCTION(relatedPort)
+STRING_FUNCTION(rtcp)
+STRING_FUNCTION(rtcpAddress)
+STRING_FUNCTION(rtcpPort)
+STRING_FUNCTION(rtxTime)
+STRING_FUNCTION(sessionId)
+STRING_FUNCTION(sessionVersion)
+STRING_FUNCTION(setup)
+STRING_FUNCTION(ssrcs)
+STRING_FUNCTION(tcpType)
+STRING_FUNCTION(transport)
+STRING_FUNCTION(type)
+STRING_FUNCTION(ufrag)
+
+SDPProcessor::SDPProcessor(ScriptExecutionContext* context)
+    : ContextDestructionObserver(context)
+{
+}
+
+// Note that MediaEndpointSessionConfiguration is a "flatter" structure that the JSON representation. For
+// example, the JSON representation has an "ice" object which collects a set of properties under a
+// namespace. MediaEndpointSessionConfiguration has "ice"-prefixes on the corresponding properties.
+
+static RefPtr<InspectorObject> createCandidateObject(const IceCandidate& candidate)
+{
+    RefPtr<InspectorObject> candidateObject = InspectorObject::create();
+
+    candidateObject->setString(typeString(), candidate.type());
+    candidateObject->setString(foundationString(), candidate.foundation());
+    candidateObject->setInteger(componentIdString(), candidate.componentId());
+    candidateObject->setString(transportString(), candidate.transport());
+    candidateObject->setInteger(priorityString(), candidate.priority());
+    candidateObject->setString(addressString(), candidate.address());
+    candidateObject->setInteger(portString(), candidate.port());
+    if (!candidate.tcpType().isEmpty())
+        candidateObject->setString(tcpTypeString(), candidate.tcpType());
+    if (candidate.type().convertToASCIIUppercase() != "HOST") {
+        candidateObject->setString(relatedAddressString(), candidate.relatedAddress());
+        candidateObject->setInteger(relatedPortString(), candidate.relatedPort());
+    }
+
+    return candidateObject;
+}
+
+static RefPtr<IceCandidate> createCandidate(const InspectorObject& candidateObject)
+{
+    RefPtr<IceCandidate> candidate = IceCandidate::create();
+    String stringValue;
+    unsigned intValue;
+
+    if (candidateObject.getString(typeString(), stringValue))
+        candidate->setType(stringValue);
+
+    if (candidateObject.getString(foundationString(), stringValue))
+        candidate->setFoundation(stringValue);
+
+    if (candidateObject.getInteger(componentIdString(), intValue))
+        candidate->setComponentId(intValue);
+
+    if (candidateObject.getString(transportString(), stringValue))
+        candidate->setTransport(stringValue);
+
+    if (candidateObject.getInteger(priorityString(), intValue))
+        candidate->setPriority(intValue);
+
+    if (candidateObject.getString(addressString(), stringValue))
+        candidate->setAddress(stringValue);
+
+    if (candidateObject.getInteger(portString(), intValue))
+        candidate->setPort(intValue);
+
+    if (candidateObject.getString(tcpTypeString(), stringValue))
+        candidate->setTcpType(stringValue);
+
+    if (candidateObject.getString(relatedAddressString(), stringValue))
+        candidate->setRelatedAddress(stringValue);
+
+    if (candidateObject.getInteger(relatedPortString(), intValue))
+        candidate->setRelatedPort(intValue);
+
+    return candidate;
+}
+
+static RefPtr<MediaEndpointSessionConfiguration> configurationFromJSON(const String& json)
+{
+    RefPtr<InspectorValue> value;
+    if (!InspectorValue::parseJSON(json, value))
+        return nullptr;
+
+    RefPtr<InspectorObject> object;
+    if (!value->asObject(object))
+        return nullptr;
+
+    RefPtr<MediaEndpointSessionConfiguration> configuration = MediaEndpointSessionConfiguration::create();
+
+    String stringValue;
+    unsigned intValue;
+    unsigned long longValue;
+    bool boolValue;
+
+    RefPtr<InspectorObject> originatorObject = InspectorObject::create();
+    if (object->getObject(originatorString(), originatorObject)) {
+        if (originatorObject->getInteger(sessionIdString(), longValue))
+            configuration->setSessionId(longValue);
+        if (originatorObject->getInteger(sessionVersionString(), intValue))
+            configuration->setSessionVersion(intValue);
+    }
+
+    RefPtr<InspectorArray> mediaDescriptionsArray = InspectorArray::create();
+    object->getArray(mediaDescriptionsString(), mediaDescriptionsArray);
+
+    for (unsigned i = 0; i < mediaDescriptionsArray->length(); ++i) {
+        RefPtr<InspectorObject> mediaDescriptionObject = InspectorObject::create();
+        mediaDescriptionsArray->get(i)->asObject(mediaDescriptionObject);
+
+        RefPtr<PeerMediaDescription> mediaDescription = PeerMediaDescription::create();
+
+        if (mediaDescriptionObject->getString(typeString(), stringValue))
+            mediaDescription->setType(stringValue);
+
+        if (mediaDescriptionObject->getInteger(portString(), intValue))
+            mediaDescription->setPort(intValue);
+
+        if (mediaDescriptionObject->getString(addressString(), stringValue))
+            mediaDescription->setAddress(stringValue);
+
+        if (mediaDescriptionObject->getString(modeString(), stringValue))
+            mediaDescription->setMode(stringValue);
+
+        RefPtr<InspectorArray> payloadsArray = InspectorArray::create();
+        mediaDescriptionObject->getArray(payloadsString(), payloadsArray);
+
+        for (unsigned j = 0; j < payloadsArray->length(); ++j) {
+            RefPtr<InspectorObject> payloadsObject = InspectorObject::create();
+            payloadsArray->get(j)->asObject(payloadsObject);
+
+            RefPtr<MediaPayload> payload = MediaPayload::create();
+
+            if (payloadsObject->getInteger(typeString(), intValue))
+                payload->setType(intValue);
+
+            if (payloadsObject->getString(encodingNameString(), stringValue))
+                payload->setEncodingName(stringValue);
+
+            if (payloadsObject->getInteger(clockRateString(), intValue))
+                payload->setClockRate(intValue);
+
+            if (payloadsObject->getInteger(channelsString(), intValue))
+                payload->setChannels(intValue);
+
+            if (payloadsObject->getBoolean(ccmfirString(), boolValue))
+                payload->setCcmfir(boolValue);
+
+            if (payloadsObject->getBoolean(nackpliString(), boolValue))
+                payload->setNackpli(boolValue);
+
+            if (payloadsObject->getBoolean(nackString(), boolValue))
+                payload->setNack(boolValue);
+
+            RefPtr<InspectorObject> parametersObject = InspectorObject::create();
+            if (payloadsObject->getObject(parametersString(), parametersObject)) {
+                if (parametersObject->getInteger(packetizationModeString(), intValue))
+                    payload->addParameter("packetizationMode", intValue);
+
+                if (parametersObject->getInteger(aptString(), intValue))
+                    payload->addParameter("apt", intValue);
+
+                if (parametersObject->getInteger(rtxTimeString(), intValue))
+                    payload->addParameter("rtxTime", intValue);
+            }
+
+            mediaDescription->addPayload(WTFMove(payload));
+        }
+
+        RefPtr<InspectorObject> rtcpObject = InspectorObject::create();
+        if (mediaDescriptionObject->getObject(rtcpString(), rtcpObject)) {
+            if (rtcpObject->getBoolean(muxString(), boolValue))
+                mediaDescription->setRtcpMux(boolValue);
+
+            if (rtcpObject->getString(rtcpAddressString(), stringValue))
+                mediaDescription->setRtcpAddress(stringValue);
+
+            if (rtcpObject->getInteger(rtcpPortString(), intValue))
+                mediaDescription->setRtcpPort(intValue);
+        }
+
+        if (mediaDescriptionObject->getString(mediaStreamIdString(), stringValue))
+            mediaDescription->setMediaStreamId(stringValue);
+
+        if (mediaDescriptionObject->getString(mediaStreamTrackIdString(), stringValue))
+            mediaDescription->setMediaStreamTrackId(stringValue);
+
+        RefPtr<InspectorObject> dtlsObject = InspectorObject::create();
+        if (mediaDescriptionObject->getObject(dtlsString(), dtlsObject)) {
+            if (dtlsObject->getString(setupString(), stringValue))
+                mediaDescription->setDtlsSetup(stringValue);
+
+            if (dtlsObject->getString(fingerprintHashFunctionString(), stringValue))
+                mediaDescription->setDtlsFingerprintHashFunction(stringValue);
+
+            if (dtlsObject->getString(fingerprintString(), stringValue))
+                mediaDescription->setDtlsFingerprint(stringValue);
+        }
+
+        RefPtr<InspectorArray> ssrcsArray = InspectorArray::create();
+        mediaDescriptionObject->getArray(ssrcsString(), ssrcsArray);
+
+        for (unsigned j = 0; j < ssrcsArray->length(); ++j) {
+            ssrcsArray->get(j)->asInteger(intValue);
+            mediaDescription->addSsrc(intValue);
+        }
+
+        if (mediaDescriptionObject->getString(cnameString(), stringValue))
+            mediaDescription->setCname(stringValue);
+
+        RefPtr<InspectorObject> iceObject = InspectorObject::create();
+        if (mediaDescriptionObject->getObject(iceString(), iceObject)) {
+            if (iceObject->getString(ufragString(), stringValue))
+                mediaDescription->setIceUfrag(stringValue);
+
+            if (iceObject->getString(passwordString(), stringValue))
+                mediaDescription->setIcePassword(stringValue);
+
+            RefPtr<InspectorArray> candidatesArray = InspectorArray::create();
+            iceObject->getArray(candidatesString(), candidatesArray);
+
+            for (unsigned j = 0; j < candidatesArray->length(); ++j) {
+                RefPtr<InspectorObject> candidateObject = InspectorObject::create();
+                candidatesArray->get(j)->asObject(candidateObject);
+
+                mediaDescription->addIceCandidate(createCandidate(*candidateObject));
+            }
+        }
+
+        configuration->addMediaDescription(WTFMove(mediaDescription));
+    }
+
+    return configuration;
+}
+
+static RefPtr<IceCandidate> iceCandidateFromJSON(const String& json)
+{
+    RefPtr<InspectorValue> value;
+    if (!InspectorValue::parseJSON(json, value))
+        return nullptr;
+
+    RefPtr<InspectorObject> candidateObject;
+    if (!value->asObject(candidateObject))
+        return nullptr;
+
+    return createCandidate(*candidateObject);
+}
+
+static String configurationToJSON(const MediaEndpointSessionConfiguration& configuration)
+{
+    RefPtr<InspectorObject> object = InspectorObject::create();
+
+    RefPtr<InspectorObject> originatorObject = InspectorObject::create();
+    originatorObject->setDouble(sessionIdString(), configuration.sessionId());
+    originatorObject->setInteger(sessionVersionString(), configuration.sessionVersion());
+    object->setObject(originatorString(), originatorObject);
+
+    RefPtr<InspectorArray> mediaDescriptionsArray = InspectorArray::create();
+
+    for (const RefPtr<PeerMediaDescription>& mediaDescription : configuration.mediaDescriptions()) {
+        RefPtr<InspectorObject> mediaDescriptionObject = InspectorObject::create();
+
+        mediaDescriptionObject->setString(typeString(), mediaDescription->type());
+        mediaDescriptionObject->setInteger(portString(), mediaDescription->port());
+        mediaDescriptionObject->setString(addressString(), mediaDescription->address());
+        mediaDescriptionObject->setString(modeString(), mediaDescription->mode());
+
+        RefPtr<InspectorArray> payloadsArray = InspectorArray::create();
+
+        for (RefPtr<MediaPayload> payload : mediaDescription->payloads()) {
+            RefPtr<InspectorObject> payloadObject = InspectorObject::create();
+
+            payloadObject->setInteger(typeString(), payload->type());
+            payloadObject->setString(encodingNameString(), payload->encodingName());
+            payloadObject->setInteger(clockRateString(), payload->clockRate());
+            payloadObject->setInteger(channelsString(), payload->channels());
+            payloadObject->setBoolean(ccmfirString(), payload->ccmfir());
+            payloadObject->setBoolean(nackpliString(), payload->nackpli());
+            payloadObject->setBoolean(nackString(), payload->nack());
+
+            if (!payload->parameters().isEmpty()) {
+                RefPtr<InspectorObject> parametersObject = InspectorObject::create();
+
+                for (auto& name : payload->parameters().keys())
+                    parametersObject->setInteger(name, payload->parameters().get(name));
+
+                payloadObject->setObject(parametersString(), parametersObject);
+            }
+
+            payloadsArray->pushObject(payloadObject);
+        }
+        mediaDescriptionObject->setArray(payloadsString(), payloadsArray);
+
+        RefPtr<InspectorObject> rtcpObject = InspectorObject::create();
+        rtcpObject->setBoolean(muxString(), mediaDescription->rtcpMux());
+        rtcpObject->setString(addressString(), mediaDescription->rtcpAddress());
+        rtcpObject->setInteger(portString(), mediaDescription->rtcpPort());
+        mediaDescriptionObject->setObject(rtcpString(), rtcpObject);
+
+        mediaDescriptionObject->setString(mediaStreamIdString(), mediaDescription->mediaStreamId());
+        mediaDescriptionObject->setString(mediaStreamTrackIdString(), mediaDescription->mediaStreamTrackId());
+
+        RefPtr<InspectorObject> dtlsObject = InspectorObject::create();
+        dtlsObject->setString(setupString(), mediaDescription->dtlsSetup());
+        dtlsObject->setString(fingerprintHashFunctionString(), mediaDescription->dtlsFingerprintHashFunction());
+        dtlsObject->setString(fingerprintString(), mediaDescription->dtlsFingerprint());
+        mediaDescriptionObject->setObject(dtlsString(), dtlsObject);
+
+        RefPtr<InspectorArray> ssrcsArray = InspectorArray::create();
+
+        for (auto ssrc : mediaDescription->ssrcs())
+            ssrcsArray->pushDouble(ssrc);
+        mediaDescriptionObject->setArray(ssrcsString(), ssrcsArray);
+
+        mediaDescriptionObject->setString(cnameString(), mediaDescription->cname());
+
+        RefPtr<InspectorObject> iceObject = InspectorObject::create();
+        iceObject->setString(ufragString(), mediaDescription->iceUfrag());
+        iceObject->setString(passwordString(), mediaDescription->icePassword());
+
+        RefPtr<InspectorArray> candidatesArray = InspectorArray::create();
+
+        for (RefPtr<IceCandidate> candidate : mediaDescription->iceCandidates())
+            candidatesArray->pushObject(createCandidateObject(*candidate));
+
+        iceObject->setArray(candidatesString(), candidatesArray);
+        mediaDescriptionObject->setObject(iceString(), iceObject);
+
+        mediaDescriptionsArray->pushObject(mediaDescriptionObject);
+    }
+    object->setArray(mediaDescriptionsString(), mediaDescriptionsArray);
+
+    return object->toJSONString();
+}
+
+static String iceCandidateToJSON(const IceCandidate& candidate)
+{
+    return createCandidateObject(candidate)->toJSONString();
+}
+
+SDPProcessor::Result SDPProcessor::generate(const MediaEndpointSessionConfiguration& configuration, String& outSdpString) const
+{
+    String sdpString;
+    if (!callScript("generate", configurationToJSON(configuration), sdpString))
+        return Result::InternalError;
+
+    outSdpString = sdpString;
+    return Result::Success;
+}
+
+SDPProcessor::Result SDPProcessor::parse(const String& sdp, RefPtr<MediaEndpointSessionConfiguration>& outConfiguration) const
+{
+    String scriptOutput;
+    if (!callScript("parse", sdp, scriptOutput))
+        return Result::InternalError;
+
+    if (scriptOutput == "ParseError")
+        return Result::ParseError;
+
+    RefPtr<MediaEndpointSessionConfiguration> configuration = configurationFromJSON(scriptOutput);
+    if (!configuration)
+        return Result::InternalError;
+
+    outConfiguration = configuration;
+    return Result::Success;
+}
+
+SDPProcessor::Result SDPProcessor::generateCandidateLine(const IceCandidate& candidate, String& outCandidateLine) const
+{
+    String candidateLine;
+    if (!callScript("generateCandidateLine", iceCandidateToJSON(candidate), candidateLine))
+        return Result::InternalError;
+
+    outCandidateLine = candidateLine;
+    return Result::Success;
+}
+
+SDPProcessor::Result SDPProcessor::parseCandidateLine(const String& candidateLine, RefPtr<IceCandidate>& outCandidate) const
+{
+    String scriptOutput;
+    if (!callScript("parseCandidateLine", candidateLine, scriptOutput))
+        return Result::InternalError;
+
+    if (scriptOutput == "ParseError")
+        return Result::ParseError;
+
+    RefPtr<IceCandidate> candidate = iceCandidateFromJSON(scriptOutput);
+    if (!candidate)
+        return Result::InternalError;
+
+    outCandidate = candidate;
+    return Result::Success;
+}
+
+bool SDPProcessor::callScript(const String& functionName, const String& argument, String& outResult) const
+{
+    if (!scriptExecutionContext())
+        return false;
+
+    Document* document = downcast<Document>(scriptExecutionContext());
+    if (!document->frame())
+        return false;
+
+    if (!m_isolatedWorld)
+        m_isolatedWorld = DOMWrapperWorld::create(JSDOMWindow::commonVM());
+
+    ScriptController& scriptController = document->frame()->script();
+    JSDOMGlobalObject* globalObject = JSC::jsCast<JSDOMGlobalObject*>(scriptController.globalObject(*m_isolatedWorld));
+    JSC::ExecState* exec = globalObject->globalExec();
+    JSC::JSLockHolder lock(exec);
+
+    JSC::JSValue probeFunctionValue = globalObject->get(exec, JSC::Identifier::fromString(exec, "generate"));
+    if (!probeFunctionValue.isFunction()) {
+        URL scriptURL;
+        scriptController.evaluateInWorld(ScriptSourceCode(SDPProcessorScriptResource::scriptString(), scriptURL), *m_isolatedWorld);
+        if (exec->hadException()) {
+            exec->clearException();
+            return false;
+        }
+    }
+
+    JSC::JSValue functionValue = globalObject->get(exec, JSC::Identifier::fromString(exec, functionName));
+    if (!functionValue.isFunction())
+        return false;
+
+    JSC::JSObject* function = functionValue.toObject(exec);
+    JSC::CallData callData;
+    JSC::CallType callType = function->methodTable()->getCallData(function, callData);
+    if (callType == JSC::CallType::None)
+        return false;
+
+    JSC::MarkedArgumentBuffer argList;
+    argList.append(JSC::jsString(exec, argument));
+
+    JSC::JSValue result = JSC::call(exec, function, callType, callData, globalObject, argList);
+    if (exec->hadException()) {
+        LOG_ERROR("SDPProcessor script threw in function %s", functionName.ascii().data());
+        exec->clearException();
+        return false;
+    }
+
+    if (!result.isString())
+        return false;
+
+    outResult = result.getString(exec);
+    return true;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/Modules/mediastream/SDPProcessor.h b/Source/WebCore/Modules/mediastream/SDPProcessor.h
new file mode 100644 (file)
index 0000000..23b415e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 Ericsson AB. 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 name of Ericsson 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
+ * OWNER 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.
+ */
+
+#ifndef SDPProcessor_h
+#define SDPProcessor_h
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "ContextDestructionObserver.h"
+#include "IceCandidate.h"
+#include "MediaEndpointSessionConfiguration.h"
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class DOMWrapperWorld;
+class ScriptExecutionContext;
+
+class SDPProcessor : public ContextDestructionObserver {
+public:
+    enum class Result {
+        Success = 1,
+        InternalError = 2,
+        ParseError = 3
+    };
+
+    SDPProcessor(ScriptExecutionContext*);
+
+    Result generate(const MediaEndpointSessionConfiguration&, String& outSdpString) const;
+    Result parse(const String& sdp, RefPtr<MediaEndpointSessionConfiguration>&) const;
+
+    Result generateCandidateLine(const IceCandidate&, String& outCandidateLine) const;
+    Result parseCandidateLine(const String& candidateLine, RefPtr<IceCandidate>&) const;
+
+private:
+    bool callScript(const String& functionName, const String& argument, String& outResult) const;
+
+    mutable RefPtr<DOMWrapperWorld> m_isolatedWorld;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
+
+#endif // SDPProcessor_h
diff --git a/Source/WebCore/Modules/mediastream/sdp.js b/Source/WebCore/Modules/mediastream/sdp.js
new file mode 100644 (file)
index 0000000..24fc88c
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * Copyright (C) 2014-2015 Ericsson AB. 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.
+ *
+ * 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
+ * OWNER 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.
+ */
+
+"use strict";
+
+if (typeof(SDP) == "undefined")
+    var SDP = {};
+
+(function () {
+    var regexps = {
+        "vline": "^v=([\\d]+).*$",
+        "oline": "^o=([\\w\\-@\\.]+) ([\\d]+) ([\\d]+) IN (IP[46]) ([\\d\\.a-f\\:]+).*$",
+        "sline": "^s=(.*)$",
+        "tline": "^t=([\\d]+) ([\\d]+).*$",
+        "cline": "^c=IN (IP[46]) ([\\d\\.a-f\\:]+).*$",
+        "msidsemantic": "^a=msid-semantic: *WMS .*$",
+        "mblock": "^m=(audio|video|application) ([\\d]+) ([A-Z/]+)([\\d ]*)$\\r?\\n",
+        "mode": "^a=(sendrecv|sendonly|recvonly|inactive).*$",
+        "rtpmap": "^a=rtpmap:${type} ([\\w\\-]+)/([\\d]+)/?([\\d]+)?.*$",
+        "fmtp": "^a=fmtp:${type} ([\\w\\-=;]+).*$",
+        "param": "([\\w\\-]+)=([\\w\\-]+);?",
+        "nack": "^a=rtcp-fb:${type} nack$",
+        "nackpli": "^a=rtcp-fb:${type} nack pli$",
+        "ccmfir": "^a=rtcp-fb:${type} ccm fir$",
+        "ericscream": "^a=rtcp-fb:${type} ericscream$",
+        "rtcp": "^a=rtcp:([\\d]+)( IN (IP[46]) ([\\d\\.a-f\\:]+))?.*$",
+        "rtcpmux": "^a=rtcp-mux.*$",
+        "cname": "^a=ssrc:(\\d+) cname:([\\w+/\\-@\\.\\{\\}]+).*$",
+        "msid": "^a=(ssrc:\\d+ )?msid:([\\w+/\\-=]+) +([\\w+/\\-=]+).*$",
+        "ufrag": "^a=ice-ufrag:([\\w+/]*).*$",
+        "pwd": "^a=ice-pwd:([\\w+/]*).*$",
+        "candidate": "^a=candidate:(\\d+) (\\d) (UDP|TCP) ([\\d\\.]*) ([\\d\\.a-f\\:]*) (\\d*)" +
+            " typ ([a-z]*)( raddr ([\\d\\.a-f\\:]*) rport (\\d*))?" +
+            "( tcptype (active|passive|so))?.*$",
+        "fingerprint": "^a=fingerprint:(sha-1|sha-256) ([A-Fa-f\\d\:]+).*$",
+        "setup": "^a=setup:(actpass|active|passive).*$",
+        "sctpmap": "^a=sctpmap:${port} ([\\w\\-]+)( [\\d]+)?.*$"
+    };
+
+    var templates = {
+        "sdp":
+            "v=${version}\r\n" +
+            "o=${username} ${sessionId} ${sessionVersion} ${netType} ${addressType} ${address}\r\n" +
+            "s=${sessionName}\r\n" +
+            "t=${startTime} ${stopTime}\r\n" +
+            "${msidsemanticLine}",
+
+        "msidsemantic": "a=msid-semantic:WMS ${mediaStreamIds}\r\n",
+
+        "mblock":
+            "m=${type} ${port} ${protocol} ${fmt}\r\n" +
+            "c=${netType} ${addressType} ${address}\r\n" +
+            "${rtcpLine}" +
+            "${rtcpMuxLine}" +
+            "a=${mode}\r\n" +
+            "${rtpMapLines}" +
+            "${fmtpLines}" +
+            "${nackLines}" +
+            "${nackpliLines}" +
+            "${ccmfirLines}" +
+            "${ericScreamLines}" +
+            "${cnameLines}" +
+            "${msidLines}" +
+            "${iceCredentialLines}" +
+            "${candidateLines}" +
+            "${dtlsFingerprintLine}" +
+            "${dtlsSetupLine}" +
+            "${sctpmapLine}",
+
+        "rtcp": "a=rtcp:${port}${[ ]netType}${[ ]addressType}${[ ]address}\r\n",
+        "rtcpMux": "a=rtcp-mux\r\n",
+
+        "rtpMap": "a=rtpmap:${type} ${encodingName}/${clockRate}${[/]channels}\r\n",
+        "fmtp": "a=fmtp:${type} ${parameters}\r\n",
+        "nack": "a=rtcp-fb:${type} nack\r\n",
+        "nackpli": "a=rtcp-fb:${type} nack pli\r\n",
+        "ccmfir": "a=rtcp-fb:${type} ccm fir\r\n",
+        "ericscream": "a=rtcp-fb:${type} ericscream\r\n",
+
+        "cname": "a=ssrc:${ssrc} cname:${cname}\r\n",
+        "msid": "a=msid:${mediaStreamId} ${mediaStreamTrackId}\r\n",
+
+        "iceCredentials":
+            "a=ice-ufrag:${ufrag}\r\n" +
+            "a=ice-pwd:${password}\r\n",
+
+        "candidate":
+            "a=candidate:${foundation} ${componentId} ${transport} ${priority} ${address} ${port}" +
+            " typ ${type}${[ raddr ]relatedAddress}${[ rport ]relatedPort}${[ tcptype ]tcpType}\r\n",
+
+        "dtlsFingerprint": "a=fingerprint:${fingerprintHashFunction} ${fingerprint}\r\n",
+        "dtlsSetup": "a=setup:${setup}\r\n",
+
+        "sctpmap": "a=sctpmap:${port} ${app}${[ ]streams}\r\n"
+    };
+
+    function match(data, pattern, flags, alt) {
+        var r = new RegExp(pattern, flags);
+        return data.match(r) || alt && alt.match(r) || null;
+    }
+
+    function addDefaults(obj, defaults) {
+        for (var p in defaults) {
+            if (!defaults.hasOwnProperty(p))
+                continue;
+            if (typeof(obj[p]) == "undefined")
+                obj[p] = defaults[p];
+        }
+    }
+
+    function fillTemplate(template, info) {
+        var text = template;
+        for (var p in info) {
+            if (!info.hasOwnProperty(p))
+                continue;
+            var r = new RegExp("\\${(\\[[^\\]]+\\])?" + p + "(\\[[^\\]]+\\])?}");
+            text = text.replace(r, function (_, prefix, suffix) {
+                if (!info[p] && info[p] != 0)
+                    return "";
+                prefix = prefix ? prefix.substr(1, prefix.length - 2) : "";
+                suffix = suffix ? suffix.substr(1, suffix.length - 2) : "";
+                return prefix + info[p] + suffix;
+            });
+        }
+        return text;
+    }
+
+    SDP.parse = function (sdpText) {
+        sdpText = new String(sdpText);
+        var sdpObj = {};
+        var parts = sdpText.split(new RegExp(regexps.mblock, "m")) || [sdpText];
+        var sblock = parts.shift();
+        var version = parseInt((match(sblock, regexps.vline, "m") || [])[1]);
+        if (!isNaN(version))
+            sdpObj.version = version;
+        var originator = match(sblock, regexps.oline, "m");;
+        if (originator) {
+            sdpObj.originator = {
+                "username": originator[1],
+                "sessionId": originator[2],
+                "sessionVersion": parseInt(originator[3]),
+                "netType": "IN",
+                "addressType": originator[4],
+                "address": originator[5]
+            };
+        }
+        var sessionName = match(sblock, regexps.sline, "m");
+        if (sessionName)
+            sdpObj.sessionName = sessionName[1];
+        var sessionTime = match(sblock, regexps.tline, "m");
+        if (sessionTime) {
+            sdpObj.startTime = parseInt(sessionTime[1]);
+            sdpObj.stopTime = parseInt(sessionTime[2]);
+        }
+        var hasMediaStreamId = !!match(sblock, regexps.msidsemantic, "m");
+        sdpObj.mediaDescriptions = [];
+
+        for (var i = 0; i < parts.length; i += 5) {
+            var mediaDescription = {
+                "type": parts[i],
+                "port": parseInt(parts[i + 1]),
+                "protocol": parts[i + 2],
+            };
+            var fmt = parts[i + 3].replace(/^[\s\uFEFF\xA0]+/, '')
+                .split(/ +/)
+                .map(function (x) {
+                    return parseInt(x);
+                });
+            var mblock = parts[i + 4];
+
+            var connection = match(mblock, regexps.cline, "m", sblock);
+            if (connection) {
+                mediaDescription.netType = "IN";
+                mediaDescription.addressType = connection[1];
+                mediaDescription.address = connection[2];
+            }
+            var mode = match(mblock, regexps.mode, "m", sblock);
+            if (mode)
+                mediaDescription.mode = mode[1];
+
+            var payloadTypes = [];
+            if (match(mediaDescription.protocol, "(UDP/TLS)?RTP/S?AVPF?")) {
+                mediaDescription.payloads = [];
+                payloadTypes = fmt;
+            }
+            payloadTypes.forEach(function (payloadType) {
+                var payload = { "type": payloadType };
+                var rtpmapLine = fillTemplate(regexps.rtpmap, payload);
+                var rtpmap = match(mblock, rtpmapLine, "m");
+                if (rtpmap) {
+                    payload.encodingName = rtpmap[1];
+                    payload.clockRate = parseInt(rtpmap[2]);
+                    if (mediaDescription.type == "audio")
+                        payload.channels = parseInt(rtpmap[3]) || 1;
+                    else if (mediaDescription.type == "video") {
+                        var nackLine = fillTemplate(regexps.nack, payload);
+                        payload.nack = !!match(mblock, nackLine, "m");
+                        var nackpliLine = fillTemplate(regexps.nackpli, payload);
+                        payload.nackpli = !!match(mblock, nackpliLine, "m");
+                        var ccmfirLine = fillTemplate(regexps.ccmfir, payload);
+                        payload.ccmfir = !!match(mblock, ccmfirLine, "m");
+                        var ericScreamLine = fillTemplate(regexps.ericscream, payload);
+                        payload.ericscream = !!match(mblock, ericScreamLine, "m");
+                    }
+                } else if (payloadType == 0 || payloadType == 8) {
+                    payload.encodingName = payloadType == 8 ? "PCMA" : "PCMU";
+                    payload.clockRate = 8000;
+                    payload.channels = 1;
+                }
+                var fmtpLine = fillTemplate(regexps.fmtp, payload);
+                var fmtp = match(mblock, fmtpLine, "m");
+                if (fmtp) {
+                    payload.parameters = {};
+                    fmtp[1].replace(new RegExp(regexps.param, "g"),
+                        function(_, key, value) {
+                            key = key.replace(/-([a-z])/g, function (_, c) {
+                                return c.toUpperCase();
+                            });
+                            payload.parameters[key] = isNaN(+value) ? value : +value;
+                    });
+                }
+                mediaDescription.payloads.push(payload);
+            });
+
+            var rtcp = match(mblock, regexps.rtcp, "m");
+            if (rtcp) {
+                mediaDescription.rtcp = {
+                    "netType": "IN",
+                    "port": parseInt(rtcp[1])
+                };
+                if (rtcp[2]) {
+                    mediaDescription.rtcp.addressType = rtcp[3];
+                    mediaDescription.rtcp.address = rtcp[4];
+                }
+            }
+            var rtcpmux = match(mblock, regexps.rtcpmux, "m", sblock);
+            if (rtcpmux) {
+                if (!mediaDescription.rtcp)
+                    mediaDescription.rtcp = {};
+                mediaDescription.rtcp.mux = true;
+            }
+
+            var cnameLines = match(mblock, regexps.cname, "mg");
+            if (cnameLines) {
+                mediaDescription.ssrcs = [];
+                cnameLines.forEach(function (line) {
+                    var cname = match(line, regexps.cname, "m");
+                    mediaDescription.ssrcs.push(parseInt(cname[1]));
+                    if (!mediaDescription.cname)
+                        mediaDescription.cname = cname[2];
+                });
+            }
+
+            if (hasMediaStreamId) {
+                var msid = match(mblock, regexps.msid, "m");
+                if (msid) {
+                    mediaDescription.mediaStreamId = msid[2];
+                    mediaDescription.mediaStreamTrackId = msid[3];
+                }
+            }
+
+            var ufrag = match(mblock, regexps.ufrag, "m", sblock);
+            var pwd = match(mblock, regexps.pwd, "m", sblock);
+            if (ufrag && pwd) {
+                mediaDescription.ice = {
+                    "ufrag": ufrag[1],
+                    "password": pwd[1]
+                };
+            }
+            var candidateLines = match(mblock, regexps.candidate, "mig");
+            if (candidateLines) {
+                if (!mediaDescription.ice)
+                    mediaDescription.ice = {};
+                mediaDescription.ice.candidates = [];
+                candidateLines.forEach(function (line) {
+                    var candidateLine = match(line, regexps.candidate, "mi");
+                    var candidate = {
+                        "foundation": candidateLine[1],
+                        "componentId": parseInt(candidateLine[2]),
+                        "transport": candidateLine[3].toUpperCase(),
+                        "priority": parseInt(candidateLine[4]),
+                        "address": candidateLine[5],
+                        "port": parseInt(candidateLine[6]),
+                        "type": candidateLine[7]
+                    };
+                    if (candidateLine[9])
+                        candidate.relatedAddress = candidateLine[9];
+                    if (!isNaN(candidateLine[10]))
+                        candidate.relatedPort = parseInt(candidateLine[10]);
+                    if (candidateLine[12])
+                        candidate.tcpType = candidateLine[12];
+                    else if (candidate.transport == "TCP") {
+                        if (candidate.port == 0 || candidate.port == 9) {
+                            candidate.tcpType = "active";
+                            candidate.port = 9;
+                        } else {
+                            return;
+                        }
+                    }
+                    mediaDescription.ice.candidates.push(candidate);
+                });
+            }
+
+            var fingerprint = match(mblock, regexps.fingerprint, "mi", sblock);
+            if (fingerprint) {
+                mediaDescription.dtls = {
+                    "fingerprintHashFunction": fingerprint[1].toLowerCase(),
+                    "fingerprint": fingerprint[2].toUpperCase()
+                };
+            }
+            var setup = match(mblock, regexps.setup, "m", sblock);
+            if (setup) {
+                if (!mediaDescription.dtls)
+                    mediaDescription.dtls = {};
+                mediaDescription.dtls.setup = setup[1];
+            }
+
+            if (mediaDescription.protocol == "DTLS/SCTP") {
+                mediaDescription.sctp = {
+                    "port": fmt[0]
+                };
+                var sctpmapLine = fillTemplate(regexps.sctpmap, mediaDescription.sctp);
+                var sctpmap = match(mblock, sctpmapLine, "m");
+                if (sctpmap) {
+                    mediaDescription.sctp.app = sctpmap[1];
+                    if (sctpmap[2])
+                        mediaDescription.sctp.streams = parseInt(sctpmap[2]);
+                }
+            }
+
+            sdpObj.mediaDescriptions.push(mediaDescription);
+        }
+
+        return sdpObj;
+    };
+
+    SDP.generate = function (sdpObj) {
+        sdpObj = JSON.parse(JSON.stringify(sdpObj));
+        addDefaults(sdpObj, {
+            "version": 0,
+            "originator": {},
+            "sessionName": "-",
+            "startTime": 0,
+            "stopTime": 0,
+            "mediaDescriptions": []
+        });
+        addDefaults(sdpObj.originator, {
+            "username": "-",
+            "sessionId": "" + Math.floor((Math.random() + +new Date()) * 1e6),
+            "sessionVersion": 1,
+            "netType": "IN",
+            "addressType": "IP4",
+            "address": "127.0.0.1"
+        });
+        var sdpText = fillTemplate(templates.sdp, sdpObj);
+        sdpText = fillTemplate(sdpText, sdpObj.originator);
+
+        var msidsemanticLine = "";
+        var mediaStreamIds = [];
+        sdpObj.mediaDescriptions.forEach(function (mdesc) {
+            if (mdesc.mediaStreamId && mdesc.mediaStreamTrackId
+                && mediaStreamIds.indexOf(mdesc.mediaStreamId) == -1)
+                mediaStreamIds.push(mdesc.mediaStreamId);
+        });
+        if (mediaStreamIds.length) {
+            var msidsemanticLine = fillTemplate(templates.msidsemantic,
+                { "mediaStreamIds": mediaStreamIds.join(" ") });
+        }
+        sdpText = fillTemplate(sdpText, { "msidsemanticLine": msidsemanticLine });
+
+        sdpObj.mediaDescriptions.forEach(function (mediaDescription) {
+            addDefaults(mediaDescription, {
+                "port": 9,
+                "protocol": "UDP/TLS/RTP/SAVPF",
+                "netType": "IN",
+                "addressType": "IP4",
+                "address": "0.0.0.0",
+                "mode": "sendrecv",
+                "payloads": [],
+                "rtcp": {}
+            });
+            var mblock = fillTemplate(templates.mblock, mediaDescription);
+
+            var payloadInfo = {"rtpMapLines": "", "fmtpLines": "", "nackLines": "",
+                "nackpliLines": "", "ccmfirLines": "", "ericScreamLines": ""};
+            mediaDescription.payloads.forEach(function (payload) {
+                if (payloadInfo.fmt)
+                    payloadInfo.fmt += " " + payload.type;
+                else
+                    payloadInfo.fmt = payload.type;
+                if (!payload.channels || payload.channels == 1)
+                    payload.channels = null;
+                payloadInfo.rtpMapLines += fillTemplate(templates.rtpMap, payload);
+                if (payload.parameters) {
+                    var fmtpInfo = { "type": payload.type, "parameters": "" };
+                    for (var p in payload.parameters) {
+                        var param = p.replace(/([A-Z])([a-z])/g, function (_, a, b) {
+                            return "-" + a.toLowerCase() + b;
+                        });
+                        if (fmtpInfo.parameters)
+                            fmtpInfo.parameters += ";";
+                        fmtpInfo.parameters += param + "=" + payload.parameters[p];
+                    }
+                    payloadInfo.fmtpLines += fillTemplate(templates.fmtp, fmtpInfo);
+                }
+                if (payload.nack)
+                    payloadInfo.nackLines += fillTemplate(templates.nack, payload);
+                if (payload.nackpli)
+                    payloadInfo.nackpliLines += fillTemplate(templates.nackpli, payload);
+                if (payload.ccmfir)
+                    payloadInfo.ccmfirLines += fillTemplate(templates.ccmfir, payload);
+                if (payload.ericscream)
+                    payloadInfo.ericScreamLines += fillTemplate(templates.ericscream, payload);
+            });
+            mblock = fillTemplate(mblock, payloadInfo);
+
+            var rtcpInfo = {"rtcpLine": "", "rtcpMuxLine": ""};
+            if (mediaDescription.rtcp.port) {
+                addDefaults(mediaDescription.rtcp, {
+                    "netType": "IN",
+                    "addressType": "IP4",
+                    "address": ""
+                });
+                if (!mediaDescription.rtcp.address)
+                    mediaDescription.rtcp.netType = mediaDescription.rtcp.addressType = "";
+                rtcpInfo.rtcpLine = fillTemplate(templates.rtcp, mediaDescription.rtcp);
+            }
+            if (mediaDescription.rtcp.mux)
+                rtcpInfo.rtcpMuxLine = templates.rtcpMux;
+            mblock = fillTemplate(mblock, rtcpInfo);
+
+            var srcAttributeLines = { "cnameLines": "", "msidLines": "" };
+            var srcAttributes = {
+                "cname": mediaDescription.cname,
+                "mediaStreamId": mediaDescription.mediaStreamId,
+                "mediaStreamTrackId": mediaDescription.mediaStreamTrackId
+            };
+            if (mediaDescription.cname && mediaDescription.ssrcs) {
+                mediaDescription.ssrcs.forEach(function (ssrc) {
+                    srcAttributes.ssrc = ssrc;
+                    srcAttributeLines.cnameLines += fillTemplate(templates.cname, srcAttributes);
+                    if (mediaDescription.mediaStreamId && mediaDescription.mediaStreamTrackId)
+                        srcAttributeLines.msidLines += fillTemplate(templates.msid, srcAttributes);
+                });
+            } else if (mediaDescription.mediaStreamId && mediaDescription.mediaStreamTrackId) {
+                srcAttributes.ssrc = null;
+                srcAttributeLines.msidLines += fillTemplate(templates.msid, srcAttributes);
+            }
+            mblock = fillTemplate(mblock, srcAttributeLines);
+
+            var iceInfo = {"iceCredentialLines": "", "candidateLines": ""};
+            if (mediaDescription.ice) {
+                iceInfo.iceCredentialLines = fillTemplate(templates.iceCredentials,
+                    mediaDescription.ice);
+                if (mediaDescription.ice.candidates) {
+                    mediaDescription.ice.candidates.forEach(function (candidate) {
+                        addDefaults(candidate, {
+                            "relatedAddress": null,
+                            "relatedPort": null,
+                            "tcpType": null
+                        });
+                        iceInfo.candidateLines += fillTemplate(templates.candidate, candidate);
+                    });
+                }
+            }
+            mblock = fillTemplate(mblock, iceInfo);
+
+            var dtlsInfo = { "dtlsFingerprintLine": "", "dtlsSetupLine": "" };
+            if (mediaDescription.dtls) {
+                if (mediaDescription.dtls.fingerprint) {
+                    dtlsInfo.dtlsFingerprintLine = fillTemplate(templates.dtlsFingerprint,
+                        mediaDescription.dtls);
+                }
+                addDefaults(mediaDescription.dtls, {"setup": "actpass"});
+                dtlsInfo.dtlsSetupLine = fillTemplate(templates.dtlsSetup, mediaDescription.dtls);
+            }
+            mblock = fillTemplate(mblock, dtlsInfo);
+
+            var sctpInfo = {"sctpmapLine": "", "fmt": ""};
+            if (mediaDescription.sctp) {
+                addDefaults(mediaDescription.sctp, {"streams": null});
+                sctpInfo.sctpmapLine = fillTemplate(templates.sctpmap, mediaDescription.sctp);
+                sctpInfo.fmt = mediaDescription.sctp.port;
+            }
+            mblock = fillTemplate(mblock, sctpInfo);
+
+            sdpText += mblock;
+        });
+
+        return sdpText;
+    };
+
+    SDP.generateCandidateLine = function (candidateObj) {
+        addDefaults(candidateObj, {
+            "relatedAddress": null,
+            "relatedPort": null,
+            "tcpType": null
+        });
+
+        return fillTemplate(templates.candidate, candidateObj);
+    };
+
+    var expectedProperties = {
+        "session": [ "version", "originator", "sessionName", "startTime", "stopTime" ],
+        "mline": [ "type", "port", "protocol", "mode", "payloads", "rtcp", "mediaStreamId",
+            "mediaStreamTrackId", "dtls", "ssrcs", "cname", "ice" ],
+        "mlineSubObjects": {
+            "rtcp": [ "mux" ],
+            "ice": [ "ufrag", "password" ],
+            "dtls": [ "setup", "fingerprintHashFunction", "fingerprint" ]
+        }
+    };
+
+    function hasAllProperties(object, properties) {
+        var missing = properties.filter(function (property) {
+            return !object.hasOwnProperty(property);
+        });
+
+        return !missing.length;
+    }
+
+    SDP.verifyObject = function (sdpObj) {
+        if (!hasAllProperties(sdpObj, expectedProperties.session))
+            return false;
+
+        for (var i = 0; i < sdpObj.mediaDescriptions.length; i++) {
+            var mediaDescription = sdpObj.mediaDescriptions[i];
+
+            if (!hasAllProperties(mediaDescription, expectedProperties.mline))
+                return false;
+
+            for (var p in expectedProperties.mlineSubObjects) {
+                if (!hasAllProperties(mediaDescription[p], expectedProperties.mlineSubObjects[p]))
+                    return false;
+            }
+        }
+
+        return true;
+    };
+
+})();
+
+function generate(json) {
+    var object = JSON.parse(json);
+    return SDP.generate(object);
+}
+
+function parse(sdp) {
+    var object = SDP.parse(sdp);
+
+    if (!SDP.verifyObject(object))
+        return "ParseError";
+
+    return JSON.stringify(object);
+}
+
+function generateCandidateLine(json) {
+    var candidate = JSON.parse(json);
+    return SDP.generateCandidateLine(candidate).substr(2);
+}
+
+function parseCandidateLine(candidateLine) {
+    var mdesc = SDP.parse("m=application 0 NONE\r\na=" + candidateLine + "\r\n").mediaDescriptions[0];
+    if (!mdesc.ice)
+        return "ParseError";
+
+    return JSON.stringify(mdesc.ice.candidates[0]);
+}
+
+if (typeof(module) != "undefined" && typeof(exports) != "undefined")
+    module.exports = SDP;
index 819f5eb..e6c87b2 100644 (file)
@@ -44,6 +44,7 @@ list(APPEND WebCore_INCLUDE_DIRECTORIES
     "${WEBCORE_DIR}/platform/graphics/opentype"
     "${WEBCORE_DIR}/platform/graphics/wayland"
     "${WEBCORE_DIR}/platform/graphics/x11"
     "${WEBCORE_DIR}/platform/graphics/opentype"
     "${WEBCORE_DIR}/platform/graphics/wayland"
     "${WEBCORE_DIR}/platform/graphics/x11"
+    "${WEBCORE_DIR}/platform/mediastream/gtk"
     "${WEBCORE_DIR}/platform/mock/mediasource"
     "${WEBCORE_DIR}/platform/network/gtk"
     "${WEBCORE_DIR}/platform/network/soup"
     "${WEBCORE_DIR}/platform/mock/mediasource"
     "${WEBCORE_DIR}/platform/network/gtk"
     "${WEBCORE_DIR}/platform/network/soup"
@@ -154,6 +155,8 @@ list(APPEND WebCore_SOURCES
 
     platform/image-decoders/cairo/ImageDecoderCairo.cpp
 
 
     platform/image-decoders/cairo/ImageDecoderCairo.cpp
 
+    platform/mediastream/gtk/SDPProcessorScriptResourceGtk.cpp
+
     platform/network/gtk/CredentialBackingStore.cpp
 
     platform/network/soup/AuthenticationChallengeSoup.cpp
     platform/network/gtk/CredentialBackingStore.cpp
 
     platform/network/soup/AuthenticationChallengeSoup.cpp
@@ -248,6 +251,9 @@ set(WebCore_USER_AGENT_SCRIPTS
 
 set(WebCore_USER_AGENT_SCRIPTS_DEPENDENCIES ${WEBCORE_DIR}/platform/gtk/RenderThemeGtk.cpp)
 
 
 set(WebCore_USER_AGENT_SCRIPTS_DEPENDENCIES ${WEBCORE_DIR}/platform/gtk/RenderThemeGtk.cpp)
 
+set(WebCore_SDP_PROCESSOR_SCRIPTS ${WEBCORE_DIR}/Modules/mediastream/sdp.js)
+set(WebCore_SDP_PROCESSOR_SCRIPTS_DEPENDENCIES ${WEBCORE_DIR}/platform/mediastream/gtk/SDPProcessorScriptResource.cpp)
+
 list(APPEND WebCore_LIBRARIES
     ${ATK_LIBRARIES}
     ${CAIRO_LIBRARIES}
 list(APPEND WebCore_LIBRARIES
     ${ATK_LIBRARIES}
     ${CAIRO_LIBRARIES}
index 3f972b8..8622a4d 100644 (file)
                5E2C43741BCF0D750001E2BC /* JSRTCRtpSender.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43701BCF0D690001E2BC /* JSRTCRtpSender.h */; };
                5E2C437B1BCF9A570001E2BC /* RTCPeerConnectionBuiltins.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43761BCF9A0B0001E2BC /* RTCPeerConnectionBuiltins.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5E2C437C1BCF9A840001E2BC /* RTCPeerConnectionInternalsBuiltins.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43791BCF9A0B0001E2BC /* RTCPeerConnectionInternalsBuiltins.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5E2C43741BCF0D750001E2BC /* JSRTCRtpSender.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43701BCF0D690001E2BC /* JSRTCRtpSender.h */; };
                5E2C437B1BCF9A570001E2BC /* RTCPeerConnectionBuiltins.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43761BCF9A0B0001E2BC /* RTCPeerConnectionBuiltins.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5E2C437C1BCF9A840001E2BC /* RTCPeerConnectionInternalsBuiltins.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43791BCF9A0B0001E2BC /* RTCPeerConnectionInternalsBuiltins.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               5EA3D6DF1C859D7F00300BBB /* MockMediaEndpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 5EA3D6DE1C859D5300300BBB /* MockMediaEndpoint.h */; };
+               5EA3D6E01C859D8400300BBB /* MockMediaEndpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EA3D6DD1C859D5300300BBB /* MockMediaEndpoint.cpp */; };
+               5EA3D6E31C859DC100300BBB /* SDPProcessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EA3D6E11C859DAA00300BBB /* SDPProcessor.cpp */; };
+               5EA3D6E41C859DC100300BBB /* SDPProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 5EA3D6E21C859DAA00300BBB /* SDPProcessor.h */; };
+               5EA3D6E71C85A9DB00300BBB /* SDPProcessorScriptResource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EA3D6E51C85A9C300300BBB /* SDPProcessorScriptResource.cpp */; };
+               5EA3D6E81C85A9DB00300BBB /* SDPProcessorScriptResource.h in Headers */ = {isa = PBXBuildFile; fileRef = 5EA3D6E61C85A9C300300BBB /* SDPProcessorScriptResource.h */; };
                5EA725D21ACABD4700EAD17B /* MediaDevices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EA725CD1ACABCD900EAD17B /* MediaDevices.cpp */; };
                5EA725D31ACABD4700EAD17B /* MediaDevices.h in Headers */ = {isa = PBXBuildFile; fileRef = 5EA725CE1ACABCD900EAD17B /* MediaDevices.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5EA725D51ACABD5700EAD17B /* NavigatorMediaDevices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EA725CA1ACABCB500EAD17B /* NavigatorMediaDevices.cpp */; };
                5EA725D21ACABD4700EAD17B /* MediaDevices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EA725CD1ACABCD900EAD17B /* MediaDevices.cpp */; };
                5EA725D31ACABD4700EAD17B /* MediaDevices.h in Headers */ = {isa = PBXBuildFile; fileRef = 5EA725CE1ACABCD900EAD17B /* MediaDevices.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5EA725D51ACABD5700EAD17B /* NavigatorMediaDevices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EA725CA1ACABCB500EAD17B /* NavigatorMediaDevices.cpp */; };
                5E2C43761BCF9A0B0001E2BC /* RTCPeerConnectionBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCPeerConnectionBuiltins.h; sourceTree = "<group>"; };
                5E2C43781BCF9A0B0001E2BC /* RTCPeerConnectionInternalsBuiltins.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RTCPeerConnectionInternalsBuiltins.cpp; sourceTree = "<group>"; };
                5E2C43791BCF9A0B0001E2BC /* RTCPeerConnectionInternalsBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCPeerConnectionInternalsBuiltins.h; sourceTree = "<group>"; };
                5E2C43761BCF9A0B0001E2BC /* RTCPeerConnectionBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCPeerConnectionBuiltins.h; sourceTree = "<group>"; };
                5E2C43781BCF9A0B0001E2BC /* RTCPeerConnectionInternalsBuiltins.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RTCPeerConnectionInternalsBuiltins.cpp; sourceTree = "<group>"; };
                5E2C43791BCF9A0B0001E2BC /* RTCPeerConnectionInternalsBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCPeerConnectionInternalsBuiltins.h; sourceTree = "<group>"; };
+               5EA3D6DD1C859D5300300BBB /* MockMediaEndpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockMediaEndpoint.cpp; sourceTree = "<group>"; };
+               5EA3D6DE1C859D5300300BBB /* MockMediaEndpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockMediaEndpoint.h; sourceTree = "<group>"; };
+               5EA3D6E11C859DAA00300BBB /* SDPProcessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SDPProcessor.cpp; sourceTree = "<group>"; };
+               5EA3D6E21C859DAA00300BBB /* SDPProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDPProcessor.h; sourceTree = "<group>"; };
+               5EA3D6E51C85A9C300300BBB /* SDPProcessorScriptResource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SDPProcessorScriptResource.cpp; sourceTree = "<group>"; };
+               5EA3D6E61C85A9C300300BBB /* SDPProcessorScriptResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDPProcessorScriptResource.h; sourceTree = "<group>"; };
                5EA725CA1ACABCB500EAD17B /* NavigatorMediaDevices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NavigatorMediaDevices.cpp; sourceTree = "<group>"; };
                5EA725CB1ACABCB500EAD17B /* NavigatorMediaDevices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NavigatorMediaDevices.h; sourceTree = "<group>"; };
                5EA725CC1ACABCB500EAD17B /* NavigatorMediaDevices.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = NavigatorMediaDevices.idl; sourceTree = "<group>"; };
                5EA725CA1ACABCB500EAD17B /* NavigatorMediaDevices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NavigatorMediaDevices.cpp; sourceTree = "<group>"; };
                5EA725CB1ACABCB500EAD17B /* NavigatorMediaDevices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NavigatorMediaDevices.h; sourceTree = "<group>"; };
                5EA725CC1ACABCB500EAD17B /* NavigatorMediaDevices.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = NavigatorMediaDevices.idl; sourceTree = "<group>"; };
                                5E2C43641BCEE3720001E2BC /* RTCTrackEvent.cpp */,
                                5E2C43651BCEE3720001E2BC /* RTCTrackEvent.h */,
                                5E2C43661BCEE3720001E2BC /* RTCTrackEvent.idl */,
                                5E2C43641BCEE3720001E2BC /* RTCTrackEvent.cpp */,
                                5E2C43651BCEE3720001E2BC /* RTCTrackEvent.h */,
                                5E2C43661BCEE3720001E2BC /* RTCTrackEvent.idl */,
+                               5EA3D6E11C859DAA00300BBB /* SDPProcessor.cpp */,
+                               5EA3D6E21C859DAA00300BBB /* SDPProcessor.h */,
                                076306D417E149CF005A7C4E /* SourceInfo.cpp */,
                                076306D517E149CF005A7C4E /* SourceInfo.h */,
                                076306D617E149CF005A7C4E /* SourceInfo.idl */,
                                076306D417E149CF005A7C4E /* SourceInfo.cpp */,
                                076306D517E149CF005A7C4E /* SourceInfo.h */,
                                076306D617E149CF005A7C4E /* SourceInfo.idl */,
                                07221BAE17CF0AD400848E51 /* RTCStatsRequest.h */,
                                07221BAF17CF0AD400848E51 /* RTCStatsResponseBase.h */,
                                07221BB017CF0AD400848E51 /* RTCVoidRequest.h */,
                                07221BAE17CF0AD400848E51 /* RTCStatsRequest.h */,
                                07221BAF17CF0AD400848E51 /* RTCStatsResponseBase.h */,
                                07221BB017CF0AD400848E51 /* RTCVoidRequest.h */,
+                               5EA3D6E51C85A9C300300BBB /* SDPProcessorScriptResource.cpp */,
+                               5EA3D6E61C85A9C300300BBB /* SDPProcessorScriptResource.h */,
                                070E81D01BF27656001FDA48 /* VideoTrackPrivateMediaStream.h */,
                        );
                        path = mediastream;
                                070E81D01BF27656001FDA48 /* VideoTrackPrivateMediaStream.h */,
                        );
                        path = mediastream;
                                077B64151B95F703003E9AD5 /* MediaPlaybackTargetMock.h */,
                                077B64101B94F12E003E9AD5 /* MediaPlaybackTargetPickerMock.cpp */,
                                077B64111B94F12E003E9AD5 /* MediaPlaybackTargetPickerMock.h */,
                                077B64151B95F703003E9AD5 /* MediaPlaybackTargetMock.h */,
                                077B64101B94F12E003E9AD5 /* MediaPlaybackTargetPickerMock.cpp */,
                                077B64111B94F12E003E9AD5 /* MediaPlaybackTargetPickerMock.h */,
+                               5EA3D6DD1C859D5300300BBB /* MockMediaEndpoint.cpp */,
+                               5EA3D6DE1C859D5300300BBB /* MockMediaEndpoint.h */,
                                07D6A4F11BED5F8800174146 /* MockRealtimeAudioSource.cpp */,
                                07D6A4F21BED5F8800174146 /* MockRealtimeAudioSource.h */,
                                07D6A4ED1BECF2D200174146 /* MockRealtimeMediaSource.cpp */,
                                07D6A4F11BED5F8800174146 /* MockRealtimeAudioSource.cpp */,
                                07D6A4F21BED5F8800174146 /* MockRealtimeAudioSource.h */,
                                07D6A4ED1BECF2D200174146 /* MockRealtimeMediaSource.cpp */,
                                85E711A60AC5D5350053270F /* DOMHTMLDocumentInternal.h in Headers */,
                                85DF2EED0AA387CB00AD64C5 /* DOMHTMLElement.h in Headers */,
                                85E711A70AC5D5350053270F /* DOMHTMLElementInternal.h in Headers */,
                                85E711A60AC5D5350053270F /* DOMHTMLDocumentInternal.h in Headers */,
                                85DF2EED0AA387CB00AD64C5 /* DOMHTMLElement.h in Headers */,
                                85E711A70AC5D5350053270F /* DOMHTMLElementInternal.h in Headers */,
+                               5EA3D6DF1C859D7F00300BBB /* MockMediaEndpoint.h in Headers */,
                                8540756A0AD6CBF900620C57 /* DOMHTMLEmbedElement.h in Headers */,
                                855247D00AD850B80012093B /* DOMHTMLEmbedElementInternal.h in Headers */,
                                85BA4CDF0AA6861B0088052D /* DOMHTMLFieldSetElement.h in Headers */,
                                8540756A0AD6CBF900620C57 /* DOMHTMLEmbedElement.h in Headers */,
                                855247D00AD850B80012093B /* DOMHTMLEmbedElementInternal.h in Headers */,
                                85BA4CDF0AA6861B0088052D /* DOMHTMLFieldSetElement.h in Headers */,
                                31C0FF4C0E4CEFDD007D6FE5 /* DOMWebKitTransitionEvent.h in Headers */,
                                31C0FF4E0E4CEFDD007D6FE5 /* DOMWebKitTransitionEventInternal.h in Headers */,
                                85C7F5E70AAFBAFB004014DD /* DOMWheelEvent.h in Headers */,
                                31C0FF4C0E4CEFDD007D6FE5 /* DOMWebKitTransitionEvent.h in Headers */,
                                31C0FF4E0E4CEFDD007D6FE5 /* DOMWebKitTransitionEventInternal.h in Headers */,
                                85C7F5E70AAFBAFB004014DD /* DOMWheelEvent.h in Headers */,
+                               5EA3D6E41C859DC100300BBB /* SDPProcessor.h in Headers */,
                                85989DD10ACC8BBD00A0BC51 /* DOMWheelEventInternal.h in Headers */,
                                1403B99709EB13AF00797C7F /* DOMWindow.h in Headers */,
                                FC9A0F75164094CF003D6B8D /* DOMWindowCSS.h in Headers */,
                                85989DD10ACC8BBD00A0BC51 /* DOMWheelEventInternal.h in Headers */,
                                1403B99709EB13AF00797C7F /* DOMWindow.h in Headers */,
                                FC9A0F75164094CF003D6B8D /* DOMWindowCSS.h in Headers */,
                                CD5E5B5F1A15CE54000C609E /* PageConfiguration.h in Headers */,
                                F3820893147D35F90010BC06 /* PageConsoleAgent.h in Headers */,
                                DAED203116F244480070EC0F /* PageConsoleClient.h in Headers */,
                                CD5E5B5F1A15CE54000C609E /* PageConfiguration.h in Headers */,
                                F3820893147D35F90010BC06 /* PageConsoleAgent.h in Headers */,
                                DAED203116F244480070EC0F /* PageConsoleClient.h in Headers */,
+                               5EA3D6E81C85A9DB00300BBB /* SDPProcessorScriptResource.h in Headers */,
                                A5A2AF0C1829734300DE1729 /* PageDebuggable.h in Headers */,
                                F34742DD134362F000531BC2 /* PageDebuggerAgent.h in Headers */,
                                9302B0BF0D79F82C00C7EE83 /* PageGroup.h in Headers */,
                                A5A2AF0C1829734300DE1729 /* PageDebuggable.h in Headers */,
                                F34742DD134362F000531BC2 /* PageDebuggerAgent.h in Headers */,
                                9302B0BF0D79F82C00C7EE83 /* PageGroup.h in Headers */,
                                BC4918C60BFEA050009D6316 /* JSHTMLFrameElement.cpp in Sources */,
                                BC2ED7A50C6C0F3600920BFF /* JSHTMLFrameElementCustom.cpp in Sources */,
                                BC926F800C0552470082776B /* JSHTMLFrameSetElement.cpp in Sources */,
                                BC4918C60BFEA050009D6316 /* JSHTMLFrameElement.cpp in Sources */,
                                BC2ED7A50C6C0F3600920BFF /* JSHTMLFrameElementCustom.cpp in Sources */,
                                BC926F800C0552470082776B /* JSHTMLFrameSetElement.cpp in Sources */,
+                               5EA3D6E31C859DC100300BBB /* SDPProcessor.cpp in Sources */,
                                BCD41ABB0C060DE800C0E446 /* JSHTMLFrameSetElementCustom.cpp in Sources */,
                                A80E7B140A19D606007FB8C5 /* JSHTMLHeadElement.cpp in Sources */,
                                1AE2AA2E0A1CDAB400B42B25 /* JSHTMLHeadingElement.cpp in Sources */,
                                BCD41ABB0C060DE800C0E446 /* JSHTMLFrameSetElementCustom.cpp in Sources */,
                                A80E7B140A19D606007FB8C5 /* JSHTMLHeadElement.cpp in Sources */,
                                1AE2AA2E0A1CDAB400B42B25 /* JSHTMLHeadingElement.cpp in Sources */,
                                5E2C43671BCEE3770001E2BC /* RTCTrackEvent.cpp in Sources */,
                                5824ABA21AE81116009074B7 /* RubyElement.cpp in Sources */,
                                5824ABA61AE81384009074B7 /* RubyTextElement.cpp in Sources */,
                                5E2C43671BCEE3770001E2BC /* RTCTrackEvent.cpp in Sources */,
                                5824ABA21AE81116009074B7 /* RubyElement.cpp in Sources */,
                                5824ABA61AE81384009074B7 /* RubyTextElement.cpp in Sources */,
+                               5EA3D6E71C85A9DB00300BBB /* SDPProcessorScriptResource.cpp in Sources */,
                                A79BADA1161E7F3F00C2E652 /* RuleFeature.cpp in Sources */,
                                A79BADA3161E7F3F00C2E652 /* RuleSet.cpp in Sources */,
                                2D76BB8419456F8100CFD29A /* RunLoopObserver.cpp in Sources */,
                                A79BADA1161E7F3F00C2E652 /* RuleFeature.cpp in Sources */,
                                A79BADA3161E7F3F00C2E652 /* RuleSet.cpp in Sources */,
                                2D76BB8419456F8100CFD29A /* RunLoopObserver.cpp in Sources */,
                                0FC4E40E187F82E10045882C /* ScrollingCoordinatorIOS.mm in Sources */,
                                1AF62EE614DA22A70041556C /* ScrollingCoordinatorMac.mm in Sources */,
                                93C38BFE164473C700091EB2 /* ScrollingStateFixedNode.cpp in Sources */,
                                0FC4E40E187F82E10045882C /* ScrollingCoordinatorIOS.mm in Sources */,
                                1AF62EE614DA22A70041556C /* ScrollingCoordinatorMac.mm in Sources */,
                                93C38BFE164473C700091EB2 /* ScrollingStateFixedNode.cpp in Sources */,
+                               5EA3D6E01C859D8400300BBB /* MockMediaEndpoint.cpp in Sources */,
                                0FEA3E7C191B2FC5000F1B55 /* ScrollingStateFrameScrollingNode.cpp in Sources */,
                                0FA88EBD16A8D1BD00F99984 /* ScrollingStateFrameScrollingNodeMac.mm in Sources */,
                                931CBD0C161A44E900E4C874 /* ScrollingStateNode.cpp in Sources */,
                                0FEA3E7C191B2FC5000F1B55 /* ScrollingStateFrameScrollingNode.cpp in Sources */,
                                0FA88EBD16A8D1BD00F99984 /* ScrollingStateFrameScrollingNodeMac.mm in Sources */,
                                931CBD0C161A44E900E4C874 /* ScrollingStateNode.cpp in Sources */,
index 01fb6c7..2c38660 100644 (file)
@@ -35,7 +35,7 @@
 
 namespace WebCore {
 
 
 namespace WebCore {
 
-static std::unique_ptr<MediaEndpoint> createMediaEndpoint(MediaEndpointClient*)
+static std::unique_ptr<MediaEndpoint> createMediaEndpoint(MediaEndpointClient&)
 {
     return nullptr;
 }
 {
     return nullptr;
 }
index 570688d..612978b 100644 (file)
@@ -54,7 +54,7 @@ public:
     virtual ~MediaEndpointClient() { }
 };
 
     virtual ~MediaEndpointClient() { }
 };
 
-typedef std::unique_ptr<MediaEndpoint> (*CreateMediaEndpoint)(MediaEndpointClient*);
+typedef std::unique_ptr<MediaEndpoint> (*CreateMediaEndpoint)(MediaEndpointClient&);
 
 class MediaEndpoint {
 public:
 
 class MediaEndpoint {
 public:
index ac6c6d4..1c1386d 100644 (file)
@@ -150,20 +150,20 @@ private:
     PeerMediaDescription() { }
 
     String m_type;
     PeerMediaDescription() { }
 
     String m_type;
-    unsigned short m_port { 0 };
-    String m_address;
-    String m_mode;
+    unsigned short m_port { 9 };
+    String m_address { "0.0.0.0" };
+    String m_mode { "sendrecv" };
 
     Vector<RefPtr<MediaPayload>> m_payloads;
 
 
     Vector<RefPtr<MediaPayload>> m_payloads;
 
-    bool m_rtcpMux { false };
+    bool m_rtcpMux { true };
     String m_rtcpAddress;
     unsigned short m_rtcpPort { 0 };
 
     String m_mediaStreamId;
     String m_mediaStreamTrackId;
 
     String m_rtcpAddress;
     unsigned short m_rtcpPort { 0 };
 
     String m_mediaStreamId;
     String m_mediaStreamTrackId;
 
-    String m_dtlsSetup;
+    String m_dtlsSetup { "actpass" };
     String m_dtlsFingerprintHashFunction;
     String m_dtlsFingerprint;
 
     String m_dtlsFingerprintHashFunction;
     String m_dtlsFingerprint;
 
diff --git a/Source/WebCore/platform/mediastream/SDPProcessorScriptResource.cpp b/Source/WebCore/platform/mediastream/SDPProcessorScriptResource.cpp
new file mode 100644 (file)
index 0000000..bcb95ab
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 Ericsson AB. 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 name of Ericsson 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
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(MEDIA_STREAM)
+#include "SDPProcessorScriptResource.h"
+
+namespace WebCore {
+
+namespace SDPProcessorScriptResource {
+
+const String& scriptString()
+{
+    return emptyString();
+}
+
+} // namespace SDPProcessorScriptResource
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mediastream/SDPProcessorScriptResource.h b/Source/WebCore/platform/mediastream/SDPProcessorScriptResource.h
new file mode 100644 (file)
index 0000000..1cdc7c9
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 Ericsson AB. 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 name of Ericsson 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
+ * OWNER 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.
+ */
+
+#ifndef SDPProcessorScriptResource_h
+#define SDPProcessorScriptResource_h
+
+#if ENABLE(MEDIA_STREAM)
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+namespace SDPProcessorScriptResource {
+
+const String& scriptString();
+
+} // namespace SDPProcessorScriptResource
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
+
+#endif // SDPProcessorScriptResource_h
diff --git a/Source/WebCore/platform/mediastream/gtk/SDPProcessorScriptResourceGtk.cpp b/Source/WebCore/platform/mediastream/gtk/SDPProcessorScriptResourceGtk.cpp
new file mode 100644 (file)
index 0000000..ad62806
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 Ericsson AB. 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 name of Ericsson 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
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(MEDIA_STREAM)
+#include "SDPProcessorScriptResource.h"
+
+#include "SDPProcessorScripts.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+namespace SDPProcessorScriptResource {
+
+const String& scriptString()
+{
+    static NeverDestroyed<const String> script = String(sdpJavaScript);
+    return script;
+}
+
+} // namespace SDPProcessorScriptResource
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mock/MockMediaEndpoint.cpp b/Source/WebCore/platform/mock/MockMediaEndpoint.cpp
new file mode 100644 (file)
index 0000000..b1799d7
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2015 Ericsson AB. 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 name of Ericsson 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
+ * OWNER 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(MEDIA_STREAM)
+#include "MockMediaEndpoint.h"
+
+#include "MediaPayload.h"
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+
+static const char* fingerprint = "8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B";
+static const char* fingerprintFunction = "sha-256";
+
+std::unique_ptr<MediaEndpoint> MockMediaEndpoint::create(MediaEndpointClient& client)
+{
+    return std::unique_ptr<MediaEndpoint>(new MockMediaEndpoint(client));
+}
+
+MockMediaEndpoint::MockMediaEndpoint(MediaEndpointClient& client)
+    : m_client(client)
+{
+}
+
+MockMediaEndpoint::~MockMediaEndpoint()
+{
+    stop();
+}
+
+void MockMediaEndpoint::setConfiguration(RefPtr<MediaEndpointConfiguration>&& configuration)
+{
+    UNUSED_PARAM(configuration);
+}
+
+void MockMediaEndpoint::generateDtlsInfo()
+{
+    callOnMainThread([this]() {
+        m_client.gotDtlsFingerprint(String(fingerprint), String(fingerprintFunction));
+    });
+}
+
+Vector<RefPtr<MediaPayload>> MockMediaEndpoint::getDefaultAudioPayloads()
+{
+    Vector<RefPtr<MediaPayload>> payloads;
+
+    RefPtr<MediaPayload> payload = MediaPayload::create();
+    payload->setType(111);
+    payload->setEncodingName("OPUS");
+    payload->setClockRate(48000);
+    payload->setChannels(2);
+    payloads.append(payload);
+
+    payload = MediaPayload::create();
+    payload->setType(8);
+    payload->setEncodingName("PCMA");
+    payload->setClockRate(8000);
+    payload->setChannels(1);
+    payloads.append(payload);
+
+    payload = MediaPayload::create();
+    payload->setType(0);
+    payload->setEncodingName("PCMU");
+    payload->setClockRate(8000);
+    payload->setChannels(1);
+    payloads.append(payload);
+
+    return payloads;
+}
+
+Vector<RefPtr<MediaPayload>> MockMediaEndpoint::getDefaultVideoPayloads()
+{
+    Vector<RefPtr<MediaPayload>> payloads;
+
+    RefPtr<MediaPayload> payload = MediaPayload::create();
+    payload->setType(103);
+    payload->setEncodingName("H264");
+    payload->setClockRate(90000);
+    payload->setCcmfir(true);
+    payload->setNackpli(true);
+    payload->addParameter("packetizationMode", 1);
+    payloads.append(payload);
+
+    payload = MediaPayload::create();
+    payload->setType(100);
+    payload->setEncodingName("VP8");
+    payload->setClockRate(90000);
+    payload->setCcmfir(true);
+    payload->setNackpli(true);
+    payload->setNack(true);
+    payloads.append(payload);
+
+    payload = MediaPayload::create();
+    payload->setType(120);
+    payload->setEncodingName("RTX");
+    payload->setClockRate(90000);
+    payload->addParameter("apt", 100);
+    payload->addParameter("rtxTime", 200);
+    payloads.append(payload);
+
+    return payloads;
+}
+
+MediaEndpoint::UpdateResult MockMediaEndpoint::updateReceiveConfiguration(MediaEndpointSessionConfiguration* configuration, bool isInitiator)
+{
+    UNUSED_PARAM(configuration);
+    UNUSED_PARAM(isInitiator);
+
+    return UpdateResult::Success;
+}
+
+MediaEndpoint::UpdateResult MockMediaEndpoint::updateSendConfiguration(MediaEndpointSessionConfiguration* configuration, bool isInitiator)
+{
+    UNUSED_PARAM(configuration);
+    UNUSED_PARAM(isInitiator);
+
+    return UpdateResult::Success;
+}
+
+void MockMediaEndpoint::addRemoteCandidate(IceCandidate& candidate, unsigned mdescIndex, const String& ufrag, const String& password)
+{
+    UNUSED_PARAM(candidate);
+    UNUSED_PARAM(mdescIndex);
+    UNUSED_PARAM(ufrag);
+    UNUSED_PARAM(password);
+}
+
+void MockMediaEndpoint::replaceSendSource(RealtimeMediaSource& newSource, unsigned mdescIndex)
+{
+    UNUSED_PARAM(newSource);
+    UNUSED_PARAM(mdescIndex);
+}
+
+void MockMediaEndpoint::stop()
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mock/MockMediaEndpoint.h b/Source/WebCore/platform/mock/MockMediaEndpoint.h
new file mode 100644 (file)
index 0000000..87389d1
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 Ericsson AB. 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 name of Ericsson 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
+ * OWNER 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.
+ */
+
+#ifndef MockMediaEndpoint_h
+#define MockMediaEndpoint_h
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "MediaEndpoint.h"
+
+namespace WebCore {
+
+class MockMediaEndpoint : public MediaEndpoint {
+public:
+    WEBCORE_EXPORT static std::unique_ptr<MediaEndpoint> create(MediaEndpointClient&);
+
+    MockMediaEndpoint(MediaEndpointClient&);
+    ~MockMediaEndpoint();
+
+    void setConfiguration(RefPtr<MediaEndpointConfiguration>&&) override;
+
+    void generateDtlsInfo() override;
+    Vector<RefPtr<MediaPayload>> getDefaultAudioPayloads() override;
+    Vector<RefPtr<MediaPayload>> getDefaultVideoPayloads() override;
+
+    UpdateResult updateReceiveConfiguration(MediaEndpointSessionConfiguration*, bool isInitiator) override;
+    UpdateResult updateSendConfiguration(MediaEndpointSessionConfiguration*, bool isInitiator) override;
+
+    void addRemoteCandidate(IceCandidate&, unsigned mdescIndex, const String& ufrag, const String& password) override;
+
+    void replaceSendSource(RealtimeMediaSource&, unsigned mdescIndex) override;
+
+    void stop() override;
+
+private:
+    MediaEndpointClient& m_client;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
+
+#endif // MockMediaEndpoint_h
index 1f0eb8e..d6d034e 100644 (file)
 #endif
 
 #if ENABLE(MEDIA_STREAM)
 #endif
 
 #if ENABLE(MEDIA_STREAM)
+#include "MockMediaEndpoint.h"
 #include "MockRealtimeMediaSourceCenter.h"
 #include "RTCPeerConnection.h"
 #include "RTCPeerConnectionHandlerMock.h"
 #include "MockRealtimeMediaSourceCenter.h"
 #include "RTCPeerConnection.h"
 #include "RTCPeerConnectionHandlerMock.h"
@@ -416,6 +417,7 @@ Internals::Internals(Document* document)
 
 #if ENABLE(MEDIA_STREAM)
     setMockMediaCaptureDevicesEnabled(true);
 
 #if ENABLE(MEDIA_STREAM)
     setMockMediaCaptureDevicesEnabled(true);
+    enableMockMediaEndpoint();
     enableMockRTCPeerConnectionHandler();
 #endif
 
     enableMockRTCPeerConnectionHandler();
 #endif
 
@@ -1016,6 +1018,11 @@ void Internals::enableMockSpeechSynthesizer()
 #endif
 
 #if ENABLE(MEDIA_STREAM)
 #endif
 
 #if ENABLE(MEDIA_STREAM)
+void Internals::enableMockMediaEndpoint()
+{
+    MediaEndpoint::create = MockMediaEndpoint::create;
+}
+
 void Internals::enableMockRTCPeerConnectionHandler()
 {
     RTCPeerConnectionHandler::create = RTCPeerConnectionHandlerMock::create;
 void Internals::enableMockRTCPeerConnectionHandler()
 {
     RTCPeerConnectionHandler::create = RTCPeerConnectionHandlerMock::create;
index 46aeede..f394299 100644 (file)
@@ -370,6 +370,7 @@ public:
 #endif
 
 #if ENABLE(MEDIA_STREAM)
 #endif
 
 #if ENABLE(MEDIA_STREAM)
+    void enableMockMediaEndpoint();
     void enableMockRTCPeerConnectionHandler();
     void setMockMediaCaptureDevicesEnabled(bool);
 #endif
     void enableMockRTCPeerConnectionHandler();
     void setMockMediaCaptureDevicesEnabled(bool);
 #endif