50 changed files with 1247 additions and 543 deletions
@ -1,8 +1,8 @@ |
|||||||
{ |
{ |
||||||
"private": true, |
"private": true, |
||||||
"dependencies": { |
"dependencies": { |
||||||
"jshint": ">= 2.5.5", |
|
||||||
"autoprefixer": ">= 3.1.0", |
"autoprefixer": ">= 3.1.0", |
||||||
"po2json": ">= 0.3.0" |
"po2json": ">= 0.3.0", |
||||||
|
"jshint": ">= 2.5.5" |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -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 @@ |
|||||||
|
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 @@ |
|||||||
/* |
/* |
||||||
* Spreed WebRTC. |
* Spreed WebRTC. |
||||||
* Copyright (C) 2013-2014 struktur AG |
* Copyright (C) 2013-2015 struktur AG |
||||||
* |
* |
||||||
* This file is part of Spreed WebRTC. |
* This file is part of Spreed WebRTC. |
||||||
* |
* |
||||||
* This program is free software: you can redistribute it and/or modify |
* This file is a AMD wrapped version of the sdputils.js from the |
||||||
* it under the terms of the GNU Affero General Public License as published by |
* WebRTC apprtc example. https://github.com/webrtc/apprtc/blob/master/src
|
||||||
* 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, |
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
||||||
* 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 |
* Redistribution and use in source and binary forms, with or without |
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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"; |
"use strict"; |
||||||
define([], function() { |
define([], function() { |
||||||
|
|
||||||
var Utils = function() {} |
function trace(text) { |
||||||
|
// noop
|
||||||
Utils.prototype.mergeConstraints = function(cons1, cons2) { |
} |
||||||
var merged = cons1; |
|
||||||
var name; |
function mergeConstraints(cons1, cons2) { |
||||||
for (name in cons2.mandatory) { |
if (!cons1 || !cons2) { |
||||||
if (cons2.mandatory.hasOwnProperty(name)) { |
return cons1 || cons2; |
||||||
merged.mandatory[name] = cons2.mandatory[name]; |
} |
||||||
} |
var merged = cons1; |
||||||
} |
for (var name in cons2.mandatory) { |
||||||
merged.optional.concat(cons2.optional); |
if (cons2.mandatory.hasOwnProperty(name)) { |
||||||
return merged; |
merged.mandatory[name] = cons2.mandatory[name]; |
||||||
}; |
} |
||||||
|
} |
||||||
Utils.prototype.extractSdp = function(sdpLine, pattern) { |
merged.optional = merged.optional.concat(cons2.optional); |
||||||
var result = sdpLine.match(pattern); |
return merged; |
||||||
return (result && result.length == 2) ? result[1] : null; |
} |
||||||
}; |
|
||||||
|
function iceCandidateType(candidateStr) { |
||||||
Utils.prototype.addStereo = function(sdp) { |
return candidateStr.split(' ')[7]; |
||||||
// Set Opus in Stereo.
|
} |
||||||
|
|
||||||
var sdpLines = sdp.split('\r\n'); |
function maybeSetOpusOptions(sdp, params) { |
||||||
var opusPayload = ""; |
// Set Opus in Stereo, if stereo is true, unset it, if stereo is false, and
|
||||||
var fmtpLineIndex = null; |
// do nothing if otherwise.
|
||||||
var i; |
if (params.opusStereo === 'true') { |
||||||
|
sdp = setCodecParam(sdp, 'opus/48000', 'stereo', '1'); |
||||||
// Find opus payload.
|
} else if (params.opusStereo === 'false') { |
||||||
for (i = 0; i < sdpLines.length; i++) { |
sdp = removeCodecParam(sdp, 'opus/48000', 'stereo'); |
||||||
if (sdpLines[i].search('opus/48000') !== -1) { |
} |
||||||
opusPayload = this.extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); |
|
||||||
break; |
// 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'); |
||||||
// Find the payload in fmtp line.
|
} else if (params.opusFec === 'false') { |
||||||
for (i = 0; i < sdpLines.length; i++) { |
sdp = removeCodecParam(sdp, 'opus/48000', 'useinbandfec'); |
||||||
if (sdpLines[i].search('a=fmtp') !== -1) { |
} |
||||||
var payload = this.extractSdp(sdpLines[i], /a=fmtp:(\d+)/); |
|
||||||
if (payload === opusPayload) { |
// Set Opus maxplaybackrate, if requested.
|
||||||
fmtpLineIndex = i; |
if (params.opusMaxPbr) { |
||||||
break; |
sdp = setCodecParam( |
||||||
} |
sdp, 'opus/48000', 'maxplaybackrate', params.opusMaxPbr); |
||||||
} |
} |
||||||
} |
return sdp; |
||||||
// No fmtp line found.
|
} |
||||||
if (fmtpLineIndex === null) { |
|
||||||
console.log("Unable to add stereo (no fmtp line for opus payload)", opusPayload); |
function maybeSetAudioSendBitRate(sdp, params) { |
||||||
return sdp; |
if (!params.audioSendBitrate) { |
||||||
} |
return sdp; |
||||||
|
} |
||||||
// Append stereo=1 to fmtp line.
|
trace('Prefer audio send bitrate: ' + params.audioSendBitrate); |
||||||
sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat(' stereo=1'); |
return preferBitRate(sdp, params.audioSendBitrate, 'audio'); |
||||||
|
} |
||||||
sdp = sdpLines.join('\r\n'); |
|
||||||
console.log("Enabled opus stereo."); |
function maybeSetAudioReceiveBitRate(sdp, params) { |
||||||
return sdp; |
if (!params.audioRecvBitrate) { |
||||||
|
return sdp; |
||||||
}; |
} |
||||||
|
trace('Prefer audio receive bitrate: ' + params.audioRecvBitrate); |
||||||
Utils.prototype.preferOpus = function(sdp) { |
return preferBitRate(sdp, params.audioRecvBitrate, 'audio'); |
||||||
// Set Opus as the preferred codec in SDP if Opus is present.
|
} |
||||||
|
|
||||||
var sdpLines = sdp.split('\r\n'); |
function maybeSetVideoSendBitRate(sdp, params) { |
||||||
var mLineIndex = null; |
if (!params.videoSendBitrate) { |
||||||
var i; |
return sdp; |
||||||
|
} |
||||||
// Search for m line.
|
trace('Prefer video send bitrate: ' + params.videoSendBitrate); |
||||||
for (i = 0; i < sdpLines.length; i++) { |
return preferBitRate(sdp, params.videoSendBitrate, 'video'); |
||||||
if (sdpLines[i].search('m=audio') !== -1) { |
} |
||||||
mLineIndex = i; |
|
||||||
break; |
function maybeSetVideoReceiveBitRate(sdp, params) { |
||||||
} |
if (!params.videoRecvBitrate) { |
||||||
} |
return sdp; |
||||||
if (mLineIndex === null) { |
} |
||||||
return sdp; |
trace('Prefer video receive bitrate: ' + params.videoRecvBitrate); |
||||||
} |
return preferBitRate(sdp, params.videoRecvBitrate, 'video'); |
||||||
|
} |
||||||
// If Opus is available, set it as the default in m line.
|
|
||||||
for (i = 0; i < sdpLines.length; i++) { |
// Add a b=AS:bitrate line to the m=mediaType section.
|
||||||
if (sdpLines[i].search('opus/48000') !== -1) { |
function preferBitRate(sdp, bitrate, mediaType) { |
||||||
var opusPayload = this.extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); |
var sdpLines = sdp.split('\r\n'); |
||||||
if (opusPayload) { |
|
||||||
sdpLines[mLineIndex] = this.setDefaultCodec(sdpLines[mLineIndex], opusPayload); |
// Find m line for the given mediaType.
|
||||||
} |
var mLineIndex = findLine(sdpLines, 'm=', mediaType); |
||||||
break; |
if (mLineIndex === null) { |
||||||
} |
trace('Failed to add bandwidth line to sdp, as no m-line found'); |
||||||
} |
return sdp; |
||||||
|
} |
||||||
// Remove CN in m line and sdp.
|
|
||||||
sdpLines = this.removeCN(sdpLines, mLineIndex); |
// Find next m-line if any.
|
||||||
|
var nextMLineIndex = findLineInRange(sdpLines, mLineIndex + 1, -1, 'm='); |
||||||
sdp = sdpLines.join('\r\n'); |
if (nextMLineIndex === null) { |
||||||
return sdp; |
nextMLineIndex = sdpLines.length; |
||||||
|
} |
||||||
}; |
|
||||||
|
// Find c-line corresponding to the m-line.
|
||||||
Utils.prototype.setDefaultCodec = function(mLine, payload) { |
var cLineIndex = findLineInRange(sdpLines, mLineIndex + 1, |
||||||
// Set the selected codec to the first in m line.
|
nextMLineIndex, 'c='); |
||||||
var elements = mLine.split(' '); |
if (cLineIndex === null) { |
||||||
var newLine = []; |
trace('Failed to add bandwidth line to sdp, as no c-line found'); |
||||||
var index = 0; |
return sdp; |
||||||
for (var i = 0; i < elements.length; i++) { |
} |
||||||
// Format of media starts from the fourth.
|
|
||||||
if (index === 3) { |
// Check if bandwidth line already exists between c-line and next m-line.
|
||||||
newLine[index++] = payload; // Put target payload to the first.
|
var bLineIndex = findLineInRange(sdpLines, cLineIndex + 1, |
||||||
} |
nextMLineIndex, 'b=AS'); |
||||||
if (elements[i] !== payload) { |
if (bLineIndex) { |
||||||
newLine[index++] = elements[i]; |
sdpLines.splice(bLineIndex, 1); |
||||||
} |
} |
||||||
} |
|
||||||
return newLine.join(' '); |
// Create the b (bandwidth) sdp line.
|
||||||
}; |
var bwLine = 'b=AS:' + bitrate; |
||||||
|
// As per RFC 4566, the b line should follow after c-line.
|
||||||
Utils.prototype.removeCN = function(sdpLines, mLineIndex) { |
sdpLines.splice(cLineIndex + 1, 0, bwLine); |
||||||
// Strip CN from sdp before CN constraints is ready.
|
sdp = sdpLines.join('\r\n'); |
||||||
var mLineElements = sdpLines[mLineIndex].split(' '); |
return sdp; |
||||||
// 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); |
// Add an a=fmtp: x-google-min-bitrate=kbps line, if videoSendInitialBitrate
|
||||||
if (payload) { |
// is specified. We'll also add a x-google-min-bitrate value, since the max
|
||||||
var cnPos = mLineElements.indexOf(payload); |
// must be >= the min.
|
||||||
if (cnPos !== -1) { |
function maybeSetVideoSendInitialBitRate(sdp, params) { |
||||||
// Remove CN payload from m line.
|
var initialBitrate = params.videoSendInitialBitrate; |
||||||
mLineElements.splice(cnPos, 1); |
if (!initialBitrate) { |
||||||
} |
return sdp; |
||||||
// Remove CN line in sdp
|
} |
||||||
sdpLines.splice(i, 1); |
|
||||||
} |
// Validate the initial bitrate value.
|
||||||
} |
var maxBitrate = initialBitrate; |
||||||
sdpLines[mLineIndex] = mLineElements.join(' '); |
var bitrate = params.videoSendBitrate; |
||||||
return sdpLines; |
if (bitrate) { |
||||||
}; |
if (initialBitrate > bitrate) { |
||||||
|
trace('Clamping initial bitrate to max bitrate of ' + |
||||||
var utils = new Utils(); |
bitrate + ' kbps.'); |
||||||
return utils; |
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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
<div class="buddy" ng-class="{'contact': contact, 'withSubline': display.subline || session.Userid, 'isself': session.Userid === myuserid}"> |
<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="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="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> |
</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