pax_global_header 0000666 0000000 0000000 00000000064 13422365270 0014516 g ustar 00root root 0000000 0000000 52 comment=ffb0dea7c730a52ab30c9cfb11a564da43114872
sdp-jingle-json-3.1.0/ 0000775 0000000 0000000 00000000000 13422365270 0014522 5 ustar 00root root 0000000 0000000 sdp-jingle-json-3.1.0/.gitignore 0000664 0000000 0000000 00000000023 13422365270 0016505 0 ustar 00root root 0000000 0000000 node_modules
build
sdp-jingle-json-3.1.0/.jshintignore 0000664 0000000 0000000 00000000023 13422365270 0017221 0 ustar 00root root 0000000 0000000 node_modules
build
sdp-jingle-json-3.1.0/.jshintrc 0000664 0000000 0000000 00000000400 13422365270 0016341 0 ustar 00root root 0000000 0000000 {
"asi": false,
"expr": true,
"loopfunc": true,
"curly": false,
"evil": true,
"white": true,
"undef": true,
"browser": true,
"node": true,
"trailing": true,
"indent": 4,
"latedef": true,
"newcap": true
}
sdp-jingle-json-3.1.0/.travis.yml 0000664 0000000 0000000 00000000062 13422365270 0016631 0 ustar 00root root 0000000 0000000 sudo: false
language: node_js
node_js:
- '0.10'
sdp-jingle-json-3.1.0/CONTRIBUTING.md 0000664 0000000 0000000 00000001317 13422365270 0016755 0 ustar 00root root 0000000 0000000 # Contributing
## Issues
Feel free to submit bug reports or pull requests.
If you have a security related issue, please see the [Security Guidelines](SECURITY.md) first.
## Pull Requests
For any code changes, please ensure that:
- The latest master branch has been incorporated in your branch
- JSHint is happy
- All current tests pass
- All new tests (there are new tests, right?) pass
The git pre-commit hook should catch most of the above issues if you run `npm install` first to set it up.
## Licensing
All contributions MUST be submitted under the MIT license. Please do not contribute code that you did not write,
unless you are certain you have the authorization to both do so and release it under MIT.
sdp-jingle-json-3.1.0/Gruntfile.js 0000664 0000000 0000000 00000001704 13422365270 0017021 0 ustar 00root root 0000000 0000000 "use strict";
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: {
options: {
standalone: 'SJJ'
},
dist: {
files: {
'build/<%= pkg.name %>.bundle.js': ['<%= pkg.main %>']
}
}
},
uglify: {
dist: {
files: {
'build/<%= pkg.name %>.bundle.min.js': ['build/<%= pkg.name %>.bundle.js']
}
}
},
jshint: {
files: ['Gruntfile.js', 'index.js', 'lib/**.js', 'test/**.js'],
options: grunt.file.readJSON('.jshintrc')
}
});
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.registerTask('default', ['jshint', 'browserify', 'uglify']);
};
sdp-jingle-json-3.1.0/LICENSE 0000664 0000000 0000000 00000004104 13422365270 0015526 0 ustar 00root root 0000000 0000000 Copyright (c) 2013 Lance Stout
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2012-2013 ESTOS GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
sdp-jingle-json-3.1.0/README.md 0000664 0000000 0000000 00000013422 13422365270 0016003 0 ustar 00root root 0000000 0000000 # SDP-Jingle-JSON
**Convert SDP blobs to and from JSON**
[](https://travis-ci.org/otalk/sdp-jingle-json)
[](https://david-dm.org/otalk/sdp-jingle-json)
[](https://david-dm.org/otalk/sdp-jingle-json#info=devDependencies)
[](https://ci.testling.com/otalk/sdp-jingle-json)
## What is this?
Ever taken a peek at the data blobs that get sent back and forth in WebRTC
signalling? Yeah, that mess of line-oriented data is SDP. But sometimes
you want to have that data available in JSON, like if you want to use XMPP
Jingle for signalling.
This library will convert raw SDP into JSON that mirrors the structure of
XMPP Jingle content, making it simple to convert the SDP data into an XMPP
stanza with any of the various JS XMPP libraries, such as [stanza.io](https://github.com/otalk/stanza.io),
or [xmpp-ftw](https://github.com/lloydwatkin/xmpp-ftw).
And since you're working with WebRTC, be sure to check out
[simplewebrtc](http://simplewebrtc.com).
## Installing
```
npm install sdp-jingle-json
```
## Building bundled/minified version (for AMD, etc)
```sh
$ grunt
```
The bundled and minified files will be in the generated `build` directory.
## How to use it
```
var sjj = require('sdp-jingle-json');
// I have SDP, but want JSON:
var json = sjj.toSessionJSON(sdpBlob, {
creators: ['initiator', 'initiator'], // Who created the media contents
role: 'initiator', // Which side of the offer/answer are we acting as
direction: 'outgoing' // Are we parsing SDP that we are sending or receiving?
});
// I have JSON (a dictionary of session and content descriptions), but want SDP:
var sdp = sjj.toSessionSDP(jsonSession, {
role: 'responder',
direction: 'incoming'
});
```
You can also use `toMediaSDP` and `toMediaJSON` to convert only a single media section.
## See it in action
Open the `convert.html` file and enter in SDP or JSON to see how it converts back and forth.
## Jingle JSON
The format for the generated JSON content is:
```
{
"action": "",
"initiator": "",
"responder": "",
"sid": "",
// ---- Content payload
"groups": [
{
"semantics": "",
"contents": [],
} //...
],
"contents": [
{
"name": "",
"creator": "",
"senders": "",
"application": {
// ---- RTP description
"applicationType": "rtp",
"media": "",
"ssrc": "",
"sourceGroups": [
{
"semantics": "",
"sources": [
"" //...
]
} //...
],
"sources": [
{
"ssrc": "",
"parameters: [
{
"key": "",
"value": ""
} //...
]
} //...
],
"bandwidth": "",
"bandwidthType": "",
"headerExtensions": [
{
"id": "",
"uri": "",
"senders": ""
} //...
],
"payloads": [
{
"id": "",
"channels": "",
"clockrate": "",
"maxptime": "",
"ptime": "",
"name": "",
"parameters": [
{
"key": "",
"value": ""
} //...
],
"feedback": [
{
"type": "",
"subtype": "",
"value": ""
} //...
]
}
],
"encryption": [
{
"cipherSuite": "",
"keyParams": "",
"sessionParams": "",
"tag": ""
} //...
]
},
"transport": {
// ---- ICE UDP transport
"transportType": "iceUdp",
"ufrag": "",
"pwd": "",
"setup": "",
"candidates": [
{
"component": "",
"foundation": "",
"generation": "",
"id": "",
"ip": "",
"network": "",
"port": "",
"priority": "",
"protocol": "",
"relAddr": "",
"relPort": "",
"type": ""
} //...
],
"fingerprints": [
{
"hash": "",
"value": ""
} // ...
]
}
} //...
]
}
```
## License
MIT
## Created By
If you like this, follow [@lancestout](http://twitter.com/lancestout) or [@HCornflower](http://twitter.com/HCornflower) on twitter.
SDP-Jingle-JSON is derived, in collaboration, from the work done by Philipp Hancke for [strophe.jingle](https://github.com/estos/strophe.jingle).
sdp-jingle-json-3.1.0/SECURITY.md 0000664 0000000 0000000 00000000635 13422365270 0016317 0 ustar 00root root 0000000 0000000 # Reporting Security Issues
[Report Vulnerability to the Node Security Project](mailto:report@nodesecurity.io?cc=lancestout@gmail.com&subject=Security%20Issue%20for%20SDP-Jingle-JSON)
In the interest of responsible disclosure, please use the above to report any security issues so
that the appropriate patches and advisories can be made.
## History
No security issues have been reported for this project yet.
sdp-jingle-json-3.1.0/convert.html 0000664 0000000 0000000 00000002600 13422365270 0017066 0 ustar 00root root 0000000 0000000
SDP JSON converter
sdp-jingle-json-3.1.0/index.js 0000664 0000000 0000000 00000006226 13422365270 0016175 0 ustar 00root root 0000000 0000000 var toSDP = require('./lib/tosdp');
var toJSON = require('./lib/tojson');
// Converstion from JSON to SDP
exports.toIncomingSDPOffer = function (session) {
return toSDP.toSessionSDP(session, {
role: 'responder',
direction: 'incoming'
});
};
exports.toOutgoingSDPOffer = function (session) {
return toSDP.toSessionSDP(session, {
role: 'initiator',
direction: 'outgoing'
});
};
exports.toIncomingSDPAnswer = function (session) {
return toSDP.toSessionSDP(session, {
role: 'initiator',
direction: 'incoming'
});
};
exports.toOutgoingSDPAnswer = function (session) {
return toSDP.toSessionSDP(session, {
role: 'responder',
direction: 'outgoing'
});
};
exports.toIncomingMediaSDPOffer = function (media) {
return toSDP.toMediaSDP(media, {
role: 'responder',
direction: 'incoming'
});
};
exports.toOutgoingMediaSDPOffer = function (media) {
return toSDP.toMediaSDP(media, {
role: 'initiator',
direction: 'outgoing'
});
};
exports.toIncomingMediaSDPAnswer = function (media) {
return toSDP.toMediaSDP(media, {
role: 'initiator',
direction: 'incoming'
});
};
exports.toOutgoingMediaSDPAnswer = function (media) {
return toSDP.toMediaSDP(media, {
role: 'responder',
direction: 'outgoing'
});
};
exports.toCandidateSDP = toSDP.toCandidateSDP;
exports.toMediaSDP = toSDP.toMediaSDP;
exports.toSessionSDP = toSDP.toSessionSDP;
// Conversion from SDP to JSON
exports.toIncomingJSONOffer = function (sdp, creators) {
return toJSON.toSessionJSON(sdp, {
role: 'responder',
direction: 'incoming',
creators: creators
});
};
exports.toOutgoingJSONOffer = function (sdp, creators) {
return toJSON.toSessionJSON(sdp, {
role: 'initiator',
direction: 'outgoing',
creators: creators
});
};
exports.toIncomingJSONAnswer = function (sdp, creators) {
return toJSON.toSessionJSON(sdp, {
role: 'initiator',
direction: 'incoming',
creators: creators
});
};
exports.toOutgoingJSONAnswer = function (sdp, creators) {
return toJSON.toSessionJSON(sdp, {
role: 'responder',
direction: 'outgoing',
creators: creators
});
};
exports.toIncomingMediaJSONOffer = function (sdp, creator) {
return toJSON.toMediaJSON(sdp, {
role: 'responder',
direction: 'incoming',
creator: creator
});
};
exports.toOutgoingMediaJSONOffer = function (sdp, creator) {
return toJSON.toMediaJSON(sdp, {
role: 'initiator',
direction: 'outgoing',
creator: creator
});
};
exports.toIncomingMediaJSONAnswer = function (sdp, creator) {
return toJSON.toMediaJSON(sdp, {
role: 'initiator',
direction: 'incoming',
creator: creator
});
};
exports.toOutgoingMediaJSONAnswer = function (sdp, creator) {
return toJSON.toMediaJSON(sdp, {
role: 'responder',
direction: 'outgoing',
creator: creator
});
};
exports.toCandidateJSON = toJSON.toCandidateJSON;
exports.toMediaJSON = toJSON.toMediaJSON;
exports.toSessionJSON = toJSON.toSessionJSON;
sdp-jingle-json-3.1.0/lib/ 0000775 0000000 0000000 00000000000 13422365270 0015270 5 ustar 00root root 0000000 0000000 sdp-jingle-json-3.1.0/lib/parsers.js 0000664 0000000 0000000 00000014706 13422365270 0017315 0 ustar 00root root 0000000 0000000 exports.lines = function (sdp) {
return sdp.split(/\r?\n/).filter(function (line) {
return line.length > 0;
});
};
exports.findLine = function (prefix, mediaLines, sessionLines) {
var prefixLength = prefix.length;
for (var i = 0; i < mediaLines.length; i++) {
if (mediaLines[i].substr(0, prefixLength) === prefix) {
return mediaLines[i];
}
}
// Continue searching in parent session section
if (!sessionLines) {
return false;
}
for (var j = 0; j < sessionLines.length; j++) {
if (sessionLines[j].substr(0, prefixLength) === prefix) {
return sessionLines[j];
}
}
return false;
};
exports.findLines = function (prefix, mediaLines, sessionLines) {
var results = [];
var prefixLength = prefix.length;
for (var i = 0; i < mediaLines.length; i++) {
if (mediaLines[i].substr(0, prefixLength) === prefix) {
results.push(mediaLines[i]);
}
}
if (results.length || !sessionLines) {
return results;
}
for (var j = 0; j < sessionLines.length; j++) {
if (sessionLines[j].substr(0, prefixLength) === prefix) {
results.push(sessionLines[j]);
}
}
return results;
};
exports.mline = function (line) {
var parts = line.substr(2).split(' ');
var parsed = {
media: parts[0],
port: parts[1],
proto: parts[2],
formats: []
};
for (var i = 3; i < parts.length; i++) {
if (parts[i]) {
parsed.formats.push(parts[i]);
}
}
return parsed;
};
exports.rtpmap = function (line) {
var parts = line.substr(9).split(' ');
var parsed = {
id: parts.shift()
};
parts = parts[0].split('/');
parsed.name = parts[0];
parsed.clockrate = parts[1];
parsed.channels = parts.length == 3 ? parts[2] : '1';
return parsed;
};
exports.sctpmap = function (line) {
// based on -05 draft
var parts = line.substr(10).split(' ');
var parsed = {
number: parts.shift(),
protocol: parts.shift(),
streams: parts.shift()
};
return parsed;
};
exports.fmtp = function (line) {
var kv, key, value;
var parts = line.substr(line.indexOf(' ') + 1).split(';');
var parsed = [];
for (var i = 0; i < parts.length; i++) {
kv = parts[i].split('=');
key = kv[0].trim();
value = kv[1];
if (key && value) {
parsed.push({key: key, value: value});
} else if (key) {
parsed.push({key: '', value: key});
}
}
return parsed;
};
exports.crypto = function (line) {
var parts = line.substr(9).split(' ');
var parsed = {
tag: parts[0],
cipherSuite: parts[1],
keyParams: parts[2],
sessionParams: parts.slice(3).join(' ')
};
return parsed;
};
exports.fingerprint = function (line) {
var parts = line.substr(14).split(' ');
return {
hash: parts[0],
value: parts[1]
};
};
exports.extmap = function (line) {
var parts = line.substr(9).split(' ');
var parsed = {};
var idpart = parts.shift();
var sp = idpart.indexOf('/');
if (sp >= 0) {
parsed.id = idpart.substr(0, sp);
parsed.senders = idpart.substr(sp + 1);
} else {
parsed.id = idpart;
parsed.senders = 'sendrecv';
}
parsed.uri = parts.shift() || '';
return parsed;
};
exports.rtcpfb = function (line) {
var parts = line.substr(10).split(' ');
var parsed = {};
parsed.id = parts.shift();
parsed.type = parts.shift();
if (parsed.type === 'trr-int') {
parsed.value = parts.shift();
} else {
parsed.subtype = parts.shift() || '';
}
parsed.parameters = parts;
return parsed;
};
exports.candidate = function (line) {
var parts;
if (line.indexOf('a=candidate:') === 0) {
parts = line.substring(12).split(' ');
} else { // no a=candidate
parts = line.substring(10).split(' ');
}
var candidate = {
foundation: parts[0],
component: parts[1],
protocol: parts[2].toLowerCase(),
priority: parts[3],
ip: parts[4],
port: parts[5],
// skip parts[6] == 'typ'
type: parts[7],
generation: '0'
};
for (var i = 8; i < parts.length; i += 2) {
if (parts[i] === 'raddr') {
candidate.relAddr = parts[i + 1];
} else if (parts[i] === 'rport') {
candidate.relPort = parts[i + 1];
} else if (parts[i] === 'generation') {
candidate.generation = parts[i + 1];
} else if (parts[i] === 'tcptype') {
candidate.tcpType = parts[i + 1];
}
}
candidate.network = '1';
return candidate;
};
exports.sourceGroups = function (lines) {
var parsed = [];
for (var i = 0; i < lines.length; i++) {
var parts = lines[i].substr(13).split(' ');
parsed.push({
semantics: parts.shift(),
sources: parts
});
}
return parsed;
};
exports.sources = function (lines) {
// http://tools.ietf.org/html/rfc5576
var parsed = [];
var sources = {};
for (var i = 0; i < lines.length; i++) {
var parts = lines[i].substr(7).split(' ');
var ssrc = parts.shift();
if (!sources[ssrc]) {
var source = {
ssrc: ssrc,
parameters: []
};
parsed.push(source);
// Keep an index
sources[ssrc] = source;
}
parts = parts.join(' ').split(':');
var attribute = parts.shift();
var value = parts.join(':') || null;
sources[ssrc].parameters.push({
key: attribute,
value: value
});
}
return parsed;
};
exports.groups = function (lines) {
// http://tools.ietf.org/html/rfc5888
var parsed = [];
var parts;
for (var i = 0; i < lines.length; i++) {
parts = lines[i].substr(8).split(' ');
parsed.push({
semantics: parts.shift(),
contents: parts
});
}
return parsed;
};
exports.bandwidth = function (line) {
var parts = line.substr(2).split(':');
var parsed = {};
parsed.type = parts.shift();
parsed.bandwidth = parts.shift();
return parsed;
};
exports.msid = function (line) {
var data = line.substr(7);
var parts = data.split(' ');
return {
msid: data,
mslabel: parts[0],
label: parts[1]
};
};
sdp-jingle-json-3.1.0/lib/senders.js 0000664 0000000 0000000 00000002313 13422365270 0017270 0 ustar 00root root 0000000 0000000 module.exports = {
initiator: {
incoming: {
initiator: 'recvonly',
responder: 'sendonly',
both: 'sendrecv',
none: 'inactive',
recvonly: 'initiator',
sendonly: 'responder',
sendrecv: 'both',
inactive: 'none'
},
outgoing: {
initiator: 'sendonly',
responder: 'recvonly',
both: 'sendrecv',
none: 'inactive',
recvonly: 'responder',
sendonly: 'initiator',
sendrecv: 'both',
inactive: 'none'
}
},
responder: {
incoming: {
initiator: 'sendonly',
responder: 'recvonly',
both: 'sendrecv',
none: 'inactive',
recvonly: 'responder',
sendonly: 'initiator',
sendrecv: 'both',
inactive: 'none'
},
outgoing: {
initiator: 'recvonly',
responder: 'sendonly',
both: 'sendrecv',
none: 'inactive',
recvonly: 'initiator',
sendonly: 'responder',
sendrecv: 'both',
inactive: 'none'
}
}
};
sdp-jingle-json-3.1.0/lib/tojson.js 0000664 0000000 0000000 00000016355 13422365270 0017154 0 ustar 00root root 0000000 0000000 var SENDERS = require('./senders');
var parsers = require('./parsers');
var idCounter = Math.random();
exports._setIdCounter = function (counter) {
idCounter = counter;
};
exports.toSessionJSON = function (sdp, opts) {
var i;
var creators = opts.creators || [];
var role = opts.role || 'initiator';
var direction = opts.direction || 'outgoing';
// Divide the SDP into session and media sections.
var media = sdp.split(/\r?\nm=/);
for (i = 1; i < media.length; i++) {
media[i] = 'm=' + media[i];
if (i !== media.length - 1) {
media[i] += '\r\n';
}
}
var session = media.shift() + '\r\n';
var sessionLines = parsers.lines(session);
var parsed = {};
var contents = [];
for (i = 0; i < media.length; i++) {
contents.push(exports.toMediaJSON(media[i], session, {
role: role,
direction: direction,
creator: creators[i] || 'initiator'
}));
}
parsed.contents = contents;
var groupLines = parsers.findLines('a=group:', sessionLines);
if (groupLines.length) {
parsed.groups = parsers.groups(groupLines);
}
return parsed;
};
exports.toMediaJSON = function (media, session, opts) {
var creator = opts.creator || 'initiator';
var role = opts.role || 'initiator';
var direction = opts.direction || 'outgoing';
var lines = parsers.lines(media);
var sessionLines = parsers.lines(session);
var mline = parsers.mline(lines[0]);
var content = {
creator: creator,
name: mline.media,
application: {
applicationType: 'rtp',
media: mline.media,
payloads: [],
encryption: [],
feedback: [],
headerExtensions: []
},
transport: {
transportType: 'iceUdp',
candidates: [],
fingerprints: []
}
};
if (mline.media == 'application') {
// FIXME: the description is most likely to be independent
// of the SDP and should be processed by other parts of the library
content.application = {
applicationType: 'datachannel'
};
content.transport.sctp = [];
}
var desc = content.application;
var trans = content.transport;
// If we have a mid, use that for the content name instead.
var mid = parsers.findLine('a=mid:', lines);
if (mid) {
content.name = mid.substr(6);
}
if (parsers.findLine('a=sendrecv', lines, sessionLines)) {
content.senders = 'both';
} else if (parsers.findLine('a=sendonly', lines, sessionLines)) {
content.senders = SENDERS[role][direction].sendonly;
} else if (parsers.findLine('a=recvonly', lines, sessionLines)) {
content.senders = SENDERS[role][direction].recvonly;
} else if (parsers.findLine('a=inactive', lines, sessionLines)) {
content.senders = 'none';
}
if (desc.applicationType == 'rtp') {
var bandwidth = parsers.findLine('b=', lines);
if (bandwidth) {
desc.bandwidth = parsers.bandwidth(bandwidth);
}
var ssrc = parsers.findLine('a=ssrc:', lines);
if (ssrc) {
desc.ssrc = ssrc.substr(7).split(' ')[0];
}
var rtpmapLines = parsers.findLines('a=rtpmap:', lines);
rtpmapLines.forEach(function (line) {
var payload = parsers.rtpmap(line);
payload.parameters = [];
payload.feedback = [];
var fmtpLines = parsers.findLines('a=fmtp:' + payload.id, lines);
// There should only be one fmtp line per payload
fmtpLines.forEach(function (line) {
payload.parameters = parsers.fmtp(line);
});
var fbLines = parsers.findLines('a=rtcp-fb:' + payload.id, lines);
fbLines.forEach(function (line) {
payload.feedback.push(parsers.rtcpfb(line));
});
desc.payloads.push(payload);
});
var cryptoLines = parsers.findLines('a=crypto:', lines, sessionLines);
cryptoLines.forEach(function (line) {
desc.encryption.push(parsers.crypto(line));
});
if (parsers.findLine('a=rtcp-mux', lines)) {
desc.mux = true;
}
if (parsers.findLine('a=rtcp-rsize', lines)) {
desc.rsize = true;
}
var fbLines = parsers.findLines('a=rtcp-fb:*', lines);
fbLines.forEach(function (line) {
desc.feedback.push(parsers.rtcpfb(line));
});
var extLines = parsers.findLines('a=extmap:', lines);
extLines.forEach(function (line) {
var ext = parsers.extmap(line);
ext.senders = SENDERS[role][direction][ext.senders];
desc.headerExtensions.push(ext);
});
var ssrcGroupLines = parsers.findLines('a=ssrc-group:', lines);
desc.sourceGroups = parsers.sourceGroups(ssrcGroupLines || []);
var ssrcLines = parsers.findLines('a=ssrc:', lines);
var sources = desc.sources = parsers.sources(ssrcLines || []);
var msidLine = parsers.findLine('a=msid:', lines);
if (msidLine) {
var msid = parsers.msid(msidLine);
['msid', 'mslabel', 'label'].forEach(function (key) {
for (var i = 0; i < sources.length; i++) {
var found = false;
for (var j = 0; j < sources[i].parameters.length; j++) {
if (sources[i].parameters[j].key === key) {
found = true;
}
}
if (!found) {
sources[i].parameters.push({ key: key, value: msid[key] });
}
}
});
}
if (parsers.findLine('a=x-google-flag:conference', lines, sessionLines)) {
desc.googConferenceFlag = true;
}
}
// transport specific attributes
var fingerprintLines = parsers.findLines('a=fingerprint:', lines, sessionLines);
var setup = parsers.findLine('a=setup:', lines, sessionLines);
fingerprintLines.forEach(function (line) {
var fp = parsers.fingerprint(line);
if (setup) {
fp.setup = setup.substr(8);
}
trans.fingerprints.push(fp);
});
var ufragLine = parsers.findLine('a=ice-ufrag:', lines, sessionLines);
var pwdLine = parsers.findLine('a=ice-pwd:', lines, sessionLines);
if (ufragLine && pwdLine) {
trans.ufrag = ufragLine.substr(12);
trans.pwd = pwdLine.substr(10);
trans.candidates = [];
var candidateLines = parsers.findLines('a=candidate:', lines, sessionLines);
candidateLines.forEach(function (line) {
trans.candidates.push(exports.toCandidateJSON(line));
});
}
if (desc.applicationType == 'datachannel') {
var sctpmapLines = parsers.findLines('a=sctpmap:', lines);
sctpmapLines.forEach(function (line) {
var sctp = parsers.sctpmap(line);
trans.sctp.push(sctp);
});
}
return content;
};
exports.toCandidateJSON = function (line) {
var candidate = parsers.candidate(line.split(/\r?\n/)[0]);
candidate.id = (idCounter++).toString(36).substr(0, 12);
return candidate;
};
sdp-jingle-json-3.1.0/lib/tosdp.js 0000664 0000000 0000000 00000017101 13422365270 0016757 0 ustar 00root root 0000000 0000000 var SENDERS = require('./senders');
exports.toSessionSDP = function (session, opts) {
var role = opts.role || 'initiator';
var direction = opts.direction || 'outgoing';
var sid = opts.sid || session.sid || Date.now();
var time = opts.time || Date.now();
var sdp = [
'v=0',
'o=- ' + sid + ' ' + time + ' IN IP4 0.0.0.0',
's=-',
't=0 0'
];
var contents = session.contents || [];
var hasSources = false;
contents.forEach(function (content) {
if (content.application.sources &&
content.application.sources.length) {
hasSources = true;
}
});
if (hasSources) {
sdp.push('a=msid-semantic: WMS *');
}
var groups = session.groups || [];
groups.forEach(function (group) {
sdp.push('a=group:' + group.semantics + ' ' + group.contents.join(' '));
});
contents.forEach(function (content) {
sdp.push(exports.toMediaSDP(content, opts));
});
return sdp.join('\r\n') + '\r\n';
};
exports.toMediaSDP = function (content, opts) {
var sdp = [];
var role = opts.role || 'initiator';
var direction = opts.direction || 'outgoing';
var desc = content.application;
var transport = content.transport;
var payloads = desc.payloads || [];
var fingerprints = (transport && transport.fingerprints) || [];
var mline = [];
if (desc.applicationType == 'datachannel') {
mline.push('application');
mline.push('1');
mline.push('DTLS/SCTP');
if (transport.sctp) {
transport.sctp.forEach(function (map) {
mline.push(map.number);
});
}
} else {
mline.push(desc.media);
mline.push('1');
if (fingerprints.length > 0) {
mline.push('UDP/TLS/RTP/SAVPF');
} else if (desc.encryption && desc.encryption.length > 0) {
mline.push('RTP/SAVPF');
} else {
mline.push('RTP/AVPF');
}
payloads.forEach(function (payload) {
mline.push(payload.id);
});
}
sdp.push('m=' + mline.join(' '));
sdp.push('c=IN IP4 0.0.0.0');
if (desc.bandwidth && desc.bandwidth.type && desc.bandwidth.bandwidth) {
sdp.push('b=' + desc.bandwidth.type + ':' + desc.bandwidth.bandwidth);
}
if (desc.applicationType == 'rtp') {
sdp.push('a=rtcp:1 IN IP4 0.0.0.0');
}
if (transport) {
if (transport.ufrag) {
sdp.push('a=ice-ufrag:' + transport.ufrag);
}
if (transport.pwd) {
sdp.push('a=ice-pwd:' + transport.pwd);
}
var pushedSetup = false;
fingerprints.forEach(function (fingerprint) {
sdp.push('a=fingerprint:' + fingerprint.hash + ' ' + fingerprint.value);
if (fingerprint.setup && !pushedSetup) {
sdp.push('a=setup:' + fingerprint.setup);
}
});
if (transport.sctp) {
transport.sctp.forEach(function (map) {
sdp.push('a=sctpmap:' + map.number + ' ' + map.protocol + ' ' + map.streams);
});
}
}
if (desc.applicationType == 'rtp') {
sdp.push('a=' + (SENDERS[role][direction][content.senders] || 'sendrecv'));
}
sdp.push('a=mid:' + content.name);
if (desc.sources && desc.sources.length) {
var streams = {};
desc.sources.forEach(function (source) {
(source.parameters || []).forEach(function (param) {
if (param.key === 'msid') {
streams[param.value] = 1;
}
});
});
streams = Object.keys(streams);
if (streams.length === 1) {
sdp.push('a=msid:' + streams[0]);
}
}
if (desc.mux) {
sdp.push('a=rtcp-mux');
}
if (desc.rsize) {
sdp.push('a=rtcp-rsize');
}
var encryption = desc.encryption || [];
encryption.forEach(function (crypto) {
sdp.push('a=crypto:' + crypto.tag + ' ' + crypto.cipherSuite + ' ' + crypto.keyParams + (crypto.sessionParams ? ' ' + crypto.sessionParams : ''));
});
if (desc.googConferenceFlag) {
sdp.push('a=x-google-flag:conference');
}
payloads.forEach(function (payload) {
var rtpmap = 'a=rtpmap:' + payload.id + ' ' + payload.name + '/' + payload.clockrate;
if (payload.channels && payload.channels != '1') {
rtpmap += '/' + payload.channels;
}
sdp.push(rtpmap);
if (payload.parameters && payload.parameters.length) {
var fmtp = ['a=fmtp:' + payload.id];
var parameters = [];
payload.parameters.forEach(function (param) {
parameters.push((param.key ? param.key + '=' : '') + param.value);
});
fmtp.push(parameters.join(';'));
sdp.push(fmtp.join(' '));
}
if (payload.feedback) {
payload.feedback.forEach(function (fb) {
if (fb.type === 'trr-int') {
sdp.push('a=rtcp-fb:' + payload.id + ' trr-int ' + (fb.value ? fb.value : '0'));
} else {
sdp.push('a=rtcp-fb:' + payload.id + ' ' + fb.type + (fb.subtype ? ' ' + fb.subtype : ''));
}
});
}
});
if (desc.feedback) {
desc.feedback.forEach(function (fb) {
if (fb.type === 'trr-int') {
sdp.push('a=rtcp-fb:* trr-int ' + (fb.value ? fb.value : '0'));
} else {
sdp.push('a=rtcp-fb:* ' + fb.type + (fb.subtype ? ' ' + fb.subtype : ''));
}
});
}
var hdrExts = desc.headerExtensions || [];
hdrExts.forEach(function (hdr) {
sdp.push('a=extmap:' + hdr.id + (hdr.senders ? '/' + SENDERS[role][direction][hdr.senders] : '') + ' ' + hdr.uri);
});
var ssrcGroups = desc.sourceGroups || [];
ssrcGroups.forEach(function (ssrcGroup) {
sdp.push('a=ssrc-group:' + ssrcGroup.semantics + ' ' + ssrcGroup.sources.join(' '));
});
var ssrcs = desc.sources || [];
ssrcs.forEach(function (ssrc) {
for (var i = 0; i < ssrc.parameters.length; i++) {
var param = ssrc.parameters[i];
sdp.push('a=ssrc:' + (ssrc.ssrc || desc.ssrc) + ' ' + param.key + (param.value ? (':' + param.value) : ''));
}
});
var candidates = transport.candidates || [];
candidates.forEach(function (candidate) {
sdp.push(exports.toCandidateSDP(candidate));
});
return sdp.join('\r\n');
};
exports.toCandidateSDP = function (candidate) {
var sdp = [];
sdp.push(candidate.foundation);
sdp.push(candidate.component);
sdp.push(candidate.protocol.toUpperCase());
sdp.push(candidate.priority);
sdp.push(candidate.ip);
sdp.push(candidate.port);
var type = candidate.type;
sdp.push('typ');
sdp.push(type);
if (type === 'srflx' || type === 'prflx' || type === 'relay') {
if (candidate.relAddr && candidate.relPort) {
sdp.push('raddr');
sdp.push(candidate.relAddr);
sdp.push('rport');
sdp.push(candidate.relPort);
}
}
if (candidate.tcpType && candidate.protocol.toUpperCase() == 'TCP') {
sdp.push('tcptype');
sdp.push(candidate.tcpType);
}
sdp.push('generation');
sdp.push(candidate.generation || '0');
// FIXME: apparently this is wrong per spec
// but then, we need this when actually putting this into
// SDP so it's going to stay.
// decision needs to be revisited when browsers dont
// accept this any longer
return 'a=candidate:' + sdp.join(' ');
};
sdp-jingle-json-3.1.0/package.json 0000664 0000000 0000000 00000002327 13422365270 0017014 0 ustar 00root root 0000000 0000000 {
"name": "sdp-jingle-json",
"version": "3.1.0",
"description": "A parser/serializer for SDP to JSON. Useful for converting SDP to other formats like Jingle for WebRTC signalling",
"main": "index.js",
"repository": {
"type": "git",
"url": "https://github.com/legastero/sdp-jingle-json.git"
},
"bugs": "https://github.com/legastero/sdp-jingle-json/issues",
"keywords": [
"sdp",
"webrtc",
"xmpp",
"jingle"
],
"contributors": [
"Lance Stout ",
"Philipp Hancke "
],
"license": "MIT",
"dependencies": {},
"devDependencies": {
"browserify": "2.36.1",
"grunt": "0.4.2",
"grunt-browserify": "1.2.11",
"grunt-contrib-jshint": "0.7.2",
"grunt-contrib-uglify": "0.2.7",
"precommit-hook": "0.3.8",
"tape": "2.3.0"
},
"testling": {
"files": [
"test/test.js"
],
"browsers": [
"ie/10..latest",
"chrome/20..latest",
"chrome/canary",
"firefox/10..latest",
"firefox/nightly",
"opera/next",
"safari/6..latest",
"iphone/6..latest",
"ipad/6..latest",
"android-browser/4.2..latest"
]
},
"scripts": {
"test": "node test/test.js"
}
}
sdp-jingle-json-3.1.0/test/ 0000775 0000000 0000000 00000000000 13422365270 0015501 5 ustar 00root root 0000000 0000000 sdp-jingle-json-3.1.0/test/data/ 0000775 0000000 0000000 00000000000 13422365270 0016412 5 ustar 00root root 0000000 0000000 sdp-jingle-json-3.1.0/test/data/json.js 0000664 0000000 0000000 00000027315 13422365270 0017731 0 ustar 00root root 0000000 0000000 module.exports = {
"contents": [
{
"creator": "initiator",
"name": "audio",
"application": {
"applicationType": "rtp",
"media": "audio",
"payloads": [
{
"id": "111",
"name": "opus",
"clockrate": "48000",
"channels": "2",
"feedback": [],
"parameters": [
{
"key": "minptime",
"value": "10"
}
]
},
{
"id": "103",
"name": "ISAC",
"clockrate": "16000",
"channels": "1",
"feedback": [],
"parameters": []
},
{
"id": "104",
"name": "ISAC",
"clockrate": "32000",
"channels": "1",
"feedback": [],
"parameters": []
},
{
"id": "0",
"name": "PCMU",
"clockrate": "8000",
"channels": "1",
"feedback": [],
"parameters": []
},
{
"id": "8",
"name": "PCMA",
"clockrate": "8000",
"channels": "1",
"feedback": [],
"parameters": []
},
{
"id": "107",
"name": "CN",
"clockrate": "48000",
"channels": "1",
"feedback": [],
"parameters": []
},
{
"id": "106",
"name": "CN",
"clockrate": "32000",
"channels": "1",
"feedback": [],
"parameters": []
},
{
"id": "105",
"name": "CN",
"clockrate": "16000",
"channels": "1",
"feedback": [],
"parameters": []
},
{
"id": "13",
"name": "CN",
"clockrate": "8000",
"channels": "1",
"feedback": [],
"parameters": []
},
{
"id": "126",
"name": "telephone-event",
"clockrate": "8000",
"channels": "1",
"feedback": [],
"parameters": []
}
],
"encryption": [
{
"tag": "1",
"cipherSuite": "AES_CM_128_HMAC_SHA1_80",
"keyParams": "inline:EwN4nicDelI9pradqeXwjvJVjhIZthVgukUu33Of",
"sessionParams": ""
}
],
"feedback": [],
"headerExtensions": [
{
"id": "1",
"uri": "urn:ietf:params:rtp-hdrext:ssrc-audio-level",
"senders": "both"
}
],
"ssrc": "445948959",
"mux": true,
"rsize": true,
"sourceGroups": [],
"sources": [
{
"ssrc": "445948959",
"parameters": [
{
"key": "cname",
"value": "RbR04HtIjW+Sa+yz"
},
{
"key": "msid",
"value": "uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgoa0"
},
{
"key": "mslabel",
"value": "uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo"
},
{
"key": "label",
"value": "uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgoa0"
}
]
}
]
},
"transport": {
"transportType": "iceUdp",
"candidates": [
{
"foundation": "1529647030",
"component": "1",
"protocol": "udp",
"priority": "2113937151",
"ip": "192.12.211.22",
"port": "63522",
"type": "host",
"generation": "0",
"network": "1",
"id": "0"
}
],
"fingerprints": [
{
"hash": "sha-256",
"value": "39:52:60:61:9D:6B:97:2A:43:DE:E0:BD:80:4B:2D:EE:A3:00:72:FE:FF:11:8E:43:85:06:4A:14:80:FE:9F:DD"
}
],
"ufrag": "TESg/uYDt8nNomZd",
"pwd": "abQXlDvFdLKIVdRDdg1t5Tbn"
},
"senders": "both"
},
{
"creator": "initiator",
"name": "video",
"application": {
"applicationType": "rtp",
"media": "video",
"payloads": [
{
"id": "100",
"name": "VP8",
"clockrate": "90000",
"channels": "1",
"feedback": [
{
"id": "100",
"type": "ccm",
"subtype": "fir",
"parameters": []
},
{
"id": "100",
"type": "nack",
"subtype": "",
"parameters": []
},
{
"id": "100",
"type": "goog-remb",
"subtype": "",
"parameters": []
}
],
"parameters": []
},
{
"id": "116",
"name": "red",
"clockrate": "90000",
"channels": "1",
"feedback": [],
"parameters": []
},
{
"id": "117",
"name": "ulpfec",
"clockrate": "90000",
"channels": "1",
"feedback": [],
"parameters": []
}
],
"encryption": [
{
"tag": "1",
"cipherSuite": "AES_CM_128_HMAC_SHA1_80",
"keyParams": "inline:EwN4nicDelI9pradqeXwjvJVjhIZthVgukUu33Of",
"sessionParams": ""
}
],
"feedback": [],
"headerExtensions": [
{
"id": "2",
"uri": "urn:ietf:params:rtp-hdrext:toffset",
"senders": "both"
}
],
"ssrc": "797563643",
"mux": true,
"sourceGroups": [
{
"semantics": "FID",
"sources": ["797563643", "193463643"]
}
],
"sources": [
{
"ssrc": "797563643",
"parameters": [
{
"key": "cname",
"value": "RbR04HtIjW+Sa+yz"
},
{
"key": "msid",
"value": "uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgov0"
},
{
"key": "mslabel",
"value": "uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo"
},
{
"key": "label",
"value": "uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgov0"
}
]
},
{
"ssrc": "193463643",
"parameters": [
{
"key": "cname",
"value": "RbR04HtIjW+Sa+yz"
},
{
"key": "msid",
"value": "uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgov0"
},
{
"key": "mslabel",
"value": "uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo"
},
{
"key": "label",
"value": "uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgov0"
}
]
}
]
},
"transport": {
"transportType": "iceUdp",
"candidates": [
{
"foundation": "1529647030",
"component": "1",
"protocol": "udp",
"priority": "2113937151",
"ip": "192.12.211.22",
"port": "63522",
"type": "host",
"generation": "0",
"network": "1",
"id": "1"
}
],
"fingerprints": [
{
"hash": "sha-256",
"value": "39:52:60:61:9D:6B:97:2A:43:DE:E0:BD:80:4B:2D:EE:A3:00:72:FE:FF:11:8E:43:85:06:4A:14:80:FE:9F:DD"
}
],
"ufrag": "TESg/uYDt8nNomZd",
"pwd": "abQXlDvFdLKIVdRDdg1t5Tbn"
},
"senders": "both"
}
],
"groups": [
{
"semantics": "BUNDLE",
"contents": [
"audio",
"video"
]
}
]
};
sdp-jingle-json-3.1.0/test/data/no-source-json.js 0000664 0000000 0000000 00000005442 13422365270 0021636 0 ustar 00root root 0000000 0000000 module.exports = {
"contents": [
{
"creator": "initiator",
"name": "audio",
"application": {
"applicationType": "rtp",
"media": "audio",
"payloads": [
{
"id": "96",
"name": "opus",
"clockrate": "48000",
"channels": "2",
"parameters": [],
"feedback": []
},
{
"id": "101",
"name": "telephone-event",
"clockrate": "48000",
"channels": "1",
"parameters": [
{
"key": "bitrate",
"value": "0"
}
],
"feedback": []
}
],
"encryption": [],
"feedback": [],
"headerExtensions": [],
"sourceGroups": [],
"sources": []
},
"transport": {
"transportType": "iceUdp",
"candidates": [
{
"foundation": "1",
"component": "1",
"protocol": "udp",
"priority": "0",
"ip": "xx.xx.xxx.xxx",
"port": "27622",
"type": "host",
"generation": "0",
"network": "1",
"id": "0"
},
{
"foundation": "1974206464",
"component": "1",
"protocol": "udp",
"priority": "1694498815",
"ip": "xxx.xx.xxx.xxx",
"port": "27622",
"type": "srflx",
"generation": "0",
"relAddr": "xx.xx.xxx.xxx",
"relPort": "27622",
"network": "1",
"id": "1"
}
],
"fingerprints": [
{
"hash": "sha-256",
"value": "A1:D1:E8:C0:A3:B2:66:AA:8E:40:46:F0:4F:FE:FB:B9:99:82:E3:D9:6B:C9:F4:11:64:5E:AD:54:99:2C:E3:03",
"setup": "actpass"
}
],
"ufrag": "GXUH9ptTQlZT2f1l",
"pwd": "6AWVYDmAkCyeBQeG75QCC6TE"
},
"senders": "both"
}
]
};
sdp-jingle-json-3.1.0/test/data/no-source-sdp.js 0000664 0000000 0000000 00000001454 13422365270 0021452 0 ustar 00root root 0000000 0000000 module.exports = [
"v=0",
"o=- 1382398245712 1385147470924 IN IP4 0.0.0.0",
"s=-",
"t=0 0",
"m=audio 1 UDP/TLS/RTP/SAVPF 96 101",
"c=IN IP4 0.0.0.0",
"a=rtcp:1 IN IP4 0.0.0.0",
"a=ice-ufrag:GXUH9ptTQlZT2f1l",
"a=ice-pwd:6AWVYDmAkCyeBQeG75QCC6TE",
"a=fingerprint:sha-256 A1:D1:E8:C0:A3:B2:66:AA:8E:40:46:F0:4F:FE:FB:B9:99:82:E3:D9:6B:C9:F4:11:64:5E:AD:54:99:2C:E3:03",
"a=setup:actpass",
"a=sendrecv",
"a=mid:audio",
"a=rtpmap:96 opus/48000/2",
"a=rtpmap:101 telephone-event/48000",
"a=fmtp:101 bitrate=0",
"a=candidate:1 1 UDP 0 xx.xx.xxx.xxx 27622 typ host generation 0",
"a=candidate:1974206464 1 UDP 1694498815 xxx.xx.xxx.xxx 27622 typ srflx raddr xx.xx.xxx.xxx rport 27622 generation 0",
"" // So we end with a \r\n
].join('\r\n');
sdp-jingle-json-3.1.0/test/data/sdp.js 0000664 0000000 0000000 00000006013 13422365270 0017536 0 ustar 00root root 0000000 0000000 module.exports = [
"v=0",
"o=- 1382398245712 1385147470924 IN IP4 0.0.0.0",
"s=-",
"t=0 0",
"a=msid-semantic: WMS *",
"a=group:BUNDLE audio video",
"m=audio 1 UDP/TLS/RTP/SAVPF 111 103 104 0 8 107 106 105 13 126",
"c=IN IP4 0.0.0.0",
"a=rtcp:1 IN IP4 0.0.0.0",
"a=ice-ufrag:TESg/uYDt8nNomZd",
"a=ice-pwd:abQXlDvFdLKIVdRDdg1t5Tbn",
"a=fingerprint:sha-256 39:52:60:61:9D:6B:97:2A:43:DE:E0:BD:80:4B:2D:EE:A3:00:72:FE:FF:11:8E:43:85:06:4A:14:80:FE:9F:DD",
"a=sendrecv",
"a=mid:audio",
"a=msid:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgoa0",
"a=rtcp-mux",
"a=rtcp-rsize",
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:EwN4nicDelI9pradqeXwjvJVjhIZthVgukUu33Of",
"a=rtpmap:111 opus/48000/2",
"a=fmtp:111 minptime=10",
"a=rtpmap:103 ISAC/16000",
"a=rtpmap:104 ISAC/32000",
"a=rtpmap:0 PCMU/8000",
"a=rtpmap:8 PCMA/8000",
"a=rtpmap:107 CN/48000",
"a=rtpmap:106 CN/32000",
"a=rtpmap:105 CN/16000",
"a=rtpmap:13 CN/8000",
"a=rtpmap:126 telephone-event/8000",
"a=extmap:1/sendrecv urn:ietf:params:rtp-hdrext:ssrc-audio-level",
"a=ssrc:445948959 cname:RbR04HtIjW+Sa+yz",
"a=ssrc:445948959 msid:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgoa0",
"a=ssrc:445948959 mslabel:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo",
"a=ssrc:445948959 label:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgoa0",
"a=candidate:1529647030 1 UDP 2113937151 192.12.211.22 63522 typ host generation 0",
"m=video 1 UDP/TLS/RTP/SAVPF 100 116 117",
"c=IN IP4 0.0.0.0",
"a=rtcp:1 IN IP4 0.0.0.0",
"a=ice-ufrag:TESg/uYDt8nNomZd",
"a=ice-pwd:abQXlDvFdLKIVdRDdg1t5Tbn",
"a=fingerprint:sha-256 39:52:60:61:9D:6B:97:2A:43:DE:E0:BD:80:4B:2D:EE:A3:00:72:FE:FF:11:8E:43:85:06:4A:14:80:FE:9F:DD",
"a=sendrecv",
"a=mid:video",
"a=msid:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgov0",
"a=rtcp-mux",
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:EwN4nicDelI9pradqeXwjvJVjhIZthVgukUu33Of",
"a=rtpmap:100 VP8/90000",
"a=rtcp-fb:100 ccm fir",
"a=rtcp-fb:100 nack",
"a=rtcp-fb:100 goog-remb",
"a=rtpmap:116 red/90000",
"a=rtpmap:117 ulpfec/90000",
"a=extmap:2/sendrecv urn:ietf:params:rtp-hdrext:toffset",
"a=ssrc-group:FID 797563643 193463643",
"a=ssrc:797563643 cname:RbR04HtIjW+Sa+yz",
"a=ssrc:797563643 msid:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgov0",
"a=ssrc:797563643 mslabel:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo",
"a=ssrc:797563643 label:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgov0",
"a=ssrc:193463643 cname:RbR04HtIjW+Sa+yz",
"a=ssrc:193463643 msid:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgov0",
"a=ssrc:193463643 mslabel:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgo",
"a=ssrc:193463643 label:uwwsnlQmzOrjxCsin4Z5lQ5XVpUFHQgUYLgov0",
"a=candidate:1529647030 1 UDP 2113937151 192.12.211.22 63522 typ host generation 0",
"" // So we end with a \r\n
].join('\r\n');
sdp-jingle-json-3.1.0/test/npm-debug.log 0000664 0000000 0000000 00000001507 13422365270 0020065 0 ustar 00root root 0000000 0000000 0 info it worked if it ends with ok
1 verbose cli [ '/Users/lance/.nvm/v0.10.21/bin/node',
1 verbose cli '/Users/lance/.nvm/v0.10.21/bin/npm',
1 verbose cli 'test' ]
2 info using npm@1.3.11
3 info using node@v0.10.21
4 error Error: ENOENT, open '/Users/lance/Projects/sdp-jingle-json/test/package.json'
5 error If you need help, you may report this log at:
5 error
5 error or email it to:
5 error
6 error System Darwin 13.0.1
7 error command "/Users/lance/.nvm/v0.10.21/bin/node" "/Users/lance/.nvm/v0.10.21/bin/npm" "test"
8 error cwd /Users/lance/Projects/sdp-jingle-json/test
9 error node -v v0.10.21
10 error npm -v 1.3.11
11 error path /Users/lance/Projects/sdp-jingle-json/test/package.json
12 error code ENOENT
13 error errno 34
14 verbose exit [ 34, true ]
sdp-jingle-json-3.1.0/test/test.js 0000664 0000000 0000000 00000004331 13422365270 0017017 0 ustar 00root root 0000000 0000000 "use strict";
var fs = require('fs');
var test = require('tape');
var SJJ = require('../index');
var tojson = require('../lib/tojson');
var jsonData = require('./data/json');
var sdpData = require('./data/sdp');
var noSourceSdpData = require('./data/no-source-sdp');
var noSourceJsonData = require('./data/no-source-json');
// Data that is typically unique or time dependent
var sid = '1382398245712';
var time = '1385147470924';
test('to json', function (t) {
tojson._setIdCounter(0);
var json = SJJ.toSessionJSON(sdpData, {
creator: 'initiator',
role: 'initiator',
direction: 'outgoing'
});
t.deepEqual(json, jsonData);
t.end();
});
test('to sdp', function (t) {
var sdp = SJJ.toSessionSDP(jsonData, {
role: 'initiator',
direction: 'outgoing',
sid: sid,
time: time
});
t.deepEqual(sdp, sdpData);
t.end();
});
test('no source to json', function (t) {
tojson._setIdCounter(0);
var json = SJJ.toSessionJSON(noSourceSdpData, {
creator: 'initiator',
role: 'initiator',
direction: 'outgoing'
});
t.deepEqual(json, noSourceJsonData);
t.end();
});
test('no source to sdp', function (t) {
t.plan(2);
var sdp = SJJ.toSessionSDP(noSourceJsonData, {
role: 'initiator',
direction: 'outgoing',
sid: sid,
time: time
});
t.ok(sdp.indexOf('msid-semantic') === -1);
t.deepEqual(sdp, noSourceSdpData);
t.end();
});
test('multiple pases', function (t) {
t.plan(2);
tojson._setIdCounter(0);
var json1 = SJJ.toSessionJSON(sdpData, {
creator: 'initiator',
role: 'initiator',
direction: 'outgoing'
});
var sdp1 = SJJ.toSessionSDP(json1, {
role: 'initiator',
direction: 'outgoing',
sid: sid,
time: time
});
tojson._setIdCounter(0);
var json2 = SJJ.toSessionJSON(sdp1, {
creator: 'initiator',
role: 'initiator',
direction: 'outgoing'
});
var sdp2 = SJJ.toSessionSDP(json2, {
role: 'initiator',
direction: 'outgoing',
sid: sid,
time: time
});
t.deepEqual(json2, jsonData);
t.deepEqual(sdp2, sdpData);
t.end();
});