50 changed files with 1247 additions and 543 deletions
@ -1,8 +1,8 @@
@@ -1,8 +1,8 @@
|
||||
{ |
||||
"private": true, |
||||
"dependencies": { |
||||
"jshint": ">= 2.5.5", |
||||
"autoprefixer": ">= 3.1.0", |
||||
"po2json": ">= 0.3.0" |
||||
"po2json": ">= 0.3.0", |
||||
"jshint": ">= 2.5.5" |
||||
} |
||||
} |
||||
|
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
/* |
||||
* Spreed WebRTC. |
||||
* Copyright (C) 2013-2014 struktur AG |
||||
* |
||||
* This file is part of Spreed WebRTC. |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
.visible-with-contacts, |
||||
.visible-with-contacts-inline { |
||||
display: none; |
||||
} |
||||
|
||||
.hidden-with-contacts { |
||||
} |
||||
|
||||
.with-contacts { |
||||
|
||||
.visible-with-contacts { |
||||
display: block; |
||||
} |
||||
|
||||
.visible-with-contacts-inline { |
||||
display: inline-block; |
||||
} |
||||
|
||||
.hidden-with-contacts { |
||||
display: none; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,199 @@
@@ -0,0 +1,199 @@
|
||||
scss_files: "**/*.scss" |
||||
|
||||
exclude: "libs/**" |
||||
|
||||
linters: |
||||
BangFormat: |
||||
enabled: true |
||||
space_before_bang: true |
||||
space_after_bang: false |
||||
|
||||
BorderZero: |
||||
enabled: true |
||||
convention: zero # or `none` |
||||
|
||||
ColorKeyword: |
||||
enabled: true |
||||
|
||||
ColorVariable: |
||||
enabled: true |
||||
|
||||
Comment: |
||||
enabled: false |
||||
|
||||
DebugStatement: |
||||
enabled: true |
||||
|
||||
DeclarationOrder: |
||||
enabled: true |
||||
|
||||
DuplicateProperty: |
||||
enabled: true |
||||
|
||||
ElsePlacement: |
||||
enabled: true |
||||
style: same_line # or 'new_line' |
||||
|
||||
EmptyLineBetweenBlocks: |
||||
enabled: true |
||||
ignore_single_line_blocks: true |
||||
|
||||
EmptyRule: |
||||
enabled: false |
||||
|
||||
FinalNewline: |
||||
enabled: true |
||||
present: true |
||||
|
||||
HexLength: |
||||
enabled: true |
||||
style: short # or 'long' |
||||
|
||||
HexNotation: |
||||
enabled: true |
||||
style: lowercase # or 'uppercase' |
||||
|
||||
HexValidation: |
||||
enabled: true |
||||
|
||||
IdSelector: |
||||
enabled: true |
||||
|
||||
ImportantRule: |
||||
enabled: true |
||||
|
||||
ImportPath: |
||||
enabled: true |
||||
leading_underscore: false |
||||
filename_extension: false |
||||
|
||||
Indentation: |
||||
enabled: true |
||||
allow_non_nested_indentation: false |
||||
character: space # or 'tab' |
||||
width: 2 |
||||
|
||||
LeadingZero: |
||||
enabled: true |
||||
style: exclude_zero # or 'include_zero' |
||||
|
||||
MergeableSelector: |
||||
enabled: true |
||||
force_nesting: true |
||||
|
||||
NameFormat: |
||||
enabled: true |
||||
allow_leading_underscore: true |
||||
convention: hyphenated_lowercase # or 'BEM', or a regex pattern |
||||
|
||||
NestingDepth: |
||||
enabled: true |
||||
max_depth: 3 |
||||
|
||||
PlaceholderInExtend: |
||||
enabled: true |
||||
|
||||
PropertyCount: |
||||
enabled: false |
||||
include_nested: false |
||||
max_properties: 10 |
||||
|
||||
PropertySortOrder: |
||||
enabled: true |
||||
ignore_unspecified: false |
||||
separate_groups: false |
||||
|
||||
PropertySpelling: |
||||
enabled: true |
||||
extra_properties: [] |
||||
|
||||
QualifyingElement: |
||||
enabled: true |
||||
allow_element_with_attribute: false |
||||
allow_element_with_class: false |
||||
allow_element_with_id: false |
||||
|
||||
SelectorDepth: |
||||
enabled: true |
||||
max_depth: 3 |
||||
|
||||
SelectorFormat: |
||||
enabled: true |
||||
convention: hyphenated_lowercase # or 'BEM', or 'hyphenated_BEM', or 'snake_case', or 'camel_case', or a regex pattern |
||||
|
||||
Shorthand: |
||||
enabled: true |
||||
|
||||
SingleLinePerProperty: |
||||
enabled: true |
||||
allow_single_line_rule_sets: true |
||||
|
||||
SingleLinePerSelector: |
||||
enabled: true |
||||
|
||||
SpaceAfterComma: |
||||
enabled: true |
||||
|
||||
SpaceAfterPropertyColon: |
||||
enabled: true |
||||
style: one_space # or 'no_space', or 'at_least_one_space', or 'aligned' |
||||
|
||||
SpaceAfterPropertyName: |
||||
enabled: true |
||||
|
||||
SpaceBeforeBrace: |
||||
enabled: true |
||||
style: space # or 'new_line' |
||||
allow_single_line_padding: false |
||||
|
||||
SpaceBetweenParens: |
||||
enabled: true |
||||
spaces: 0 |
||||
|
||||
StringQuotes: |
||||
enabled: true |
||||
style: single_quotes # or double_quotes |
||||
|
||||
TrailingSemicolon: |
||||
enabled: true |
||||
|
||||
TrailingZero: |
||||
enabled: false |
||||
|
||||
UnnecessaryMantissa: |
||||
enabled: true |
||||
|
||||
UnnecessaryParentReference: |
||||
enabled: true |
||||
|
||||
UrlFormat: |
||||
enabled: true |
||||
|
||||
UrlQuotes: |
||||
enabled: true |
||||
|
||||
VariableForProperty: |
||||
enabled: false |
||||
properties: [] |
||||
|
||||
VendorPrefixes: |
||||
enabled: true |
||||
identifier_list: base |
||||
include: [] |
||||
exclude: [] |
||||
|
||||
ZeroUnit: |
||||
enabled: true |
||||
|
||||
Compass::*: |
||||
enabled: true |
||||
|
||||
Compass::PropertyWithMixin: |
||||
ignore: |
||||
- 'inline-block' |
||||
- 'box-shadow' |
||||
- 'opacity' |
||||
- 'border-radius' |
||||
- 'transform' |
||||
- 'text-shadow' |
||||
- 'background-clip' |
File diff suppressed because one or more lines are too long
@ -1,162 +1,423 @@
@@ -1,162 +1,423 @@
|
||||
/* |
||||
* Spreed WebRTC. |
||||
* Copyright (C) 2013-2014 struktur AG |
||||
* Copyright (C) 2013-2015 struktur AG |
||||
* |
||||
* This file is part of Spreed WebRTC. |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* This file is a AMD wrapped version of the sdputils.js from the |
||||
* WebRTC apprtc example. https://github.com/webrtc/apprtc/blob/master/src
|
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in |
||||
* the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* |
||||
* * Neither the name of Google nor the names of its contributors may |
||||
* be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
"use strict"; |
||||
define([], function() { |
||||
|
||||
var Utils = function() {} |
||||
|
||||
Utils.prototype.mergeConstraints = function(cons1, cons2) { |
||||
var merged = cons1; |
||||
var name; |
||||
for (name in cons2.mandatory) { |
||||
if (cons2.mandatory.hasOwnProperty(name)) { |
||||
merged.mandatory[name] = cons2.mandatory[name]; |
||||
} |
||||
} |
||||
merged.optional.concat(cons2.optional); |
||||
return merged; |
||||
}; |
||||
|
||||
Utils.prototype.extractSdp = function(sdpLine, pattern) { |
||||
var result = sdpLine.match(pattern); |
||||
return (result && result.length == 2) ? result[1] : null; |
||||
}; |
||||
|
||||
Utils.prototype.addStereo = function(sdp) { |
||||
// Set Opus in Stereo.
|
||||
|
||||
var sdpLines = sdp.split('\r\n'); |
||||
var opusPayload = ""; |
||||
var fmtpLineIndex = null; |
||||
var i; |
||||
|
||||
// Find opus payload.
|
||||
for (i = 0; i < sdpLines.length; i++) { |
||||
if (sdpLines[i].search('opus/48000') !== -1) { |
||||
opusPayload = this.extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
// Find the payload in fmtp line.
|
||||
for (i = 0; i < sdpLines.length; i++) { |
||||
if (sdpLines[i].search('a=fmtp') !== -1) { |
||||
var payload = this.extractSdp(sdpLines[i], /a=fmtp:(\d+)/); |
||||
if (payload === opusPayload) { |
||||
fmtpLineIndex = i; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
// No fmtp line found.
|
||||
if (fmtpLineIndex === null) { |
||||
console.log("Unable to add stereo (no fmtp line for opus payload)", opusPayload); |
||||
return sdp; |
||||
} |
||||
|
||||
// Append stereo=1 to fmtp line.
|
||||
sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat(' stereo=1'); |
||||
|
||||
sdp = sdpLines.join('\r\n'); |
||||
console.log("Enabled opus stereo."); |
||||
return sdp; |
||||
|
||||
}; |
||||
|
||||
Utils.prototype.preferOpus = function(sdp) { |
||||
// Set Opus as the preferred codec in SDP if Opus is present.
|
||||
|
||||
var sdpLines = sdp.split('\r\n'); |
||||
var mLineIndex = null; |
||||
var i; |
||||
|
||||
// Search for m line.
|
||||
for (i = 0; i < sdpLines.length; i++) { |
||||
if (sdpLines[i].search('m=audio') !== -1) { |
||||
mLineIndex = i; |
||||
break; |
||||
} |
||||
} |
||||
if (mLineIndex === null) { |
||||
return sdp; |
||||
} |
||||
|
||||
// If Opus is available, set it as the default in m line.
|
||||
for (i = 0; i < sdpLines.length; i++) { |
||||
if (sdpLines[i].search('opus/48000') !== -1) { |
||||
var opusPayload = this.extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); |
||||
if (opusPayload) { |
||||
sdpLines[mLineIndex] = this.setDefaultCodec(sdpLines[mLineIndex], opusPayload); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
// Remove CN in m line and sdp.
|
||||
sdpLines = this.removeCN(sdpLines, mLineIndex); |
||||
|
||||
sdp = sdpLines.join('\r\n'); |
||||
return sdp; |
||||
|
||||
}; |
||||
|
||||
Utils.prototype.setDefaultCodec = function(mLine, payload) { |
||||
// Set the selected codec to the first in m line.
|
||||
var elements = mLine.split(' '); |
||||
var newLine = []; |
||||
var index = 0; |
||||
for (var i = 0; i < elements.length; i++) { |
||||
// Format of media starts from the fourth.
|
||||
if (index === 3) { |
||||
newLine[index++] = payload; // Put target payload to the first.
|
||||
} |
||||
if (elements[i] !== payload) { |
||||
newLine[index++] = elements[i]; |
||||
} |
||||
} |
||||
return newLine.join(' '); |
||||
}; |
||||
|
||||
Utils.prototype.removeCN = function(sdpLines, mLineIndex) { |
||||
// Strip CN from sdp before CN constraints is ready.
|
||||
var mLineElements = sdpLines[mLineIndex].split(' '); |
||||
// Scan from end for the convenience of removing an item.
|
||||
for (var i = sdpLines.length - 1; i >= 0; i--) { |
||||
var payload = this.extractSdp(sdpLines[i], /a=rtpmap:(\d+) CN\/\d+/i); |
||||
if (payload) { |
||||
var cnPos = mLineElements.indexOf(payload); |
||||
if (cnPos !== -1) { |
||||
// Remove CN payload from m line.
|
||||
mLineElements.splice(cnPos, 1); |
||||
} |
||||
// Remove CN line in sdp
|
||||
sdpLines.splice(i, 1); |
||||
} |
||||
} |
||||
sdpLines[mLineIndex] = mLineElements.join(' '); |
||||
return sdpLines; |
||||
}; |
||||
|
||||
var utils = new Utils(); |
||||
return utils; |
||||
function trace(text) { |
||||
// noop
|
||||
} |
||||
|
||||
function mergeConstraints(cons1, cons2) { |
||||
if (!cons1 || !cons2) { |
||||
return cons1 || cons2; |
||||
} |
||||
var merged = cons1; |
||||
for (var name in cons2.mandatory) { |
||||
if (cons2.mandatory.hasOwnProperty(name)) { |
||||
merged.mandatory[name] = cons2.mandatory[name]; |
||||
} |
||||
} |
||||
merged.optional = merged.optional.concat(cons2.optional); |
||||
return merged; |
||||
} |
||||
|
||||
function iceCandidateType(candidateStr) { |
||||
return candidateStr.split(' ')[7]; |
||||
} |
||||
|
||||
function maybeSetOpusOptions(sdp, params) { |
||||
// Set Opus in Stereo, if stereo is true, unset it, if stereo is false, and
|
||||
// do nothing if otherwise.
|
||||
if (params.opusStereo === 'true') { |
||||
sdp = setCodecParam(sdp, 'opus/48000', 'stereo', '1'); |
||||
} else if (params.opusStereo === 'false') { |
||||
sdp = removeCodecParam(sdp, 'opus/48000', 'stereo'); |
||||
} |
||||
|
||||
// Set Opus FEC, if opusfec is true, unset it, if opusfec is false, and
|
||||
// do nothing if otherwise.
|
||||
if (params.opusFec === 'true') { |
||||
sdp = setCodecParam(sdp, 'opus/48000', 'useinbandfec', '1'); |
||||
} else if (params.opusFec === 'false') { |
||||
sdp = removeCodecParam(sdp, 'opus/48000', 'useinbandfec'); |
||||
} |
||||
|
||||
// Set Opus maxplaybackrate, if requested.
|
||||
if (params.opusMaxPbr) { |
||||
sdp = setCodecParam( |
||||
sdp, 'opus/48000', 'maxplaybackrate', params.opusMaxPbr); |
||||
} |
||||
return sdp; |
||||
} |
||||
|
||||
function maybeSetAudioSendBitRate(sdp, params) { |
||||
if (!params.audioSendBitrate) { |
||||
return sdp; |
||||
} |
||||
trace('Prefer audio send bitrate: ' + params.audioSendBitrate); |
||||
return preferBitRate(sdp, params.audioSendBitrate, 'audio'); |
||||
} |
||||
|
||||
function maybeSetAudioReceiveBitRate(sdp, params) { |
||||
if (!params.audioRecvBitrate) { |
||||
return sdp; |
||||
} |
||||
trace('Prefer audio receive bitrate: ' + params.audioRecvBitrate); |
||||
return preferBitRate(sdp, params.audioRecvBitrate, 'audio'); |
||||
} |
||||
|
||||
function maybeSetVideoSendBitRate(sdp, params) { |
||||
if (!params.videoSendBitrate) { |
||||
return sdp; |
||||
} |
||||
trace('Prefer video send bitrate: ' + params.videoSendBitrate); |
||||
return preferBitRate(sdp, params.videoSendBitrate, 'video'); |
||||
} |
||||
|
||||
function maybeSetVideoReceiveBitRate(sdp, params) { |
||||
if (!params.videoRecvBitrate) { |
||||
return sdp; |
||||
} |
||||
trace('Prefer video receive bitrate: ' + params.videoRecvBitrate); |
||||
return preferBitRate(sdp, params.videoRecvBitrate, 'video'); |
||||
} |
||||
|
||||
// Add a b=AS:bitrate line to the m=mediaType section.
|
||||
function preferBitRate(sdp, bitrate, mediaType) { |
||||
var sdpLines = sdp.split('\r\n'); |
||||
|
||||
// Find m line for the given mediaType.
|
||||
var mLineIndex = findLine(sdpLines, 'm=', mediaType); |
||||
if (mLineIndex === null) { |
||||
trace('Failed to add bandwidth line to sdp, as no m-line found'); |
||||
return sdp; |
||||
} |
||||
|
||||
// Find next m-line if any.
|
||||
var nextMLineIndex = findLineInRange(sdpLines, mLineIndex + 1, -1, 'm='); |
||||
if (nextMLineIndex === null) { |
||||
nextMLineIndex = sdpLines.length; |
||||
} |
||||
|
||||
// Find c-line corresponding to the m-line.
|
||||
var cLineIndex = findLineInRange(sdpLines, mLineIndex + 1, |
||||
nextMLineIndex, 'c='); |
||||
if (cLineIndex === null) { |
||||
trace('Failed to add bandwidth line to sdp, as no c-line found'); |
||||
return sdp; |
||||
} |
||||
|
||||
// Check if bandwidth line already exists between c-line and next m-line.
|
||||
var bLineIndex = findLineInRange(sdpLines, cLineIndex + 1, |
||||
nextMLineIndex, 'b=AS'); |
||||
if (bLineIndex) { |
||||
sdpLines.splice(bLineIndex, 1); |
||||
} |
||||
|
||||
// Create the b (bandwidth) sdp line.
|
||||
var bwLine = 'b=AS:' + bitrate; |
||||
// As per RFC 4566, the b line should follow after c-line.
|
||||
sdpLines.splice(cLineIndex + 1, 0, bwLine); |
||||
sdp = sdpLines.join('\r\n'); |
||||
return sdp; |
||||
} |
||||
|
||||
// Add an a=fmtp: x-google-min-bitrate=kbps line, if videoSendInitialBitrate
|
||||
// is specified. We'll also add a x-google-min-bitrate value, since the max
|
||||
// must be >= the min.
|
||||
function maybeSetVideoSendInitialBitRate(sdp, params) { |
||||
var initialBitrate = params.videoSendInitialBitrate; |
||||
if (!initialBitrate) { |
||||
return sdp; |
||||
} |
||||
|
||||
// Validate the initial bitrate value.
|
||||
var maxBitrate = initialBitrate; |
||||
var bitrate = params.videoSendBitrate; |
||||
if (bitrate) { |
||||
if (initialBitrate > bitrate) { |
||||
trace('Clamping initial bitrate to max bitrate of ' + |
||||
bitrate + ' kbps.'); |
||||
initialBitrate = bitrate; |
||||
params.videoSendInitialBitrate = initialBitrate; |
||||
} |
||||
maxBitrate = bitrate; |
||||
} |
||||
|
||||
var sdpLines = sdp.split('\r\n'); |
||||
|
||||
// Search for m line.
|
||||
var mLineIndex = findLine(sdpLines, 'm=', 'video'); |
||||
if (mLineIndex === null) { |
||||
trace('Failed to find video m-line'); |
||||
return sdp; |
||||
} |
||||
|
||||
sdp = setCodecParam(sdp, 'VP8/90000', 'x-google-min-bitrate', |
||||
params.videoSendInitialBitrate.toString()); |
||||
sdp = setCodecParam(sdp, 'VP8/90000', 'x-google-max-bitrate', |
||||
maxBitrate.toString()); |
||||
|
||||
return sdp; |
||||
} |
||||
|
||||
// Promotes |audioSendCodec| to be the first in the m=audio line, if set.
|
||||
function maybePreferAudioSendCodec(sdp, params) { |
||||
return maybePreferCodec(sdp, 'audio', 'send', params.audioSendCodec); |
||||
} |
||||
|
||||
// Promotes |audioRecvCodec| to be the first in the m=audio line, if set.
|
||||
function maybePreferAudioReceiveCodec(sdp, params) { |
||||
return maybePreferCodec(sdp, 'audio', 'receive', params.audioRecvCodec); |
||||
} |
||||
|
||||
// Promotes |videoSendCodec| to be the first in the m=audio line, if set.
|
||||
function maybePreferVideoSendCodec(sdp, params) { |
||||
return maybePreferCodec(sdp, 'video', 'send', params.videoSendCodec); |
||||
} |
||||
|
||||
// Promotes |videoRecvCodec| to be the first in the m=audio line, if set.
|
||||
function maybePreferVideoReceiveCodec(sdp, params) { |
||||
return maybePreferCodec(sdp, 'video', 'receive', params.videoRecvCodec); |
||||
} |
||||
|
||||
// Sets |codec| as the default |type| codec if it's present.
|
||||
// The format of |codec| is 'NAME/RATE', e.g. 'opus/48000'.
|
||||
function maybePreferCodec(sdp, type, dir, codec) { |
||||
var str = type + ' ' + dir + ' codec'; |
||||
if (codec === '') { |
||||
trace('No preference on ' + str + '.'); |
||||
return sdp; |
||||
} |
||||
|
||||
trace('Prefer ' + str + ': ' + codec); |
||||
|
||||
var sdpLines = sdp.split('\r\n'); |
||||
|
||||
// Search for m line.
|
||||
var mLineIndex = findLine(sdpLines, 'm=', type); |
||||
if (mLineIndex === null) { |
||||
return sdp; |
||||
} |
||||
|
||||
// If the codec is available, set it as the default in m line.
|
||||
var payload = getCodecPayloadType(sdpLines, codec); |
||||
if (payload) { |
||||
sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex], payload); |
||||
} |
||||
|
||||
sdp = sdpLines.join('\r\n'); |
||||
return sdp; |
||||
} |
||||
|
||||
// Set fmtp param to specific codec in SDP. If param does not exists, add it.
|
||||
function setCodecParam(sdp, codec, param, value) { |
||||
var sdpLines = sdp.split('\r\n'); |
||||
|
||||
var fmtpLineIndex = findFmtpLine(sdpLines, codec); |
||||
|
||||
var fmtpObj = {}; |
||||
if (fmtpLineIndex === null) { |
||||
var index = findLine(sdpLines, 'a=rtpmap', codec); |
||||
if (index === null) { |
||||
return sdp; |
||||
} |
||||
var payload = getCodecPayloadTypeFromLine(sdpLines[index]); |
||||
fmtpObj.pt = payload.toString(); |
||||
fmtpObj.params = {}; |
||||
fmtpObj.params[param] = value; |
||||
sdpLines.splice(index + 1, 0, writeFmtpLine(fmtpObj)); |
||||
} else { |
||||
fmtpObj = parseFmtpLine(sdpLines[fmtpLineIndex]); |
||||
fmtpObj.params[param] = value; |
||||
sdpLines[fmtpLineIndex] = writeFmtpLine(fmtpObj); |
||||
} |
||||
|
||||
sdp = sdpLines.join('\r\n'); |
||||
return sdp; |
||||
} |
||||
|
||||
// Remove fmtp param if it exists.
|
||||
function removeCodecParam(sdp, codec, param) { |
||||
var sdpLines = sdp.split('\r\n'); |
||||
|
||||
var fmtpLineIndex = findFmtpLine(sdpLines, codec); |
||||
if (fmtpLineIndex === null) { |
||||
return sdp; |
||||
} |
||||
|
||||
var map = parseFmtpLine(sdpLines[fmtpLineIndex]); |
||||
delete map.params[param]; |
||||
|
||||
var newLine = writeFmtpLine(map); |
||||
if (newLine === null) { |
||||
sdpLines.splice(fmtpLineIndex, 1); |
||||
} else { |
||||
sdpLines[fmtpLineIndex] = newLine; |
||||
} |
||||
|
||||
sdp = sdpLines.join('\r\n'); |
||||
return sdp; |
||||
} |
||||
|
||||
// Split an fmtp line into an object including 'pt' and 'params'.
|
||||
function parseFmtpLine(fmtpLine) { |
||||
var fmtpObj = {}; |
||||
var spacePos = fmtpLine.indexOf(' '); |
||||
var keyValues = fmtpLine.substring(spacePos + 1).split('; '); |
||||
|
||||
var pattern = new RegExp('a=fmtp:(\\d+)'); |
||||
var result = fmtpLine.match(pattern); |
||||
if (result && result.length === 2) { |
||||
fmtpObj.pt = result[1]; |
||||
} else { |
||||
return null; |
||||
} |
||||
|
||||
var params = {}; |
||||
for (var i = 0; i < keyValues.length; ++i) { |
||||
var pair = keyValues[i].split('='); |
||||
if (pair.length === 2) { |
||||
params[pair[0]] = pair[1]; |
||||
} |
||||
} |
||||
fmtpObj.params = params; |
||||
|
||||
return fmtpObj; |
||||
} |
||||
|
||||
// Generate an fmtp line from an object including 'pt' and 'params'.
|
||||
function writeFmtpLine(fmtpObj) { |
||||
if (!fmtpObj.hasOwnProperty('pt') || !fmtpObj.hasOwnProperty('params')) { |
||||
return null; |
||||
} |
||||
var pt = fmtpObj.pt; |
||||
var params = fmtpObj.params; |
||||
var keyValues = []; |
||||
var i = 0; |
||||
for (var key in params) { |
||||
if (params.hasOwnProperty(key)) { |
||||
keyValues[i] = key + '=' + params[key]; |
||||
++i; |
||||
} |
||||
} |
||||
if (i === 0) { |
||||
return null; |
||||
} |
||||
return 'a=fmtp:' + pt.toString() + ' ' + keyValues.join('; '); |
||||
} |
||||
|
||||
// Find fmtp attribute for |codec| in |sdpLines|.
|
||||
function findFmtpLine(sdpLines, codec) { |
||||
// Find payload of codec.
|
||||
var payload = getCodecPayloadType(sdpLines, codec); |
||||
// Find the payload in fmtp line.
|
||||
return payload ? findLine(sdpLines, 'a=fmtp:' + payload.toString()) : null; |
||||
} |
||||
|
||||
// Find the line in sdpLines that starts with |prefix|, and, if specified,
|
||||
// contains |substr| (case-insensitive search).
|
||||
function findLine(sdpLines, prefix, substr) { |
||||
return findLineInRange(sdpLines, 0, -1, prefix, substr); |
||||
} |
||||
|
||||
// Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix|
|
||||
// and, if specified, contains |substr| (case-insensitive search).
|
||||
function findLineInRange(sdpLines, startLine, endLine, prefix, substr) { |
||||
var realEndLine = endLine !== -1 ? endLine : sdpLines.length; |
||||
for (var i = startLine; i < realEndLine; ++i) { |
||||
if (sdpLines[i].indexOf(prefix) === 0) { |
||||
if (!substr || |
||||
sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) { |
||||
return i; |
||||
} |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
// Gets the codec payload type from sdp lines.
|
||||
function getCodecPayloadType(sdpLines, codec) { |
||||
var index = findLine(sdpLines, 'a=rtpmap', codec); |
||||
return index ? getCodecPayloadTypeFromLine(sdpLines[index]) : null; |
||||
} |
||||
|
||||
// Gets the codec payload type from an a=rtpmap:X line.
|
||||
function getCodecPayloadTypeFromLine(sdpLine) { |
||||
var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+'); |
||||
var result = sdpLine.match(pattern); |
||||
return (result && result.length === 2) ? result[1] : null; |
||||
} |
||||
|
||||
// Returns a new m= line with the specified codec as the first one.
|
||||
function setDefaultCodec(mLine, payload) { |
||||
var elements = mLine.split(' '); |
||||
|
||||
// Just copy the first three parameters; codec order starts on fourth.
|
||||
var newLine = elements.slice(0, 3); |
||||
|
||||
// Put target payload first and copy in the rest.
|
||||
newLine.push(payload); |
||||
for (var i = 3; i < elements.length; i++) { |
||||
if (elements[i] !== payload) { |
||||
newLine.push(elements[i]); |
||||
} |
||||
} |
||||
return newLine.join(' '); |
||||
} |
||||
|
||||
// Exported utils.
|
||||
return { |
||||
mergeConstraints: mergeConstraints, |
||||
maybeSetOpusOptions: maybeSetOpusOptions, |
||||
maybeSetAudioSendBitRate: maybeSetAudioSendBitRate, |
||||
maybeSetAudioReceiveBitRate: maybeSetAudioReceiveBitRate, |
||||
maybeSetVideoSendBitRate: maybeSetVideoSendBitRate, |
||||
maybeSetVideoReceiveBitRate: maybeSetVideoReceiveBitRate, |
||||
maybeSetVideoSendInitialBitRate: maybeSetVideoSendInitialBitRate, |
||||
maybePreferAudioSendCodec: maybePreferAudioSendCodec, |
||||
maybePreferAudioReceiveCodec: maybePreferAudioReceiveCodec, |
||||
maybePreferVideoSendCodec: maybePreferVideoSendCodec, |
||||
maybePreferVideoReceiveCodec: maybePreferVideoReceiveCodec |
||||
} |
||||
|
||||
}); |
||||
|
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
/* |
||||
* Spreed WebRTC. |
||||
* Copyright (C) 2013-2014 struktur AG |
||||
* |
||||
* This file is part of Spreed WebRTC. |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* |
||||
*/ |
||||
|
||||
"use strict"; |
||||
define([], function() { |
||||
|
||||
// modules
|
||||
return ["mediaStream", function(mediaStream) { |
||||
|
||||
var enabledModules = mediaStream.config.Modules || []; |
||||
|
||||
// Public api.
|
||||
return { |
||||
withModule: function(m) { |
||||
return enabledModules.indexOf(m) !== -1; |
||||
} |
||||
} |
||||
|
||||
}]; |
||||
}); |
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
||||
<div class="buddy" ng-class="{'contact': contact, 'withSubline': display.subline || session.Userid, 'isself': session.Userid === myuserid}"> |
||||
<div class="buddyPicture"><i class="fa fa-user"/><img ng-show="display.buddyPicture" alt ng-src="{{display.buddyPicture}}"/></div> |
||||
<div class="buddy1">{{session.Id|displayName}}</div> |
||||
<div class="buddy2"><span ng-show="session.Userid"><i class="fa contact" data-action="contact"></i><span ng-show="session.count"> ({{session.count}})</span></span> <span title="{{display.sublineFull}}">{{display.subline}}</span></div> |
||||
<div class="buddy2"><span ng-show="session.Userid"><i class="fa contact visible-with-contacts-inline" data-action="contact"></i><span ng-show="session.count"> ({{session.count}})</span></span> <span title="{{display.sublineFull}}">{{display.subline}}</span></div> |
||||
</div> |
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue