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) { |
function mergeConstraints(cons1, cons2) { |
||||||
|
if (!cons1 || !cons2) { |
||||||
|
return cons1 || cons2; |
||||||
|
} |
||||||
var merged = cons1; |
var merged = cons1; |
||||||
var name; |
for (var name in cons2.mandatory) { |
||||||
for (name in cons2.mandatory) { |
|
||||||
if (cons2.mandatory.hasOwnProperty(name)) { |
if (cons2.mandatory.hasOwnProperty(name)) { |
||||||
merged.mandatory[name] = cons2.mandatory[name]; |
merged.mandatory[name] = cons2.mandatory[name]; |
||||||
} |
} |
||||||
} |
} |
||||||
merged.optional.concat(cons2.optional); |
merged.optional = merged.optional.concat(cons2.optional); |
||||||
return merged; |
return merged; |
||||||
}; |
} |
||||||
|
|
||||||
Utils.prototype.extractSdp = function(sdpLine, pattern) { |
function iceCandidateType(candidateStr) { |
||||||
var result = sdpLine.match(pattern); |
return candidateStr.split(' ')[7]; |
||||||
return (result && result.length == 2) ? result[1] : null; |
} |
||||||
}; |
|
||||||
|
|
||||||
Utils.prototype.addStereo = function(sdp) { |
function maybeSetOpusOptions(sdp, params) { |
||||||
// Set Opus in Stereo.
|
// 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'); |
||||||
|
} |
||||||
|
|
||||||
var sdpLines = sdp.split('\r\n'); |
// Set Opus FEC, if opusfec is true, unset it, if opusfec is false, and
|
||||||
var opusPayload = ""; |
// do nothing if otherwise.
|
||||||
var fmtpLineIndex = null; |
if (params.opusFec === 'true') { |
||||||
var i; |
sdp = setCodecParam(sdp, 'opus/48000', 'useinbandfec', '1'); |
||||||
|
} else if (params.opusFec === 'false') { |
||||||
|
sdp = removeCodecParam(sdp, 'opus/48000', 'useinbandfec'); |
||||||
|
} |
||||||
|
|
||||||
// Find opus payload.
|
// Set Opus maxplaybackrate, if requested.
|
||||||
for (i = 0; i < sdpLines.length; i++) { |
if (params.opusMaxPbr) { |
||||||
if (sdpLines[i].search('opus/48000') !== -1) { |
sdp = setCodecParam( |
||||||
opusPayload = this.extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); |
sdp, 'opus/48000', 'maxplaybackrate', params.opusMaxPbr); |
||||||
break; |
|
||||||
} |
} |
||||||
|
return sdp; |
||||||
} |
} |
||||||
|
|
||||||
// Find the payload in fmtp line.
|
function maybeSetAudioSendBitRate(sdp, params) { |
||||||
for (i = 0; i < sdpLines.length; i++) { |
if (!params.audioSendBitrate) { |
||||||
if (sdpLines[i].search('a=fmtp') !== -1) { |
return sdp; |
||||||
var payload = this.extractSdp(sdpLines[i], /a=fmtp:(\d+)/); |
|
||||||
if (payload === opusPayload) { |
|
||||||
fmtpLineIndex = i; |
|
||||||
break; |
|
||||||
} |
} |
||||||
|
trace('Prefer audio send bitrate: ' + params.audioSendBitrate); |
||||||
|
return preferBitRate(sdp, params.audioSendBitrate, 'audio'); |
||||||
} |
} |
||||||
|
|
||||||
|
function maybeSetAudioReceiveBitRate(sdp, params) { |
||||||
|
if (!params.audioRecvBitrate) { |
||||||
|
return sdp; |
||||||
} |
} |
||||||
// No fmtp line found.
|
trace('Prefer audio receive bitrate: ' + params.audioRecvBitrate); |
||||||
if (fmtpLineIndex === null) { |
return preferBitRate(sdp, params.audioRecvBitrate, 'audio'); |
||||||
console.log("Unable to add stereo (no fmtp line for opus payload)", opusPayload); |
} |
||||||
|
|
||||||
|
function maybeSetVideoSendBitRate(sdp, params) { |
||||||
|
if (!params.videoSendBitrate) { |
||||||
return sdp; |
return sdp; |
||||||
} |
} |
||||||
|
trace('Prefer video send bitrate: ' + params.videoSendBitrate); |
||||||
|
return preferBitRate(sdp, params.videoSendBitrate, 'video'); |
||||||
|
} |
||||||
|
|
||||||
// Append stereo=1 to fmtp line.
|
function maybeSetVideoReceiveBitRate(sdp, params) { |
||||||
sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat(' stereo=1'); |
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'); |
sdp = sdpLines.join('\r\n'); |
||||||
console.log("Enabled opus stereo."); |
|
||||||
return sdp; |
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; |
||||||
|
} |
||||||
|
|
||||||
Utils.prototype.preferOpus = function(sdp) { |
// Validate the initial bitrate value.
|
||||||
// Set Opus as the preferred codec in SDP if Opus is present.
|
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'); |
var sdpLines = sdp.split('\r\n'); |
||||||
var mLineIndex = null; |
|
||||||
var i; |
|
||||||
|
|
||||||
// Search for m line.
|
// Search for m line.
|
||||||
for (i = 0; i < sdpLines.length; i++) { |
var mLineIndex = findLine(sdpLines, 'm=', 'video'); |
||||||
if (sdpLines[i].search('m=audio') !== -1) { |
if (mLineIndex === null) { |
||||||
mLineIndex = i; |
trace('Failed to find video m-line'); |
||||||
break; |
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) { |
if (mLineIndex === null) { |
||||||
return sdp; |
return sdp; |
||||||
} |
} |
||||||
|
|
||||||
// If Opus is available, set it as the default in m line.
|
// If the codec is available, set it as the default in m line.
|
||||||
for (i = 0; i < sdpLines.length; i++) { |
var payload = getCodecPayloadType(sdpLines, codec); |
||||||
if (sdpLines[i].search('opus/48000') !== -1) { |
if (payload) { |
||||||
var opusPayload = this.extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); |
sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex], payload); |
||||||
if (opusPayload) { |
} |
||||||
sdpLines[mLineIndex] = this.setDefaultCodec(sdpLines[mLineIndex], opusPayload); |
|
||||||
|
sdp = sdpLines.join('\r\n'); |
||||||
|
return sdp; |
||||||
} |
} |
||||||
break; |
|
||||||
|
// 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); |
||||||
} |
} |
||||||
|
|
||||||
// Remove CN in m line and sdp.
|
sdp = sdpLines.join('\r\n'); |
||||||
sdpLines = this.removeCN(sdpLines, mLineIndex); |
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'); |
sdp = sdpLines.join('\r\n'); |
||||||
return sdp; |
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('; '); |
||||||
|
|
||||||
Utils.prototype.setDefaultCodec = function(mLine, payload) { |
var pattern = new RegExp('a=fmtp:(\\d+)'); |
||||||
// Set the selected codec to the first in m line.
|
var result = fmtpLine.match(pattern); |
||||||
var elements = mLine.split(' '); |
if (result && result.length === 2) { |
||||||
var newLine = []; |
fmtpObj.pt = result[1]; |
||||||
var index = 0; |
} else { |
||||||
for (var i = 0; i < elements.length; i++) { |
return null; |
||||||
// 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]; |
var params = {}; |
||||||
|
for (var i = 0; i < keyValues.length; ++i) { |
||||||
|
var pair = keyValues[i].split('='); |
||||||
|
if (pair.length === 2) { |
||||||
|
params[pair[0]] = pair[1]; |
||||||
} |
} |
||||||
} |
} |
||||||
return newLine.join(' '); |
fmtpObj.params = params; |
||||||
}; |
|
||||||
|
return fmtpObj; |
||||||
Utils.prototype.removeCN = function(sdpLines, mLineIndex) { |
} |
||||||
// Strip CN from sdp before CN constraints is ready.
|
|
||||||
var mLineElements = sdpLines[mLineIndex].split(' '); |
// Generate an fmtp line from an object including 'pt' and 'params'.
|
||||||
// Scan from end for the convenience of removing an item.
|
function writeFmtpLine(fmtpObj) { |
||||||
for (var i = sdpLines.length - 1; i >= 0; i--) { |
if (!fmtpObj.hasOwnProperty('pt') || !fmtpObj.hasOwnProperty('params')) { |
||||||
var payload = this.extractSdp(sdpLines[i], /a=rtpmap:(\d+) CN\/\d+/i); |
return null; |
||||||
if (payload) { |
} |
||||||
var cnPos = mLineElements.indexOf(payload); |
var pt = fmtpObj.pt; |
||||||
if (cnPos !== -1) { |
var params = fmtpObj.params; |
||||||
// Remove CN payload from m line.
|
var keyValues = []; |
||||||
mLineElements.splice(cnPos, 1); |
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; |
||||||
|
} |
||||||
} |
} |
||||||
// Remove CN line in sdp
|
|
||||||
sdpLines.splice(i, 1); |
|
||||||
} |
} |
||||||
|
return null; |
||||||
} |
} |
||||||
sdpLines[mLineIndex] = mLineElements.join(' '); |
|
||||||
return sdpLines; |
|
||||||
}; |
|
||||||
|
|
||||||
var utils = new Utils(); |
// Gets the codec payload type from sdp lines.
|
||||||
return utils; |
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